summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
authorH. Lehmann <ByteHamster@users.noreply.github.com>2019-08-11 14:57:44 +0200
committerGitHub <noreply@github.com>2019-08-11 14:57:44 +0200
commit1315c9e20b30e62b8022f831a0bcf5779b5bb2cb (patch)
tree65dd884ea83389d366d971ca5635e6e9f6c95dc4 /app/src
parentab864cd171a563177a8f565fc2744e88ba669516 (diff)
parentce64c412ac02041d877e4770381f29710a06ba17 (diff)
downloadAntennaPod-1315c9e20b30e62b8022f831a0bcf5779b5bb2cb.zip
Merge branch 'develop' into make_multidex_on_debug_build_only
Diffstat (limited to 'app/src')
-rw-r--r--app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java3
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java92
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java3
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java158
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java11
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java40
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/ConverterTest.java35
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java51
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/URIUtilTest.java22
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java89
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/service/download/NanoHTTPD.java1
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/AtomGenerator.java5
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/GeneratorUtil.java1
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/RSS2Generator.java7
-rw-r--r--app/src/free/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java5
l---------app/src/free/play1
-rw-r--r--app/src/main/AndroidManifest.xml53
-rw-r--r--app/src/main/java/de/danoeh/antennapod/PodcastApp.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java17
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java332
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FlattrAuthActivity.java120
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java30
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java35
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java88
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java126
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java147
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java59
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java188
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java17
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java97
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java23
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java148
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java139
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java76
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java32
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java44
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java74
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java63
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java41
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java60
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java63
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java84
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java53
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java97
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java64
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java71
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java226
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java17
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java96
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java38
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java38
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java74
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java110
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java81
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java99
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java299
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java125
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java173
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java135
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java115
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java77
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java44
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java39
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java177
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java77
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java190
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java58
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java108
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java202
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java47
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java113
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java154
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java119
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java103
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java195
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java184
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java144
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java23
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java147
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java175
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java92
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java244
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java165
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java1218
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java69
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java112
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java41
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/WrappingGridView.java35
-rw-r--r--app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java30
-rw-r--r--app/src/main/play/ar/listing/fulldescription43
-rw-r--r--app/src/main/play/ast_ES/listing/fulldescription43
-rw-r--r--app/src/main/play/az/listing/fulldescription43
-rw-r--r--app/src/main/play/bg/listing/fulldescription43
-rw-r--r--app/src/main/play/ca/listing/fulldescription43
-rw-r--r--app/src/main/play/ca_ES/listing/fulldescription43
-rw-r--r--app/src/main/play/contact-email.txt (renamed from app/src/main/play/contactEmail)0
-rw-r--r--app/src/main/play/contact-website.txt (renamed from app/src/main/play/contactWebsite)0
-rw-r--r--app/src/main/play/cs-CZ/listing/fulldescription20
-rw-r--r--app/src/main/play/cs-CZ/listing/shortdescription1
-rw-r--r--app/src/main/play/cs-CZ/listing/title1
-rw-r--r--app/src/main/play/cs_CZ/listing/fulldescription43
-rw-r--r--app/src/main/play/da-DK/listing/fulldescription20
-rw-r--r--app/src/main/play/da-DK/listing/shortdescription1
-rw-r--r--app/src/main/play/da-DK/listing/title1
-rw-r--r--app/src/main/play/da/listing/fulldescription43
-rw-r--r--app/src/main/play/de-DE/listing/fulldescription20
-rw-r--r--app/src/main/play/de-DE/listing/title1
-rw-r--r--app/src/main/play/default-language.txt (renamed from app/src/main/play/defaultLanguage)0
-rw-r--r--app/src/main/play/el/listing/fulldescription43
-rw-r--r--app/src/main/play/en-US/listing/shortdescription1
-rw-r--r--app/src/main/play/en-US/listing/title1
-rw-r--r--app/src/main/play/es-ES/listing/fulldescription40
-rw-r--r--app/src/main/play/es-ES/listing/shortdescription1
-rw-r--r--app/src/main/play/es-ES/listing/title1
-rw-r--r--app/src/main/play/es/listing/fulldescription43
-rw-r--r--app/src/main/play/es_ES/listing/fulldescription43
-rw-r--r--app/src/main/play/et/listing/fulldescription43
-rw-r--r--app/src/main/play/fa/listing/fulldescription43
-rw-r--r--app/src/main/play/fi/listing/fulldescription43
-rw-r--r--app/src/main/play/fr-FR/listing/fulldescription40
-rw-r--r--app/src/main/play/fr-FR/listing/title1
-rw-r--r--app/src/main/play/he_IL/listing/fulldescription43
-rw-r--r--app/src/main/play/hi-IN/listing/fulldescription20
-rw-r--r--app/src/main/play/hi-IN/listing/shortdescription1
-rw-r--r--app/src/main/play/hi-IN/listing/title1
-rw-r--r--app/src/main/play/hi_IN/listing/fulldescription43
-rw-r--r--app/src/main/play/hu/listing/fulldescription43
-rw-r--r--app/src/main/play/id/listing/fulldescription43
-rw-r--r--app/src/main/play/is/listing/fulldescription43
-rw-r--r--app/src/main/play/it-IT/listing/fulldescription40
-rw-r--r--app/src/main/play/it-IT/listing/shortdescription1
-rw-r--r--app/src/main/play/it-IT/listing/title1
-rw-r--r--app/src/main/play/it/listing/fulldescription43
-rw-r--r--app/src/main/play/iw-IL/listing/fulldescription23
-rw-r--r--app/src/main/play/iw-IL/listing/shortdescription1
-rw-r--r--app/src/main/play/iw-IL/listing/title1
-rw-r--r--app/src/main/play/ja-JP/listing/fulldescription41
-rw-r--r--app/src/main/play/ja-JP/listing/title1
-rw-r--r--app/src/main/play/kn_IN/listing/fulldescription43
-rw-r--r--app/src/main/play/ko-KR/listing/fulldescription20
-rw-r--r--app/src/main/play/ko-KR/listing/shortdescription1
-rw-r--r--app/src/main/play/ko-KR/listing/title1
-rw-r--r--app/src/main/play/ko/listing/fulldescription43
-rw-r--r--app/src/main/play/ko_KR/listing/fulldescription43
-rw-r--r--app/src/main/play/listings/de-DE/full-description.txt (renamed from app/src/main/play/de/listing/fulldescription)2
-rw-r--r--app/src/main/play/listings/de-DE/short-description.txt (renamed from app/src/main/play/de-DE/listing/shortdescription)0
-rw-r--r--app/src/main/play/listings/en-US/full-description.txt (renamed from app/src/main/play/en-US/listing/fulldescription)7
-rw-r--r--app/src/main/play/listings/en-US/graphics/feature-graphic/feature-graphic.png (renamed from app/src/main/play/en-US/listing/featureGraphic/feature-graphic.png)bin60183 -> 60183 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/00.png (renamed from app/src/main/play/en-US/listing/phoneScreenshots/00.png)bin300470 -> 300470 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/01.png (renamed from app/src/main/play/en-US/listing/phoneScreenshots/01.png)bin385379 -> 385379 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/02.png (renamed from app/src/main/play/en-US/listing/phoneScreenshots/02.png)bin150991 -> 150991 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/03.png (renamed from app/src/main/play/en-US/listing/phoneScreenshots/03.png)bin378048 -> 378048 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/04.png (renamed from app/src/main/play/en-US/listing/phoneScreenshots/04.png)bin167307 -> 167307 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/05.png (renamed from app/src/main/play/en-US/listing/phoneScreenshots/05.png)bin93763 -> 93763 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/06.png (renamed from app/src/main/play/en-US/listing/phoneScreenshots/06.png)bin173137 -> 173137 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/07.png (renamed from app/src/main/play/en-US/listing/phoneScreenshots/07.png)bin54530 -> 54530 bytes
-rw-r--r--app/src/main/play/listings/en-US/short-description.txt (renamed from app/src/main/play/ca/listing/shortdescription)2
-rw-r--r--app/src/main/play/listings/en-US/title.txt (renamed from app/src/main/play/ca/listing/title)0
-rw-r--r--app/src/main/play/listings/fr-FR/full-description.txt (renamed from app/src/main/play/fr/listing/fulldescription)0
-rw-r--r--app/src/main/play/listings/fr-FR/short-description.txt (renamed from app/src/main/play/fr-FR/listing/shortdescription)0
-rw-r--r--app/src/main/play/listings/gl-ES/full-description.txt (renamed from app/src/main/play/gl/listing/fulldescription)2
-rw-r--r--app/src/main/play/listings/gl-ES/short-description.txt1
-rw-r--r--app/src/main/play/listings/it-IT/full-description.txt (renamed from app/src/main/play/it_IT/listing/fulldescription)2
-rw-r--r--app/src/main/play/listings/it-IT/short-description.txt1
-rw-r--r--app/src/main/play/listings/ja-JP/full-description.txt (renamed from app/src/main/play/ja/listing/fulldescription)0
-rw-r--r--app/src/main/play/listings/ja-JP/short-description.txt (renamed from app/src/main/play/ja-JP/listing/shortdescription)2
-rw-r--r--app/src/main/play/listings/nl-NL/full-description.txt (renamed from app/src/main/play/nl/listing/fulldescription)2
-rw-r--r--app/src/main/play/listings/nl-NL/short-description.txt1
-rw-r--r--app/src/main/play/listings/zh-CN/short-description.txt1
-rw-r--r--app/src/main/play/lt/listing/fulldescription43
-rw-r--r--app/src/main/play/ms_MY/listing/fulldescription43
-rw-r--r--app/src/main/play/nb/listing/fulldescription43
-rw-r--r--app/src/main/play/nb_NO/listing/fulldescription43
-rw-r--r--app/src/main/play/nl-NL/listing/fulldescription20
-rw-r--r--app/src/main/play/nl-NL/listing/shortdescription1
-rw-r--r--app/src/main/play/nl-NL/listing/title1
-rw-r--r--app/src/main/play/no/listing/fulldescription43
-rw-r--r--app/src/main/play/pl-PL/listing/fulldescription20
-rw-r--r--app/src/main/play/pl-PL/listing/shortdescription1
-rw-r--r--app/src/main/play/pl-PL/listing/title1
-rw-r--r--app/src/main/play/pl/listing/fulldescription43
-rw-r--r--app/src/main/play/pl_PL/listing/fulldescription43
-rw-r--r--app/src/main/play/pt-BR/listing/fulldescription40
-rw-r--r--app/src/main/play/pt-BR/listing/shortdescription1
-rw-r--r--app/src/main/play/pt-BR/listing/title1
-rw-r--r--app/src/main/play/pt-PT/listing/fulldescription40
-rw-r--r--app/src/main/play/pt-PT/listing/shortdescription1
-rw-r--r--app/src/main/play/pt-PT/listing/title1
-rw-r--r--app/src/main/play/pt/listing/fulldescription43
-rw-r--r--app/src/main/play/pt_BR/listing/fulldescription43
-rw-r--r--app/src/main/play/release-notes/en-US/default.txt5
-rw-r--r--app/src/main/play/ro/listing/fulldescription20
-rw-r--r--app/src/main/play/ro/listing/shortdescription1
-rw-r--r--app/src/main/play/ro/listing/title1
-rw-r--r--app/src/main/play/ro_RO/listing/fulldescription43
-rw-r--r--app/src/main/play/ru-RU/listing/fulldescription20
-rw-r--r--app/src/main/play/ru-RU/listing/shortdescription1
-rw-r--r--app/src/main/play/ru-RU/listing/title1
-rw-r--r--app/src/main/play/ru_RU/listing/fulldescription43
-rw-r--r--app/src/main/play/sl_SI/listing/fulldescription43
-rw-r--r--app/src/main/play/sv-SE/listing/fulldescription40
-rw-r--r--app/src/main/play/sv-SE/listing/shortdescription1
-rw-r--r--app/src/main/play/sv-SE/listing/title1
-rw-r--r--app/src/main/play/sv_SE/listing/fulldescription43
-rw-r--r--app/src/main/play/sw_KE/listing/fulldescription43
-rw-r--r--app/src/main/play/te/listing/fulldescription43
-rw-r--r--app/src/main/play/tr-TR/listing/fulldescription20
-rw-r--r--app/src/main/play/tr-TR/listing/shortdescription1
-rw-r--r--app/src/main/play/tr-TR/listing/title1
-rw-r--r--app/src/main/play/tr/listing/fulldescription43
-rw-r--r--app/src/main/play/uk/listing/fulldescription40
-rw-r--r--app/src/main/play/uk/listing/shortdescription1
-rw-r--r--app/src/main/play/uk/listing/title1
-rw-r--r--app/src/main/play/uk_UA/listing/fulldescription43
-rw-r--r--app/src/main/play/vi/listing/fulldescription43
-rw-r--r--app/src/main/play/vi_VN/listing/fulldescription43
-rw-r--r--app/src/main/play/zh-CN/listing/fulldescription20
-rw-r--r--app/src/main/play/zh-CN/listing/shortdescription1
-rw-r--r--app/src/main/play/zh-CN/listing/title1
-rw-r--r--app/src/main/play/zh/listing/fulldescription43
-rw-r--r--app/src/main/play/zh_CN/listing/fulldescription43
-rw-r--r--app/src/main/play/zh_HK/listing/fulldescription43
-rw-r--r--app/src/main/play/zh_TW/listing/fulldescription43
-rw-r--r--app/src/main/res/layout/addfeed.xml255
-rw-r--r--app/src/main/res/layout/audio_controls.xml7
-rw-r--r--app/src/main/res/layout/autoflattr_preference_dialog.xml35
-rw-r--r--app/src/main/res/layout/choose_data_folder_dialog_entry.xml48
-rw-r--r--app/src/main/res/layout/cover_fragment.xml88
-rw-r--r--app/src/main/res/layout/downloaded_episodeslist_item.xml2
-rw-r--r--app/src/main/res/layout/empty_view_layout.xml39
-rw-r--r--app/src/main/res/layout/episode_filter_dialog.xml95
-rw-r--r--app/src/main/res/layout/episodes_apply_action_fragment.xml143
-rw-r--r--app/src/main/res/layout/feedsettings.xml211
-rw-r--r--app/src/main/res/layout/flattr_auth.xml30
-rw-r--r--app/src/main/res/layout/gpodnetauth_credentials.xml4
-rw-r--r--app/src/main/res/layout/gpodnetauth_device.xml6
-rw-r--r--app/src/main/res/layout/mediaplayerinfo_activity.xml20
-rw-r--r--app/src/main/res/layout/nav_feedlistitem.xml12
-rw-r--r--app/src/main/res/layout/nav_listitem.xml1
-rw-r--r--app/src/main/res/layout/onlinefeedview_header.xml99
-rw-r--r--app/src/main/res/layout/opml_import.xml41
-rw-r--r--app/src/main/res/layout/queue_fragment.xml8
-rw-r--r--app/src/main/res/layout/quick_feed_discovery.xml83
-rw-r--r--app/src/main/res/layout/quick_feed_discovery_item.xml14
-rw-r--r--app/src/main/res/layout/simple_list_item_multiple_choice_on_start.xml33
-rw-r--r--app/src/main/res/layout/videoplayer_activity.xml12
-rw-r--r--app/src/main/res/menu/advanced_search.xml14
-rw-r--r--app/src/main/res/menu/allepisodes_context.xml10
-rw-r--r--app/src/main/res/menu/episodes.xml8
-rw-r--r--app/src/main/res/menu/episodes_apply_action_speeddial.xml34
-rw-r--r--app/src/main/res/menu/feedinfo.xml6
-rw-r--r--app/src/main/res/menu/feeditem_options.xml6
-rw-r--r--app/src/main/res/menu/feeditemlist_context.xml11
-rw-r--r--app/src/main/res/menu/feedlist.xml8
-rw-r--r--app/src/main/res/menu/mediaplayer.xml7
-rw-r--r--app/src/main/res/menu/nav_feed_context.xml4
-rw-r--r--app/src/main/res/menu/opml_selection_options.xml4
-rw-r--r--app/src/main/res/menu/queue.xml31
-rw-r--r--app/src/main/res/menu/queue_context.xml10
-rw-r--r--app/src/main/res/menu/subscriptions.xml28
-rw-r--r--app/src/main/res/values-w300dp/dimens-fabspeeddial.xml8
-rw-r--r--app/src/main/res/xml/feed_settings.xml30
-rw-r--r--app/src/main/res/xml/preferences_autodownload.xml6
-rw-r--r--app/src/main/res/xml/preferences_flattr.xml21
-rw-r--r--app/src/main/res/xml/preferences_integrations.xml8
-rw-r--r--app/src/main/res/xml/preferences_network.xml9
-rw-r--r--app/src/main/res/xml/preferences_playback.xml9
-rw-r--r--app/src/main/res/xml/preferences_storage.xml9
-rw-r--r--app/src/main/templates/about.html5
-rw-r--r--app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java1
-rw-r--r--app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java3
l---------app/src/play/play1
289 files changed, 5864 insertions, 7462 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
index 6908e2ec7..9419d2318 100644
--- a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
@@ -1,6 +1,7 @@
package de.test.antennapod.handler;
import android.content.Context;
+import android.support.test.InstrumentationRegistry;
import android.test.InstrumentationTestCase;
import org.xml.sax.SAXException;
@@ -36,7 +37,7 @@ public class FeedHandlerTest extends InstrumentationTestCase {
protected void setUp() throws Exception {
super.setUp();
- Context context = getInstrumentation().getContext();
+ Context context = InstrumentationRegistry.getTargetContext();
File destDir = context.getExternalFilesDir(FEEDS_DIR);
assertNotNull(destDir);
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java
index 8be57a074..c8222b376 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java
@@ -1,6 +1,9 @@
package de.test.antennapod.service.playback;
import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.runner.AndroidJUnit4;
import android.test.InstrumentationTestCase;
import java.util.ArrayList;
@@ -16,38 +19,47 @@ import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.service.playback.PlaybackServiceTaskManager;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.playback.Playable;
-import de.greenrobot.event.EventBus;
+import org.greenrobot.eventbus.EventBus;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* Test class for PlaybackServiceTaskManager
*/
-public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class PlaybackServiceTaskManagerTest {
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
+ @After
+ public void tearDown() {
PodDBAdapter.deleteDatabase();
}
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
+ @Before
+ public void setUp() {
// create new database
- PodDBAdapter.init(getInstrumentation().getTargetContext());
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ PodDBAdapter.init(context);
PodDBAdapter.deleteDatabase();
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
adapter.close();
}
+ @Test
public void testInit() {
- PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(getInstrumentation().getTargetContext(), defaultPSTM);
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(context, defaultPSTM);
pstm.shutdown();
}
private List<FeedItem> writeTestQueue(String pref) {
- final Context c = getInstrumentation().getTargetContext();
final int NUM_ITEMS = 10;
Feed f = new Feed(0, null, "title", "link", "d", null, null, null, null, "id", null, "null", "url", false);
f.setItems(new ArrayList<>());
@@ -66,8 +78,9 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
return f.getItems();
}
+ @Test
public void testGetQueueWriteBeforeCreation() throws InterruptedException {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
List<FeedItem> queue = writeTestQueue("a");
assertNotNull(queue);
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
@@ -80,8 +93,9 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
pstm.shutdown();
}
+ @Test
public void testGetQueueWriteAfterCreation() throws InterruptedException {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
List<FeedItem> testQueue = pstm.getQueue();
@@ -111,8 +125,9 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
pstm.shutdown();
}
+ @Test
public void testStartPositionSaver() throws InterruptedException {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
final int NUM_COUNTDOWNS = 2;
final int TIMEOUT = 3 * PlaybackServiceTaskManager.POSITION_SAVER_WAITING_INTERVAL;
final CountDownLatch countDownLatch = new CountDownLatch(NUM_COUNTDOWNS);
@@ -152,16 +167,18 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
pstm.shutdown();
}
+ @Test
public void testIsPositionSaverActive() {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
pstm.startPositionSaver();
assertTrue(pstm.isPositionSaverActive());
pstm.shutdown();
}
+ @Test
public void testCancelPositionSaver() {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
pstm.startPositionSaver();
pstm.cancelPositionSaver();
@@ -169,8 +186,9 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
pstm.shutdown();
}
+ @Test
public void testStartWidgetUpdater() throws InterruptedException {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
final int NUM_COUNTDOWNS = 2;
final int TIMEOUT = 3 * PlaybackServiceTaskManager.WIDGET_UPDATER_NOTIFICATION_INTERVAL;
final CountDownLatch countDownLatch = new CountDownLatch(NUM_COUNTDOWNS);
@@ -210,16 +228,27 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
pstm.shutdown();
}
+ @Test
+ public void testStartWidgetUpdaterAfterShutdown() {
+ // Should not throw.
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
+ pstm.shutdown();
+ pstm.startWidgetUpdater();
+ }
+
+ @Test
public void testIsWidgetUpdaterActive() {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
pstm.startWidgetUpdater();
assertTrue(pstm.isWidgetUpdaterActive());
pstm.shutdown();
}
+ @Test
public void testCancelWidgetUpdater() {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
pstm.startWidgetUpdater();
pstm.cancelWidgetUpdater();
@@ -227,8 +256,9 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
pstm.shutdown();
}
+ @Test
public void testCancelAllTasksNoTasksStarted() {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
pstm.cancelAllTasks();
assertFalse(pstm.isPositionSaverActive());
@@ -237,8 +267,10 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
pstm.shutdown();
}
+ @Test
+ @UiThreadTest
public void testCancelAllTasksAllTasksStarted() {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
pstm.startWidgetUpdater();
pstm.startPositionSaver();
@@ -250,8 +282,10 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
pstm.shutdown();
}
+ @Test
+ @UiThreadTest
public void testSetSleepTimer() throws InterruptedException {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
final long TIME = 2000;
final long TIMEOUT = 2 * TIME;
final CountDownLatch countDownLatch = new CountDownLatch(1);
@@ -294,8 +328,10 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
pstm.shutdown();
}
+ @Test
+ @UiThreadTest
public void testDisableSleepTimer() throws InterruptedException {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
final long TIME = 1000;
final long TIMEOUT = 2 * TIME;
final CountDownLatch countDownLatch = new CountDownLatch(1);
@@ -336,16 +372,20 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
pstm.shutdown();
}
+ @Test
+ @UiThreadTest
public void testIsSleepTimerActivePositive() {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
pstm.setSleepTimer(10000, false, false);
assertTrue(pstm.isSleepTimerActive());
pstm.shutdown();
}
+ @Test
+ @UiThreadTest
public void testIsSleepTimerActiveNegative() {
- final Context c = getInstrumentation().getTargetContext();
+ final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
pstm.setSleepTimer(10000, false, false);
pstm.disableSleepTimer();
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java b/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java
index a577e5e36..f58008172 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java
@@ -14,7 +14,6 @@ import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.SimpleChapter;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
-import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
/**
* Utility methods for DB* tests.
@@ -46,7 +45,7 @@ class DBTestUtils {
adapter.open();
for (int i = 0; i < numFeeds; i++) {
Feed f = new Feed(0, null, "feed " + i, null, "link" + i, "descr", null, null,
- null, null, "id" + i, null, null, "url" + i, false, new FlattrStatus(), false, null, null, false);
+ null, null, "id" + i, null, null, "url" + i, false, false, null, null, false);
f.setItems(new ArrayList<>());
for (int j = 0; j < numItems; j++) {
FeedItem item = new FeedItem(0, "item " + j, "id" + j, "link" + j, new Date(),
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
index 427cc8ddd..27d76116d 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
@@ -1,10 +1,14 @@
package de.test.antennapod.storage;
import android.content.Context;
+import android.content.SharedPreferences;
import android.database.Cursor;
+import android.preference.PreferenceManager;
import android.test.InstrumentationTestCase;
import android.util.Log;
+import org.awaitility.Awaitility;
+
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -18,9 +22,11 @@ import java.util.concurrent.TimeoutException;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
+import de.danoeh.antennapod.core.util.Consumer;
/**
* Test class for DBWriter
@@ -55,6 +61,12 @@ public class DBWriterTest extends InstrumentationTestCase {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
adapter.close();
+
+ Context context = getInstrumentation().getTargetContext();
+ SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()).edit();
+ prefEdit.putBoolean(UserPreferences.PREF_DELETE_REMOVES_FROM_QUEUE, true).commit();
+
+ UserPreferences.init(context);
}
public void testSetFeedMediaPlaybackInformation()
@@ -121,6 +133,47 @@ public class DBWriterTest extends InstrumentationTestCase {
assertNull(media.getFile_url());
}
+ public void testDeleteFeedMediaOfItemRemoveFromQueue()
+ throws IOException, ExecutionException, InterruptedException, TimeoutException {
+ assertTrue(UserPreferences.shouldDeleteRemoveFromQueue());
+
+ File dest = new File(getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER), "testFile");
+
+ assertTrue(dest.createNewFile());
+
+ Feed feed = new Feed("url", null, "title");
+ List<FeedItem> items = new ArrayList<>();
+ List<FeedItem> queue = new ArrayList<>();
+ feed.setItems(items);
+ FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.UNPLAYED, feed);
+
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", dest.getAbsolutePath(), "download_url", true, null, 0, 0);
+ item.setMedia(media);
+
+ items.add(item);
+ queue.add(item);
+
+ PodDBAdapter adapter = PodDBAdapter.getInstance();
+ adapter.open();
+ adapter.setCompleteFeed(feed);
+ adapter.setQueue(queue);
+ adapter.close();
+ assertTrue(media.getId() != 0);
+ assertTrue(item.getId() != 0);
+ queue = DBReader.getQueue();
+ assertTrue(queue.size() != 0);
+
+ DBWriter.deleteFeedMediaOfItem(getInstrumentation().getTargetContext(), media.getId());
+ Awaitility.await().until(() -> dest.exists() == false);
+ media = DBReader.getFeedMedia(media.getId());
+ assertNotNull(media);
+ assertFalse(dest.exists());
+ assertFalse(media.isDownloaded());
+ assertNull(media.getFile_url());
+ queue = DBReader.getQueue();
+ assertTrue(queue.size() == 0);
+ }
+
public void testDeleteFeed() throws ExecutionException, InterruptedException, IOException, TimeoutException {
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
@@ -522,29 +575,16 @@ public class DBWriterTest extends InstrumentationTestCase {
public void testRemoveQueueItem() throws InterruptedException, ExecutionException, TimeoutException {
final int NUM_ITEMS = 10;
final Context context = getInstrumentation().getTargetContext();
- Feed feed = new Feed("url", null, "title");
- feed.setItems(new ArrayList<>());
- for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
- feed.getItems().add(item);
- }
+ Feed feed = createTestFeed(NUM_ITEMS);
- PodDBAdapter adapter = PodDBAdapter.getInstance();
- adapter.open();
- adapter.setCompleteFeed(feed);
- adapter.close();
-
- for (FeedItem item : feed.getItems()) {
- assertTrue(item.getId() != 0);
- }
for (int removeIndex = 0; removeIndex < NUM_ITEMS; removeIndex++) {
final FeedItem item = feed.getItems().get(removeIndex);
- adapter = PodDBAdapter.getInstance();
+ PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
adapter.setQueue(feed.getItems());
adapter.close();
- DBWriter.removeQueueItem(context, item, false).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.removeQueueItem(context, false, item).get(TIMEOUT, TimeUnit.SECONDS);
adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor queue = adapter.getQueueIDCursor();
@@ -564,6 +604,43 @@ public class DBWriterTest extends InstrumentationTestCase {
}
}
+ public void testRemoveQueueItemMultipleItems() throws InterruptedException, ExecutionException, TimeoutException {
+ // Setup test data
+ //
+ final int NUM_ITEMS = 5;
+ final int NUM_IN_QUEUE = NUM_ITEMS - 1; // the last one not in queue for boundary condition
+ final Context context = getInstrumentation().getTargetContext();
+ Feed feed = createTestFeed(NUM_ITEMS);
+
+ List<FeedItem> itemsToAdd = feed.getItems().subList(0, NUM_IN_QUEUE);
+ withPodDB(adapter -> adapter.setQueue(itemsToAdd) );
+
+ // Actual tests
+ //
+
+ // Use array rather than List to make codes more succinct
+ Long[] itemIds = toItemIds(feed.getItems()).toArray(new Long[0]);
+
+ DBWriter.removeQueueItem(context, false,
+ itemIds[1], itemIds[3]).get(TIMEOUT, TimeUnit.SECONDS);
+ assertQueueByItemIds("Average case - 2 items removed successfully",
+ itemIds[0], itemIds[2]);
+
+ DBWriter.removeQueueItem(context, false).get(TIMEOUT, TimeUnit.SECONDS);
+ assertQueueByItemIds("Boundary case - no items supplied. queue should see no change",
+ itemIds[0], itemIds[2]);
+
+ DBWriter.removeQueueItem(context, false,
+ itemIds[0], itemIds[4], -1L).get(TIMEOUT, TimeUnit.SECONDS);
+ assertQueueByItemIds("Boundary case - items not in queue ignored",
+ itemIds[2]);
+
+ DBWriter.removeQueueItem(context, false,
+ itemIds[2], -1L).get(TIMEOUT, TimeUnit.SECONDS);
+ assertQueueByItemIds("Boundary case - invalid itemIds ignored"); // the queue is empty
+
+ }
+
public void testMoveQueueItem() throws InterruptedException, ExecutionException, TimeoutException {
final int NUM_ITEMS = 10;
Feed feed = new Feed("url", null, "title");
@@ -661,4 +738,53 @@ public class DBWriterTest extends InstrumentationTestCase {
assertTrue(item.isPlayed());
}
}
+
+ private static Feed createTestFeed(int numItems) {
+ Feed feed = new Feed("url", null, "title");
+ feed.setItems(new ArrayList<>());
+ for (int i = 0; i < numItems; i++) {
+ FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
+ feed.getItems().add(item);
+ }
+
+ withPodDB(adapter -> adapter.setCompleteFeed(feed));
+
+ for (FeedItem item : feed.getItems()) {
+ assertTrue(item.getId() != 0);
+ }
+ return feed;
+ }
+
+ private static void withPodDB(Consumer<PodDBAdapter> action) {
+ PodDBAdapter adapter = PodDBAdapter.getInstance();
+ try {
+ adapter.open();
+ action.accept(adapter);
+ } finally {
+ adapter.close();
+ }
+ }
+
+ private static void assertQueueByItemIds(
+ String message,
+ long... itemIdsExpected
+ ) {
+ List<FeedItem> queue = DBReader.getQueue();
+ List<Long> itemIdsActualList = toItemIds(queue);
+ List<Long> itemIdsExpectedList = new ArrayList<Long>(itemIdsExpected.length);
+ for (long id : itemIdsExpected) {
+ itemIdsExpectedList.add(id);
+ }
+
+ assertEquals(message, itemIdsExpectedList, itemIdsActualList);
+ }
+
+ private static List<Long> toItemIds(List<FeedItem> items) {
+ List<Long> itemIds = new ArrayList<Long>(items.size());
+ for(FeedItem item : items) {
+ itemIds.add(item.getId());
+ }
+ return itemIds;
+ }
+
}
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
index 9a60b04b8..8e0064079 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
@@ -7,6 +7,7 @@ import android.support.test.espresso.intent.Intents;
import android.support.test.filters.FlakyTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import android.view.Gravity;
import android.widget.ListView;
import com.robotium.solo.Solo;
import com.robotium.solo.Timeout;
@@ -17,6 +18,7 @@ import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
+import de.danoeh.antennapod.dialog.RatingDialog;
import de.danoeh.antennapod.fragment.DownloadsFragment;
import de.danoeh.antennapod.fragment.EpisodesFragment;
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
@@ -36,6 +38,8 @@ import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.longClick;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.contrib.DrawerMatchers.isClosed;
import static android.support.test.espresso.intent.Intents.intended;
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
@@ -76,6 +80,9 @@ public class MainActivityTest {
prefs = context.getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE);
prefs.edit().putBoolean(MainActivity.PREF_IS_FIRST_LAUNCH, false).commit();
+ RatingDialog.init(context);
+ RatingDialog.saveRated();
+
solo = new Solo(getInstrumentation(), mActivityRule.getActivity());
}
@@ -89,7 +96,9 @@ public class MainActivityTest {
}
private void openNavDrawer() {
- onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
+ onView(withId(R.id.drawer_layout))
+ .check(matches(isClosed(Gravity.LEFT)))
+ .perform(DrawerActions.open());
}
@Test
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
index f217ecffa..d934bf3e2 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
@@ -7,18 +7,9 @@ import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
+
import com.robotium.solo.Solo;
import com.robotium.solo.Timeout;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.APCleanupAlgorithm;
-import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm;
-import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm;
-import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm;
-import de.danoeh.antennapod.fragment.EpisodesFragment;
-import de.danoeh.antennapod.fragment.QueueFragment;
-import de.danoeh.antennapod.fragment.SubscriptionFragment;
import org.hamcrest.Matcher;
import org.junit.After;
@@ -30,6 +21,17 @@ import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.storage.APCleanupAlgorithm;
+import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm;
+import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm;
+import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm;
+import de.danoeh.antennapod.fragment.EpisodesFragment;
+import de.danoeh.antennapod.fragment.QueueFragment;
+import de.danoeh.antennapod.fragment.SubscriptionFragment;
+
import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
@@ -397,7 +399,7 @@ public class PreferencesTest {
EpisodeCleanupAlgorithm alg = UserPreferences.getEpisodeCleanupAlgorithm();
if (alg instanceof APCleanupAlgorithm) {
APCleanupAlgorithm cleanupAlg = (APCleanupAlgorithm)alg;
- return cleanupAlg.getNumberOfDaysAfterPlayback() == 0;
+ return cleanupAlg.getNumberOfHoursAfterPlayback() == 0;
}
return false;
},
@@ -416,7 +418,7 @@ public class PreferencesTest {
EpisodeCleanupAlgorithm alg = UserPreferences.getEpisodeCleanupAlgorithm();
if (alg instanceof APCleanupAlgorithm) {
APCleanupAlgorithm cleanupAlg = (APCleanupAlgorithm)alg;
- return cleanupAlg.getNumberOfDaysAfterPlayback() == 5;
+ return cleanupAlg.getNumberOfHoursAfterPlayback() == 120; // 5 days
}
return false;
},
@@ -505,6 +507,20 @@ public class PreferencesTest {
Timeout.getLargeTimeout()));
}
+ @Test
+ public void testDeleteRemovesFromQueue() {
+ clickPreference(withText(R.string.storage_pref));
+ if (!UserPreferences.shouldDeleteRemoveFromQueue()) {
+ clickPreference(withText(R.string.pref_delete_removes_from_queue_title));
+ assertTrue(solo.waitForCondition(UserPreferences::shouldDeleteRemoveFromQueue, Timeout.getLargeTimeout()));
+ }
+ final boolean deleteRemovesFromQueue = UserPreferences.shouldDeleteRemoveFromQueue();
+ solo.clickOnText(solo.getString(R.string.pref_delete_removes_from_queue_title));
+ assertTrue(solo.waitForCondition(() -> deleteRemovesFromQueue != UserPreferences.shouldDeleteRemoveFromQueue(), Timeout.getLargeTimeout()));
+ solo.clickOnText(solo.getString(R.string.pref_delete_removes_from_queue_title));
+ assertTrue(solo.waitForCondition(() -> deleteRemovesFromQueue == UserPreferences.shouldDeleteRemoveFromQueue(), Timeout.getLargeTimeout()));
+ }
+
private void clickPreference(Matcher<View> matcher) {
onView(withId(R.id.list))
.perform(RecyclerViewActions.actionOnItem(hasDescendant(matcher), click()));
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
index ff5374268..263790c2f 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
@@ -27,9 +27,9 @@ import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.fragment.ExternalPlayerFragment;
-import de.greenrobot.event.EventBus;
import de.test.antennapod.util.service.download.HTTPBin;
import de.test.antennapod.util.syndication.feedgenerator.RSS2Generator;
+import org.greenrobot.eventbus.EventBus;
/**
* Utility methods for UI tests.
diff --git a/app/src/androidTest/java/de/test/antennapod/util/ConverterTest.java b/app/src/androidTest/java/de/test/antennapod/util/ConverterTest.java
deleted file mode 100644
index 47fca41ba..000000000
--- a/app/src/androidTest/java/de/test/antennapod/util/ConverterTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package de.test.antennapod.util;
-
-import android.test.AndroidTestCase;
-
-import de.danoeh.antennapod.core.util.Converter;
-
-/**
- * Test class for converter
- */
-public class ConverterTest extends AndroidTestCase {
-
- public void testGetDurationStringLong() throws Exception {
- String expected = "13:05:10";
- int input = 47110000;
- assertEquals(expected, Converter.getDurationStringLong(input));
- }
-
- public void testGetDurationStringShort() throws Exception {
- String expected = "13:05";
- int input = 47110000;
- assertEquals(expected, Converter.getDurationStringShort(input));
- }
-
- public void testDurationStringLongToMs() throws Exception {
- String input = "01:20:30";
- long expected = 4830000;
- assertEquals(expected, Converter.durationStringLongToMs(input));
- }
-
- public void testDurationStringShortToMs() throws Exception {
- String input = "8:30";
- long expected = 30600000;
- assertEquals(expected, Converter.durationStringShortToMs(input));
- }
-}
diff --git a/app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java b/app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java
deleted file mode 100644
index d564d0492..000000000
--- a/app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package de.test.antennapod.util;
-
-import junit.framework.TestCase;
-
-import de.danoeh.antennapod.core.util.RewindAfterPauseUtils;
-
-/**
- * Tests for {@link RewindAfterPauseUtils}.
- */
-public class RewindAfterPauseUtilTest extends TestCase {
-
- public void testCalculatePositionWithRewindNoRewind() {
- final int ORIGINAL_POSITION = 10000;
- long lastPlayed = System.currentTimeMillis();
- int position = RewindAfterPauseUtils.calculatePositionWithRewind(ORIGINAL_POSITION, lastPlayed);
-
- assertEquals(ORIGINAL_POSITION, position);
- }
-
- public void testCalculatePositionWithRewindSmallRewind() {
- final int ORIGINAL_POSITION = 10000;
- long lastPlayed = System.currentTimeMillis() - RewindAfterPauseUtils.ELAPSED_TIME_FOR_SHORT_REWIND - 1000;
- int position = RewindAfterPauseUtils.calculatePositionWithRewind(ORIGINAL_POSITION, lastPlayed);
-
- assertEquals(ORIGINAL_POSITION - RewindAfterPauseUtils.SHORT_REWIND, position);
- }
-
- public void testCalculatePositionWithRewindMediumRewind() {
- final int ORIGINAL_POSITION = 10000;
- long lastPlayed = System.currentTimeMillis() - RewindAfterPauseUtils.ELAPSED_TIME_FOR_MEDIUM_REWIND - 1000;
- int position = RewindAfterPauseUtils.calculatePositionWithRewind(ORIGINAL_POSITION, lastPlayed);
-
- assertEquals(ORIGINAL_POSITION - RewindAfterPauseUtils.MEDIUM_REWIND, position);
- }
-
- public void testCalculatePositionWithRewindLongRewind() {
- final int ORIGINAL_POSITION = 30000;
- long lastPlayed = System.currentTimeMillis() - RewindAfterPauseUtils.ELAPSED_TIME_FOR_LONG_REWIND - 1000;
- int position = RewindAfterPauseUtils.calculatePositionWithRewind(ORIGINAL_POSITION, lastPlayed);
-
- assertEquals(ORIGINAL_POSITION - RewindAfterPauseUtils.LONG_REWIND, position);
- }
-
- public void testCalculatePositionWithRewindNegativeNumber() {
- final int ORIGINAL_POSITION = 100;
- long lastPlayed = System.currentTimeMillis() - RewindAfterPauseUtils.ELAPSED_TIME_FOR_LONG_REWIND - 1000;
- int position = RewindAfterPauseUtils.calculatePositionWithRewind(ORIGINAL_POSITION, lastPlayed);
-
- assertEquals(0, position);
- }
-}
diff --git a/app/src/androidTest/java/de/test/antennapod/util/URIUtilTest.java b/app/src/androidTest/java/de/test/antennapod/util/URIUtilTest.java
deleted file mode 100644
index 2cca6b4dc..000000000
--- a/app/src/androidTest/java/de/test/antennapod/util/URIUtilTest.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package de.test.antennapod.util;
-
-import android.test.AndroidTestCase;
-
-import de.danoeh.antennapod.core.util.URIUtil;
-
-/**
- * Test class for URIUtil
- */
-public class URIUtilTest extends AndroidTestCase {
-
- public void testGetURIFromRequestUrlShouldNotEncode() {
- final String testUrl = "http://example.com/this%20is%20encoded";
- assertEquals(testUrl, URIUtil.getURIFromRequestUrl(testUrl).toString());
- }
-
- public void testGetURIFromRequestUrlShouldEncode() {
- final String testUrl = "http://example.com/this is not encoded";
- final String expected = "http://example.com/this%20is%20not%20encoded";
- assertEquals(expected, URIUtil.getURIFromRequestUrl(testUrl).toString());
- }
-}
diff --git a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
index 7e535e12c..4bef14cd9 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
@@ -30,12 +30,12 @@ public class TimelineTest extends InstrumentationTestCase {
context = getInstrumentation().getTargetContext();
}
- private Playable newTestPlayable(List<Chapter> chapters, String shownotes) {
+ private Playable newTestPlayable(List<Chapter> chapters, String shownotes, int duration) {
FeedItem item = new FeedItem(0, "Item", "item-id", "http://example.com/item", new Date(), FeedItem.PLAYED, null);
item.setChapters(chapters);
item.setContentEncoded(shownotes);
FeedMedia media = new FeedMedia(item, "http://example.com/episode", 100, "audio/mp3");
- media.setDuration(Integer.MAX_VALUE);
+ media.setDuration(duration);
item.setMedia(media);
return media;
}
@@ -44,7 +44,17 @@ public class TimelineTest extends InstrumentationTestCase {
final String timeStr = "10:11:12";
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11 + 12 * 1000;
- Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>");
+ Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", Integer.MAX_VALUE);
+ Timeline t = new Timeline(context, p);
+ String res = t.processShownotes(true);
+ checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
+ }
+
+ public void testProcessShownotesAddTimecodeHHMMSSMoreThen24HoursNoChapters() throws Exception {
+ final String timeStr = "25:00:00";
+ final long time = 25 * 60 * 60 * 1000;
+
+ Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", Integer.MAX_VALUE);
Timeline t = new Timeline(context, p);
String res = t.processShownotes(true);
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
@@ -54,17 +64,67 @@ public class TimelineTest extends InstrumentationTestCase {
final String timeStr = "10:11";
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11;
- Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>");
+ Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", Integer.MAX_VALUE);
+ Timeline t = new Timeline(context, p);
+ String res = t.processShownotes(true);
+ checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
+ }
+
+ public void testProcessShownotesAddTimecodeMMSSNoChapters() throws Exception {
+ final String timeStr = "10:11";
+ final long time = 10 * 60 * 1000 + 11 * 1000;
+
+ Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", 11 * 60 * 1000);
Timeline t = new Timeline(context, p);
String res = t.processShownotes(true);
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
}
+ public void testProcessShownotesAddTimecodeHMMSSNoChapters() throws Exception {
+ final String timeStr = "2:11:12";
+ final long time = 2 * 60 * 60 * 1000 + 11 * 60 * 1000 + 12 * 1000;
+
+ Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", Integer.MAX_VALUE);
+ Timeline t = new Timeline(context, p);
+ String res = t.processShownotes(true);
+ checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
+ }
+
+ public void testProcessShownotesAddTimecodeMSSNoChapters() throws Exception {
+ final String timeStr = "1:12";
+ final long time = 60 * 1000 + 12 * 1000;
+
+ Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", 2 * 60 * 1000);
+ Timeline t = new Timeline(context, p);
+ String res = t.processShownotes(true);
+ checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
+ }
+
+ public void testProcessShownotesAddTimecodeMultipleFormatsNoChapters() throws Exception {
+ final String[] timeStrings = new String[]{ "10:12", "1:10:12" };
+
+ Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStrings[0] + " here. Hey look another one " + timeStrings[1] + " here!</p>", 2 * 60 * 60 * 1000);
+ Timeline t = new Timeline(context, p);
+ String res = t.processShownotes(true);
+ checkLinkCorrect(res, new long[]{ 10 * 60 * 1000 + 12 * 1000, 60 * 60 * 1000 + 10 * 60 * 1000 + 12 * 1000 }, timeStrings);
+ }
+
+ public void testProcessShownotesAddTimecodeMultipleShortFormatNoChapters() throws Exception {
+
+ // One of these timecodes fits as HH:MM and one does not so both should be parsed as MM:SS.
+ final String[] timeStrings = new String[]{ "10:12", "2:12" };
+
+ Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStrings[0] + " here. Hey look another one " + timeStrings[1] + " here!</p>", 3 * 60 * 60 * 1000);
+ Timeline t = new Timeline(context, p);
+ String res = t.processShownotes(true);
+ checkLinkCorrect(res, new long[]{ 10 * 60 * 1000 + 12 * 1000, 2 * 60 * 1000 + 12 * 1000 }, timeStrings);
+ }
+
public void testProcessShownotesAddTimecodeParentheses() throws Exception {
final String timeStr = "10:11";
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11;
- Playable p = newTestPlayable(null, "<p> Some test text with a timecode (" + timeStr + ") here.</p>");
+ Playable p = newTestPlayable(null, "<p> Some test text with a timecode (" + timeStr + ") here.</p>", Integer.MAX_VALUE);
Timeline t = new Timeline(context, p);
String res = t.processShownotes(true);
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
@@ -74,7 +134,7 @@ public class TimelineTest extends InstrumentationTestCase {
final String timeStr = "10:11";
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11;
- Playable p = newTestPlayable(null, "<p> Some test text with a timecode [" + timeStr + "] here.</p>");
+ Playable p = newTestPlayable(null, "<p> Some test text with a timecode [" + timeStr + "] here.</p>", Integer.MAX_VALUE);
Timeline t = new Timeline(context, p);
String res = t.processShownotes(true);
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
@@ -84,12 +144,27 @@ public class TimelineTest extends InstrumentationTestCase {
final String timeStr = "10:11";
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11;
- Playable p = newTestPlayable(null, "<p> Some test text with a timecode <" + timeStr + "> here.</p>");
+ Playable p = newTestPlayable(null, "<p> Some test text with a timecode <" + timeStr + "> here.</p>", Integer.MAX_VALUE);
Timeline t = new Timeline(context, p);
String res = t.processShownotes(true);
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
}
+ public void testProcessShownotesAndInvalidTimecode() throws Exception {
+ final String[] timeStrs = new String[] {"2:1", "0:0", "000", "00", "00:000"};
+
+ StringBuilder shownotes = new StringBuilder("<p> Some test text with timecodes ");
+ for (String timeStr : timeStrs) {
+ shownotes.append(timeStr).append(" ");
+ }
+ shownotes.append("here.</p>");
+
+ Playable p = newTestPlayable(null, shownotes.toString(), Integer.MAX_VALUE);
+ Timeline t = new Timeline(context, p);
+ String res = t.processShownotes(true);
+ checkLinkCorrect(res, new long[0], new String[0]);
+ }
+
private void checkLinkCorrect(String res, long[] timecodes, String[] timecodeStr) {
assertNotNull(res);
Document d = Jsoup.parse(res);
diff --git a/app/src/androidTest/java/de/test/antennapod/util/service/download/NanoHTTPD.java b/app/src/androidTest/java/de/test/antennapod/util/service/download/NanoHTTPD.java
index 61ff65809..8d9cedbd1 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/service/download/NanoHTTPD.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/service/download/NanoHTTPD.java
@@ -776,6 +776,7 @@ public abstract class NanoHTTPD {
}
public static final class ResponseException extends Exception {
+ private static final long serialVersionUID = 1L;
private final Response.Status status;
diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/AtomGenerator.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/AtomGenerator.java
index afe15f1b2..8d2408b45 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/AtomGenerator.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/AtomGenerator.java
@@ -56,6 +56,11 @@ public class AtomGenerator implements FeedGenerator{
xml.text(feed.getDescription());
xml.endTag(null, "subtitle");
}
+ if (feed.getImageUrl() != null) {
+ xml.startTag(null, "logo");
+ xml.text(feed.getImageUrl());
+ xml.endTag(null, "logo");
+ }
if (feed.getPaymentLink() != null) {
GeneratorUtil.addPaymentLink(xml, feed.getPaymentLink(), false);
diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/GeneratorUtil.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/GeneratorUtil.java
index 89542d222..9aedbb493 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/GeneratorUtil.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/GeneratorUtil.java
@@ -14,7 +14,6 @@ class GeneratorUtil {
String ns = (withNamespace) ? "http://www.w3.org/2005/Atom" : null;
xml.startTag(ns, "link");
xml.attribute(null, "rel", "payment");
- xml.attribute(null, "title", "Flattr this!");
xml.attribute(null, "href", paymentLink);
xml.attribute(null, "type", "text/html");
xml.endTag(ns, "link");
diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/RSS2Generator.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/RSS2Generator.java
index f2d53799d..5f8b4d18c 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/RSS2Generator.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/RSS2Generator.java
@@ -54,6 +54,13 @@ public class RSS2Generator implements FeedGenerator{
xml.text(feed.getLanguage());
xml.endTag(null, "language");
}
+ if (feed.getImageUrl() != null) {
+ xml.startTag(null, "image");
+ xml.startTag(null, "url");
+ xml.text(feed.getImageUrl());
+ xml.endTag(null, "url");
+ xml.endTag(null, "image");
+ }
if (feed.getPaymentLink() != null) {
GeneratorUtil.addPaymentLink(xml, feed.getPaymentLink(), true);
diff --git a/app/src/free/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java b/app/src/free/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
index 4e2c40885..e096f883f 100644
--- a/app/src/free/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
+++ b/app/src/free/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
@@ -1,13 +1,14 @@
package de.danoeh.antennapod.preferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.fragment.preferences.PlaybackPreferencesFragment;
/**
* Implements functions from PreferenceController that are flavor dependent.
*/
-class PreferenceControllerFlavorHelper {
+public class PreferenceControllerFlavorHelper {
- static void setupFlavoredUI(PreferenceController.PreferenceUI ui) {
+ public static void setupFlavoredUI(PlaybackPreferencesFragment ui) {
ui.findPreference(UserPreferences.PREF_CAST_ENABLED).setEnabled(false);
}
}
diff --git a/app/src/free/play b/app/src/free/play
new file mode 120000
index 000000000..e9d641154
--- /dev/null
+++ b/app/src/free/play
@@ -0,0 +1 @@
+../main/play \ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index cff85e905..73af654e9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,18 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.danoeh.antennapod"
- android:installLocation="auto"
- android:versionCode="1070195"
- android:versionName="1.7.1">
- <!--
- Version code schema:
- "1.2.3-SNAPSHOT" -> 1020300
- "1.2.3-RC4" -> 1020304
- -->
+ android:installLocation="auto">
+
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<supports-screens
android:anyDensity="true"
@@ -38,6 +33,7 @@
android:label="@string/app_name"
android:backupAgent=".core.backup.OpmlBackupAgent"
android:restoreAnyVersion="true"
+ android:usesCleartextTraffic="true"
android:logo="@mipmap/ic_launcher">
<meta-data android:name="com.google.android.gms.car.notification.SmallIcon"
android:resource="@drawable/ic_notification" />
@@ -47,10 +43,13 @@
<activity
android:name=".activity.SplashActivity"
- android:configChanges="keyboardHidden|orientation|screenSize"
- android:launchMode="singleTask"
android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/Theme.AntennaPod.Dark.Splash">
+ <!-- android:launchMode="singleTask" removed for #2948, so that
+ when app is launched again, the app will go to the last activity users use
+ (if the app has been used recently, e.g., last 30 minutes),
+ rather than always go to MainActivity (launched by SplashActivity here) -->
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -144,25 +143,6 @@
<activity android:name=".activity.StorageErrorActivity">
</activity>
<activity
- android:name=".activity.FlattrAuthActivity"
- android:label="@string/flattr_auth_label">
- <intent-filter>
- <action android:name=".activities.FlattrAuthActivity"/>
-
- <category android:name="android.intent.category.DEFAULT"/>
- </intent-filter>
- <intent-filter>
- <action android:name="android.intent.action.VIEW"/>
-
- <category android:name="android.intent.category.DEFAULT"/>
- <category android:name="android.intent.category.BROWSABLE"/>
-
- <data
- android:host="de.danoeh.antennapod"
- android:scheme="flattr4j"/>
- </intent-filter>
- </activity>
- <activity
android:name=".activity.AboutActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/about_pref">
@@ -339,8 +319,7 @@
<activity
android:name=".activity.gpoddernet.GpodnetAuthenticationActivity"
android:configChanges="orientation"
- android:label="@string/gpodnet_auth_label"
- android:screenOrientation="portrait">
+ android:label="@string/gpodnet_auth_label">
<intent-filter>
<action android:name=".activity.gpoddernet.GpodnetAuthenticationActivity"/>
<category android:name="android.intent.category.DEFAULT"/>
@@ -368,18 +347,6 @@
<action android:name="de.danoeh.antennapdsp.intent.SP_APPS_QUERY_FEEDS_RESPONSE"/>
</intent-filter>
</receiver>
- <receiver android:name="de.danoeh.antennapod.core.receiver.AlarmUpdateReceiver">
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED"/>
- </intent-filter>
- <intent-filter>
- <action android:name="android.intent.action.PACKAGE_REPLACED"/>
-
- <data
- android:path="de.danoeh.antennapod"
- android:scheme="package"/>
- </intent-filter>
- </receiver>
<provider
android:authorities="@string/provider_authority"
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
index fde9af16f..cb2f597d6 100644
--- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
+++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
@@ -8,9 +8,11 @@ import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.fonts.FontAwesomeModule;
import com.joanzapata.iconify.fonts.MaterialModule;
+import de.danoeh.antennapod.core.ApCoreEventBusIndex;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.spa.SPAUtil;
+import org.greenrobot.eventbus.EventBus;
/** Main application class. */
public class PodcastApp extends Application {
@@ -58,6 +60,10 @@ public class PodcastApp extends Application {
Iconify.with(new MaterialModule());
SPAUtil.sendSPAppsQueryFeedsIntent(this);
+ EventBus.builder()
+ .addIndex(new ApEventBusIndex())
+ .addIndex(new ApCoreEventBusIndex())
+ .installDefaultEventBus();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java
index ecfdf24b0..1bcdada44 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java
@@ -1,7 +1,9 @@
package de.danoeh.antennapod.activity;
+import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
@@ -46,22 +48,23 @@ public class AboutActivity extends AppCompatActivity {
webViewContainer = findViewById(R.id.webViewContainer);
webView = findViewById(R.id.webViewAbout);
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
- if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
- webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
- }
- webView.setBackgroundColor(Color.TRANSPARENT);
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+ webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
+ webView.setBackgroundColor(Color.TRANSPARENT);
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
- if (!url.startsWith("http")) {
+ if (url.startsWith("http")) {
+ Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ startActivity(browserIntent);
+ return true;
+ } else {
url = url.replace("file:///android_asset/", "");
loadAsset(url);
return true;
}
- return false;
}
});
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
index 67dda01cf..2bcd7a461 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -129,6 +129,7 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
}
UserPreferences.setPlaybackSpeed(newSpeed);
controller.setPlaybackSpeed(Float.parseFloat(newSpeed));
+ onPositionObserverUpdate();
} else {
VariableSpeedDialog.showGetPluginDialog(this);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
index bfa694e5c..26e360bd3 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
@@ -199,8 +199,6 @@ public class FeedInfoActivity extends AppCompatActivity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.support_item).setVisible(
- feed != null && feed.getPaymentLink() != null);
menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null);
menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null &&
IntentUtils.isCallable(this, new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink()))));
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java
index 4698ed90e..fbd19f88a 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java
@@ -1,48 +1,26 @@
package de.danoeh.antennapod.activity;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
+import android.arch.lifecycle.ViewModelProviders;
import android.graphics.LightingColorFilter;
-import android.net.Uri;
import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
-import android.text.Editable;
import android.text.TextUtils;
-import android.text.TextWatcher;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.CheckBox;
-import android.widget.EditText;
import android.widget.ImageView;
-import android.widget.RadioButton;
-import android.widget.Spinner;
import android.widget.TextView;
-
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
-
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
-import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedFilter;
-import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.glide.FastBlurTransformation;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.storage.DownloadRequestException;
-import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
-import io.reactivex.Maybe;
-import io.reactivex.MaybeOnSubscribe;
+import de.danoeh.antennapod.fragment.FeedSettingsFragment;
+import de.danoeh.antennapod.viewmodel.FeedSettingsViewModel;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
@@ -51,59 +29,14 @@ import io.reactivex.schedulers.Schedulers;
* Displays information about a feed.
*/
public class FeedSettingsActivity extends AppCompatActivity {
-
public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
private static final String TAG = "FeedSettingsActivity";
- private boolean autoDeleteChanged = false;
private Feed feed;
-
+ private Disposable disposable;
private ImageView imgvCover;
private TextView txtvTitle;
- private EditText etxtUsername;
- private EditText etxtPassword;
- private EditText etxtFilterText;
- private RadioButton rdoFilterInclude;
- private RadioButton rdoFilterExclude;
- private CheckBox cbxAutoDownload;
- private CheckBox cbxKeepUpdated;
- private Spinner spnAutoDelete;
- private boolean filterInclude = true;
-
- private Disposable disposable;
-
- private boolean authInfoChanged = false;
-
- private final TextWatcher authTextWatcher = new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- authInfoChanged = true;
- }
- };
-
- private boolean filterTextChanged = false;
-
- private final TextWatcher filterTextWatcher = new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- filterTextChanged = true;
- }
- };
+ private ImageView imgvBackground;
+ private TextView txtvAuthorHeader;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -111,142 +44,24 @@ public class FeedSettingsActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.feedsettings);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1);
imgvCover = findViewById(R.id.imgvCover);
txtvTitle = findViewById(R.id.txtvTitle);
- TextView txtvAuthorHeader = findViewById(R.id.txtvAuthor);
- ImageView imgvBackground = findViewById(R.id.imgvBackground);
+ txtvAuthorHeader = findViewById(R.id.txtvAuthor);
+ imgvBackground = findViewById(R.id.imgvBackground);
findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
// https://github.com/bumptech/glide/issues/529
imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
- cbxAutoDownload = findViewById(R.id.cbxAutoDownload);
- cbxKeepUpdated = findViewById(R.id.cbxKeepUpdated);
- spnAutoDelete = findViewById(R.id.spnAutoDelete);
- etxtUsername = findViewById(R.id.etxtUsername);
- etxtPassword = findViewById(R.id.etxtPassword);
- etxtFilterText = findViewById(R.id.etxtEpisodeFilterText);
- rdoFilterInclude = findViewById(R.id.radio_filter_include);
- rdoFilterInclude.setOnClickListener(v -> {
- filterInclude = true;
- filterTextChanged = true;
- });
- rdoFilterExclude = findViewById(R.id.radio_filter_exclude);
- rdoFilterExclude.setOnClickListener(v -> {
- filterInclude = false;
- filterTextChanged = true;
- });
-
- disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
- Feed feed = DBReader.getFeed(feedId);
- if (feed != null) {
- emitter.onSuccess(feed);
- } else {
- emitter.onComplete();
- }
- })
+ long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1);
+ disposable = ViewModelProviders.of(this).get(FeedSettingsViewModel.class).getFeed(feedId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
feed = result;
- FeedPreferences prefs = feed.getPreferences();
- Glide.with(FeedSettingsActivity.this)
- .load(feed.getImageLocation())
- .apply(new RequestOptions()
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate())
- .into(imgvCover);
- Glide.with(FeedSettingsActivity.this)
- .load(feed.getImageLocation())
- .apply(new RequestOptions()
- .placeholder(R.color.image_readability_tint)
- .error(R.color.image_readability_tint)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .transform(new FastBlurTransformation())
- .dontAnimate())
- .into(imgvBackground);
-
- txtvTitle.setText(feed.getTitle());
-
- if (!TextUtils.isEmpty(feed.getAuthor())) {
- txtvAuthorHeader.setText(feed.getAuthor());
- }
-
- cbxAutoDownload.setEnabled(UserPreferences.isEnableAutodownload());
- cbxAutoDownload.setChecked(prefs.getAutoDownload());
- cbxAutoDownload.setOnCheckedChangeListener((compoundButton, checked) -> {
- feed.getPreferences().setAutoDownload(checked);
- feed.savePreferences();
- updateAutoDownloadSettings();
- ApplyToEpisodesDialog dialog = new ApplyToEpisodesDialog(FeedSettingsActivity.this,
- feed, checked);
- dialog.createNewDialog().show();
- });
- cbxKeepUpdated.setChecked(prefs.getKeepUpdated());
- cbxKeepUpdated.setOnCheckedChangeListener((compoundButton, checked) -> {
- feed.getPreferences().setKeepUpdated(checked);
- feed.savePreferences();
- });
- spnAutoDelete.setOnItemSelectedListener(new OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
- FeedPreferences.AutoDeleteAction auto_delete_action;
- switch (parent.getSelectedItemPosition()) {
- case 0:
- auto_delete_action = FeedPreferences.AutoDeleteAction.GLOBAL;
- break;
- case 1:
- auto_delete_action = FeedPreferences.AutoDeleteAction.YES;
- break;
- case 2:
- auto_delete_action = FeedPreferences.AutoDeleteAction.NO;
- break;
- default: // TODO - add exceptions here
- return;
- }
- feed.getPreferences().setAutoDeleteAction(auto_delete_action);// p
- autoDeleteChanged = true;
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // Another interface callback
- }
- });
- spnAutoDelete.setSelection(prefs.getAutoDeleteAction().ordinal());
-
- etxtUsername.setText(prefs.getUsername());
- etxtPassword.setText(prefs.getPassword());
-
- etxtUsername.addTextChangedListener(authTextWatcher);
- etxtPassword.addTextChangedListener(authTextWatcher);
-
- FeedFilter filter = prefs.getFilter();
- if (filter.includeOnly()) {
- etxtFilterText.setText(filter.getIncludeFilter());
- rdoFilterInclude.setChecked(true);
- rdoFilterExclude.setChecked(false);
- filterInclude = true;
- } else if (filter.excludeOnly()) {
- etxtFilterText.setText(filter.getExcludeFilter());
- rdoFilterInclude.setChecked(false);
- rdoFilterExclude.setChecked(true);
- filterInclude = false;
- } else {
- Log.d(TAG, "No filter set");
- rdoFilterInclude.setChecked(false);
- rdoFilterExclude.setChecked(false);
- etxtFilterText.setText("");
- }
- etxtFilterText.addTextChangedListener(filterTextWatcher);
-
- supportInvalidateOptionsMenu();
- updateAutoDownloadSettings();
+ showFragment();
+ showHeader();
}, error -> {
Log.d(TAG, Log.getStackTraceString(error));
finish();
@@ -256,35 +71,42 @@ public class FeedSettingsActivity extends AppCompatActivity {
});
}
- @Override
- protected void onPause() {
- super.onPause();
- if (feed != null) {
- FeedPreferences prefs = feed.getPreferences();
- if (authInfoChanged) {
- Log.d(TAG, "Auth info changed, saving credentials");
- prefs.setUsername(etxtUsername.getText().toString());
- prefs.setPassword(etxtPassword.getText().toString());
- }
- if (filterTextChanged) {
- Log.d(TAG, "Filter info changed, saving...");
- String filterText = etxtFilterText.getText().toString();
- String includeString = "";
- String excludeString = "";
- if (filterInclude) {
- includeString = filterText;
- } else {
- excludeString = filterText;
- }
- prefs.setFilter(new FeedFilter(includeString, excludeString));
- }
- if (authInfoChanged || autoDeleteChanged || filterTextChanged) {
- DBWriter.setFeedPreferences(prefs);
- }
- authInfoChanged = false;
- autoDeleteChanged = false;
- filterTextChanged = false;
+ private void showFragment() {
+ FeedSettingsFragment fragment = new FeedSettingsFragment();
+ fragment.setArguments(getIntent().getExtras());
+
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ FragmentTransaction fragmentTransaction =
+ fragmentManager.beginTransaction();
+ fragmentTransaction.replace(R.id.settings_fragment_container, fragment);
+ fragmentTransaction.commit();
+ }
+
+ private void showHeader() {
+ txtvTitle.setText(feed.getTitle());
+
+ if (!TextUtils.isEmpty(feed.getAuthor())) {
+ txtvAuthorHeader.setText(feed.getAuthor());
}
+
+ Glide.with(FeedSettingsActivity.this)
+ .load(feed.getImageLocation())
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
+ .into(imgvCover);
+ Glide.with(FeedSettingsActivity.this)
+ .load(feed.getImageLocation())
+ .apply(new RequestOptions()
+ .placeholder(R.color.image_readability_tint)
+ .error(R.color.image_readability_tint)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .transform(new FastBlurTransformation())
+ .dontAnimate())
+ .into(imgvBackground);
}
@Override
@@ -296,69 +118,13 @@ public class FeedSettingsActivity extends AppCompatActivity {
}
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.feedinfo, menu);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.support_item).setVisible(
- feed != null && feed.getPaymentLink() != null);
- menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null);
- menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null &&
- IntentUtils.isCallable(this, new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink()))));
- return true;
- }
-
- @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
default:
- try {
- return FeedMenuHandler.onOptionsItemClicked(this, item, feed);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
- e.getMessage());
- }
return super.onOptionsItemSelected(item);
}
}
-
- private void updateAutoDownloadSettings() {
- if (feed != null && feed.getPreferences() != null) {
- boolean enabled = feed.getPreferences().getAutoDownload() && UserPreferences.isEnableAutodownload();
- rdoFilterInclude.setEnabled(enabled);
- rdoFilterExclude.setEnabled(enabled);
- etxtFilterText.setEnabled(enabled);
- }
- }
-
- private static class ApplyToEpisodesDialog extends ConfirmationDialog {
-
- private final Feed feed;
- private final boolean autoDownload;
-
- ApplyToEpisodesDialog(Context context, Feed feed, boolean autoDownload) {
- super(context, R.string.auto_download_apply_to_items_title,
- R.string.auto_download_apply_to_items_message);
- this.feed = feed;
- this.autoDownload = autoDownload;
- setPositiveText(R.string.yes);
- setNegativeText(R.string.no);
- }
-
- @Override
- public void onConfirmButtonPressed(DialogInterface dialog) {
- DBWriter.setFeedsItemsAutoDownload(feed, autoDownload);
- }
- }
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FlattrAuthActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FlattrAuthActivity.java
deleted file mode 100644
index 2b4384a02..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/FlattrAuthActivity.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-import org.shredzone.flattr4j.exception.FlattrException;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
-
-/** Guides the user through the authentication process */
-
-public class FlattrAuthActivity extends AppCompatActivity {
- private static final String TAG = "FlattrAuthActivity";
-
- private TextView txtvExplanation;
- private Button butAuthenticate;
- private Button butReturn;
-
- private boolean authSuccessful;
-
- private static FlattrAuthActivity singleton;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- singleton = this;
- authSuccessful = false;
- if (BuildConfig.DEBUG) Log.d(TAG, "Activity created");
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.flattr_auth);
- txtvExplanation = findViewById(R.id.txtvExplanation);
- butAuthenticate = findViewById(R.id.but_authenticate);
- butReturn = findViewById(R.id.but_return_home);
-
- butReturn.setOnClickListener(v -> {
- Intent intent = new Intent(FlattrAuthActivity.this, MainActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- });
-
- butAuthenticate.setOnClickListener(v -> {
- try {
- FlattrUtils.startAuthProcess(FlattrAuthActivity.this);
- } catch (FlattrException e) {
- e.printStackTrace();
- }
- });
- }
-
- public static FlattrAuthActivity getInstance() {
- return singleton;
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (BuildConfig.DEBUG) Log.d(TAG, "Activity resumed");
- Uri uri = getIntent().getData();
- if (uri != null) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Received uri");
- FlattrUtils.handleCallback(this, uri);
- }
- }
-
- public void handleAuthenticationSuccess() {
- authSuccessful = true;
- txtvExplanation.setText(R.string.flattr_auth_success);
- butAuthenticate.setEnabled(false);
- butReturn.setVisibility(View.VISIBLE);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- return true;
- }
-
-
-
- @Override
- protected void onPause() {
- super.onPause();
- if (authSuccessful) {
- finish();
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- if (authSuccessful) {
- Intent intent = new Intent(this, PreferenceActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- } else {
- finish();
- }
- break;
- default:
- return false;
- }
- return true;
- }
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
index e6c9c37cc..9795c1240 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
@@ -23,6 +23,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileChannel;
+import java.util.Arrays;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -109,9 +110,14 @@ public class ImportExportActivity extends AppCompatActivity {
}
private void restoreFrom(Uri inputUri) {
- File currentDB = getDatabasePath(PodDBAdapter.DATABASE_NAME);
InputStream inputStream = null;
try {
+ if (!validateDB(inputUri)) {
+ displayBadFileDialog();
+ return;
+ }
+
+ File currentDB = getDatabasePath(PodDBAdapter.DATABASE_NAME);
inputStream = getContentResolver().openInputStream(inputUri);
FileUtils.copyInputStreamToFile(inputStream, currentDB);
displayImportSuccessDialog();
@@ -123,6 +129,28 @@ public class ImportExportActivity extends AppCompatActivity {
}
}
+ private static final byte[] SQLITE3_MAGIC = "SQLite format 3\0".getBytes();
+ private boolean validateDB(Uri inputUri) throws IOException {
+ try (InputStream inputStream = getContentResolver().openInputStream(inputUri)) {
+ byte[] magicBuf = new byte[SQLITE3_MAGIC.length];
+ if (inputStream.read(magicBuf) == magicBuf.length) {
+ return Arrays.equals(SQLITE3_MAGIC, magicBuf);
+ }
+ }
+
+ return false;
+ }
+
+ private void displayBadFileDialog() {
+ AlertDialog.Builder d = new AlertDialog.Builder(ImportExportActivity.this);
+ d.setMessage(R.string.import_bad_file)
+ .setCancelable(false)
+ .setPositiveButton(android.R.string.ok, ((dialogInterface, i) -> {
+ // do nothing
+ }))
+ .show();
+ }
+
private void displayImportSuccessDialog() {
AlertDialog.Builder d = new AlertDialog.Builder(ImportExportActivity.this);
d.setMessage(R.string.import_ok);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
index 9f4fbe271..728019196 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -31,6 +31,7 @@ import android.widget.Toast;
import com.bumptech.glide.Glide;
+import de.danoeh.antennapod.preferences.PreferenceUpgrader;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
@@ -43,7 +44,6 @@ import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.MessageEvent;
import de.danoeh.antennapod.core.event.ProgressEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
-import de.danoeh.antennapod.core.event.ServiceEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
@@ -55,7 +55,6 @@ import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.Flavors;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
import de.danoeh.antennapod.dialog.RatingDialog;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
@@ -68,11 +67,13 @@ import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
import de.danoeh.antennapod.fragment.QueueFragment;
import de.danoeh.antennapod.fragment.SubscriptionFragment;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
-import de.greenrobot.event.EventBus;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
/**
* The activity that is shown when the user launches the app.
@@ -206,8 +207,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
transaction.commit();
checkFirstLaunch();
- NotificationUtils.createChannels(this);
- UserPreferences.restartUpdateAlarm(false);
+ PreferenceUpgrader.checkUpgrades(this);
}
private void saveLastNavFragment(String tag) {
@@ -474,7 +474,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
protected void onResume() {
super.onResume();
StorageUtils.checkStorageAvailability(this);
- AutoUpdateManager.checkShouldRefreshFeeds(getApplicationContext());
Intent intent = getIntent();
if (intent.hasExtra(EXTRA_FEED_ID) ||
@@ -579,17 +578,17 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
switch(item.getItemId()) {
- case R.id.mark_all_seen_item:
- ConfirmationDialog markAllSeenConfirmationDialog = new ConfirmationDialog(this,
- R.string.mark_all_seen_label,
- R.string.mark_all_seen_confirmation_msg) {
+ case R.id.remove_all_new_flags_item:
+ ConfirmationDialog removeAllNewFlagsConfirmationDialog = new ConfirmationDialog(this,
+ R.string.remove_all_new_flags_label,
+ R.string.remove_all_new_flags_confirmation_msg) {
@Override
public void onConfirmButtonPressed(DialogInterface dialog) {
dialog.dismiss();
- DBWriter.markFeedSeen(feed.getId());
+ DBWriter.removeFeedNewFlag(feed.getId());
}
};
- markAllSeenConfirmationDialog.createNewDialog().show();
+ removeAllNewFlagsConfirmationDialog.createNewDialog().show();
return true;
case R.id.mark_all_read_item:
ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(this,
@@ -765,6 +764,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
+ @Subscribe
public void onEvent(QueueEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
// we are only interested in the number of queue items, not download status or position
@@ -776,15 +776,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
loadData();
}
- public void onEventMainThread(ServiceEvent event) {
- Log.d(TAG, "onEvent(" + event + ")");
- switch(event.action) {
- case SERVICE_STARTED:
- externalPlayerFragment.connectToPlaybackService();
- break;
- }
- }
-
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(ProgressEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
switch(event.action) {
@@ -803,6 +795,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(MessageEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
View parentLayout = findViewById(R.id.drawer_layout);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 1cddaa655..3946400a4 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -38,7 +38,6 @@ import com.joanzapata.iconify.fonts.FontAwesomeIcons;
import java.util.Locale;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.event.ServiceEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
@@ -56,6 +55,7 @@ import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.Supplier;
+import de.danoeh.antennapod.core.util.TimeSpeedConverter;
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
@@ -79,6 +79,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
private static final String PREFS = "MediaPlayerActivityPreferences";
private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft";
private static final int REQUEST_CODE_STORAGE = 42;
+ private static final float PLAYBACK_SPEED_STEP = 0.05f;
+ private static final float DEFAULT_MIN_PLAYBACK_SPEED = 0.5f;
+ private static final float DEFAULT_MAX_PLAYBACK_SPEED = 2.5f;
PlaybackController controller;
@@ -235,6 +238,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
StorageUtils.checkStorageAvailability(this);
getWindow().setFormat(PixelFormat.TRANSPARENT);
+ setupGUI();
}
@Override
@@ -274,11 +278,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
@Override
protected void onStart() {
super.onStart();
- if (controller != null) {
- controller.release();
- }
controller = newPlaybackController();
- setupGUI();
+ controller.init();
loadMediaInfo();
onPositionObserverUpdate();
}
@@ -329,11 +330,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
Playable media = controller.getMedia();
boolean isFeedMedia = media != null && (media instanceof FeedMedia);
- menu.findItem(R.id.support_item).setVisible(isFeedMedia && media.getPaymentLink() != null &&
- ((FeedMedia) media).getItem() != null &&
- ((FeedMedia) media).getItem().getFlattrStatus().flattrable()
- );
-
boolean hasWebsiteLink = ( getWebsiteLinkWithFallback(media) != null );
menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink);
@@ -469,7 +465,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
final Button butDecSpeed = (Button) dialog.findViewById(R.id.butDecSpeed);
butDecSpeed.setOnClickListener(v -> {
if(controller != null && controller.canSetPlaybackSpeed()) {
- barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 2);
+ barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 1);
} else {
VariableSpeedDialog.showGetPluginDialog(this);
}
@@ -477,7 +473,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
final Button butIncSpeed = (Button) dialog.findViewById(R.id.butIncSpeed);
butIncSpeed.setOnClickListener(v -> {
if(controller != null && controller.canSetPlaybackSpeed()) {
- barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 2);
+ barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 1);
} else {
VariableSpeedDialog.showGetPluginDialog(this);
}
@@ -492,12 +488,20 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
UserPreferences.setPlaybackSpeed(String.valueOf(currentSpeed));
}
+ String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
+ final float minPlaybackSpeed = availableSpeeds.length > 1 ?
+ Float.valueOf(availableSpeeds[0]) : DEFAULT_MIN_PLAYBACK_SPEED;
+ float maxPlaybackSpeed = availableSpeeds.length > 1 ?
+ Float.valueOf(availableSpeeds[availableSpeeds.length - 1]) : DEFAULT_MAX_PLAYBACK_SPEED;
+ int progressMax = (int) ((maxPlaybackSpeed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP);
+ barPlaybackSpeed.setMax(progressMax);
+
txtvPlaybackSpeed.setText(String.format("%.2fx", currentSpeed));
barPlaybackSpeed.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(controller != null && controller.canSetPlaybackSpeed()) {
- float playbackSpeed = (progress + 10) / 20.0f;
+ float playbackSpeed = progress * PLAYBACK_SPEED_STEP + minPlaybackSpeed;
controller.setPlaybackSpeed(playbackSpeed);
String speedPref = String.format(Locale.US, "%.2f", playbackSpeed);
UserPreferences.setPlaybackSpeed(speedPref);
@@ -505,7 +509,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
txtvPlaybackSpeed.setText(speedStr);
} else if(fromUser) {
float speed = Float.valueOf(UserPreferences.getPlaybackSpeed());
- barPlaybackSpeed.post(() -> barPlaybackSpeed.setProgress((int) (20 * speed) - 10));
+ barPlaybackSpeed.post(() -> barPlaybackSpeed.setProgress(
+ (int) ((speed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP)));
}
}
@@ -520,7 +525,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
- barPlaybackSpeed.setProgress((int) (20 * currentSpeed) - 10);
+ barPlaybackSpeed.setProgress((int) ((currentSpeed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP));
final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
barLeftVolume.setProgress(UserPreferences.getLeftVolumePercentage());
@@ -534,6 +539,22 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
stereoToMono.setText(stereoToMono.getText() + " [" + sonicOnly + "]");
}
+ if (UserPreferences.useExoplayer()) {
+ barRightVolume.setEnabled(false);
+ }
+
+ final CheckBox skipSilence = (CheckBox) dialog.findViewById(R.id.skipSilence);
+ skipSilence.setChecked(UserPreferences.isSkipSilence());
+ if (!UserPreferences.useExoplayer()) {
+ skipSilence.setEnabled(false);
+ String exoplayerOnly = getString(R.string.exoplayer_only);
+ skipSilence.setText(skipSilence.getText() + " [" + exoplayerOnly + "]");
+ }
+ skipSilence.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ UserPreferences.setSkipSilence(isChecked);
+ controller.setSkipSilence(isChecked);
+ });
+
barLeftVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
@@ -577,11 +598,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
Uri uri = Uri.parse(getWebsiteLinkWithFallback(media));
startActivity(new Intent(Intent.ACTION_VIEW, uri));
break;
- case R.id.support_item:
- if (media instanceof FeedMedia) {
- DBTasks.flattrItemIfLoggedIn(this, ((FeedMedia) media).getItem());
- }
- break;
case R.id.share_link_item:
if (media instanceof FeedMedia) {
ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem());
@@ -633,18 +649,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
super.onResume();
Log.d(TAG, "onResume()");
StorageUtils.checkStorageAvailability(this);
- if (controller != null) {
- controller.init();
- }
- }
-
- public void onEventMainThread(ServiceEvent event) {
- Log.d(TAG, "onEvent(" + event + ")");
- if (event.action == ServiceEvent.Action.SERVICE_STARTED) {
- if (controller != null) {
- controller.init();
- }
- }
}
/**
@@ -661,8 +665,11 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
if (controller == null || txtvPosition == null || txtvLength == null) {
return;
}
- int currentPosition = controller.getPosition();
- int duration = controller.getDuration();
+
+ int currentPosition = TimeSpeedConverter.convert(controller.getPosition());
+ int duration = TimeSpeedConverter.convert(controller.getDuration());
+ int remainingTime = TimeSpeedConverter.convert(
+ controller.getDuration() - controller.getPosition());
Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition));
if (currentPosition == PlaybackService.INVALID_TIME ||
duration == PlaybackService.INVALID_TIME) {
@@ -671,7 +678,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
}
txtvPosition.setText(Converter.getDurationStringLong(currentPosition));
if (showTimeLeft) {
- txtvLength.setText("-" + Converter.getDurationStringLong(duration - currentPosition));
+ txtvLength.setText("-" + Converter.getDurationStringLong(remainingTime));
} else {
txtvLength.setText(Converter.getDurationStringLong(duration));
}
@@ -819,9 +826,13 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
String length;
if (showTimeLeft) {
- length = "-" + Converter.getDurationStringLong(media.getDuration() - media.getPosition());
+ int remainingTime = TimeSpeedConverter.convert(
+ media.getDuration() - media.getPosition());
+
+ length = "-" + Converter.getDurationStringLong(remainingTime);
} else {
- length = Converter.getDurationStringLong(media.getDuration());
+ int duration = TimeSpeedConverter.convert(media.getDuration());
+ length = Converter.getDurationStringLong(duration);
}
txtvLength.setText(length);
@@ -924,7 +935,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser, txtvPosition);
if (showTimeLeft && prog != 0) {
int duration = controller.getDuration();
- String length = "-" + Converter.getDurationStringLong(duration - (int) (prog * duration));
+ int timeLeft = TimeSpeedConverter.convert(duration - (int) (prog * duration));
+ String length = "-" + Converter.getDurationStringLong(timeLeft);
txtvLength.setText(length);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
index a2389dabd..4fec1cfc5 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
@@ -7,7 +7,6 @@ import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
-import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
@@ -34,7 +33,6 @@ import com.viewpagerindicator.CirclePageIndicator;
import java.util.List;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.adapter.ChaptersListAdapter;
import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
@@ -48,7 +46,6 @@ import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
@@ -62,11 +59,13 @@ import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
import de.danoeh.antennapod.fragment.QueueFragment;
import de.danoeh.antennapod.fragment.SubscriptionFragment;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
-import de.greenrobot.event.EventBus;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
/**
* Activity for playing files that do not require a video surface.
@@ -102,19 +101,12 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
private ActionBarDrawerToggle drawerToggle;
private int mPosition = -1;
- private Playable media;
private ViewPager pager;
private MediaplayerInfoPagerAdapter pagerAdapter;
private Disposable disposable;
@Override
- protected void onPause() {
- super.onPause();
- EventBus.getDefault().unregister(this);
- }
-
- @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportPostponeEnterTransition();
@@ -124,13 +116,11 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop()");
- if(pagerAdapter != null) {
- pagerAdapter.setController(null);
- }
if (disposable != null) {
disposable.dispose();
}
EventDistributor.getInstance().unregister(contentUpdate);
+ EventBus.getDefault().unregister(this);
saveCurrentFragment();
}
@@ -180,15 +170,8 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
}
@Override
- protected void onResume() {
- super.onResume();
- if(pagerAdapter != null && controller != null && controller.getMedia() != media) {
- media = controller.getMedia();
- pagerAdapter.onMediaChanged(media);
- pagerAdapter.setController(controller);
- }
- AutoUpdateManager.checkShouldRefreshFeeds(getApplicationContext());
-
+ protected void onStart() {
+ super.onStart();
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
loadData();
@@ -278,8 +261,8 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
butCastDisconnect = findViewById(R.id.butCastDisconnect);
pager = findViewById(R.id.pager);
- pagerAdapter = new MediaplayerInfoPagerAdapter(getSupportFragmentManager(), media);
- pagerAdapter.setController(controller);
+ pager.setOffscreenPageLimit(3);
+ pagerAdapter = new MediaplayerInfoPagerAdapter(getSupportFragmentManager());
pager.setAdapter(pagerAdapter);
CirclePageIndicator pageIndicator = findViewById(R.id.page_indicator);
pageIndicator.setViewPager(pager);
@@ -290,37 +273,6 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
}
@Override
- protected void onPositionObserverUpdate() {
- super.onPositionObserverUpdate();
- notifyMediaPositionChanged();
- }
-
- @Override
- protected boolean loadMediaInfo() {
- if (!super.loadMediaInfo()) {
- return false;
- }
- if(controller != null && controller.getMedia() != media) {
- media = controller.getMedia();
- pagerAdapter.onMediaChanged(media);
- }
- return true;
- }
-
- private void notifyMediaPositionChanged() {
- if(pagerAdapter == null) {
- return;
- }
- ChaptersFragment chaptersFragment = pagerAdapter.getChaptersFragment();
- if(chaptersFragment != null) {
- ChaptersListAdapter adapter = (ChaptersListAdapter) chaptersFragment.getListAdapter();
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
- }
- }
-
- @Override
protected void onReloadNotification(int notificationCode) {
if (notificationCode == PlaybackService.EXTRA_CODE_VIDEO) {
Log.d(TAG, "ReloadNotification received, switching to Videoplayer now");
@@ -387,8 +339,8 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
}
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
switch(item.getItemId()) {
- case R.id.mark_all_seen_item:
- DBWriter.markFeedSeen(feed.getId());
+ case R.id.remove_all_new_flags_item:
+ DBWriter.removeFeedNewFlag(feed.getId());
return true;
case R.id.mark_all_read_item:
DBWriter.markFeedRead(feed.getId());
@@ -483,6 +435,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(MessageEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
View parentLayout = findViewById(R.id.drawer_layout);
@@ -566,50 +519,11 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
}
};
- public interface MediaplayerInfoContentFragment {
- void onMediaChanged(Playable media);
- }
-
private static class MediaplayerInfoPagerAdapter extends FragmentStatePagerAdapter {
-
private static final String TAG = "MPInfoPagerAdapter";
- private Playable media;
- private PlaybackController controller;
-
- public MediaplayerInfoPagerAdapter(FragmentManager fm, Playable media) {
+ public MediaplayerInfoPagerAdapter(FragmentManager fm) {
super(fm);
- this.media = media;
- }
-
- private CoverFragment coverFragment;
- private ItemDescriptionFragment itemDescriptionFragment;
- private ChaptersFragment chaptersFragment;
-
- public void onMediaChanged(Playable media) {
- Log.d(TAG, "media changing to " + ((media != null) ? media.getEpisodeTitle() : "null"));
- this.media = media;
- if(coverFragment != null) {
- coverFragment.onMediaChanged(media);
- }
- if(itemDescriptionFragment != null) {
- itemDescriptionFragment.onMediaChanged(media);
- }
- if(chaptersFragment != null) {
- chaptersFragment.onMediaChanged(media);
- }
- }
-
- public void setController(PlaybackController controller) {
- this.controller = controller;
- if(chaptersFragment != null) {
- chaptersFragment.setController(controller);
- }
- }
-
- @Nullable
- public ChaptersFragment getChaptersFragment() {
- return chaptersFragment;
}
@Override
@@ -617,21 +531,11 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
Log.d(TAG, "getItem(" + position + ")");
switch (position) {
case POS_COVER:
- if(coverFragment == null) {
- coverFragment = CoverFragment.newInstance(media);
- }
- return coverFragment;
+ return new CoverFragment();
case POS_DESCR:
- if(itemDescriptionFragment == null) {
- itemDescriptionFragment = ItemDescriptionFragment.newInstance(media, true, true);
- }
- return itemDescriptionFragment;
+ return new ItemDescriptionFragment();
case POS_CHAPTERS:
- if(chaptersFragment == null) {
- chaptersFragment = ChaptersFragment.newInstance(media);
- chaptersFragment.setController(controller);
- }
- return chaptersFragment;
+ return new ChaptersFragment();
default:
return null;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
index 73da9a834..ea7687bc9 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -4,7 +4,10 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.graphics.LightingColorFilter;
+import android.os.Build;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBar;
@@ -27,9 +30,13 @@ import android.widget.Spinner;
import android.widget.TextView;
import com.bumptech.glide.Glide;
-
import com.bumptech.glide.request.RequestOptions;
+
+import de.danoeh.antennapod.core.glide.FastBlurTransformation;
import org.apache.commons.lang3.StringUtils;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@@ -57,15 +64,16 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.syndication.handler.FeedHandler;
+import de.danoeh.antennapod.core.syndication.handler.FeedHandlerResult;
import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeException;
import de.danoeh.antennapod.core.util.DownloadError;
import de.danoeh.antennapod.core.util.FileNameGenerator;
+import de.danoeh.antennapod.core.util.Optional;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.URLChecker;
import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer;
import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
-import de.greenrobot.event.EventBus;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -120,6 +128,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
};
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
setSubscribeButtonState(feed);
@@ -140,7 +149,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
StorageUtils.checkStorageAvailability(this);
- final String feedUrl;
+ String feedUrl = null;
if (getIntent().hasExtra(ARG_FEEDURL)) {
feedUrl = getIntent().getStringExtra(ARG_FEEDURL);
} else if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND)
@@ -150,16 +159,23 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
if (actionBar != null) {
actionBar.setTitle(R.string.add_feed_label);
}
- } else {
- throw new IllegalArgumentException("Activity must be started with feedurl argument!");
}
- Log.d(TAG, "Activity was started with url " + feedUrl);
- setLoadingLayout();
- if (savedInstanceState == null) {
- startFeedDownload(feedUrl, null, null);
+ if (feedUrl == null) {
+ Log.e(TAG, "feedUrl is null.");
+ new AlertDialog.Builder(OnlineFeedViewActivity.this).
+ setNeutralButton(android.R.string.ok,
+ (dialog, which) -> finish()).
+ setTitle(R.string.error_label).
+ setMessage(R.string.null_value_podcast_error).create().show();
} else {
- startFeedDownload(feedUrl, savedInstanceState.getString("username"), savedInstanceState.getString("password"));
+ Log.d(TAG, "Activity was started with url " + feedUrl);
+ setLoadingLayout();
+ if (savedInstanceState == null) {
+ startFeedDownload(feedUrl, null, null);
+ } else {
+ startFeedDownload(feedUrl, savedInstanceState.getString("username"), savedInstanceState.getString("password"));
+ }
}
}
@@ -183,24 +199,19 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
@Override
- protected void onResume() {
- super.onResume();
+ protected void onStart() {
+ super.onStart();
isPaused = false;
EventDistributor.getInstance().register(listener);
EventBus.getDefault().register(this);
}
@Override
- protected void onPause() {
- super.onPause();
+ protected void onStop() {
+ super.onStop();
isPaused = true;
EventDistributor.getInstance().unregister(listener);
EventBus.getDefault().unregister(this);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
if (downloader != null && !downloader.isFinished()) {
downloader.cancel();
}
@@ -280,12 +291,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
error -> Log.e(TAG, Log.getStackTraceString(error)));
}
- private void checkDownloadResult(DownloadStatus status) {
- if (status == null) {
- Log.wtf(TAG, "DownloadStatus returned by Downloader was null");
- finish();
- return;
- }
+ private void checkDownloadResult(@NonNull DownloadStatus status) {
if (status.isCancelled()) {
return;
}
@@ -312,30 +318,12 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
Log.d(TAG, "Parsing feed");
- parser = Observable.fromCallable(() -> {
- FeedHandler handler = new FeedHandler();
- try {
- return handler.parseFeed(feed);
- } catch (UnsupportedFeedtypeException e) {
- Log.d(TAG, "Unsupported feed type detected");
- if ("html".equalsIgnoreCase(e.getRootElement())) {
- showFeedDiscoveryDialog(new File(feed.getFile_url()), feed.getDownload_url());
- return null;
- } else {
- throw e;
- }
- } catch (Exception e) {
- Log.e(TAG, Log.getStackTraceString(e));
- throw e;
- } finally {
- boolean rc = new File(feed.getFile_url()).delete();
- Log.d(TAG, "Deleted feed source file. Result: " + rc);
- }
- })
+ parser = Observable.fromCallable(this::doParseFeed)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- if(result != null) {
+ .subscribe(optionalResult -> {
+ if(optionalResult.isPresent()) {
+ FeedHandlerResult result = optionalResult.get();
beforeShowFeedInformation(result.feed);
showFeedInformation(result.feed, result.alternateFeedUrls);
}
@@ -347,6 +335,33 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
});
}
+ @NonNull
+ private Optional<FeedHandlerResult> doParseFeed() throws Exception {
+ FeedHandler handler = new FeedHandler();
+ try {
+ return Optional.of(handler.parseFeed(feed));
+ } catch (UnsupportedFeedtypeException e) {
+ Log.d(TAG, "Unsupported feed type detected");
+ if ("html".equalsIgnoreCase(e.getRootElement())) {
+ boolean dialogShown = showFeedDiscoveryDialog(new File(feed.getFile_url()), feed.getDownload_url());
+ if (dialogShown) {
+ return Optional.empty();
+ } else {
+ Log.d(TAG, "Supplied feed is an HTML web page that has no references to any feed");
+ throw e;
+ }
+ } else {
+ throw e;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ throw e;
+ } finally {
+ boolean rc = new File(feed.getFile_url()).delete();
+ Log.d(TAG, "Deleted feed source file. Result: " + rc);
+ }
+ }
+
/**
* Called after the feed has been downloaded and parsed and before showFeedInformation is called.
* This method is executed on a background thread
@@ -381,6 +396,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
this.selectedDownloadUrl = feed.getDownload_url();
EventDistributor.getInstance().register(listener);
ListView listView = findViewById(R.id.listview);
+ listView.setSelector(android.R.color.transparent);
LayoutInflater inflater = LayoutInflater.from(this);
View header = inflater.inflate(R.layout.onlinefeedview_header, listView, false);
listView.addHeaderView(header);
@@ -388,6 +404,10 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
listView.setAdapter(new FeedItemlistDescriptionAdapter(this, 0, feed.getItems()));
ImageView cover = header.findViewById(R.id.imgvCover);
+ ImageView headerBackground = header.findViewById(R.id.imgvBackground);
+ header.findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
+ header.findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
+ headerBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
TextView title = header.findViewById(R.id.txtvTitle);
TextView author = header.findViewById(R.id.txtvAuthor);
TextView description = header.findViewById(R.id.txtvDescription);
@@ -405,6 +425,15 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
.fitCenter()
.dontAnimate())
.into(cover);
+ Glide.with(this)
+ .load(feed.getImageUrl())
+ .apply(new RequestOptions()
+ .placeholder(R.color.image_readability_tint)
+ .error(R.color.image_readability_tint)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .transform(new FastBlurTransformation())
+ .dontAnimate())
+ .into(headerBackground);
}
title.setText(feed.getTitle());
@@ -433,6 +462,17 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
});
+ final int MAX_LINES_COLLAPSED = 10;
+ description.setMaxLines(MAX_LINES_COLLAPSED);
+ description.setOnClickListener(v -> {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
+ && description.getMaxLines() > MAX_LINES_COLLAPSED) {
+ description.setMaxLines(MAX_LINES_COLLAPSED);
+ } else {
+ description.setMaxLines(2000);
+ }
+ });
+
if (alternateFeedUrls.isEmpty()) {
spAlternateUrls.setVisibility(View.GONE);
} else {
@@ -530,21 +570,25 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
}
- private void showFeedDiscoveryDialog(File feedFile, String baseUrl) {
+ /**
+ *
+ * @return true if a FeedDiscoveryDialog is shown, false otherwise (e.g., due to no feed found).
+ */
+ private boolean showFeedDiscoveryDialog(File feedFile, String baseUrl) {
FeedDiscoverer fd = new FeedDiscoverer();
final Map<String, String> urlsMap;
try {
urlsMap = fd.findLinks(feedFile, baseUrl);
if (urlsMap == null || urlsMap.isEmpty()) {
- return;
+ return false;
}
} catch (IOException e) {
e.printStackTrace();
- return;
+ return false;
}
if (isPaused || isFinishing()) {
- return;
+ return false;
}
final List<String> titles = new ArrayList<>();
@@ -580,6 +624,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
dialog = ab.show();
});
+ return true;
}
private class FeedViewAuthenticationDialog extends AuthenticationDialog {
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
index a63d3b735..158e3b7a4 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
@@ -25,7 +25,6 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
private static final int CHOOSE_OPML_FILE = 1;
- private Intent intentPickAction;
private Intent intentGetContentAction;
@Override
@@ -36,50 +35,30 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.opml_import);
- final TextView txtvHeaderExplanation1 = findViewById(R.id.txtvHeadingExplanation1);
- final TextView txtvExplanation1 = findViewById(R.id.txtvExplanation1);
- final TextView txtvHeaderExplanation2 = findViewById(R.id.txtvHeadingExplanation2);
- final TextView txtvExplanation2 = findViewById(R.id.txtvExplanation2);
- final TextView txtvHeaderExplanation3 = findViewById(R.id.txtvHeadingExplanation3);
+ final TextView txtvHeaderExplanation = findViewById(R.id.txtvHeadingExplanation);
+ final TextView txtvExplanation = findViewById(R.id.txtvExplanation);
+ final TextView txtvHeaderExplanationOpenWith = findViewById(R.id.txtvHeadingExplanationOpenWith);
Button butChooseFilesystem = findViewById(R.id.butChooseFileFromFilesystem);
- butChooseFilesystem.setOnClickListener(v -> chooseFileFromFilesystem());
-
- Button butChooseExternal = findViewById(R.id.butChooseFileFromExternal);
- butChooseExternal.setOnClickListener(v -> chooseFileFromExternal());
+ butChooseFilesystem.setOnClickListener(v -> chooseFileFromExternal());
int nextOption = 1;
String optionLabel = getString(R.string.opml_import_option);
- intentPickAction = new Intent(Intent.ACTION_PICK);
-
- if(!IntentUtils.isCallable(getApplicationContext(), intentPickAction)) {
- intentPickAction.setData(null);
- if(!IntentUtils.isCallable(getApplicationContext(), intentPickAction)) {
- txtvHeaderExplanation1.setVisibility(View.GONE);
- txtvExplanation1.setVisibility(View.GONE);
- findViewById(R.id.divider1).setVisibility(View.GONE);
- butChooseFilesystem.setVisibility(View.GONE);
- }
- }
- if(txtvExplanation1.getVisibility() == View.VISIBLE) {
- txtvHeaderExplanation1.setText(String.format(optionLabel, nextOption));
- nextOption++;
- }
-
intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT);
intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE);
intentGetContentAction.setType("*/*");
- if(!IntentUtils.isCallable(getApplicationContext(), intentGetContentAction)) {
- txtvHeaderExplanation2.setVisibility(View.GONE);
- txtvExplanation2.setVisibility(View.GONE);
- findViewById(R.id.divider2).setVisibility(View.GONE);
- butChooseExternal.setVisibility(View.GONE);
- } else {
- txtvHeaderExplanation2.setText(String.format(optionLabel, nextOption));
+
+ if (IntentUtils.isCallable(getApplicationContext(), intentGetContentAction)) {
+ txtvHeaderExplanation.setText(String.format(optionLabel, nextOption));
nextOption++;
+ } else {
+ txtvHeaderExplanation.setVisibility(View.GONE);
+ txtvExplanation.setVisibility(View.GONE);
+ findViewById(R.id.divider).setVisibility(View.GONE);
+ butChooseFilesystem.setVisibility(View.GONE);
}
- txtvHeaderExplanation3.setText(String.format(optionLabel, nextOption));
+ txtvHeaderExplanationOpenWith.setText(String.format(optionLabel, nextOption));
}
@Override
@@ -106,18 +85,6 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
}
}
- /*
- * Creates an implicit intent to launch a file manager which lets
- * the user choose a specific OPML-file to import from.
- */
- private void chooseFileFromFilesystem() {
- try {
- startActivityForResult(intentPickAction, CHOOSE_OPML_FILE);
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "No activity found. Should never happen...");
- }
- }
-
private void chooseFileFromExternal() {
try {
startActivityForResult(intentGetContentAction, CHOOSE_OPML_FILE);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
index 452e91bd3..7e0ae173f 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -1,12 +1,9 @@
package de.danoeh.antennapod.activity;
-import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
-import android.support.v7.preference.PreferenceScreen;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
@@ -15,56 +12,24 @@ import android.widget.FrameLayout;
import com.bytehamster.lib.preferencesearch.SearchPreferenceResult;
import com.bytehamster.lib.preferencesearch.SearchPreferenceResultListener;
-import java.lang.ref.WeakReference;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.preferences.PreferenceController;
+import de.danoeh.antennapod.fragment.preferences.AutoDownloadPreferencesFragment;
+import de.danoeh.antennapod.fragment.preferences.GpodderPreferencesFragment;
+import de.danoeh.antennapod.fragment.preferences.IntegrationsPreferencesFragment;
+import de.danoeh.antennapod.fragment.preferences.MainPreferencesFragment;
+import de.danoeh.antennapod.fragment.preferences.NetworkPreferencesFragment;
+import de.danoeh.antennapod.fragment.preferences.PlaybackPreferencesFragment;
+import de.danoeh.antennapod.fragment.preferences.StoragePreferencesFragment;
+import de.danoeh.antennapod.fragment.preferences.UserInterfacePreferencesFragment;
/**
* PreferenceActivity for API 11+. In order to change the behavior of the preference UI, see
* PreferenceController.
*/
public class PreferenceActivity extends AppCompatActivity implements SearchPreferenceResultListener {
-
- public static final String PARAM_RESOURCE = "resource";
- private static WeakReference<PreferenceActivity> instance;
- private PreferenceController preferenceController;
- private final PreferenceController.PreferenceUI preferenceUI = new PreferenceController.PreferenceUI() {
- private PreferenceFragmentCompat fragment;
-
- @Override
- public void setFragment(PreferenceFragmentCompat fragment) {
- this.fragment = fragment;
- }
-
- @Override
- public PreferenceFragmentCompat getFragment() {
- return fragment;
- }
-
- @Override
- public Preference findPreference(CharSequence key) {
- return fragment.findPreference(key);
- }
-
- @Override
- public PreferenceScreen getPreferenceScreen() {
- return fragment.getPreferenceScreen();
- }
-
- @Override
- public AppCompatActivity getActivity() {
- return PreferenceActivity.this;
- }
- };
-
@Override
protected void onCreate(Bundle savedInstanceState) {
- // This must be the FIRST thing we do, otherwise other code may not have the
- // reference it needs
- instance = new WeakReference<>(this);
-
setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
@@ -73,38 +38,63 @@ public class PreferenceActivity extends AppCompatActivity implements SearchPrefe
ab.setDisplayHomeAsUpEnabled(true);
}
- // set up layout
FrameLayout root = new FrameLayout(this);
root.setId(R.id.content);
root.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
setContentView(root);
- // we need to create the PreferenceController before the MainFragment
- // since the MainFragment depends on the preferenceController already being created
- preferenceController = new PreferenceController(preferenceUI);
+ getSupportFragmentManager().beginTransaction().replace(R.id.content, new MainPreferencesFragment()).commit();
- showPreferenceScreen(R.xml.preferences, false);
}
- private void showPreferenceScreen(int screen, boolean addHistory) {
- PreferenceFragmentCompat prefFragment = new MainFragment();
- preferenceUI.setFragment(prefFragment);
- Bundle args = new Bundle();
- args.putInt(PARAM_RESOURCE, screen);
- prefFragment.setArguments(args);
- if (addHistory) {
- getSupportFragmentManager().beginTransaction().replace(R.id.content, prefFragment)
- .addToBackStack(getString(PreferenceController.getTitleOfPage(screen))).commit();
- } else {
- getSupportFragmentManager().beginTransaction().replace(R.id.content, prefFragment).commit();
+ private PreferenceFragmentCompat getPreferenceScreen(int screen) {
+ PreferenceFragmentCompat prefFragment = null;
+
+ if (screen == R.xml.preferences_user_interface) {
+ prefFragment = new UserInterfacePreferencesFragment();
+ } else if (screen == R.xml.preferences_integrations) {
+ prefFragment = new IntegrationsPreferencesFragment();
+ } else if (screen == R.xml.preferences_network) {
+ prefFragment = new NetworkPreferencesFragment();
+ } else if (screen == R.xml.preferences_storage) {
+ prefFragment = new StoragePreferencesFragment();
+ } else if (screen == R.xml.preferences_autodownload) {
+ prefFragment = new AutoDownloadPreferencesFragment();
+ } else if (screen == R.xml.preferences_gpodder) {
+ prefFragment = new GpodderPreferencesFragment();
+ } else if (screen == R.xml.preferences_playback) {
+ prefFragment = new PlaybackPreferencesFragment();
}
+ return prefFragment;
}
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- preferenceController.onActivityResult(requestCode, resultCode, data);
+ public static int getTitleOfPage(int preferences) {
+ switch (preferences) {
+ case R.xml.preferences_network:
+ return R.string.network_pref;
+ case R.xml.preferences_autodownload:
+ return R.string.pref_automatic_download_title;
+ case R.xml.preferences_playback:
+ return R.string.playback_pref;
+ case R.xml.preferences_storage:
+ return R.string.storage_pref;
+ case R.xml.preferences_user_interface:
+ return R.string.user_interface_label;
+ case R.xml.preferences_integrations:
+ return R.string.integrations_label;
+ case R.xml.preferences_gpodder:
+ return R.string.gpodnet_main_label;
+ default:
+ return R.string.settings_label;
+ }
+ }
+
+ public PreferenceFragmentCompat openScreen(int screen) {
+ PreferenceFragmentCompat fragment = getPreferenceScreen(screen);
+ getSupportFragmentManager().beginTransaction().replace(R.id.content, fragment)
+ .addToBackStack(getString(getTitleOfPage(screen))).commit();
+ return fragment;
}
@Override
@@ -115,72 +105,20 @@ public class PreferenceActivity extends AppCompatActivity implements SearchPrefe
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
- finish();
- } else {
- getSupportFragmentManager().popBackStack();
- }
- return true;
- default:
- return false;
+ if (item.getItemId() == android.R.id.home) {
+ if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
+ finish();
+ } else {
+ getSupportFragmentManager().popBackStack();
+ }
+ return true;
}
+ return false;
}
@Override
public void onSearchResultClicked(SearchPreferenceResult result) {
- showPreferenceScreen(result.getResourceFile(), true);
- result.highlight(preferenceUI.getFragment());
- }
-
- public static class MainFragment extends PreferenceFragmentCompat {
- private int screen;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setRetainInstance(true);
- }
-
- @Override
- public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
- screen = getArguments().getInt(PARAM_RESOURCE);
- addPreferencesFromResource(screen);
- PreferenceActivity activity = instance.get();
- if (activity != null && activity.preferenceController != null) {
- activity.preferenceUI.setFragment(this);
- activity.preferenceController.onCreate(screen);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- PreferenceActivity activity = instance.get();
- if(activity != null && activity.preferenceController != null) {
- activity.setTitle(PreferenceController.getTitleOfPage(screen));
- activity.preferenceUI.setFragment(this);
- activity.preferenceController.onResume(screen);
- }
- }
-
- @Override
- public void onPause() {
- PreferenceActivity activity = instance.get();
- if (screen == R.xml.preferences_gpodder) {
- activity.preferenceController.unregisterGpodnet();
- }
- super.onPause();
- }
-
- @Override
- public void onStop() {
- PreferenceActivity activity = instance.get();
- if (screen == R.xml.preferences_storage) {
- activity.preferenceController.unsubscribeExportSubscription();
- }
- super.onStop();
- }
+ PreferenceFragmentCompat fragment = openScreen(result.getResourceFile());
+ result.highlight(fragment);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
index 8fcdb4371..2d7898d5b 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
@@ -25,6 +25,8 @@ import android.widget.ViewFlipper;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
@@ -102,10 +104,6 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- }
-
private void setupLoginView(View view) {
final EditText username = view.findViewById(R.id.etxtUsername);
final EditText password = view.findViewById(R.id.etxtPassword);
@@ -123,6 +121,11 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
final String usernameStr = username.getText().toString();
final String passwordStr = password.getText().toString();
+ if (usernameHasUnwantedChars(usernameStr)) {
+ txtvError.setText(R.string.gpodnetsync_username_characters_error);
+ txtvError.setVisibility(View.VISIBLE);
+ return;
+ }
if (BuildConfig.DEBUG) Log.d(TAG, "Checking login credentials");
AsyncTask<GpodnetService, Void, Void> authTask = new AsyncTask<GpodnetService, Void, Void>() {
@@ -395,4 +398,10 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
finish();
}
}
+
+ private boolean usernameHasUnwantedChars(String username) {
+ Pattern special = Pattern.compile("[!@#$%&*()+=|<>?{}\\[\\]~]");
+ Matcher containsUnwantedChars = special.matcher(username);
+ return containsUnwantedChars.find();
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java
deleted file mode 100644
index e6b42efcb..000000000
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.util.LongList;
-
-interface ActionButtonCallback {
- /** Is called when the action button of a list item has been pressed. */
- void onActionButtonPressed(FeedItem item, LongList queueIds);
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
deleted file mode 100644
index a915692d1..000000000
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.view.View;
-import android.widget.ImageButton;
-
-import org.apache.commons.lang3.Validate;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.storage.DownloadRequester;
-
-/**
- * Utility methods for the action button that is displayed on the right hand side
- * of a listitem.
- */
-class ActionButtonUtils {
-
- private final int[] labels;
- private final TypedArray drawables;
- private final Context context;
-
- public ActionButtonUtils(Context context) {
- Validate.notNull(context);
-
- this.context = context.getApplicationContext();
- drawables = context.obtainStyledAttributes(new int[] {
- R.attr.av_play,
- R.attr.navigation_cancel,
- R.attr.av_download,
- R.attr.av_pause,
- R.attr.navigation_accept,
- R.attr.content_new
- });
- labels = new int[] {
- R.string.play_label,
- R.string.cancel_download_label,
- R.string.download_label,
- R.string.mark_read_label,
- R.string.add_to_queue_label
- };
- }
-
- /**
- * Sets the displayed bitmap and content description of the given
- * action button so that it matches the state of the FeedItem.
- */
- @SuppressWarnings("ResourceType")
- public void configureActionButton(ImageButton butSecondary, FeedItem item, boolean isInQueue) {
- Validate.isTrue(butSecondary != null && item != null, "butSecondary or item was null");
-
- final FeedMedia media = item.getMedia();
- if (media != null) {
- final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
- if (!media.isDownloaded()) {
- if (isDownloadingMedia) {
- // item is being downloaded
- butSecondary.setVisibility(View.VISIBLE);
- butSecondary.setImageDrawable(drawables.getDrawable(1));
- butSecondary.setContentDescription(context.getString(labels[1]));
- } else {
- // item is not downloaded and not being downloaded
- if(DefaultActionButtonCallback.userAllowedMobileDownloads() ||
- !DefaultActionButtonCallback.userChoseAddToQueue() || isInQueue) {
- butSecondary.setVisibility(View.VISIBLE);
- butSecondary.setImageDrawable(drawables.getDrawable(2));
- butSecondary.setContentDescription(context.getString(labels[2]));
- } else {
- // mobile download not allowed yet, item is not in queue and user chose add to queue
- butSecondary.setVisibility(View.VISIBLE);
- butSecondary.setImageDrawable(drawables.getDrawable(5));
- butSecondary.setContentDescription(context.getString(labels[4]));
- }
- }
- } else {
- // item is downloaded
- butSecondary.setVisibility(View.VISIBLE);
- if (media.isCurrentlyPlaying()) {
- butSecondary.setImageDrawable(drawables.getDrawable(3));
- } else {
- butSecondary.setImageDrawable(drawables.getDrawable(0));
- }
- butSecondary.setContentDescription(context.getString(labels[0]));
- }
- } else {
- if (item.isPlayed()) {
- butSecondary.setVisibility(View.INVISIBLE);
- } else {
- butSecondary.setVisibility(View.VISIBLE);
- butSecondary.setImageDrawable(drawables.getDrawable(4));
- butSecondary.setContentDescription(context.getString(labels[3]));
- }
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java
index 5c58d00f2..315b3a173 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java
@@ -49,7 +49,7 @@ class AdapterUtils {
} else if (!media.isDownloaded()) {
if (media.getSize() > 0) {
txtvPos.setText(Converter.byteToString(media.getSize()));
- } else if(NetworkUtils.isDownloadAllowed() && !media.checkedOnSizeButUnknown()) {
+ } else if(NetworkUtils.isEpisodeHeadDownloadAllowed() && !media.checkedOnSizeButUnknown()) {
txtvPos.setText("{fa-spinner}");
Iconify.addIcons(txtvPos);
NetworkUtils.getFeedMediaSizeObservable(media)
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
index 0b2b81edb..2eff33339 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
@@ -26,6 +26,7 @@ import java.lang.ref.WeakReference;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.storage.DownloadRequester;
@@ -46,8 +47,6 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
private final WeakReference<MainActivity> mainActivityRef;
private final ItemAccess itemAccess;
- private final ActionButtonCallback actionButtonCallback;
- private final ActionButtonUtils actionButtonUtils;
private final boolean showOnlyNewEpisodes;
private FeedItem selectedItem;
@@ -57,13 +56,10 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
public AllEpisodesRecycleAdapter(MainActivity mainActivity,
ItemAccess itemAccess,
- ActionButtonCallback actionButtonCallback,
boolean showOnlyNewEpisodes) {
super();
this.mainActivityRef = new WeakReference<>(mainActivity);
this.itemAccess = itemAccess;
- this.actionButtonUtils = new ActionButtonUtils(mainActivity);
- this.actionButtonCallback = actionButtonCallback;
this.showOnlyNewEpisodes = showOnlyNewEpisodes;
playingBackGroundColor = ThemeUtils.getColorFromAttr(mainActivity, R.attr.currently_playing_background);
@@ -134,7 +130,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
} else if (media.getSize() > 0) {
holder.txtvDuration.setText(Converter.byteToString(media.getSize()));
- } else if(NetworkUtils.isDownloadAllowed() && !media.checkedOnSizeButUnknown()) {
+ } else if(NetworkUtils.isEpisodeHeadDownloadAllowed() && !media.checkedOnSizeButUnknown()) {
holder.txtvDuration.setText("{fa-spinner}");
Iconify.addIcons(holder.txtvDuration);
NetworkUtils.getFeedMediaSizeObservable(media)
@@ -186,10 +182,11 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.queueStatus.setVisibility(View.INVISIBLE);
}
- actionButtonUtils.configureActionButton(holder.butSecondary, item, isInQueue);
+ ItemActionButton actionButton = ItemActionButton.forItem(item, isInQueue);
+ actionButton.configure(holder.butSecondary, mainActivityRef.get());
+
holder.butSecondary.setFocusable(false);
holder.butSecondary.setTag(item);
- holder.butSecondary.setOnClickListener(secondaryActionListener);
new CoverLoader(mainActivityRef.get())
.withUri(item.getImageLocation())
@@ -215,14 +212,6 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
return itemAccess.getCount();
}
- private final View.OnClickListener secondaryActionListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- FeedItem item = (FeedItem) v.getTag();
- actionButtonCallback.onActionButtonPressed(item, itemAccess.getQueueIds());
- }
- };
-
public class Holder extends RecyclerView.ViewHolder
implements View.OnClickListener,
View.OnCreateContextMenuListener,
@@ -290,7 +279,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
};
FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, null);
- contextMenuInterface.setItemVisibility(R.id.mark_as_seen_item, item.isNew());
+ contextMenuInterface.setItemVisibility(R.id.remove_new_flag_item, item.isNew());
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
index 54ecdae77..79dc1f96e 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
@@ -66,7 +66,7 @@ public class CoverLoader {
options = options.error(errorResource);
}
- RequestBuilder builder = Glide.with(activity)
+ RequestBuilder<Drawable> builder = Glide.with(activity)
.load(uri)
.apply(options);
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
new file mode 100644
index 000000000..909fd6459
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
@@ -0,0 +1,148 @@
+package de.danoeh.antennapod.adapter;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RadioButton;
+import android.widget.TextView;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.StorageUtils;
+import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
+import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
+
+
+public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.ViewHolder> {
+ private final ChooseDataFolderDialog.RunnableWithString selectionHandler;
+ private final String currentPath;
+ private final List<StoragePath> entries;
+ private final String freeSpaceString;
+ private Dialog dialog;
+
+ public DataFolderAdapter(Context context, ChooseDataFolderDialog.RunnableWithString selectionHandler) {
+ this.entries = getStorageEntries(context);
+ this.currentPath = getCurrentPath();
+ this.selectionHandler = selectionHandler;
+ this.freeSpaceString = context.getString(R.string.choose_data_directory_available_space);
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ View entryView = inflater.inflate(R.layout.choose_data_folder_dialog_entry, parent, false);
+ return new ViewHolder(entryView);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ StoragePath storagePath = entries.get(position);
+ String freeSpace = Converter.byteToString(storagePath.getAvailableSpace());
+ String totalSpace = Converter.byteToString(storagePath.getTotalSpace());
+
+ holder.path.setText(storagePath.getShortPath());
+ holder.size.setText(String.format(freeSpaceString, freeSpace, totalSpace));
+ holder.progressBar.setProgress(storagePath.getUsagePercentage());
+ holder.root.setOnClickListener((View v) -> selectAndDismiss(storagePath));
+ holder.radioButton.setOnClickListener((View v) -> selectAndDismiss(storagePath));
+ if (storagePath.getFullPath().equals(currentPath)) {
+ holder.radioButton.toggle();
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ if (currentPath == null) {
+ return 0;
+ } else {
+ return entries.size();
+ }
+ }
+
+ public void setDialog(Dialog dialog) {
+ this.dialog = dialog;
+ }
+
+ private String getCurrentPath() {
+ File dataFolder = UserPreferences.getDataFolder(null);
+ if (dataFolder != null) return dataFolder.getAbsolutePath();
+ return null;
+ }
+
+ private List<StoragePath> getStorageEntries(Context context) {
+ File[] mediaDirs = ContextCompat.getExternalFilesDirs(context, null);
+ final List<StoragePath> entries = new ArrayList<>(mediaDirs.length);
+ for (File dir : mediaDirs) {
+ if (isNotWritable(dir)) continue;
+
+ entries.add(new StoragePath(dir.getAbsolutePath()));
+ }
+ return entries;
+ }
+
+ private boolean isNotWritable(File dir) {
+ return dir == null || !dir.exists() || !dir.canRead() || !dir.canWrite();
+ }
+
+ private void selectAndDismiss(StoragePath storagePath) {
+ selectionHandler.run(storagePath.getFullPath());
+ dialog.dismiss();
+ }
+
+ class ViewHolder extends RecyclerView.ViewHolder {
+ private View root;
+ private TextView path;
+ private TextView size;
+ private RadioButton radioButton;
+ private MaterialProgressBar progressBar;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+ root = itemView.findViewById(R.id.root);
+ path = itemView.findViewById(R.id.path);
+ size = itemView.findViewById(R.id.size);
+ radioButton = itemView.findViewById(R.id.radio_button);
+ progressBar = itemView.findViewById(R.id.used_space);
+ }
+ }
+
+ class StoragePath {
+ private final String path;
+
+ StoragePath(String path) {
+ this.path = path;
+ }
+
+ String getShortPath() {
+ int prefixIndex = path.indexOf("Android");
+ return (prefixIndex > 0) ? path.substring(0, prefixIndex) : path;
+ }
+
+ String getFullPath() {
+ return this.path;
+ }
+
+ long getAvailableSpace() {
+ return StorageUtils.getFreeSpaceAvailable(path);
+ }
+
+ long getTotalSpace() {
+ return StorageUtils.getTotalSpaceAvailable(path);
+ }
+
+ int getUsagePercentage() {
+ return 100 - (int) (100 * getAvailableSpace() / (float) getTotalSpace());
+ }
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
deleted file mode 100644
index 1286d9dc7..000000000
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
+++ /dev/null
@@ -1,139 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.content.Intent;
-import android.widget.Toast;
-
-import com.afollestad.materialdialogs.MaterialDialog;
-
-import org.apache.commons.lang3.Validate;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBTasks;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.storage.DownloadRequestException;
-import de.danoeh.antennapod.core.storage.DownloadRequester;
-import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.LongList;
-import de.danoeh.antennapod.core.util.NetworkUtils;
-import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
-
-/**
- * Default implementation of an ActionButtonCallback
- */
-public class DefaultActionButtonCallback implements ActionButtonCallback {
-
- private static final String TAG = "DefaultActionButtonCallback";
-
- private final Context context;
-
- private static final int TEN_MINUTES_IN_MILLIS = 60 * 1000 * 10;
-
- // remember timestamp when user allowed downloading via mobile connection
- private static long allowMobileDownloadsTimestamp;
- private static long onlyAddToQueueTimeStamp;
-
- public DefaultActionButtonCallback(Context context) {
- Validate.notNull(context);
- this.context = context;
- }
-
- public static boolean userAllowedMobileDownloads() {
- return System.currentTimeMillis() - allowMobileDownloadsTimestamp < TEN_MINUTES_IN_MILLIS;
- }
-
- public static boolean userChoseAddToQueue() {
- return System.currentTimeMillis() - onlyAddToQueueTimeStamp < TEN_MINUTES_IN_MILLIS;
- }
-
- @Override
- public void onActionButtonPressed(final FeedItem item, final LongList queueIds) {
-
- if (item.hasMedia()) {
- final FeedMedia media = item.getMedia();
- boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
- if (!isDownloading && !media.isDownloaded()) {
- if (NetworkUtils.isDownloadAllowed() || userAllowedMobileDownloads()) {
- try {
- DBTasks.downloadFeedItems(context, item);
- Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage());
- }
- } else if(userChoseAddToQueue() && !queueIds.contains(item.getId())) {
- DBWriter.addQueueItem(context, item);
- Toast.makeText(context, R.string.added_to_queue_label, Toast.LENGTH_SHORT).show();
- } else {
- confirmMobileDownload(context, item);
- }
- } else if (isDownloading) {
- DownloadRequester.getInstance().cancelDownload(context, media);
- if(UserPreferences.isEnableAutodownload()) {
- DBWriter.setFeedItemAutoDownload(media.getItem(), false);
- Toast.makeText(context, R.string.download_canceled_autodownload_enabled_msg, Toast.LENGTH_LONG).show();
- } else {
- Toast.makeText(context, R.string.download_canceled_msg, Toast.LENGTH_LONG).show();
- }
- } else { // media is downloaded
- if (media.isCurrentlyPlaying()) {
- new PlaybackServiceStarter(context, media)
- .startWhenPrepared(true)
- .shouldStream(false)
- .start();
- IntentUtils.sendLocalBroadcast(context, PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
- } else if (media.isCurrentlyPaused()) {
- new PlaybackServiceStarter(context, media)
- .startWhenPrepared(true)
- .shouldStream(false)
- .start();
- IntentUtils.sendLocalBroadcast(context, PlaybackService.ACTION_RESUME_PLAY_CURRENT_EPISODE);
- } else {
- DBTasks.playMedia(context, media, false, true, false);
- }
- }
- } else {
- if (!item.isPlayed()) {
- DBWriter.markItemPlayed(item, FeedItem.PLAYED, true);
- }
- }
- }
-
- private void confirmMobileDownload(final Context context, final FeedItem item) {
- MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
- builder
- .title(R.string.confirm_mobile_download_dialog_title)
- .content(R.string.confirm_mobile_download_dialog_message)
- .positiveText(context.getText(R.string.confirm_mobile_download_dialog_enable_temporarily))
- .onPositive((dialog, which) -> {
- allowMobileDownloadsTimestamp = System.currentTimeMillis();
- try {
- DBTasks.downloadFeedItems(context, item);
- Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage());
- }
- });
- LongList queueIds = DBReader.getQueueIDList();
- if(!queueIds.contains(item.getId())) {
- builder
- .content(R.string.confirm_mobile_download_dialog_message_not_in_queue)
- .neutralText(R.string.confirm_mobile_download_dialog_only_add_to_queue)
- .onNeutral((dialog, which) -> {
- onlyAddToQueueTimeStamp = System.currentTimeMillis();
- DBWriter.addQueueItem(context, item);
- Toast.makeText(context, R.string.added_to_queue_label, Toast.LENGTH_SHORT).show();
- });
- }
- builder.show();
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java
new file mode 100644
index 000000000..df7ec46e0
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java
@@ -0,0 +1,76 @@
+package de.danoeh.antennapod.adapter;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FeedDiscoverAdapter extends BaseAdapter {
+
+ private final WeakReference<MainActivity> mainActivityRef;
+ private final List<PodcastSearchResult> data = new ArrayList<>();
+
+ public FeedDiscoverAdapter(MainActivity mainActivity) {
+ this.mainActivityRef = new WeakReference<>(mainActivity);
+ }
+
+ public void updateData(List<PodcastSearchResult> newData) {
+ data.clear();
+ data.addAll(newData);
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return data.size();
+ }
+
+ @Override
+ public PodcastSearchResult getItem(int position) {
+ return data.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+
+ if (convertView == null) {
+ convertView = View.inflate(mainActivityRef.get(), R.layout.quick_feed_discovery_item, null);
+ holder = new Holder();
+ holder.imageView = convertView.findViewById(R.id.discovery_cover);
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+
+
+ final PodcastSearchResult podcast = getItem(position);
+ Glide.with(mainActivityRef.get())
+ .load(podcast.imageUrl)
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .fitCenter()
+ .dontAnimate())
+ .into(holder.imageView);
+
+ return convertView;
+ }
+
+ static class Holder {
+ ImageView imageView;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
index 738a0a636..a365b1b2e 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
@@ -7,7 +7,6 @@ import android.support.v4.content.ContextCompat;
import android.text.Layout;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.BaseAdapter;
@@ -18,6 +17,7 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
@@ -31,14 +31,12 @@ import de.danoeh.antennapod.core.util.ThemeUtils;
*/
public class FeedItemlistAdapter extends BaseAdapter {
- private final ActionButtonCallback callback;
private final ItemAccess itemAccess;
private final Context context;
private final boolean showFeedtitle;
private final int selectedItemIndex;
/** true if played items should be made partially transparent */
private final boolean makePlayedItemsTransparent;
- private final ActionButtonUtils actionButtonUtils;
private static final int SELECTION_NONE = -1;
@@ -47,16 +45,13 @@ public class FeedItemlistAdapter extends BaseAdapter {
public FeedItemlistAdapter(Context context,
ItemAccess itemAccess,
- ActionButtonCallback callback,
boolean showFeedtitle,
boolean makePlayedItemsTransparent) {
super();
- this.callback = callback;
this.context = context;
this.itemAccess = itemAccess;
this.showFeedtitle = showFeedtitle;
this.selectedItemIndex = SELECTION_NONE;
- this.actionButtonUtils = new ActionButtonUtils(context);
this.makePlayedItemsTransparent = makePlayedItemsTransparent;
playingBackGroundColor = ThemeUtils.getColorFromAttr(context, R.attr.currently_playing_background);
@@ -199,10 +194,11 @@ public class FeedItemlistAdapter extends BaseAdapter {
}
}
- actionButtonUtils.configureActionButton(holder.butAction, item, isInQueue);
+ ItemActionButton actionButton = ItemActionButton.forItem(item, isInQueue);
+ actionButton.configure(holder.butAction, context);
+
holder.butAction.setFocusable(false);
holder.butAction.setTag(item);
- holder.butAction.setOnClickListener(butActionListener);
} else {
convertView.setVisibility(View.GONE);
@@ -210,14 +206,6 @@ public class FeedItemlistAdapter extends BaseAdapter {
return convertView;
}
- private final OnClickListener butActionListener = new OnClickListener() {
- @Override
- public void onClick(View v) {
- FeedItem item = (FeedItem) v.getTag();
- callback.onActionButtonPressed(item, itemAccess.getQueueIds());
- }
- };
-
static class Holder {
LinearLayout container;
TextView title;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
index fbf6b804a..be8e52cfc 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -8,6 +8,7 @@ import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.preference.PreferenceManager;
import android.support.v7.app.AlertDialog;
+import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -214,10 +215,17 @@ public class NavListAdapter extends BaseAdapter
}
if (v != null && viewType != VIEW_TYPE_SECTION_DIVIDER) {
TextView txtvTitle = v.findViewById(R.id.txtvTitle);
+ TypedValue typedValue = new TypedValue();
+
if (position == itemAccess.getSelectedItemIndex()) {
txtvTitle.setTypeface(null, Typeface.BOLD);
+ v.getContext().getTheme().resolveAttribute(de.danoeh.antennapod.core.R.attr.drawer_activated_color, typedValue, true);
+ v.setBackgroundResource(typedValue.resourceId);
+
} else {
txtvTitle.setTypeface(null, Typeface.NORMAL);
+ v.getContext().getTheme().resolveAttribute(de.danoeh.antennapod.core.R.attr.nav_drawer_background, typedValue, true);
+ v.setBackgroundResource(typedValue.resourceId);
}
}
return v;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
index df8cafb9d..382abfb32 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.adapter;
+import android.content.Context;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
@@ -22,8 +23,6 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.request.RequestOptions;
import com.joanzapata.iconify.Iconify;
import org.apache.commons.lang3.ArrayUtils;
@@ -32,9 +31,9 @@ import java.lang.ref.WeakReference;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
@@ -54,8 +53,6 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
private final WeakReference<MainActivity> mainActivity;
private final ItemAccess itemAccess;
- private final ActionButtonCallback actionButtonCallback;
- private final ActionButtonUtils actionButtonUtils;
private final ItemTouchHelper itemTouchHelper;
private boolean locked;
@@ -67,13 +64,10 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
public QueueRecyclerAdapter(MainActivity mainActivity,
ItemAccess itemAccess,
- ActionButtonCallback actionButtonCallback,
ItemTouchHelper itemTouchHelper) {
super();
this.mainActivity = new WeakReference<>(mainActivity);
this.itemAccess = itemAccess;
- this.actionButtonUtils = new ActionButtonUtils(mainActivity);
- this.actionButtonCallback = actionButtonCallback;
this.itemTouchHelper = itemTouchHelper;
locked = UserPreferences.isQueueLocked();
@@ -258,7 +252,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
} else {
if(media.getSize() > 0) {
progressLeft.setText(Converter.byteToString(media.getSize()));
- } else if(NetworkUtils.isDownloadAllowed() && !media.checkedOnSizeButUnknown()) {
+ } else if(NetworkUtils.isEpisodeHeadDownloadAllowed() && !media.checkedOnSizeButUnknown()) {
progressLeft.setText("{fa-spinner}");
Iconify.addIcons(progressLeft);
NetworkUtils.getFeedMediaSizeObservable(media)
@@ -287,10 +281,11 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
}
}
- actionButtonUtils.configureActionButton(butSecondary, item, true);
+ ItemActionButton actionButton = ItemActionButton.forItem(item, true);
+ actionButton.configure(butSecondary, mainActivity.get());
+
butSecondary.setFocusable(false);
butSecondary.setTag(item);
- butSecondary.setOnClickListener(secondaryActionListener);
new CoverLoader(mainActivity.get())
.withUri(item.getImageLocation())
@@ -302,15 +297,6 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
}
- private final View.OnClickListener secondaryActionListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- FeedItem item = (FeedItem) v.getTag();
- actionButtonCallback.onActionButtonPressed(item, itemAccess.getQueueIds());
- }
- };
-
-
public interface ItemAccess {
FeedItem getItem(int position);
int getCount();
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java
new file mode 100644
index 000000000..3299db3ab
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java
@@ -0,0 +1,32 @@
+package de.danoeh.antennapod.adapter.actionbutton;
+
+import android.content.Context;
+import android.support.annotation.AttrRes;
+import android.support.annotation.StringRes;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.FeedItem;
+
+class AddToQueueActionButton extends ItemActionButton {
+
+ AddToQueueActionButton(FeedItem item) {
+ super(item);
+ }
+
+ @Override
+ @StringRes
+ public int getLabel() {
+ return R.string.add_to_queue_label;
+ }
+
+ @Override
+ @AttrRes
+ public int getDrawable() {
+ return R.attr.content_new;
+ }
+
+ @Override
+ public void onClick(Context context) {
+ MobileDownloadHelper.confirmMobileDownload(context, item);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java
new file mode 100644
index 000000000..1275a799b
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java
@@ -0,0 +1,44 @@
+package de.danoeh.antennapod.adapter.actionbutton;
+
+import android.content.Context;
+import android.support.annotation.AttrRes;
+import android.support.annotation.StringRes;
+import android.widget.Toast;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.core.storage.DownloadRequester;
+
+class CancelDownloadActionButton extends ItemActionButton {
+
+ CancelDownloadActionButton(FeedItem item) {
+ super(item);
+ }
+
+ @Override
+ @StringRes
+ public int getLabel() {
+ return R.string.cancel_download_label;
+ }
+
+ @Override
+ @AttrRes
+ public int getDrawable() {
+ return R.attr.navigation_cancel;
+ }
+
+ @Override
+ public void onClick(Context context) {
+ FeedMedia media = item.getMedia();
+ DownloadRequester.getInstance().cancelDownload(context, media);
+ if (UserPreferences.isEnableAutodownload()) {
+ DBWriter.setFeedItemAutoDownload(media.getItem(), false);
+ Toast.makeText(context, R.string.download_canceled_autodownload_enabled_msg, Toast.LENGTH_LONG).show();
+ } else {
+ Toast.makeText(context, R.string.download_canceled_msg, Toast.LENGTH_LONG).show();
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java
new file mode 100644
index 000000000..c1559528e
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java
@@ -0,0 +1,74 @@
+package de.danoeh.antennapod.adapter.actionbutton;
+
+import android.content.Context;
+import android.support.annotation.AttrRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
+import android.widget.Toast;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.core.storage.DownloadRequestException;
+import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.NetworkUtils;
+
+class DownloadActionButton extends ItemActionButton {
+ private boolean isInQueue;
+
+ DownloadActionButton(FeedItem item, boolean isInQueue) {
+ super(item);
+ this.isInQueue = isInQueue;
+ }
+
+ @Override
+ @StringRes
+ public int getLabel() {
+ return R.string.download_label;
+ }
+
+ @Override
+ @AttrRes
+ public int getDrawable() {
+ return R.attr.av_download;
+ }
+
+ @Override
+ public void onClick(Context context) {
+ final FeedMedia media = item.getMedia();
+ if (media == null || shouldNotDownload(media)) {
+ return;
+ }
+
+ if (NetworkUtils.isEpisodeDownloadAllowed() || MobileDownloadHelper.userAllowedMobileDownloads()) {
+ downloadEpisode(context);
+ } else if (MobileDownloadHelper.userChoseAddToQueue() && !isInQueue) {
+ addEpisodeToQueue(context);
+ } else {
+ MobileDownloadHelper.confirmMobileDownload(context, item);
+ }
+ }
+
+ private boolean shouldNotDownload(@NonNull FeedMedia media) {
+ boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
+ return isDownloading || media.isDownloaded();
+ }
+
+ private void addEpisodeToQueue(Context context) {
+ DBWriter.addQueueItem(context, item);
+ Toast.makeText(context, R.string.added_to_queue_label, Toast.LENGTH_SHORT).show();
+ }
+
+ private void downloadEpisode(Context context) {
+ try {
+ DBTasks.downloadFeedItems(context, item);
+ Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage());
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java
new file mode 100644
index 000000000..da5ebf6e1
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java
@@ -0,0 +1,63 @@
+package de.danoeh.antennapod.adapter.actionbutton;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.annotation.AttrRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
+import android.view.View;
+import android.widget.ImageButton;
+
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.storage.DownloadRequester;
+
+public abstract class ItemActionButton {
+ FeedItem item;
+
+ ItemActionButton(FeedItem item) {
+ this.item = item;
+ }
+
+ @StringRes
+ abstract public int getLabel();
+
+ @AttrRes
+ abstract public int getDrawable();
+
+ abstract public void onClick(Context context);
+
+ public int getVisibility() {
+ return View.VISIBLE;
+ }
+
+ @NonNull
+ public static ItemActionButton forItem(@NonNull FeedItem item, boolean isInQueue) {
+ final FeedMedia media = item.getMedia();
+ if (media == null) {
+ return new MarkAsPlayedActionButton(item);
+ }
+
+ final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
+ if (media.isDownloaded()) {
+ return new PlayActionButton(item);
+ } else if (isDownloadingMedia) {
+ return new CancelDownloadActionButton(item);
+ } else if (MobileDownloadHelper.userAllowedMobileDownloads() || !MobileDownloadHelper.userChoseAddToQueue() || isInQueue) {
+ return new DownloadActionButton(item, isInQueue);
+ } else {
+ return new AddToQueueActionButton(item);
+ }
+ }
+
+ public void configure(@NonNull ImageButton button, Context context) {
+ TypedArray drawables = context.obtainStyledAttributes(new int[]{getDrawable()});
+
+ button.setVisibility(getVisibility());
+ button.setContentDescription(context.getString(getLabel()));
+ button.setImageDrawable(drawables.getDrawable(0));
+ button.setOnClickListener((view) -> onClick(context));
+
+ drawables.recycle();
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java
new file mode 100644
index 000000000..4d906cee5
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java
@@ -0,0 +1,41 @@
+package de.danoeh.antennapod.adapter.actionbutton;
+
+import android.content.Context;
+import android.support.annotation.AttrRes;
+import android.support.annotation.StringRes;
+import android.view.View;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.storage.DBWriter;
+
+class MarkAsPlayedActionButton extends ItemActionButton {
+
+ MarkAsPlayedActionButton(FeedItem item) {
+ super(item);
+ }
+
+ @Override
+ @StringRes
+ public int getLabel() {
+ return R.string.mark_read_label;
+ }
+
+ @Override
+ @AttrRes
+ public int getDrawable() {
+ return R.attr.navigation_accept;
+ }
+
+ @Override
+ public void onClick(Context context) {
+ if (!item.isPlayed()) {
+ DBWriter.markItemPlayed(item, FeedItem.PLAYED, true);
+ }
+ }
+
+ @Override
+ public int getVisibility() {
+ return (item.isPlayed()) ? View.INVISIBLE : View.VISIBLE;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java
new file mode 100644
index 000000000..f8d2a139e
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java
@@ -0,0 +1,60 @@
+package de.danoeh.antennapod.adapter.actionbutton;
+
+import android.content.Context;
+import android.widget.Toast;
+
+import com.afollestad.materialdialogs.MaterialDialog;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.core.storage.DownloadRequestException;
+
+class MobileDownloadHelper {
+ private static long addToQueueTimestamp;
+ private static long allowMobileDownloadTimestamp;
+ private static final int TEN_MINUTES_IN_MILLIS = 10 * 60 * 1000;
+
+ static boolean userChoseAddToQueue() {
+ return System.currentTimeMillis() - addToQueueTimestamp < TEN_MINUTES_IN_MILLIS;
+ }
+
+ static boolean userAllowedMobileDownloads() {
+ return System.currentTimeMillis() - allowMobileDownloadTimestamp < TEN_MINUTES_IN_MILLIS;
+ }
+
+ static void confirmMobileDownload(final Context context, final FeedItem item) {
+ MaterialDialog.Builder builder = new MaterialDialog.Builder(context)
+ .title(R.string.confirm_mobile_download_dialog_title)
+ .content(R.string.confirm_mobile_download_dialog_message)
+ .positiveText(context.getText(R.string.confirm_mobile_download_dialog_enable_temporarily))
+ .onPositive((dialog, which) -> downloadFeedItems(context, item));
+ if (!DBReader.getQueueIDList().contains(item.getId())) {
+ builder
+ .content(R.string.confirm_mobile_download_dialog_message_not_in_queue)
+ .neutralText(R.string.confirm_mobile_download_dialog_only_add_to_queue)
+ .onNeutral((dialog, which) -> addToQueue(context, item));
+ }
+ builder.show();
+ }
+
+ private static void addToQueue(Context context, FeedItem item) {
+ addToQueueTimestamp = System.currentTimeMillis();
+ DBWriter.addQueueItem(context, item);
+ Toast.makeText(context, R.string.added_to_queue_label, Toast.LENGTH_SHORT).show();
+ }
+
+ private static void downloadFeedItems(Context context, FeedItem item) {
+ allowMobileDownloadTimestamp = System.currentTimeMillis();
+ try {
+ DBTasks.downloadFeedItems(context, item);
+ Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage());
+ }
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java
new file mode 100644
index 000000000..3992c7240
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java
@@ -0,0 +1,63 @@
+package de.danoeh.antennapod.adapter.actionbutton;
+
+import android.content.Context;
+import android.support.annotation.AttrRes;
+import android.support.annotation.StringRes;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.util.IntentUtils;
+import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
+
+import static de.danoeh.antennapod.core.service.playback.PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE;
+import static de.danoeh.antennapod.core.service.playback.PlaybackService.ACTION_RESUME_PLAY_CURRENT_EPISODE;
+
+class PlayActionButton extends ItemActionButton {
+
+ PlayActionButton(FeedItem item) {
+ super(item);
+ }
+
+ @Override
+ @StringRes
+ public int getLabel() {
+ return R.string.play_label;
+ }
+
+ @Override
+ @AttrRes
+ public int getDrawable() {
+ FeedMedia media = item.getMedia();
+ if (media != null && media.isCurrentlyPlaying()) {
+ return R.attr.av_pause;
+ } else {
+ return R.attr.av_play;
+ }
+ }
+
+ @Override
+ public void onClick(Context context) {
+ FeedMedia media = item.getMedia();
+ if (media == null) {
+ return;
+ }
+
+ if (media.isPlaying()) {
+ togglePlayPause(context, media);
+ } else {
+ DBTasks.playMedia(context, media, false, true, false);
+ }
+ }
+
+ private void togglePlayPause(Context context, FeedMedia media) {
+ new PlaybackServiceStarter(context, media)
+ .startWhenPrepared(true)
+ .shouldStream(false)
+ .start();
+
+ String pauseOrResume = media.isCurrentlyPlaying() ? ACTION_PAUSE_PLAY_CURRENT_EPISODE : ACTION_RESUME_PLAY_CURRENT_EPISODE;
+ IntentUtils.sendLocalBroadcast(context, pauseOrResume);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
index 2cf17c85f..f5213e4ab 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
@@ -2,7 +2,6 @@ package de.danoeh.antennapod.adapter.itunes;
import android.content.Context;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
@@ -13,18 +12,14 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
-import de.danoeh.antennapod.core.glide.ApGlideSettings;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.mfietz.fyydlin.SearchHit;
-public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
+public class ItunesAdapter extends ArrayAdapter<PodcastSearchResult> {
/**
* Related Context
*/
@@ -33,7 +28,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
/**
* List holding the podcasts found in the search
*/
- private final List<Podcast> data;
+ private final List<PodcastSearchResult> data;
/**
* Constructor.
@@ -41,7 +36,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
* @param context Related context
* @param objects Search result
*/
- public ItunesAdapter(Context context, List<Podcast> objects) {
+ public ItunesAdapter(Context context, List<PodcastSearchResult> objects) {
super(context, 0, objects);
this.data = objects;
this.context = context;
@@ -51,7 +46,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
//Current podcast
- Podcast podcast = data.get(position);
+ PodcastSearchResult podcast = data.get(position);
//ViewHolder
PodcastViewHolder viewHolder;
@@ -94,75 +89,6 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
}
/**
- * Represents an individual podcast on the iTunes Store.
- */
- public static class Podcast { //TODO: Move this out eventually. Possibly to core.itunes.model
-
- /**
- * The name of the podcast
- */
- public final String title;
-
- /**
- * URL of the podcast image
- */
- @Nullable
- public final String imageUrl;
- /**
- * URL of the podcast feed
- */
- @Nullable
- public final String feedUrl;
-
-
- private Podcast(String title, @Nullable String imageUrl, @Nullable String feedUrl) {
- this.title = title;
- this.imageUrl = imageUrl;
- this.feedUrl = feedUrl;
- }
-
- /**
- * Constructs a Podcast instance from a iTunes search result
- *
- * @param json object holding the podcast information
- * @throws JSONException
- */
- public static Podcast fromSearch(JSONObject json) {
- String title = json.optString("collectionName", "");
- String imageUrl = json.optString("artworkUrl100", null);
- String feedUrl = json.optString("feedUrl", null);
- return new Podcast(title, imageUrl, feedUrl);
- }
-
- public static Podcast fromSearch(SearchHit searchHit) {
- return new Podcast(searchHit.getTitle(), searchHit.getThumbImageURL(), searchHit.getXmlUrl());
- }
-
- /**
- * Constructs a Podcast instance from iTunes toplist entry
- *
- * @param json object holding the podcast information
- * @throws JSONException
- */
- public static Podcast fromToplist(JSONObject json) throws JSONException {
- String title = json.getJSONObject("title").getString("label");
- String imageUrl = null;
- JSONArray images = json.getJSONArray("im:image");
- for(int i=0; imageUrl == null && i < images.length(); i++) {
- JSONObject image = images.getJSONObject(i);
- String height = image.getJSONObject("attributes").getString("height");
- if(Integer.parseInt(height) >= 100) {
- imageUrl = image.getString("label");
- }
- }
- String feedUrl = "https://itunes.apple.com/lookup?id=" +
- json.getJSONObject("id").getJSONObject("attributes").getString("im:id");
- return new Podcast(title, imageUrl, feedUrl);
- }
-
- }
-
- /**
* View holder object for the GridView
*/
static class PodcastViewHolder {
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
index 7c3c570a0..219725b01 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
@@ -23,15 +23,15 @@ public class ExportWorker {
private static final String TAG = "ExportWorker";
private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds";
- private final ExportWriter exportWriter;
- private final File output;
+ private final @NonNull ExportWriter exportWriter;
+ private final @NonNull File output;
- public ExportWorker(ExportWriter exportWriter) {
+ public ExportWorker(@NonNull ExportWriter exportWriter) {
this(exportWriter, new File(UserPreferences.getDataFolder(EXPORT_DIR),
DEFAULT_OUTPUT_NAME + "." + exportWriter.fileExtension()));
}
- private ExportWorker(ExportWriter exportWriter, @NonNull File output) {
+ private ExportWorker(@NonNull ExportWriter exportWriter, @NonNull File output) {
this.exportWriter = exportWriter;
this.output = output;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
index 4138738f6..3dd7c350d 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
@@ -16,7 +16,6 @@ class ClientConfigurator {
ClientConfig.downloadServiceCallbacks = new DownloadServiceCallbacksImpl();
ClientConfig.gpodnetCallbacks = new GpodnetCallbacksImpl();
ClientConfig.playbackServiceCallbacks = new PlaybackServiceCallbacksImpl();
- ClientConfig.flattrCallbacks = new FlattrCallbacksImpl();
ClientConfig.dbTasksCallbacks = new DBTasksCallbacksImpl();
ClientConfig.castCallbacks = new CastCallbackImpl();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java
deleted file mode 100644
index 3817db6de..000000000
--- a/app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package de.danoeh.antennapod.config;
-
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import org.shredzone.flattr4j.oauth.AccessToken;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.activity.FlattrAuthActivity;
-import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.FlattrCallbacks;
-
-public class FlattrCallbacksImpl implements FlattrCallbacks {
- private static final String TAG = "FlattrCallbacksImpl";
-
- @Override
- public boolean flattrEnabled() {
- return true;
- }
-
- @Override
- public Intent getFlattrAuthenticationActivityIntent(Context context) {
- return new Intent(context, FlattrAuthActivity.class);
- }
-
- @Override
- public PendingIntent getFlattrFailedNotificationContentIntent(Context context) {
- return PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);
- }
-
- @Override
- public String getFlattrAppKey() {
- return BuildConfig.FLATTR_APP_KEY;
- }
-
- @Override
- public String getFlattrAppSecret() {
- return BuildConfig.FLATTR_APP_SECRET;
- }
-
- @Override
- public void handleFlattrAuthenticationSuccess(AccessToken token) {
- FlattrAuthActivity instance = FlattrAuthActivity.getInstance();
- if (instance != null) {
- instance.handleAuthenticationSuccess();
- } else {
- Log.e(TAG, "FlattrAuthActivity instance was null");
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java
deleted file mode 100644
index c28342374..000000000
--- a/app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package de.danoeh.antennapod.dialog;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.Context;
-import android.support.v7.app.AlertDialog;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-import org.apache.commons.lang3.Validate;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-
-/**
- * Creates a new AlertDialog that displays preferences for auto-flattring to the user.
- */
-public class AutoFlattrPreferenceDialog {
-
- private AutoFlattrPreferenceDialog() {
- }
-
- public static void newAutoFlattrPreferenceDialog(final Activity activity, final AutoFlattrPreferenceDialogInterface callback) {
- Validate.notNull(activity);
- Validate.notNull(callback);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
-
- @SuppressLint("InflateParams") View view = activity.getLayoutInflater().inflate(R.layout.autoflattr_preference_dialog, null);
- final CheckBox chkAutoFlattr = view.findViewById(R.id.chkAutoFlattr);
- final SeekBar skbPercent = view.findViewById(R.id.skbPercent);
- final TextView txtvStatus = view.findViewById(R.id.txtvStatus);
-
- chkAutoFlattr.setChecked(UserPreferences.isAutoFlattr());
- skbPercent.setEnabled(chkAutoFlattr.isChecked());
- txtvStatus.setEnabled(chkAutoFlattr.isChecked());
-
- final int initialValue = (int) (UserPreferences.getAutoFlattrPlayedDurationThreshold() * 100.0f);
- setStatusMsgText(activity, txtvStatus, initialValue);
- skbPercent.setProgress(initialValue);
-
- chkAutoFlattr.setOnClickListener(v -> {
- skbPercent.setEnabled(chkAutoFlattr.isChecked());
- txtvStatus.setEnabled(chkAutoFlattr.isChecked());
- });
-
- skbPercent.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- setStatusMsgText(activity, txtvStatus, progress);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
-
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
-
- }
- });
-
- builder.setTitle(R.string.pref_auto_flattr_title)
- .setView(view)
- .setPositiveButton(R.string.confirm_label, (dialog, which) -> {
- float progDouble = ((float) skbPercent.getProgress()) / 100.0f;
- callback.onConfirmed(chkAutoFlattr.isChecked(), progDouble);
- dialog.dismiss();
- })
- .setNegativeButton(R.string.cancel_label, (dialog, which) -> {
- callback.onCancelled();
- dialog.dismiss();
- })
- .setCancelable(false).show();
- }
-
- private static void setStatusMsgText(Context context, TextView txtvStatus, int progress) {
- if (progress == 0) {
- txtvStatus.setText(R.string.auto_flattr_ater_beginning);
- } else if (progress == 100) {
- txtvStatus.setText(R.string.auto_flattr_ater_end);
- } else {
- txtvStatus.setText(context.getString(R.string.auto_flattr_after_percent, progress));
- }
- }
-
- public interface AutoFlattrPreferenceDialogInterface {
- void onCancelled();
-
- void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue);
- }
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
index e8faa7c29..c185a5557 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
@@ -1,20 +1,11 @@
package de.danoeh.antennapod.dialog;
import android.content.Context;
-import android.os.Build;
-import android.support.v4.content.ContextCompat;
-import android.text.Html;
import com.afollestad.materialdialogs.MaterialDialog;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.Converter;
-import de.danoeh.antennapod.core.util.StorageUtils;
+import de.danoeh.antennapod.adapter.DataFolderAdapter;
public class ChooseDataFolderDialog {
@@ -31,39 +22,9 @@ public class ChooseDataFolderDialog {
private ChooseDataFolderDialog() {}
public static void showDialog(final Context context, RunnableWithString handlerFunc) {
- File dataFolder = UserPreferences.getDataFolder(null);
- if (dataFolder == null) {
- new MaterialDialog.Builder(context)
- .title(R.string.error_label)
- .content(R.string.external_storage_error_msg)
- .neutralText(android.R.string.ok)
- .show();
- return;
- }
- String dataFolderPath = dataFolder.getAbsolutePath();
- int selectedIndex = -1;
- int index = 0;
- File[] mediaDirs = ContextCompat.getExternalFilesDirs(context, null);
- final List<String> folders = new ArrayList<>(mediaDirs.length);
- final List<CharSequence> choices = new ArrayList<>(mediaDirs.length);
- for (File dir : mediaDirs) {
- if(dir == null || !dir.exists() || !dir.canRead() || !dir.canWrite()) {
- continue;
- }
- String path = dir.getAbsolutePath();
- folders.add(path);
- if(dataFolderPath.equals(path)) {
- selectedIndex = index;
- }
- int prefixIndex = path.indexOf("Android");
- String choice = (prefixIndex > 0) ? path.substring(0, prefixIndex) : path;
- long bytes = StorageUtils.getFreeSpaceAvailable(path);
- String item = String.format(
- "<small>%1$s [%2$s]</small>", choice, Converter.byteToString(bytes));
- choices.add(fromHtmlVersioned(item));
- index++;
- }
- if (choices.isEmpty()) {
+ DataFolderAdapter adapter = new DataFolderAdapter(context, handlerFunc);
+
+ if (adapter.getItemCount() == 0) {
new MaterialDialog.Builder(context)
.title(R.string.error_label)
.content(R.string.external_storage_error_msg)
@@ -71,27 +32,16 @@ public class ChooseDataFolderDialog {
.show();
return;
}
+
MaterialDialog dialog = new MaterialDialog.Builder(context)
.title(R.string.choose_data_directory)
.content(R.string.choose_data_directory_message)
- .items(choices)
- .itemsCallbackSingleChoice(selectedIndex, (dialog1, itemView, which, text) -> {
- String folder = folders.get(which);
- handlerFunc.run(folder);
- return true;
- })
+ .adapter(adapter, null)
.negativeText(R.string.cancel_label)
.cancelable(true)
.build();
+ adapter.setDialog(dialog);
dialog.show();
}
- @SuppressWarnings("deprecation")
- private static CharSequence fromHtmlVersioned(final String html) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
- return Html.fromHtml(html);
- }
- return Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
- }
-
} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java
new file mode 100644
index 000000000..ba778be56
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java
@@ -0,0 +1,71 @@
+package de.danoeh.antennapod.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.RadioButton;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.FeedFilter;
+
+/**
+ * Displays a dialog with a text box for filtering episodes and two radio buttons for exclusion/inclusion
+ */
+public abstract class EpisodeFilterDialog extends Dialog {
+
+ private final FeedFilter initialFilter;
+
+ public EpisodeFilterDialog(Context context, FeedFilter filter) {
+ super(context);
+ this.initialFilter = filter;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.episode_filter_dialog);
+ final EditText etxtEpisodeFilterText = findViewById(R.id.etxtEpisodeFilterText);
+ final RadioButton radioInclude = findViewById(R.id.radio_filter_include);
+ final RadioButton radioExclude = findViewById(R.id.radio_filter_exclude);
+ final Button butConfirm = findViewById(R.id.butConfirm);
+ final Button butCancel = findViewById(R.id.butCancel);
+
+ setTitle(R.string.episode_filters_label);
+ setOnCancelListener(dialog -> onCancelled());
+
+ if (initialFilter.includeOnly()) {
+ radioInclude.setChecked(true);
+ etxtEpisodeFilterText.setText(initialFilter.getIncludeFilter());
+ } else if(initialFilter.excludeOnly()) {
+ radioExclude.setChecked(true);
+ etxtEpisodeFilterText.setText(initialFilter.getExcludeFilter());
+ } else {
+ radioExclude.setChecked(false);
+ radioInclude.setChecked(false);
+ etxtEpisodeFilterText.setText("");
+ }
+
+
+ butCancel.setOnClickListener(v -> cancel());
+ butConfirm.setOnClickListener(v -> {
+
+ String includeString = "";
+ String excludeString = "";
+ if (radioInclude.isChecked()) {
+ includeString = etxtEpisodeFilterText.getText().toString();
+ } else {
+ excludeString = etxtEpisodeFilterText.getText().toString();
+ }
+
+ onConfirmed(new FeedFilter(includeString, excludeString));
+ dismiss();
+ });
+ }
+
+ protected void onCancelled() {
+
+ }
+
+ protected abstract void onConfirmed(FeedFilter filter);
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
index 07a64cde8..7697aaa69 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -3,10 +3,20 @@ package de.danoeh.antennapod.dialog;
import android.app.AlertDialog;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Bundle;
+import android.support.annotation.IdRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.PluralsRes;
+import android.support.annotation.StringRes;
+import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.util.ArrayMap;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -14,11 +24,12 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
-import android.widget.Button;
import android.widget.ListView;
-import android.widget.Toast;
+
+import com.leinardi.android.speeddial.SpeedDialView;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -35,22 +46,42 @@ public class EpisodesApplyActionFragment extends Fragment {
public static final String TAG = "EpisodeActionFragment";
- public static final int ACTION_QUEUE = 1;
- private static final int ACTION_MARK_PLAYED = 2;
- private static final int ACTION_MARK_UNPLAYED = 4;
- private static final int ACTION_DOWNLOAD = 8;
- public static final int ACTION_REMOVE = 16;
- private static final int ACTION_ALL = ACTION_QUEUE | ACTION_MARK_PLAYED | ACTION_MARK_UNPLAYED
- | ACTION_DOWNLOAD | ACTION_REMOVE;
+ public static final int ACTION_ADD_TO_QUEUE = 1;
+ public static final int ACTION_REMOVE_FROM_QUEUE = 2;
+ private static final int ACTION_MARK_PLAYED = 4;
+ private static final int ACTION_MARK_UNPLAYED = 8;
+ private static final int ACTION_DOWNLOAD = 16;
+ public static final int ACTION_DELETE = 32;
+ private static final int ACTION_ALL = ACTION_ADD_TO_QUEUE | ACTION_REMOVE_FROM_QUEUE
+ | ACTION_MARK_PLAYED | ACTION_MARK_UNPLAYED | ACTION_DOWNLOAD | ACTION_DELETE;
+
+ /**
+ * Specify an action (defined by #flag) 's UI bindings.
+ *
+ * Includes: the menu / action item and the actual logic
+ */
+ private class ActionBinding {
+ int flag;
+ @IdRes
+ final int actionItemId;
+ @NonNull
+ final Runnable action;
+
+ ActionBinding(int flag, @IdRes int actionItemId, @NonNull Runnable action) {
+ this.flag = flag;
+ this.actionItemId = actionItemId;
+ this.action = action;
+ }
+ }
+
+ private final List<? extends ActionBinding> actionBindings;
private ListView mListView;
private ArrayAdapter<String> mAdapter;
- private Button btnAddToQueue;
- private Button btnMarkAsPlayed;
- private Button btnMarkAsUnplayed;
- private Button btnDownload;
- private Button btnDelete;
+ private SpeedDialView mSpeedDialView;
+ @NonNull
+ private CharSequence actionBarTitleOriginal = "";
private final Map<Long,FeedItem> idMap = new ArrayMap<>();
private final List<FeedItem> episodes = new ArrayList<>();
@@ -60,6 +91,23 @@ public class EpisodesApplyActionFragment extends Fragment {
private MenuItem mSelectToggle;
+ public EpisodesApplyActionFragment() {
+ actionBindings = Arrays.asList(
+ new ActionBinding(ACTION_ADD_TO_QUEUE,
+ R.id.add_to_queue_batch, this::queueChecked),
+ new ActionBinding(ACTION_REMOVE_FROM_QUEUE,
+ R.id.remove_from_queue_batch, this::removeFromQueueChecked),
+ new ActionBinding(ACTION_MARK_PLAYED,
+ R.id.mark_read_batch, this::markedCheckedPlayed),
+ new ActionBinding(ACTION_MARK_UNPLAYED,
+ R.id.mark_unread_batch, this::markedCheckedUnplayed),
+ new ActionBinding(ACTION_DOWNLOAD,
+ R.id.download_batch, this::downloadChecked),
+ new ActionBinding(ACTION_DELETE,
+ R.id.delete_batch, this::deleteChecked)
+ );
+ }
+
public static EpisodesApplyActionFragment newInstance(List<FeedItem> items) {
return newInstance(items, ACTION_ALL);
}
@@ -77,6 +125,7 @@ public class EpisodesApplyActionFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setRetainInstance(true);
setHasOptionsMenu(true);
}
@@ -124,57 +173,58 @@ public class EpisodesApplyActionFragment extends Fragment {
}
mAdapter = new ArrayAdapter<>(getActivity(),
- android.R.layout.simple_list_item_multiple_choice, titles);
+ R.layout.simple_list_item_multiple_choice_on_start, titles);
mListView.setAdapter(mAdapter);
- checkAll();
- int lastVisibleDiv = 0;
- btnAddToQueue = view.findViewById(R.id.btnAddToQueue);
- if((actions & ACTION_QUEUE) != 0) {
- btnAddToQueue.setOnClickListener(v -> queueChecked());
- lastVisibleDiv = R.id.divider1;
- } else {
- btnAddToQueue.setVisibility(View.GONE);
- view.findViewById(R.id.divider1).setVisibility(View.GONE);
- }
- btnMarkAsPlayed = view.findViewById(R.id.btnMarkAsPlayed);
- if((actions & ACTION_MARK_PLAYED) != 0) {
- btnMarkAsPlayed.setOnClickListener(v -> markedCheckedPlayed());
- lastVisibleDiv = R.id.divider2;
- } else {
- btnMarkAsPlayed.setVisibility(View.GONE);
- view.findViewById(R.id.divider2).setVisibility(View.GONE);
- }
- btnMarkAsUnplayed = view.findViewById(R.id.btnMarkAsUnplayed);
- if((actions & ACTION_MARK_UNPLAYED) != 0) {
- btnMarkAsUnplayed.setOnClickListener(v -> markedCheckedUnplayed());
- lastVisibleDiv = R.id.divider3;
- } else {
- btnMarkAsUnplayed.setVisibility(View.GONE);
- view.findViewById(R.id.divider3).setVisibility(View.GONE);
- }
- btnDownload = view.findViewById(R.id.btnDownload);
- if((actions & ACTION_DOWNLOAD) != 0) {
- btnDownload.setOnClickListener(v -> downloadChecked());
- lastVisibleDiv = R.id.divider4;
- } else {
- btnDownload.setVisibility(View.GONE);
- view.findViewById(R.id.divider4).setVisibility(View.GONE);
+ saveActionBarTitle(); // needed when we dynamically change the title based on selection
+
+ // Init action UI (via a FAB Speed Dial)
+ mSpeedDialView = view.findViewById(R.id.fabSD);
+ mSpeedDialView.inflate(R.menu.episodes_apply_action_speeddial);
+
+ // show only specified actions, and bind speed dial UIs to the actual logic
+ for (ActionBinding binding : actionBindings) {
+ if ((actions & binding.flag) == 0) {
+ mSpeedDialView.removeActionItemById(binding.actionItemId);
+ }
}
- btnDelete = view.findViewById(R.id.btnDelete);
- if((actions & ACTION_REMOVE) != 0) {
- btnDelete.setOnClickListener(v -> deleteChecked());
- } else {
- btnDelete.setVisibility(View.GONE);
- if(lastVisibleDiv > 0) {
- view.findViewById(lastVisibleDiv).setVisibility(View.GONE);
+
+ mSpeedDialView.setOnActionSelectedListener(actionItem -> {
+ ActionBinding selectedBinding = null;
+ for (ActionBinding binding : actionBindings) {
+ if (actionItem.getId() == binding.actionItemId) {
+ selectedBinding = binding;
+ break;
+ }
}
+ if (selectedBinding != null) {
+ selectedBinding.action.run();
+ } else {
+ Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=" + actionItem.getId());
+ }
+ return true;
+ });
+
+ if (Build.VERSION.SDK_INT == 23 || Build.VERSION.SDK_INT == 24) {
+ ViewCompat.setElevation(view.findViewById(R.id.fabSDScrollCtr), 8);
}
+ showSpeedDialIfAnyChecked();
+
return view;
}
@Override
+ public void onStop() {
+ restoreActionBarTitle(); // it might have been changed to "N selected". Restore original.
+ super.onStop();
+ }
+
+ private void showSpeedDialIfAnyChecked() {
+ mSpeedDialView.setVisibility(checkedIds.size() > 0 ? View.VISIBLE : View.GONE);
+ }
+
+ @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.episodes_apply_action_options, menu);
@@ -196,11 +246,9 @@ public class EpisodesApplyActionFragment extends Fragment {
int[] icon = new int[1];
if (checkedIds.size() == episodes.size()) {
- icon[0] = R.attr.ic_check_box;
- } else if (checkedIds.size() == 0) {
- icon[0] = R.attr.ic_check_box_outline;
+ icon[0] = R.attr.ic_select_none;
} else {
- icon[0] = R.attr.ic_indeterminate_check_box;
+ icon[0] = R.attr.ic_select_all;
}
TypedArray a = getActivity().obtainStyledAttributes(icon);
@@ -212,7 +260,7 @@ public class EpisodesApplyActionFragment extends Fragment {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- int resId = 0;
+ @StringRes int resId = 0;
switch(item.getItemId()) {
case R.id.select_options:
return true;
@@ -272,7 +320,8 @@ public class EpisodesApplyActionFragment extends Fragment {
return true;
}
if(resId != 0) {
- Toast.makeText(getActivity(), resId, Toast.LENGTH_SHORT).show();
+ Snackbar.make(getActivity().findViewById(R.id.content), resId, Snackbar.LENGTH_SHORT)
+ .show();
return true;
} else {
return false;
@@ -410,21 +459,56 @@ public class EpisodesApplyActionFragment extends Fragment {
mListView.setItemChecked(i, checked);
}
ActivityCompat.invalidateOptionsMenu(EpisodesApplyActionFragment.this.getActivity());
+ showSpeedDialIfAnyChecked();
+ updateActionBarTitle();
+ }
+
+ private void saveActionBarTitle() {
+ ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+ if (actionBar != null) {
+ CharSequence title = actionBar.getTitle();
+ if (title == null) {
+ title = "";
+ }
+ actionBarTitleOriginal = title;
+ }
+ }
+
+ private void restoreActionBarTitle() {
+ ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setTitle(actionBarTitleOriginal);
+ }
+ }
+
+ private void updateActionBarTitle() {
+ ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+ if (actionBar != null) {
+ CharSequence title = checkedIds.size() > 0 ?
+ getString(R.string.num_selected_label, checkedIds.size()) :
+ actionBarTitleOriginal;
+ actionBar.setTitle(title);
+ }
}
private void queueChecked() {
DBWriter.addQueueItem(getActivity(), true, checkedIds.toArray());
- close();
+ close(R.plurals.added_to_queue_batch_label, checkedIds.size());
+ }
+
+ private void removeFromQueueChecked() {
+ DBWriter.removeQueueItem(getActivity(), true, checkedIds.toArray());
+ close(R.plurals.removed_from_queue_batch_label, checkedIds.size());
}
private void markedCheckedPlayed() {
DBWriter.markItemPlayed(FeedItem.PLAYED, checkedIds.toArray());
- close();
+ close(R.plurals.marked_read_batch_label, checkedIds.size());
}
private void markedCheckedUnplayed() {
DBWriter.markItemPlayed(FeedItem.UNPLAYED, checkedIds.toArray());
- close();
+ close(R.plurals.marked_unread_batch_label, checkedIds.size());
}
private void downloadChecked() {
@@ -441,7 +525,7 @@ public class EpisodesApplyActionFragment extends Fragment {
e.printStackTrace();
DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage());
}
- close();
+ close(R.plurals.downloading_batch_label, checkedIds.size());
}
private void deleteChecked() {
@@ -451,10 +535,18 @@ public class EpisodesApplyActionFragment extends Fragment {
DBWriter.deleteFeedMediaOfItem(getActivity(), episode.getMedia().getId());
}
}
- close();
+ close(R.plurals.deleted_episode_batch_label, checkedIds.size());
}
- private void close() {
+ private void close(@PluralsRes int msgId, int numItems) {
+ if (numItems > 0) {
+ Snackbar.make(getActivity().findViewById(R.id.content),
+ getResources().getQuantityString(msgId, numItems, numItems),
+ Snackbar.LENGTH_LONG
+ )
+ .setAction(android.R.string.ok, v -> {})
+ .show();
+ }
getActivity().getSupportFragmentManager().popBackStack();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
index 8f2629b43..c1008a380 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.dialog;
import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
+import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.text.Editable;
import android.text.TextUtils;
@@ -23,6 +24,8 @@ import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.R;
@@ -92,7 +95,11 @@ public class ProxyDialog {
if(!TextUtils.isEmpty(port)) {
portValue = Integer.valueOf(port);
}
- proxy = ProxyConfig.http(host, portValue, username, password);
+ if (Proxy.Type.valueOf(type) == Proxy.Type.SOCKS) {
+ proxy = ProxyConfig.socks(host, portValue, username, password);
+ } else {
+ proxy = ProxyConfig.http(host, portValue, username, password);
+ }
}
UserPreferences.setProxyConfig(proxy);
AntennapodHttpClient.reinit();
@@ -103,7 +110,13 @@ public class ProxyDialog {
.build();
View view = dialog.getCustomView();
spType = view.findViewById(R.id.spType);
- String[] types = { Proxy.Type.DIRECT.name(), Proxy.Type.HTTP.name() };
+
+ List<String> types= new ArrayList<>();
+ types.add(Proxy.Type.DIRECT.name());
+ types.add(Proxy.Type.HTTP.name());
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ types.add(Proxy.Type.SOCKS.name());
+ }
ArrayAdapter<String> adapter = new ArrayAdapter<>(context,
android.R.layout.simple_spinner_item, types);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
index ece184035..24656ed29 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
@@ -6,6 +6,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.util.Log;
import com.afollestad.materialdialogs.MaterialDialog;
@@ -73,7 +74,8 @@ public class RatingDialog {
return mPreferences.getBoolean(KEY_RATED, false);
}
- private static void saveRated() {
+ @VisibleForTesting
+ public static void saveRated() {
mPreferences
.edit()
.putBoolean(KEY_RATED, true)
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
index 4b8601ec6..dc056a3f9 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
@@ -18,7 +18,7 @@ import com.afollestad.materialdialogs.MaterialDialog;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.event.MessageEvent;
import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
-import de.greenrobot.event.EventBus;
+import org.greenrobot.eventbus.EventBus;
public abstract class SleepTimerDialog {
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java
new file mode 100644
index 000000000..18d65a03c
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java
@@ -0,0 +1,96 @@
+package de.danoeh.antennapod.discovery;
+
+import android.content.Context;
+import android.util.Log;
+import android.util.Pair;
+import io.reactivex.Single;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+
+public class CombinedSearcher implements PodcastSearcher {
+ private static final String TAG = "CombinedSearcher";
+
+ private final List<Pair<PodcastSearcher, Float>> searchProviders = new ArrayList<>();
+
+ public CombinedSearcher(Context context) {
+ addProvider(new FyydPodcastSearcher(), 1.f);
+ addProvider(new ItunesPodcastSearcher(context), 1.f);
+ addProvider(new GpodnetPodcastSearcher(), 0.6f);
+ }
+
+ private void addProvider(PodcastSearcher provider, float priority) {
+ searchProviders.add(new Pair<>(provider, priority));
+ }
+
+ public Single<List<PodcastSearchResult>> search(String query) {
+ ArrayList<Disposable> disposables = new ArrayList<>();
+ List<List<PodcastSearchResult>> singleResults = new ArrayList<>(Collections.nCopies(searchProviders.size(), null));
+ CountDownLatch latch = new CountDownLatch(searchProviders.size());
+ for (int i = 0; i < searchProviders.size(); i++) {
+ Pair<PodcastSearcher, Float> searchProviderInfo = searchProviders.get(i);
+ PodcastSearcher searcher = searchProviderInfo.first;
+ final int index = i;
+ disposables.add(searcher.search(query).subscribe(e -> {
+ singleResults.set(index, e);
+ latch.countDown();
+ }, throwable -> {
+ Log.d(TAG, Log.getStackTraceString(throwable));
+ latch.countDown();
+ }
+ ));
+ }
+
+ return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
+ latch.await();
+ List<PodcastSearchResult> results = weightSearchResults(singleResults);
+ subscriber.onSuccess(results);
+ })
+ .doOnDispose(() -> {
+ for (Disposable disposable : disposables) {
+ disposable.dispose();
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
+ private List<PodcastSearchResult> weightSearchResults(List<List<PodcastSearchResult>> singleResults) {
+ HashMap<String, Float> resultRanking = new HashMap<>();
+ HashMap<String, PodcastSearchResult> urlToResult = new HashMap<>();
+ for (int i = 0; i < singleResults.size(); i++) {
+ float providerPriority = searchProviders.get(i).second;
+ List<PodcastSearchResult> providerResults = singleResults.get(i);
+ if (providerResults == null) {
+ continue;
+ }
+ for (int position = 0; position < providerResults.size(); position++) {
+ PodcastSearchResult result = providerResults.get(position);
+ urlToResult.put(result.feedUrl, result);
+
+ float ranking = 0;
+ if (resultRanking.containsKey(result.feedUrl)) {
+ ranking = resultRanking.get(result.feedUrl);
+ }
+ ranking += 1.f / (position + 1.f);
+ resultRanking.put(result.feedUrl, ranking * providerPriority);
+ }
+ }
+ List<Map.Entry<String, Float>> sortedResults = new ArrayList<>(resultRanking.entrySet());
+ Collections.sort(sortedResults, (o1, o2) -> Double.compare(o2.getValue(), o1.getValue()));
+
+ List<PodcastSearchResult> results = new ArrayList<>();
+ for (Map.Entry<String, Float> res : sortedResults) {
+ results.add(urlToResult.get(res.getKey()));
+ }
+ return results;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java
new file mode 100644
index 000000000..529a9e3d5
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java
@@ -0,0 +1,38 @@
+package de.danoeh.antennapod.discovery;
+
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import de.mfietz.fyydlin.FyydClient;
+import de.mfietz.fyydlin.FyydResponse;
+import de.mfietz.fyydlin.SearchHit;
+import io.reactivex.Single;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FyydPodcastSearcher implements PodcastSearcher {
+ private final FyydClient client = new FyydClient(AntennapodHttpClient.getHttpClient());
+
+ public Single<List<PodcastSearchResult>> search(String query) {
+ return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
+ FyydResponse response = client.searchPodcasts(query, 10)
+ .subscribeOn(Schedulers.io())
+ .blockingGet();
+
+ ArrayList<PodcastSearchResult> searchResults = new ArrayList<>();
+
+ if (!response.getData().isEmpty()) {
+ for (SearchHit searchHit : response.getData()) {
+ PodcastSearchResult podcast = PodcastSearchResult.fromFyyd(searchHit);
+ searchResults.add(podcast);
+ }
+ }
+
+ subscriber.onSuccess(searchResults);
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java
new file mode 100644
index 000000000..6e5debb38
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java
@@ -0,0 +1,38 @@
+package de.danoeh.antennapod.discovery;
+
+import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
+import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
+import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast;
+import io.reactivex.Single;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GpodnetPodcastSearcher implements PodcastSearcher {
+ public Single<List<PodcastSearchResult>> search(String query) {
+ return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
+ GpodnetService service = null;
+ try {
+ service = new GpodnetService();
+ List<GpodnetPodcast> gpodnetPodcasts = service.searchPodcasts(query, 0);
+ List<PodcastSearchResult> results = new ArrayList<>();
+ for (GpodnetPodcast podcast : gpodnetPodcasts) {
+ results.add(PodcastSearchResult.fromGpodder(podcast));
+ }
+ subscriber.onSuccess(results);
+ } catch (GpodnetServiceException e) {
+ e.printStackTrace();
+ subscriber.onError(e);
+ } finally {
+ if (service != null) {
+ service.shutdown();
+ }
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java
new file mode 100644
index 000000000..a91aae1a8
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java
@@ -0,0 +1,74 @@
+package de.danoeh.antennapod.discovery;
+
+import android.content.Context;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.ClientConfig;
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import io.reactivex.Single;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ItunesPodcastSearcher implements PodcastSearcher {
+ private static final String ITUNES_API_URL = "https://itunes.apple.com/search?media=podcast&term=%s";
+ private final Context context;
+
+ public ItunesPodcastSearcher(Context context) {
+ this.context = context;
+ }
+
+ public Single<List<PodcastSearchResult>> search(String query) {
+ return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
+ String encodedQuery;
+ try {
+ encodedQuery = URLEncoder.encode(query, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // this won't ever be thrown
+ encodedQuery = query;
+ }
+
+ String formattedUrl = String.format(ITUNES_API_URL, encodedQuery);
+
+ OkHttpClient client = AntennapodHttpClient.getHttpClient();
+ Request.Builder httpReq = new Request.Builder()
+ .url(formattedUrl)
+ .header("User-Agent", ClientConfig.USER_AGENT);
+ List<PodcastSearchResult> podcasts = new ArrayList<>();
+ try {
+ Response response = client.newCall(httpReq.build()).execute();
+
+ if (response.isSuccessful()) {
+ String resultString = response.body().string();
+ JSONObject result = new JSONObject(resultString);
+ JSONArray j = result.getJSONArray("results");
+
+ for (int i = 0; i < j.length(); i++) {
+ JSONObject podcastJson = j.getJSONObject(i);
+ PodcastSearchResult podcast = PodcastSearchResult.fromItunes(podcastJson);
+ podcasts.add(podcast);
+ }
+ } else {
+ String prefix = context.getString(R.string.error_msg_prefix);
+ subscriber.onError(new IOException(prefix + response));
+ }
+ } catch (IOException | JSONException e) {
+ subscriber.onError(e);
+ }
+ subscriber.onSuccess(podcasts);
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java
new file mode 100644
index 000000000..bc9133258
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java
@@ -0,0 +1,110 @@
+package de.danoeh.antennapod.discovery;
+
+import android.content.Context;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.ClientConfig;
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import io.reactivex.Single;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+public class ItunesTopListLoader {
+ private final Context context;
+
+ public ItunesTopListLoader(Context context) {
+ this.context = context;
+ }
+
+ public Single<List<PodcastSearchResult>> loadToplist(int limit) {
+ return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) emitter -> {
+ String lang = Locale.getDefault().getLanguage();
+ OkHttpClient client = AntennapodHttpClient.getHttpClient();
+ String feedString;
+ try {
+ try {
+ feedString = getTopListFeed(client, lang, limit);
+ } catch (IOException e) {
+ feedString = getTopListFeed(client, "us", limit);
+ }
+ List<PodcastSearchResult> podcasts = parseFeed(feedString);
+ emitter.onSuccess(podcasts);
+ } catch (IOException | JSONException e) {
+ emitter.onError(e);
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
+ public Single<String> getFeedUrl(PodcastSearchResult podcast) {
+ if (!podcast.feedUrl.contains("itunes.apple.com")) {
+ return Single.just(podcast.feedUrl)
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+ return Single.create((SingleOnSubscribe<String>) emitter -> {
+ OkHttpClient client = AntennapodHttpClient.getHttpClient();
+ Request.Builder httpReq = new Request.Builder()
+ .url(podcast.feedUrl)
+ .header("User-Agent", ClientConfig.USER_AGENT);
+ try {
+ Response response = client.newCall(httpReq.build()).execute();
+ if (response.isSuccessful()) {
+ String resultString = response.body().string();
+ JSONObject result = new JSONObject(resultString);
+ JSONObject results = result.getJSONArray("results").getJSONObject(0);
+ String feedUrl = results.getString("feedUrl");
+ emitter.onSuccess(feedUrl);
+ } else {
+ String prefix = context.getString(R.string.error_msg_prefix);
+ emitter.onError(new IOException(prefix + response));
+ }
+ } catch (IOException | JSONException e) {
+ emitter.onError(e);
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
+ private String getTopListFeed(OkHttpClient client, String language, int limit) throws IOException {
+ String url = "https://itunes.apple.com/%s/rss/toppodcasts/limit="+limit+"/explicit=true/json";
+ Request.Builder httpReq = new Request.Builder()
+ .header("User-Agent", ClientConfig.USER_AGENT)
+ .url(String.format(url, language));
+
+ try (Response response = client.newCall(httpReq.build()).execute()) {
+ if (response.isSuccessful()) {
+ return response.body().string();
+ }
+ String prefix = context.getString(R.string.error_msg_prefix);
+ throw new IOException(prefix + response);
+ }
+ }
+
+ private List<PodcastSearchResult> parseFeed(String jsonString) throws JSONException {
+ JSONObject result = new JSONObject(jsonString);
+ JSONObject feed = result.getJSONObject("feed");
+ JSONArray entries = feed.getJSONArray("entry");
+
+ List<PodcastSearchResult> results = new ArrayList<>();
+ for (int i=0; i < entries.length(); i++) {
+ JSONObject json = entries.getJSONObject(i);
+ results.add(PodcastSearchResult.fromItunesToplist(json));
+ }
+
+ return results;
+ }
+
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
new file mode 100644
index 000000000..ca9ed83d7
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
@@ -0,0 +1,81 @@
+package de.danoeh.antennapod.discovery;
+
+import android.support.annotation.Nullable;
+import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast;
+import de.mfietz.fyydlin.SearchHit;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class PodcastSearchResult {
+
+ /**
+ * The name of the podcast
+ */
+ public final String title;
+
+ /**
+ * URL of the podcast image
+ */
+ @Nullable
+ public final String imageUrl;
+ /**
+ * URL of the podcast feed
+ */
+ @Nullable
+ public final String feedUrl;
+
+
+ private PodcastSearchResult(String title, @Nullable String imageUrl, @Nullable String feedUrl) {
+ this.title = title;
+ this.imageUrl = imageUrl;
+ this.feedUrl = feedUrl;
+ }
+
+ public static PodcastSearchResult dummy() {
+ return new PodcastSearchResult("", "", "");
+ }
+
+ /**
+ * Constructs a Podcast instance from a iTunes search result
+ *
+ * @param json object holding the podcast information
+ * @throws JSONException
+ */
+ public static PodcastSearchResult fromItunes(JSONObject json) {
+ String title = json.optString("collectionName", "");
+ String imageUrl = json.optString("artworkUrl100", null);
+ String feedUrl = json.optString("feedUrl", null);
+ return new PodcastSearchResult(title, imageUrl, feedUrl);
+ }
+
+ /**
+ * Constructs a Podcast instance from iTunes toplist entry
+ *
+ * @param json object holding the podcast information
+ * @throws JSONException
+ */
+ public static PodcastSearchResult fromItunesToplist(JSONObject json) throws JSONException {
+ String title = json.getJSONObject("title").getString("label");
+ String imageUrl = null;
+ JSONArray images = json.getJSONArray("im:image");
+ for(int i=0; imageUrl == null && i < images.length(); i++) {
+ JSONObject image = images.getJSONObject(i);
+ String height = image.getJSONObject("attributes").getString("height");
+ if(Integer.parseInt(height) >= 100) {
+ imageUrl = image.getString("label");
+ }
+ }
+ String feedUrl = "https://itunes.apple.com/lookup?id=" +
+ json.getJSONObject("id").getJSONObject("attributes").getString("im:id");
+ return new PodcastSearchResult(title, imageUrl, feedUrl);
+ }
+
+ public static PodcastSearchResult fromFyyd(SearchHit searchHit) {
+ return new PodcastSearchResult(searchHit.getTitle(), searchHit.getThumbImageURL(), searchHit.getXmlUrl());
+ }
+
+ public static PodcastSearchResult fromGpodder(GpodnetPodcast searchHit) {
+ return new PodcastSearchResult(searchHit.getTitle(), searchHit.getLogoUrl(), searchHit.getUrl());
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java
new file mode 100644
index 000000000..b19d7d695
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java
@@ -0,0 +1,10 @@
+package de.danoeh.antennapod.discovery;
+
+import io.reactivex.Single;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Consumer;
+import java.util.List;
+
+public interface PodcastSearcher {
+ Single<List<PodcastSearchResult>> search(String query);
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
index ee2373da8..35bcaa76e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -2,13 +2,20 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
+import android.provider.MediaStore;
import android.support.v4.app.Fragment;
+import android.view.ContextMenu;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
@@ -27,11 +34,28 @@ public class AddFeedFragment extends Fragment {
*/
private static final String ARG_FEED_URL = "feedurl";
+ private EditText combinedFeedSearchBox;
+ private MainActivity activity;
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.addfeed, container, false);
+ activity = (MainActivity) getActivity();
+ activity.getSupportActionBar().setTitle(R.string.add_feed_label);
+
+ setupAdvancedSearchButtons(root);
+ setupSeachBox(root);
+
+ View butOpmlImport = root.findViewById(R.id.btn_opml_import);
+ butOpmlImport.setOnClickListener(v -> startActivity(new Intent(getActivity(),
+ OpmlImportFromPathActivity.class)));
+
+ return root;
+ }
+
+ private void setupSeachBox(View root) {
final EditText etxtFeedurl = root.findViewById(R.id.etxtFeedurl);
Bundle args = getArguments();
@@ -39,32 +63,69 @@ public class AddFeedFragment extends Fragment {
etxtFeedurl.setText(args.getString(ARG_FEED_URL));
}
- Button butSearchITunes = root.findViewById(R.id.butSearchItunes);
- Button butBrowserGpoddernet = root.findViewById(R.id.butBrowseGpoddernet);
- Button butSearchFyyd = root.findViewById(R.id.butSearchFyyd);
- Button butOpmlImport = root.findViewById(R.id.butOpmlImport);
- Button butConfirm = root.findViewById(R.id.butConfirm);
+ Button butConfirmAddUrl = root.findViewById(R.id.butConfirm);
+ butConfirmAddUrl.setOnClickListener(v -> {
+ addUrl(etxtFeedurl.getText().toString());
+ });
- final MainActivity activity = (MainActivity) getActivity();
- activity.getSupportActionBar().setTitle(R.string.add_feed_label);
+ combinedFeedSearchBox = root.findViewById(R.id.combinedFeedSearchBox);
+ combinedFeedSearchBox.setOnEditorActionListener((v, actionId, event) -> {
+ if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+ performSearch();
+ return true;
+ }
+ return false;
+ });
+ }
- butSearchITunes.setOnClickListener(v -> activity.loadChildFragment(new ItunesSearchFragment()));
+ private void setupAdvancedSearchButtons(View root) {
+ View butAdvancedSearch = root.findViewById(R.id.advanced_search);
+ registerForContextMenu(butAdvancedSearch);
+ butAdvancedSearch.setOnClickListener(v -> butAdvancedSearch.showContextMenu());
+ }
- butBrowserGpoddernet.setOnClickListener(v -> activity.loadChildFragment(new GpodnetMainFragment()));
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ getActivity().getMenuInflater().inflate(R.menu.advanced_search, menu);
+ }
- butSearchFyyd.setOnClickListener(v -> activity.loadChildFragment(new FyydSearchFragment()));
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.search_fyyd:
+ activity.loadChildFragment(new FyydSearchFragment());
+ return true;
+ case R.id.search_gpodder:
+ activity.loadChildFragment(new GpodnetMainFragment());
+ return true;
+ case R.id.search_itunes:
+ activity.loadChildFragment(new ItunesSearchFragment());
+ return true;
+ }
+ return false;
+ }
- butOpmlImport.setOnClickListener(v -> startActivity(new Intent(getActivity(),
- OpmlImportFromPathActivity.class)));
- butConfirm.setOnClickListener(v -> {
- Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
- intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, etxtFeedurl.getText().toString());
- intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, getString(R.string.add_feed_label));
- startActivity(intent);
- });
+ private void addUrl(String url) {
+ Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, url);
+ intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, getString(R.string.add_feed_label));
+ startActivity(intent);
+ }
- return root;
+ private void performSearch() {
+ String query = combinedFeedSearchBox.getText().toString();
+
+ if (query.startsWith("http")) {
+ addUrl(query);
+ return;
+ }
+
+ Bundle bundle = new Bundle();
+ bundle.putString(CombinedSearchFragment.ARGUMENT_QUERY, query);
+ CombinedSearchFragment fragment = new CombinedSearchFragment();
+ fragment.setArguments(bundle);
+ activity.loadChildFragment(fragment);
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
index ef522d3b3..62d798cf6 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
@@ -5,6 +5,7 @@ import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
+import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
@@ -24,12 +25,16 @@ import android.widget.Toast;
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
-import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
@@ -39,6 +44,7 @@ import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.download.DownloadRequest;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -49,7 +55,7 @@ import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
-import de.greenrobot.event.EventBus;
+import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -74,12 +80,12 @@ public class AllEpisodesFragment extends Fragment {
RecyclerView recyclerView;
AllEpisodesRecycleAdapter listAdapter;
private ProgressBar progLoading;
+ EmptyViewHandler emptyView;
- List<FeedItem> episodes;
- private List<Downloader> downloaderList;
-
- private boolean itemsLoaded = false;
- private boolean viewsCreated = false;
+ @NonNull
+ List<FeedItem> episodes = new ArrayList<>();
+ @NonNull
+ private List<Downloader> downloaderList = new ArrayList<>();
private boolean isUpdatingFeeds;
boolean isMenuInvalidationAllowed = false;
@@ -87,36 +93,32 @@ public class AllEpisodesFragment extends Fragment {
Disposable disposable;
private LinearLayoutManager layoutManager;
- boolean showOnlyNewEpisodes() { return false; }
- String getPrefName() { return DEFAULT_PREF_NAME; }
+ boolean showOnlyNewEpisodes() {
+ return false;
+ }
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setHasOptionsMenu(true);
+ String getPrefName() {
+ return DEFAULT_PREF_NAME;
}
@Override
public void onStart() {
super.onStart();
+ setHasOptionsMenu(true);
EventDistributor.getInstance().register(contentUpdate);
- if (viewsCreated && itemsLoaded) {
- onFragmentLoaded();
- }
+ EventBus.getDefault().register(this);
+ loadItems();
}
@Override
public void onResume() {
super.onResume();
- EventBus.getDefault().registerSticky(this);
- loadItems();
registerForContextMenu(recyclerView);
}
@Override
public void onPause() {
super.onPause();
- EventBus.getDefault().unregister(this);
saveScrollPosition();
unregisterForContextMenu(recyclerView);
}
@@ -124,23 +126,18 @@ public class AllEpisodesFragment extends Fragment {
@Override
public void onStop() {
super.onStop();
+ EventBus.getDefault().unregister(this);
EventDistributor.getInstance().unregister(contentUpdate);
if (disposable != null) {
disposable.dispose();
}
}
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- resetViewState();
- }
-
private void saveScrollPosition() {
int firstItem = layoutManager.findFirstVisibleItemPosition();
View firstItemView = layoutManager.findViewByPosition(firstItem);
float topOffset;
- if(firstItemView == null) {
+ if (firstItemView == null) {
topOffset = 0;
} else {
topOffset = firstItemView.getTop();
@@ -167,43 +164,35 @@ public class AllEpisodesFragment extends Fragment {
}
}
- void resetViewState() {
- viewsCreated = false;
- listAdapter = null;
- }
-
-
private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker =
() -> DownloadService.isRunning && DownloadRequester.getInstance().isDownloadingFeeds();
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if(!isAdded()) {
+ if (!isAdded()) {
return;
}
super.onCreateOptionsMenu(menu, inflater);
- if (itemsLoaded) {
- inflater.inflate(R.menu.episodes, menu);
-
- MenuItem searchItem = menu.findItem(R.id.action_search);
- final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
- sv.setQueryHint(getString(R.string.search_hint));
- sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
- @Override
- public boolean onQueryTextSubmit(String s) {
- sv.clearFocus();
- ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s));
- return true;
- }
+ inflater.inflate(R.menu.episodes, menu);
+
+ MenuItem searchItem = menu.findItem(R.id.action_search);
+ final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
+ MenuItemUtils.adjustTextColor(getActivity(), sv);
+ sv.setQueryHint(getString(R.string.search_hint));
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ ((MainActivity) requireActivity()).loadChildFragment(SearchFragment.newInstance(s));
+ return true;
+ }
- @Override
- public boolean onQueryTextChange(String s) {
- return false;
- }
- });
- isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
- }
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
@Override
@@ -211,11 +200,11 @@ public class AllEpisodesFragment extends Fragment {
super.onPrepareOptionsMenu(menu);
MenuItem markAllRead = menu.findItem(R.id.mark_all_read_item);
if (markAllRead != null) {
- markAllRead.setVisible(!showOnlyNewEpisodes() && episodes != null && !episodes.isEmpty());
+ markAllRead.setVisible(!showOnlyNewEpisodes() && !episodes.isEmpty());
}
- MenuItem markAllSeen = menu.findItem(R.id.mark_all_seen_item);
- if(markAllSeen != null) {
- markAllSeen.setVisible(showOnlyNewEpisodes() && episodes != null && !episodes.isEmpty());
+ MenuItem removeAllNewFlags = menu.findItem(R.id.remove_all_new_flags_item);
+ if (removeAllNewFlags != null) {
+ removeAllNewFlags.setVisible(showOnlyNewEpisodes() && !episodes.isEmpty());
}
}
@@ -243,19 +232,19 @@ public class AllEpisodesFragment extends Fragment {
};
markAllReadConfirmationDialog.createNewDialog().show();
return true;
- case R.id.mark_all_seen_item:
- ConfirmationDialog markAllSeenConfirmationDialog = new ConfirmationDialog(getActivity(),
- R.string.mark_all_seen_label,
- R.string.mark_all_seen_confirmation_msg) {
+ case R.id.remove_all_new_flags_item:
+ ConfirmationDialog removeAllNewFlagsConfirmationDialog = new ConfirmationDialog(getActivity(),
+ R.string.remove_all_new_flags_label,
+ R.string.remove_all_new_flags_confirmation_msg) {
@Override
public void onConfirmButtonPressed(DialogInterface dialog) {
dialog.dismiss();
- DBWriter.markNewItemsSeen();
- Toast.makeText(getActivity(), R.string.mark_all_seen_msg, Toast.LENGTH_SHORT).show();
+ DBWriter.removeAllNewFlags();
+ Toast.makeText(getActivity(), R.string.removed_all_new_flags_msg, Toast.LENGTH_SHORT).show();
}
};
- markAllSeenConfirmationDialog.createNewDialog().show();
+ removeAllNewFlagsConfirmationDialog.createNewDialog().show();
return true;
default:
return false;
@@ -269,98 +258,102 @@ public class AllEpisodesFragment extends Fragment {
@Override
public boolean onContextItemSelected(MenuItem item) {
Log.d(TAG, "onContextItemSelected() called with: " + "item = [" + item + "]");
- if(!isVisible()) {
+ if (!getUserVisibleHint()) {
return false;
}
- if(item.getItemId() == R.id.share_item) {
+ if (!isVisible()) {
+ return false;
+ }
+ if (item.getItemId() == R.id.share_item) {
return true; // avoids that the position is reset when we need it in the submenu
}
- FeedItem selectedItem = listAdapter.getSelectedItem();
- if (selectedItem == null) {
- Log.i(TAG, "Selected item was null, ignoring selection");
+ if (listAdapter.getSelectedItem() == null) {
+ Log.i(TAG, "Selected item or listAdapter was null, ignoring selection");
return super.onContextItemSelected(item);
}
+ FeedItem selectedItem = listAdapter.getSelectedItem();
- // Mark as seen contains UI logic specific to All/New/FavoriteSegments,
+ // Remove new flag contains UI logic specific to All/New/FavoriteSegments,
// e.g., Undo with Snackbar,
// and is handled by this class rather than the generic FeedItemMenuHandler
- // Undo is useful for Mark as seen, given there is no UI to undo it otherwise,
+ // Undo is useful for Remove new flag, given there is no UI to undo it otherwise,
// i.e., there is context menu item for Mark as new
- if (R.id.mark_as_seen_item == item.getItemId()) {
- markItemAsSeenWithUndo(selectedItem);
+ if (R.id.remove_new_flag_item == item.getItemId()) {
+ removeNewFlagWithUndo(selectedItem);
return true;
}
return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
}
+ @NonNull
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- return onCreateViewHelper(inflater, container, savedInstanceState,
- R.layout.all_episodes_fragment);
- }
-
- View onCreateViewHelper(LayoutInflater inflater,
- ViewGroup container,
- Bundle savedInstanceState,
- int fragmentResource) {
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
+ View root = inflater.inflate(R.layout.all_episodes_fragment, container, false);
- View root = inflater.inflate(fragmentResource, container, false);
-
+ layoutManager = new LinearLayoutManager(getActivity());
recyclerView = root.findViewById(android.R.id.list);
+ recyclerView.setLayoutManager(layoutManager);
+ recyclerView.setHasFixedSize(true);
+ recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());
+ recyclerView.setVisibility(View.GONE);
+
RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}
- layoutManager = new LinearLayoutManager(getActivity());
- recyclerView.setLayoutManager(layoutManager);
- recyclerView.setHasFixedSize(true);
- recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());
progLoading = root.findViewById(R.id.progLoading);
+ progLoading.setVisibility(View.VISIBLE);
- if (!itemsLoaded) {
- progLoading.setVisibility(View.VISIBLE);
- }
+ emptyView = new EmptyViewHandler(getContext());
+ emptyView.attachToRecyclerView(recyclerView);
+ emptyView.setIcon(R.attr.feed);
+ emptyView.setTitle(R.string.no_all_episodes_head_label);
+ emptyView.setMessage(R.string.no_all_episodes_label);
- viewsCreated = true;
-
- if (itemsLoaded) {
- onFragmentLoaded();
- }
+ createRecycleAdapter(recyclerView, emptyView);
+ emptyView.hide();
return root;
}
- private void onFragmentLoaded() {
- if (listAdapter == null) {
- MainActivity mainActivity = (MainActivity) getActivity();
- listAdapter = new AllEpisodesRecycleAdapter(mainActivity, itemAccess,
- new DefaultActionButtonCallback(mainActivity), showOnlyNewEpisodes());
- listAdapter.setHasStableIds(true);
- recyclerView.setAdapter(listAdapter);
- }
+ private void onFragmentLoaded(List<FeedItem> episodes) {
+ this.episodes = episodes;
listAdapter.notifyDataSetChanged();
+
+ if (episodes.size() == 0) {
+ createRecycleAdapter(recyclerView, emptyView);
+ }
+
restoreScrollPosition();
- getActivity().supportInvalidateOptionsMenu();
- updateShowOnlyEpisodesListViewState();
+ requireActivity().invalidateOptionsMenu();
+ }
+
+ /**
+ * Currently, we need to recreate the list adapter in order to be able to undo last item via the
+ * snackbar. See #3084 for details.
+ */
+ private void createRecycleAdapter(RecyclerView recyclerView, EmptyViewHandler emptyViewHandler) {
+ MainActivity mainActivity = (MainActivity) getActivity();
+ listAdapter = new AllEpisodesRecycleAdapter(mainActivity, itemAccess, showOnlyNewEpisodes());
+ listAdapter.setHasStableIds(true);
+ recyclerView.setAdapter(listAdapter);
+ emptyViewHandler.updateAdapter(listAdapter);
}
private final AllEpisodesRecycleAdapter.ItemAccess itemAccess = new AllEpisodesRecycleAdapter.ItemAccess() {
@Override
public int getCount() {
- if (episodes != null) {
- return episodes.size();
- }
- return 0;
+ return episodes.size();
}
@Override
public FeedItem getItem(int position) {
- if (episodes != null && 0 <= position && position < episodes.size()) {
+ if (0 <= position && position < episodes.size()) {
return episodes.get(position);
}
return null;
@@ -368,11 +361,8 @@ public class AllEpisodesFragment extends Fragment {
@Override
public LongList getItemsIds() {
- if(episodes == null) {
- return new LongList(0);
- }
LongList ids = new LongList(episodes.size());
- for(FeedItem episode : episodes) {
+ for (FeedItem episode : episodes) {
ids.add(episode.getId());
}
return ids;
@@ -380,12 +370,11 @@ public class AllEpisodesFragment extends Fragment {
@Override
public int getItemDownloadProgressPercent(FeedItem item) {
- if (downloaderList != null) {
- for (Downloader downloader : downloaderList) {
- if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
- && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
- return downloader.getDownloadRequest().getProgressPercent();
- }
+ for (Downloader downloader : downloaderList) {
+ DownloadRequest downloadRequest = downloader.getDownloadRequest();
+ if (downloadRequest.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
+ && downloadRequest.getFeedfileId() == item.getMedia().getId()) {
+ return downloadRequest.getProgressPercent();
}
}
return 0;
@@ -399,11 +388,8 @@ public class AllEpisodesFragment extends Fragment {
@Override
public LongList getQueueIds() {
LongList queueIds = new LongList();
- if(episodes == null) {
- return queueIds;
- }
- for(FeedItem item : episodes) {
- if(item.isTagged(FeedItem.TAG_QUEUE)) {
+ for (FeedItem item : episodes) {
+ if (item.isTagged(FeedItem.TAG_QUEUE)) {
queueIds.add(item.getId());
}
}
@@ -412,34 +398,39 @@ public class AllEpisodesFragment extends Fragment {
};
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
- if(episodes == null || listAdapter == null) {
- return;
- }
- for(int i=0, size = event.items.size(); i < size; i++) {
- FeedItem item = event.items.get(i);
+ for (FeedItem item : event.items) {
int pos = FeedItemUtil.indexOfItemWithId(episodes, item.getId());
- if(pos >= 0) {
+ if (pos >= 0) {
episodes.remove(pos);
- episodes.add(pos, item);
- listAdapter.notifyItemChanged(pos);
+ if (shouldUpdatedItemRemainInList(item)) {
+ episodes.add(pos, item);
+ listAdapter.notifyItemChanged(pos);
+ } else {
+ listAdapter.notifyItemRemoved(pos);
+ }
}
}
}
+ protected boolean shouldUpdatedItemRemainInList(FeedItem item) {
+ return true;
+ }
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
if (isMenuInvalidationAllowed && isUpdatingFeeds != update.feedIds.length > 0) {
- getActivity().supportInvalidateOptionsMenu();
+ requireActivity().invalidateOptionsMenu();
}
- if(listAdapter != null && update.mediaIds.length > 0) {
- for(long mediaId : update.mediaIds) {
+ if (update.mediaIds.length > 0) {
+ for (long mediaId : update.mediaIds) {
int pos = FeedItemUtil.indexOfItemWithMediaId(episodes, mediaId);
- if(pos >= 0) {
+ if (pos >= 0) {
listAdapter.notifyItemChanged(pos);
}
}
@@ -452,49 +443,36 @@ public class AllEpisodesFragment extends Fragment {
if ((arg & EVENTS) != 0) {
loadItems();
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
- getActivity().supportInvalidateOptionsMenu();
+ requireActivity().invalidateOptionsMenu();
}
}
}
};
- private void updateShowOnlyEpisodesListViewState() {
- }
-
void loadItems() {
if (disposable != null) {
disposable.dispose();
}
- if (viewsCreated && !itemsLoaded) {
- recyclerView.setVisibility(View.GONE);
- progLoading.setVisibility(View.VISIBLE);
- }
disposable = Observable.fromCallable(this::loadData)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
- recyclerView.setVisibility(View.VISIBLE);
progLoading.setVisibility(View.GONE);
- if (data != null) {
- episodes = data;
- itemsLoaded = true;
- if (viewsCreated) {
- onFragmentLoaded();
- }
- }
+ onFragmentLoaded(data);
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
+ @NonNull
List<FeedItem> loadData() {
return DBReader.getRecentlyPublishedEpisodes(RECENT_EPISODES_LIMIT);
}
- void markItemAsSeenWithUndo(FeedItem item) {
+ void removeNewFlagWithUndo(FeedItem item) {
if (item == null) {
return;
}
- Log.d(TAG, "markItemAsSeenWithUndo(" + item.getId() + ")");
+ Log.d(TAG, "removeNewFlagWithUndo(" + item.getId() + ")");
if (disposable != null) {
disposable.dispose();
}
@@ -503,14 +481,14 @@ public class AllEpisodesFragment extends Fragment {
DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId());
final Handler h = new Handler(getActivity().getMainLooper());
- final Runnable r = () -> {
+ final Runnable r = () -> {
FeedMedia media = item.getMedia();
if (media != null && media.hasAlmostEnded() && UserPreferences.isAutoDelete()) {
DBWriter.deleteFeedMediaOfItem(getActivity(), media.getId());
}
};
- Snackbar snackbar = Snackbar.make(getView(), getString(R.string.marked_as_seen_label),
+ Snackbar snackbar = Snackbar.make(getView(), getString(R.string.removed_new_flag_label),
Snackbar.LENGTH_LONG);
snackbar.setAction(getString(R.string.undo), v -> {
DBWriter.markItemPlayed(FeedItem.NEW, item.getId());
@@ -518,7 +496,6 @@ public class AllEpisodesFragment extends Fragment {
h.removeCallbacks(r);
});
snackbar.show();
- h.postDelayed(r, (int)Math.ceil(snackbar.getDuration() * 1.05f));
+ h.postDelayed(r, (int) Math.ceil(snackbar.getDuration() * 1.05f));
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
index 4d34d076d..4bebfe4c9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
@@ -6,28 +6,28 @@ import android.util.Log;
import android.view.View;
import android.widget.ListView;
+import java.util.List;
+import java.util.ListIterator;
+
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.MediaplayerInfoActivity.MediaplayerInfoContentFragment;
import de.danoeh.antennapod.adapter.ChaptersListAdapter;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.view.EmptyViewHandler;
+import io.reactivex.Maybe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
-public class ChaptersFragment extends ListFragment implements MediaplayerInfoContentFragment {
-
+public class ChaptersFragment extends ListFragment {
private static final String TAG = "ChaptersFragment";
-
- private Playable media;
- private PlaybackController controller;
-
private ChaptersListAdapter adapter;
+ private PlaybackController controller;
+ private Disposable disposable;
+ private EmptyViewHandler emptyView;
- public static ChaptersFragment newInstance(Playable media) {
- ChaptersFragment f = new ChaptersFragment();
- f.media = media;
- return f;
- }
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
@@ -38,11 +38,13 @@ public class ChaptersFragment extends ListFragment implements MediaplayerInfoCon
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
lv.setPadding(0, vertPadding, 0, vertPadding);
+ emptyView = new EmptyViewHandler(getContext());
+ emptyView.attachToListView(lv);
+ emptyView.setIcon(R.attr.ic_bookmark);
+ emptyView.setTitle(R.string.no_chapters_head_label);
+ emptyView.setMessage(R.string.no_chapters_label);
+
adapter = new ChaptersListAdapter(getActivity(), 0, pos -> {
- if(controller == null) {
- Log.d(TAG, "controller is null");
- return;
- }
Chapter chapter = (Chapter) getListAdapter().getItem(pos);
controller.seekToChapter(chapter);
});
@@ -50,42 +52,83 @@ public class ChaptersFragment extends ListFragment implements MediaplayerInfoCon
}
@Override
- public void onResume() {
- super.onResume();
- adapter.setMedia(media);
- adapter.notifyDataSetChanged();
- if(media == null || media.getChapters() == null) {
- setEmptyText(getString(R.string.no_chapters_label));
- } else {
- setEmptyText(null);
+ public void onStart() {
+ super.onStart();
+ controller = new PlaybackController(getActivity(), false) {
+ @Override
+ public boolean loadMediaInfo() {
+ ChaptersFragment.this.loadMediaInfo();
+ return true;
+ }
+
+ @Override
+ public void onPositionObserverUpdate() {
+ adapter.notifyDataSetChanged();
+ }
+ };
+ controller.init();
+
+ loadMediaInfo();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+
+ if (disposable != null) {
+ disposable.dispose();
}
}
- public void onDestroy() {
- super.onDestroy();
- adapter = null;
+ @Override
+ public void onStop() {
+ super.onStop();
+ controller.release();
controller = null;
}
- @Override
- public void onMediaChanged(Playable media) {
- if(this.media == media) {
- return;
+ private void scrollTo(int position) {
+ getListView().setSelection(position);
+ }
+
+ private int getCurrentChapter(Playable media) {
+ int currentPosition = controller.getPosition();
+
+ List<Chapter> chapters = media.getChapters();
+ for (final ListIterator<Chapter> it = chapters.listIterator(); it.hasNext(); ) {
+ Chapter chapter = it.next();
+ if (chapter.getStart() > currentPosition) {
+ return it.previousIndex() - 1;
+ }
}
- this.media = media;
+ return chapters.size() - 1;
+ }
+
+ private void loadMediaInfo() {
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ disposable = Maybe.create(emitter -> {
+ Playable media = controller.getMedia();
+ if (media != null) {
+ emitter.onSuccess(media);
+ } else {
+ emitter.onComplete();
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(media -> onMediaChanged((Playable) media),
+ error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+
+ private void onMediaChanged(Playable media) {
if (adapter != null) {
adapter.setMedia(media);
adapter.notifyDataSetChanged();
- if(media == null || media.getChapters() == null || media.getChapters().size() == 0) {
- setEmptyText(getString(R.string.no_items_label));
- } else {
- setEmptyText(null);
+ if (media != null && media.getChapters() != null && media.getChapters().size() != 0) {
+ scrollTo(getCurrentChapter(media));
}
}
}
-
- public void setController(PlaybackController controller) {
- this.controller = controller;
- }
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java
new file mode 100644
index 000000000..1d9020f0d
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java
@@ -0,0 +1,173 @@
+package de.danoeh.antennapod.fragment;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.widget.SearchView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.GridView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
+import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
+import de.danoeh.antennapod.discovery.CombinedSearcher;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import io.reactivex.disposables.Disposable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CombinedSearchFragment extends Fragment {
+
+ private static final String TAG = "CombinedSearchFragment";
+ public static final String ARGUMENT_QUERY = "query";
+
+ /**
+ * Adapter responsible with the search results
+ */
+ private ItunesAdapter adapter;
+ private GridView gridView;
+ private ProgressBar progressBar;
+ private TextView txtvError;
+ private Button butRetry;
+ private TextView txtvEmpty;
+
+ /**
+ * List of podcasts retreived from the search
+ */
+ private List<PodcastSearchResult> searchResults = new ArrayList<>();
+ private Disposable disposable;
+
+ /**
+ * Constructor
+ */
+ public CombinedSearchFragment() {
+ // Required empty public constructor
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
+ gridView = root.findViewById(R.id.gridView);
+ adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
+ gridView.setAdapter(adapter);
+
+ //Show information about the podcast when the list item is clicked
+ gridView.setOnItemClickListener((parent, view1, position, id) -> {
+ PodcastSearchResult podcast = searchResults.get(position);
+ Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl);
+ intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, podcast.title);
+ startActivity(intent);
+ });
+ progressBar = root.findViewById(R.id.progressBar);
+ txtvError = root.findViewById(R.id.txtvError);
+ butRetry = root.findViewById(R.id.butRetry);
+ txtvEmpty = root.findViewById(android.R.id.empty);
+
+ return root;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ adapter = null;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.itunes_search, menu);
+ MenuItem searchItem = menu.findItem(R.id.action_search);
+ final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
+ MenuItemUtils.adjustTextColor(getActivity(), sv);
+ sv.setQueryHint(getString(R.string.search_label));
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ search(s);
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ getActivity().getSupportFragmentManager().popBackStack();
+ return true;
+ }
+ });
+ MenuItemCompat.expandActionView(searchItem);
+
+ if (getArguments() != null && getArguments().getString(ARGUMENT_QUERY, null) != null) {
+ sv.setQuery(getArguments().getString(ARGUMENT_QUERY, null), true);
+ }
+ }
+
+ private void search(String query) {
+ if (disposable != null) {
+ disposable.dispose();
+ }
+
+ showOnlyProgressBar();
+
+ CombinedSearcher searcher = new CombinedSearcher(getContext());
+ disposable = searcher.search(query).subscribe(result -> {
+ searchResults = result;
+ progressBar.setVisibility(View.GONE);
+
+ adapter.clear();
+ adapter.addAll(searchResults);
+ adapter.notifyDataSetInvalidated();
+ gridView.setVisibility(!searchResults.isEmpty() ? View.VISIBLE : View.GONE);
+ txtvEmpty.setVisibility(searchResults.isEmpty() ? View.VISIBLE : View.GONE);
+
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ txtvError.setText(error.toString());
+ txtvError.setVisibility(View.VISIBLE);
+ butRetry.setOnClickListener(v -> search(query));
+ butRetry.setVisibility(View.VISIBLE);
+ });
+ }
+
+ private void showOnlyProgressBar() {
+ gridView.setVisibility(View.GONE);
+ txtvError.setVisibility(View.GONE);
+ butRetry.setVisibility(View.GONE);
+ txtvEmpty.setVisibility(View.GONE);
+ progressBar.setVisibility(View.VISIBLE);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
index 4bba9b255..705151062 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.fragment;
-import android.content.Context;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.Menu;
@@ -10,6 +10,7 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
+import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
@@ -21,11 +22,15 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
+import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_ADD_TO_QUEUE;
+import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DELETE;
+
/**
* Displays all running downloads and provides a button to delete them
*/
@@ -37,24 +42,27 @@ public class CompletedDownloadsFragment extends ListFragment {
EventDistributor.DOWNLOADLOG_UPDATE |
EventDistributor.UNREAD_ITEMS_UPDATE;
- private List<FeedItem> items;
+ private List<FeedItem> items = new ArrayList<>();
private DownloadedEpisodesListAdapter listAdapter;
-
- private boolean viewCreated = false;
-
private Disposable disposable;
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
- loadItems();
+ addVerticalPadding();
+ addEmptyView();
+
+ listAdapter = new DownloadedEpisodesListAdapter(getActivity(), itemAccess);
+ setListAdapter(listAdapter);
+ setListShown(false);
}
@Override
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
+ loadItems();
}
@Override
@@ -67,99 +75,54 @@ public class CompletedDownloadsFragment extends ListFragment {
}
@Override
- public void onDetach() {
- super.onDetach();
- if (disposable != null) {
- disposable.dispose();
- }
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- listAdapter = null;
- viewCreated = false;
- if (disposable != null) {
- disposable.dispose();
- }
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- if (viewCreated && items != null) {
- onFragmentLoaded();
- }
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- // add padding
- final ListView lv = getListView();
- lv.setClipToPadding(false);
- final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
- lv.setPadding(0, vertPadding, 0, vertPadding);
-
- viewCreated = true;
- if (items != null && getActivity() != null) {
- onFragmentLoaded();
- }
- }
-
- @Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
position -= l.getHeaderViewsCount();
long[] ids = FeedItemUtil.getIds(items);
- ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(ids, position));
- }
-
- private void onFragmentLoaded() {
- if (listAdapter == null) {
- listAdapter = new DownloadedEpisodesListAdapter(getActivity(), itemAccess);
- setListAdapter(listAdapter);
- }
- setListShown(true);
- listAdapter.notifyDataSetChanged();
- getActivity().supportInvalidateOptionsMenu();
+ ((MainActivity) requireActivity()).loadChildFragment(ItemFragment.newInstance(ids, position));
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if(!isAdded()) {
- return;
- }
super.onCreateOptionsMenu(menu, inflater);
- if(items != null) {
- inflater.inflate(R.menu.downloads_completed, menu);
- menu.findItem(R.id.episode_actions).setVisible(items.size() > 0);
- }
+ inflater.inflate(R.menu.downloads_completed, menu);
+ menu.findItem(R.id.episode_actions).setVisible(items.size() > 0);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.episode_actions:
- EpisodesApplyActionFragment fragment = EpisodesApplyActionFragment
- .newInstance(items, EpisodesApplyActionFragment.ACTION_REMOVE | EpisodesApplyActionFragment.ACTION_QUEUE);
- ((MainActivity) getActivity()).loadChildFragment(fragment);
- return true;
- default:
- return false;
+ if (item.getItemId() == R.id.episode_actions) {
+ ((MainActivity) requireActivity())
+ .loadChildFragment(EpisodesApplyActionFragment.newInstance(items, ACTION_DELETE | ACTION_ADD_TO_QUEUE));
+ return true;
}
+ return false;
+ }
+
+ private void addEmptyView() {
+ EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
+ emptyView.setIcon(R.attr.av_download);
+ emptyView.setTitle(R.string.no_comp_downloads_head_label);
+ emptyView.setMessage(R.string.no_comp_downloads_label);
+ emptyView.attachToListView(getListView());
+ }
+
+ private void addVerticalPadding() {
+ final ListView lv = getListView();
+ lv.setClipToPadding(false);
+ final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
+ lv.setPadding(0, vertPadding, 0, vertPadding);
}
private final DownloadedEpisodesListAdapter.ItemAccess itemAccess = new DownloadedEpisodesListAdapter.ItemAccess() {
@Override
public int getCount() {
- return (items != null) ? items.size() : 0;
+ return items.size();
}
@Override
public FeedItem getItem(int position) {
- if (items != null && 0 <= position && position < items.size()) {
+ if (0 <= position && position < items.size()) {
return items.get(position);
} else {
return null;
@@ -168,7 +131,7 @@ public class CompletedDownloadsFragment extends ListFragment {
@Override
public void onFeedItemSecondaryAction(FeedItem item) {
- DBWriter.deleteFeedMediaOfItem(getActivity(), item.getMedia().getId());
+ DBWriter.deleteFeedMediaOfItem(requireActivity(), item.getMedia().getId());
}
};
@@ -185,18 +148,18 @@ public class CompletedDownloadsFragment extends ListFragment {
if (disposable != null) {
disposable.dispose();
}
- if (items == null && viewCreated) {
- setListShown(false);
- }
disposable = Observable.fromCallable(DBReader::getDownloadedItems)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
items = result;
- if (viewCreated && getActivity() != null) {
- onFragmentLoaded();
- }
- }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ onItemsLoaded();
+ }, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
+ private void onItemsLoaded() {
+ setListShown(true);
+ listAdapter.notifyDataSetChanged();
+ requireActivity().invalidateOptionsMenu();
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
index 5a061c7e6..db9dd9530 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
@@ -13,74 +14,68 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.MediaplayerInfoActivity.MediaplayerInfoContentFragment;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.util.playback.Playable;
+import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import io.reactivex.Maybe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Displays the cover and the title of a FeedItem.
*/
-public class CoverFragment extends Fragment implements MediaplayerInfoContentFragment {
+public class CoverFragment extends Fragment {
private static final String TAG = "CoverFragment";
- private Playable media;
-
private View root;
private TextView txtvPodcastTitle;
private TextView txtvEpisodeTitle;
private ImageView imgvCover;
-
- public static CoverFragment newInstance(Playable item) {
- CoverFragment f = new CoverFragment();
- f.media = item;
- return f;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (media == null) {
- Log.e(TAG, TAG + " was called without media");
- }
- }
+ private PlaybackController controller;
+ private Disposable disposable;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
+ setRetainInstance(true);
root = inflater.inflate(R.layout.cover_fragment, container, false);
txtvPodcastTitle = root.findViewById(R.id.txtvPodcastTitle);
txtvEpisodeTitle = root.findViewById(R.id.txtvEpisodeTitle);
imgvCover = root.findViewById(R.id.imgvCover);
+ imgvCover.setOnClickListener(v -> onPlayPause());
return root;
}
private void loadMediaInfo() {
- if (media != null) {
- txtvPodcastTitle.setText(media.getFeedTitle());
- txtvEpisodeTitle.setText(media.getEpisodeTitle());
- Glide.with(this)
- .load(media.getImageLocation())
- .apply(new RequestOptions()
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .dontAnimate()
- .fitCenter())
- .into(imgvCover);
- } else {
- Log.w(TAG, "loadMediaInfo was called while media was null");
+ if (disposable != null) {
+ disposable.dispose();
}
+ disposable = Maybe.create(emitter -> {
+ Playable media = controller.getMedia();
+ if (media != null) {
+ emitter.onSuccess(media);
+ } else {
+ emitter.onComplete();
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(media -> displayMediaInfo((Playable) media),
+ error -> Log.e(TAG, Log.getStackTraceString(error)));
}
- @Override
- public void onStart() {
- Log.d(TAG, "On Start");
- super.onStart();
- if (media != null) {
- Log.d(TAG, "Loading media info");
- loadMediaInfo();
- } else {
- Log.w(TAG, "Unable to load media info: media was null");
- }
+ private void displayMediaInfo(@NonNull Playable media) {
+ txtvPodcastTitle.setText(media.getFeedTitle());
+ txtvEpisodeTitle.setText(media.getEpisodeTitle());
+ Glide.with(this)
+ .load(media.getImageLocation())
+ .apply(new RequestOptions()
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .dontAnimate()
+ .fitCenter())
+ .into(imgvCover);
}
@Override
@@ -91,14 +86,40 @@ public class CoverFragment extends Fragment implements MediaplayerInfoContentFra
}
@Override
- public void onMediaChanged(Playable media) {
- if(this.media == media) {
- return;
- }
- this.media = media;
- if (isAdded()) {
- loadMediaInfo();
+ public void onStart() {
+ super.onStart();
+ controller = new PlaybackController(getActivity(), false) {
+ @Override
+ public boolean loadMediaInfo() {
+ CoverFragment.this.loadMediaInfo();
+ return true;
+ }
+
+ };
+ controller.init();
+ loadMediaInfo();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ controller.release();
+ controller = null;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+
+ if (disposable != null) {
+ disposable.dispose();
}
}
+ void onPlayPause() {
+ if (controller == null) {
+ return;
+ }
+ controller.playPause();
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
index 5ab6bac63..26b115b4b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -14,15 +14,18 @@ import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
+import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.DownloadLogAdapter;
import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -35,18 +38,13 @@ public class DownloadLogFragment extends ListFragment {
private static final String TAG = "DownloadLogFragment";
- private List<DownloadStatus> downloadLog;
+ private List<DownloadStatus> downloadLog = new ArrayList<>();
private DownloadLogAdapter adapter;
-
- private boolean viewsCreated = false;
- private boolean itemsLoaded = false;
-
private Disposable disposable;
@Override
public void onStart() {
super.onStart();
- setHasOptionsMenu(true);
EventDistributor.getInstance().register(contentUpdate);
loadItems();
}
@@ -55,7 +53,7 @@ public class DownloadLogFragment extends ListFragment {
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
- if(disposable != null) {
+ if (disposable != null) {
disposable.dispose();
}
}
@@ -63,6 +61,7 @@ public class DownloadLogFragment extends ListFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+ setHasOptionsMenu(true);
// add padding
final ListView lv = getListView();
@@ -70,17 +69,17 @@ public class DownloadLogFragment extends ListFragment {
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
lv.setPadding(0, vertPadding, 0, vertPadding);
- viewsCreated = true;
- if (itemsLoaded) {
- onFragmentLoaded();
- }
+ EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
+ emptyView.setIcon(R.attr.av_download);
+ emptyView.setTitle(R.string.no_log_downloads_head_label);
+ emptyView.setMessage(R.string.no_log_downloads_label);
+ emptyView.attachToListView(getListView());
+
+ adapter = new DownloadLogAdapter(getActivity(), itemAccess);
+ setListAdapter(adapter);
}
private void onFragmentLoaded() {
- if (adapter == null) {
- adapter = new DownloadLogAdapter(getActivity(), itemAccess);
- setListAdapter(adapter);
- }
setListShown(true);
adapter.notifyDataSetChanged();
getActivity().supportInvalidateOptionsMenu();
@@ -93,10 +92,18 @@ public class DownloadLogFragment extends ListFragment {
DownloadStatus status = adapter.getItem(position);
String url = "unknown";
String message = getString(R.string.download_successful);
- FeedMedia media = DBReader.getFeedMedia(status.getFeedfileId());
- if (media != null) {
- url = media.getDownload_url();
+ if (status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
+ FeedMedia media = DBReader.getFeedMedia(status.getFeedfileId());
+ if (media != null) {
+ url = media.getDownload_url();
+ }
+ } else if (status.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
+ Feed feed = DBReader.getFeed(status.getFeedfileId());
+ if (feed != null) {
+ url = feed.getDownload_url();
+ }
}
+
if (!status.isSuccessful()) {
message = status.getReasonDetailed();
}
@@ -113,12 +120,12 @@ public class DownloadLogFragment extends ListFragment {
@Override
public int getCount() {
- return (downloadLog != null) ? downloadLog.size() : 0;
+ return downloadLog.size();
}
@Override
public DownloadStatus getItem(int position) {
- if (downloadLog != null && 0 <= position && position < downloadLog.size()) {
+ if (0 <= position && position < downloadLog.size()) {
return downloadLog.get(position);
} else {
return null;
@@ -138,27 +145,23 @@ public class DownloadLogFragment extends ListFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if(!isAdded()) {
+ if (!isAdded()) {
return;
}
super.onCreateOptionsMenu(menu, inflater);
- if (itemsLoaded) {
- MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
- MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
- TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.content_discard});
- clearHistory.setIcon(drawables.getDrawable(0));
- drawables.recycle();
- }
+ MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
+ MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.content_discard});
+ clearHistory.setIcon(drawables.getDrawable(0));
+ drawables.recycle();
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- if (itemsLoaded) {
- MenuItem menuItem = menu.findItem(R.id.clear_history_item);
- if(menuItem != null) {
- menuItem.setVisible(downloadLog != null && !downloadLog.isEmpty());
- }
+ MenuItem menuItem = menu.findItem(R.id.clear_history_item);
+ if (menuItem != null) {
+ menuItem.setVisible(!downloadLog.isEmpty());
}
}
@@ -178,7 +181,7 @@ public class DownloadLogFragment extends ListFragment {
}
private void loadItems() {
- if(disposable != null) {
+ if (disposable != null) {
disposable.dispose();
}
disposable = Observable.fromCallable(DBReader::getDownloadLog)
@@ -187,12 +190,8 @@ public class DownloadLogFragment extends ListFragment {
.subscribe(result -> {
if (result != null) {
downloadLog = result;
- itemsLoaded = true;
- if (viewsCreated) {
- onFragmentLoaded();
- }
+ onFragmentLoaded();
}
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
index de2f04590..348c73b92 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -18,6 +18,7 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.event.ServiceEvent;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
@@ -90,10 +91,6 @@ public class ExternalPlayerFragment extends Fragment {
loadMediaInfo();
}
- public void connectToPlaybackService() {
- controller.init();
- }
-
private PlaybackController setupPlaybackController() {
return new PlaybackController(getActivity(), true) {
@@ -109,12 +106,12 @@ public class ExternalPlayerFragment extends Fragment {
@Override
public boolean loadMediaInfo() {
- ExternalPlayerFragment fragment = ExternalPlayerFragment.this;
- if (fragment != null) {
- return fragment.loadMediaInfo();
- } else {
- return false;
- }
+ return ExternalPlayerFragment.this.loadMediaInfo();
+ }
+
+ @Override
+ public void setupGUI() {
+ ExternalPlayerFragment.this.loadMediaInfo();
}
@Override
@@ -133,17 +130,29 @@ public class ExternalPlayerFragment extends Fragment {
public void onResume() {
super.onResume();
onPositionObserverUpdate();
+ }
+ @Override
+ public void onStart() {
+ super.onStart();
+ controller = setupPlaybackController();
controller.init();
+ loadMediaInfo();
}
@Override
- public void onDestroy() {
- super.onDestroy();
- Log.d(TAG, "Fragment is about to be destroyed");
+ public void onStop() {
+ super.onStop();
if (controller != null) {
controller.release();
+ controller = null;
}
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.d(TAG, "Fragment is about to be destroyed");
if (disposable != null) {
disposable.dispose();
}
@@ -196,7 +205,8 @@ public class ExternalPlayerFragment extends Fragment {
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(media -> updateUi((Playable) media),
- error -> Log.e(TAG, Log.getStackTraceString(error)));
+ error -> Log.e(TAG, Log.getStackTraceString(error)),
+ () -> fragmentLayout.setVisibility(View.GONE));
return true;
}
@@ -217,7 +227,7 @@ public class ExternalPlayerFragment extends Fragment {
.into(imgvCover);
fragmentLayout.setVisibility(View.VISIBLE);
- if (controller.isPlayingVideoLocally()) {
+ if (controller != null && controller.isPlayingVideoLocally()) {
butPlay.setVisibility(View.GONE);
} else {
butPlay.setVisibility(View.VISIBLE);
@@ -232,7 +242,9 @@ public class ExternalPlayerFragment extends Fragment {
}
private void onPositionObserverUpdate() {
- if (controller.getPosition() == PlaybackService.INVALID_TIME
+ if (controller == null) {
+ return;
+ } else if (controller.getPosition() == PlaybackService.INVALID_TIME
|| controller.getDuration() == PlaybackService.INVALID_TIME) {
return;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
index 70f82c2ec..bb029b731 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
@@ -9,6 +10,8 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import org.greenrobot.eventbus.Subscribe;
+
import java.util.List;
import de.danoeh.antennapod.R;
@@ -18,38 +21,38 @@ import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
-
/**
* Like 'EpisodesFragment' except that it only shows favorite episodes and
* supports swiping to remove from favorites.
*/
-
public class FavoriteEpisodesFragment extends AllEpisodesFragment {
private static final String TAG = "FavoriteEpisodesFrag";
-
private static final String PREF_NAME = "PrefFavoriteEpisodesFragment";
@Override
- protected boolean showOnlyNewEpisodes() { return true; }
+ protected boolean showOnlyNewEpisodes() {
+ return true;
+ }
@Override
- protected String getPrefName() { return PREF_NAME; }
+ protected String getPrefName() {
+ return PREF_NAME;
+ }
+ @Subscribe
public void onEvent(FavoritesEvent event) {
- Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
+ Log.d(TAG, String.format("onEvent() called with: event = [%s]", event));
loadItems();
}
+ @NonNull
@Override
- protected void resetViewState() {
- super.resetViewState();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View root = super.onCreateViewHelper(inflater, container, savedInstanceState,
- R.layout.all_episodes_fragment);
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View root = super.onCreateView(inflater, container, savedInstanceState);
+ emptyView.setIcon(R.attr.ic_unfav);
+ emptyView.setTitle(R.string.no_fav_episodes_head_label);
+ emptyView.setMessage(R.string.no_fav_episodes_label);
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
@@ -59,8 +62,8 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment {
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
- AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder)viewHolder;
- Log.d(TAG, "remove(" + holder.getItemId() + ")");
+ AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) viewHolder;
+ Log.d(TAG, String.format("remove(%s)", holder.getItemId()));
if (disposable != null) {
disposable.dispose();
@@ -69,8 +72,7 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment {
if (item != null) {
DBWriter.removeFavoriteItem(item);
- Snackbar snackbar = Snackbar.make(root, getString(R.string.removed_item),
- Snackbar.LENGTH_LONG);
+ Snackbar snackbar = Snackbar.make(root, getString(R.string.removed_item), Snackbar.LENGTH_LONG);
snackbar.setAction(getString(R.string.undo), v -> DBWriter.addFavoriteItem(item));
snackbar.show();
}
@@ -82,6 +84,7 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment {
return root;
}
+ @NonNull
@Override
protected List<FeedItem> loadData() {
return DBReader.getFavoriteItemsList();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
new file mode 100644
index 000000000..4fb3d90f5
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
@@ -0,0 +1,177 @@
+package de.danoeh.antennapod.fragment;
+
+import android.arch.lifecycle.ViewModelProviders;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedFilter;
+import de.danoeh.antennapod.core.feed.FeedPreferences;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.dialog.AuthenticationDialog;
+import de.danoeh.antennapod.dialog.EpisodeFilterDialog;
+import de.danoeh.antennapod.viewmodel.FeedSettingsViewModel;
+
+import static de.danoeh.antennapod.activity.FeedSettingsActivity.EXTRA_FEED_ID;
+
+public class FeedSettingsFragment extends PreferenceFragmentCompat {
+ private static final CharSequence PREF_EPISODE_FILTER = "episodeFilter";
+ private Feed feed;
+ private FeedPreferences feedPreferences;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.feed_settings);
+
+ long feedId = getArguments().getLong(EXTRA_FEED_ID);
+ ViewModelProviders.of(getActivity()).get(FeedSettingsViewModel.class).getFeed(feedId)
+ .subscribe(result -> {
+ feed = result;
+ feedPreferences = feed.getPreferences();
+
+ setupAutoDownloadPreference();
+ setupKeepUpdatedPreference();
+ setupAutoDeletePreference();
+ setupAuthentificationPreference();
+ setupEpisodeFilterPreference();
+
+ updateAutoDeleteSummary();
+ updateAutoDownloadEnabled();
+ }).dispose();
+ }
+
+ private void setupEpisodeFilterPreference() {
+ findPreference(PREF_EPISODE_FILTER).setOnPreferenceClickListener(preference -> {
+ new EpisodeFilterDialog(getContext(), feedPreferences.getFilter()) {
+ @Override
+ protected void onConfirmed(FeedFilter filter) {
+ feedPreferences.setFilter(filter);
+ feed.savePreferences();
+ }
+ }.show();
+ return false;
+ });
+ }
+
+ private void setupAuthentificationPreference() {
+ findPreference("authentication").setOnPreferenceClickListener(preference -> {
+ new AuthenticationDialog(getContext(),
+ R.string.authentication_label, true, false,
+ feedPreferences.getUsername(), feedPreferences.getPassword()) {
+ @Override
+ protected void onConfirmed(String username, String password, boolean saveUsernamePassword) {
+ feedPreferences.setUsername(username);
+ feedPreferences.setPassword(password);
+ feed.savePreferences();
+ }
+ }.show();
+ return false;
+ });
+ }
+
+ private void setupAutoDeletePreference() {
+ ListPreference autoDeletePreference = (ListPreference) findPreference("autoDelete");
+ autoDeletePreference.setOnPreferenceChangeListener((preference, newValue) -> {
+ switch ((String) newValue) {
+ case "global":
+ feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.GLOBAL);
+ break;
+ case "always":
+ feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.YES);
+ break;
+ case "never":
+ feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.NO);
+ break;
+ }
+ feed.savePreferences();
+ updateAutoDeleteSummary();
+ return false;
+ });
+ }
+
+ private void updateAutoDeleteSummary() {
+ ListPreference autoDeletePreference = (ListPreference) findPreference("autoDelete");
+
+ switch (feedPreferences.getAutoDeleteAction()) {
+ case GLOBAL:
+ autoDeletePreference.setSummary(R.string.feed_auto_download_global);
+ autoDeletePreference.setValue("global");
+ break;
+ case YES:
+ autoDeletePreference.setSummary(R.string.feed_auto_download_always);
+ autoDeletePreference.setValue("always");
+ break;
+ case NO:
+ autoDeletePreference.setSummary(R.string.feed_auto_download_never);
+ autoDeletePreference.setValue("never");
+ break;
+ }
+ }
+
+ private void setupKeepUpdatedPreference() {
+ SwitchPreference pref = (SwitchPreference) findPreference("keepUpdated");
+
+ pref.setChecked(feedPreferences.getKeepUpdated());
+ pref.setOnPreferenceChangeListener((preference, newValue) -> {
+ boolean checked = newValue == Boolean.TRUE;
+ feedPreferences.setKeepUpdated(checked);
+ feed.savePreferences();
+ pref.setChecked(checked);
+ return false;
+ });
+ }
+
+ private void setupAutoDownloadPreference() {
+ SwitchPreference pref = (SwitchPreference) findPreference("autoDownload");
+
+ pref.setEnabled(UserPreferences.isEnableAutodownload());
+ if (UserPreferences.isEnableAutodownload()) {
+ pref.setChecked(feedPreferences.getAutoDownload());
+ } else {
+ pref.setChecked(false);
+ pref.setSummary(R.string.auto_download_disabled_globally);
+ }
+
+ pref.setOnPreferenceChangeListener((preference, newValue) -> {
+ boolean checked = newValue == Boolean.TRUE;
+
+ feedPreferences.setAutoDownload(checked);
+ feed.savePreferences();
+ updateAutoDownloadEnabled();
+ ApplyToEpisodesDialog dialog = new ApplyToEpisodesDialog(getActivity(), checked);
+ dialog.createNewDialog().show();
+ pref.setChecked(checked);
+ return false;
+ });
+ }
+
+ private void updateAutoDownloadEnabled() {
+ if (feed != null && feed.getPreferences() != null) {
+ boolean enabled = feed.getPreferences().getAutoDownload() && UserPreferences.isEnableAutodownload();
+ findPreference(PREF_EPISODE_FILTER).setEnabled(enabled);
+ }
+ }
+
+ private class ApplyToEpisodesDialog extends ConfirmationDialog {
+ private final boolean autoDownload;
+
+ ApplyToEpisodesDialog(Context context, boolean autoDownload) {
+ super(context, R.string.auto_download_apply_to_items_title,
+ R.string.auto_download_apply_to_items_message);
+ this.autoDownload = autoDownload;
+ setPositiveText(R.string.yes);
+ setNegativeText(R.string.no);
+ }
+
+ @Override
+ public void onConfirmButtonPressed(DialogInterface dialog) {
+ DBWriter.setFeedsItemsAutoDownload(feed, autoDownload);
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
index dadc596e2..9c16cfe56 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
@@ -16,24 +16,16 @@ import android.widget.Button;
import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.List;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
-import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import de.danoeh.antennapod.discovery.FyydPodcastSearcher;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
-import de.mfietz.fyydlin.FyydClient;
-import de.mfietz.fyydlin.FyydResponse;
-import de.mfietz.fyydlin.SearchHit;
-import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
-import io.reactivex.schedulers.Schedulers;
-import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast;
-import static java.util.Collections.emptyList;
+import java.util.ArrayList;
+import java.util.List;
public class FyydSearchFragment extends Fragment {
@@ -49,12 +41,10 @@ public class FyydSearchFragment extends Fragment {
private Button butRetry;
private TextView txtvEmpty;
- private final FyydClient client = new FyydClient(AntennapodHttpClient.getHttpClient());
-
/**
* List of podcasts retreived from the search
*/
- private List<Podcast> searchResults;
+ private List<PodcastSearchResult> searchResults;
private Disposable disposable;
/**
@@ -81,7 +71,7 @@ public class FyydSearchFragment extends Fragment {
//Show information about the podcast when the list item is clicked
gridView.setOnItemClickListener((parent, view1, position, id) -> {
- Podcast podcast = searchResults.get(position);
+ PodcastSearchResult podcast = searchResults.get(position);
Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl);
intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, podcast.title);
@@ -145,20 +135,26 @@ public class FyydSearchFragment extends Fragment {
disposable.dispose();
}
showOnlyProgressBar();
- disposable = client.searchPodcasts(query, 10)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- progressBar.setVisibility(View.GONE);
- processSearchResult(result);
- }, error -> {
- Log.e(TAG, Log.getStackTraceString(error));
- progressBar.setVisibility(View.GONE);
- txtvError.setText(error.toString());
- txtvError.setVisibility(View.VISIBLE);
- butRetry.setOnClickListener(v -> search(query));
- butRetry.setVisibility(View.VISIBLE);
- });
+
+ FyydPodcastSearcher searcher = new FyydPodcastSearcher();
+ disposable = searcher.search(query).subscribe(result -> {
+ searchResults = result;
+ progressBar.setVisibility(View.GONE);
+
+ adapter.clear();
+ adapter.addAll(searchResults);
+ adapter.notifyDataSetInvalidated();
+ gridView.setVisibility(!searchResults.isEmpty() ? View.VISIBLE : View.GONE);
+ txtvEmpty.setVisibility(searchResults.isEmpty() ? View.VISIBLE : View.GONE);
+
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ txtvError.setText(error.toString());
+ txtvError.setVisibility(View.VISIBLE);
+ butRetry.setOnClickListener(v -> search(query));
+ butRetry.setVisibility(View.VISIBLE);
+ });
}
private void showOnlyProgressBar() {
@@ -168,25 +164,4 @@ public class FyydSearchFragment extends Fragment {
txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
}
-
- private void processSearchResult(FyydResponse response) {
- adapter.clear();
- if (!response.getData().isEmpty()) {
- adapter.clear();
- searchResults = new ArrayList<>();
- for (SearchHit searchHit : response.getData()) {
- Podcast podcast = Podcast.fromSearch(searchHit);
- searchResults.add(podcast);
- }
- } else {
- searchResults = emptyList();
- }
- for(Podcast podcast : searchResults) {
- adapter.add(podcast);
- }
- adapter.notifyDataSetInvalidated();
- gridView.setVisibility(!searchResults.isEmpty() ? View.VISIBLE : View.GONE);
- txtvEmpty.setVisibility(searchResults.isEmpty() ? View.VISIBLE : View.GONE);
- }
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
index 4ee7a06ad..5cf2c5eeb 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -10,7 +10,9 @@ import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.ContextMenu;
@@ -27,16 +29,11 @@ import android.widget.Toast;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MediaplayerInfoActivity;
-import de.danoeh.antennapod.activity.MediaplayerInfoActivity.MediaplayerInfoContentFragment;
-import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
-import de.danoeh.antennapod.core.util.ShownotesProvider;
-import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.core.util.playback.Timeline;
import io.reactivex.Observable;
@@ -47,7 +44,7 @@ import io.reactivex.schedulers.Schedulers;
/**
* Displays the description of a Playable object in a Webview.
*/
-public class ItemDescriptionFragment extends Fragment implements MediaplayerInfoContentFragment {
+public class ItemDescriptionFragment extends Fragment {
private static final String TAG = "ItemDescriptionFragment";
@@ -55,58 +52,16 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
private static final String PREF_SCROLL_Y = "prefScrollY";
private static final String PREF_PLAYABLE_ID = "prefPlayableId";
- private static final String ARG_PLAYABLE = "arg.playable";
- private static final String ARG_FEEDITEM_ID = "arg.feeditem";
-
- private static final String ARG_SAVE_STATE = "arg.saveState";
- private static final String ARG_HIGHLIGHT_TIMECODES = "arg.highlightTimecodes";
-
private WebView webvDescription;
-
- private ShownotesProvider shownotesProvider;
- private Playable media;
-
private Disposable webViewLoader;
+ private PlaybackController controller;
/**
* URL that was selected via long-press.
*/
private String selectedURL;
- /**
- * True if Fragment should save its state (e.g. scrolling position) in a
- * shared preference.
- */
- private boolean saveState;
-
- /**
- * True if Fragment should highlight timecodes (e.g. time codes in the HH:MM:SS format).
- */
- private boolean highlightTimecodes;
-
- public static ItemDescriptionFragment newInstance(Playable media,
- boolean saveState,
- boolean highlightTimecodes) {
- ItemDescriptionFragment f = new ItemDescriptionFragment();
- Bundle args = new Bundle();
- args.putParcelable(ARG_PLAYABLE, media);
- args.putBoolean(ARG_SAVE_STATE, saveState);
- args.putBoolean(ARG_HIGHLIGHT_TIMECODES, highlightTimecodes);
- f.setArguments(args);
- return f;
- }
-
- public static ItemDescriptionFragment newInstance(FeedItem item, boolean saveState, boolean highlightTimecodes) {
- ItemDescriptionFragment f = new ItemDescriptionFragment();
- Bundle args = new Bundle();
- args.putLong(ARG_FEEDITEM_ID, item.getId());
- args.putBoolean(ARG_SAVE_STATE, saveState);
- args.putBoolean(ARG_HIGHLIGHT_TIMECODES, highlightTimecodes);
- f.setArguments(args);
- return f;
- }
- @SuppressLint("NewApi")
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@@ -126,6 +81,10 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
webvDescription.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
// Use cached resources, even if they have expired
}
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ webvDescription.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
+ }
+
webvDescription.getSettings().setUseWideViewPort(false);
webvDescription.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
webvDescription.getSettings().setLoadWithOverviewMode(true);
@@ -175,39 +134,6 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
}
}
- @SuppressLint("NewApi")
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.d(TAG, "Creating fragment");
- Bundle args = getArguments();
- saveState = args.getBoolean(ARG_SAVE_STATE, false);
- highlightTimecodes = args.getBoolean(ARG_HIGHLIGHT_TIMECODES, false);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- Bundle args = getArguments();
- if (args.containsKey(ARG_PLAYABLE)) {
- if (media == null) {
- media = args.getParcelable(ARG_PLAYABLE);
- shownotesProvider = media;
- }
- load();
- } else if (args.containsKey(ARG_FEEDITEM_ID)) {
- long id = getArguments().getLong(ARG_FEEDITEM_ID);
- Observable.defer(() -> Observable.just(DBReader.getFeedItem(id)))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(feedItem -> {
- shownotesProvider = feedItem;
- load();
- }, error -> Log.e(TAG, Log.getStackTraceString(error)));
- }
- }
-
-
private final View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
@Override
@@ -300,22 +226,20 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
if(webViewLoader != null) {
webViewLoader.dispose();
}
- if(shownotesProvider == null) {
- return;
- }
webViewLoader = Observable.fromCallable(this::loadData)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
- webvDescription.loadDataWithBaseURL(null, data, "text/html",
+ webvDescription.loadDataWithBaseURL("https://127.0.0.1", data, "text/html",
"utf-8", "about:blank");
Log.d(TAG, "Webview loaded");
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
+ @NonNull
private String loadData() {
- Timeline timeline = new Timeline(getActivity(), shownotesProvider);
- return timeline.processShownotes(highlightTimecodes);
+ Timeline timeline = new Timeline(getActivity(), controller.getMedia());
+ return timeline.processShownotes(true);
}
@Override
@@ -325,42 +249,38 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
}
private void savePreference() {
- if (saveState) {
- Log.d(TAG, "Saving preferences");
- SharedPreferences prefs = getActivity().getSharedPreferences(PREF,
- Activity.MODE_PRIVATE);
- SharedPreferences.Editor editor = prefs.edit();
- if (media != null && webvDescription != null) {
- Log.d(TAG, "Saving scroll position: " + webvDescription.getScrollY());
- editor.putInt(PREF_SCROLL_Y, webvDescription.getScrollY());
- editor.putString(PREF_PLAYABLE_ID, media.getIdentifier()
- .toString());
- } else {
- Log.d(TAG, "savePreferences was called while media or webview was null");
- editor.putInt(PREF_SCROLL_Y, -1);
- editor.putString(PREF_PLAYABLE_ID, "");
- }
- editor.commit();
+ Log.d(TAG, "Saving preferences");
+ SharedPreferences prefs = getActivity().getSharedPreferences(PREF,
+ Activity.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+ if (controller != null && controller.getMedia() != null && webvDescription != null) {
+ Log.d(TAG, "Saving scroll position: " + webvDescription.getScrollY());
+ editor.putInt(PREF_SCROLL_Y, webvDescription.getScrollY());
+ editor.putString(PREF_PLAYABLE_ID, controller.getMedia().getIdentifier()
+ .toString());
+ } else {
+ Log.d(TAG, "savePreferences was called while media or webview was null");
+ editor.putInt(PREF_SCROLL_Y, -1);
+ editor.putString(PREF_PLAYABLE_ID, "");
}
+ editor.commit();
}
private boolean restoreFromPreference() {
- if (saveState) {
- Log.d(TAG, "Restoring from preferences");
- Activity activity = getActivity();
- if (activity != null) {
- SharedPreferences prefs = activity.getSharedPreferences(
- PREF, Activity.MODE_PRIVATE);
- String id = prefs.getString(PREF_PLAYABLE_ID, "");
- int scrollY = prefs.getInt(PREF_SCROLL_Y, -1);
- if (scrollY != -1 && media != null
- && id.equals(media.getIdentifier().toString())
- && webvDescription != null) {
- Log.d(TAG, "Restored scroll Position: " + scrollY);
- webvDescription.scrollTo(webvDescription.getScrollX(),
- scrollY);
- return true;
- }
+ Log.d(TAG, "Restoring from preferences");
+ Activity activity = getActivity();
+ if (activity != null) {
+ SharedPreferences prefs = activity.getSharedPreferences(
+ PREF, Activity.MODE_PRIVATE);
+ String id = prefs.getString(PREF_PLAYABLE_ID, "");
+ int scrollY = prefs.getInt(PREF_SCROLL_Y, -1);
+ if (controller != null && scrollY != -1 && controller.getMedia() != null
+ && id.equals(controller.getMedia().getIdentifier().toString())
+ && webvDescription != null) {
+ Log.d(TAG, "Restored scroll Position: " + scrollY);
+ webvDescription.scrollTo(webvDescription.getScrollX(),
+ scrollY);
+ return true;
}
}
return false;
@@ -377,15 +297,27 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
}
@Override
- public void onMediaChanged(Playable media) {
- if(this.media == media) {
- return;
- }
- this.media = media;
- this.shownotesProvider = media;
- if (webvDescription != null) {
- load();
- }
+ public void onStart() {
+ super.onStart();
+ controller = new PlaybackController(getActivity(), false) {
+ @Override
+ public boolean loadMediaInfo() {
+ if (getMedia() == null) {
+ return false;
+ }
+ load();
+ return true;
+ }
+
+ };
+ controller.init();
+ load();
}
+ @Override
+ public void onStop() {
+ super.onStop();
+ controller.release();
+ controller = null;
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
index bcca281d4..432ada44e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -36,13 +36,16 @@ import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconButton;
import org.apache.commons.lang3.ArrayUtils;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.CastEnabledActivity;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
+import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
@@ -61,14 +64,12 @@ import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.DateUtils;
import de.danoeh.antennapod.core.util.Flavors;
import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
import de.danoeh.antennapod.core.util.playback.Timeline;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.view.OnSwipeGesture;
import de.danoeh.antennapod.view.SwipeGestureDetector;
-import de.greenrobot.event.EventBus;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -196,6 +197,9 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
webvDescription.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
// Use cached resources, even if they have expired
}
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ webvDescription.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
+ }
webvDescription.getSettings().setUseWideViewPort(false);
webvDescription.getSettings().setLayoutAlgorithm(
WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
@@ -227,9 +231,9 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
if (item == null) {
return;
}
- DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getActivity());
- actionButtonCallback.onActionButtonPressed(item, item.isTagged(FeedItem.TAG_QUEUE) ?
- LongList.of(item.getId()) : new LongList(0));
+ ItemActionButton actionButton = ItemActionButton.forItem(item, item.isTagged(FeedItem.TAG_QUEUE));
+ actionButton.onClick(getActivity());
+
FeedMedia media = item.getMedia();
if (media != null && media.isDownloaded()) {
// playback was started, dialog should close itself
@@ -262,14 +266,19 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ EventDistributor.getInstance().register(contentUpdate);
+ EventBus.getDefault().register(this);
load();
}
@Override
public void onResume() {
super.onResume();
- EventDistributor.getInstance().register(contentUpdate);
- EventBus.getDefault().registerSticky(this);
if(itemsLoaded) {
progbarLoading.setVisibility(View.GONE);
updateAppearance();
@@ -277,8 +286,8 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
}
@Override
- public void onPause() {
- super.onPause();
+ public void onStop() {
+ super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
}
@@ -297,19 +306,20 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
@Override
public boolean onSwipeLeftToRight() {
- Log.d(TAG, "onSwipeLeftToRight()");
- feedItemPos = feedItemPos - 1;
- if(feedItemPos < 0) {
- feedItemPos = feedItems.length - 1;
- }
- load();
- return true;
+ return swipeFeedItem(-1);
}
@Override
public boolean onSwipeRightToLeft() {
- Log.d(TAG, "onSwipeRightToLeft()");
- feedItemPos = (feedItemPos + 1) % feedItems.length;
+ return swipeFeedItem(+1);
+ }
+
+ private boolean swipeFeedItem(int position) {
+ Log.d(TAG, String.format("onSwipe() shift: %s", position));
+ feedItemPos = (feedItemPos + position) % feedItems.length;
+ if (feedItemPos < 0) {
+ feedItemPos = feedItems.length - 1;
+ }
load();
return true;
}
@@ -358,7 +368,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
private void onFragmentLoaded() {
if (webviewData != null) {
- webvDescription.loadDataWithBaseURL(null, webviewData, "text/html", "utf-8", "about:blank");
+ webvDescription.loadDataWithBaseURL("https://127.0.0.1", webviewData, "text/html", "utf-8", "about:blank");
}
updateAppearance();
}
@@ -537,6 +547,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
((MainActivity)getActivity()).loadChildFragment(fragment);
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
for(FeedItem item : event.items) {
@@ -547,6 +558,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
}
}
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
@@ -588,10 +600,12 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
+ @Nullable
private FeedItem loadInBackground() {
FeedItem feedItem = DBReader.getFeedItem(feedItems[feedItemPos]);
- if (feedItem != null) {
- Timeline t = new Timeline(getActivity(), feedItem);
+ Context context = getContext();
+ if (feedItem != null && context != null) {
+ Timeline t = new Timeline(context, feedItem);
webviewData = t.processShownotes(false);
}
return feedItem;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
index d9e318069..0c75af986 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -6,6 +6,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.LightingColorFilter;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.app.ListFragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.SearchView;
@@ -25,11 +26,13 @@ import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
-import com.joanzapata.iconify.IconDrawable;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconTextView;
import org.apache.commons.lang3.Validate;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
@@ -37,7 +40,6 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.FeedInfoActivity;
import de.danoeh.antennapod.activity.FeedSettingsActivity;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
@@ -61,13 +63,13 @@ import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
+import de.danoeh.antennapod.core.util.Optional;
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
-import de.greenrobot.event.EventBus;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -94,8 +96,6 @@ public class ItemlistFragment extends ListFragment {
private long feedID;
private Feed feed;
- private boolean itemsLoaded = false;
- private boolean viewsCreated = false;
private boolean headerCreated = false;
private List<Downloader> downloaderList;
@@ -103,7 +103,7 @@ public class ItemlistFragment extends ListFragment {
private MoreContentListFooterUtil listFooter;
private boolean isUpdatingFeed;
-
+
private TextView txtvTitle;
private IconTextView txtvFailure;
private ImageView imgvBackground;
@@ -142,24 +142,21 @@ public class ItemlistFragment extends ListFragment {
@Override
public void onStart() {
super.onStart();
- if (viewsCreated && itemsLoaded) {
- onFragmentLoaded();
- }
+ EventDistributor.getInstance().register(contentUpdate);
+ EventBus.getDefault().register(this);
+ loadItems();
}
@Override
public void onResume() {
super.onResume();
- EventDistributor.getInstance().register(contentUpdate);
- EventBus.getDefault().registerSticky(this);
((MainActivity)getActivity()).getSupportActionBar().setTitle("");
updateProgressBarVisibility();
- loadItems();
}
@Override
- public void onPause() {
- super.onPause();
+ public void onStop() {
+ super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
if(disposable != null) {
@@ -175,7 +172,6 @@ public class ItemlistFragment extends ListFragment {
private void resetViewState() {
adapter = null;
- viewsCreated = false;
listFooter = null;
}
@@ -188,45 +184,43 @@ public class ItemlistFragment extends ListFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if(!isAdded()) {
+ if (!isAdded()) {
return;
}
super.onCreateOptionsMenu(menu, inflater);
- if (itemsLoaded) {
- FeedMenuHandler.onCreateOptionsMenu(inflater, menu);
-
- MenuItem searchItem = menu.findItem(R.id.action_search);
- final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
- sv.setQueryHint(getString(R.string.search_hint));
- sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
- @Override
- public boolean onQueryTextSubmit(String s) {
- sv.clearFocus();
- if (itemsLoaded) {
- ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s, feed.getId()));
- }
- return true;
- }
+ FeedMenuHandler.onCreateOptionsMenu(inflater, menu);
- @Override
- public boolean onQueryTextChange(String s) {
- return false;
+ MenuItem searchItem = menu.findItem(R.id.action_search);
+ final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
+ MenuItemUtils.adjustTextColor(getActivity(), sv);
+ sv.setQueryHint(getString(R.string.search_hint));
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ if (feed != null) {
+ ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s, feed.getId()));
}
- });
- if(feed == null || feed.getLink() == null) {
- menu.findItem(R.id.share_link_item).setVisible(false);
- menu.findItem(R.id.visit_website_item).setVisible(false);
+ return true;
}
- isUpdatingFeed = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ if (feed == null || feed.getLink() == null) {
+ menu.findItem(R.id.share_link_item).setVisible(false);
+ menu.findItem(R.id.visit_website_item).setVisible(false);
}
+
+ isUpdatingFeed = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
- if (itemsLoaded) {
+ if (feed != null) {
FeedMenuHandler.onPrepareOptionsMenu(menu, feed);
}
}
@@ -339,11 +333,6 @@ public class ItemlistFragment extends ListFragment {
super.onViewCreated(view, savedInstanceState);
registerForContextMenu(getListView());
-
- viewsCreated = true;
- if (itemsLoaded) {
- onFragmentLoaded();
- }
}
@Override
@@ -358,6 +347,7 @@ public class ItemlistFragment extends ListFragment {
activity.getSupportActionBar().setTitle(feed.getTitle());
}
+ @Subscribe
public void onEvent(FeedEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
if(event.feedId == feedID) {
@@ -365,6 +355,7 @@ public class ItemlistFragment extends ListFragment {
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
if(feed == null || feed.getItems() == null || adapter == null) {
@@ -379,6 +370,7 @@ public class ItemlistFragment extends ListFragment {
}
}
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
@@ -422,7 +414,7 @@ public class ItemlistFragment extends ListFragment {
setListAdapter(null);
setupHeaderView();
setupFooterView();
- adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(getActivity()), false, true);
+ adapter = new FeedItemlistAdapter(getActivity(), itemAccess, false, true);
setListAdapter(adapter);
}
refreshHeaderView();
@@ -498,7 +490,7 @@ public class ItemlistFragment extends ListFragment {
butShowInfo.setOnClickListener(v -> showFeedInfo());
imgvCover.setOnClickListener(v -> showFeedInfo());
butShowSettings.setOnClickListener(v -> {
- if (viewsCreated && itemsLoaded) {
+ if (feed != null) {
Intent startIntent = new Intent(getActivity(), FeedSettingsActivity.class);
startIntent.putExtra(FeedSettingsActivity.EXTRA_FEED_ID,
feed.getId());
@@ -509,7 +501,7 @@ public class ItemlistFragment extends ListFragment {
}
private void showFeedInfo() {
- if (viewsCreated && itemsLoaded) {
+ if (feed != null) {
Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class);
startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID,
feed.getId());
@@ -618,24 +610,20 @@ public class ItemlistFragment extends ListFragment {
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
- if (result != null) {
- feed = result;
- itemsLoaded = true;
- if (viewsCreated) {
- onFragmentLoaded();
- }
- }
+ feed = result.orElse(null);
+ onFragmentLoaded();
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
- private Feed loadData() {
+ @NonNull
+ private Optional<Feed> loadData() {
Feed feed = DBReader.getFeed(feedID);
- DBReader.loadAdditionalFeedItemListData(feed.getItems());
- if(feed != null && feed.getItemFilter() != null) {
+ if (feed != null && feed.getItemFilter() != null) {
+ DBReader.loadAdditionalFeedItemListData(feed.getItems());
FeedItemFilter filter = feed.getItemFilter();
feed.setItems(filter.filter(feed.getItems()));
}
- return feed;
+ return Optional.ofNullable(feed);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
index a0e2ca22a..80767bef2 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
@@ -5,6 +5,7 @@ import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.SearchView;
+import android.support.annotation.NonNull;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -19,13 +20,14 @@ import android.widget.TextView;
import com.afollestad.materialdialogs.MaterialDialog;
+import de.danoeh.antennapod.discovery.ItunesPodcastSearcher;
+import de.danoeh.antennapod.discovery.ItunesTopListLoader;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -45,15 +47,11 @@ import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
-import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast;
-
//Searches iTunes store for given string and displays results in a list
public class ItunesSearchFragment extends Fragment {
private static final String TAG = "ItunesSearchFragment";
- private static final String API_URL = "https://itunes.apple.com/search?media=podcast&term=%s";
-
/**
* Adapter responsible with the search results
@@ -68,21 +66,21 @@ public class ItunesSearchFragment extends Fragment {
/**
* List of podcasts retreived from the search
*/
- private List<Podcast> searchResults;
- private List<Podcast> topList;
+ private List<PodcastSearchResult> searchResults;
+ private List<PodcastSearchResult> topList;
private Disposable disposable;
/**
* Replace adapter data with provided search results from SearchTask.
* @param result List of Podcast objects containing search results
*/
- private void updateData(List<Podcast> result) {
+ private void updateData(List<PodcastSearchResult> result) {
this.searchResults = result;
adapter.clear();
if (result != null && result.size() > 0) {
gridView.setVisibility(View.VISIBLE);
txtvEmpty.setVisibility(View.GONE);
- for (Podcast p : result) {
+ for (PodcastSearchResult p : result) {
adapter.add(p);
}
adapter.notifyDataSetInvalidated();
@@ -106,7 +104,7 @@ public class ItunesSearchFragment extends Fragment {
}
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
@@ -116,59 +114,31 @@ public class ItunesSearchFragment extends Fragment {
//Show information about the podcast when the list item is clicked
gridView.setOnItemClickListener((parent, view1, position, id) -> {
- Podcast podcast = searchResults.get(position);
- if(podcast.feedUrl == null) {
+ PodcastSearchResult podcast = searchResults.get(position);
+ if (podcast.feedUrl == null) {
return;
}
- if (!podcast.feedUrl.contains("itunes.apple.com")) {
- Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
- intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl);
- intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, "iTunes");
- startActivity(intent);
- } else {
- gridView.setVisibility(View.GONE);
- progressBar.setVisibility(View.VISIBLE);
- disposable = Single.create((SingleOnSubscribe<String>) emitter -> {
- OkHttpClient client = AntennapodHttpClient.getHttpClient();
- Request.Builder httpReq = new Request.Builder()
- .url(podcast.feedUrl)
- .header("User-Agent", ClientConfig.USER_AGENT);
- try {
- Response response = client.newCall(httpReq.build()).execute();
- if (response.isSuccessful()) {
- String resultString = response.body().string();
- JSONObject result = new JSONObject(resultString);
- JSONObject results = result.getJSONArray("results").getJSONObject(0);
- String feedUrl = results.getString("feedUrl");
- emitter.onSuccess(feedUrl);
- } else {
- String prefix = getString(R.string.error_msg_prefix);
- emitter.onError(new IOException(prefix + response));
- }
- } catch (IOException | JSONException e) {
- emitter.onError(e);
- }
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(feedUrl -> {
- progressBar.setVisibility(View.GONE);
- gridView.setVisibility(View.VISIBLE);
- Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
- intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, feedUrl);
- intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, "iTunes");
- startActivity(intent);
- }, error -> {
- Log.e(TAG, Log.getStackTraceString(error));
- progressBar.setVisibility(View.GONE);
- gridView.setVisibility(View.VISIBLE);
- String prefix = getString(R.string.error_msg_prefix);
- new MaterialDialog.Builder(getActivity())
- .content(prefix + " " + error.getMessage())
- .neutralText(android.R.string.ok)
- .show();
- });
- }
+ gridView.setVisibility(View.GONE);
+ progressBar.setVisibility(View.VISIBLE);
+ ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
+ disposable = loader.getFeedUrl(podcast)
+ .subscribe(feedUrl -> {
+ progressBar.setVisibility(View.GONE);
+ gridView.setVisibility(View.VISIBLE);
+ Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, feedUrl);
+ intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, "iTunes");
+ startActivity(intent);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ gridView.setVisibility(View.VISIBLE);
+ String prefix = getString(R.string.error_msg_prefix);
+ new MaterialDialog.Builder(getActivity())
+ .content(prefix + " " + error.getMessage())
+ .neutralText(android.R.string.ok)
+ .show();
+ });
});
progressBar = root.findViewById(R.id.progressBar);
txtvError = root.findViewById(R.id.txtvError);
@@ -236,47 +206,9 @@ public class ItunesSearchFragment extends Fragment {
butRetry.setVisibility(View.GONE);
txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
- disposable = Single.create((SingleOnSubscribe<List<Podcast>>) emitter -> {
- String lang = Locale.getDefault().getLanguage();
- String url = "https://itunes.apple.com/" + lang + "/rss/toppodcasts/limit=25/explicit=true/json";
- OkHttpClient client = AntennapodHttpClient.getHttpClient();
- Request.Builder httpReq = new Request.Builder()
- .url(url)
- .header("User-Agent", ClientConfig.USER_AGENT);
- List<Podcast> results = new ArrayList<>();
- try {
- Response response = client.newCall(httpReq.build()).execute();
- if(!response.isSuccessful()) {
- // toplist for language does not exist, fall back to united states
- url = "https://itunes.apple.com/us/rss/toppodcasts/limit=25/explicit=true/json";
- httpReq = new Request.Builder()
- .url(url)
- .header("User-Agent", ClientConfig.USER_AGENT);
- response = client.newCall(httpReq.build()).execute();
- }
- if(response.isSuccessful()) {
- String resultString = response.body().string();
- JSONObject result = new JSONObject(resultString);
- JSONObject feed = result.getJSONObject("feed");
- JSONArray entries = feed.getJSONArray("entry");
- for(int i=0; i < entries.length(); i++) {
- JSONObject json = entries.getJSONObject(i);
- Podcast podcast = Podcast.fromToplist(json);
- results.add(podcast);
- }
- }
- else {
- String prefix = getString(R.string.error_msg_prefix);
- emitter.onError(new IOException(prefix + response));
- }
- } catch (IOException | JSONException e) {
- emitter.onError(e);
- }
- emitter.onSuccess(results);
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
+ ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
+ disposable = loader.loadToplist(25)
.subscribe(podcasts -> {
progressBar.setVisibility(View.GONE);
topList = podcasts;
@@ -300,61 +232,19 @@ public class ItunesSearchFragment extends Fragment {
butRetry.setVisibility(View.GONE);
txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
- disposable = Single.create((SingleOnSubscribe<List<Podcast>>) subscriber -> {
- String encodedQuery = null;
- try {
- encodedQuery = URLEncoder.encode(query, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- // this won't ever be thrown
- }
- if (encodedQuery == null) {
- encodedQuery = query; // failsafe
- }
-
- //Spaces in the query need to be replaced with '+' character.
- String formattedUrl = String.format(API_URL, query).replace(' ', '+');
- OkHttpClient client = AntennapodHttpClient.getHttpClient();
- Request.Builder httpReq = new Request.Builder()
- .url(formattedUrl)
- .header("User-Agent", ClientConfig.USER_AGENT);
- List<Podcast> podcasts = new ArrayList<>();
- try {
- Response response = client.newCall(httpReq.build()).execute();
-
- if(response.isSuccessful()) {
- String resultString = response.body().string();
- JSONObject result = new JSONObject(resultString);
- JSONArray j = result.getJSONArray("results");
-
- for (int i = 0; i < j.length(); i++) {
- JSONObject podcastJson = j.getJSONObject(i);
- Podcast podcast = Podcast.fromSearch(podcastJson);
- podcasts.add(podcast);
- }
- }
- else {
- String prefix = getString(R.string.error_msg_prefix);
- subscriber.onError(new IOException(prefix + response));
- }
- } catch (IOException | JSONException e) {
- subscriber.onError(e);
- }
- subscriber.onSuccess(podcasts);
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(podcasts -> {
- progressBar.setVisibility(View.GONE);
- updateData(podcasts);
- }, error -> {
- Log.e(TAG, Log.getStackTraceString(error));
- progressBar.setVisibility(View.GONE);
- txtvError.setText(error.toString());
- txtvError.setVisibility(View.VISIBLE);
- butRetry.setOnClickListener(v -> search(query));
- butRetry.setVisibility(View.VISIBLE);
- });
+ ItunesPodcastSearcher searcher = new ItunesPodcastSearcher(getContext());
+ disposable = searcher.search(query).subscribe(podcasts -> {
+ progressBar.setVisibility(View.GONE);
+ updateData(podcasts);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ txtvError.setText(error.toString());
+ txtvError.setVisibility(View.VISIBLE);
+ butRetry.setOnClickListener(v -> search(query));
+ butRetry.setVisibility(View.VISIBLE);
+ });
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
index 6695ba427..1bf907aee 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -1,9 +1,9 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -12,53 +12,39 @@ import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
-import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.util.FeedItemUtil;
-
/**
* Like 'EpisodesFragment' except that it only shows new episodes and
* supports swiping to mark as read.
*/
-
public class NewEpisodesFragment extends AllEpisodesFragment {
public static final String TAG = "NewEpisodesFragment";
-
private static final String PREF_NAME = "PrefNewEpisodesFragment";
@Override
- protected boolean showOnlyNewEpisodes() { return true; }
-
- @Override
- protected String getPrefName() { return PREF_NAME; }
+ protected boolean showOnlyNewEpisodes() {
+ return true;
+ }
@Override
- protected void resetViewState() {
- super.resetViewState();
+ protected String getPrefName() {
+ return PREF_NAME;
}
@Override
- public void onEventMainThread(FeedItemEvent event) {
- Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
- if(episodes == null) {
- return;
- }
- for(FeedItem item : event.items) {
- int pos = FeedItemUtil.indexOfItemWithId(episodes, item.getId());
- if(pos >= 0 && item.isTagged(FeedItem.TAG_QUEUE)) {
- episodes.remove(pos);
- listAdapter.notifyItemRemoved(pos);
- }
- }
+ protected boolean shouldUpdatedItemRemainInList(FeedItem item) {
+ return item.isNew();
}
+ @NonNull
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View root = super.onCreateViewHelper(inflater, container, savedInstanceState,
- R.layout.all_episodes_fragment);
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View root = super.onCreateView(inflater, container, savedInstanceState);
+ emptyView.setTitle(R.string.no_new_episodes_head_label);
+ emptyView.setMessage(R.string.no_new_episodes_label);
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
@@ -68,8 +54,8 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
- AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder)viewHolder;
- markItemAsSeenWithUndo(holder.getFeedItem());
+ AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) viewHolder;
+ removeNewFlagWithUndo(holder.getFeedItem());
}
@Override
@@ -86,6 +72,7 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
super.onSelectedChanged(viewHolder, actionState);
}
+
@Override
public void clearView(RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder) {
@@ -105,9 +92,9 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
return root;
}
+ @NonNull
@Override
protected List<FeedItem> loadData() {
return DBReader.getNewItemsList();
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
index c2a9200c8..e2060481f 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.fragment;
-import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.app.ListFragment;
import android.support.v4.view.MenuItemCompat;
import android.util.Log;
@@ -12,11 +12,14 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
@@ -29,7 +32,7 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
-import de.greenrobot.event.EventBus;
+import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -44,23 +47,10 @@ public class PlaybackHistoryFragment extends ListFragment {
private List<FeedItem> playbackHistory;
private FeedItemlistAdapter adapter;
-
- private boolean itemsLoaded = false;
- private boolean viewsCreated = false;
-
private List<Downloader> downloaderList;
-
private Disposable disposable;
@Override
- public void onAttach(Context context) {
- super.onAttach(context);
- if (viewsCreated && itemsLoaded) {
- onFragmentLoaded();
- }
- }
-
- @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
@@ -77,63 +67,43 @@ public class PlaybackHistoryFragment extends ListFragment {
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
lv.setPadding(0, vertPadding, 0, vertPadding);
- viewsCreated = true;
- if (itemsLoaded) {
- onFragmentLoaded();
- }
- }
-
+ EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
+ emptyView.setIcon(R.attr.ic_history);
+ emptyView.setTitle(R.string.no_history_head_label);
+ emptyView.setMessage(R.string.no_history_label);
+ emptyView.attachToListView(getListView());
- @Override
- public void onResume() {
- super.onResume();
- EventBus.getDefault().registerSticky(this);
- loadItems();
+ // played items shoudln't be transparent for this fragment since, *all* items
+ // in this fragment will, by definition, be played. So it serves no purpose and can make
+ // it harder to read.
+ adapter = new FeedItemlistAdapter(getActivity(), itemAccess, true, false);
+ setListAdapter(adapter);
}
@Override
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- EventBus.getDefault().unregister(this);
+ EventBus.getDefault().register(this);
+ loadItems();
}
@Override
public void onStop() {
super.onStop();
+ EventBus.getDefault().unregister(this);
EventDistributor.getInstance().unregister(contentUpdate);
- if(disposable != null) {
+ if (disposable != null) {
disposable.dispose();
}
}
- @Override
- public void onDetach() {
- super.onDetach();
- if(disposable != null) {
- disposable.dispose();
- }
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- adapter = null;
- viewsCreated = false;
- }
-
+ @Subscribe(sticky = true)
public void onEvent(DownloadEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
+ adapter.notifyDataSetChanged();
}
@Override
@@ -146,27 +116,23 @@ public class PlaybackHistoryFragment extends ListFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if(!isAdded()) {
+ if (!isAdded()) {
return;
}
super.onCreateOptionsMenu(menu, inflater);
- if (itemsLoaded) {
- MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
- MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
- TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.content_discard});
- clearHistory.setIcon(drawables.getDrawable(0));
- drawables.recycle();
- }
+ MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
+ MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.content_discard});
+ clearHistory.setIcon(drawables.getDrawable(0));
+ drawables.recycle();
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- if (itemsLoaded) {
- MenuItem menuItem = menu.findItem(R.id.clear_history_item);
- if (menuItem != null) {
- menuItem.setVisible(playbackHistory != null && !playbackHistory.isEmpty());
- }
+ MenuItem menuItem = menu.findItem(R.id.clear_history_item);
+ if (menuItem != null) {
+ menuItem.setVisible(playbackHistory != null && !playbackHistory.isEmpty());
}
}
@@ -185,6 +151,7 @@ public class PlaybackHistoryFragment extends ListFragment {
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
if(playbackHistory == null) {
@@ -211,15 +178,6 @@ public class PlaybackHistoryFragment extends ListFragment {
};
private void onFragmentLoaded() {
- if (adapter == null) {
- // played items shoudln't be transparent for this fragment since, *all* items
- // in this fragment will, by definition, be played. So it serves no purpose and can make
- // it harder to read.
- adapter = new FeedItemlistAdapter(getActivity(), itemAccess,
- new DefaultActionButtonCallback(getActivity()), true, false);
- setListAdapter(adapter);
- }
- setListShown(true);
adapter.notifyDataSetChanged();
getActivity().supportInvalidateOptionsMenu();
}
@@ -278,18 +236,15 @@ public class PlaybackHistoryFragment extends ListFragment {
.subscribe(result -> {
if (result != null) {
playbackHistory = result;
- itemsLoaded = true;
- if (viewsCreated) {
- onFragmentLoaded();
- }
+ onFragmentLoaded();
}
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
+ @NonNull
private List<FeedItem> loadData() {
List<FeedItem> history = DBReader.getPlaybackHistory();
DBReader.loadAdditionalFeedItemListData(history);
return history;
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
index faeabf75c..0fe413954 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -28,7 +28,6 @@ import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.QueueRecyclerAdapter;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.DownloadEvent;
@@ -50,13 +49,22 @@ import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.QueueSorter;
+import de.danoeh.antennapod.core.util.SortOrder;
+import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
-import de.greenrobot.event.EventBus;
+
+import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DELETE;
+import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_REMOVE_FROM_QUEUE;
/**
* Shows all items in the queue
@@ -72,7 +80,7 @@ public class QueueFragment extends Fragment {
private TextView infoBar;
private RecyclerView recyclerView;
private QueueRecyclerAdapter recyclerAdapter;
- private TextView txtvEmpty;
+ private EmptyViewHandler emptyView;
private ProgressBar progLoading;
private List<FeedItem> queue;
@@ -102,20 +110,20 @@ public class QueueFragment extends Fragment {
if (queue != null) {
onFragmentLoaded(true);
}
- }
-
- @Override
- public void onResume() {
- super.onResume();
loadItems(true);
EventDistributor.getInstance().register(contentUpdate);
- EventBus.getDefault().registerSticky(this);
+ EventBus.getDefault().register(this);
}
@Override
public void onPause() {
super.onPause();
saveScrollPosition();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
if(disposable != null) {
@@ -123,9 +131,13 @@ public class QueueFragment extends Fragment {
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(QueueEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
- if(queue == null || recyclerAdapter == null) {
+ if (queue == null) {
+ return;
+ } else if (recyclerAdapter == null) {
+ loadItems(true);
return;
}
switch(event.action) {
@@ -158,9 +170,13 @@ public class QueueFragment extends Fragment {
onFragmentLoaded(false);
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
- if(queue == null || recyclerAdapter == null) {
+ if (queue == null) {
+ return;
+ } else if (recyclerAdapter == null) {
+ loadItems(true);
return;
}
for(int i=0, size = event.items.size(); i < size; i++) {
@@ -170,10 +186,12 @@ public class QueueFragment extends Fragment {
queue.remove(pos);
queue.add(pos, item);
recyclerAdapter.notifyItemChanged(pos);
+ refreshInfoBar();
}
}
}
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
@@ -259,6 +277,19 @@ public class QueueFragment extends Fragment {
MenuItemUtils.refreshLockItem(getActivity(), menu);
+ // Show Lock Item only if queue is sorted manually
+ boolean keepSorted = UserPreferences.isQueueKeepSorted();
+ MenuItem lockItem = menu.findItem(R.id.queue_lock);
+ lockItem.setVisible(!keepSorted);
+
+ // Random sort is not supported in keep sorted mode
+ MenuItem sortRandomItem = menu.findItem(R.id.queue_sort_random);
+ sortRandomItem.setVisible(!keepSorted);
+
+ // Set keep sorted checkbox
+ MenuItem keepSortedItem = menu.findItem(R.id.queue_keep_sorted);
+ keepSortedItem.setChecked(keepSorted);
+
isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
}
@@ -271,7 +302,9 @@ public class QueueFragment extends Fragment {
boolean newLockState = !UserPreferences.isQueueLocked();
UserPreferences.setQueueLocked(newLockState);
getActivity().supportInvalidateOptionsMenu();
- recyclerAdapter.setLocked(newLockState);
+ if (recyclerAdapter != null) {
+ recyclerAdapter.setLocked(newLockState);
+ }
if (newLockState) {
Snackbar.make(getActivity().findViewById(R.id.content), R.string
.queue_locked, Snackbar.LENGTH_SHORT).show();
@@ -301,38 +334,55 @@ public class QueueFragment extends Fragment {
};
conDialog.createNewDialog().show();
return true;
+ case R.id.episode_actions:
+ ((MainActivity) requireActivity()) .loadChildFragment(
+ EpisodesApplyActionFragment.newInstance(queue, ACTION_DELETE | ACTION_REMOVE_FROM_QUEUE));
+ return true;
case R.id.queue_sort_episode_title_asc:
- QueueSorter.sort(getActivity(), QueueSorter.Rule.EPISODE_TITLE_ASC, true);
+ setSortOrder(SortOrder.EPISODE_TITLE_A_Z);
return true;
case R.id.queue_sort_episode_title_desc:
- QueueSorter.sort(getActivity(), QueueSorter.Rule.EPISODE_TITLE_DESC, true);
+ setSortOrder(SortOrder.EPISODE_TITLE_Z_A);
return true;
case R.id.queue_sort_date_asc:
- QueueSorter.sort(getActivity(), QueueSorter.Rule.DATE_ASC, true);
+ setSortOrder(SortOrder.DATE_OLD_NEW);
return true;
case R.id.queue_sort_date_desc:
- QueueSorter.sort(getActivity(), QueueSorter.Rule.DATE_DESC, true);
+ setSortOrder(SortOrder.DATE_NEW_OLD);
return true;
case R.id.queue_sort_duration_asc:
- QueueSorter.sort(getActivity(), QueueSorter.Rule.DURATION_ASC, true);
+ setSortOrder(SortOrder.DURATION_SHORT_LONG);
return true;
case R.id.queue_sort_duration_desc:
- QueueSorter.sort(getActivity(), QueueSorter.Rule.DURATION_DESC, true);
+ setSortOrder(SortOrder.DURATION_LONG_SHORT);
return true;
case R.id.queue_sort_feed_title_asc:
- QueueSorter.sort(getActivity(), QueueSorter.Rule.FEED_TITLE_ASC, true);
+ setSortOrder(SortOrder.FEED_TITLE_A_Z);
return true;
case R.id.queue_sort_feed_title_desc:
- QueueSorter.sort(getActivity(), QueueSorter.Rule.FEED_TITLE_DESC, true);
+ setSortOrder(SortOrder.FEED_TITLE_Z_A);
return true;
case R.id.queue_sort_random:
- QueueSorter.sort(getActivity(), QueueSorter.Rule.RANDOM, true);
+ setSortOrder(SortOrder.RANDOM);
return true;
case R.id.queue_sort_smart_shuffle_asc:
- QueueSorter.sort(getActivity(), QueueSorter.Rule.SMART_SHUFFLE_ASC, true);
+ setSortOrder(SortOrder.SMART_SHUFFLE_OLD_NEW);
return true;
case R.id.queue_sort_smart_shuffle_desc:
- QueueSorter.sort(getActivity(), QueueSorter.Rule.SMART_SHUFFLE_DESC, true);
+ setSortOrder(SortOrder.SMART_SHUFFLE_NEW_OLD);
+ return true;
+ case R.id.queue_keep_sorted:
+ boolean keepSortedOld = UserPreferences.isQueueKeepSorted();
+ boolean keepSortedNew = !keepSortedOld;
+ UserPreferences.setQueueKeepSorted(keepSortedNew);
+ if (keepSortedNew) {
+ SortOrder sortOrder = UserPreferences.getQueueKeepSortedOrder();
+ QueueSorter.sort(sortOrder, true);
+ recyclerAdapter.setLocked(true);
+ } else {
+ recyclerAdapter.setLocked(UserPreferences.isQueueLocked());
+ }
+ getActivity().invalidateOptionsMenu();
return true;
default:
return false;
@@ -342,6 +392,15 @@ public class QueueFragment extends Fragment {
}
}
+ /**
+ * This method is called if the user clicks on a sort order menu item.
+ *
+ * @param sortOrder New sort order.
+ */
+ private void setSortOrder(SortOrder sortOrder) {
+ UserPreferences.setQueueKeepSortedOrder(sortOrder);
+ QueueSorter.sort(sortOrder, true);
+ }
@Override
public boolean onContextItemSelected(MenuItem item) {
@@ -431,7 +490,7 @@ public class QueueFragment extends Fragment {
final FeedItem item = queue.get(position);
final boolean isRead = item.isPlayed();
DBWriter.markItemPlayed(FeedItem.PLAYED, false, item.getId());
- DBWriter.removeQueueItem(getActivity(), item, true);
+ DBWriter.removeQueueItem(getActivity(), true, item);
Snackbar snackbar = Snackbar.make(root, getString(R.string.marked_as_read_label), Snackbar.LENGTH_LONG);
snackbar.setAction(getString(R.string.undo), v -> {
DBWriter.addQueueItemAt(getActivity(), item.getId(), position, false);
@@ -494,8 +553,12 @@ public class QueueFragment extends Fragment {
);
itemTouchHelper.attachToRecyclerView(recyclerView);
- txtvEmpty = root.findViewById(android.R.id.empty);
- txtvEmpty.setVisibility(View.GONE);
+ emptyView = new EmptyViewHandler(getContext());
+ emptyView.attachToRecyclerView(recyclerView);
+ emptyView.setIcon(R.attr.stat_playlist);
+ emptyView.setTitle(R.string.no_items_header_label);
+ emptyView.setMessage(R.string.no_items_label);
+
progLoading = root.findViewById(R.id.progLoading);
progLoading.setVisibility(View.VISIBLE);
@@ -503,19 +566,19 @@ public class QueueFragment extends Fragment {
}
private void onFragmentLoaded(final boolean restoreScrollPosition) {
- if (recyclerAdapter == null) {
- MainActivity activity = (MainActivity) getActivity();
- recyclerAdapter = new QueueRecyclerAdapter(activity, itemAccess,
- new DefaultActionButtonCallback(activity), itemTouchHelper);
- recyclerAdapter.setHasStableIds(true);
- recyclerView.setAdapter(recyclerAdapter);
- }
- if(queue == null || queue.size() == 0) {
- recyclerView.setVisibility(View.GONE);
- txtvEmpty.setVisibility(View.VISIBLE);
- } else {
- txtvEmpty.setVisibility(View.GONE);
+ if (queue != null && queue.size() > 0) {
+ if (recyclerAdapter == null) {
+ MainActivity activity = (MainActivity) getActivity();
+ recyclerAdapter = new QueueRecyclerAdapter(activity, itemAccess, itemTouchHelper);
+ recyclerAdapter.setHasStableIds(true);
+ recyclerView.setAdapter(recyclerAdapter);
+ emptyView.updateAdapter(recyclerAdapter);
+ }
recyclerView.setVisibility(View.VISIBLE);
+ } else {
+ recyclerAdapter = null;
+ recyclerView.setVisibility(View.GONE);
+ emptyView.updateAdapter(recyclerAdapter);
}
if (restoreScrollPosition) {
@@ -628,22 +691,19 @@ public class QueueFragment extends Fragment {
}
if (queue == null) {
recyclerView.setVisibility(View.GONE);
- txtvEmpty.setVisibility(View.GONE);
+ emptyView.hide();
progLoading.setVisibility(View.VISIBLE);
}
disposable = Observable.fromCallable(DBReader::getQueue)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(items -> {
- if(items != null) {
- progLoading.setVisibility(View.GONE);
- queue = items;
- onFragmentLoaded(restoreScrollPosition);
- if(recyclerAdapter != null) {
- recyclerAdapter.notifyDataSetChanged();
- }
+ progLoading.setVisibility(View.GONE);
+ queue = items;
+ onFragmentLoaded(restoreScrollPosition);
+ if(recyclerAdapter != null) {
+ recyclerAdapter.notifyDataSetChanged();
}
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
new file mode 100644
index 000000000..e4213cc6b
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
@@ -0,0 +1,119 @@
+package de.danoeh.antennapod.fragment;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.GridView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import com.afollestad.materialdialogs.MaterialDialog;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
+import de.danoeh.antennapod.adapter.FeedDiscoverAdapter;
+import de.danoeh.antennapod.discovery.ItunesTopListLoader;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
+import io.reactivex.disposables.Disposable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.OnItemClickListener {
+ private static final String TAG = "FeedDiscoveryFragment";
+
+ private ProgressBar progressBar;
+ private Disposable disposable;
+ private FeedDiscoverAdapter adapter;
+ private GridView subscriptionGridLayout;
+ private TextView errorTextView;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ View root = inflater.inflate(R.layout.quick_feed_discovery, container, false);
+ View discoverMore = root.findViewById(R.id.discover_more);
+ discoverMore.setOnClickListener(v ->
+ ((MainActivity) getActivity()).loadChildFragment(new ItunesSearchFragment()));
+
+ subscriptionGridLayout = root.findViewById(R.id.discover_grid);
+ progressBar = root.findViewById(R.id.discover_progress_bar);
+ errorTextView = root.findViewById(R.id.discover_error);
+
+ adapter = new FeedDiscoverAdapter((MainActivity) getActivity());
+ subscriptionGridLayout.setAdapter(adapter);
+ subscriptionGridLayout.setOnItemClickListener(this);
+
+ // Fill with dummy elements to have a fixed height and
+ // prevent the UI elements below from jumping on slow connections
+ List<PodcastSearchResult> dummies = new ArrayList<>();
+ for (int i = 0; i < 8; i++) {
+ dummies.add(PodcastSearchResult.dummy());
+ }
+ adapter.updateData(dummies);
+
+ loadToplist();
+
+ return root;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ private void loadToplist() {
+ progressBar.setVisibility(View.VISIBLE);
+ subscriptionGridLayout.setVisibility(View.INVISIBLE);
+ errorTextView.setVisibility(View.GONE);
+
+ ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
+ disposable = loader.loadToplist(8)
+ .subscribe(podcasts -> {
+ errorTextView.setVisibility(View.GONE);
+ progressBar.setVisibility(View.GONE);
+ subscriptionGridLayout.setVisibility(View.VISIBLE);
+ adapter.updateData(podcasts);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ errorTextView.setText(error.getLocalizedMessage());
+ errorTextView.setVisibility(View.VISIBLE);
+ progressBar.setVisibility(View.GONE);
+ subscriptionGridLayout.setVisibility(View.INVISIBLE);
+ });
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
+ PodcastSearchResult podcast = adapter.getItem(position);
+ if (podcast.feedUrl == null) {
+ return;
+ }
+ view.setAlpha(0.5f);
+ ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
+ disposable = loader.getFeedUrl(podcast)
+ .subscribe(feedUrl -> {
+ view.setAlpha(1f);
+ Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, feedUrl);
+ intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, getString(R.string.add_feed_label));
+ startActivity(intent);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ view.setAlpha(1f);
+ String prefix = getString(R.string.error_msg_prefix);
+ new MaterialDialog.Builder(getActivity())
+ .content(prefix + " " + error.getMessage())
+ .neutralText(android.R.string.ok)
+ .show();
+ });
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
index 66c59b7f7..2a7f7d12b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
@@ -7,6 +7,10 @@ import android.view.View;
import android.widget.ListView;
import android.widget.Toast;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+
+import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
@@ -20,7 +24,7 @@ import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
-import de.greenrobot.event.EventBus;
+import de.danoeh.antennapod.view.EmptyViewHandler;
/**
* Displays all running downloads and provides actions to cancel them
@@ -30,7 +34,7 @@ public class RunningDownloadsFragment extends ListFragment {
private static final String TAG = "RunningDownloadsFrag";
private DownloadlistAdapter adapter;
- private List<Downloader> downloaderList;
+ private List<Downloader> downloaderList = new ArrayList<>();
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
@@ -44,17 +48,24 @@ public class RunningDownloadsFragment extends ListFragment {
adapter = new DownloadlistAdapter(getActivity(), itemAccess);
setListAdapter(adapter);
+
+ EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
+ emptyView.setIcon(R.attr.av_download);
+ emptyView.setTitle(R.string.no_run_downloads_head_label);
+ emptyView.setMessage(R.string.no_run_downloads_label);
+ emptyView.attachToListView(getListView());
+
}
@Override
- public void onResume() {
- super.onResume();
- EventBus.getDefault().registerSticky(this);
+ public void onStart() {
+ super.onStart();
+ EventBus.getDefault().register(this);
}
@Override
- public void onPause() {
- super.onPause();
+ public void onStop() {
+ super.onStop();
EventBus.getDefault().unregister(this);
}
@@ -62,28 +73,25 @@ public class RunningDownloadsFragment extends ListFragment {
public void onDestroy() {
super.onDestroy();
setListAdapter(null);
- adapter = null;
}
+ @Subscribe(sticky = true)
public void onEvent(DownloadEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
+ adapter.notifyDataSetChanged();
}
-
private final DownloadlistAdapter.ItemAccess itemAccess = new DownloadlistAdapter.ItemAccess() {
@Override
public int getCount() {
- return (downloaderList != null) ? downloaderList.size() : 0;
+ return downloaderList.size();
}
@Override
public Downloader getItem(int position) {
- if (downloaderList != null && 0 <= position && position < downloaderList.size()) {
+ if (0 <= position && position < downloaderList.size()) {
return downloaderList.get(position);
} else {
return null;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
index 8322a5573..0892bce0a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.fragment;
import android.content.Context;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.app.ListFragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AppCompatActivity;
@@ -13,6 +14,7 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
+import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
@@ -39,11 +41,7 @@ public class SearchFragment extends ListFragment {
private static final String ARG_FEED = "feed";
private SearchlistAdapter searchAdapter;
- private List<SearchResult> searchResults;
-
- private boolean viewCreated = false;
- private boolean itemsLoaded = false;
-
+ private List<SearchResult> searchResults = new ArrayList<>();
private Disposable disposable;
/**
@@ -73,13 +71,13 @@ public class SearchFragment extends ListFragment {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
- search();
}
@Override
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
+ search();
}
@Override
@@ -92,21 +90,6 @@ public class SearchFragment extends ListFragment {
}
@Override
- public void onDetach() {
- super.onDetach();
- if(disposable != null) {
- disposable.dispose();
- }
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- searchAdapter = null;
- viewCreated = false;
- }
-
- @Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@@ -117,10 +100,9 @@ public class SearchFragment extends ListFragment {
lv.setPadding(0, vertPadding, 0, vertPadding);
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.search_label);
- viewCreated = true;
- if (itemsLoaded) {
- onFragmentLoaded();
- }
+
+ searchAdapter = new SearchlistAdapter(getActivity(), itemAccess);
+ setListAdapter(searchAdapter);
}
@Override
@@ -141,28 +123,26 @@ public class SearchFragment extends ListFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
- if (itemsLoaded) {
- MenuItem item = menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label);
- MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
- final SearchView sv = new SearchView(getActivity());
- sv.setQueryHint(getString(R.string.search_hint));
- sv.setQuery(getArguments().getString(ARG_QUERY), false);
- sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
- @Override
- public boolean onQueryTextSubmit(String s) {
- getArguments().putString(ARG_QUERY, s);
- itemsLoaded = false;
- search();
- return true;
- }
-
- @Override
- public boolean onQueryTextChange(String s) {
- return false;
- }
- });
- MenuItemCompat.setActionView(item, sv);
- }
+ MenuItem item = menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label);
+ MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ final SearchView sv = new SearchView(getActivity());
+ sv.setQueryHint(getString(R.string.search_hint));
+ sv.setQuery(getArguments().getString(ARG_QUERY), false);
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ getArguments().putString(ARG_QUERY, s);
+ search();
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ MenuItemCompat.setActionView(item, sv);
}
private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@@ -175,14 +155,9 @@ public class SearchFragment extends ListFragment {
}
};
- private void onFragmentLoaded() {
- if (searchAdapter == null) {
- searchAdapter = new SearchlistAdapter(getActivity(), itemAccess);
- setListAdapter(searchAdapter);
- }
+ private void onSearchResults(List<SearchResult> results) {
+ searchResults = results;
searchAdapter.notifyDataSetChanged();
- setListShown(true);
-
String query = getArguments().getString(ARG_QUERY);
setEmptyText(getString(R.string.no_results_for_query, query));
}
@@ -190,12 +165,12 @@ public class SearchFragment extends ListFragment {
private final SearchlistAdapter.ItemAccess itemAccess = new SearchlistAdapter.ItemAccess() {
@Override
public int getCount() {
- return (searchResults != null) ? searchResults.size() : 0;
+ return searchResults.size();
}
@Override
public SearchResult getItem(int position) {
- if (searchResults != null && 0 <= position && position < searchResults.size()) {
+ if (0 <= position && position < searchResults.size()) {
return searchResults.get(position);
} else {
return null;
@@ -203,28 +178,17 @@ public class SearchFragment extends ListFragment {
}
};
-
private void search() {
if(disposable != null) {
disposable.dispose();
}
- if (viewCreated && !itemsLoaded) {
- setListShown(false);
- }
disposable = Observable.fromCallable(this::performSearch)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- if (result != null) {
- itemsLoaded = true;
- searchResults = result;
- if (viewCreated) {
- onFragmentLoaded();
- }
- }
- }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ .subscribe(this::onSearchResults, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
+ @NonNull
private List<SearchResult> performSearch() {
Bundle args = getArguments();
String query = args.getString(ARG_QUERY);
@@ -232,5 +196,4 @@ public class SearchFragment extends ListFragment {
Context context = getActivity();
return FeedSearcher.performSearch(context, query, feed);
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
index 5f09be8ce..15c6052a9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
@@ -1,11 +1,16 @@
package de.danoeh.antennapod.fragment;
+import android.annotation.SuppressLint;
+import android.content.Context;
import android.content.DialogInterface;
+import android.content.SharedPreferences;
import android.os.Bundle;
+import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
+import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
@@ -13,6 +18,8 @@ import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridView;
+import java.util.concurrent.Callable;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.SubscriptionsAdapter;
@@ -41,6 +48,8 @@ public class SubscriptionFragment extends Fragment {
private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE
| EventDistributor.UNREAD_ITEMS_UPDATE;
+ private static final String PREFS = "SubscriptionFragment";
+ private static final String PREF_NUM_COLUMNS = "columns";
private GridView subscriptionGridLayout;
private DBReader.NavDrawerData navDrawerData;
@@ -49,19 +58,15 @@ public class SubscriptionFragment extends Fragment {
private int mPosition = -1;
private Disposable disposable;
-
- public SubscriptionFragment() {
- }
+ private SharedPreferences prefs;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
-
- // So, we certainly *don't* have an options menu,
- // but unless we say we do, old options menus sometimes
- // persist. mfietz thinks this causes the ActionBar to be invalidated
setHasOptionsMenu(true);
+
+ prefs = requireActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
}
@Override
@@ -69,31 +74,75 @@ public class SubscriptionFragment extends Fragment {
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_subscriptions, container, false);
subscriptionGridLayout = root.findViewById(R.id.subscriptions_grid);
+ subscriptionGridLayout.setNumColumns(prefs.getInt(PREF_NUM_COLUMNS, 3));
registerForContextMenu(subscriptionGridLayout);
return root;
}
@Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.subscriptions, menu);
+
+ int columns = prefs.getInt(PREF_NUM_COLUMNS, 3);
+ menu.findItem(R.id.subscription_num_columns_2).setChecked(columns == 2);
+ menu.findItem(R.id.subscription_num_columns_3).setChecked(columns == 3);
+ menu.findItem(R.id.subscription_num_columns_4).setChecked(columns == 4);
+ menu.findItem(R.id.subscription_num_columns_5).setChecked(columns == 5);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (super.onOptionsItemSelected(item)) {
+ return true;
+ }
+ switch (item.getItemId()) {
+ case R.id.subscription_num_columns_2:
+ setColumnNumber(2);
+ return true;
+ case R.id.subscription_num_columns_3:
+ setColumnNumber(3);
+ return true;
+ case R.id.subscription_num_columns_4:
+ setColumnNumber(4);
+ return true;
+ case R.id.subscription_num_columns_5:
+ setColumnNumber(5);
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private void setColumnNumber(int columns) {
+ subscriptionGridLayout.setNumColumns(columns);
+ prefs.edit().putInt(PREF_NUM_COLUMNS, columns).apply();
+ getActivity().invalidateOptionsMenu();
+ }
+
+ @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
subscriptionAdapter = new SubscriptionsAdapter((MainActivity)getActivity(), itemAccess);
-
subscriptionGridLayout.setAdapter(subscriptionAdapter);
-
- loadSubscriptions();
-
subscriptionGridLayout.setOnItemClickListener(subscriptionAdapter);
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.subscriptions_label);
}
+ }
+ @Override
+ public void onStart() {
+ super.onStart();
EventDistributor.getInstance().register(contentUpdate);
+ loadSubscriptions();
}
@Override
- public void onDestroy() {
- super.onDestroy();
+ public void onStop() {
+ super.onStop();
+ EventDistributor.getInstance().unregister(contentUpdate);
if(disposable != null) {
disposable.dispose();
}
@@ -126,7 +175,7 @@ public class SubscriptionFragment extends Fragment {
Feed feed = (Feed)selectedObject;
- MenuInflater inflater = getActivity().getMenuInflater();
+ MenuInflater inflater = requireActivity().getMenuInflater();
inflater.inflate(R.menu.nav_feed_context, menu);
menu.setHeaderTitle(feed.getTitle());
@@ -136,7 +185,6 @@ public class SubscriptionFragment extends Fragment {
@Override
public boolean onContextItemSelected(MenuItem item) {
-
final int position = mPosition;
mPosition = -1; // reset
if(position < 0) {
@@ -151,84 +199,73 @@ public class SubscriptionFragment extends Fragment {
Feed feed = (Feed)selectedObject;
switch(item.getItemId()) {
- case R.id.mark_all_seen_item:
- ConfirmationDialog markAllSeenConfirmationDialog = new ConfirmationDialog(getActivity(),
- R.string.mark_all_seen_label,
- R.string.mark_all_seen_confirmation_msg) {
-
- @Override
- public void onConfirmButtonPressed(DialogInterface dialog) {
- dialog.dismiss();
-
- Observable.fromCallable(() -> DBWriter.markFeedSeen(feed.getId()))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> loadSubscriptions(),
- error -> Log.e(TAG, Log.getStackTraceString(error)));
- }
- };
- markAllSeenConfirmationDialog.createNewDialog().show();
+ case R.id.remove_all_new_flags_item:
+ displayConfirmationDialog(
+ R.string.remove_all_new_flags_label,
+ R.string.remove_all_new_flags_confirmation_msg,
+ () -> DBWriter.removeFeedNewFlag(feed.getId()));
return true;
case R.id.mark_all_read_item:
- ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(getActivity(),
+ displayConfirmationDialog(
R.string.mark_all_read_label,
- R.string.mark_all_read_confirmation_msg) {
-
- @Override
- public void onConfirmButtonPressed(DialogInterface dialog) {
- dialog.dismiss();
- Observable.fromCallable(() -> DBWriter.markFeedRead(feed.getId()))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> loadSubscriptions(),
- error -> Log.e(TAG, Log.getStackTraceString(error)));
- }
- };
- markAllReadConfirmationDialog.createNewDialog().show();
+ R.string.mark_all_read_confirmation_msg,
+ () -> DBWriter.markFeedRead(feed.getId()));
return true;
case R.id.rename_item:
new RenameFeedDialog(getActivity(), feed).show();
return true;
case R.id.remove_item:
- final FeedRemover remover = new FeedRemover(getContext(), feed) {
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
- loadSubscriptions();
- }
- };
- ConfirmationDialog conDialog = new ConfirmationDialog(getContext(),
- R.string.remove_feed_label,
- getString(R.string.feed_delete_confirmation_msg, feed.getTitle())) {
- @Override
- public void onConfirmButtonPressed(
- DialogInterface dialog) {
- dialog.dismiss();
- long mediaId = PlaybackPreferences.getCurrentlyPlayingFeedMediaId();
- if (mediaId > 0 &&
- FeedItemUtil.indexOfItemWithMediaId(feed.getItems(), mediaId) >= 0) {
- Log.d(TAG, "Currently playing episode is about to be deleted, skipping");
- remover.skipOnCompletion = true;
- int playerStatus = PlaybackPreferences.getCurrentPlayerStatus();
- if(playerStatus == PlaybackPreferences.PLAYER_STATUS_PLAYING) {
- IntentUtils.sendLocalBroadcast(getContext(), PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
-
- }
- }
- remover.executeAsync();
- }
- };
- conDialog.createNewDialog().show();
+ displayRemoveFeedDialog(feed);
return true;
default:
return super.onContextItemSelected(item);
}
}
- @Override
- public void onResume() {
- super.onResume();
- loadSubscriptions();
+ private void displayRemoveFeedDialog(Feed feed) {
+ final FeedRemover remover = new FeedRemover(getContext(), feed) {
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ loadSubscriptions();
+ }
+ };
+
+ String message = getString(R.string.feed_delete_confirmation_msg, feed.getTitle());
+ ConfirmationDialog dialog = new ConfirmationDialog(getContext(), R.string.remove_feed_label, message) {
+ @Override
+ public void onConfirmButtonPressed(DialogInterface clickedDialog) {
+ clickedDialog.dismiss();
+ long mediaId = PlaybackPreferences.getCurrentlyPlayingFeedMediaId();
+ if (mediaId > 0 && FeedItemUtil.indexOfItemWithMediaId(feed.getItems(), mediaId) >= 0) {
+ Log.d(TAG, "Currently playing episode is about to be deleted, skipping");
+ remover.skipOnCompletion = true;
+ int playerStatus = PlaybackPreferences.getCurrentPlayerStatus();
+ if(playerStatus == PlaybackPreferences.PLAYER_STATUS_PLAYING) {
+ IntentUtils.sendLocalBroadcast(getContext(), PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
+
+ }
+ }
+ remover.executeAsync();
+ }
+ };
+ dialog.createNewDialog().show();
+ }
+
+ private <T> void displayConfirmationDialog(@StringRes int title, @StringRes int message, Callable<? extends T> task) {
+ ConfirmationDialog dialog = new ConfirmationDialog(getActivity(), title, message) {
+ @Override
+ @SuppressLint("CheckResult")
+ public void onConfirmButtonPressed(DialogInterface clickedDialog) {
+ clickedDialog.dismiss();
+ Observable.fromCallable(task)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(result -> loadSubscriptions(),
+ error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+ };
+ dialog.createNewDialog().show();
}
private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
new file mode 100644
index 000000000..6cba798ba
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
@@ -0,0 +1,184 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.support.v7.preference.CheckBoxPreference;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import android.support.v7.preference.PreferenceScreen;
+import android.util.Log;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat {
+ private static final String TAG = "AutoDnldPrefFragment";
+ private CheckBoxPreference[] selectedNetworks;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.preferences_autodownload);
+
+ setupAutoDownloadScreen();
+ buildAutodownloadSelectedNetworksPreference();
+ setSelectedNetworksEnabled(UserPreferences.isEnableAutodownloadWifiFilter());
+ buildEpisodeCleanupPreference();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ checkAutodownloadItemVisibility(UserPreferences.isEnableAutodownload());
+ }
+
+ private void setupAutoDownloadScreen() {
+ findPreference(UserPreferences.PREF_ENABLE_AUTODL).setOnPreferenceChangeListener(
+ (preference, newValue) -> {
+ if (newValue instanceof Boolean) {
+ checkAutodownloadItemVisibility((Boolean) newValue);
+ }
+ return true;
+ });
+ findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
+ .setOnPreferenceChangeListener(
+ (preference, newValue) -> {
+ if (newValue instanceof Boolean) {
+ setSelectedNetworksEnabled((Boolean) newValue);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ );
+ }
+
+ private void checkAutodownloadItemVisibility(boolean autoDownload) {
+ findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setEnabled(autoDownload);
+ findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY).setEnabled(autoDownload);
+ findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled(autoDownload);
+ findPreference(UserPreferences.PREF_EPISODE_CLEANUP).setEnabled(autoDownload);
+ setSelectedNetworksEnabled(autoDownload && UserPreferences.isEnableAutodownloadWifiFilter());
+ }
+
+ private static String blankIfNull(String val) {
+ return val == null ? "" : val;
+ }
+
+ private void buildAutodownloadSelectedNetworksPreference() {
+ final Activity activity = getActivity();
+
+ if (selectedNetworks != null) {
+ clearAutodownloadSelectedNetworsPreference();
+ }
+ // get configured networks
+ WifiManager wifiservice = (WifiManager) activity.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+ List<WifiConfiguration> networks = wifiservice.getConfiguredNetworks();
+
+ if (networks == null) {
+ Log.e(TAG, "Couldn't get list of configure Wi-Fi networks");
+ return;
+ }
+ Collections.sort(networks, (x, y) ->
+ blankIfNull(x.SSID).compareTo(blankIfNull(y.SSID)));
+ selectedNetworks = new CheckBoxPreference[networks.size()];
+ List<String> prefValues = Arrays.asList(UserPreferences
+ .getAutodownloadSelectedNetworks());
+ PreferenceScreen prefScreen = getPreferenceScreen();
+ Preference.OnPreferenceClickListener clickListener = preference -> {
+ if (preference instanceof CheckBoxPreference) {
+ String key = preference.getKey();
+ List<String> prefValuesList = new ArrayList<>(
+ Arrays.asList(UserPreferences
+ .getAutodownloadSelectedNetworks())
+ );
+ boolean newValue = ((CheckBoxPreference) preference)
+ .isChecked();
+ Log.d(TAG, "Selected network " + key + ". New state: " + newValue);
+
+ int index = prefValuesList.indexOf(key);
+ if (index >= 0 && !newValue) {
+ // remove network
+ prefValuesList.remove(index);
+ } else if (index < 0 && newValue) {
+ prefValuesList.add(key);
+ }
+
+ UserPreferences.setAutodownloadSelectedNetworks(
+ prefValuesList.toArray(new String[prefValuesList.size()])
+ );
+ return true;
+ } else {
+ return false;
+ }
+ };
+ // create preference for each known network. attach listener and set
+ // value
+ for (int i = 0; i < networks.size(); i++) {
+ WifiConfiguration config = networks.get(i);
+
+ CheckBoxPreference pref = new CheckBoxPreference(activity);
+ String key = Integer.toString(config.networkId);
+ pref.setTitle(config.SSID);
+ pref.setKey(key);
+ pref.setOnPreferenceClickListener(clickListener);
+ pref.setPersistent(false);
+ pref.setChecked(prefValues.contains(key));
+ selectedNetworks[i] = pref;
+ prefScreen.addPreference(pref);
+ }
+ }
+
+ private void clearAutodownloadSelectedNetworsPreference() {
+ if (selectedNetworks != null) {
+ PreferenceScreen prefScreen = getPreferenceScreen();
+
+ for (CheckBoxPreference network : selectedNetworks) {
+ if (network != null) {
+ prefScreen.removePreference(network);
+ }
+ }
+ }
+ }
+
+ private void buildEpisodeCleanupPreference() {
+ final Resources res = getActivity().getResources();
+
+ ListPreference pref = (ListPreference) findPreference(UserPreferences.PREF_EPISODE_CLEANUP);
+ String[] values = res.getStringArray(
+ R.array.episode_cleanup_values);
+ String[] entries = new String[values.length];
+ for (int x = 0; x < values.length; x++) {
+ int v = Integer.parseInt(values[x]);
+ if (v == UserPreferences.EPISODE_CLEANUP_QUEUE) {
+ entries[x] = res.getString(R.string.episode_cleanup_queue_removal);
+ } else if (v == UserPreferences.EPISODE_CLEANUP_NULL){
+ entries[x] = res.getString(R.string.episode_cleanup_never);
+ } else if (v == 0) {
+ entries[x] = res.getString(R.string.episode_cleanup_after_listening);
+ } else if (v > 0 && v < 24) {
+ entries[x] = res.getQuantityString(R.plurals.episode_cleanup_hours_after_listening, v, v);
+ } else {
+ int numDays = v / 24; // assume underlying value will be NOT fraction of days, e.g., 36 (hours)
+ entries[x] = res.getQuantityString(R.plurals.episode_cleanup_days_after_listening, numDays, numDays);
+ }
+ }
+ pref.setEntries(entries);
+ }
+
+ private void setSelectedNetworksEnabled(boolean b) {
+ if (selectedNetworks != null) {
+ for (Preference p : selectedNetworks) {
+ p.setEnabled(b);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
new file mode 100644
index 000000000..491922056
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
@@ -0,0 +1,144 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import android.text.Html;
+import android.text.format.DateUtils;
+import android.widget.Toast;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
+import de.danoeh.antennapod.core.service.GpodnetSyncService;
+import de.danoeh.antennapod.dialog.AuthenticationDialog;
+import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
+
+public class GpodderPreferencesFragment extends PreferenceFragmentCompat {
+ private static final String PREF_GPODNET_LOGIN = "pref_gpodnet_authenticate";
+ private static final String PREF_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information";
+ private static final String PREF_GPODNET_SYNC = "pref_gpodnet_sync";
+ private static final String PREF_GPODNET_FORCE_FULL_SYNC = "pref_gpodnet_force_full_sync";
+ private static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout";
+ private static final String PREF_GPODNET_HOSTNAME = "pref_gpodnet_hostname";
+ private static final String PREF_GPODNET_NOTIFICATIONS = "pref_gpodnet_notifications";
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.preferences_gpodder);
+ setupGpodderScreen();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ GpodnetPreferences.registerOnSharedPreferenceChangeListener(gpoddernetListener);
+ updateGpodnetPreferenceScreen();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ GpodnetPreferences.unregisterOnSharedPreferenceChangeListener(gpoddernetListener);
+ }
+
+ private final SharedPreferences.OnSharedPreferenceChangeListener gpoddernetListener =
+ (sharedPreferences, key) -> {
+ if (GpodnetPreferences.PREF_LAST_SYNC_ATTEMPT_TIMESTAMP.equals(key)) {
+ updateLastGpodnetSyncReport(GpodnetPreferences.getLastSyncAttemptResult(),
+ GpodnetPreferences.getLastSyncAttemptTimestamp());
+ }
+ };
+
+ private void setupGpodderScreen() {
+ final Activity activity = getActivity();
+
+ findPreference(PREF_GPODNET_SETLOGIN_INFORMATION)
+ .setOnPreferenceClickListener(preference -> {
+ AuthenticationDialog dialog = new AuthenticationDialog(activity,
+ R.string.pref_gpodnet_setlogin_information_title, false, false, GpodnetPreferences.getUsername(),
+ null) {
+
+ @Override
+ protected void onConfirmed(String username, String password, boolean saveUsernamePassword) {
+ GpodnetPreferences.setPassword(password);
+ }
+ };
+ dialog.show();
+ return true;
+ });
+ findPreference(PREF_GPODNET_SYNC).
+ setOnPreferenceClickListener(preference -> {
+ GpodnetSyncService.sendSyncIntent(getActivity().getApplicationContext());
+ Toast toast = Toast.makeText(getActivity(), R.string.pref_gpodnet_sync_started,
+ Toast.LENGTH_SHORT);
+ toast.show();
+ return true;
+ });
+ findPreference(PREF_GPODNET_FORCE_FULL_SYNC).
+ setOnPreferenceClickListener(preference -> {
+ GpodnetPreferences.setLastSubscriptionSyncTimestamp(0L);
+ GpodnetPreferences.setLastEpisodeActionsSyncTimestamp(0L);
+ GpodnetPreferences.setLastSyncAttempt(false, 0);
+ updateLastGpodnetSyncReport(false, 0);
+ GpodnetSyncService.sendSyncIntent(getActivity().getApplicationContext());
+ Toast toast = Toast.makeText(getActivity(), R.string.pref_gpodnet_sync_started,
+ Toast.LENGTH_SHORT);
+ toast.show();
+ return true;
+ });
+ findPreference(PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(
+ preference -> {
+ GpodnetPreferences.logout();
+ Toast toast = Toast.makeText(activity, R.string.pref_gpodnet_logout_toast, Toast.LENGTH_SHORT);
+ toast.show();
+ updateGpodnetPreferenceScreen();
+ return true;
+ });
+ findPreference(PREF_GPODNET_HOSTNAME).setOnPreferenceClickListener(
+ preference -> {
+ GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(dialog -> updateGpodnetPreferenceScreen());
+ return true;
+ });
+ }
+
+ private void updateGpodnetPreferenceScreen() {
+ final boolean loggedIn = GpodnetPreferences.loggedIn();
+ findPreference(PREF_GPODNET_LOGIN).setEnabled(!loggedIn);
+ findPreference(PREF_GPODNET_SETLOGIN_INFORMATION).setEnabled(loggedIn);
+ findPreference(PREF_GPODNET_SYNC).setEnabled(loggedIn);
+ findPreference(PREF_GPODNET_FORCE_FULL_SYNC).setEnabled(loggedIn);
+ findPreference(PREF_GPODNET_LOGOUT).setEnabled(loggedIn);
+ findPreference(PREF_GPODNET_NOTIFICATIONS).setEnabled(loggedIn);
+ if(loggedIn) {
+ String format = getActivity().getString(R.string.pref_gpodnet_login_status);
+ String summary = String.format(format, GpodnetPreferences.getUsername(),
+ GpodnetPreferences.getDeviceID());
+ findPreference(PREF_GPODNET_LOGOUT).setSummary(Html.fromHtml(summary));
+ updateLastGpodnetSyncReport(GpodnetPreferences.getLastSyncAttemptResult(),
+ GpodnetPreferences.getLastSyncAttemptTimestamp());
+ } else {
+ findPreference(PREF_GPODNET_LOGOUT).setSummary(null);
+ updateLastGpodnetSyncReport(false, 0);
+ }
+ findPreference(PREF_GPODNET_HOSTNAME).setSummary(GpodnetPreferences.getHostname());
+ }
+
+ private void updateLastGpodnetSyncReport(boolean successful, long lastTime) {
+ Preference sync = findPreference(PREF_GPODNET_SYNC);
+ if (lastTime != 0) {
+ sync.setSummary(getActivity().getString(R.string.pref_gpodnet_sync_changes_sum) + "\n" +
+ getActivity().getString(R.string.pref_gpodnet_sync_sum_last_sync_line,
+ getActivity().getString(successful ?
+ R.string.gpodnetsync_pref_report_successful :
+ R.string.gpodnetsync_pref_report_failed),
+ DateUtils.getRelativeDateTimeString(getActivity(),
+ lastTime,
+ DateUtils.MINUTE_IN_MILLIS,
+ DateUtils.WEEK_IN_MILLIS,
+ DateUtils.FORMAT_SHOW_TIME)));
+ } else {
+ sync.setSummary(getActivity().getString(R.string.pref_gpodnet_sync_changes_sum));
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java
new file mode 100644
index 000000000..229274b76
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java
@@ -0,0 +1,23 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.os.Bundle;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+
+public class IntegrationsPreferencesFragment extends PreferenceFragmentCompat {
+ private static final String PREF_SCREEN_GPODDER = "prefGpodderSettings";
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.preferences_integrations);
+ setupIntegrationsScreen();
+ }
+
+ private void setupIntegrationsScreen() {
+ findPreference(PREF_SCREEN_GPODDER).setOnPreferenceClickListener(preference -> {
+ ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_gpodder);
+ return true;
+ });
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
new file mode 100644
index 000000000..701d21ce0
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
@@ -0,0 +1,147 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.content.FileProvider;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import android.util.Log;
+import android.widget.Toast;
+import com.bytehamster.lib.preferencesearch.SearchConfiguration;
+import com.bytehamster.lib.preferencesearch.SearchPreference;
+import de.danoeh.antennapod.CrashReportWriter;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.AboutActivity;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.activity.StatisticsActivity;
+
+import java.util.List;
+
+public class MainPreferencesFragment extends PreferenceFragmentCompat {
+ private static final String TAG = "MainPreferencesFragment";
+
+ private static final String PREF_SCREEN_USER_INTERFACE = "prefScreenInterface";
+ private static final String PREF_SCREEN_PLAYBACK = "prefScreenPlayback";
+ private static final String PREF_SCREEN_NETWORK = "prefScreenNetwork";
+ private static final String PREF_SCREEN_INTEGRATIONS = "prefScreenIntegrations";
+ private static final String PREF_SCREEN_STORAGE = "prefScreenStorage";
+ private static final String PREF_KNOWN_ISSUES = "prefKnownIssues";
+ private static final String PREF_FAQ = "prefFaq";
+ private static final String PREF_SEND_CRASH_REPORT = "prefSendCrashReport";
+ private static final String STATISTICS = "statistics";
+ private static final String PREF_ABOUT = "prefAbout";
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.preferences);
+ setupMainScreen();
+ setupSearch();
+ }
+
+ private void setupMainScreen() {
+ findPreference(PREF_SCREEN_USER_INTERFACE).setOnPreferenceClickListener(preference -> {
+ ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_user_interface);
+ return true;
+ });
+ findPreference(PREF_SCREEN_PLAYBACK).setOnPreferenceClickListener(preference -> {
+ ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_playback);
+ return true;
+ });
+ findPreference(PREF_SCREEN_NETWORK).setOnPreferenceClickListener(preference -> {
+ ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_network);
+ return true;
+ });
+ findPreference(PREF_SCREEN_INTEGRATIONS).setOnPreferenceClickListener(preference -> {
+ ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_integrations);
+ return true;
+ });
+ findPreference(PREF_SCREEN_STORAGE).setOnPreferenceClickListener(preference -> {
+ ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_storage);
+ return true;
+ });
+
+ findPreference(PREF_ABOUT).setOnPreferenceClickListener(
+ preference -> {
+ startActivity(new Intent(getActivity(), AboutActivity.class));
+ return true;
+ }
+ );
+ findPreference(STATISTICS).setOnPreferenceClickListener(
+ preference -> {
+ startActivity(new Intent(getActivity(), StatisticsActivity.class));
+ return true;
+ }
+ );
+ findPreference(PREF_KNOWN_ISSUES).setOnPreferenceClickListener(preference -> {
+ openInBrowser("https://github.com/AntennaPod/AntennaPod/labels/bug");
+ return true;
+ });
+ findPreference(PREF_FAQ).setOnPreferenceClickListener(preference -> {
+ openInBrowser("http://antennapod.org/faq.html");
+ return true;
+ });
+ findPreference(PREF_SEND_CRASH_REPORT).setOnPreferenceClickListener(preference -> {
+ Context context = getActivity().getApplicationContext();
+ Intent emailIntent = new Intent(Intent.ACTION_SEND);
+ emailIntent.setType("text/plain");
+ emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"Martin.Fietz@gmail.com"});
+ emailIntent.putExtra(Intent.EXTRA_SUBJECT, "AntennaPod Crash Report");
+ emailIntent.putExtra(Intent.EXTRA_TEXT, "Please describe what you were doing when the app crashed");
+ // the attachment
+ Uri fileUri = FileProvider.getUriForFile(context, context.getString(R.string.provider_authority),
+ CrashReportWriter.getFile());
+ emailIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
+ emailIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ String intentTitle = getActivity().getString(R.string.send_email);
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
+ List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(emailIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ for (ResolveInfo resolveInfo : resInfoList) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ }
+ getActivity().startActivity(Intent.createChooser(emailIntent, intentTitle));
+ return true;
+ });
+ }
+
+ private void openInBrowser(String url) {
+ try {
+ Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ startActivity(myIntent);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(getActivity(), R.string.pref_no_browser_found, Toast.LENGTH_LONG).show();
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ }
+
+ private void setupSearch() {
+ SearchPreference searchPreference = (SearchPreference) findPreference("searchPreference");
+ SearchConfiguration config = searchPreference.getSearchConfiguration();
+ config.setActivity((AppCompatActivity) getActivity());
+ config.setFragmentContainerViewId(R.id.content);
+ config.setBreadcrumbsEnabled(true);
+
+ config.index(R.xml.preferences_user_interface)
+ .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_user_interface));
+ config.index(R.xml.preferences_playback)
+ .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_playback));
+ config.index(R.xml.preferences_network)
+ .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_network));
+ config.index(R.xml.preferences_storage)
+ .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_storage));
+ config.index(R.xml.preferences_autodownload)
+ .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_network))
+ .addBreadcrumb(R.string.automation)
+ .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_autodownload));
+ config.index(R.xml.preferences_gpodder)
+ .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_integrations))
+ .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_gpodder));
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
new file mode 100644
index 000000000..ac2436e25
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
@@ -0,0 +1,175 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.app.TimePickerDialog;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import android.text.format.DateFormat;
+import com.afollestad.materialdialogs.MaterialDialog;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.dialog.ProxyDialog;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.concurrent.TimeUnit;
+
+public class NetworkPreferencesFragment extends PreferenceFragmentCompat {
+ private static final String PREF_SCREEN_AUTODL = "prefAutoDownloadSettings";
+ private static final String PREF_PROXY = "prefProxy";
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.preferences_network);
+ setupNetworkScreen();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ setUpdateIntervalText();
+ setParallelDownloadsText(UserPreferences.getParallelDownloads());
+ }
+
+ private void setupNetworkScreen() {
+ findPreference(PREF_SCREEN_AUTODL).setOnPreferenceClickListener(preference -> {
+ ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_autodownload);
+ return true;
+ });
+ findPreference(UserPreferences.PREF_UPDATE_INTERVAL)
+ .setOnPreferenceClickListener(preference -> {
+ showUpdateIntervalTimePreferencesDialog();
+ return true;
+ });
+ findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)
+ .setOnPreferenceChangeListener(
+ (preference, o) -> {
+ if (o instanceof Integer) {
+ setParallelDownloadsText((Integer) o);
+ }
+ return true;
+ }
+ );
+ // validate and set correct value: number of downloads between 1 and 50 (inclusive)
+ findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> {
+ ProxyDialog dialog = new ProxyDialog(getActivity());
+ dialog.createDialog().show();
+ return true;
+ });
+ }
+
+ private void setUpdateIntervalText() {
+ Context context = getActivity().getApplicationContext();
+ String val;
+ long interval = UserPreferences.getUpdateInterval();
+ if(interval > 0) {
+ int hours = (int) TimeUnit.MILLISECONDS.toHours(interval);
+ String hoursStr = context.getResources().getQuantityString(R.plurals.time_hours_quantified, hours, hours);
+ val = String.format(context.getString(R.string.pref_autoUpdateIntervallOrTime_every), hoursStr);
+ } else {
+ int[] timeOfDay = UserPreferences.getUpdateTimeOfDay();
+ if(timeOfDay.length == 2) {
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, timeOfDay[0]);
+ cal.set(Calendar.MINUTE, timeOfDay[1]);
+ String timeOfDayStr = DateFormat.getTimeFormat(context).format(cal.getTime());
+ val = String.format(context.getString(R.string.pref_autoUpdateIntervallOrTime_at),
+ timeOfDayStr);
+ } else {
+ val = context.getString(R.string.pref_smart_mark_as_played_disabled); // TODO: Is this a bug? Otherwise document why is this related to smart mark???
+ }
+ }
+ String summary = context.getString(R.string.pref_autoUpdateIntervallOrTime_sum) + "\n"
+ + String.format(context.getString(R.string.pref_current_value), val);
+ findPreference(UserPreferences.PREF_UPDATE_INTERVAL).setSummary(summary);
+ }
+
+ private void setParallelDownloadsText(int downloads) {
+ final Resources res = getActivity().getResources();
+
+ String s = Integer.toString(downloads)
+ + res.getString(R.string.parallel_downloads_suffix);
+ findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS).setSummary(s);
+ }
+
+ private void showUpdateIntervalTimePreferencesDialog() {
+ final Context context = getActivity();
+
+ MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
+ builder.title(R.string.pref_autoUpdateIntervallOrTime_title);
+ builder.content(R.string.pref_autoUpdateIntervallOrTime_message);
+ builder.positiveText(R.string.pref_autoUpdateIntervallOrTime_Interval);
+ builder.negativeText(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay);
+ builder.neutralText(R.string.pref_autoUpdateIntervallOrTime_Disable);
+ builder.onPositive((dialog, which) -> {
+ AlertDialog.Builder builder1 = new AlertDialog.Builder(context);
+ builder1.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
+ final String[] values = context.getResources().getStringArray(R.array.update_intervall_values);
+ final String[] entries = getUpdateIntervalEntries(values);
+ long currInterval = UserPreferences.getUpdateInterval();
+ int checkedItem = -1;
+ if(currInterval > 0) {
+ String currIntervalStr = String.valueOf(TimeUnit.MILLISECONDS.toHours(currInterval));
+ checkedItem = ArrayUtils.indexOf(values, currIntervalStr);
+ }
+ builder1.setSingleChoiceItems(entries, checkedItem, (dialog1, which1) -> {
+ int hours = Integer.parseInt(values[which1]);
+ UserPreferences.setUpdateInterval(hours);
+ dialog1.dismiss();
+ setUpdateIntervalText();
+ });
+ builder1.setNegativeButton(context.getString(R.string.cancel_label), null);
+ builder1.show();
+ });
+ builder.onNegative((dialog, which) -> {
+ int hourOfDay = 7, minute = 0;
+ int[] updateTime = UserPreferences.getUpdateTimeOfDay();
+ if (updateTime.length == 2) {
+ hourOfDay = updateTime[0];
+ minute = updateTime[1];
+ }
+ TimePickerDialog timePickerDialog = new TimePickerDialog(context,
+ (view, selectedHourOfDay, selectedMinute) -> {
+ if (view.getTag() == null) { // onTimeSet() may get called twice!
+ view.setTag("TAGGED");
+ UserPreferences.setUpdateTimeOfDay(selectedHourOfDay, selectedMinute);
+ setUpdateIntervalText();
+ }
+ }, hourOfDay, minute, DateFormat.is24HourFormat(context));
+ timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay));
+ timePickerDialog.show();
+ });
+ builder.onNeutral((dialog, which) -> {
+ UserPreferences.disableAutoUpdate();
+ setUpdateIntervalText();
+ });
+ builder.show();
+ }
+
+ private String[] getUpdateIntervalEntries(final String[] values) {
+ final Resources res = getActivity().getResources();
+ String[] entries = new String[values.length];
+ for (int x = 0; x < values.length; x++) {
+ Integer v = Integer.parseInt(values[x]);
+ switch (v) {
+ case 0:
+ entries[x] = res.getString(R.string.pref_update_interval_hours_manual);
+ break;
+ case 1:
+ entries[x] = v + " " + res.getString(R.string.pref_update_interval_hours_singular);
+ break;
+ default:
+ entries[x] = v + " " + res.getString(R.string.pref_update_interval_hours_plural);
+ break;
+
+ }
+ }
+ return entries;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
new file mode 100644
index 000000000..e1714d4bd
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
@@ -0,0 +1,92 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MediaplayerActivity;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
+import de.danoeh.antennapod.dialog.VariableSpeedDialog;
+import de.danoeh.antennapod.preferences.PreferenceControllerFlavorHelper;
+
+public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
+ private static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher";
+ private static final String PREF_PLAYBACK_REWIND_DELTA_LAUNCHER = "prefPlaybackRewindDeltaLauncher";
+ private static final String PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER = "prefPlaybackFastForwardDeltaLauncher";
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.preferences_playback);
+
+ setupPlaybackScreen();
+ PreferenceControllerFlavorHelper.setupFlavoredUI(this);
+ buildSmartMarkAsPlayedPreference();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ checkSonicItemVisibility();
+ }
+
+ private void setupPlaybackScreen() {
+ final Activity activity = getActivity();
+
+ findPreference(PREF_PLAYBACK_SPEED_LAUNCHER)
+ .setOnPreferenceClickListener(preference -> {
+ VariableSpeedDialog.showDialog(activity);
+ return true;
+ });
+ findPreference(PREF_PLAYBACK_REWIND_DELTA_LAUNCHER)
+ .setOnPreferenceClickListener(preference -> {
+ MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_REWIND);
+ return true;
+ });
+ findPreference(PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER)
+ .setOnPreferenceClickListener(preference -> {
+ MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_FORWARD);
+ return true;
+ });
+ if (!PictureInPictureUtil.supportsPictureInPicture(activity)) {
+ ListPreference behaviour = (ListPreference) findPreference(UserPreferences.PREF_VIDEO_BEHAVIOR);
+ behaviour.setEntries(R.array.video_background_behavior_options_without_pip);
+ behaviour.setEntryValues(R.array.video_background_behavior_values_without_pip);
+ }
+ }
+
+ private void buildSmartMarkAsPlayedPreference() {
+ final Resources res = getActivity().getResources();
+
+ ListPreference pref = (ListPreference) findPreference(UserPreferences.PREF_SMART_MARK_AS_PLAYED_SECS);
+ String[] values = res.getStringArray(R.array.smart_mark_as_played_values);
+ String[] entries = new String[values.length];
+ for (int x = 0; x < values.length; x++) {
+ if(x == 0) {
+ entries[x] = res.getString(R.string.pref_smart_mark_as_played_disabled);
+ } else {
+ Integer v = Integer.parseInt(values[x]);
+ if(v < 60) {
+ entries[x] = res.getQuantityString(R.plurals.time_seconds_quantified, v, v);
+ } else {
+ v /= 60;
+ entries[x] = res.getQuantityString(R.plurals.time_minutes_quantified, v, v);
+ }
+ }
+ }
+ pref.setEntries(entries);
+ }
+
+
+
+ private void checkSonicItemVisibility() {
+ if (Build.VERSION.SDK_INT < 16) {
+ ListPreference p = (ListPreference) findPreference(UserPreferences.PREF_MEDIA_PLAYER);
+ p.setEntries(R.array.media_player_options_no_sonic);
+ p.setEntryValues(R.array.media_player_values_no_sonic);
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
new file mode 100644
index 000000000..b4226b546
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
@@ -0,0 +1,244 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.FileProvider;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import android.util.Log;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.DirectoryChooserActivity;
+import de.danoeh.antennapod.activity.ImportExportActivity;
+import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
+import de.danoeh.antennapod.asynctask.ExportWorker;
+import de.danoeh.antennapod.core.export.ExportWriter;
+import de.danoeh.antennapod.core.export.html.HtmlWriter;
+import de.danoeh.antennapod.core.export.opml.OpmlWriter;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+import java.io.File;
+import java.util.List;
+
+public class StoragePreferencesFragment extends PreferenceFragmentCompat {
+ private static final String TAG = "StoragePrefFragment";
+ private static final String PREF_OPML_EXPORT = "prefOpmlExport";
+ private static final String PREF_OPML_IMPORT = "prefOpmlImport";
+ private static final String PREF_HTML_EXPORT = "prefHtmlExport";
+ private static final String IMPORT_EXPORT = "importExport";
+ private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
+ private static final String[] EXTERNAL_STORAGE_PERMISSIONS = {
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE };
+ private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 41;
+ private Disposable disposable;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.preferences_storage);
+ setupStorageScreen();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ setDataFolderText();
+ }
+
+ private void setupStorageScreen() {
+ final Activity activity = getActivity();
+
+ findPreference(IMPORT_EXPORT).setOnPreferenceClickListener(
+ preference -> {
+ activity.startActivity(new Intent(activity, ImportExportActivity.class));
+ return true;
+ }
+ );
+ findPreference(PREF_OPML_EXPORT).setOnPreferenceClickListener(
+ preference -> export(new OpmlWriter()));
+ findPreference(PREF_HTML_EXPORT).setOnPreferenceClickListener(
+ preference -> export(new HtmlWriter()));
+ findPreference(PREF_OPML_IMPORT).setOnPreferenceClickListener(
+ preference -> {
+ activity.startActivity(new Intent(activity, OpmlImportFromPathActivity.class));
+ return true;
+ });
+ findPreference(PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
+ preference -> {
+ if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
+ Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ showChooseDataFolderDialog();
+ } else {
+ int readPermission = ActivityCompat.checkSelfPermission(
+ activity, Manifest.permission.READ_EXTERNAL_STORAGE);
+ int writePermission = ActivityCompat.checkSelfPermission(
+ activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ if (readPermission == PackageManager.PERMISSION_GRANTED &&
+ writePermission == PackageManager.PERMISSION_GRANTED) {
+ openDirectoryChooser();
+ } else {
+ requestPermission();
+ }
+ }
+ return true;
+ }
+ );
+ findPreference(PREF_CHOOSE_DATA_DIR)
+ .setOnPreferenceClickListener(
+ preference -> {
+ if (Build.VERSION.SDK_INT >= 19) {
+ showChooseDataFolderDialog();
+ } else {
+ Intent intent = new Intent(activity, DirectoryChooserActivity.class);
+ activity.startActivityForResult(intent,
+ DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
+ }
+ return true;
+ }
+ );
+ findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE).setOnPreferenceChangeListener(
+ (preference, o) -> {
+ if (o instanceof String) {
+ int newValue = Integer.parseInt((String) o) * 1024 * 1024;
+ if (newValue != UserPreferences.getImageCacheSize()) {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity());
+ dialog.setTitle(android.R.string.dialog_alert_title);
+ dialog.setMessage(R.string.pref_restart_required);
+ dialog.setPositiveButton(android.R.string.ok, null);
+ dialog.show();
+ }
+ return true;
+ }
+ return false;
+ }
+ );
+ }
+
+ private boolean export(ExportWriter exportWriter) {
+ Context context = getActivity();
+ final ProgressDialog progressDialog = new ProgressDialog(context);
+ progressDialog.setMessage(context.getString(R.string.exporting_label));
+ progressDialog.setIndeterminate(true);
+ progressDialog.show();
+ final AlertDialog.Builder alert = new AlertDialog.Builder(context)
+ .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
+ Observable<File> observable = new ExportWorker(exportWriter).exportObservable();
+ disposable = observable.subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(output -> {
+ alert.setTitle(R.string.export_success_title);
+ String message = context.getString(R.string.export_success_sum, output.toString());
+ alert.setMessage(message);
+ alert.setPositiveButton(R.string.send_label, (dialog, which) -> {
+ Uri fileUri = FileProvider.getUriForFile(context.getApplicationContext(),
+ context.getString(R.string.provider_authority), output);
+ Intent sendIntent = new Intent(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_SUBJECT,
+ context.getResources().getText(R.string.opml_export_label));
+ sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
+ sendIntent.setType("text/plain");
+ sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
+ List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(sendIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ for (ResolveInfo resolveInfo : resInfoList) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ }
+ context.startActivity(Intent.createChooser(sendIntent,
+ context.getResources().getText(R.string.send_label)));
+ });
+ alert.create().show();
+ }, error -> {
+ alert.setTitle(R.string.export_error_label);
+ alert.setMessage(error.getMessage());
+ alert.show();
+ }, progressDialog::dismiss);
+ return true;
+ }
+
+ public void unsubscribeExportSubscription() {
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ @SuppressLint("NewApi")
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == Activity.RESULT_OK &&
+ requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
+ String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
+
+ File path;
+ if(dir != null) {
+ path = new File(dir);
+ } else {
+ path = getActivity().getExternalFilesDir(null);
+ }
+ String message = null;
+ final Context context= getActivity().getApplicationContext();
+ if(!path.exists()) {
+ message = String.format(context.getString(R.string.folder_does_not_exist_error), dir);
+ } else if(!path.canRead()) {
+ message = String.format(context.getString(R.string.folder_not_readable_error), dir);
+ } else if(!path.canWrite()) {
+ message = String.format(context.getString(R.string.folder_not_writable_error), dir);
+ }
+
+ if(message == null) {
+ Log.d(TAG, "Setting data folder: " + dir);
+ UserPreferences.setDataFolder(dir);
+ setDataFolderText();
+ } else {
+ AlertDialog.Builder ab = new AlertDialog.Builder(getActivity());
+ ab.setMessage(message);
+ ab.setPositiveButton(android.R.string.ok, null);
+ ab.show();
+ }
+ }
+ }
+
+ private void setDataFolderText() {
+ File f = UserPreferences.getDataFolder(null);
+ if (f != null) {
+ findPreference(PREF_CHOOSE_DATA_DIR)
+ .setSummary(f.getAbsolutePath());
+ }
+ }
+
+ private void requestPermission() {
+ ActivityCompat.requestPermissions(getActivity(), EXTERNAL_STORAGE_PERMISSIONS,
+ PERMISSION_REQUEST_EXTERNAL_STORAGE);
+ }
+
+ private void openDirectoryChooser() {
+ Activity activity = getActivity();
+ Intent intent = new Intent(activity, DirectoryChooserActivity.class);
+ activity.startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
+ }
+
+ private void showChooseDataFolderDialog() {
+ ChooseDataFolderDialog.showDialog(
+ getActivity(), new ChooseDataFolderDialog.RunnableWithString() {
+ @Override
+ public void run(final String folder) {
+ UserPreferences.setDataFolder(folder);
+ setDataFolderText();
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
new file mode 100644
index 000000000..e1d44f7d3
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
@@ -0,0 +1,165 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.design.widget.Snackbar;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import android.widget.ListView;
+import android.widget.Toast;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.util.List;
+
+public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat {
+ private static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify";
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.preferences_user_interface);
+ setupInterfaceScreen();
+ }
+
+ private void setupInterfaceScreen() {
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+ // disable expanded notification option on unsupported android versions
+ findPreference(PREF_EXPANDED_NOTIFICATION).setEnabled(false);
+ findPreference(PREF_EXPANDED_NOTIFICATION).setOnPreferenceClickListener(
+ preference -> {
+ Toast toast = Toast.makeText(getActivity(),
+ R.string.pref_expand_notify_unsupport_toast, Toast.LENGTH_SHORT);
+ toast.show();
+ return true;
+ }
+ );
+ }
+ findPreference(UserPreferences.PREF_THEME)
+ .setOnPreferenceChangeListener(
+ (preference, newValue) -> {
+ Intent i = new Intent(getActivity(), MainActivity.class);
+ i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
+ | Intent.FLAG_ACTIVITY_NEW_TASK);
+ getActivity().finish();
+ startActivity(i);
+ return true;
+ }
+ );
+ findPreference(UserPreferences.PREF_HIDDEN_DRAWER_ITEMS)
+ .setOnPreferenceClickListener(preference -> {
+ showDrawerPreferencesDialog();
+ return true;
+ });
+
+ findPreference(UserPreferences.PREF_COMPACT_NOTIFICATION_BUTTONS)
+ .setOnPreferenceClickListener(preference -> {
+ showNotificationButtonsDialog();
+ return true;
+ });
+
+ findPreference(UserPreferences.PREF_BACK_BUTTON_BEHAVIOR)
+ .setOnPreferenceChangeListener((preference, newValue) -> {
+ if (newValue.equals("page")) {
+ final Context context = getActivity();
+ final String[] navTitles = context.getResources().getStringArray(R.array.back_button_go_to_pages);
+ final String[] navTags = context.getResources().getStringArray(R.array.back_button_go_to_pages_tags);
+ final String choice[] = { UserPreferences.getBackButtonGoToPage() };
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.back_button_go_to_page_title);
+ builder.setSingleChoiceItems(navTitles, ArrayUtils.indexOf(navTags, UserPreferences.getBackButtonGoToPage()), (dialogInterface, i) -> {
+ if (i >= 0) {
+ choice[0] = navTags[i];
+ }
+ });
+ builder.setPositiveButton(R.string.confirm_label, (dialogInterface, i) -> UserPreferences.setBackButtonGoToPage(choice[0]));
+ builder.setNegativeButton(R.string.cancel_label, null);
+ builder.create().show();
+ return true;
+ } else {
+ return true;
+ }
+ });
+
+ if (Build.VERSION.SDK_INT >= 26) {
+ findPreference(UserPreferences.PREF_EXPANDED_NOTIFICATION).setVisible(false);
+ }
+ }
+
+ private void showDrawerPreferencesDialog() {
+ final Context context = getActivity();
+ final List<String> hiddenDrawerItems = UserPreferences.getHiddenDrawerItems();
+ final String[] navTitles = context.getResources().getStringArray(R.array.nav_drawer_titles);
+ final String[] NAV_DRAWER_TAGS = MainActivity.NAV_DRAWER_TAGS;
+ boolean[] checked = new boolean[MainActivity.NAV_DRAWER_TAGS.length];
+ for(int i=0; i < NAV_DRAWER_TAGS.length; i++) {
+ String tag = NAV_DRAWER_TAGS[i];
+ if(!hiddenDrawerItems.contains(tag)) {
+ checked[i] = true;
+ }
+ }
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.drawer_preferences);
+ builder.setMultiChoiceItems(navTitles, checked, (dialog, which, isChecked) -> {
+ if (isChecked) {
+ hiddenDrawerItems.remove(NAV_DRAWER_TAGS[which]);
+ } else {
+ hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]);
+ }
+ });
+ builder.setPositiveButton(R.string.confirm_label, (dialog, which) ->
+ UserPreferences.setHiddenDrawerItems(hiddenDrawerItems));
+ builder.setNegativeButton(R.string.cancel_label, null);
+ builder.create().show();
+ }
+
+ private void showNotificationButtonsDialog() {
+ final Context context = getActivity();
+ final List<Integer> preferredButtons = UserPreferences.getCompactNotificationButtons();
+ final String[] allButtonNames = context.getResources().getStringArray(
+ R.array.compact_notification_buttons_options);
+ boolean[] checked = new boolean[allButtonNames.length]; // booleans default to false in java
+
+ for(int i=0; i < checked.length; i++) {
+ if(preferredButtons.contains(i)) {
+ checked[i] = true;
+ }
+ }
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(String.format(context.getResources().getString(
+ R.string.pref_compact_notification_buttons_dialog_title), 2));
+ builder.setMultiChoiceItems(allButtonNames, checked, (dialog, which, isChecked) -> {
+ checked[which] = isChecked;
+
+ if (isChecked) {
+ if (preferredButtons.size() < 2) {
+ preferredButtons.add(which);
+ } else {
+ // Only allow a maximum of two selections. This is because the notification
+ // on the lock screen can only display 3 buttons, and the play/pause button
+ // is always included.
+ checked[which] = false;
+ ListView selectionView = ((AlertDialog) dialog).getListView();
+ selectionView.setItemChecked(which, false);
+ Snackbar.make(
+ selectionView,
+ String.format(context.getResources().getString(
+ R.string.pref_compact_notification_buttons_dialog_error), 2),
+ Snackbar.LENGTH_SHORT).show();
+ }
+ } else {
+ preferredButtons.remove((Integer) which);
+ }
+ });
+ builder.setPositiveButton(R.string.confirm_label, (dialog, which) ->
+ UserPreferences.setCompactNotificationButtons(preferredButtons));
+ builder.setNegativeButton(R.string.cancel_label, null);
+ builder.create().show();
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
index ffdfa9516..156657a00 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
@@ -15,7 +15,6 @@ import de.danoeh.antennapod.core.gpoddernet.model.GpodnetEpisodeAction.Action;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
@@ -68,16 +67,17 @@ public class FeedItemMenuHandler {
}
boolean hasMedia = selectedItem.getMedia() != null;
boolean isPlaying = hasMedia && selectedItem.getState() == FeedItem.State.PLAYING;
+ boolean keepSorted = UserPreferences.isQueueKeepSorted();
if (!isPlaying) {
mi.setItemVisibility(R.id.skip_episode_item, false);
}
boolean isInQueue = selectedItem.isTagged(FeedItem.TAG_QUEUE);
- if(queueAccess == null || queueAccess.size() == 0 || queueAccess.get(0) == selectedItem.getId()) {
+ if (queueAccess == null || queueAccess.size() == 0 || queueAccess.get(0) == selectedItem.getId() || keepSorted) {
mi.setItemVisibility(R.id.move_to_top_item, false);
}
- if(queueAccess == null || queueAccess.size() == 0 || queueAccess.get(queueAccess.size()-1) == selectedItem.getId()) {
+ if (queueAccess == null || queueAccess.size() == 0 || queueAccess.get(queueAccess.size()-1) == selectedItem.getId() || keepSorted) {
mi.setItemVisibility(R.id.move_to_bottom_item, false);
}
if (!isInQueue) {
@@ -101,7 +101,8 @@ public class FeedItemMenuHandler {
mi.setItemVisibility(R.id.share_download_url_with_position_item, false);
}
- mi.setItemVisibility(R.id.share_file, hasMedia && selectedItem.getMedia().fileExists());
+ boolean fileDownloaded = hasMedia && selectedItem.getMedia().fileExists();
+ mi.setItemVisibility(R.id.share_file, fileDownloaded);
if (selectedItem.isPlayed()) {
mi.setItemVisibility(R.id.mark_read_item, false);
@@ -122,14 +123,12 @@ public class FeedItemMenuHandler {
mi.setItemVisibility(R.id.deactivate_auto_download, false);
}
- if (selectedItem.getPaymentLink() == null || !selectedItem.getFlattrStatus().flattrable()) {
- mi.setItemVisibility(R.id.support_item, false);
- }
-
boolean isFavorite = selectedItem.isTagged(FeedItem.TAG_FAVORITE);
mi.setItemVisibility(R.id.add_to_favorites_item, !isFavorite);
mi.setItemVisibility(R.id.remove_from_favorites_item, isFavorite);
+ mi.setItemVisibility(R.id.remove_item, fileDownloaded);
+
return true;
}
@@ -196,7 +195,7 @@ public class FeedItemMenuHandler {
DBWriter.addQueueItem(context, selectedItem);
break;
case R.id.remove_from_queue_item:
- DBWriter.removeQueueItem(context, selectedItem, true);
+ DBWriter.removeQueueItem(context, true, selectedItem);
break;
case R.id.add_to_favorites_item:
DBWriter.addFavoriteItem(selectedItem);
@@ -226,9 +225,6 @@ public class FeedItemMenuHandler {
Toast.LENGTH_SHORT).show();
}
break;
- case R.id.support_item:
- DBTasks.flattrItemIfLoggedIn(context, selectedItem);
- break;
case R.id.share_link_item:
ShareUtils.shareFeedItemLink(context, selectedItem);
break;
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
index bd4fe9bcf..0928cfd62 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -46,11 +46,6 @@ public class FeedMenuHandler {
}
Log.d(TAG, "Preparing options menu");
- if (selectedFeed.getPaymentLink() != null && selectedFeed.getFlattrStatus().flattrable()) {
- menu.findItem(R.id.support_item).setVisible(true);
- } else {
- menu.findItem(R.id.support_item).setVisible(false);
- }
menu.findItem(R.id.refresh_complete_item).setVisible(selectedFeed.isPaged());
@@ -98,9 +93,6 @@ public class FeedMenuHandler {
Toast.LENGTH_SHORT).show();
}
break;
- case R.id.support_item:
- DBTasks.flattrFeedIfLoggedIn(context, selectedFeed);
- break;
case R.id.share_link_item:
ShareUtils.shareFeedlink(context, selectedFeed);
break;
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
deleted file mode 100644
index 31b2cbcb2..000000000
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
+++ /dev/null
@@ -1,1218 +0,0 @@
-package de.danoeh.antennapod.preferences;
-
-import android.Manifest;
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.app.TimePickerDialog;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.FileProvider;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.preference.CheckBoxPreference;
-import android.support.v7.preference.ListPreference;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceFragmentCompat;
-import android.support.v7.preference.PreferenceManager;
-import android.support.v7.preference.PreferenceScreen;
-import android.text.Html;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.util.Log;
-import android.widget.ListView;
-import android.widget.Toast;
-
-import com.afollestad.materialdialogs.MaterialDialog;
-import com.bytehamster.lib.preferencesearch.SearchConfiguration;
-import com.bytehamster.lib.preferencesearch.SearchPreference;
-
-import org.apache.commons.lang3.ArrayUtils;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.GregorianCalendar;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import de.danoeh.antennapod.CrashReportWriter;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.AboutActivity;
-import de.danoeh.antennapod.activity.DirectoryChooserActivity;
-import de.danoeh.antennapod.activity.ImportExportActivity;
-import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.activity.MediaplayerActivity;
-import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
-import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.activity.StatisticsActivity;
-import de.danoeh.antennapod.asynctask.ExportWorker;
-import de.danoeh.antennapod.core.export.ExportWriter;
-import de.danoeh.antennapod.core.export.html.HtmlWriter;
-import de.danoeh.antennapod.core.export.opml.OpmlWriter;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.GpodnetSyncService;
-import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
-import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
-import de.danoeh.antennapod.dialog.AuthenticationDialog;
-import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog;
-import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
-import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
-import de.danoeh.antennapod.dialog.ProxyDialog;
-import de.danoeh.antennapod.dialog.VariableSpeedDialog;
-import io.reactivex.Observable;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.disposables.Disposable;
-import io.reactivex.schedulers.Schedulers;
-
-import static de.danoeh.antennapod.activity.PreferenceActivity.PARAM_RESOURCE;
-
-/**
- * Sets up a preference UI that lets the user change user preferences.
- */
-
-public class PreferenceController implements SharedPreferences.OnSharedPreferenceChangeListener {
-
- private static final String TAG = "PreferenceController";
-
- private static final String PREF_SCREEN_USER_INTERFACE = "prefScreenInterface";
- private static final String PREF_SCREEN_PLAYBACK = "prefScreenPlayback";
- private static final String PREF_SCREEN_NETWORK = "prefScreenNetwork";
- private static final String PREF_SCREEN_INTEGRATIONS = "prefScreenIntegrations";
- private static final String PREF_SCREEN_STORAGE = "prefScreenStorage";
- private static final String PREF_SCREEN_AUTODL = "prefAutoDownloadSettings";
- private static final String PREF_SCREEN_FLATTR = "prefFlattrSettings";
- private static final String PREF_SCREEN_GPODDER = "prefGpodderSettings";
-
- private static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate";
- private static final String PREF_FLATTR_REVOKE = "prefRevokeAccess";
- private static final String PREF_AUTO_FLATTR_PREFS = "prefAutoFlattrPrefs";
- private static final String PREF_OPML_EXPORT = "prefOpmlExport";
- private static final String PREF_OPML_IMPORT = "prefOpmlImport";
- private static final String PREF_HTML_EXPORT = "prefHtmlExport";
- private static final String STATISTICS = "statistics";
- private static final String IMPORT_EXPORT = "importExport";
- private static final String PREF_ABOUT = "prefAbout";
- private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
- private static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher";
- private static final String PREF_PLAYBACK_REWIND_DELTA_LAUNCHER = "prefPlaybackRewindDeltaLauncher";
- private static final String PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER = "prefPlaybackFastForwardDeltaLauncher";
- private static final String PREF_GPODNET_LOGIN = "pref_gpodnet_authenticate";
- private static final String PREF_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information";
- private static final String PREF_GPODNET_SYNC = "pref_gpodnet_sync";
- private static final String PREF_GPODNET_FORCE_FULL_SYNC = "pref_gpodnet_force_full_sync";
- private static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout";
- private static final String PREF_GPODNET_HOSTNAME = "pref_gpodnet_hostname";
- private static final String PREF_GPODNET_NOTIFICATIONS = "pref_gpodnet_notifications";
- private static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify";
- private static final String PREF_PROXY = "prefProxy";
- private static final String PREF_KNOWN_ISSUES = "prefKnownIssues";
- private static final String PREF_FAQ = "prefFaq";
- private static final String PREF_SEND_CRASH_REPORT = "prefSendCrashReport";
- private static final String[] EXTERNAL_STORAGE_PERMISSIONS = {
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE };
- private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 41;
- private final PreferenceUI ui;
- private final SharedPreferences.OnSharedPreferenceChangeListener gpoddernetListener =
- (sharedPreferences, key) -> {
- if (GpodnetPreferences.PREF_LAST_SYNC_ATTEMPT_TIMESTAMP.equals(key)) {
- updateLastGpodnetSyncReport(GpodnetPreferences.getLastSyncAttemptResult(),
- GpodnetPreferences.getLastSyncAttemptTimestamp());
- }
- };
- private CheckBoxPreference[] selectedNetworks;
- private Disposable disposable;
-
- public PreferenceController(PreferenceUI ui) {
- this.ui = ui;
- PreferenceManager.getDefaultSharedPreferences(ui.getActivity().getApplicationContext())
- .registerOnSharedPreferenceChangeListener(this);
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
-
- }
-
-
-
- public void onCreate(int screen) {
- switch (screen) {
- case R.xml.preferences:
- setupMainScreen();
- break;
- case R.xml.preferences_network:
- setupNetworkScreen();
- break;
- case R.xml.preferences_autodownload:
- setupAutoDownloadScreen();
- buildAutodownloadSelectedNetworksPreference();
- setSelectedNetworksEnabled(UserPreferences.isEnableAutodownloadWifiFilter());
- buildEpisodeCleanupPreference();
- break;
- case R.xml.preferences_playback:
- setupPlaybackScreen();
- PreferenceControllerFlavorHelper.setupFlavoredUI(ui);
- buildSmartMarkAsPlayedPreference();
- break;
- case R.xml.preferences_integrations:
- setupIntegrationsScreen();
- break;
- case R.xml.preferences_flattr:
- setupFlattrScreen();
- break;
- case R.xml.preferences_gpodder:
- setupGpodderScreen();
- break;
- case R.xml.preferences_storage:
- setupStorageScreen();
- break;
- case R.xml.preferences_user_interface:
- setupInterfaceScreen();
- break;
- }
- }
-
- private void setupInterfaceScreen() {
- final Activity activity = ui.getActivity();
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
- // disable expanded notification option on unsupported android versions
- ui.findPreference(PreferenceController.PREF_EXPANDED_NOTIFICATION).setEnabled(false);
- ui.findPreference(PreferenceController.PREF_EXPANDED_NOTIFICATION).setOnPreferenceClickListener(
- preference -> {
- Toast toast = Toast.makeText(activity,
- R.string.pref_expand_notify_unsupport_toast, Toast.LENGTH_SHORT);
- toast.show();
- return true;
- }
- );
- }
- ui.findPreference(UserPreferences.PREF_THEME)
- .setOnPreferenceChangeListener(
- (preference, newValue) -> {
- Intent i = new Intent(activity, MainActivity.class);
- i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_ACTIVITY_NEW_TASK);
- activity.finish();
- activity.startActivity(i);
- return true;
- }
- );
- ui.findPreference(UserPreferences.PREF_HIDDEN_DRAWER_ITEMS)
- .setOnPreferenceClickListener(preference -> {
- showDrawerPreferencesDialog();
- return true;
- });
-
- ui.findPreference(UserPreferences.PREF_COMPACT_NOTIFICATION_BUTTONS)
- .setOnPreferenceClickListener(preference -> {
- showNotificationButtonsDialog();
- return true;
- });
-
- ui.findPreference(UserPreferences.PREF_BACK_BUTTON_BEHAVIOR)
- .setOnPreferenceChangeListener((preference, newValue) -> {
- if (newValue.equals("page")) {
- final Context context = ui.getActivity();
- final String[] navTitles = context.getResources().getStringArray(R.array.back_button_go_to_pages);
- final String[] navTags = context.getResources().getStringArray(R.array.back_button_go_to_pages_tags);
- final String choice[] = { UserPreferences.getBackButtonGoToPage() };
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.back_button_go_to_page_title);
- builder.setSingleChoiceItems(navTitles, ArrayUtils.indexOf(navTags, UserPreferences.getBackButtonGoToPage()), (dialogInterface, i) -> {
- if (i >= 0) {
- choice[0] = navTags[i];
- }
- });
- builder.setPositiveButton(R.string.confirm_label, (dialogInterface, i) -> UserPreferences.setBackButtonGoToPage(choice[0]));
- builder.setNegativeButton(R.string.cancel_label, null);
- builder.create().show();
- return true;
- } else {
- return true;
- }
- });
-
- if (Build.VERSION.SDK_INT >= 26) {
- ui.findPreference(UserPreferences.PREF_EXPANDED_NOTIFICATION).setVisible(false);
- }
- }
-
- private void setupStorageScreen() {
- final Activity activity = ui.getActivity();
-
- ui.findPreference(PreferenceController.IMPORT_EXPORT).setOnPreferenceClickListener(
- preference -> {
- activity.startActivity(new Intent(activity, ImportExportActivity.class));
- return true;
- }
- );
- ui.findPreference(PreferenceController.PREF_OPML_EXPORT).setOnPreferenceClickListener(
- preference -> export(new OpmlWriter()));
- ui.findPreference(PreferenceController.PREF_HTML_EXPORT).setOnPreferenceClickListener(
- preference -> export(new HtmlWriter()));
- ui.findPreference(PreferenceController.PREF_OPML_IMPORT).setOnPreferenceClickListener(
- preference -> {
- activity.startActivity(new Intent(activity, OpmlImportFromPathActivity.class));
- return true;
- });
- ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
- preference -> {
- if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
- Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
- showChooseDataFolderDialog();
- } else {
- int readPermission = ActivityCompat.checkSelfPermission(
- activity, Manifest.permission.READ_EXTERNAL_STORAGE);
- int writePermission = ActivityCompat.checkSelfPermission(
- activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
- if (readPermission == PackageManager.PERMISSION_GRANTED &&
- writePermission == PackageManager.PERMISSION_GRANTED) {
- openDirectoryChooser();
- } else {
- requestPermission();
- }
- }
- return true;
- }
- );
- ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR)
- .setOnPreferenceClickListener(
- preference -> {
- if (Build.VERSION.SDK_INT >= 19) {
- showChooseDataFolderDialog();
- } else {
- Intent intent = new Intent(activity, DirectoryChooserActivity.class);
- activity.startActivityForResult(intent,
- DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
- }
- return true;
- }
- );
- ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE).setOnPreferenceChangeListener(
- (preference, o) -> {
- if (o instanceof String) {
- int newValue = Integer.parseInt((String) o) * 1024 * 1024;
- if (newValue != UserPreferences.getImageCacheSize()) {
- AlertDialog.Builder dialog = new AlertDialog.Builder(ui.getActivity());
- dialog.setTitle(android.R.string.dialog_alert_title);
- dialog.setMessage(R.string.pref_restart_required);
- dialog.setPositiveButton(android.R.string.ok, null);
- dialog.show();
- }
- return true;
- }
- return false;
- }
- );
- }
-
- private void setupIntegrationsScreen() {
- final AppCompatActivity activity = ui.getActivity();
-
- ui.findPreference(PREF_SCREEN_FLATTR).setOnPreferenceClickListener(preference -> {
- openScreen(R.xml.preferences_flattr, activity);
- return true;
- });
- ui.findPreference(PREF_SCREEN_GPODDER).setOnPreferenceClickListener(preference -> {
- openScreen(R.xml.preferences_gpodder, activity);
- return true;
- });
- }
-
- private void setupFlattrScreen() {
- final AppCompatActivity activity = ui.getActivity();
-
- ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setOnPreferenceClickListener(
- preference -> {
- FlattrUtils.revokeAccessToken(activity);
- checkFlattrItemVisibility();
- return true;
- }
- );
-
- ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS)
- .setOnPreferenceClickListener(preference -> {
- AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity,
- new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() {
- @Override
- public void onCancelled() {
-
- }
-
- @Override
- public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) {
- UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue);
- checkFlattrItemVisibility();
- }
- });
- return true;
- });
- }
-
- private void setupGpodderScreen() {
- final AppCompatActivity activity = ui.getActivity();
-
- ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION)
- .setOnPreferenceClickListener(preference -> {
- AuthenticationDialog dialog = new AuthenticationDialog(activity,
- R.string.pref_gpodnet_setlogin_information_title, false, false, GpodnetPreferences.getUsername(),
- null) {
-
- @Override
- protected void onConfirmed(String username, String password, boolean saveUsernamePassword) {
- GpodnetPreferences.setPassword(password);
- }
- };
- dialog.show();
- return true;
- });
- ui.findPreference(PreferenceController.PREF_GPODNET_SYNC).
- setOnPreferenceClickListener(preference -> {
- GpodnetSyncService.sendSyncIntent(ui.getActivity().getApplicationContext());
- Toast toast = Toast.makeText(ui.getActivity(), R.string.pref_gpodnet_sync_started,
- Toast.LENGTH_SHORT);
- toast.show();
- return true;
- });
- ui.findPreference(PreferenceController.PREF_GPODNET_FORCE_FULL_SYNC).
- setOnPreferenceClickListener(preference -> {
- GpodnetPreferences.setLastSubscriptionSyncTimestamp(0L);
- GpodnetPreferences.setLastEpisodeActionsSyncTimestamp(0L);
- GpodnetPreferences.setLastSyncAttempt(false, 0);
- updateLastGpodnetSyncReport(false, 0);
- GpodnetSyncService.sendSyncIntent(ui.getActivity().getApplicationContext());
- Toast toast = Toast.makeText(ui.getActivity(), R.string.pref_gpodnet_sync_started,
- Toast.LENGTH_SHORT);
- toast.show();
- return true;
- });
- ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(
- preference -> {
- GpodnetPreferences.logout();
- Toast toast = Toast.makeText(activity, R.string.pref_gpodnet_logout_toast, Toast.LENGTH_SHORT);
- toast.show();
- updateGpodnetPreferenceScreen();
- return true;
- });
- ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setOnPreferenceClickListener(
- preference -> {
- GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(dialog -> updateGpodnetPreferenceScreen());
- return true;
- });
- }
-
- private void setupPlaybackScreen() {
- final Activity activity = ui.getActivity();
-
- ui.findPreference(PreferenceController.PREF_PLAYBACK_SPEED_LAUNCHER)
- .setOnPreferenceClickListener(preference -> {
- VariableSpeedDialog.showDialog(activity);
- return true;
- });
- ui.findPreference(PreferenceController.PREF_PLAYBACK_REWIND_DELTA_LAUNCHER)
- .setOnPreferenceClickListener(preference -> {
- MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_REWIND);
- return true;
- });
- ui.findPreference(PreferenceController.PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER)
- .setOnPreferenceClickListener(preference -> {
- MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_FORWARD);
- return true;
- });
- if (!PictureInPictureUtil.supportsPictureInPicture(activity)) {
- ListPreference behaviour = (ListPreference) ui.findPreference(UserPreferences.PREF_VIDEO_BEHAVIOR);
- behaviour.setEntries(R.array.video_background_behavior_options_without_pip);
- behaviour.setEntryValues(R.array.video_background_behavior_values_without_pip);
- }
- }
-
- private void setupAutoDownloadScreen() {
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL).setOnPreferenceChangeListener(
- (preference, newValue) -> {
- if (newValue instanceof Boolean) {
- checkAutodownloadItemVisibility((Boolean) newValue);
- }
- return true;
- });
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
- .setOnPreferenceChangeListener(
- (preference, newValue) -> {
- if (newValue instanceof Boolean) {
- setSelectedNetworksEnabled((Boolean) newValue);
- return true;
- } else {
- return false;
- }
- }
- );
- ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE)
- .setOnPreferenceChangeListener(
- (preference, o) -> {
- if (o instanceof String) {
- setEpisodeCacheSizeText(UserPreferences.readEpisodeCacheSize((String) o));
- }
- return true;
- }
- );
- }
-
- private void setupNetworkScreen() {
- final AppCompatActivity activity = ui.getActivity();
- ui.findPreference(PREF_SCREEN_AUTODL).setOnPreferenceClickListener(preference -> {
- openScreen(R.xml.preferences_autodownload, activity);
- return true;
- });
- ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL)
- .setOnPreferenceClickListener(preference -> {
- showUpdateIntervalTimePreferencesDialog();
- return true;
- });
- ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)
- .setOnPreferenceChangeListener(
- (preference, o) -> {
- if (o instanceof Integer) {
- setParallelDownloadsText((Integer) o);
- }
- return true;
- }
- );
- // validate and set correct value: number of downloads between 1 and 50 (inclusive)
- ui.findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> {
- ProxyDialog dialog = new ProxyDialog(ui.getActivity());
- dialog.createDialog().show();
- return true;
- });
- }
-
- private void setupMainScreen() {
- final AppCompatActivity activity = ui.getActivity();
- setupSearch();
- ui.findPreference(PREF_SCREEN_USER_INTERFACE).setOnPreferenceClickListener(preference -> {
- openScreen(R.xml.preferences_user_interface, activity);
- return true;
- });
- ui.findPreference(PREF_SCREEN_PLAYBACK).setOnPreferenceClickListener(preference -> {
- openScreen(R.xml.preferences_playback, activity);
- return true;
- });
- ui.findPreference(PREF_SCREEN_NETWORK).setOnPreferenceClickListener(preference -> {
- openScreen(R.xml.preferences_network, activity);
- return true;
- });
- ui.findPreference(PREF_SCREEN_INTEGRATIONS).setOnPreferenceClickListener(preference -> {
- openScreen(R.xml.preferences_integrations, activity);
- return true;
- });
- ui.findPreference(PREF_SCREEN_STORAGE).setOnPreferenceClickListener(preference -> {
- openScreen(R.xml.preferences_storage, activity);
- return true;
- });
-
- ui.findPreference(PreferenceController.PREF_ABOUT).setOnPreferenceClickListener(
- preference -> {
- activity.startActivity(new Intent(activity, AboutActivity.class));
- return true;
- }
- );
- ui.findPreference(PreferenceController.STATISTICS).setOnPreferenceClickListener(
- preference -> {
- activity.startActivity(new Intent(activity, StatisticsActivity.class));
- return true;
- }
- );
- ui.findPreference(PREF_KNOWN_ISSUES).setOnPreferenceClickListener(preference -> {
- openInBrowser("https://github.com/AntennaPod/AntennaPod/labels/bug");
- return true;
- });
- ui.findPreference(PREF_FAQ).setOnPreferenceClickListener(preference -> {
- openInBrowser("http://antennapod.org/faq.html");
- return true;
- });
- ui.findPreference(PREF_SEND_CRASH_REPORT).setOnPreferenceClickListener(preference -> {
- Context context = ui.getActivity().getApplicationContext();
- Intent emailIntent = new Intent(Intent.ACTION_SEND);
- emailIntent.setType("text/plain");
- emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"Martin.Fietz@gmail.com"});
- emailIntent.putExtra(Intent.EXTRA_SUBJECT, "AntennaPod Crash Report");
- emailIntent.putExtra(Intent.EXTRA_TEXT, "Please describe what you were doing when the app crashed");
- // the attachment
- Uri fileUri = FileProvider.getUriForFile(context, context.getString(R.string.provider_authority),
- CrashReportWriter.getFile());
- emailIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
- emailIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- String intentTitle = ui.getActivity().getString(R.string.send_email);
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
- List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(emailIntent, PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo resolveInfo : resInfoList) {
- String packageName = resolveInfo.activityInfo.packageName;
- context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- }
- ui.getActivity().startActivity(Intent.createChooser(emailIntent, intentTitle));
- return true;
- });
- }
-
- private void setupSearch() {
- final AppCompatActivity activity = ui.getActivity();
-
- SearchPreference searchPreference = (SearchPreference) ui.findPreference("searchPreference");
- SearchConfiguration config = searchPreference.getSearchConfiguration();
- config.setActivity(activity);
- config.setFragmentContainerViewId(R.id.content);
- config.setBreadcrumbsEnabled(true);
-
- config.index()
- .addBreadcrumb(getTitleOfPage(R.xml.preferences_user_interface))
- .addFile(R.xml.preferences_user_interface);
- config.index()
- .addBreadcrumb(getTitleOfPage(R.xml.preferences_playback))
- .addFile(R.xml.preferences_playback);
- config.index()
- .addBreadcrumb(getTitleOfPage(R.xml.preferences_network))
- .addFile(R.xml.preferences_network);
- config.index()
- .addBreadcrumb(getTitleOfPage(R.xml.preferences_storage))
- .addFile(R.xml.preferences_storage);
- config.index()
- .addBreadcrumb(getTitleOfPage(R.xml.preferences_network))
- .addBreadcrumb(R.string.automation)
- .addBreadcrumb(getTitleOfPage(R.xml.preferences_autodownload))
- .addFile(R.xml.preferences_autodownload);
- config.index()
- .addBreadcrumb(getTitleOfPage(R.xml.preferences_integrations))
- .addBreadcrumb(getTitleOfPage(R.xml.preferences_gpodder))
- .addFile(R.xml.preferences_gpodder);
- config.index()
- .addBreadcrumb(getTitleOfPage(R.xml.preferences_integrations))
- .addBreadcrumb(getTitleOfPage(R.xml.preferences_flattr))
- .addFile(R.xml.preferences_flattr);
- }
-
- public PreferenceFragmentCompat openScreen(int preferences, AppCompatActivity activity) {
- PreferenceFragmentCompat prefFragment = new PreferenceActivity.MainFragment();
- Bundle args = new Bundle();
- args.putInt(PARAM_RESOURCE, preferences);
- prefFragment.setArguments(args);
- activity.getSupportFragmentManager().beginTransaction()
- .replace(R.id.content, prefFragment)
- .addToBackStack(TAG).commit();
- return prefFragment;
- }
-
- public static int getTitleOfPage(int preferences) {
- switch (preferences) {
- case R.xml.preferences_network:
- return R.string.network_pref;
- case R.xml.preferences_autodownload:
- return R.string.pref_automatic_download_title;
- case R.xml.preferences_playback:
- return R.string.playback_pref;
- case R.xml.preferences_storage:
- return R.string.storage_pref;
- case R.xml.preferences_user_interface:
- return R.string.user_interface_label;
- case R.xml.preferences_integrations:
- return R.string.integrations_label;
- case R.xml.preferences_flattr:
- return R.string.flattr_label;
- case R.xml.preferences_gpodder:
- return R.string.gpodnet_main_label;
- default:
- return R.string.settings_label;
- }
- }
-
- private boolean export(ExportWriter exportWriter) {
- Context context = ui.getActivity();
- final ProgressDialog progressDialog = new ProgressDialog(context);
- progressDialog.setMessage(context.getString(R.string.exporting_label));
- progressDialog.setIndeterminate(true);
- progressDialog.show();
- final AlertDialog.Builder alert = new AlertDialog.Builder(context)
- .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
- Observable<File> observable = new ExportWorker(exportWriter).exportObservable();
- disposable = observable.subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(output -> {
- alert.setTitle(R.string.export_success_title);
- String message = context.getString(R.string.export_success_sum, output.toString());
- alert.setMessage(message);
- alert.setPositiveButton(R.string.send_label, (dialog, which) -> {
- Uri fileUri = FileProvider.getUriForFile(context.getApplicationContext(),
- "de.danoeh.antennapod.provider", output);
- Intent sendIntent = new Intent(Intent.ACTION_SEND);
- sendIntent.putExtra(Intent.EXTRA_SUBJECT,
- context.getResources().getText(R.string.opml_export_label));
- sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
- sendIntent.setType("text/plain");
- sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
- List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(sendIntent, PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo resolveInfo : resInfoList) {
- String packageName = resolveInfo.activityInfo.packageName;
- context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- }
- context.startActivity(Intent.createChooser(sendIntent,
- context.getResources().getText(R.string.send_label)));
- });
- alert.create().show();
- }, error -> {
- alert.setTitle(R.string.export_error_label);
- alert.setMessage(error.getMessage());
- alert.show();
- }, progressDialog::dismiss);
- return true;
- }
-
- private void openInBrowser(String url) {
- try {
- Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- ui.getActivity().startActivity(myIntent);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(ui.getActivity(), R.string.pref_no_browser_found, Toast.LENGTH_LONG).show();
- Log.e(TAG, Log.getStackTraceString(e));
- }
- }
-
- public void onResume(int screen) {
- switch (screen) {
- case R.xml.preferences_network:
- setUpdateIntervalText();
- setParallelDownloadsText(UserPreferences.getParallelDownloads());
- break;
- case R.xml.preferences_autodownload:
- setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize());
- checkAutodownloadItemVisibility(UserPreferences.isEnableAutodownload());
- break;
- case R.xml.preferences_storage:
- setDataFolderText();
- break;
- case R.xml.preferences_integrations:
- setIntegrationsItemVisibility();
- return;
- case R.xml.preferences_flattr:
- checkFlattrItemVisibility();
- break;
- case R.xml.preferences_gpodder:
- GpodnetPreferences.registerOnSharedPreferenceChangeListener(gpoddernetListener);
- updateGpodnetPreferenceScreen();
- break;
- case R.xml.preferences_playback:
- checkSonicItemVisibility();
- break;
- }
- }
-
- public void unregisterGpodnet() {
- GpodnetPreferences.unregisterOnSharedPreferenceChangeListener(gpoddernetListener);
- }
-
- public void unsubscribeExportSubscription() {
- if (disposable != null) {
- disposable.dispose();
- }
- }
-
- @SuppressLint("NewApi")
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (resultCode == Activity.RESULT_OK &&
- requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
- String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
-
- File path;
- if(dir != null) {
- path = new File(dir);
- } else {
- path = ui.getActivity().getExternalFilesDir(null);
- }
- String message = null;
- final Context context= ui.getActivity().getApplicationContext();
- if(!path.exists()) {
- message = String.format(context.getString(R.string.folder_does_not_exist_error), dir);
- } else if(!path.canRead()) {
- message = String.format(context.getString(R.string.folder_not_readable_error), dir);
- } else if(!path.canWrite()) {
- message = String.format(context.getString(R.string.folder_not_writable_error), dir);
- }
-
- if(message == null) {
- Log.d(TAG, "Setting data folder: " + dir);
- UserPreferences.setDataFolder(dir);
- setDataFolderText();
- } else {
- AlertDialog.Builder ab = new AlertDialog.Builder(ui.getActivity());
- ab.setMessage(message);
- ab.setPositiveButton(android.R.string.ok, null);
- ab.show();
- }
- }
- }
-
-
- private void updateGpodnetPreferenceScreen() {
- final boolean loggedIn = GpodnetPreferences.loggedIn();
- ui.findPreference(PreferenceController.PREF_GPODNET_LOGIN).setEnabled(!loggedIn);
- ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION).setEnabled(loggedIn);
- ui.findPreference(PreferenceController.PREF_GPODNET_SYNC).setEnabled(loggedIn);
- ui.findPreference(PreferenceController.PREF_GPODNET_FORCE_FULL_SYNC).setEnabled(loggedIn);
- ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setEnabled(loggedIn);
- ui.findPreference(PREF_GPODNET_NOTIFICATIONS).setEnabled(loggedIn);
- if(loggedIn) {
- String format = ui.getActivity().getString(R.string.pref_gpodnet_login_status);
- String summary = String.format(format, GpodnetPreferences.getUsername(),
- GpodnetPreferences.getDeviceID());
- ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setSummary(Html.fromHtml(summary));
- updateLastGpodnetSyncReport(GpodnetPreferences.getLastSyncAttemptResult(),
- GpodnetPreferences.getLastSyncAttemptTimestamp());
- } else {
- ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setSummary(null);
- updateLastGpodnetSyncReport(false, 0);
- }
- ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setSummary(GpodnetPreferences.getHostname());
- }
-
- private void updateLastGpodnetSyncReport(boolean successful, long lastTime) {
- Preference sync = ui.findPreference(PREF_GPODNET_SYNC);
- if (lastTime != 0) {
- sync.setSummary(ui.getActivity().getString(R.string.pref_gpodnet_sync_changes_sum) + "\n" +
- ui.getActivity().getString(R.string.pref_gpodnet_sync_sum_last_sync_line,
- ui.getActivity().getString(successful ?
- R.string.gpodnetsync_pref_report_successful :
- R.string.gpodnetsync_pref_report_failed),
- DateUtils.getRelativeDateTimeString(ui.getActivity(),
- lastTime,
- DateUtils.MINUTE_IN_MILLIS,
- DateUtils.WEEK_IN_MILLIS,
- DateUtils.FORMAT_SHOW_TIME)));
- } else {
- sync.setSummary(ui.getActivity().getString(R.string.pref_gpodnet_sync_changes_sum));
- }
- }
-
- private String[] getUpdateIntervalEntries(final String[] values) {
- final Resources res = ui.getActivity().getResources();
- String[] entries = new String[values.length];
- for (int x = 0; x < values.length; x++) {
- Integer v = Integer.parseInt(values[x]);
- switch (v) {
- case 0:
- entries[x] = res.getString(R.string.pref_update_interval_hours_manual);
- break;
- case 1:
- entries[x] = v + " " + res.getString(R.string.pref_update_interval_hours_singular);
- break;
- default:
- entries[x] = v + " " + res.getString(R.string.pref_update_interval_hours_plural);
- break;
-
- }
- }
- return entries;
- }
-
- private void buildEpisodeCleanupPreference() {
- final Resources res = ui.getActivity().getResources();
-
- ListPreference pref = (ListPreference) ui.findPreference(UserPreferences.PREF_EPISODE_CLEANUP);
- String[] values = res.getStringArray(
- R.array.episode_cleanup_values);
- String[] entries = new String[values.length];
- for (int x = 0; x < values.length; x++) {
- int v = Integer.parseInt(values[x]);
- if (v == UserPreferences.EPISODE_CLEANUP_QUEUE) {
- entries[x] = res.getString(R.string.episode_cleanup_queue_removal);
- } else if (v == UserPreferences.EPISODE_CLEANUP_NULL){
- entries[x] = res.getString(R.string.episode_cleanup_never);
- } else if (v == 0) {
- entries[x] = res.getString(R.string.episode_cleanup_after_listening);
- } else {
- entries[x] = res.getQuantityString(R.plurals.episode_cleanup_days_after_listening, v, v);
- }
- }
- pref.setEntries(entries);
- }
-
- private void buildSmartMarkAsPlayedPreference() {
- final Resources res = ui.getActivity().getResources();
-
- ListPreference pref = (ListPreference) ui.findPreference(UserPreferences.PREF_SMART_MARK_AS_PLAYED_SECS);
- String[] values = res.getStringArray(R.array.smart_mark_as_played_values);
- String[] entries = new String[values.length];
- for (int x = 0; x < values.length; x++) {
- if(x == 0) {
- entries[x] = res.getString(R.string.pref_smart_mark_as_played_disabled);
- } else {
- Integer v = Integer.parseInt(values[x]);
- if(v < 60) {
- entries[x] = res.getQuantityString(R.plurals.time_seconds_quantified, v, v);
- } else {
- v /= 60;
- entries[x] = res.getQuantityString(R.plurals.time_minutes_quantified, v, v);
- }
- }
- }
- pref.setEntries(entries);
- }
-
- private void setSelectedNetworksEnabled(boolean b) {
- if (selectedNetworks != null) {
- for (Preference p : selectedNetworks) {
- p.setEnabled(b);
- }
- }
- }
-
- private void setIntegrationsItemVisibility() {
- ui.findPreference(PreferenceController.PREF_SCREEN_FLATTR).setEnabled(FlattrUtils.hasAPICredentials());
- }
-
- @SuppressWarnings("deprecation")
- private void checkFlattrItemVisibility() {
- boolean hasFlattrToken = FlattrUtils.hasToken();
- ui.findPreference(PreferenceController.PREF_FLATTR_AUTH).setEnabled(!hasFlattrToken);
- ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setEnabled(hasFlattrToken);
- ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS).setEnabled(hasFlattrToken);
- }
-
- private void checkAutodownloadItemVisibility(boolean autoDownload) {
- ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setEnabled(autoDownload);
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY).setEnabled(autoDownload);
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled(autoDownload);
- ui.findPreference(UserPreferences.PREF_EPISODE_CLEANUP).setEnabled(autoDownload);
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_MOBILE).setEnabled(autoDownload);
- setSelectedNetworksEnabled(autoDownload && UserPreferences.isEnableAutodownloadWifiFilter());
- }
-
- private void checkSonicItemVisibility() {
- if (Build.VERSION.SDK_INT < 16) {
- ListPreference p = (ListPreference) ui.findPreference(UserPreferences.PREF_MEDIA_PLAYER);
- p.setEntries(R.array.media_player_options_no_sonic);
- p.setEntryValues(R.array.media_player_values_no_sonic);
- }
- }
-
- private void setUpdateIntervalText() {
- Context context = ui.getActivity().getApplicationContext();
- String val;
- long interval = UserPreferences.getUpdateInterval();
- if(interval > 0) {
- int hours = (int) TimeUnit.MILLISECONDS.toHours(interval);
- String hoursStr = context.getResources().getQuantityString(R.plurals.time_hours_quantified, hours, hours);
- val = String.format(context.getString(R.string.pref_autoUpdateIntervallOrTime_every), hoursStr);
- } else {
- int[] timeOfDay = UserPreferences.getUpdateTimeOfDay();
- if(timeOfDay.length == 2) {
- Calendar cal = new GregorianCalendar();
- cal.set(Calendar.HOUR_OF_DAY, timeOfDay[0]);
- cal.set(Calendar.MINUTE, timeOfDay[1]);
- String timeOfDayStr = DateFormat.getTimeFormat(context).format(cal.getTime());
- val = String.format(context.getString(R.string.pref_autoUpdateIntervallOrTime_at),
- timeOfDayStr);
- } else {
- val = context.getString(R.string.pref_smart_mark_as_played_disabled); // TODO: Is this a bug? Otherwise document why is this related to smart mark???
- }
- }
- String summary = context.getString(R.string.pref_autoUpdateIntervallOrTime_sum) + "\n"
- + String.format(context.getString(R.string.pref_current_value), val);
- ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL).setSummary(summary);
- }
-
- private void setParallelDownloadsText(int downloads) {
- final Resources res = ui.getActivity().getResources();
-
- String s = Integer.toString(downloads)
- + res.getString(R.string.parallel_downloads_suffix);
- ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS).setSummary(s);
- }
-
- private void setEpisodeCacheSizeText(int cacheSize) {
- final Resources res = ui.getActivity().getResources();
-
- String s;
- if (cacheSize == res.getInteger(
- R.integer.episode_cache_size_unlimited)) {
- s = res.getString(R.string.pref_episode_cache_unlimited);
- } else {
- s = Integer.toString(cacheSize)
- + res.getString(R.string.episodes_suffix);
- }
- ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setSummary(s);
- }
-
- private void setDataFolderText() {
- File f = UserPreferences.getDataFolder(null);
- if (f != null) {
- ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR)
- .setSummary(f.getAbsolutePath());
- }
- }
-
- private static String blankIfNull(String val) {
- return val == null ? "" : val;
- }
-
- private void buildAutodownloadSelectedNetworksPreference() {
- final Activity activity = ui.getActivity();
-
- if (selectedNetworks != null) {
- clearAutodownloadSelectedNetworsPreference();
- }
- // get configured networks
- WifiManager wifiservice = (WifiManager) activity.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
- List<WifiConfiguration> networks = wifiservice.getConfiguredNetworks();
-
- if (networks == null) {
- Log.e(TAG, "Couldn't get list of configure Wi-Fi networks");
- return;
- }
- Collections.sort(networks, (x, y) ->
- blankIfNull(x.SSID).compareTo(blankIfNull(y.SSID)));
- selectedNetworks = new CheckBoxPreference[networks.size()];
- List<String> prefValues = Arrays.asList(UserPreferences
- .getAutodownloadSelectedNetworks());
- PreferenceScreen prefScreen = ui.getPreferenceScreen();
- Preference.OnPreferenceClickListener clickListener = preference -> {
- if (preference instanceof CheckBoxPreference) {
- String key = preference.getKey();
- List<String> prefValuesList = new ArrayList<>(
- Arrays.asList(UserPreferences
- .getAutodownloadSelectedNetworks())
- );
- boolean newValue = ((CheckBoxPreference) preference)
- .isChecked();
- Log.d(TAG, "Selected network " + key + ". New state: " + newValue);
-
- int index = prefValuesList.indexOf(key);
- if (index >= 0 && !newValue) {
- // remove network
- prefValuesList.remove(index);
- } else if (index < 0 && newValue) {
- prefValuesList.add(key);
- }
-
- UserPreferences.setAutodownloadSelectedNetworks(
- prefValuesList.toArray(new String[prefValuesList.size()])
- );
- return true;
- } else {
- return false;
- }
- };
- // create preference for each known network. attach listener and set
- // value
- for (int i = 0; i < networks.size(); i++) {
- WifiConfiguration config = networks.get(i);
-
- CheckBoxPreference pref = new CheckBoxPreference(activity);
- String key = Integer.toString(config.networkId);
- pref.setTitle(config.SSID);
- pref.setKey(key);
- pref.setOnPreferenceClickListener(clickListener);
- pref.setPersistent(false);
- pref.setChecked(prefValues.contains(key));
- selectedNetworks[i] = pref;
- prefScreen.addPreference(pref);
- }
- }
-
- private void clearAutodownloadSelectedNetworsPreference() {
- if (selectedNetworks != null) {
- PreferenceScreen prefScreen = ui.getPreferenceScreen();
-
- for (CheckBoxPreference network : selectedNetworks) {
- if (network != null) {
- prefScreen.removePreference(network);
- }
- }
- }
- }
-
- private void showDrawerPreferencesDialog() {
- final Context context = ui.getActivity();
- final List<String> hiddenDrawerItems = UserPreferences.getHiddenDrawerItems();
- final String[] navTitles = context.getResources().getStringArray(R.array.nav_drawer_titles);
- final String[] NAV_DRAWER_TAGS = MainActivity.NAV_DRAWER_TAGS;
- boolean[] checked = new boolean[MainActivity.NAV_DRAWER_TAGS.length];
- for(int i=0; i < NAV_DRAWER_TAGS.length; i++) {
- String tag = NAV_DRAWER_TAGS[i];
- if(!hiddenDrawerItems.contains(tag)) {
- checked[i] = true;
- }
- }
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.drawer_preferences);
- builder.setMultiChoiceItems(navTitles, checked, (dialog, which, isChecked) -> {
- if (isChecked) {
- hiddenDrawerItems.remove(NAV_DRAWER_TAGS[which]);
- } else {
- hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]);
- }
- });
- builder.setPositiveButton(R.string.confirm_label, (dialog, which) ->
- UserPreferences.setHiddenDrawerItems(hiddenDrawerItems));
- builder.setNegativeButton(R.string.cancel_label, null);
- builder.create().show();
- }
-
- private void showNotificationButtonsDialog() {
- final Context context = ui.getActivity();
- final List<Integer> preferredButtons = UserPreferences.getCompactNotificationButtons();
- final String[] allButtonNames = context.getResources().getStringArray(
- R.array.compact_notification_buttons_options);
- boolean[] checked = new boolean[allButtonNames.length]; // booleans default to false in java
-
- for(int i=0; i < checked.length; i++) {
- if(preferredButtons.contains(i)) {
- checked[i] = true;
- }
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(String.format(context.getResources().getString(
- R.string.pref_compact_notification_buttons_dialog_title), 2));
- builder.setMultiChoiceItems(allButtonNames, checked, (dialog, which, isChecked) -> {
- checked[which] = isChecked;
-
- if (isChecked) {
- if (preferredButtons.size() < 2) {
- preferredButtons.add(which);
- } else {
- // Only allow a maximum of two selections. This is because the notification
- // on the lock screen can only display 3 buttons, and the play/pause button
- // is always included.
- checked[which] = false;
- ListView selectionView = ((AlertDialog) dialog).getListView();
- selectionView.setItemChecked(which, false);
- Snackbar.make(
- selectionView,
- String.format(context.getResources().getString(
- R.string.pref_compact_notification_buttons_dialog_error), 2),
- Snackbar.LENGTH_SHORT).show();
- }
- } else {
- preferredButtons.remove((Integer) which);
- }
- });
- builder.setPositiveButton(R.string.confirm_label, (dialog, which) ->
- UserPreferences.setCompactNotificationButtons(preferredButtons));
- builder.setNegativeButton(R.string.cancel_label, null);
- builder.create().show();
- }
-
- // CHOOSE DATA FOLDER
-
- private void requestPermission() {
- ActivityCompat.requestPermissions(ui.getActivity(), EXTERNAL_STORAGE_PERMISSIONS,
- PERMISSION_REQUEST_EXTERNAL_STORAGE);
- }
-
- private void openDirectoryChooser() {
- Activity activity = ui.getActivity();
- Intent intent = new Intent(activity, DirectoryChooserActivity.class);
- activity.startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
- }
-
- private void showChooseDataFolderDialog() {
- ChooseDataFolderDialog.showDialog(
- ui.getActivity(), new ChooseDataFolderDialog.RunnableWithString() {
- @Override
- public void run(final String folder) {
- UserPreferences.setDataFolder(folder);
- setDataFolderText();
- }
- });
- }
-
- // UPDATE TIME/INTERVAL DIALOG
-
- private void showUpdateIntervalTimePreferencesDialog() {
- final Context context = ui.getActivity();
-
- MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
- builder.title(R.string.pref_autoUpdateIntervallOrTime_title);
- builder.content(R.string.pref_autoUpdateIntervallOrTime_message);
- builder.positiveText(R.string.pref_autoUpdateIntervallOrTime_Interval);
- builder.negativeText(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay);
- builder.neutralText(R.string.pref_autoUpdateIntervallOrTime_Disable);
- builder.onPositive((dialog, which) -> {
- AlertDialog.Builder builder1 = new AlertDialog.Builder(context);
- builder1.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
- final String[] values = context.getResources().getStringArray(R.array.update_intervall_values);
- final String[] entries = getUpdateIntervalEntries(values);
- long currInterval = UserPreferences.getUpdateInterval();
- int checkedItem = -1;
- if(currInterval > 0) {
- String currIntervalStr = String.valueOf(TimeUnit.MILLISECONDS.toHours(currInterval));
- checkedItem = ArrayUtils.indexOf(values, currIntervalStr);
- }
- builder1.setSingleChoiceItems(entries, checkedItem, (dialog1, which1) -> {
- int hours = Integer.parseInt(values[which1]);
- UserPreferences.setUpdateInterval(hours);
- dialog1.dismiss();
- setUpdateIntervalText();
- });
- builder1.setNegativeButton(context.getString(R.string.cancel_label), null);
- builder1.show();
- });
- builder.onNegative((dialog, which) -> {
- int hourOfDay = 7, minute = 0;
- int[] updateTime = UserPreferences.getUpdateTimeOfDay();
- if (updateTime.length == 2) {
- hourOfDay = updateTime[0];
- minute = updateTime[1];
- }
- TimePickerDialog timePickerDialog = new TimePickerDialog(context,
- (view, selectedHourOfDay, selectedMinute) -> {
- if (view.getTag() == null) { // onTimeSet() may get called twice!
- view.setTag("TAGGED");
- UserPreferences.setUpdateTimeOfDay(selectedHourOfDay, selectedMinute);
- setUpdateIntervalText();
- }
- }, hourOfDay, minute, DateFormat.is24HourFormat(context));
- timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay));
- timePickerDialog.show();
- });
- builder.onNeutral((dialog, which) -> {
- UserPreferences.setUpdateInterval(0);
- setUpdateIntervalText();
- });
- builder.show();
- }
-
-
- public interface PreferenceUI {
-
- void setFragment(PreferenceFragmentCompat fragment);
- PreferenceFragmentCompat getFragment();
-
- /**
- * Finds a preference based on its key.
- */
- Preference findPreference(CharSequence key);
-
- PreferenceScreen getPreferenceScreen();
-
- AppCompatActivity getActivity();
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
new file mode 100644
index 000000000..e56703598
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
@@ -0,0 +1,69 @@
+package de.danoeh.antennapod.preferences;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.gui.NotificationUtils;
+
+public class PreferenceUpgrader {
+ private static final String PREF_CONFIGURED_VERSION = "configuredVersion";
+ private static final String PREF_NAME = "PreferenceUpgrader";
+
+ private static SharedPreferences prefs;
+
+ public static void checkUpgrades(Context context) {
+ prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences upgraderPrefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
+ int oldVersion = upgraderPrefs.getInt(PREF_CONFIGURED_VERSION, 1070200);
+ int newVersion = BuildConfig.VERSION_CODE;
+
+ if (oldVersion != newVersion) {
+ NotificationUtils.createChannels(context);
+
+ upgraderPrefs.edit().putInt(PREF_CONFIGURED_VERSION, newVersion).apply();
+ upgrade(oldVersion);
+ }
+ }
+
+ private static void upgrade(int oldVersion) {
+ if (oldVersion < 1070196) {
+ // migrate episode cleanup value (unit changed from days to hours)
+ int oldValueInDays = UserPreferences.getEpisodeCleanupValue();
+ if (oldValueInDays > 0) {
+ UserPreferences.setEpisodeCleanupValue(oldValueInDays * 24);
+ } // else 0 or special negative values, no change needed
+ }
+ if (oldVersion < 1070197) {
+ if (prefs.getBoolean("prefMobileUpdate", false)) {
+ prefs.edit().putString("prefMobileUpdateAllowed", "everything").apply();
+ }
+ }
+ if (oldVersion < 1070300) {
+ UserPreferences.restartUpdateAlarm();
+
+ if (UserPreferences.getMediaPlayer().equals("builtin")) {
+ prefs.edit().putString(UserPreferences.PREF_MEDIA_PLAYER,
+ UserPreferences.PREF_MEDIA_PLAYER_EXOPLAYER).apply();
+ }
+
+ if (prefs.getBoolean("prefEnableAutoDownloadOnMobile", false)) {
+ UserPreferences.setAllowMobileAutoDownload(true);
+ }
+ switch (prefs.getString("prefMobileUpdateAllowed", "images")) {
+ case "everything":
+ UserPreferences.setAllowMobileFeedRefresh(true);
+ UserPreferences.setAllowMobileEpisodeDownload(true);
+ UserPreferences.setAllowMobileImages(true);
+ break;
+ case "images":
+ UserPreferences.setAllowMobileImages(true);
+ break;
+ case "nothing":
+ UserPreferences.setAllowMobileImages(false);
+ break;
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java
new file mode 100644
index 000000000..8b886e699
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java
@@ -0,0 +1,112 @@
+package de.danoeh.antennapod.view;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.AttrRes;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.RecyclerView;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import de.danoeh.antennapod.R;
+
+public class EmptyViewHandler {
+ private boolean layoutAdded = false;
+ private RecyclerView recyclerView;
+ private RecyclerView.Adapter adapter;
+
+ private final Context context;
+ private final View emptyView;
+ private final TextView tvTitle;
+ private final TextView tvMessage;
+ private final ImageView ivIcon;
+
+ public EmptyViewHandler(Context context) {
+ emptyView = View.inflate(context, R.layout.empty_view_layout, null);
+ this.context = context;
+ tvTitle = emptyView.findViewById(R.id.emptyViewTitle);
+ tvMessage = emptyView.findViewById(R.id.emptyViewMessage);
+ ivIcon = emptyView.findViewById(R.id.emptyViewIcon);
+ }
+
+ public void setTitle(int title) {
+ tvTitle.setText(title);
+ }
+
+ public void setMessage(int message) {
+ tvMessage.setText(message);
+ }
+
+ public void setIcon(@AttrRes int iconAttr) {
+ TypedValue typedValue = new TypedValue();
+ context.getTheme().resolveAttribute(iconAttr, typedValue, true);
+ Drawable d = ContextCompat.getDrawable(context, typedValue.resourceId);
+ ivIcon.setImageDrawable(d);
+ ivIcon.setVisibility(View.VISIBLE);
+ }
+
+ public void hide() {
+ emptyView.setVisibility(View.GONE);
+ }
+
+ public void attachToListView(ListView listView) {
+ if (layoutAdded) {
+ throw new IllegalStateException("Can not attach to ListView multiple times");
+ }
+ layoutAdded = true;
+ ((ViewGroup) listView.getParent()).addView(emptyView);
+ listView.setEmptyView(emptyView);
+ }
+
+ public void attachToRecyclerView(RecyclerView recyclerView) {
+ if (layoutAdded) {
+ throw new IllegalStateException("Can not attach to ListView multiple times");
+ }
+ layoutAdded = true;
+ this.recyclerView = recyclerView;
+ ViewGroup parent = ((ViewGroup) recyclerView.getParent());
+ parent.addView(emptyView);
+ updateAdapter(recyclerView.getAdapter());
+
+ if (parent instanceof RelativeLayout) {
+ RelativeLayout.LayoutParams layoutParams =
+ (RelativeLayout.LayoutParams)emptyView.getLayoutParams();
+ layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
+ emptyView.setLayoutParams(layoutParams);
+ }
+ }
+
+ public void updateAdapter(RecyclerView.Adapter adapter) {
+ if (this.adapter != null) {
+ this.adapter.unregisterAdapterDataObserver(adapterObserver);
+ }
+ this.adapter = adapter;
+ if (adapter != null) {
+ adapter.registerAdapterDataObserver(adapterObserver);
+ }
+ updateVisibility();
+ }
+
+ private final SimpleAdapterDataObserver adapterObserver = new SimpleAdapterDataObserver() {
+ @Override
+ public void anythingChanged() {
+ updateVisibility();
+ }
+ };
+
+ private void updateVisibility() {
+ boolean empty;
+ if (adapter == null) {
+ empty = true;
+ } else {
+ empty = adapter.getItemCount() == 0;
+ }
+ recyclerView.setVisibility(empty ? View.GONE : View.VISIBLE);
+ emptyView.setVisibility(empty ? View.VISIBLE : View.GONE);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java b/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java
new file mode 100644
index 000000000..45c3a35bd
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java
@@ -0,0 +1,41 @@
+package de.danoeh.antennapod.view;
+
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+
+/**
+ * AdapterDataObserver that relays all events to the method anythingChanged().
+ */
+public abstract class SimpleAdapterDataObserver extends RecyclerView.AdapterDataObserver {
+ public abstract void anythingChanged();
+
+ @Override
+ public void onChanged() {
+ anythingChanged();
+ }
+
+ @Override
+ public void onItemRangeChanged(int positionStart, int itemCount) {
+ anythingChanged();
+ }
+
+ @Override
+ public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
+ anythingChanged();
+ }
+
+ @Override
+ public void onItemRangeInserted(int positionStart, int itemCount) {
+ anythingChanged();
+ }
+
+ @Override
+ public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+ anythingChanged();
+ }
+
+ @Override
+ public void onItemRangeRemoved(int positionStart, int itemCount) {
+ anythingChanged();
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/WrappingGridView.java b/app/src/main/java/de/danoeh/antennapod/view/WrappingGridView.java
new file mode 100644
index 000000000..37792b4d1
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/view/WrappingGridView.java
@@ -0,0 +1,35 @@
+package de.danoeh.antennapod.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.GridView;
+
+/**
+ * Source: https://stackoverflow.com/a/46350213/
+ */
+public class WrappingGridView extends GridView {
+
+ public WrappingGridView(Context context) {
+ super(context);
+ }
+
+ public WrappingGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public WrappingGridView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int heightSpec = heightMeasureSpec;
+ if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) {
+ // The great Android "hackatlon", the love, the magic.
+ // The two leftmost bits in the height measure spec have
+ // a special meaning, hence we can't use them to describe height.
+ heightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
+ }
+ super.onMeasure(widthMeasureSpec, heightSpec);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java b/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java
new file mode 100644
index 000000000..fe11a645c
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java
@@ -0,0 +1,30 @@
+package de.danoeh.antennapod.viewmodel;
+
+import android.arch.lifecycle.ViewModel;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.storage.DBReader;
+import io.reactivex.Maybe;
+
+public class FeedSettingsViewModel extends ViewModel {
+ private Feed feed;
+
+ public Maybe<Feed> getFeed(long feedId) {
+ if (feed == null) {
+ return loadFeed(feedId);
+ } else {
+ return Maybe.just(feed);
+ }
+ }
+
+ private Maybe<Feed> loadFeed(long feedId) {
+ return Maybe.create(emitter -> {
+ Feed feed = DBReader.getFeed(feedId);
+ if (feed != null) {
+ this.feed = feed;
+ emitter.onSuccess(feed);
+ } else {
+ emitter.onComplete();
+ }
+ });
+ }
+}
diff --git a/app/src/main/play/ar/listing/fulldescription b/app/src/main/play/ar/listing/fulldescription
deleted file mode 100644
index 27abb5532..000000000
--- a/app/src/main/play/ar/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod هو مدير للبودكاست واللاعب الذي يتيح لك الوصول الفوري إلى ملايين البودكاست المجانية والمدفوعة ، من البودكاسترات المستقلة إلى دور النشر الكبيرة مثل بي بي سي ، إن بي آر وسي إن إن. يمكنك إضافة واستيراد وتصدير خلاصاتهم الخالية من المتاعب باستخدام قاعدة بيانات بودكاست iTunes أو ملفات OPML أو عناوين URL RSS بسيطة. يمكنك توفير الجهد واستخدام طاقة البطارية واستخدام البيانات المتنقلة مع عناصر تحكم تلقائية قوية لتنزيل الحلقات (حدد الأوقات والفترات الزمنية وشبكات WiFi) وحذف الحلقات (استنادًا إلى إعداداتك المفضلة وتأخير الإعدادات).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ast_ES/listing/fulldescription b/app/src/main/play/ast_ES/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/ast_ES/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/az/listing/fulldescription b/app/src/main/play/az/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/az/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/bg/listing/fulldescription b/app/src/main/play/bg/listing/fulldescription
deleted file mode 100644
index 16a005e22..000000000
--- a/app/src/main/play/bg/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod е подкаст мениджър и плейър, който ви дава незабавен достъп до милиони безплатни и платени подкасти, от независими подкасти до големи издателства като BBC, NPR и CNN. Добавете, импортирайте и експортирайте своите емисии безпроблемно, като използвате базата данни на iTunes, OPML файлове или обикновени URL адреси. Спестете усилие, захранване на батерията и мобилни данни чрез мощни контролни механизми за автоматизиране на изтеглянето на епизоди (задайте часове, интервали и WiFi мрежи) и изтриването на епизоди (базирани на предпочитаните от вас и настройките за отлагане).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>Всички функции:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Присъединете се към общността на AntennaPod!</b><br>
-AntennaPod се разработва активно от доброволци. Можете да допринесете с код или с коментар!
-
-GitHub е мястото за заявки за функции, отчети за грешки и участие:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Имате въпрос или искате да дадете отзиви?
-https://twitter.com/@AntennaPod
-
-Transifex е мястото за помощ при преводите:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ca/listing/fulldescription b/app/src/main/play/ca/listing/fulldescription
deleted file mode 100644
index 0e8d76e5e..000000000
--- a/app/src/main/play/ca/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-L'AntennaPod és un gestor i reproductor de podcasts que us dóna accés instantani a milions de podcasts gratuïts i de pagament, fets per podcasters independents o grans emissores com la BBC, l'NPR i la CNN. Afegiu, importeu i exporteu les seves subscripcions sense complicacions utilitzant la base de dades de podcasts de l'iTunes, fitxers OPML o enllaços RSS. Estalvieu esforços, bateria i consum de dades al mòbil amb potents controls d'automatització per a baixar episodis (especifiqueu hores, intervals i xarxes WiFi) i esborrar-los (basats en la vostra configuració sobre favorits i demores).<br>
-Però el més important: baixeu, transmeteu o afegiu episodis a la cua i gaudiu-ne a la vostra manera amb velocitats de reproducció ajustables, capacitat per a usar capítols i un temporitzador per a dormir. Fins i tot podeu demostrar la vostra estima pels creadors de continguts amb la nostra integració de Flattr.
-
-Fet per entusiastes del podcàsting, l'AntennaPod és lliure en tots els sentits del terme: codi obert, sense cost ni anuncis.
-
-<b>Totes les funcions:</b><br>
-IMPORTA, ORGANITZA I REPRODUEIX<br>
-&#8226; Afegeix i importa canals mitjançant els directoris iTunes i gPodder.net, fitxers OPML i enllaços RSS o Atom<br>
-&#8226; Gestiona la reproducció des de qualsevol banda: giny de la pantalla d'inici, notificacions del sistema i controls d'auriculars i Bluetooth.<br>
-&#8226; Gaudiu escoltant a la vostra manera amb velocitat de reproducció ajustable, capacitat per a usar capítols (MP3, VorbisComment i Podlove), record de la posició de reproducció i un temporitzador per a dormir avançat (agiteu per a reiniciar, abaixar el volum i reduir la velocitat de reproducció).<br>
-&#8226; Accediu a subscripcions i episodis protegits per contrasenya.<br>
-&#8226; Aprofiteu les subscripcions paginades (www.podlove.org/paged-feeds).
-
-FEU SEGUIMENT, COMPARTIU I AGRAÏU<br>
-&#8226; Seguiu el millor del millor marcant episodis com a favorits.<br>
-&#8226; Trobeu l'episodi que busqueu mitjançant l'historial de reproducció o la cerca (de títols i descripcions).<br>
-&#8226; Compartiu episodis i subscripcions mitjançant xarxes socials i correu electrònic, els serveis de gPodder.net i exportant a OPML.<br>
-&#8226; Recolzeu els creadors de continguts amb la integració de Flattr, fins i tot de forma automàtica.
-
-CONTROLEU EL SISTEMA<br>
-&#8226; Prengueu el control de les baixades automàtiques: trieu les subscripcions, exclogueu xarxes mòbils, trieu xarxes WiFi específiques, requeriu que el telèfon s'estigui carregat i establiu les hores o intervals.<br>
-&#8226; Gestioneu l'emmagatzematge ajustant la quantitat d'episodis en emmagatzematge temporal, l'esborrat intel·ligent (basat en els vostres favorits i l'estat de reproducció) i triant la vostra ubicació preferida.<br>
-&#8226; Feu servir l'AntennaPod en la vostra llengua (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH).<br>
-&#8226; Adapteu-vos al vostre entorn fent servir el tema clar o el fosc.<br>
-&#8226; Feu còpies de seguretat de les vostres subscripcions amb la integració amb gPodder.net i l'exportació a OPML.
-
-<b>Uniu-vos a la comunitat d'AntennaPod!</b><br>
-L'AntennaPod el desenvolupen voluntaris. Podeu col·laborar, amb codi o comentaris.
-
-Podeu proposar noves característiques, informar d'errors i aportar codi a GitHub:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Podeu compartir les vostres idees, els vostres moments de podcàsting favorits i la gratitud amb tots els voluntaris al nostre grup de Google:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Teniu preguntes o voleu comentar-nos alguna cosa?
-https://twitter.com/@AntennaPod
-
-Ens podeu ajudar amb les traduccions a Transifex:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Consulteu el nostre programa de proves beta per a obtenir els primers<br> les últimes característiques:
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ca_ES/listing/fulldescription b/app/src/main/play/ca_ES/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/ca_ES/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/contactEmail b/app/src/main/play/contact-email.txt
index d4543c6e0..d4543c6e0 100644
--- a/app/src/main/play/contactEmail
+++ b/app/src/main/play/contact-email.txt
diff --git a/app/src/main/play/contactWebsite b/app/src/main/play/contact-website.txt
index cb1c2f641..cb1c2f641 100644
--- a/app/src/main/play/contactWebsite
+++ b/app/src/main/play/contact-website.txt
diff --git a/app/src/main/play/cs-CZ/listing/fulldescription b/app/src/main/play/cs-CZ/listing/fulldescription
deleted file mode 100644
index 204c521f2..000000000
--- a/app/src/main/play/cs-CZ/listing/fulldescription
+++ /dev/null
@@ -1,20 +0,0 @@
-AntennaPod je open-source správce podcastů pro Android 2.3.3 a novější. Nabízí všechny základní funkce, které můžete očekávat od podcast klienta, jako jsou přehrávání streamu a stahování epizod, automatické sledování jednotlivých podcastů nebo přidávání nových epizod do fronty pro pozdější poslech. Navíc AntennaPod umožňuje podpořit podcasty přímo z aplikace pomocí služby flattr.
-
-Zatím jsou zavedeny tyto možnosti:
-
-* Stahování a streamovaný poslech epizod
-* Různé rychlosti přehrávání (vyžaduje knihovnu Presto Sound nebo Prestissimo)
-* Podpora Atom a RSS zdrojů
-* Podpora pro zdroje a epizody chráněné heslem
-* Support for searching iTunes listings
-* OPML import a export
-* Integrace pro Flattr včetně automatického flattrování
-* Widget přehrávače na domácí obrazovku
-* Vyhledávání
-* Automatické sledování zdrojů
-* Automatické stahování nových epizod
-* Časovač vypnutí
-* Přístup do seznamu podcastů na gpodder.net
-* Synchronizace přihlášené služby na gpodder.net
-* Podporuje MP3 kapitoly, VorbisComment kapitoly a Podlove Simple Chapters
-* Podporuje stránkované kanály (http://podlove.org/paged-feeds/) \ No newline at end of file
diff --git a/app/src/main/play/cs-CZ/listing/shortdescription b/app/src/main/play/cs-CZ/listing/shortdescription
deleted file mode 100644
index 5f700bd93..000000000
--- a/app/src/main/play/cs-CZ/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Open-source správce podcastu pro Android \ No newline at end of file
diff --git a/app/src/main/play/cs-CZ/listing/title b/app/src/main/play/cs-CZ/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/cs-CZ/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/cs_CZ/listing/fulldescription b/app/src/main/play/cs_CZ/listing/fulldescription
deleted file mode 100644
index 4e15342ee..000000000
--- a/app/src/main/play/cs_CZ/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Používejte AntennaPod ve vlastním jazyce (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Přidejte se ke komunitě AntennaPod!</b><br>
-AntennaPod je aktivně vyvíjen dobrovolníky. Můžete přispět také svým kódem nebo komentáři!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Máte dotaz nebo chcete poslat svůj názor?
-https://twitter.com/@AntennaPod
-
-Překlady jsou spravovány pomocí služby Transifex:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/da-DK/listing/fulldescription b/app/src/main/play/da-DK/listing/fulldescription
deleted file mode 100644
index 1d19da2e8..000000000
--- a/app/src/main/play/da-DK/listing/fulldescription
+++ /dev/null
@@ -1,20 +0,0 @@
-AntennaPod er en open-source podcast afspiller for Android 2.3.3 og nyere. Den tilbyder alle basale features du forventer fra en podcastafspiller, som streaming og download af episoder, opdaterer automatisk feeds eller tilføjer dem automatisk i en kø så du kan høre dem senere. Derudover lader AntennaPod dig flattr podcasts og episoder inde i appen.
-
-Indtil nu er følgende features blevet implementeret:
-
-* Download og Streaming af episoder
-* Variabel afspilningshastighed (kræver Presto Sound Library eller Prestissimo)
-* Understøttelse af Atom og RSS feeds
-* Understøttelse af password-beskyttede feeds og episoder
-* Support for searching iTunes listings
-* OPML import og eksport
-* Flattr integration inkluderer automatisk flattring
-* Afspiller widget
-* Søg
-* Automatisk opdatering af feeds
-* Automatisk download af nye episoder
-* Sleep timer
-* Adgang til gpodder.net's podcast bibliotek
-* Synkronisering af abonnementer med gpodder.net's service
-* Understøtter af MP3 kapitler, VorbisComment kapitler and Podlove Simple Chapters
-* Understøtter side-delte feeds (http://podlove.org/paged-feeds/) \ No newline at end of file
diff --git a/app/src/main/play/da-DK/listing/shortdescription b/app/src/main/play/da-DK/listing/shortdescription
deleted file mode 100644
index 4eceefbb7..000000000
--- a/app/src/main/play/da-DK/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Easy-to-use, flexible and open-source podcast manager and player \ No newline at end of file
diff --git a/app/src/main/play/da-DK/listing/title b/app/src/main/play/da-DK/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/da-DK/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/da/listing/fulldescription b/app/src/main/play/da/listing/fulldescription
deleted file mode 100644
index 241066fd4..000000000
--- a/app/src/main/play/da/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod er en app til håndtering og afspilning af podcasts. Den giver dig øjeblikkelig adgang til millioner af gratis og betalte podcasts, fra uafhængige podcastere til store udgivere som BBC, NPR, CNN og DR. Tilføj, importer og eksporter deres feeds problemfrit ved hjælp af iTunes-podcastdatabasen, OPML-filer eller enkle RSS-webadresser. Spar kræfter, batteristrøm og mobilt dataforbrug med kraftfulde automatiske styringsværktøjer til at hente udsendelser (angiv tidspunkter, tidsintervaller og udvalgte wi-fi-netværk) og sletning af episoder (baseret på dine foretrukne udsendelser og forsinkelsesindstillinger).<br>
-Men vigtigst af alt: Hent, stream eller sæt udsendelser i kø og nyd dem på den måde du kan lide med justerbare hastigheder, kapitelunderstøttelse og en søvntimer. Du kan endda vise din påskønnelse over for indholdsskaberne med vores Flattr-integration.
-
-AntennaPod er lavet af en podcast-entusiast og er gratis og fri i alle betydninger: open source, ingen udgifter, ingen reklamer.
-
-<b>Alle funktioner:</b><br>
-IMPORTER, ORGANISER OG AFSPIL<br>
-&#8226; Tilføj og importer feeds via iTunes- og gpodder.net-oversigterne, OPML-filer og RSS- eller Atom-links<br>
-&#8226; Håndter afspilning fra hvor som helst: widget på startskærmen, systemnotifikation, samt hovedtelefon- og bluetooth-styring<br>
-&#8226; Lyt på din egen måde med justerbar afspilningshastighed, kapitelunderstøttelse (MP3, VorbisComment og Podlove), erindring af afspilningsposition og en avanceret søvntimer (ryst for at nulstille, sænke lydstyrken og afspille langsommere)<br>
-&#8226; Tilgå feeds og udsendelser beskyttet med adgangskode<br>
-&#8226; Brug sideinddelte feeds (www.podlove.org/paged-feeds)
-
-HOLD STYR PÅ, DEL OG ANERKEND<br>
-&#8226; Hold styr på det bedste af det bedste ved at markere udsendelser som foretrukne<br>
-&#8226; Find en bestemt udsendelse via afspilningshistorikken eller ved at søge (titler og beskrivelser)<br>
-&#8226; Del udsendelser og feeds via avancerede valgmuligheder for sociale medier, gpodder.net-tjenesterne og OPML-eksport<br>
-&#8226; Støt indholdsskabere med Flattr-integration, inklusive automatisk flattring
-
-STYR SYSTEMET<br>
-&#8226; Tag styring over automatiseret hentning: vælg feeds, udeluk mobile netværk, vælg specifikke wi-fi-netvæk, kræv at telefonen oplader og indstil tidspunkter eller tidsintervaller
-&#8226; Håndter lagerforbruget ved at indstille antallet af udsendelser, der skal gemmes, smart sletning (baseret på dine foretrukne og afspilningsstatus) og ved at vælge den lagerplacering, du foretrækker<br>
-&#8226; Brug AntennaPod på dit eget sprog (EN, DE, DA, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Tilpas appen til dit miljø med det lyse og mørke tema<br>
-&#8226; Sikkerhedskopier dine abonnementer med gpodder.net-integrationen og OPML-eksport
-
-<b>Bliv en del af AntennaPod-fællesskabet!</b><br>
-AntennaPod er under aktiv udvikling af frivillige. Du kan også bidrage, med kode eller kommentarer!
-
-GitHub er stedet for forslag tli ny funktionalitet, fejlrapporter og kodebidrag:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Vores Google-gruppe er stedet til at dele dine ideer, foretrukne podcast-øjeblikke og taknemmelighed til alle de frivillige:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Har du et spørgsmål eller vil du give os en tilbagemelding?
-https://twitter.com/@AntennaPod
-
-Transifex er stedet, hvis du vil hjælpe med oversættelser:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Prøv vores beta-testprogram for at få de nyeste funktioner først:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/de-DE/listing/fulldescription b/app/src/main/play/de-DE/listing/fulldescription
deleted file mode 100644
index c2299c44f..000000000
--- a/app/src/main/play/de-DE/listing/fulldescription
+++ /dev/null
@@ -1,20 +0,0 @@
-AntennaPod ist ein Open-Source Podcastmanager für Android 2.3.3+. Er bietet alle grundlegenden Funktionen, die Sie von einem Podcatcher erwarten. Dazu gehören das Streaming und Herunterladen von Episoden, alle Feeds automatisch zu aktualisieren oder sie einer Warteschlange hinzuzufügen, um sie später zu hören. Darüber hinaus können Sie mit AntennaPod Podcasts und Episoden aus der App heraus flattrn.
-
-Bisher sind folgende Funktionen eingebaut:
-
-* Herunterladen und Streamen von Episoden
-Variable Abspielgeschwindigkeit (benötigt Presto Sound Library oder Prestissimo)
-* Unterstützung von Atom- und RSS-Feeds
-* Unterstützung für Passwort-geschützte Feeds und Episoden
-* Unterstützung für Auflistungen die in iTunes gesucht werden
-* OPML-Import und -Export
-* Flattr-Integration, einschließlich automatischem Flattrn
-* Player-Homescreen-Widget
-* Suche
-* Automatische Feed-Aktualisierungen
-* Automatisches Herunterladen von neuen Episoden
-* Schlummerfunktion
-* Zugang zum gpodder.net-Verzeichnis hinzugefügt
-* Option zum Synchronisieren der Podcast-Abonnements mit dem gpodder.net-Service hinzugefügt
-* Unterstützt Kapitelmarken in MP3 und VorbisComment, sowie Podlove Simple Chapters
-* Unterstützt Paged Feeds (http://podlove.org/paged-feeds/) \ No newline at end of file
diff --git a/app/src/main/play/de-DE/listing/title b/app/src/main/play/de-DE/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/de-DE/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/defaultLanguage b/app/src/main/play/default-language.txt
index f2b0341fe..f2b0341fe 100644
--- a/app/src/main/play/defaultLanguage
+++ b/app/src/main/play/default-language.txt
diff --git a/app/src/main/play/el/listing/fulldescription b/app/src/main/play/el/listing/fulldescription
deleted file mode 100644
index f0ec3ae38..000000000
--- a/app/src/main/play/el/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-Το Antennapod είναι μία εφαρμογή διαχείρισης και εκτέλεσης podcasts που σας δίνει άμεση πρόσβαση σε εκατομμύρια δωρεάν και επί πληρωμή podcasts, από ανεξάρτητους podcasters έως μεγάλους εκδοτικούς οίκους όπως το BBC, NPR και CNN. Μπορείτε εύκολα να προσθέσετε, να εισάγετε και να εξάγετε τις ροές τους χρησιμοποιώντας τη βάση δεδομένων podcast του iTunes, αρχεία OPML ή απλά RSS URLs. Γλυτώστε προσπάθεια, μπαταρία και χρήση δεδομένων κινητής τηλεφωνίας με ισχυρές ρυθμίσεις αυτοματισμών για λήψη επεισοδίων (ορίστε τους χρόνους, τα διαστήματα και τα δίκτυα WiFi) και σβήστε επεισόδια (με βάση τα αγαπημένα σας και τις ρυθμίσεις καθυστέρησης).<br>
-Αλλά το πλέον σημαντικό: Κατεβάστε, κάντε stream ή βάλτε στη σειρά επεισόδια και απολαύστε τα όπως επιθυμήτε με ρυθμιζόμενη ταχύτητα αναπαραγωγής, υποστήριξη κεφάλαιων και χρονόμετρο απενεργοποίησης. Μπορείτε ακόμη και να δείξετε την αγάπη σας στους δημιουργούς περιεχομένου μέσω της ενσωμάτωσης του Flattr.
-
-Φτιαγμένο από λάτρη των podcast, το AntennaPod είναι ελεύθερο με όλες τις έννοιες της λέξης: ανοικτού λογισμικού, χωρίς κόστη, χωρίς διαφημίσεις.
-
-<b>Όλα τα χαρακτηριστικά:</b><br>
-ΕΙΣΑΓΩΓΉ, ΟΡΓΆΝΩΣΗ ΚΑΙ ΕΚΤΈΛΕΣΗ<br>
-&#8226; Προσθέστε και εισάγετε ροές μέσω των φακέλων του iTunes και του gPodder.net, αρχείων OPML και RSS ή συνδέσμους Atom<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Ενταχθείτε στη κοινότητα του AntennaPod!</b><br>
-Το AntennaPod βρίσκεται υπό ενεργή ανάπτυξη από εθελοντές. Μπορείτε και εσείς να συνεισφέρετε, με κώδικα ή με κάποιο σχόλιο.
-
-Το Github είναι το μέρος να επισκεφθείτε για να ζητήσετε καινούρια χαρακτηριστικά, να αναφέρετε σφάλματα και για συνεισφορά κώδικα:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Το Google Group μας είναι το μέρος να μοιραστείτε τις ιδέες σας, τις αγαπημένες σας στιγμές ενασχόλησης με τα podcasts και ευγνωμοσύνη σε όλους τους εθελοντές:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Έχετε κάποια ερώτηση ή θέλετε να μας δώσετε κάποια ανατροφοδότηση;
-https://twitter.com/@AntennaPod
-
-Το Transifex είναι το μέρος για να βοηθήσετε με τις μεταφράσεις:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Ελέγξτε το πρόγραμμά μας Beta Testing για να λαμβάνετε τα τελευταία χαρακτηριστικά πρώτοι:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/en-US/listing/shortdescription b/app/src/main/play/en-US/listing/shortdescription
deleted file mode 100644
index 7afb5a62d..000000000
--- a/app/src/main/play/en-US/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Easy-to-use, flexible and open-source podcast & radio manager and player \ No newline at end of file
diff --git a/app/src/main/play/en-US/listing/title b/app/src/main/play/en-US/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/en-US/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/es-ES/listing/fulldescription b/app/src/main/play/es-ES/listing/fulldescription
deleted file mode 100644
index 5cc6c5bf5..000000000
--- a/app/src/main/play/es-ES/listing/fulldescription
+++ /dev/null
@@ -1,40 +0,0 @@
-AntennaPod is un gestor y reproductor de podcast que te da acceso instantáneo a millones de podcast gratuitos y de pago, desde podcasters independientes a grandes estaciones como la BBC, NPR y CNN. Agrega, importa y exporta las fuentes de manera sencilla usando el listado de iTunes, archivos OPML o las URL de tipo RSS. Ahorra esfuerzo, batería y datos con los controles de descarga (a horas o intervalos específicos, o redes WiFi) y de borrado de episodios (basado en favoritos y ajustes de tiempo).<br>
-Y lo más importante: descarga, escucha en stream y disfrutalos como quieras con velocidad de reproducción variable, soporte para capítulos y temporizador de sueño. Incluso puedes mostrar tu gratitud a los creadores de contenido mediante Flattr.
-
-Hecho por entusiastas del podcasting, AntennaPod es libre, gratuito y sin publicidad.
-
-<b>Características:</b><br>
-IMPORTAR, ORGANIZAR Y REPRODUCIR<br>
-&#8226; Añadir e importar feeds mediante los directorios iTunes o gPodder.net, archivos OPML y los enlaces RSS y Atom<br>
-&#8226; Gestiona la reproducción desde cualquier parte: widget, notificación del sistema y controles de auricular y bluetooth<br>
-&#8226; Disfruta escuchando a tu manera ajustando la velocidad de reproducción, con soporte para capítulos (MP3, VorbisComment y Podlove), recordando la posición de reproducción y un temporizador de sueño (agita para reiniciar, bajada de volumen y ralentización)<br>
-&#8226; Accede a feeds y episodios protegidos con contraseña<br>
-&#8226; Accede a feeds paginados (www.podlove.org/paged-feeds)
-
-RECUERDA, COMPARTE Y APRECIA
-&#8226; Ten localizado lo mejor de lo mejor marcando episodios como favoritos<br>
-&#8226; Encuentra ese episodio consultando el histórico o buscándolo (por título o por notas de episodio)<br>
-&#8226; Comparte episodios feeds con opciones avanzadas de redes sociales, email, servicios gPodder.net y exportación OPML<br>
-&#8226; Ayuda a los creadores de contenido con la integración Flatter, siendo posible hacer Flattr automático
-
-CONTROLA EL SISTEMA<br>
-&#8226; Toma el control de la descarga automática: elige los feeds, excluye las redes móviles, elige redes WiFi específicas, hazlo sólo si el teléfono está cargando o a ciertas horas o intervalos<br>
-&#8226; Gestiona el almacenamiento configurando la cantidad de episodios en caché, configura borrado inteligente (basado en favoritos y el estado de reproducción) y eligiendo tu ubicación favorita<br>
-&#8226; Usa AntennaPod en tu idioma (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adáptate a tu entorno usando el tema claro u oscuro<br>
-&#8226; Haz backup de tus suscripciones usando gPodder.net o exportando a OPML
-
-<b>¡Únete a la comunidad AntennaPod!</b><br>
-AntennaPod está en continuo desarrollo por voluntarios. ¡Tú también puedes contribuir, con tu código o con tus comentarios!
-
-GitHub es el sitio que debes visitar para solicitar características nuevas, reportar fallos y contribuir con código<br>
-www.github.com/AntennaPod/AntennaPod
-
-Nuestro Grupo de Google es el sitio para compartir tus ideas, tus momentos favoritos de podcasting y tu gratitud a los voluntarios:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Transifex es el sitio para ayudar con las traducciones:<br>
-www.transifex.com/antennapod/antennapod
-
-Echa un vistazo a nuestro programa de Beta Testing para ser el primero en usar las nuevas características:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/es-ES/listing/shortdescription b/app/src/main/play/es-ES/listing/shortdescription
deleted file mode 100644
index e5b6ace85..000000000
--- a/app/src/main/play/es-ES/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Reproductor y gestor de podcast de código abierto, flexible y fácil de usar \ No newline at end of file
diff --git a/app/src/main/play/es-ES/listing/title b/app/src/main/play/es-ES/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/es-ES/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/es/listing/fulldescription b/app/src/main/play/es/listing/fulldescription
deleted file mode 100644
index 96f914f26..000000000
--- a/app/src/main/play/es/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod es un gestor y reproductor de podcast que te da acceso instantáneo a millones de podcast gratuitos y pagos, desde podcasters independientes a grandes estaciones como la BBC, NPR y CNN. Agrega, importa y exporta las fuentes de manera sencilla usando el listado de iTunes, archivos OPML o las URL de tipo RSS. Ahorre esfuerzo, energía de la batería y uso de datos móviles con potentes controles de automatización para descargar episodios (especifique horarios, intervalos y redes WiFi) y elimine episodios (según sus preferencias y configuraciones de demora).<br>
-Y lo más importante: descarga, escucha en stream y disfrutalos como quieras con velocidad de reproducción variable, soporte para capítulos y temporizador de sueño. Incluso puedes mostrar tu gratitud a los creadores de contenido mediante Flattr.
-
-Hecho por entusiastas del podcasting, AntennaPod es libre, gratuito y sin publicidad.
-
-<b>Características:</b><br>
-IMPORTAR, ORGANIZAR Y REPRODUCIR<br>
-&#8226; Añadir e importar feeds mediante los directorios iTunes o gPodder.net, archivos OPML y los enlaces RSS y Atom<br>
-&#8226; Gestiona la reproducción desde cualquier parte: widget, notificación del sistema y controles de auricular y bluetooth<br>
-&#8226; Disfruta escuchando a tu manera ajustando la velocidad de reproducción, con soporte para capítulos (MP3, VorbisComment y Podlove), recordando la posición de reproducción y un temporizador de sueño (agita para reiniciar, bajada de volumen y ralentización)<br>
-&#8226; Accede a feeds y episodios protegidos con contraseña<br>
-&#8226; Accede a feeds paginados (www.podlove.org/paged-feeds)
-
-RECUERDA, COMPARTE Y APRECIA
-&#8226; Ten localizado lo mejor de lo mejor marcando episodios como favoritos<br>
-&#8226; Encuentra ese episodio consultando el histórico o buscándolo (por título o por notas de episodio)<br>
-&#8226; Comparte episodios feeds con opciones avanzadas de redes sociales, email, servicios gPodder.net y exportación OPML<br>
-&#8226; Ayuda a los creadores de contenido con la integración Flatter, siendo posible hacer Flattr automático
-
-CONTROLA EL SISTEMA<br>
-&#8226; Toma el control de la descarga automática: elige los feeds, excluye las redes móviles, elige redes WiFi específicas, hazlo sólo si el teléfono está cargando o a ciertas horas o intervalos<br>
-&#8226; Gestiona el almacenamiento configurando la cantidad de episodios en caché, configura borrado inteligente (basado en favoritos y el estado de reproducción) y eligiendo tu ubicación favorita<br>
-&#8226; Usa AntennaPod en tu idioma (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adáptate a tu entorno usando el tema claro u oscuro<br>
-&#8226; Haz backup de tus suscripciones usando gPodder.net o exportando a OPML
-
-<b>¡Únete a la comunidad AntennaPod!</b><br>
-AntennaPod está en continuo desarrollo por voluntarios. ¡Tú también puedes contribuir, con tu código o con tus comentarios!
-
-GitHub es el sitio que debes visitar para solicitar características nuevas, reportar fallos y contribuir con código<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Nuestro Grupo de Google es el sitio para compartir tus ideas, tus momentos favoritos de podcasting y tu gratitud a los voluntarios:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-¿Tienes una pregunta o quieres darnos tu opinión?
-https://twitter.com/@AntennaPod
-
-Transifex es el sitio para ayudar con las traducciones:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Echa un vistazo a nuestro programa de Beta Testing para ser el primero en usar las nuevas características:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/es_ES/listing/fulldescription b/app/src/main/play/es_ES/listing/fulldescription
deleted file mode 100644
index 1ce12e3b4..000000000
--- a/app/src/main/play/es_ES/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>¡Únete a la comunidad de AntennaPod!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/et/listing/fulldescription b/app/src/main/play/et/listing/fulldescription
deleted file mode 100644
index d33e8f4e8..000000000
--- a/app/src/main/play/et/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>Kõik omadused:</b><br>
-IMPORDI, ORGANISEERI JA ESITA<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Kasuta ära lehekülgedeks jagatud voogusid (www.podlove.org/paged-feeds)
-
-JÄLGI, JAGA JA HINDA<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-KONTROLLI SÜSTEEMI<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Kasuta AntennaPodi omaenda keeles (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH, ET)<br>
-&#8226; Kohandu oma keskkonnale valides heleda ja tumeda ekraani vahet<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Liitu AntennaPodi kogukonnaga!</b>
-AntennaPod on vabatahtlike poolt aktiivselt arendamisel. Ka sina võid anda oma osa kirjutades koodi või andes oma kommentaare!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Kas sul on küsimus või soovid anda meile tagasisidet?
-https://twitter.com/@AntennaPod
-
-Transifex on koht, kus saad abiks olla tõlkimisega:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Vaata meie beeta testide programmi, et saada esimesena osa värskeimatest omadustest:
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/fa/listing/fulldescription b/app/src/main/play/fa/listing/fulldescription
deleted file mode 100644
index 0a005f962..000000000
--- a/app/src/main/play/fa/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod یک نرم افزار مدیریت و پخش پادکست میباشد که به شما امکان دسترسی سریع به میلیون ها پادکست رایگان و پرداخت شده ، از طریق انتشارات بزرگ و مستقل مانند بی بی سی، NPR و CNN را می دهد. همچنین شما میتوانید از پایگاه داده iTunes podcast، فایل های OPML یا URL های ساده RSS، استفاده نمایید ، آنها را اضافه کنید ،اطلاعالت خود را وارد و یا از انها فایل پشتیبان تهیه کنید.. صرفه جویی در زمان جستجو ، قدرت باتری و استفاده از داده های تلفن همراه با استفاده از ترفندهای قدرتمند اتوماسیون برای دانلود قسمت ها (تعیین زمان، فواصل و شبکه های WiFi) و حذف قسمت (بر اساس علاقه مندی های خود و تنظیمات تاخیر)<br>
-ما مهمتر از همه: دانلود، پخش یا پخش قسمت ها و لذت بردن از آنهاست، سرعت پخش قابل تنظیم، به هر سرعتی که شما علاقه دارید ، با پشتیبانی فصل ( قسمتها ) و یک تایمر برای خواب .حتی شما میتوانید علاقه خود را با سازندگان محتوا با استفاده از Flattr integration ما ، نشان دهید.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/fi/listing/fulldescription b/app/src/main/play/fi/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/fi/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/fr-FR/listing/fulldescription b/app/src/main/play/fr-FR/listing/fulldescription
deleted file mode 100644
index 61177b28a..000000000
--- a/app/src/main/play/fr-FR/listing/fulldescription
+++ /dev/null
@@ -1,40 +0,0 @@
-AntennaPod est un lecteur et gestionnaire de podcast permettant l'accès à des millions de podcast gratuits ou payants produit aussi bien par des podcasters indépendants que de gros éditeurs comme la BBC, NPR ou CNN. Ajoutez, importez et exportez leurs flux facilement à partir d'ITunes, de fichiers OPML ou simplement à partir de liens RSS. Économisez votre temps, votre batterie et votre consommation internet grâce à une automatisation puissante des téléchargements (quand, à quel rythme et à partir de quel réseau wifi) et de la suppression des épisodes (à partir d'un certains temps ou des favoris)<br>
-Encore plus important : téléchargez, streamez ou mettez dans votre liste de lecture vos épisodes et écoutez les à votre manière grâce à une vitesse de lecture réglable, au support des chapitres et une fonction de mise en veille automatique. Vous pouvez même montrer votre appréciation aux créateurs de contenu avec notre intégration de Flattr.
-
-Programmé par des fans de podcast, AntennaPod est gratuit dans tous les sens du terme : open source, aucun cout et pas de publicité.
-
-<b>Caractéristiques complètes :</b><br>
-Importer, gérer et écouter<br>
-&#8226; Ajouter et importer à partir d'iTunes, gPodder.net, de fichiers OPML ou de liens RSS ou Atom<br>
-&#8226; Gérez la lecture de n'importe où : widget sur l'écran d'accueil, notification système, commande casque ou bluetooth<br>
-&#8226; Ecoutez à votre façon grâce à une vitesse de lecture réglable, au support des chapitres (MP3, VorbisComment et Podlove), enregistrement de la position de lecture et une mise en veille automatique puissante (secouer pour prolonger le minuteur, baisse du volume et ralentissement de la lecture)<br>
-&#8226; Accès aux flux et épisodes protégés par mot de passe<br>
-&#8226; Tirez profit des flux à plusieurs pages (www.podlove.org/paged-feeds)
-
-GARDEZ TRACE, PARTAGEZ & APPRECIEZ<br>
-&#8226; Gardez trace des meilleurs épisodes en les marquant comme favoris<br>
-&#8226; Retrouvez un épisode à partir de l'historique de lecture ou en cherchant (les titres et les commentaires des épisodes)<br>
-&#8226; Partagez vos épisodes ou flux à travers des options de réseaux sociaux et email avancées, du service gPodder.net ou par des exports OPML<br>
-&#8226; Soutenez les créateurs de contenu avec l'intégration à Flattr et la possibilité de flatter automatiquement
-
-CONTRÔLER LE SYSTÈME<br>
-&#8226; Prenez le contrôle avec l'automatisation des téléchargements : choisissez les flux, empêchez l'utilisation du réseau mobile, sélectionnez les réseaux WIFI à utiliser, exigez que le téléphone soit en train de charger et spécifiez quand ou à quel rythme<br>
-&#8226; Gérez l'espace de stockage en paramétrant le nombre d'épisodes à garder, de leurs suppressions automatique (à partir de vos favoris et du statut de lecture) et de l'emplacement où les enregistrer<br>
-&#8226; Utilisez AntennaPod dans votre langue (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adaptez à votre environnement avec un thème clair ou sombre<br>
-&#8226; Sauvegardez vos abonnements avec l'intération à gPodder.net ou des exports OPML
-
-<b>Rejoignez la communauté d'AntennaPod !</b><br>
-AntennaPod est développé activement par des volontaires. Vous pouvez aussi contribuer avec du code ou des commentaires !
-
-GitHub est l'endroit où aller pour demander de nouvelles options, faire part de bug ou pour contribuer au code :<br>
-www.github.com/AntennaPod/AntennaPod
-
-Notre groupe Google est l'endroit où aller pour partager vos idées, moments préférés de podcast et vos remerciements aux volontaires :<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Transifex est le lieu où vous pouvez aider à la traduction :<br>
-www.transifex.com/antennapod/antennapod
-
-Jetez un coup d’œil à notre programme de version Beta pour bénéficier des dernières options :<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/fr-FR/listing/title b/app/src/main/play/fr-FR/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/fr-FR/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/he_IL/listing/fulldescription b/app/src/main/play/he_IL/listing/fulldescription
deleted file mode 100644
index 4ccee5452..000000000
--- a/app/src/main/play/he_IL/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-היישומון אנטנה־פּוֹד הוא נגן ומנהל פודקאסטים שמעניק לך גישה ישירה למיליונים של פודקאסטים בחינם ובתשלום, החל ממגישי פודקאסטים עצמאיים ועד למפיצים גדולים כגון BBC,‏ NPR ו־CNN. ניתן להוסיף, לייבא ולייצא את ההזנות שלהם בקלות יחסית באמצעות מסד נתוני הפודקאסטים של iTunes, קובצי OPML או כתובות של RSS. מאפשר לך לחסוך במאמץ, סוללה ותקשורת נתונים עם פקדי אוטומציה להורדה של פרקים (לפי זמנים, הפרשי זמן ורשתות אלחוטיות) ומחיקה של פרקים (על בסיס הגדרות המועדפים וההשהיה שלך).<br>
-אבל הכי חשוב: ניתן להוריד, להזרים או לסדר רשימות של פרקים וליהנות מהם בכל דרך שמתאימה לך עם מהירויות נגינה משתנות, תמיכה במקטעים ומתזמן שינה. ניתן אפילו להביע את חיבתך ליוצרי התוכן עם שילוב של Flattr ביישומון.
-
-מיוצרת על ידי חובבי פודקאסטים, אנטנהפוד הינה תוכנה חינמית בכל מובן המילה: קוד פתוח, ללא עלות וללא פרסומות.
-
-<b>כל התכונות:</b><br>
-ייבוא, ארגון ונגינה<br>
-&#8226; ניתן להוסיף ולייבא הזנות דרך הספריות של iTunes ושל gPodder.net, קובצי OPML וקישורי RSS או Atom<br>
-&#8226; ניתן לנהל את הנגינה מכל מקום: וידג׳ט על מסך הבית, התרעות המערכת ופקדי שקע אוזניות ובלוטות׳<br>
-&#8226; פשוט ליהנות בדרך שלך עם מהירות נגינה משתנה, תמיכה במקטעים (MP3, VorbisComment ו־Podlove), שמירת מיקום הנגינה ומתזמן שינה מתקדם (ניתן לנער כדי לאפס, להנמיך את עצמך השמע ולהאט את מהירות הנגינה)<br>
-&#8226; גישה להזנות ולפרקים המוגנים בססמה<br>
-&#8226; ניתן להשתמש בעימודי ההזנות שלנו (www.podlove.org/paged-feeds)
-
-מעקב, שיתוף והבעת הערכה<br>
-&#8226; מעקב אחר הטובים שבטובים על ידי סימון פרקים כמועדפים<br>
-&#8226; ניתן לאתר פרק אחד דרך היסטוריית הנגינה או על ידי חיפוש (כותרות והערות פרק)<br>
-&#8226; ניתן לשתף פרקים והזנות דרך אפשרויות מתקדמות ברשתות חברתיות ודוא״ל, שירותי gPodder.net ודרך ייצוא OPML<br>
-&#8226; ניתן לתמוך בעורכי תוכן עם שילוב של Flattr לתוך המערכת לרבות תרומה אוטומטית
-
-שליטה במערכת<br>
-&#8226; ניתן לשלוט על הורדה אוטומטית: לבחור הזנות, להחריג רשתות סלולריות, לבחור רשתות אלחוטיות מסוימות, לדרוש מהטלפון להיות בטעינה ולהגדיר מועדים או מרווחי זמן<br>
-&#8226; ניתן לנהל את האחסון על ידי הגדרת כמות הפרקים שנשמרים במטמון, מחיקה חכמה (בהתבסס על המועדפים ומצב הנגינה שלך) ובחירת המיקום המועדף עליך<br>
-&#8226; ניתן להשתמש באנטנה־פּוֹד בשפה שלך (HE, EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; התאמה לסביבה שלך באמצעות ערכות עיצוב בהירה וכהה<br>
-&#8226; גיבוי התמיכה שלך עם שילוב מול gPodder.net וייצוא של OPML
-
-<b>מזמינים אותך להצטרף לקהילת אנטנה־פּוֹד!</b><br>
-את תהליכי הפיתוח הפעילים של אנטנה־פּוֹד מובילים מתנדבים. ניתן לתרום גם כן, עם קוד או עם הערה!
-
-GitHub הוא המקום בו אנו מרכזים את בקשות התכונות, דיווחי התקלות ותרומות הקוד:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-הקבוצה שלנו ב־Google היא המקום לשתף את הרעיונות שלך, רגעי הפודקאסט המועדפים עליך ואת הערכתך לכל המתנדבים:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-יש לך שאלה או שמעניין אותך לתת לנו משוב?
-https://twitter.com/@AntennaPod
-
-Transifex הוא המקום לסייע בתרגומים:<br>
-https://www.transifex.com/antennapod/antennapod
-
-מזמינים אותך לחקור את תכנית הבדיקות שלנו כדי לקבל את התכונות העדכניות ביותר לפני כולם:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/hi-IN/listing/fulldescription b/app/src/main/play/hi-IN/listing/fulldescription
deleted file mode 100644
index f4687b885..000000000
--- a/app/src/main/play/hi-IN/listing/fulldescription
+++ /dev/null
@@ -1,20 +0,0 @@
-ऐन्टेनापॉड एंड्रॉयड 2.3.3 और ऊपर के लिए एक खुला स्रोत पॉडकास्ट प्रबंधक है. यह आपको स्वचालित रूप से सभी फ़ीड ताज़ा या बाद में उन्हें सुनने के लिए एक कतार में जोड़ने, एपिसोड स्ट्रीमिंग और डाउनलोड करने, एक पॉडकैचर से उम्मीद रखने वाली सभी बुनियादी सुविधाएँ प्रदान करता है. इसके अलावा, ऐन्टेनापॉड आपको अनुप्रयोग के भीतर से फ्लेटर पॉडकास्ट और प्रकरणों की सुविधा देता है.
-
-So far the following features are implemented:
-
-* डाउनलोड और एपिसोड के स्ट्रीमिंग
-* चर गति प्लेबैक (सफ़ाई ध्वनि पुस्तकालय या प्रेस्टिसीमो कि आवश्यकता है)
- * एटम और आरएसएस फ़ीड के लिए सहायता
-* Support for password-protected feeds and episodes
-* Support for searching iTunes listings
-* ओएमपीएल आयात और निर्यात
-* Flattr integration including automatic flattring
-* प्लेयर होमस्क्रीन विजेट
-* खोज
-* स्वचालित फ़ीड अद्यतन
-* नए एपिसोड की स्वचालित डाउनलोड
-* स्लीप टाइमर
-* Gpodder.net podcast निर्देशिका के लिए प्रवेश
-* gpodder.net सेवा के साथ सदस्यता सिंक्रनाइज़
-* Supports MP3 chapters, VorbisComment chapters and Podlove Simple Chapters
-* Supports paged feeds (http://podlove.org/paged-feeds/) \ No newline at end of file
diff --git a/app/src/main/play/hi-IN/listing/shortdescription b/app/src/main/play/hi-IN/listing/shortdescription
deleted file mode 100644
index 4eceefbb7..000000000
--- a/app/src/main/play/hi-IN/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Easy-to-use, flexible and open-source podcast manager and player \ No newline at end of file
diff --git a/app/src/main/play/hi-IN/listing/title b/app/src/main/play/hi-IN/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/hi-IN/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/hi_IN/listing/fulldescription b/app/src/main/play/hi_IN/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/hi_IN/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/hu/listing/fulldescription b/app/src/main/play/hu/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/hu/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/id/listing/fulldescription b/app/src/main/play/id/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/id/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/is/listing/fulldescription b/app/src/main/play/is/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/is/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/it-IT/listing/fulldescription b/app/src/main/play/it-IT/listing/fulldescription
deleted file mode 100644
index a88d693e0..000000000
--- a/app/src/main/play/it-IT/listing/fulldescription
+++ /dev/null
@@ -1,40 +0,0 @@
-AntennaPod è un riproduttore e gestore di podcast che ti da accesso immediato a milioni di podcast gratuiti e a pagamento, dai podcaster indipendenti alle più grandi case editrici come BBC, NPR e CNN. Aggiungi, importa e esporta in modo semplici usando il database di podcast di iTunes, da file OPML o da semplici URL RSS. Risparmia fatica, batteria e dati con il potente controllo automatizzato per il download di episodi (orari specifici, intervalli e reti WiFi) e l'eliminazione degli episodi.<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>Funzioni:</b><br>
-IMPORTA, ORGANIZZA E RIPRODUCI<br>
-&#8226; Aggiungi e importa feed via iTunes, gPodder.net, file OPML e link RSS o Atom<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Accedi a feed e episodi protetti da password<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-TIENI TRACCIA, CONDIVIDI & APPREZZA<br>
-&#8226; Tieni traccia del meglio del meglio segnando i tuoi episodi preferiti<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROLLA IL SISTEMA<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Entra nella community di AntennaPod!</b><br>
-AntennaPod è sviluppato da volontari. Anche tu puoi contribuire, con il codice o con dei commenti!
-
-GitHub è il posto nel quale fare richieste, segnalare bug e contribuire allo sviluppo:<br>
-www.github.com/AntennaPod/AntennaPod
-
-Il nostro Gruppo Google è il posto dove condividere le tue idee, podcast preferiti e gratitudine a tutti i nostri volontari:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Transifex è il posto dove puoi aiutare a tradurre AntennaPod:<br>
-www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/it-IT/listing/shortdescription b/app/src/main/play/it-IT/listing/shortdescription
deleted file mode 100644
index bbc1e1f84..000000000
--- a/app/src/main/play/it-IT/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Un riproduttore e gestore di podcast open-source, flessibile e facile da usare \ No newline at end of file
diff --git a/app/src/main/play/it-IT/listing/title b/app/src/main/play/it-IT/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/it-IT/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/it/listing/fulldescription b/app/src/main/play/it/listing/fulldescription
deleted file mode 100644
index 3d0425660..000000000
--- a/app/src/main/play/it/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod è un gestore e player di podcast che ti dà accesso istantaneo a milioni di podcast gratuiti e a pagamento, da podcaster indipendenti a grandi case editrici come BBC, NPR e CNN. Aggiungi, Importa ed esporta facilmente i Feed dal database di iTunes, file OPML oppure semplici collegamenti RSS. Risparmia fatica, batteria e dati con potenti controlli automatici per scaricare gli episodi (specifica orari, intervalli e reti WiFi) ed eliminare gli episodi.<br>
-Ma soprattutto: Scarica, fai Stream o metti in coda gli episodi e goditeli come preferisci cambiando la velocità di riproduzione, saltando tra capitoli e impostando lo sleep timer. Puoi persino mostrare il tuo amore attraverso l'integrazione con Flattr.
-
-Creato da amatori del podcast, AntennaPod è <i>free</i> in tutti i sensi: open-source, nessun costo, nessuna pubblicità.
-
-<b>Tutte le funzioni:</b><br>
-IMPORTA, ORGANIZZA E RIPRODUCI<br>
-&#8226; Aggiungi ed importa i feed tramite i database di iTunes e gPodder.net, file OPML e link RSS o Atom<br>
-&#8226; Gestisci la riproduzione in ogni modo: attraverso il widget per la home, le notifiche di sistema oppure tramite i controlli sulle cuffie, sia cablate che bluetooth<br>
-&#8226; Goditi l'ascolto a modo tuo attraverso la velocità di riproduzione regolabile, il supporto ai capitoli (MP3, VorbisComment e Podlove), la memoria della posizione di riproduzione e un timer di riproduzione avanzato (scuoti per reimpostare, abbassamento del volume e rallentamento di riproduzione)<br>
-&#8226; Accedi a feed ed episodi protetti da password<br>
-&#8226; Approfitta dei <i>paged feeds</i> (www.podlove.org/paged-feeds)
-
-TIENI TRACCIA, CONDIVIDI E APPREZZA<br>
-&#8226; Tieni traccia degli episodi migliori aggiungendoli ai preferiti<br>
-&#8226; Trova episodi specifici nella cronologia di riproduzione o cercando tra titoli e descrizioni<br>
-&#8226; Condividi episodi e feed attraverso le opzioni avanzate di condivisione verso social e emali, i servizi online di gPodder.net e l'esportazione in file OPML<br>
-&#8226; Supporta i creatori attraverso Flattr consentendo anche il <i>flattring</i> automatico
-
-CONTROLLA IL SISTEMA<br>
-&#8226; Prendi il controllo dei download automatici: scegli i Feed, escludi le reti cellulari, seleziona reti WiFi specifiche, attiva solo a telefono in carica e imposta orari e intervalli.<br>
-&#8226; Gestisci la memoria impostando il numero massimo di episodi scaricati, l'eliminazione automatica (basata sui tuoi preferiti e lo stato di riproduzione) e selezionando la tua posizione preferita in memoria<br>
-&#8226; Utilizza AntennaPod nella tua lingua (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adatta all'ambiente usando il tema chiaro e quello scuro<br>
-&#8226; Fai il backup delle tue iscrizione con gPodder.net e l'esportazione OPML
-
-<b>Unisciti alla comunità di AntennaPod!</b><br>
-AntennaPod è in fase attiva di sviluppo da parte di volontari. Anche te puoi contribuire, con codice o commenti!
-
-Per chiedere nuove funzioni, contribuire con del codice o segnalare problemi, puoi trovarci su GitHub:
-https://www.github.com/AntennaPod/AntennaPod
-
-Il nostro Gruppo Google è il posto giusto per condividere le tue idee, i tuoi più bei momenti di podcasting e per mostrare gratitudine ai volontari<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Hai una domanda o vuoi fornirci un feedback?
-https://twitter.com/@AntennaPod
-
-Transifex è il posto in cui aiutare con le traduzioni:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Dai un'occhiata al nostro programma di beta testing per ricevere per primo le funzioni più recenti:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/iw-IL/listing/fulldescription b/app/src/main/play/iw-IL/listing/fulldescription
deleted file mode 100644
index cbbf5de28..000000000
--- a/app/src/main/play/iw-IL/listing/fulldescription
+++ /dev/null
@@ -1,23 +0,0 @@
-אנטנה-פוד הוא מנהל פודקאסט בקוד פתוח עבור אנדרויד 2.3.3 ומעלה. הוא מציע את כל תכונות הבסיסיות שאתה מצפה ממנהל פודקאסטים, כמו הזרמה והורדה של פרקים, ריענון הזנות אוטומטי או הוספת פרקים לתור להאזנה בהמשך. כמו כן, אנטנה-פוד מאפשר לך לתרום דרך flattr פודקאסטים ופרקים מבתוך האפליקציה.
-
-עד כה התכונות הבאות מיושמות:
-
-* הורדה והזרמה של פרקים
-* השמעה במהירות משתנה (דורש ספריית סאונד Presto או Prestissimo)
-* תמיכה בהזנות RSS ו-Atom
-* תמיכה בהזנות ופרקים מוגני ססמה
-* יבוא ויצוא OMPL
-אינטגרציה עם flattr כולל flattr אוטומאטי
-* יישומון נגן למסך הבית
-* חיפוש
-* עידכוני הזנות אוטומטים
-* הורדה אוטמטית של פרקים חדשים
-* טיימר שינה
-*גישה לאינדקס הפודקאסטים gpodder.net
-* סינכרון רישומים עם שירות gpodder.net
-* תמיכה בפרקי MP3, פרקי VorbisComment ופרקי Podlove Simple
-* תמיכה בהזנות מרובות דפים (http://podlove.org/paged-feeds/)
-
-לדווח באגים או משוב, ניתן ליצור סוגיה (issue) בעמוד פרויקט Github (https://github.com/danieloeh/AntennaPod) או לשלוח דואר אלקטרוני לfeedback@antennapod.com. ניתן גם ליצור קשר antennapod@ בטוויטר.
-
-יישום זה הוא ללא תשלום וללא פרסומות. אם אתה רוצה לתמוך באנטנה-פוד, אתה יכול לתרום ב-flattr כאן: flattr.com/thing/745609 \ No newline at end of file
diff --git a/app/src/main/play/iw-IL/listing/shortdescription b/app/src/main/play/iw-IL/listing/shortdescription
deleted file mode 100644
index ad3ccb1f8..000000000
--- a/app/src/main/play/iw-IL/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-An open-source podcast manager for Android \ No newline at end of file
diff --git a/app/src/main/play/iw-IL/listing/title b/app/src/main/play/iw-IL/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/iw-IL/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ja-JP/listing/fulldescription b/app/src/main/play/ja-JP/listing/fulldescription
deleted file mode 100644
index 38f6deffb..000000000
--- a/app/src/main/play/ja-JP/listing/fulldescription
+++ /dev/null
@@ -1,41 +0,0 @@
-AntennaPodは、独自のポッドキャスターから、BBC、NPR、CNNなどの大規模な放送まで、数百万の無料や有料ポッドキャストに瞬時にアクセスすることができる、ポッドキャストマネージャーおよびプレーヤーです。フィードは手間のかからないiTunesのPodcastのデータベース、OPMLファイルや簡単なRSSのURLを使用して追加、インポート、エクスポートします。エピソードのダウンロード (時間、間隔およびWiFiネットワークを指定) とエピソードの削除 (お気に入りと遅延設定に基づいて) をするために強力な自動コントロールで、手間、バッテリ消費、モバイルデータ使用量を節約します。<br>
-しかし最も重要なこと: エピソードをダウンロード、ストリーム再生、またはキューに入れて、そして再生速度の調整、チャプターのサポート、スリープタイマーで好きなように楽しんでください。Flattr統合でコンテンツ作成者にあなたの愛を示すことができます。
-
-ポッドキャスト愛好家が作成した AntennaPod はすべての意味でフリー自由です: オープンソース、コスト不要、広告はありません。
-
-<b>すべての機能:</b><br>
-インポート、整理、再生<br>
-&#8226; iTunesや、gPodder.netディレクトリ、OPMLファイル、RSSまたはAtom経由でフィードを追加およびインポートします<br>
-&#8226; 様々な場所で再生を管理します: ホーム画面ウィジェット、システム通知、イヤホン、Bluetoothコントロール<br>
-&#8226; 再生速度の調整、チャプターのサポート (MP3、VorbisCommentとPodlove)、再生位置の保存、高度なスリープタイマー (シェイクしてリセット、音量を小さく、再生速度を遅く) で、お好みの
-聞き方でお楽しみください<br>
-&#8226; アクセスパスワードで保護されたフィードとエピソード<br>
-&#8226; ページフィードをご利用ください (www.podlove.org/paged-feeds)
-
-記録、共有 & 感謝<br>
-&#8226; エピソードをお気に入りとしてマークして、一番の中の一番を記録してください<br>
-&#8226; 再生履歴から、または検索 (タイトルとショーノート) して目的のエピソードを見つけてください<br>
-&#8226; 高度なソーシャルメディアとメールオプション、gPodder.netサービス、OPMLエクスポートからエピソードやフィードを共有してください<br>
-&#8226; 自動Flattrを含むFlattrの統合でコンテンツクリエイターをサポートします
-
-システムのコントロール
-&#8226; 自動ダウンロードの制御: フィードを選択、モバイルネットワークを除外、特定のWiFiネットワークを選択、電話を充電する必要、時間や間隔を設定<br>
-&#8226; キャッシュされるエピソードの量の設定、スマート削除 (お気に入りやプレイ状況に基づいて) と、お好みの場所を選択して、ストレージを管理します<br>
-&#8226; AntennaPod をあなたの言語でご利用ください (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; ライトとダーク テーマを使用して環境に適応します<br>
-&#8226; gPodder.net統合とOPMLのエクスポートで、購読をバックアップします
-
-<b>AntennaPod のコミュニティに参加してください!</b><br>
-AntennaPod はボランティアによって活発に開発中です。コードやコメントで、あなたもも貢献することができます!
-
-GitHubは、機能のリクエスト、バグの報告、コードの貢献のための場所です:<br>
-www.github.com/AntennaPod/AntennaPod
-
-私たちのGoogleグループは、あなたのアイデア、お気に入りのポッドキャスティングモーメント、感謝を、すべてのボランティアと共有するための場所で:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Transifexは翻訳を支援するための場所です:<br>
-www.transifex.com/antennapod/antennapod
-
-私たちのベータテストプログラムをチェックして、最新機能を最初に入手してください:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ja-JP/listing/title b/app/src/main/play/ja-JP/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/ja-JP/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/kn_IN/listing/fulldescription b/app/src/main/play/kn_IN/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/kn_IN/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ko-KR/listing/fulldescription b/app/src/main/play/ko-KR/listing/fulldescription
deleted file mode 100644
index 7f04d4e7b..000000000
--- a/app/src/main/play/ko-KR/listing/fulldescription
+++ /dev/null
@@ -1,20 +0,0 @@
-안테나팟은 오픈소스 팟캐스트 관리 프로그램입니다. 안드로이드 2.2.3 이상에서 동작합니다. 에피소드의 스트리밍 및 다운로드, 자동으로 피드를 새로 확인하고 나중에 들을 수 있게 대기열에 추가하는 등 팟캐스트 프로그램에서 생각할 수 있는 모든 기본 기능을 지원합니다. 또 안테나팟 앱 안에서 팟캐스트에 대해 Flattr 기부 기능을 사용할 수 있습니다.
-
-지금까지 다음 기능이 구현되었습니다:
-
-* 에피소드 다운로드 및 스트리밍
-* 여러가지 배속 재생(Presto 사운드 라이브러리 또는 Prestissimo 필요)
-* Atom 및 RSS 피드 지원
-* 암호로 보호된 피드와 에피소드 지원
-* iTunes 목록 검색 기능
-* OPML 가져오기 및 내보내기
-* Flattr 통합, 자동으로 Flattr하기 기능 포함
-* 홈스크린 재생 위젯
-* 검색
-* 자동 피드 업데이트
-* 새 에피소드 자동 다운로드
-* 취침 타이머
-* gpodder.net 팟캐스트 디렉터리 찾아보기
-* gpodder.net 서비스와 구독 정보 동기화
-* MP3 챕터, VorbisComment 챕터, Podlove Simple Chapters 기능
-* 페이지 피드 (http://podlove.org/paged-feeds/) 지원 \ No newline at end of file
diff --git a/app/src/main/play/ko-KR/listing/shortdescription b/app/src/main/play/ko-KR/listing/shortdescription
deleted file mode 100644
index 9baa9eb11..000000000
--- a/app/src/main/play/ko-KR/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-안드로이드용 오픈소스 팟캐스트 관리 앱 \ No newline at end of file
diff --git a/app/src/main/play/ko-KR/listing/title b/app/src/main/play/ko-KR/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/ko-KR/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ko/listing/fulldescription b/app/src/main/play/ko/listing/fulldescription
deleted file mode 100644
index 65f20d943..000000000
--- a/app/src/main/play/ko/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-안테나팟을 사용해 소규모 독립 제작자들부터 BBC, NPR, CNN 등의 대형 언론사까지 수많은 무료 및 유료 팟캐스트에 접근할 수 있습니다. iTunes 팟캐스트 데이터베이스, OPML 파일, RSS 주소를 사용해 팟캐스트 피드를 간편하게 추가하고 내보내고 가져올 수 있습니다. 강력한 자동 다운로드 제어(특정 시간 간격 및 Wi-Fi 네트워크 지정)와 삭제 제어(즐겨찾기 및 지연 설정에 기반한)를 통해 편리하게 배터리와 모바일 데이터 사용량을 줄이세요.<br>
-하지만 가장 중요한 기능은: 에피소드를 다운로드하거나 스트리밍하거나 대기열을 만들고, 재생 속도 조절, 챕터 지원, 취침 타이머를 통해 원하는대로 즐길 수 있다는 점입니다. 내장된 Flattr 지원을 통해 팟캐스트 제작자들에게 호응을 보낼 수도 있습니다.
-
-팟캐스트 애호가에 의해 만들어진, 안테나팟은 모든 면에서 자유롭습니다: 소스 코드가 공개되어 있고, 무료인데다가 광고도 없습니다.
-
-<b>모든 기능:</b><br>
-가져오기, 관리하기, 재생하기<br>
-&#8226; iTunes, gPodder.net, OPML 파일, RSS 및 Atom 링크를 통해 피드를 추가하거나 가져올 수 있습니다.<br>
-&#8226; 재생을 어디에서나 관리할 수 있습니다: 홈스크린 위젯, 시스템 알림, 이어폰 및 블루투스 컨트롤<br>
-&#8226; 배속 재생 지원, 챕터 지원(MP3, VorbisComment, Podlove), 마지막 재생 위치 기억, 고급 취침 타이머(흔들어서 초기화, 볼륨 낮추기, 재생 느리게 하기) 등의 기능으로 팟캐스트를 즐기세요<br>
-&#8226; 암호로 보호된 피드와 에피소드에 접근<br>
-&#8226; 페이지로 구분된 피드 활용 (www.podlove.org/paged-feeds)
-
-기록하고, 공유하고, 호응하기<br>
-&#8226; 가장 좋아하는 팟캐스트 에피소드를 즐겨찾기로 저장<br>
-&#8226; 에피소드를 재생 기록 또는 검색(제목 및 노트)으로 찾기<br>
-&#8226; 에피소드와 피드를 SNS, 이메일, gPodder.net, OPML 내보내기로 공유<br>
-&#8226; 자동으로 Flattr하기 등의 Flattr 기능으로 팟캐스트 제작자 지원
-
-시스템 컨트롤
-&#8226; 자동 다운로드를 제어하세요: 피드를 고르고, 모바일 네트워크를 제외시키고, 특정 Wi-Fi 네트워크를 선택하고, 기기가 충전중일때만 다운로드하게 하고, 시간과 간격을 정하세요<br>
-&#8226; 에피소드 캐시 용량, 똑똑한 삭제(즐겨찾기와 재생 상태에 기반), 선호하는 저장 위치 등으로 저장소를 관리하세요<br>
-&#8226; 여러가지 언어로 안테나팟을 사용하세요 (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; 밝음 및 어두움 테마로 환경에 맞춰 사용하세요<br>
-&#8226; gPodder.net과 OPML 내보내기 기능으로 구독한 팟캐스트를 백업하세요
-
-<b>안테나팟 커뮤니티에 참여하세요!</b><br>
-안테나팟은 지원자들에 의해 활발히 개발되고 있습니다. 당신도 제작을 돕거나 제안을 해서 참여할 수 있습니다!
-
-GitHub에서 새로운 기능 제안, 버그 보고, 그리고 코드 기여를 할 수 있습니다.:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-구글 그룹에서 아이디어와 좋은 팟캐스트를 공유하고 모든 지원자들에게 감사할 수 있습니다:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-질문이 있으신가요? 아니면 의견이 있으신가요?
-https://twitter.com/@AntennaPod
-
-Transifex에서 번역을 도울 수 있습니다:<br>
-https://www.transifex.com/antennapod/antennapod
-
-베타 테스트 프로그램을 통해 최신 기능을 가장 먼저 확인해보세요:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ko_KR/listing/fulldescription b/app/src/main/play/ko_KR/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/ko_KR/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/de/listing/fulldescription b/app/src/main/play/listings/de-DE/full-description.txt
index 0e09c5c29..f312ea559 100644
--- a/app/src/main/play/de/listing/fulldescription
+++ b/app/src/main/play/listings/de-DE/full-description.txt
@@ -1,4 +1,4 @@
-AntennaPod ist ein Podcast-Manager und -Player, der Dir unmittelbar Zugriff auf Millionen von freien und kostenpflichtigen Podcasts ermöglicht, angefangen von unabhängigen Podcastern bis hin zu großen Rundfunkanstalten wie BBC, NPR und CNN. Abonniere, importiere und exportiere deine Feeds mühelos mit Hilfe des iTunes-Verzeichnisses, OPML-Dateien oder einfachen RSS-URLs. Reduziere Aufwand, Stromverbrauch und Datenverbrauch durch die Kontrolle der Downloads (bestimmte Uhrzeiten, Intervalle, WiFi-Netze) und des Löschens von Episoden (basierend auf deinen Favoriten und weiteren Einstellungen).<br>
+AntennaPod ist ein Podcast-Manager und -Player, der dir unmittelbar Zugriff auf Millionen von freien und bezahlten Podcasts ermöglicht, angefangen von unabhängigen Podcastern zu großen Rundfunkanstalten oder Hörfunksendern wie BBC, NPR und CNN. Abonniere, importiere und exportiere deine Feeds mühelos mit Hilfe des iTunes-Verzeichnisses, OPML-Dateien oder einfachen RSS-URLs. Reduziere Aufwand, Stromverbrauch und Datenverbrauch durch die Kontrolle der Downloads (bestimmte Uhrzeiten, Intervalle, WiFi-Netze) und des Löschens (basierend auf deinen Favoriten und weiteren Einstellungen).
Aber am wichtigsten: Downloade, streame oder füge Episoden zur Abspielliste hinzu und genieße sie mit einstellbarer Abspielgeschwindigkeit, Unterstützung von Kapiteln und Schlummerfunktion. Mit Flattr kannst du den Podcastern sogar deine Wertschätzung zeigen.
AntennaPod ist, von Podcast-Enthusiasten gemacht, frei im Sinne des Wortes: Open Source, keine Kosten, keine Werbung.
diff --git a/app/src/main/play/de-DE/listing/shortdescription b/app/src/main/play/listings/de-DE/short-description.txt
index cc5ca9df6..cc5ca9df6 100644
--- a/app/src/main/play/de-DE/listing/shortdescription
+++ b/app/src/main/play/listings/de-DE/short-description.txt
diff --git a/app/src/main/play/en-US/listing/fulldescription b/app/src/main/play/listings/en-US/full-description.txt
index 87b477fdc..c562387af 100644
--- a/app/src/main/play/en-US/listing/fulldescription
+++ b/app/src/main/play/listings/en-US/full-description.txt
@@ -1,5 +1,5 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
+AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based on your favourites and delay settings).<br>
+But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer.
Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
@@ -15,7 +15,6 @@ KEEP TRACK, SHARE & APPRECIATE<br>
&#8226; Keep track of the best of the best by marking episodes as favourites<br>
&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
CONTROL THE SYSTEM<br>
&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
@@ -40,4 +39,4 @@ Transifex is the place to help with translations:<br>
https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod
diff --git a/app/src/main/play/en-US/listing/featureGraphic/feature-graphic.png b/app/src/main/play/listings/en-US/graphics/feature-graphic/feature-graphic.png
index 3b5261b28..3b5261b28 100644
--- a/app/src/main/play/en-US/listing/featureGraphic/feature-graphic.png
+++ b/app/src/main/play/listings/en-US/graphics/feature-graphic/feature-graphic.png
Binary files differ
diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/00.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/00.png
index 9cc754f22..9cc754f22 100644
--- a/app/src/main/play/en-US/listing/phoneScreenshots/00.png
+++ b/app/src/main/play/listings/en-US/graphics/phone-screenshots/00.png
Binary files differ
diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/01.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/01.png
index 3ec9ceadf..3ec9ceadf 100644
--- a/app/src/main/play/en-US/listing/phoneScreenshots/01.png
+++ b/app/src/main/play/listings/en-US/graphics/phone-screenshots/01.png
Binary files differ
diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/02.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/02.png
index 020fa9a01..020fa9a01 100644
--- a/app/src/main/play/en-US/listing/phoneScreenshots/02.png
+++ b/app/src/main/play/listings/en-US/graphics/phone-screenshots/02.png
Binary files differ
diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/03.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/03.png
index f860032c3..f860032c3 100644
--- a/app/src/main/play/en-US/listing/phoneScreenshots/03.png
+++ b/app/src/main/play/listings/en-US/graphics/phone-screenshots/03.png
Binary files differ
diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/04.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/04.png
index be012eead..be012eead 100644
--- a/app/src/main/play/en-US/listing/phoneScreenshots/04.png
+++ b/app/src/main/play/listings/en-US/graphics/phone-screenshots/04.png
Binary files differ
diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/05.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/05.png
index 379ad27eb..379ad27eb 100644
--- a/app/src/main/play/en-US/listing/phoneScreenshots/05.png
+++ b/app/src/main/play/listings/en-US/graphics/phone-screenshots/05.png
Binary files differ
diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/06.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/06.png
index b73d58d40..b73d58d40 100644
--- a/app/src/main/play/en-US/listing/phoneScreenshots/06.png
+++ b/app/src/main/play/listings/en-US/graphics/phone-screenshots/06.png
Binary files differ
diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/07.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/07.png
index 61246306f..61246306f 100644
--- a/app/src/main/play/en-US/listing/phoneScreenshots/07.png
+++ b/app/src/main/play/listings/en-US/graphics/phone-screenshots/07.png
Binary files differ
diff --git a/app/src/main/play/ca/listing/shortdescription b/app/src/main/play/listings/en-US/short-description.txt
index 4eceefbb7..acf136ae9 100644
--- a/app/src/main/play/ca/listing/shortdescription
+++ b/app/src/main/play/listings/en-US/short-description.txt
@@ -1 +1 @@
-Easy-to-use, flexible and open-source podcast manager and player \ No newline at end of file
+Easy-to-use, flexible and open-source podcast manager and player
diff --git a/app/src/main/play/ca/listing/title b/app/src/main/play/listings/en-US/title.txt
index 31552f353..31552f353 100644
--- a/app/src/main/play/ca/listing/title
+++ b/app/src/main/play/listings/en-US/title.txt
diff --git a/app/src/main/play/fr/listing/fulldescription b/app/src/main/play/listings/fr-FR/full-description.txt
index 372e1da60..372e1da60 100644
--- a/app/src/main/play/fr/listing/fulldescription
+++ b/app/src/main/play/listings/fr-FR/full-description.txt
diff --git a/app/src/main/play/fr-FR/listing/shortdescription b/app/src/main/play/listings/fr-FR/short-description.txt
index 61c3c7e20..61c3c7e20 100644
--- a/app/src/main/play/fr-FR/listing/shortdescription
+++ b/app/src/main/play/listings/fr-FR/short-description.txt
diff --git a/app/src/main/play/gl/listing/fulldescription b/app/src/main/play/listings/gl-ES/full-description.txt
index c26d4078c..c275c1fc2 100644
--- a/app/src/main/play/gl/listing/fulldescription
+++ b/app/src/main/play/listings/gl-ES/full-description.txt
@@ -1,4 +1,4 @@
-AntennaPod é un xestor e repordutor de podcast que lle permite acceder a millóns de podcast gratuítos e de pago, desde emisións independentes a grandes produtores como BBC, NPR e CNN. Engadir, importar e exportar as súas fontes sen problemas utilizando a base de datos de iTunes, fiecheiros OPML o simples URLs de RSS. Aforre esforzos, consumo de batería e datos móbiles con un control total e automático das descargas de episodios (indique horarios, intervalos e redes WIFI) e eliminación de episodios (basándose nas preferencias de favoritos e retardo).<br>
+AntenaPod é un xestor de podcast e reprodutor que lle da acceso a millóns de podcast tanto gratuítos como de pagamento, desde podcasters independentes a grandes productores como BBC, NPR e CNN. Engada, importe e exporte as súas fontes de xeito doado utilizando a base de datos de iTunes, ficheiros OPML ou URLs RSS. Aforre traballo, enerxía da batería e datos móbiles co sistema automatizado de control das descargas de episodios (indicando horario, intervalos e redes WiFi) e borrando episodios (baseado nos seus favoritos e axustes de retardo).<br>
Mais o máis importante: Descargue, envíe ou poña na cola os episodios e disfrúteos do xeito en que máis lle conveña, axustando a velocidade de reprodución, xestión de capítulos e apagado automático. Poderá tamén mostrarlle aos creadores canto lle gustan os seus contidos gracias a integración con Flattr.
Escrito por namorados dos podcast, AntennaPod é gratuíto e libre: open source, sen custos, sen publicidade.
diff --git a/app/src/main/play/listings/gl-ES/short-description.txt b/app/src/main/play/listings/gl-ES/short-description.txt
new file mode 100644
index 000000000..755ae7c13
--- /dev/null
+++ b/app/src/main/play/listings/gl-ES/short-description.txt
@@ -0,0 +1 @@
+Xestor de podcast e reprodutor doado de utilizar, flexible e de código aberto \ No newline at end of file
diff --git a/app/src/main/play/it_IT/listing/fulldescription b/app/src/main/play/listings/it-IT/full-description.txt
index 31fa64d69..978ae2d46 100644
--- a/app/src/main/play/it_IT/listing/fulldescription
+++ b/app/src/main/play/listings/it-IT/full-description.txt
@@ -1,4 +1,4 @@
-AntennaPod è un riproduttore e gestore di podcast che ti da accesso immediato a milioni di podcast gratuiti e a pagamento, dai podcaster indipendenti alle più grandi emittenti come BBC, NPR e CNN. Aggiungi, importa e esporta in modo semplici usando il database di podcast di iTunes, da file OPML o da semplici URL RSS. Risparmia fatica, batteria e dati con il potente controllo automatizzato per il download di episodi (orari specifici, intervalli e reti WiFi) e l'eliminazione degli episodi.<br>
+AntennaPod è un riproduttore e gestore di podcast che ti da accesso immediato a milioni di podcast gratuiti e a pagamento, dai podcaster indipendenti alle più grandi emittenti come BBC, NPR e CNN. Aggiungi, importa e esporta in modo semplice usando il database di podcast di iTunes, un file OPML o i semplici URL RSS. Risparmia fatica, batteria e dati con il potente controllo automatizzato per il download di episodi (orari specifici, intervalli e reti WiFi) e dell'eliminazione degli episodi (basata sui preferiti e le impostazioni di eliminazione personali).<br>
Ancora più importante: scarica, ascolta in streaming o metti in coda gli episodi e goditeli quando e come vuoi grazie alla velocità di riproduzione personalizzabile, al supporto per i capitoli e al timer di spegnimento. Puoi anche ringraziare i creatori di contenuti grazie all'integrazione con Flattr.
Creato da amanti dei podcast, AntennaPod è libero in tutti i sensi: open source, gratis, senza pubblicità.
diff --git a/app/src/main/play/listings/it-IT/short-description.txt b/app/src/main/play/listings/it-IT/short-description.txt
new file mode 100644
index 000000000..a3c6e1c33
--- /dev/null
+++ b/app/src/main/play/listings/it-IT/short-description.txt
@@ -0,0 +1 @@
+Riproduttore e gestore di podcast facile da usare, flessibile e open source. \ No newline at end of file
diff --git a/app/src/main/play/ja/listing/fulldescription b/app/src/main/play/listings/ja-JP/full-description.txt
index b85f6787e..b85f6787e 100644
--- a/app/src/main/play/ja/listing/fulldescription
+++ b/app/src/main/play/listings/ja-JP/full-description.txt
diff --git a/app/src/main/play/ja-JP/listing/shortdescription b/app/src/main/play/listings/ja-JP/short-description.txt
index 6872efb2b..8a8011bb1 100644
--- a/app/src/main/play/ja-JP/listing/shortdescription
+++ b/app/src/main/play/listings/ja-JP/short-description.txt
@@ -1 +1 @@
-使いやすくて柔軟な、オープンソース ポッドキャスト マネージャー/プレイヤーです。 \ No newline at end of file
+使いやすくて柔軟な、オープンソース ポッドキャスト マネージャー/プレイヤー \ No newline at end of file
diff --git a/app/src/main/play/nl/listing/fulldescription b/app/src/main/play/listings/nl-NL/full-description.txt
index 736a3f3a5..6c6ef1e8a 100644
--- a/app/src/main/play/nl/listing/fulldescription
+++ b/app/src/main/play/listings/nl-NL/full-description.txt
@@ -1,4 +1,4 @@
-Met AntennaPod speel en beheer je al je podcasts en krijg je directe toegang tot duizenden gratis en betaalde podcasts - van onafhankelijke makers tot grote merken zoals BBC, CNN en NPO. Via de iTunes database, OPML-bestanden en simpele RSS-linkjes voeg je deze podcasts makkelijk toe. Dankzij simpele maar slimme automatische controle van het downloaden en verwijderen van afleveringen spaar je je batterij, hoef je je favoriete podcast niet meer handmatig te volgen en verbruik je geen onnodig mobiele data.<br>
+Met AntennaPod speel en beheer je al je podcasts en krijg je directe toegang tot duizenden gratis en betaalde podcasts - van onafhankelijke makers tot grote merken zoals BBC, CNN en NPO. Via de iTunes-databank, OPML-bestanden en simpele RSS-linkjes voeg je deze podcasts gemakkelijk toe. Dankzij simpele maar slimme automatische controle van het downloaden en verwijderen van afleveringen bespaar je de accu, hoef je je favoriete podcast niet meer handmatig te volgen en verbruik je geen onnodige mobiele gegevens.<br>
Maar belangrijker: Met een handige wachtrij, aanpasbare afspeelsnelheden, ondersteuning van hoofdstukken en een slaap timer luister je naar podcasts op de manier die jij prettig vindt. Je kunt zelfs je liefde voor de makers uiten met onze Flattr-integratie.
Gemaakt door podcast-enthousiastelingen, AntennaPod is vrij in de breedste zin van het woord: vrij van advertenties, open source en gratis.
diff --git a/app/src/main/play/listings/nl-NL/short-description.txt b/app/src/main/play/listings/nl-NL/short-description.txt
new file mode 100644
index 000000000..31c66d634
--- /dev/null
+++ b/app/src/main/play/listings/nl-NL/short-description.txt
@@ -0,0 +1 @@
+Gemakkelijk te gebruiken, flexibele en open-source podcastbeheerder en -speler \ No newline at end of file
diff --git a/app/src/main/play/listings/zh-CN/short-description.txt b/app/src/main/play/listings/zh-CN/short-description.txt
new file mode 100644
index 000000000..ab28b4df7
--- /dev/null
+++ b/app/src/main/play/listings/zh-CN/short-description.txt
@@ -0,0 +1 @@
+简单易用、灵活的开源播客管理工具与播放器 \ No newline at end of file
diff --git a/app/src/main/play/lt/listing/fulldescription b/app/src/main/play/lt/listing/fulldescription
deleted file mode 100644
index 3f9f50a90..000000000
--- a/app/src/main/play/lt/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-„AntennaPod“ yra tinklalaidžių tvarkytuvė ir leistuvė, įgalinanti momentinę prieigą prie milijonų nemokamų bei mokamų tinklalaidžių, nuo nepriklausomų tinklalaidžių kūrėjų iki didžiųjų leidyklų, tokių kaip „BBC“, „NPR“ ir „CNN“. Be vargo pridėkite, importuokite ir eksportuokite jų sklaidos kanalus naudodamiesi „iTunes“ tinklalaidžių duomenų baze, OPML failais ar tiesiogiai iš RSS kanalo adreso. Sutaupykite laiko, baterijos energijos ir suvartojamų mobiliųjų duomenų išnaudodami galingas automatinio epizodų atsiuntimo priemones (nurodykite atsiuntimo metą, laiko intervalą ir belaidžius tinklus) ir ištrindami epizodus (remiantis mėgiamųjų sąrašu ir laikymo nustatymais).<br>
-Bet svarbiausia: atsisiųskite, klausykitės iš karto ar pridėkite epizodus į eilę ir mėgaukitės jais pasirinkdami atkūrimo spartą, naudodamiesi skyrių palaikymu bei miego laikmačiu. Jūs netgi galite išreikšti savo meilę turinio kūrėjams naudodamiesi mūsų „Flattr“ integracija.
-
-Sukurtas tinklalaidžių entuziasto, „AntennaPod“ yra laisvas visomis šio žodžio prasmėmis: atvirojo kodo, jokių mokesčių, jokių reklamų.
-
-<b>Visos funkcijos:</b><br>
-IMPORTUOKITE, TVARKYKITE BEI KLAUSYKITĖS<br>
-&#8226; Pridėkite bei importuokite sklaidos kanalus iš „iTunes“ bei „gPodder.net“ paslaugų, OPML failų ir RSS ar Atom nuorodų<br>
-&#8226; Valdykite atkūrimą bet kur: pradžios ekrano valdyklyje, programos pranešimuose, ausinių ar „Bluetooth“ valdikliu<br>
-&#8226; Mėgaukitės klausydamiesi taip, kaip Jums patinka, naudodamiesi derinama atkūrimo sparta, skyrių palaikymu (MP3, „VorbisComment“ ir „Podlove“), išsaugota paskutinio atkūrimo pozicija ir miego laikmačiu (mažinamas garsis bei lėtinama atkūrimo sparta, pakračius nustatomas iš naujo)<br>
-&#8226; Pasiekite slaptažodžiu apsaugotus sklaidos kanalus bei epizodus<br>
-&#8226; Išnaudokite puslapiuotus sklaidos kanalus (www.podlove.org/paged-feeds)
-
-STEBĖKITE, DALINKITĖS IR MĖGAUKITĖS<br>
-&#8226; Kaupkite geriausius iš geriausiųjų pažymėdami epizodus kaip mėgstamiausius<br>
-&#8226; Raskite tą vienintelį epizodą naudodamiesi atkūrimo istorija arba paieška (pavadinimuose ir laidų užrašuose)<br>
-&#8226; Dalinkitės epizodais bei sklaidos kanalais per socialinius tinklus, el. paštu, „gPodder.net“ paslaugą bei eksportuotus OPML failus<br>
-&#8226; Remkite turinio kūrėjus naudodamiesi „Flattr“ integracija bei automatiniu rėmimu
-
-VALDYKITE SISTEMĄ<br>
-&#8226; Valdykite automatinį atsiuntimą: pasirinkite sklaidos kanalus, neleiskite atsiuntimų mobiliuoju duomenų ryšiu, apibrėžkite leidžiamus belaidžio ryšio tinklus, reikalaukite, jog atsiuntimai būtų vykdomi telefono įkrovos metu ir nurodykite atsiuntimų dienos metą ar intervalą<br>
-&#8226; Valdykite atmintinės naudojimą nurodydami podėlyje laikomų epizodų kiekį, išmanų ištrynimą (remiantis atkūrimo būsena bei mėgiamųjų sąrašu) ir nurodykite saugojimo vietą<br>
-&#8226; Naudokitės „AntennaPod“ savo kalba (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH, LT)<br>
-&#8226; Pritaikykite savo aplinkai pasirinkdami šviesią arba tamsią temą<br>
-&#8226; Sukurkite savo prenumeratų atsarginę kopiją pasinaudodami „gPodder.net“ integracija arba OPML eksportu
-
-<b>Prisijunkite prie AntennaPod bendruomenės!</b><br>
-„AntennaPod“ aplikaciją aktyviai vysto savanoriai. Jūs taip pat galite prisidėti, nuo atsiliepimų iki programinio kodo!
-
-„GitHub“ yra ta vieta, kur galite pageidauti naujų funkcijų, pranešti apie riktą arba prisidėti programiniu kodu:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Mūsų „Google“ grupė yra puiki vieta pasidalinti idėjomis, mėgstamiausiais tinklalaidžių sklaidos momentais ar išreikšti padėką visiems savanoriams:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Turite klausimų ar norite palikti atsiliepimą?
-https://twitter.com/@AntennaPod
-
-„Transifex“ yra ta vieta, kur galite prisidėti prie aplikacijos vertimo:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Išbandykite mūsų Beta Testavimo programą, jei norite pirmieji gauti naujausias funkcijas:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ms_MY/listing/fulldescription b/app/src/main/play/ms_MY/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/ms_MY/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/nb/listing/fulldescription b/app/src/main/play/nb/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/nb/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/nb_NO/listing/fulldescription b/app/src/main/play/nb_NO/listing/fulldescription
deleted file mode 100644
index 460a880fe..000000000
--- a/app/src/main/play/nb_NO/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-Men viktigst av alt: Last ned, strøm eller legg episoder i kø og nyt dem slik du ønsker med regulerbar avspillingshasitghet, kapittelstøtte og en tidtaker for automatisk avslåing. Du kan til og med vise din takknemlighet til innholdets skapere med vår Flattr-integrasjon.
-
-Laget av podkast-entusiaster er AntennaPod gratis i ordets rette forstand: åpen kildekode, ingen kostnader, ingen reklame.
-
-<br>Alle funksjoner:</b></b>
-IMPORTER, ORGANISER OG SPILL AV<br>
-&#8226; Legg til og importer strømmer fra mapper fra iTunes og gPodder.net, OPML-filer og linker fra RSS og Atom<br>
-&#8226; Behandle avspillinger fra hvor som helst: widget på startskjerm, systemnotifikasjoner og ørepropp- og bluetoothkontroller<br>
-&#8226; Nyt det å høre på din måte med regulerbar avspillingshastighet, kapittelstøtte (MP3, VorbisComment og Podlove), husket avspillingsposisjon og en avansert tidtaker for automatisk avslåing (rist for å tilbakestille, senke volumet og sakke ned avspillingen)<br>
-&#8226; Støtte for passordbeskyttede strømmer og episoder<br>
-&#8226; Støtte for &#171;paged feeds&#187; (www.podlove.org/paged-feeds)
-
-FØLG MED, DEL OG SETT PRIS PÅ<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find den ene episoden gjennom avspillingshistorien eller ved å søke (titler og shownotater)<br>
-&#8226; Del episoder og strømmer gjennom avanserte sosiale medier- og e-postinstillinger, gPodder.net-tjenester og via OPML-eksportering<br>
-&#8226; Støtt innholdsskapere med Flattr-integrasjon gjennom automatisk &#171;flattring&#187;
-
-KONTROLLER SYSTEMET<br>
-&#8226; Ta kontroll over automatiske nedlastninger: velg feeds, ekskluder mobil tilkobling, spesifiser Wifi-nettverk, krev at telefonen er tilkoblet lader, sett tidspunk eller intervaller<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Bruk AntennaPod i ditt språk (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Tilpass appens stil ved å bruke det mørke eller lyse temaet<br>
-&#8226; Lag back-up av dine abonnement med gPodder.net-integrasjon og OPML-eksport
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod er under aktiv utvikling av frivillige. Du kan også bidra, med kode eller kommentarer!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Har du spørsmål eller vil du gi oss tilbakemelding?
-https://twitter.com/@AntennaPod
-
-Transifex er stedet for å hjelpe til med oversettinger:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Sjekk ut vårt program for betatesting for å få de nyeste funksjonene først:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/nl-NL/listing/fulldescription b/app/src/main/play/nl-NL/listing/fulldescription
deleted file mode 100644
index 52a2d4337..000000000
--- a/app/src/main/play/nl-NL/listing/fulldescription
+++ /dev/null
@@ -1,20 +0,0 @@
-AntennaPod is een open-source podcast manager voor Android 2.3.3 en hoger. Het biedt alle basisfuncties die u verwacht van een podcatcher, zoals streaming en downloaden van episodes, alle feeds automatisch verversen of episodes aan een wachtrij toevoegen om ze later te luisteren. Bovendien laat AntennaPod je podcasts en afleveringen vanuit de app flattr'en.
-
-So far the following features are implemented:
-
-* Episodes downloaden en streamen
-* Variabele afspeelsnelheid (vereist Presto Sound Library of Prestissimo)
-* Support voor Atom en RSS feeds
-* Ondersteuning voor wachtwoord-beveiligde feeds en afleveringen
-* Support for searching iTunes listings
-* OPML import en export
-* Flattr integration including automatic flattring
-* Homescreen widget voor de player
-* Zoekfunctie
-* Automatische feed updates
-* Automatisch downloaden van nieuwe episodes
-* Sleep timer
-* Toegang tot de gpodder.net podcast gids
-* Abonnementen synchroniseren met de gpodder.net dienst
-* Supports MP3 chapters, VorbisComment chapters and Podlove Simple Chapters
-* Supports paged feeds (http://podlove.org/paged-feeds/) \ No newline at end of file
diff --git a/app/src/main/play/nl-NL/listing/shortdescription b/app/src/main/play/nl-NL/listing/shortdescription
deleted file mode 100644
index 4eceefbb7..000000000
--- a/app/src/main/play/nl-NL/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Easy-to-use, flexible and open-source podcast manager and player \ No newline at end of file
diff --git a/app/src/main/play/nl-NL/listing/title b/app/src/main/play/nl-NL/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/nl-NL/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/no/listing/fulldescription b/app/src/main/play/no/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/no/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/pl-PL/listing/fulldescription b/app/src/main/play/pl-PL/listing/fulldescription
deleted file mode 100644
index 795addbc5..000000000
--- a/app/src/main/play/pl-PL/listing/fulldescription
+++ /dev/null
@@ -1,20 +0,0 @@
-AntennaPod jest menadżerem podcastów dla Androida 2.3.3 i nowszych na otwartej licencji. Oferuje wszystkie podstawowe funkcje których oczekuje się od podcathera, takie jak strumieniowanie oraz pobieranie odcinków, odświeżanie wszystkich wątków automatycznie i dodawanie ich do kolejki do późniejszego odsłuchania. Oprócz tego AntennaPod pozwala na flattr-owanie podcastów i odcinków z poziomu aplikacji.
-
-Dotychczas zostały wdrożone następujące funkcjonalności:
-
-* Pobieranie i strumieniowanie odcinków
-* Zmienna prędkość odtwarzania (wymaga Presto Sound Library lub Prestissimo)
-* Wsparcie dla wątków Atom i RSS
-* Wsparcie dla kanałów i odcinków zabezpieczonych hasłem
-* Support for searching iTunes listings
-* Import i eksport OPML
-Integracja z serwisem Flattr umożliwiająca flattring
-* Widget odtwarzacza na home screen
-* Wyszukiwanie
-* Automatyczne aktualizaje wątków
-* Automatyczne pobieranie nowych odcinków
-* Timer snu
-* Dostęp do katalogu podcastów na gpodder.net
-* Synchronizację subskrypcji z gpodder.net
-* Obsługuje rodziały MP3, VorbisComment i Podlove Simple.
-* Wspiera stronicowane kanały (http://podlove.org/paged-feeds/) \ No newline at end of file
diff --git a/app/src/main/play/pl-PL/listing/shortdescription b/app/src/main/play/pl-PL/listing/shortdescription
deleted file mode 100644
index 4eceefbb7..000000000
--- a/app/src/main/play/pl-PL/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Easy-to-use, flexible and open-source podcast manager and player \ No newline at end of file
diff --git a/app/src/main/play/pl-PL/listing/title b/app/src/main/play/pl-PL/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/pl-PL/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/pl/listing/fulldescription b/app/src/main/play/pl/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/pl/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/pl_PL/listing/fulldescription b/app/src/main/play/pl_PL/listing/fulldescription
deleted file mode 100644
index c2c8cc597..000000000
--- a/app/src/main/play/pl_PL/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod jest programem katalogującym i odtwarzającym który daje możliwość natychmiastowego dostępu do milionów darmowych i płatnych podcastów. Od niezależych twórców po wielkich producentów takich jak BBC, NPR czy CNN. Dodawaj, importuj, eksportuj wątki bez przeszkód używając bazy iTunes, plików OPML czy po prostu przez linki RSS. Oszczędź wysiłek, baterię oraz pakiety danych mobilnych poprzez zaawansowaną kontrolę automatycznego pobierania (określone godziny, interwały czy sieci WiFi) oraz inteligentne usuwanie odcinków ( na podstawie ulubionych i ustawień opóźnień).<br>
-Najważniejsze: pobieraj , streamuj lub kolejkuj odcinki oraz rozkoszuj się nimi jak tylko chcesz z możliwością zmiany prędkości odtwarzania, wsparciem rozdziałów i wyłącznikiem czasowym. Możesz nawet pokazać jak bardzo doceniach twórców dzięki integracji z Flattr.
-
-Stworzone przez entuzjastów podcastów, AntennaPod jest darmowe w każdym słowa znaczeniu: otwarty kod, brak opłat i reklam.
-
-<b>Wszystkie funkcje:</b><br>
-ZAIMPORTUJ, ZORGANIZUJ I ODTWARZAJ<br>
-&#8226; Dodawaj i importuj kanały poprzez iTunes, gPodder.net, z plików OPML, RSS i linków Atom<br>
-&#8226; Zarządzaj odtwarzaniem zewsząd: widget na ekranie głównym, powiadomienia systemowe i kontrolery bluetooth<br>
-&#8226; Delektuj się słuchaniem po swojemu z: zmienną prędkością odtwarzania, wsparciem rozdziałów (MP3, VorbisComment i Podlove), zapamiętywaniem miejsca zakończenia słuchania i zaawansowanym wyłącznikiem czasowym (potrząśnij aby zrestartować, zmiejszanie głośności i zwalnianie odtwarzania) <br>
-&#8226; Dostęp do odcinków i kanałów chroniony hasłem<br>
-&#8226; Wykorzystaj zapisane kanały (www.podlove.org/paged-feeds)
-
-ŚLEDŹ, DZIEL SIĘ I DOCENIAJ<br>
-&#8226; Zapamiętywanie najlepszych z najlepszych poprzez dodawania odcinków do ulubionych<br>
-&#8226; Wyszukiwanie odcinów w historii odtwarzania lub poprzez tytuł/przypisy<br>
-&#8226; Dzial się odcinkami i wątkami poprzez zaawansowane opcje medii społecznych oraz emaila, serwisu gPodder.net lub poprzez eksport do OPML<br>
-&#8226; Wsparcie twórców poprzez integrację z Flattr, również poprzez automatyczne flattr-owanie
-
-Kontroluj system<br>
-&#8226; Ustaw automatyczne pobieranie zgodnie z własnymi preferencjami: wybieranie wątków, pobieranie tylko przez WiFi, wybór określonych sieci WiFi, wymaganie ładowania przy pobieraniu oraz ustawienie harmonogramu i interwałów<br>
-&#8226; Zarządanie pamięcią poprzez ustawienia liczby pobranych odcinków z pomocą inteligentnego kasowania( na podstawie ulubionych i statusu odtwarzania) oraz wyboru lokalizacji<br>
-&#8226; Używaj AntennaPod w swoim języku (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Dostosowanie wyglądu jasną i ciemną skórką<br>
-&#8226; Twórz kopie bezpieczeństwa swoich subskrypcji z pomocą zintegrowanego gPoddder.net oraz plików OPML
-
-<b>Dołącz do społeczności AntennaPod</b><br>
-AntennaPod jest ciągle rozwijane przez ochotników. Ty też możesz pomóc, kodem lub komentarzem!
-
-Sugestie ulepszeń, raporty błędów oraz dodatki do kodu prosimy kierować poprzez GitHub<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Nasza grupa Google jest miejsce do dzielenia się pomysłami, ulubionymi momentami podcastów oraz miejscem gdzie można podziękować ochotnikom za ich pracę:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Masz pytanie lub chcesz przekazać nam swoją opinię ?
-https://twitter.com/@AntennaPod
-
-Pomoc w tłumaczeniach na Transifex:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Jeśli chcesz otrzymywać najnowsze ulepszenia wcześniej niż inni rozważ dołączenie do programu beta testów:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/pt-BR/listing/fulldescription b/app/src/main/play/pt-BR/listing/fulldescription
deleted file mode 100644
index 735334e0c..000000000
--- a/app/src/main/play/pt-BR/listing/fulldescription
+++ /dev/null
@@ -1,40 +0,0 @@
-O AntennaPod é um gestor de podcasts que lhe permite aceder a milhões de podcasts (gratuitos ou pagos), a partir de diversas fontes tais como as estações BBC, NPR e CNN. A adição de fontes é muito fácil através das base de dados iTunes ou gPodder, ficheiros OPML ou fontes RSS. Poupe tempo, economize energia e dados móveis através dos mecanismos de controlo de transferência de episódios (possibilidade de especificar intervalos ou horas para as transferências e redes WiFi) e de eliminação de episódios (de acordo com as suas preferências).<br>
-Mas ainda mais importante: pode transferir, emitir ou colocar episódios na lista de reprodução ao seu gosto, pode utilizar velocidades variáveis de reprodução, tem suporte a capítulos e um temporizador. Pode também mostrar o seu apreço aos disponibilizadores dos episódios através do serviço Flattr.
-
-Criado por entusiastas de podcasts, o AntennaPod é livre em todos os sentidos da palavra: open source, gratuito e sem publicidade.
-
-<b>Funcionalidades:</b><br>
-Importação, organização e reprodução<br>
-&#8226; Adicione e importe fontes existentes nos diretórios iTunes e gPodder.net, ficheiros OPML e ligações ATOM e RSS<br>
-&#8226; Gestão de podcasts através do widget, barra de notificações e controlos de auriculares ou auscultadores<br>
-&#8226; Velocidade variável de reprodução, suporte a capítulos (MP3, VorbisComment e Podlove), memorização da posição de reprodução e um temporizador avançado (agite para repor ou baixar e aumentar o volume)<br>
-&#8226; Acesso a fontes e episódios protegidos por palavra-passe<br>
-&#8226; Possibilidade de subscrever fontes paginadas (www.podlove.org/paged-feeds)
-
-Monitorização, partilha e suporte<br>
-&#8226; Monitorize os seus podcasts preferidos marcando-os como favoritos<br>
-&#8226; Localize um episódio através do histórico de reprodução ou através de uma pesquisa (títulos e notas)<br>
-&#8226; Partilhe episódios e fontes nas redes sociais, por e-mail, no diretório gPodder.net ou através de ficheiros OPML<br>
-&#8226; Ajude os criadores de conteúdos através do serviço Flattr
-
-Controlar o sistema<br>
-&#8226; Controle todas as transferÊncias automáticas: escolha as fontes, exclua redes móveis, especifique as redes WiFi, indique se o telefone deve estar a ser carregado e defina as horas ou intervalos das transferências<br>
-&#8226; Faça a gestão do armazenamento através da cache de episódios, da eliminação inteligente (de acordo com os seus favoritos e estado de reprodução) e selecionado a localização de armazenamento<br>
-&#8226; Utilize o AntennaPod no seu idioma (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapte-se ao seu ambiente através dos temas claro ou escuro<br>
-&#8226; Salvaguarde as suas subscrições com a integração gPodder.net ou através da exportação OPML
-
-<b>Integre a comunidade do AntennaPod!</b><br>
-O AntennaPod é desenvolvido por voluntários. Você também pode contribuir na programação ou reportando os erros encontrados!
-
-O GitHub é o local certo para os pedidos de funcionalidades, relatórios de erros e contribuições:<br>
-www.github.com/AntennaPod/AntennaPod
-
-O nosso grupo Google é o local certo para partilhar ideias e agradecer aos nossos voluntários:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-O Transifex é o local no qual pode ajudar a traduzir a aplicação:<br>
-www.transifex.com/antennapod/antennapod
-
-Junte-se ao nosso programa de testes para obter as funcionalidades mais recentes:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/pt-BR/listing/shortdescription b/app/src/main/play/pt-BR/listing/shortdescription
deleted file mode 100644
index 849436827..000000000
--- a/app/src/main/play/pt-BR/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Um gestor de podcasts de código livre para Android. \ No newline at end of file
diff --git a/app/src/main/play/pt-BR/listing/title b/app/src/main/play/pt-BR/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/pt-BR/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/pt-PT/listing/fulldescription b/app/src/main/play/pt-PT/listing/fulldescription
deleted file mode 100644
index 735334e0c..000000000
--- a/app/src/main/play/pt-PT/listing/fulldescription
+++ /dev/null
@@ -1,40 +0,0 @@
-O AntennaPod é um gestor de podcasts que lhe permite aceder a milhões de podcasts (gratuitos ou pagos), a partir de diversas fontes tais como as estações BBC, NPR e CNN. A adição de fontes é muito fácil através das base de dados iTunes ou gPodder, ficheiros OPML ou fontes RSS. Poupe tempo, economize energia e dados móveis através dos mecanismos de controlo de transferência de episódios (possibilidade de especificar intervalos ou horas para as transferências e redes WiFi) e de eliminação de episódios (de acordo com as suas preferências).<br>
-Mas ainda mais importante: pode transferir, emitir ou colocar episódios na lista de reprodução ao seu gosto, pode utilizar velocidades variáveis de reprodução, tem suporte a capítulos e um temporizador. Pode também mostrar o seu apreço aos disponibilizadores dos episódios através do serviço Flattr.
-
-Criado por entusiastas de podcasts, o AntennaPod é livre em todos os sentidos da palavra: open source, gratuito e sem publicidade.
-
-<b>Funcionalidades:</b><br>
-Importação, organização e reprodução<br>
-&#8226; Adicione e importe fontes existentes nos diretórios iTunes e gPodder.net, ficheiros OPML e ligações ATOM e RSS<br>
-&#8226; Gestão de podcasts através do widget, barra de notificações e controlos de auriculares ou auscultadores<br>
-&#8226; Velocidade variável de reprodução, suporte a capítulos (MP3, VorbisComment e Podlove), memorização da posição de reprodução e um temporizador avançado (agite para repor ou baixar e aumentar o volume)<br>
-&#8226; Acesso a fontes e episódios protegidos por palavra-passe<br>
-&#8226; Possibilidade de subscrever fontes paginadas (www.podlove.org/paged-feeds)
-
-Monitorização, partilha e suporte<br>
-&#8226; Monitorize os seus podcasts preferidos marcando-os como favoritos<br>
-&#8226; Localize um episódio através do histórico de reprodução ou através de uma pesquisa (títulos e notas)<br>
-&#8226; Partilhe episódios e fontes nas redes sociais, por e-mail, no diretório gPodder.net ou através de ficheiros OPML<br>
-&#8226; Ajude os criadores de conteúdos através do serviço Flattr
-
-Controlar o sistema<br>
-&#8226; Controle todas as transferÊncias automáticas: escolha as fontes, exclua redes móveis, especifique as redes WiFi, indique se o telefone deve estar a ser carregado e defina as horas ou intervalos das transferências<br>
-&#8226; Faça a gestão do armazenamento através da cache de episódios, da eliminação inteligente (de acordo com os seus favoritos e estado de reprodução) e selecionado a localização de armazenamento<br>
-&#8226; Utilize o AntennaPod no seu idioma (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapte-se ao seu ambiente através dos temas claro ou escuro<br>
-&#8226; Salvaguarde as suas subscrições com a integração gPodder.net ou através da exportação OPML
-
-<b>Integre a comunidade do AntennaPod!</b><br>
-O AntennaPod é desenvolvido por voluntários. Você também pode contribuir na programação ou reportando os erros encontrados!
-
-O GitHub é o local certo para os pedidos de funcionalidades, relatórios de erros e contribuições:<br>
-www.github.com/AntennaPod/AntennaPod
-
-O nosso grupo Google é o local certo para partilhar ideias e agradecer aos nossos voluntários:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-O Transifex é o local no qual pode ajudar a traduzir a aplicação:<br>
-www.transifex.com/antennapod/antennapod
-
-Junte-se ao nosso programa de testes para obter as funcionalidades mais recentes:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/pt-PT/listing/shortdescription b/app/src/main/play/pt-PT/listing/shortdescription
deleted file mode 100644
index 849436827..000000000
--- a/app/src/main/play/pt-PT/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Um gestor de podcasts de código livre para Android. \ No newline at end of file
diff --git a/app/src/main/play/pt-PT/listing/title b/app/src/main/play/pt-PT/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/pt-PT/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/pt/listing/fulldescription b/app/src/main/play/pt/listing/fulldescription
deleted file mode 100644
index 58d88eb24..000000000
--- a/app/src/main/play/pt/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-O AntennaPod é um gestor de podcasts que lhe permite aceder a milhões de podcasts, gratuitos ou pagos, a partir de diversas fontes tais como as estações BBC, NPR e CNN. A adição de fontes é muito fácil através das base de dados iTunes ou gPodder, ficheiros OPML ou fontes RSS. Poupe tempo, economize bateria e dados móveis através dos mecanismos de controlo de descargas de episódios (possibilidade de especificar intervalos ou horas para as descargas e redes WiFi) e de eliminação de episódios (de acordo com as suas preferências).<br>
-Mas ainda mais importante: pode descarregar, emitir ou colocar episódios na lista de reprodução ao seu gosto, pode utilizar velocidades variáveis de reprodução, tem suporte a capítulos e um temporizador. Pode também mostrar o seu apreço aos criadores dos episódios através do serviço Flattr.
-
-Criado por entusiastas de podcasts, o AntennaPod é livre em todos os sentidos da palavra: open source, gratuito e sem publicidade.
-
-<b>Funcionalidades:</b><br>
-Importação, organização e reprodução<br>
-&#8226; Adicione e importe fontes existentes nos diretórios iTunes e gPodder.net, ficheiros OPML e ligações ATOM e RSS<br>
-&#8226; Gestão de podcasts através do widget, barra de notificações e controlos de auriculares ou auscultadores<br>
-&#8226; Velocidade variável de reprodução, suporte a capítulos (MP3, VorbisComment e Podlove), memorização da posição de reprodução e um temporizador avançado (agite para repor, baixar e aumentar o volume)<br>
-&#8226; Acesso a fontes e episódios protegidos por palavra-passe<br>
-&#8226; Possibilidade de subscrever fontes paginadas (www.podlove.org/paged-feeds)
-
-Monitorização, partilha e suporte<br>
-&#8226; Monitorize os seus podcasts preferidos marcando-os como favoritos<br>
-&#8226; Localize um episódio através do histórico de reprodução ou através de uma pesquisa (títulos e notas)<br>
-&#8226; Partilhe episódios e fontes nas redes sociais, por e-mail, no diretório gPodder.net ou através de ficheiros OPML<br>
-&#8226; Ajude os criadores de conteúdos através do serviço Flattr
-
-Controlo do sistema<br>
-&#8226; Controle todas as descargas automáticas: escolha as fontes, exclua redes móveis, especifique as redes Wi-Fi, indique se o telefone deve estar a ser carregado e defina as horas ou intervalos das descargas<br>
-&#8226; Faça a gestão do armazenamento através da cache de episódios, da eliminação inteligente (de acordo com os seus favoritos e estado de reprodução) e selecionado a localização de armazenamento<br>
-&#8226; Utilize o AntennaPod no seu idioma (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapte-se ao seu ambiente através dos temas claro ou escuro<br>
-&#8226; Salvaguarde as suas subscrições com a integração gPodder.net ou através da exportação OPML
-
-<b>Integre a comunidade do AntennaPod!</b><br>
-O AntennaPod é desenvolvido por voluntários. Você também pode contribuir na programação ou reportando os erros encontrados!
-
-O GitHub é o local certo para os pedidos de funcionalidades, relatórios de erros e contributos:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-O nosso grupo Google é o local certo para partilhar ideias e agradecer aos nossos voluntários:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Tem alguma questão ou comentário a fazer?
-https://twitter.com/@AntennaPod
-
-O Transifex é o local no qual pode ajudar a traduzir a aplicação:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Junte-se ao nosso programa Beta para obter as funcionalidades mais recentes:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/pt_BR/listing/fulldescription b/app/src/main/play/pt_BR/listing/fulldescription
deleted file mode 100644
index e40d3f450..000000000
--- a/app/src/main/play/pt_BR/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod é um gerenciador e reprodutor de <i>podcasts</i> que te dá acesso instantâneo a milhões de <i>podcasts</i> gratuitos e pagos, desde <i>podcasters</i> independentes até grandes editores como BBC, NPR e CNN. Adicione, importe e exporte seus <i>feeds</i> sem complicações utilizando a base de dados do iTunes, arquivos OPML ou simples URLs RSS. Economize esforços, bateria e uso de dados móveis com poderosos controles de automação para baixar episódios (especifique horários, intervalos e redes WiFi) e excluir episódios (baseado nos seus favoritos e configurações de adiamento).<br>
-Mas o mais importante: Baixe, realize <i>streaming</i> ou enfilere episódios e desfrute deles da maneira que quiser com velocidades de reprodução ajustáveis, suporte para capítulos e cronômetro. Você pode até mostrar o seu apreço aos criadores de conteúdo com a integração com o Flattr.
-
-Desenvolvido por fãs de podcasts, AntennaPod é livre em todos os sentidos da palavra; <i>open source</i>, sem custos, sem propagandas.
-
-<b>Recursos disponíveis:</b><br>
-IMPORTE, ORGANIZE E TOQUE <br>
-&#8226; Adicione and importe feeds pelo iTunes e diretorios gPodder.net, arquivos OPML e links RSS ou Atom<br>
-&#8226; Gerencie suas reproduções de qualquer lugar: widget da tela inicial, notificações de sistema e fone de ouvido e controles bluetooth<br>
-&#8226; Ouça do seu jeito com velocidade de reprodução ajustável, suporte a capítulos (MP3, VorbisComment e Podlove), marcador da posição de reprodução e um despertador avançado (chacoalhe para reiniciar, volume reduzido e reprodução desacelerada)<br>
-&#8226; Acesse feeds e episódios protegidos por senha
-&#8226; Faça uso de <i>feeds</i> paginados (www.podlove.org/paged-feeds)
-
-MANTENHA-SE ATUALIZADO, COMPARTILHE E APRECIE<br>
-&#8226; Guarde o melhor do melhor marcando episódios como favoritos<br>
-&#8226; Encontre aquele episódio específico através do histórico de execução ou pelo sistema de busca (através de títulos e anotações)<br>
-&#8226; Compartilhe episódios e <i>feeds</i> através de opções em redes sociais, email, os serviços da gPodder.net e exportação OPML<br>
-&#8226; Apoie os criadores de conteúdo com a integração com o Flattr
-
-CONTROLE O SISTEMA
-&#8226; Tenha controle sobre a automação dos <i>downloads</i>: escolha <i>feeds</i>, exclua redes móveis, selecione redes específicas de WiFi, exija que o telefone esteja sendo carregado e defina horários ou intervalos<br>
-&#8226; Gerencie o armazenamento configurando a quantidade de episódios em cache, exclusão inteligente dos episódios (baseada nos seus favoritos e status de reprodução)<br>
-&#8226; Use o AntennaPod no seu idioma (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapte-se ao ambiente utilizando os temas claro ou escuro<br>
-&#8226; Faça <i>backup</i> das suas inscrições com a integração ao gPodder.net e exportação de OPML
-
-<b>Junte-se à comunidade AntennaPod!</b><br>
-O AntennaPod está sob constante desenvolvimento através de voluntários. Você também pode contribuir, com código ou um comentário!
-
-Vá ao GitHub para solicitar funcionalidades, reportar bugs e contribuir com código:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Nosso grupo no Google é o lugar para compartilhar suas idéias, momentos de podcasts favoritos e agradecer aos voluntários:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Tem uma dúvida ou um comentário?
-https://twitter.com/@AntennaPod
-
-Transifex é o lugar para ajudar com as traduções:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Cheque nosso programa de beta testing para receber as atualizações mais recentes primeiro:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/release-notes/en-US/default.txt b/app/src/main/play/release-notes/en-US/default.txt
new file mode 100644
index 000000000..611598679
--- /dev/null
+++ b/app/src/main/play/release-notes/en-US/default.txt
@@ -0,0 +1,5 @@
+- Added configurable behavior of the back button
+- Added delete option to episode's context menu
+- New UI for batch edit feature
+- Set number of columns in subscription list
+- Lots of bug fixes
diff --git a/app/src/main/play/ro/listing/fulldescription b/app/src/main/play/ro/listing/fulldescription
deleted file mode 100644
index 7fdbfa355..000000000
--- a/app/src/main/play/ro/listing/fulldescription
+++ /dev/null
@@ -1,20 +0,0 @@
-AntennaPod este un podcast manager open-source pentru Android 2.3.3 sau mai nou. Oferă toate funcțiile de bază la care vă așteptați de la un podcatcher, precum streaming și descărcare de episoade, actualizarea tuturor feedurilor automat sau adăugarea lor la o coadă pentru a le asculta mai târziu. De asemenea, AntennaPod vă permite să flattr podcasturi și episoade direct din aplicație.
-
-So far the following features are implemented:
-
-* Descărcarea și Streamingul episoadelor
-* Variable speed playback (requires Presto Sound Library or Prestissimo)
-* Suport pentru feeduri Atom și RSS
-* Support for password-protected feeds and episodes
-* Support for searching iTunes listings
-* Import și export OPML
-* Flattr integration including automatic flattring
-* Widget player
-* Căutare
-* Update automat de feeduri
-* Descărcare automată a episoadelor noi
-* Cronometru somn
-* Access to the gpodder.net podcast directory
-* Subscription syncing with the gpodder.net service
-* Supports MP3 chapters, VorbisComment chapters and Podlove Simple Chapters
-* Supports paged feeds (http://podlove.org/paged-feeds/) \ No newline at end of file
diff --git a/app/src/main/play/ro/listing/shortdescription b/app/src/main/play/ro/listing/shortdescription
deleted file mode 100644
index 4eceefbb7..000000000
--- a/app/src/main/play/ro/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Easy-to-use, flexible and open-source podcast manager and player \ No newline at end of file
diff --git a/app/src/main/play/ro/listing/title b/app/src/main/play/ro/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/ro/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ro_RO/listing/fulldescription b/app/src/main/play/ro_RO/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/ro_RO/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ru-RU/listing/fulldescription b/app/src/main/play/ru-RU/listing/fulldescription
deleted file mode 100644
index e3e1635ff..000000000
--- a/app/src/main/play/ru-RU/listing/fulldescription
+++ /dev/null
@@ -1,20 +0,0 @@
-AntennaPod — это open-source менеджер подкастов для Android 2.3.3 и выше. Он предлагает все основные функции подкаст-менеджера, такие как воспроизведение из сети, загрузка выпусков, автоматическое обновление каналов и добавление выпусков в очередь. Кроме того, AntennaPod позволяет совершать пожертвования подкаст-каналам, посредством Flattr, прямо из приложения.
-
-Были реализованы следующие возможности:
-
-* Загрузка и потоковое воспроизведение выпусков
-* Изменение скорости воспроизведения (требует Presto Sound Library или Prestissimo)
-* Поддержка каналов в форматах Atom и RSS
-* Поддержка защищенных паролем каналов и выпусков
-* Поддержка поиска по каталогу iTunes
-* Импорт и экспорт OPML
-* Интеграция с Flattr, включая автоматическую поддержку через него
-* Виджет для домашнего экрана
-* Поиск
-* Автоматическое обновление каналов
-* Автоматическая загрузка новых выпусков
-* Таймер сна
-* Доступ к каталогу подкастов на gpodder.net
-* Синхронизация подписок с сервисом gpodder.net
-* Поддержка оглавления MP3, VorbisComment и Podlove Simple Chapters
-* Поддержка постраничных лент (http://podlove.org/paged-feeds/) \ No newline at end of file
diff --git a/app/src/main/play/ru-RU/listing/shortdescription b/app/src/main/play/ru-RU/listing/shortdescription
deleted file mode 100644
index 64e181e6b..000000000
--- a/app/src/main/play/ru-RU/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Менеджер подкастов для Android с открытым исходным кодом \ No newline at end of file
diff --git a/app/src/main/play/ru-RU/listing/title b/app/src/main/play/ru-RU/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/ru-RU/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/ru_RU/listing/fulldescription b/app/src/main/play/ru_RU/listing/fulldescription
deleted file mode 100644
index 9b68a06c0..000000000
--- a/app/src/main/play/ru_RU/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod — менеджер и проигрыватель подкастов, который обеспечит Вас мгновенным доступом к миллионам бесплатных и платных подкастов, как от независимых подкастеров, так и крупных издательских домов, например, BBC, NPR и CNN. С лёгкостью добавляйте, импортируйте и экспортируйте их каналы используя каталог подкастов iTunes, файлы OPML или адреса каналов RSS. Сберегите усилия, заряд батареи и мобильный трафик при помощи мощных средств автоматизации загрузки выпусков (фильтрация, указание времени и интервалов, а также сетей WiFi) и их удаления (в соответствии с настройками избранного и ожидания).<br>
-Но самое главное: Загружайте, слушайте с эфира или ставьте в очередь и получайте удовольствие от их прослушивания применяя регулируемую скорость воспроизведения, оглавления и таймер сна. Вы даже можете выразить свою благодарность создателям аудио посредством интеграции с Flattr.
-
-Созданное поклонниками подкастов, AntennaPod — бесплатное и свободное приложение без рекламы и платежей.
-
-<b>Все возможности:</b><br>
-Импортируйте, систематизируйте и прослушивайте<br>
-&#8226; Добавление и импорт каналов через каталоги iTunes и gPodder.net, файлы OPML и ссылки на каналы RSS или Atom<br>
-&#8226; Всевозможное управление воспроизведением: виджетом, системным уведомлением и кнопками проводных и беспроводных гарнитур<br>
-&#8226; Приятное, по вашему вкусу, прослушивание применяя регулировку скорости воспроизведения, оглавления (MP3, VorbisComment и Podlove), запоминание места воспроизведения и продвинутый таймер сна (сброс при встряхивание, снижение громкости и замедление воспроизведения)<br>
-&#8226; Доступ к каналам и выпускам защищенным паролем<br>
-&#8226; Использует преимущества постраничных лент (www.podlove.org/paged-feeds)
-
-Отслеживайте, делитесь и благодарите<br>
-&#8226; Отслеживайте лучших из лучших, помещая выпуски в избранное<br>
-&#8226; Поиск того самого выпуска в истории воспроизведения или по контексту (заголовки и заметки к выпуску)<br>
-&#8226; Разнообразные возможности поделиться выпусками и каналами через социальные службы и e-mail, услуги gPodder.net и экспорт в OPML<br>
-&#8226; Поддержка создателей аудио при помощи интеграции с Flattr, в том числе и автоматически
-
-Управляйте системой<br>
-&#8226; Управление автоматической загрузкой: выбор отдельных каналов, отбор выпусков на основе ключевых слов, запрет на использование мобильных сетей, выбор отдельных точек доступа WiFi, только во время зарядки телефона и задание времени и интервалов<br>
-&#8226; Управление хранением путём задания количества выпусков в кэше, автоудаление (на основании настроек избранного и статуса прослушивания) и выбор предпочитаемого расположения<br>
-&#8226; AntennaPod на родном Вам языке (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH, RU)<br>
-&#8226; Приспосабливается к Вашему окружению посредством светлой или тёмной темы<br>
-&#8226; Резервирование Ваших подписок путём интеграции с gPodder.net и экпорта в OPML
-
-<b>Присоединяйтесь к сообществу AntennaPod!</b><br>
-AntennaPod постоянно развивается силами добровольцев. Вы тоже можете сделать свой вклад при помощи кода или комментария!
-
-Посещайте GitHub для запроса новых возможностей, уведомления об ошибках и внесения кода:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Поделитесь идеями, любимыми мгновениями прослушивания и благодарностью со всеми добровольцами из нашей группы Google:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Появились вопросы и обратная связь?
-https://twitter.com/@AntennaPod
-
-Помогайте с переводом приложения на Transifex:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Попробуйте себя в программе Бета тестирования и получите доступ к распоследним возможностям в числе первых:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/sl_SI/listing/fulldescription b/app/src/main/play/sl_SI/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/sl_SI/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/sv-SE/listing/fulldescription b/app/src/main/play/sv-SE/listing/fulldescription
deleted file mode 100644
index bdf641cf2..000000000
--- a/app/src/main/play/sv-SE/listing/fulldescription
+++ /dev/null
@@ -1,40 +0,0 @@
-AntennaPod är en podcasthanterare och spelare som ger dig omedelbar tillgång till millioner av gratis och betalda podcasts, allt ifrån oberoende podcasters till publiceringsjättar som BBC, NPR och CNN. Lägg till, importera och exportera enkelt deras flöden med hjälp av iTunes podcastdatabas, OPML filer eller enkla RSS URL:er. Spara tid, batterikraft och mobildata med kraftfull automatisering för nedladdning (specifiera tider, intervall och WiFi-nätverk) och borttagning av episoder (baserat på dina favoriter och fördröjningsinställningar).<br>
-Men viktigast: Ladda ner, strömma eller köa episoder och avnjut dem på ditt sätt med justerbar uppspelningshastighet, kapitelstöd och en sovtimer. Du kan till och med visa din uppskattning av innehållsskaparna med vår integrering av Flattr.
-
-Gjord av podcastenthusiaster, AntennaPod är fri i alla ordets bemärkelser: öppen källkod, inga kostnader, ingen reklam.
-
-<b>Alla funktioner:</b><br>
-IMPORTERA, ORGANISERA OCH SPELA<br>
-&#8226; Lägg till och importera flöden via iTunes och gPodder.net, OPML filer och RSS eller Atom länkar<br>
-&#8226; Hantera uppspelningen från vartsomhelst: hemskärmswidget, aviseringsfältet och hörlurs/bluetoth-kontroller<br>
-&#8226; Njut av att lyssna på ditt sätt med justerbar uppspelningshastighet, kapitelstöd (MP4, VorbisComment och Podlove), ihågkommen uppspelningsposition och en avancerad sömntimer (skaka för återställaning, sänk volymen och sänk hastigheten)<br>
-&#8226; Kom åt lösenordsskyddade flöden och episoder<br>
-&#8226; Dra nytta av siduppdelade flöden (www.podlove.ord/paged-feeds)
-
-SPÅRA, DELA & UPPSKATTA<br>
-&#8226; Spåra det bästa av det bästa med favoritmarkering av episoder<br>
-&#8226; Hitta just den där episoden i uppspelningshistoriken eller genom sökning (titel och shownotes)<br>
-&#8226; Dela episoder och flöden med avancerade vald för social media och och email, tjänsten gPodder.net och via OPML export<br>
-&#8226; Stöd innehållsskaparna via integrering av Flattr och automatisk flattring
-
-KONTROLLERA SYSTEMET<br>
-&#8226; Ta kontroll över automatisk nedladdning: välj flöden, exkludera mobilnätverk, välj specifika WiFi nätver, kräv att telefonen är inkopplad för laddning och sätt tider eller intervall<br>
-&#8226; Hantera lagringsutrymme genom att välja antalet cachade episoder, smart borttagning (baserat på dina favoriter och uppspelningsstatus) och välj den plats du föredrar<br>
-&#8226; Använd AntennaPod på ditt språk (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Anpassa till din omgivning med det ljusa och mörka temat<br>
-&#8226; Ta backup av dina prenumerationer med integreringen av gPodder.net och OPML exportering
-
-<b>Gå med i AntennaPods gemenskap!</b><br>
-AntennaPod är under aktiv utveckling av volontärer. Du kan också bidra, med kod eller kommentarer!
-
-GitHub är platsen att gå till för att be om funktioner, skapa buggrapporter eller bidra med kod:<br>
-www.github.com/AntennaPod/AntennaPod
-
-Vår Google Group är platsen för att dela idéer, dina favoritögonblick med podcasting och din uppskattning till volontärerna:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Transifex är platsen att gå till för att hjälpa till med översättningen:<br>
-www.transifex.com/antennapod/antennapod
-
-Kolla in vårat Beta Testing program för att få de senaste funktionerna först:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/sv-SE/listing/shortdescription b/app/src/main/play/sv-SE/listing/shortdescription
deleted file mode 100644
index 26b3b106a..000000000
--- a/app/src/main/play/sv-SE/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Användarvänlig, flexibel podcasthanterare och spelare med öppen källkod \ No newline at end of file
diff --git a/app/src/main/play/sv-SE/listing/title b/app/src/main/play/sv-SE/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/sv-SE/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/sv_SE/listing/fulldescription b/app/src/main/play/sv_SE/listing/fulldescription
deleted file mode 100644
index 84b7d9681..000000000
--- a/app/src/main/play/sv_SE/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod är en podcasthanterare och spelare som ger dig omedelbar tillgång till millioner av gratis och betalda podcasts, allt ifrån oberoende podcasters till publiceringsjättar som BBC, NPR och CNN. Lägg till, importera och exportera enkelt deras flöden med hjälp av iTunes podcastdatabas, OPML filer eller enkla RSS URL:er. Spara tid, batterikraft och mobildata med kraftfull automatisering för nedladdning (specifiera tider, intervall och WiFi-nätverk) och borttagning av episoder (baserat på dina favoriter och fördröjningsinställningar).<br>
-Men viktigast: Ladda ner, strömma eller köa episoder och avnjut dem på ditt sätt med justerbar uppspelningshastighet, kapitelstöd och en sovtimer. Du kan till och med visa din uppskattning av innehållsskaparna med vår integrering av Flattr.
-
-Gjord av podcastenthusiaster, AntennaPod är fri i alla ordets bemärkelser: öppen källkod, inga kostnader, ingen reklam.
-
-<b>Alla funktioner:</b><br>
-IMPORTERA, ORGANISERA OCH SPELA<br>
-&#8226; Lägg till och importera flöden via iTunes och gPodder.net, OPML filer och RSS eller Atom länkar<br>
-&#8226; Hantera uppspelningen från vartsomhelst: hemskärmswidget, aviseringsfältet och hörlurs/bluetoth-kontroller<br>
-&#8226; Njut av att lyssna på ditt sätt med justerbar uppspelningshastighet, kapitelstöd (MP4, VorbisComment och Podlove), ihågkommen uppspelningsposition och en avancerad sömntimer (skaka för återställaning, sänk volymen och sänk hastigheten)<br>
-&#8226; Kom åt lösenordsskyddade flöden och episoder<br>
-&#8226; Dra nytta av siduppdelade flöden (www.podlove.ord/paged-feeds)
-
-SPÅRA, DELA & UPPSKATTA<br>
-&#8226; Håll ordning på de bästa av de bästa med favoritmarkering av episoder<br>
-&#8226; Hitta just den där episoden i uppspelningshistoriken eller genom sökning (titel och shownotes)<br>
-&#8226; Dela episoder och flöden med avancerade vald för social media och och email, tjänsten gPodder.net och via OPML export<br>
-&#8226; Stöd innehållsskaparna via integrering av Flattr och automatisk flattring
-
-KONTROLLERA SYSTEMET<br>
-&#8226; Ta kontroll över automatisk nedladdning: välj flöden, exkludera mobilnätverk, välj specifika WiFi nätverk, kräv att telefonen är inkopplad för laddning och sätt tider eller intervall för körning<br>
-&#8226; Hantera lagringsutrymme genom att välja antalet cachade episoder, smart borttagning (baserat på dina favoriter och uppspelningsstatus) och välj den lagringsplats du föredrar<br>
-&#8226; Använd AntennaPod på ditt språk (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Anpassa till din omgivning med det ljusa och mörka temat<br>
-&#8226; Ta backup av dina prenumerationer med integreringen av gPodder.net och OPML exportering
-
-<b>Gå med i AntennaPods gemenskap!</b><br>
-AntennaPod är under aktiv utveckling av volontärer. Du kan också bidra, med kod eller kommentarer!
-
-GitHub är platsen att gå till för att be om funktioner, skapa buggrapporter eller bidra med kod:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Vår Google Group är platsen för att dela idéer, dina favoritögonblick med podcasting och din uppskattning till volontärerna:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Har du frågor eller vill ge feedback?
-https://twitter.com/@AntennaPod
-
-Transifex är platsen att gå till för att hjälpa till med översättningen:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Kolla in vårat Beta Testing program för att få de senaste funktionerna först:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/sw_KE/listing/fulldescription b/app/src/main/play/sw_KE/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/sw_KE/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/te/listing/fulldescription b/app/src/main/play/te/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/te/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/tr-TR/listing/fulldescription b/app/src/main/play/tr-TR/listing/fulldescription
deleted file mode 100644
index 7ea4d906d..000000000
--- a/app/src/main/play/tr-TR/listing/fulldescription
+++ /dev/null
@@ -1,20 +0,0 @@
-AntennaPod, Android 2.3.3 ve üzeri için açık kaynak kodlu cepyayını yöneticisidir. Bölümleri yayınlama ve indirme, beslemelerin otomatik olarak yenilenmesi veya daha sonra dinlemek için sıraya konması gibi bir cepyayını yakalayıcısından beklediğiniz tüm temel özellikleri içerir. Hatta cepyayınlarını ve bölümleri uygulama içinden flattr aracılığıyla desteklemenize olanak verir.
-
-Şimdiye kadar aşağıdaki özellikler eklenmiştir:
-
-* Bölümlerin indirilmesi ve yayınlanması
-* Değişken çalma hızı (Presto Sound Library veya Prestissimo gerekir)
-* Atom ve RSS besleme desteği
-* Şifre korumalı besleme ve bölüm desteği
-* iTunes listelerinde arama yapma desteği
-* OPML içe aktarma ve dışa aktarma
-* Otomatik flatter içeren Flattr entegrasyonu
-* Ev ekranı oynatıcı widget'ı
-* Arama
-* Otomatik besleme güncellemeleri
-* Yeni bölümlerin otomatik indirilmesi
-*Uyku zamanlayıcı
-* gpodder.net cepyayını dizinine erişim
-* gpodder.net servisi ile üyelik senkronizasyonu
-* MP3 kısımları, VorbisComment kısımlar ve Podlove Simple Chapter desteği
-* Sayfalanmış beslemeler desteği (http://podlove.org/paged-feeds/) \ No newline at end of file
diff --git a/app/src/main/play/tr-TR/listing/shortdescription b/app/src/main/play/tr-TR/listing/shortdescription
deleted file mode 100644
index 979342e23..000000000
--- a/app/src/main/play/tr-TR/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Android için açık kaynaklı cepyayını yöneticisi \ No newline at end of file
diff --git a/app/src/main/play/tr-TR/listing/title b/app/src/main/play/tr-TR/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/tr-TR/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/tr/listing/fulldescription b/app/src/main/play/tr/listing/fulldescription
deleted file mode 100644
index 90bda48af..000000000
--- a/app/src/main/play/tr/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>Tüm özellikler:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-SİSTEMİ KONTROL ET<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; AntennaPod'u kendi dilinizde kullanın (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>AntennaPod topluluğuna katılın!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Bir sorunuz mu var veya bize geri bildirim bırakmak mı istiyorsunuz?
-https://twitter.com/@AntennaPod
-
-Tercümelere yardım etmenin yeri Transifex:<br>
-https://www.transifex.com/antennapod/antennapod
-
-En son özellikleri ilk önce almak isterseniz Beta Testing programımıza katılın:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/uk/listing/fulldescription b/app/src/main/play/uk/listing/fulldescription
deleted file mode 100644
index 877483033..000000000
--- a/app/src/main/play/uk/listing/fulldescription
+++ /dev/null
@@ -1,40 +0,0 @@
-AntennaPod це менеджер подкастів та плейер що дає доступ до мільйонів безкоштовних та комерційних подкастів від незалежних подкастерів та великих корпорацій таких як BBC, NPR та CNN. Є можливість додавати, імпортувати та експортувати канали за допомогою бази даних подкастів iTunes, файлів OPML або простих посилань на RSS. Зберігайте зусилля, живлення та мобільний трафік за допомогою автоматичного завантаження епізодів (зазначивши час, інтервали та мережі WiFi) та видалення епізодів (з урахуванням ваших побажань та налаштувань).<br>
-Але найважливіше: завантажуйте, слухайте або додавайте до черги епізоди так, як вам подобається з налаштуванням швидкості програвання, підтримкою розділів та таймера сну. Можливо навіть фінансово заохочувати авторів за допомогою інтергації з сервісом Flattr.
-
-Зроблений ентузіастом подкастів, AntennaPod є вільним в усіх сенсах цього слова: відкриті вихідні тексти, безкоштовний, без реклами.
-
-<b>Всі можливості:</b><br>
-ІМПОРТУЙТЕ, ВПОРЯДКОВУЙТЕ ТА СЛУХАЙТЕ<br>
-&#8226; Додавайте та імпортуйте канали з каталогів iTunes та gPodder.net, файлів OPML та з посилань на RSS або Atom<br>
-&#8226; Керуйте програванням будь-де: з віджета, нотифікації, кнопками навушників або через блютус<br>
-&#8226; Слухайте так як вам подобається з налаштуванням швидкості програвання, підтримкой розділів (в форматах MP3, VorbisComment та Podlove), зберіганням момента програвання та таймером сну (перезапуск струсом, зниження гучності та уповільнення програвання)<br>
-&#8226; Доступ до каналів та епізодів що захищені паролем<br>
-&#8226; Використовуйте посторінкові канали (www.podlove.org/paged-feeds)
-
-ВІДСТЕЖУЙТЕ, ДІЛІТЬСЯ ТА ОЦІНЮЙТЕ<br>
-&#8226; Зберігайте найкраще в улюблених епізодах<br>
-&#8226; Відшукайте той самий епізод в історії програвання або пошуком (в назвах і нотатках)<br>
-&#8226; Діліться епізодами та каналами за допомогою соцмереж та пошти, сервісів gPodder.net та через експорт OPML файлів<br>
-&#8226; Підтримуйте авторів за допомогою інтегрованого сервіса Flattr з можливістю автоматичной підтримки
-
-КЕРУЙТЕ СИСТЕМОЙ<br>
-&#8226; Керуйте автоматичним завантаженням: вибирайте канали, мобільні мережі, мережі WiFi, завантажуйте тільки під час зарядки або у встановлений час і інтервали<br>
-&#8226; Керуйте збереженням, встановлюйте ліміт на кеш епізодів, налагоджуйте розумне видалення (з урахуванням улюблених епізодів і статуса програвання) та вибирайте місце зберігання<br>
-&#8226; Користуйтесь AntennaPod вашою мовою (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Пристосовуйтесь до ваших умов, користуйтесь світлой або темной темами<br>
-&#8226; Зберігайте ваші підписки на gPodder.net або експортуйте в файл OPML
-
-<b>Долучайтесь до спільноти AntennaPod!</b><br>
-AntennaPod швидко розвивається волонтерами. Ви також маєте змогу допомогти, кодом або зауваженнями!
-
-Долучитись до проекта, повідомити про ваші побажання та про помилки можна на GitHub:<br>
-www.github.com/AntennaPod/AntennaPod
-
-В нашій групі на Google можна поділитись ідеями, улюбленими моментами з подкастінга та добрими побажаннями волонтерам:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Допомагайте з перекладом на Transifex:<br>
-www.transifex.com/antennapod/antennapod
-
-Зверніть увагу на нашу програму для бета тестування якщо бажаєте получати найновіші версії в першу чергу:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/uk/listing/shortdescription b/app/src/main/play/uk/listing/shortdescription
deleted file mode 100644
index ac638de72..000000000
--- a/app/src/main/play/uk/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Менеджер подкастів для Android з відкритими вихідними текстами. \ No newline at end of file
diff --git a/app/src/main/play/uk/listing/title b/app/src/main/play/uk/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/uk/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/uk_UA/listing/fulldescription b/app/src/main/play/uk_UA/listing/fulldescription
deleted file mode 100644
index ae8ac2c20..000000000
--- a/app/src/main/play/uk_UA/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod це менеджер подкастів та плейер що дає доступ до мільйонів безкоштовних та комерційних подкастів від незалежних подкастерів та великих корпорацій таких як BBC, NPR та CNN. Є можливість додавати, імпортувати та експортувати канали за допомогою бази даних подкастів iTunes, файлів OPML або простих посилань на RSS. Зберігайте зусилля, живлення та мобільний трафік за допомогою автоматичного завантаження епізодів (зазначивши час, інтервали та мережі WiFi) та видалення епізодів (з урахуванням ваших побажань та налаштувань).<br>
-Але найважливіше: завантажуйте, слухайте або додавайте до черги епізоди так, як вам подобається з налаштуванням швидкості програвання, підтримкою розділів та таймера сну. Можливо навіть фінансово заохочувати авторів за допомогою інтергації з сервісом Flattr.
-
-Зроблений ентузіастом подкастів, AntennaPod є вільним в усіх сенсах цього слова: відкриті вихідні тексти, безкоштовний, без реклами.
-
-<b>Всі можливості:</b><br>
-ІМПОРТУЙТЕ, ВПОРЯДКОВУЙТЕ ТА СЛУХАЙТЕ<br>
-&#8226; Додавайте та імпортуйте канали з каталогів iTunes та gPodder.net, файлів OPML та з посилань на RSS або Atom<br>
-&#8226; Керуйте програванням будь-де: з віджета, нотифікації, кнопками навушників або через блютус<br>
-&#8226; Слухайте так як вам подобається з налаштуванням швидкості програвання, підтримкой розділів (в форматах MP3, VorbisComment та Podlove), зберіганням момента програвання та таймером сну (перезапуск струсом, зниження гучності та уповільнення програвання)<br>
-&#8226; Доступ до каналів та епізодів що захищені паролем<br>
-&#8226; Використовуйте посторінкові канали (www.podlove.org/paged-feeds)
-
-ВІДСТЕЖУЙТЕ, ДІЛІТЬСЯ ТА ОЦІНЮЙТЕ<br>
-&#8226; Зберігайте найкраще в улюблених епізодах<br>
-&#8226; Відшукайте той самий епізод в історії програвання або пошуком (в назвах і нотатках)<br>
-&#8226; Діліться епізодами та каналами за допомогою соцмереж та пошти, сервісів gPodder.net та через експорт OPML файлів<br>
-&#8226; Підтримуйте авторів за допомогою інтегрованого сервіса Flattr з можливістю автоматичной підтримки
-
-КЕРУЙТЕ СИСТЕМОЙ<br>
-&#8226; Керуйте автоматичним завантаженням: вибирайте канали, мобільні мережі, мережі WiFi, завантажуйте тільки під час зарядки або у встановлений час і інтервали<br>
-&#8226; Керуйте збереженням, встановлюйте ліміт на кеш епізодів, налагоджуйте розумне видалення (з урахуванням улюблених епізодів і статуса програвання) та вибирайте місце зберігання<br>
-&#8226; Користуйтесь AntennaPod вашою мовою (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Пристосовуйтесь до ваших умов, користуйтесь світлой або темной темами<br>
-&#8226; Зберігайте ваші підписки на gPodder.net або експортуйте в файл OPML
-
-<b>Долучайтесь до спільноти AntennaPod!</b><br>
-AntennaPod швидко розвивається волонтерами. Ви також маєте змогу допомогти, кодом або зауваженнями!
-
-Долучитись до проекта, повідомити про ваші побажання та про помилки можна на GitHub:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-В нашій групі на Google можна поділитись ідеями, улюбленими моментами з подкастінга та добрими побажаннями волонтерам:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Маєте питання або повідомлення для нас?
-https://twitter.com/@AntennaPod
-
-Допомагайте з перекладом на Transifex:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Зверніть увагу на нашу програму для бета тестування якщо бажаєте получати найновіші версії в першу чергу:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/vi/listing/fulldescription b/app/src/main/play/vi/listing/fulldescription
deleted file mode 100644
index 9519b5da1..000000000
--- a/app/src/main/play/vi/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-Mọi tính năng:
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-ĐIỀU KHIỂN HỆ THỐNG
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-Tham gia cộng đồng AntennaPod!
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Có một thắc mắc hay muốn phản hồi cho chúng tôi?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/vi_VN/listing/fulldescription b/app/src/main/play/vi_VN/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/vi_VN/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/zh-CN/listing/fulldescription b/app/src/main/play/zh-CN/listing/fulldescription
deleted file mode 100644
index 932b5ba3a..000000000
--- a/app/src/main/play/zh-CN/listing/fulldescription
+++ /dev/null
@@ -1,20 +0,0 @@
-AntennaPod 是一款开源播客管理软件, 提供 Android 2.3.3 及以上平台运行. 它提供了所有你所期望的播客基本功能, 例如在线流媒体和下载收听曲目, 以及自动刷新所有订阅和添加到播放列表. 此外, AntennaPod 支持应用内 Flattr 播客和节目表.
-
-So far the following features are implemented:
-
-* 在线流媒体和下载收听曲目
-* 变速播放 (需要 Presto 声音库或者 Prestissimo)
-* 支持 Atom 和 RSS 订阅
-* 支持加密的订阅
-* Support for searching iTunes listings
-* OPML 文件导入导出
-* Flattr integration including automatic flattring
-* 播放器主屏幕窗口小部件 (Widget)
-* 搜索
-* 自动订阅更新
-* 自动下载新曲目
-* 睡眠计时器
-* 访问 gpodder.net 播客目录
-* 同步 gpodder.net 订阅服务
-* Supports MP3 chapters, VorbisComment chapters and Podlove Simple Chapters
-* Supports paged feeds (http://podlove.org/paged-feeds/) \ No newline at end of file
diff --git a/app/src/main/play/zh-CN/listing/shortdescription b/app/src/main/play/zh-CN/listing/shortdescription
deleted file mode 100644
index 4eceefbb7..000000000
--- a/app/src/main/play/zh-CN/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Easy-to-use, flexible and open-source podcast manager and player \ No newline at end of file
diff --git a/app/src/main/play/zh-CN/listing/title b/app/src/main/play/zh-CN/listing/title
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/zh-CN/listing/title
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/zh/listing/fulldescription b/app/src/main/play/zh/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/zh/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/zh_CN/listing/fulldescription b/app/src/main/play/zh_CN/listing/fulldescription
deleted file mode 100644
index 6f2a6209e..000000000
--- a/app/src/main/play/zh_CN/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod 是播客管理和播放工具,使得你即刻收听到数百万来自从个人播客制作者到类似BBC、NPR和CNN等大型出版机构的免费或付费播客。通过 iTunes 数据库、OPML 文件或简单的 RSS 地址,你可以自由地添加、导入和导出播客订阅流。通过指定次数、间隔时间和 WIFI 网络的下载以及基于个人喜好和延迟删除的设置,功能强大的智能控制做到了省力、省电和省流量。<br>
-但最重要的在于,你可以选择下载、串流或加入队列等方式收听节目,并使用调节回放速度、章节跳转和定时睡眠的辅助功能。你甚至可以通过 Flattr 集成功能向内容创作者表达你衷心的感谢。
-
-AntennaPod 是一个由播客爱好者开发,在多种意义下“自由”的软件——开源、免费并且没有广告。
-
-<b>特性包括:</b><br>
-导入,组织和播放<br>
-&#8226; 通过 iTunes,gPodder.net,OPML文件,RSS或Atom链接添加和导入订阅
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/zh_HK/listing/fulldescription b/app/src/main/play/zh_HK/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/zh_HK/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/zh_TW/listing/fulldescription b/app/src/main/play/zh_TW/listing/fulldescription
deleted file mode 100644
index 87b477fdc..000000000
--- a/app/src/main/play/zh_TW/listing/fulldescription
+++ /dev/null
@@ -1,43 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
-
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>All features:</b><br>
-IMPORT, ORGANIZE AND PLAY<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-https://www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Have a question or want to give us feedback?
-https://twitter.com/@AntennaPod
-
-Transifex is the place to help with translations:<br>
-https://www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/app/src/main/res/layout/addfeed.xml b/app/src/main/res/layout/addfeed.xml
index 33951e060..011aa4c8b 100644
--- a/app/src/main/res/layout/addfeed.xml
+++ b/app/src/main/res/layout/addfeed.xml
@@ -1,100 +1,173 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scrollbars="vertical">
-
- <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingBottom="8dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:paddingTop="8dp">
-
- <TextView
- android:id="@+id/txtvPodcastDirectories"
- style="@style/AntennaPod.TextView.Heading"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/podcastdirectories_label"/>
-
- <TextView
- android:id="@+id/txtvPodcastDirectoriesDescr"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/podcastdirectories_descr"
- android:textSize="@dimen/text_size_medium"/>
-
- <Button
- android:id="@+id/butSearchItunes"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="4dp"
- android:text="@string/search_itunes_label"/>
-
- <Button
- android:id="@+id/butSearchFyyd"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/search_fyyd_label"/>
-
- <Button
- android:id="@+id/butBrowseGpoddernet"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/browse_gpoddernet_label"/>
-
- <View style="@style/Divider"/>
+ android:layout_height="match_parent"
+ android:scrollbars="vertical">
- <TextView
- android:id="@+id/txtvFeedurl"
- style="@style/AntennaPod.TextView.Heading"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/txtvfeedurl_label"/>
-
- <EditText
- android:id="@+id/etxtFeedurl"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:cursorVisible="true"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:hint="@string/etxtFeedurlHint"
- android:inputType="textUri"/>
-
- <Button
- android:id="@+id/butConfirm"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/confirm_label"/>
-
- <View style="@style/Divider"/>
-
- <TextView
- android:id="@+id/txtvOpmlImport"
- style="@style/AntennaPod.TextView.Heading"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/opml_import_label"/>
-
- <TextView
- android:id="@+id/txtvOpmlImportExpl"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/opml_import_txtv_button_lable"
- android:textSize="@dimen/text_size_medium"/>
-
- <Button
- android:id="@+id/butOpmlImport"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="4dp"
- android:text="@string/opml_import_label"/>
+ android:orientation="vertical"
+ android:padding="8dp">
+
+ <android.support.v7.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:cardCornerRadius="4dp"
+ android:elevation="16dp"
+ android:layout_margin="8dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:layout_width="40dp"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/search_podcast_hint"
+ app:srcCompat="?attr/action_search"
+ android:scaleType="center"/>
+
+ <EditText
+ android:id="@+id/combinedFeedSearchBox"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:inputType="text"
+ android:imeOptions="actionSearch"
+ android:importantForAutofill="no"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:hint="@string/search_podcast_hint"
+ android:background="@null"/>
+
+ </LinearLayout>
+
+ </android.support.v7.widget.CardView>
+
+ <fragment
+ android:id="@+id/quickFeedDiscovery"
+ android:name="de.danoeh.antennapod.fragment.QuickFeedDiscoveryFragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"/>
+
+ <android.support.v7.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:cardCornerRadius="4dp"
+ android:elevation="8dp"
+ android:layout_margin="8dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/txtvFeedurl"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/txtvfeedurl_label"
+ android:textSize="18sp"
+ android:layout_marginBottom="8dp"
+ android:textColor="?android:attr/textColorPrimary"/>
+
+ <EditText
+ android:id="@+id/etxtFeedurl"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:cursorVisible="true"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:hint="@string/etxtFeedurlHint"
+ android:inputType="textUri"/>
+
+ <Button
+ android:id="@+id/butConfirm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/confirm_label"/>
+
+ </LinearLayout>
+
+ </android.support.v7.widget.CardView>
+
+ <android.support.v7.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:cardCornerRadius="4dp"
+ android:elevation="8dp"
+ android:layout_margin="8dp">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:id="@+id/advanced_search"
+ android:layout_width="96dp"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center_horizontal"
+ android:padding="16dp"
+ android:background="?android:attr/selectableItemBackground">
+
+ <ImageView
+ android:layout_width="40dp"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/advanced_search"
+ app:srcCompat="?attr/action_search"
+ android:scaleType="center"
+ android:layout_marginBottom="4dp"
+ android:tint="?android:attr/textColorPrimary"/>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/advanced_search"
+ android:textAlignment="center"
+ android:textColor="?android:attr/textColorPrimary"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/btn_opml_import"
+ android:layout_width="96dp"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center_horizontal"
+ android:padding="16dp"
+ android:background="?android:attr/selectableItemBackground">
+
+ <ImageView
+ android:layout_width="40dp"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/opml_import_label"
+ app:srcCompat="?attr/av_download"
+ android:scaleType="center"
+ android:layout_marginBottom="4dp"
+ android:tint="?android:attr/textColorPrimary"/>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/opml_import_label"
+ android:textAlignment="center"
+ android:textColor="?android:attr/textColorPrimary"/>
+ </LinearLayout>
+
+ </LinearLayout>
+
+ </android.support.v7.widget.CardView>
</LinearLayout>
-</ScrollView>
+</ScrollView> \ No newline at end of file
diff --git a/app/src/main/res/layout/audio_controls.xml b/app/src/main/res/layout/audio_controls.xml
index f03e4c03f..090aec47f 100644
--- a/app/src/main/res/layout/audio_controls.xml
+++ b/app/src/main/res/layout/audio_controls.xml
@@ -71,6 +71,13 @@
</RelativeLayout>
+ <CheckBox
+ android:id="@+id/skipSilence"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4dp"
+ android:text="@string/pref_skip_silence_title" />
+
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/autoflattr_preference_dialog.xml b/app/src/main/res/layout/autoflattr_preference_dialog.xml
deleted file mode 100644
index fc2df30d7..000000000
--- a/app/src/main/res/layout/autoflattr_preference_dialog.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <CheckBox
- android:id="@+id/chkAutoFlattr"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="4dp"
- android:text="@string/auto_flattr_enable"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_small" />
-
- <SeekBar
- android:id="@+id/skbPercent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="8dp"
- android:max="100" />
-
- <TextView
- android:id="@+id/txtvStatus"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="8dp"
- android:ellipsize="end"
- android:lines="2"
- android:text="@string/auto_flattr_after_percent"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_small" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/choose_data_folder_dialog_entry.xml b/app/src/main/res/layout/choose_data_folder_dialog_entry.xml
new file mode 100644
index 000000000..9a216b36b
--- /dev/null
+++ b/app/src/main/res/layout/choose_data_folder_dialog_entry.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/root"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/diag_content_side_padding"
+ android:background="?attr/selectableItemBackground">
+
+ <RadioButton
+ android:id="@+id/radio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:padding="4dp" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:layout_toEndOf="@+id/radio_button"
+ android:layout_toRightOf="@+id/radio_button"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/path"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ tools:text="/storage/sdcard0" />
+
+ <TextView
+ android:id="@+id/size"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ tools:text="2 GB" />
+
+ <me.zhanghai.android.materialprogressbar.MaterialProgressBar
+ android:id="@+id/used_space"
+ style="@style/Widget.MaterialProgressBar.ProgressBar.Horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:mpb_progressStyle="horizontal" />
+ </LinearLayout>
+
+</RelativeLayout>
diff --git a/app/src/main/res/layout/cover_fragment.xml b/app/src/main/res/layout/cover_fragment.xml
index b1e93a195..8e0ec3679 100644
--- a/app/src/main/res/layout/cover_fragment.xml
+++ b/app/src/main/res/layout/cover_fragment.xml
@@ -1,70 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
-
-<android.support.percent.PercentRelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="8dp">
+
+ <TextView
+ android:id="@+id/txtvPodcastTitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.25"
+ android:ellipsize="end"
+ android:gravity="center"
+ android:maxLines="2"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textIsSelectable="true"
+ tools:text="Podcast" />
<ImageView
android:id="@+id/imgvCover"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_centerInParent="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.5"
android:contentDescription="@string/cover_label"
android:scaleType="fitCenter"
- app:layout_aspectRatio="100%"
- app:layout_widthPercent="82%"
android:transitionName="coverTransition"
- tools:src="@android:drawable/sym_def_app_icon" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="vertical"
- android:layout_above="@id/imgvCover">
-
- <TextView
- android:id="@+id/txtvPodcastTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:gravity="center"
- android:maxLines="2"
- android:ellipsize="end"
- android:text="Podcast"
- android:textIsSelectable="true"
- android:textColor="?android:attr/textColorSecondary" />
+ tools:src="@android:drawable/sym_def_app_icon"
+ android:foreground="?attr/selectableItemBackground" />
- </LinearLayout>
-
- <LinearLayout
+ <TextView
+ android:id="@+id/txtvEpisodeTitle"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.25"
+ android:ellipsize="end"
android:gravity="center"
- android:orientation="vertical"
- android:layout_below="@id/imgvCover">
-
- <TextView
- android:id="@+id/txtvEpisodeTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:gravity="center"
- android:maxLines="2"
- android:ellipsize="end"
- android:text="Episode"
- android:textIsSelectable="true"
- android:textColor="?android:attr/textColorPrimary" />
-
- </LinearLayout>
+ android:maxLines="2"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textIsSelectable="true"
+ tools:text="Episode" />
-</android.support.percent.PercentRelativeLayout>
+</LinearLayout>
diff --git a/app/src/main/res/layout/downloaded_episodeslist_item.xml b/app/src/main/res/layout/downloaded_episodeslist_item.xml
index 66ae6c180..65a08251f 100644
--- a/app/src/main/res/layout/downloaded_episodeslist_item.xml
+++ b/app/src/main/res/layout/downloaded_episodeslist_item.xml
@@ -92,7 +92,7 @@
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:clickable="false"
- android:contentDescription="@string/remove_episode_lable"
+ android:contentDescription="@string/delete_episode_label"
android:focusable="false"
android:focusableInTouchMode="false"
android:src="?attr/content_discard"
diff --git a/app/src/main/res/layout/empty_view_layout.xml b/app/src/main/res/layout/empty_view_layout.xml
new file mode 100644
index 000000000..4ccbf45db
--- /dev/null
+++ b/app/src/main/res/layout/empty_view_layout.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:layout_centerInParent="true"
+ android:paddingLeft="40dp"
+ android:paddingRight="40dp"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <ImageView
+ android:id="@+id/emptyViewIcon"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:paddingBottom="8dp"
+ android:visibility="gone"
+ tools:src="@drawable/ic_feed_grey600_24dp"
+ tools:visibility="visible"/>
+
+ <TextView
+ android:id="@+id/emptyViewTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ tools:text="Title"
+ android:textSize="16sp"
+ android:textStyle="bold"
+ android:paddingBottom="8dp"/>
+
+ <TextView
+ android:id="@+id/emptyViewMessage"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="14sp"
+ tools:text="Message"
+ android:textAlignment="center"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/episode_filter_dialog.xml b/app/src/main/res/layout/episode_filter_dialog.xml
new file mode 100644
index 000000000..6a02c82f7
--- /dev/null
+++ b/app/src/main/res/layout/episode_filter_dialog.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="16dp">
+
+ <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/radio_filter_group"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <RadioButton
+ android:id="@+id/radio_filter_include"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/episode_filters_include" />
+
+ <RadioButton
+ android:id="@+id/radio_filter_exclude"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/episode_filters_exclude" />
+ </RadioGroup>
+
+ <EditText
+ android:id="@+id/etxtEpisodeFilterText"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:lines="8"
+ android:minLines="1"
+ android:maxLines="20"
+ android:scrollbars="vertical"
+ android:hint="@string/episode_filters_hint"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true" />
+ </LinearLayout>
+
+ <RelativeLayout
+ android:id="@+id/footer"
+ android:layout_width="fill_parent"
+ android:layout_height="48dp">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:layout_alignParentTop="true"
+ android:background="?android:attr/dividerVertical" />
+
+ <View
+ android:id="@+id/horizontal_divider"
+ android:layout_width="1dip"
+ android:layout_height="fill_parent"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="4dp"
+ android:background="?android:attr/dividerVertical" />
+
+ <Button
+ android:id="@+id/butCancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true"
+ android:layout_toLeftOf="@id/horizontal_divider"
+ android:layout_toStartOf="@id/horizontal_divider"
+ android:background="?android:attr/selectableItemBackground"
+ android:text="@string/cancel_label" />
+
+ <Button
+ android:id="@+id/butConfirm"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/horizontal_divider"
+ android:layout_toEndOf="@id/horizontal_divider"
+ android:background="?android:attr/selectableItemBackground"
+ android:text="@string/confirm_label" />
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/episodes_apply_action_fragment.xml b/app/src/main/res/layout/episodes_apply_action_fragment.xml
index e9a2e2e23..984e960d8 100644
--- a/app/src/main/res/layout/episodes_apply_action_fragment.xml
+++ b/app/src/main/res/layout/episodes_apply_action_fragment.xml
@@ -1,115 +1,50 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
-
- <LinearLayout
- android:id="@+id/bottomBar"
- android:layout_width="match_parent"
- android:layout_height="68dp"
- android:layout_alignParentBottom="true"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:padding="4dp">
-
- <Button
- android:id="@+id/btnAddToQueue"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:background="@android:color/transparent"
- android:drawableTop="?attr/content_new"
- android:text="@string/add_to_queue_label"
- android:textSize="10sp" />
-
- <View
- android:id="@+id/divider1"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:layout_margin="4dp"
- android:background="?android:attr/listDivider"
- tools:background="@android:color/holo_red_dark" />
-
- <Button
- android:id="@+id/btnMarkAsPlayed"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:background="@android:color/transparent"
- android:drawableTop="?attr/navigation_accept"
- android:text="@string/mark_read_label"
- android:textSize="10sp" />
-
- <View
- android:id="@+id/divider2"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:layout_margin="4dp"
- android:background="?android:attr/listDivider"
- tools:background="@android:color/holo_red_dark" />
-
- <Button
- android:id="@+id/btnMarkAsUnplayed"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:background="@android:color/transparent"
- android:drawableTop="?attr/navigation_cancel"
- android:text="@string/mark_unread_label"
- android:textSize="10sp" />
-
- <View
- android:id="@+id/divider3"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:layout_margin="4dp"
- android:background="?android:attr/listDivider"
- tools:background="@android:color/holo_red_dark" />
-
- <Button
- android:id="@+id/btnDownload"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:background="@android:color/transparent"
- android:drawableTop="?attr/av_download"
- android:text="@string/download_label"
- android:textSize="10sp" />
-
- <View
- android:id="@+id/divider4"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:layout_margin="4dp"
- android:background="?android:attr/listDivider"
- tools:background="@android:color/holo_red_dark" />
-
- <Button
- android:id="@+id/btnDelete"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:background="@android:color/transparent"
- android:drawableTop="?attr/content_discard"
- android:text="@string/remove_episode_lable"
- android:textSize="10sp" />
-
- </LinearLayout>
-
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_above="@id/bottomBar"
- android:background="?android:attr/listDivider"
- android:paddingBottom="4dp"
- tools:background="@android:color/holo_red_dark" />
-
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_above="@id/divider"/>
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="0dp" />
+
+ <com.leinardi.android.speeddial.SpeedDialOverlayLayout
+ android:id="@+id/fabSDOverlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ <!-- The FAB SpeedDial
+ 1. MUST be placed at the bottom of the layout xml to ensure it is at the front,
+ clickable on Pre-Lollipop devices (that do not support elevation).
+ See: https://stackoverflow.com/a/2614402
+ 2. ScrollView is needed to ensure the vertical list of speed dials are
+ accessible when screen height is small, eg., landscape mode on most phones.
+ -->
+ <ScrollView
+ android:id="@+id/fabSDScrollCtr"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:elevation="@dimen/sd_close_elevation"
+ tools:ignore="UnusedAttribute">
+ <!-- android:elevation:
+ 1. Needs to match the speed dial's minimal elevation,
+ or the speed dial can't be clicked at all
+ -->
+ <com.leinardi.android.speeddial.SpeedDialView
+ android:id="@+id/fabSD"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:sdMainFabClosedSrc="@drawable/ic_fab_edit"
+ app:sdOverlayLayout="@id/fabSDOverlay"
+ android:layout_marginEnd="16dp"
+ android:layout_marginRight="16dp"
+ android:layout_marginBottom="16dp"
+ />
+ </ScrollView>
</RelativeLayout>
diff --git a/app/src/main/res/layout/feedsettings.xml b/app/src/main/res/layout/feedsettings.xml
index 9e5f2245b..b40148b00 100644
--- a/app/src/main/res/layout/feedsettings.xml
+++ b/app/src/main/res/layout/feedsettings.xml
@@ -1,218 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/feeditemlist_header" />
- <ScrollView
- android:id="@+id/scrollView"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:scrollbarStyle="outsideOverlay"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:paddingBottom="8dp"
- android:clipToPadding="false">
-
- <LinearLayout
+ <FrameLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <android.support.v7.widget.GridLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- app:columnCount="2"
- app:rowCount="1">
-
- <TextView
- android:id="@+id/txtvFeedAutoDelete"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/auto_delete_label"
- app:layout_row="0"
- app:layout_column="0"
- app:layout_gravity="center_vertical"
- android:layout_marginRight="10dp"
- android:layout_marginEnd="10dp" />
-
- <Spinner
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:id="@+id/spnAutoDelete"
- android:entries="@array/spnAutoDeleteItems"
- android:layout_marginTop="8dp"
- app:layout_row="0"
- app:layout_column="1"
- android:spinnerMode="dropdown"
- app:layout_gravity="center"
- android:dropDownWidth="wrap_content"
- android:clickable="true" />
- </android.support.v7.widget.GridLayout>
-
- <CheckBox
- android:id="@+id/cbxKeepUpdated"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/keep_updated"
- android:enabled="true"
- android:textColor="?android:attr/textColorPrimary"
- tools:background="@android:color/holo_red_light"
- android:checked="true" />
-
- <TextView
- android:id="@+id/txtvAuthentication"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/authentication_label"
- android:textSize="@dimen/text_size_medium"
- android:textColor="?android:attr/textColorPrimary"/>
-
- <TextView
- android:id="@+id/txtvAuthenticationDescr"
- android:text="@string/authentication_descr"
- android:textSize="@dimen/text_size_small"
- android:textColor="?android:attr/textColorPrimary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"/>
-
- <android.support.v7.widget.GridLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- app:columnCount="2"
- app:rowCount="3"
- android:layout_gravity="center_horizontal">
-
- <TextView
- android:id="@+id/txtvUsername"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginBottom="8dp"
- app:layout_row="0"
- app:layout_column="0"
- android:text="@string/username_label"
- android:textColor="?android:attr/textColorPrimary"/>
-
- <EditText
- android:id="@+id/etxtUsername"
- android:layout_width="140sp"
- android:layout_height="wrap_content"
- app:layout_row="0"
- app:layout_column="1"
- android:hint="@string/username_label"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:cursorVisible="true"/>
-
- <TextView
- android:id="@+id/txtvPassword"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginBottom="8dp"
- app:layout_row="1"
- app:layout_column="0"
- android:text="@string/password_label"
- android:textColor="?android:attr/textColorPrimary" />
-
- <EditText
- android:id="@+id/etxtPassword"
- android:layout_width="140sp"
- android:layout_height="wrap_content"
- app:layout_row="1"
- app:layout_column="1"
- android:hint="@string/password_label"
- android:inputType="textPassword"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:cursorVisible="true"/>
-
- </android.support.v7.widget.GridLayout>
-
- <TextView
- android:id="@+id/txtvAutoDownloadSettings"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/auto_download_settings_label"
- android:textSize="@dimen/text_size_medium"
- android:textColor="?android:attr/textColorPrimary"/>
-
- <CheckBox
- android:id="@+id/cbxAutoDownload"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/auto_download_label"
- android:enabled="false"
- android:textColor="?android:attr/textColorPrimary"
- tools:background="@android:color/holo_red_light"
- android:checked="false" />
-
- <TextView
- android:id="@+id/txtvEpisodeFilters"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/episode_filters_label"
- android:textSize="@dimen/text_size_medium"
- android:textColor="?android:attr/textColorPrimary"/>
-
- <TextView
- android:id="@+id/txtvEpisodeFiltersDescription"
- android:text="@string/episode_filters_description"
- android:textSize="@dimen/text_size_small"
- android:textColor="?android:attr/textColorPrimary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"/>
-
- <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/radio_filter_group"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center"
- android:orientation="horizontal">
- <RadioButton android:id="@+id/radio_filter_include"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/episode_filters_include" />
- <RadioButton android:id="@+id/radio_filter_exclude"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/episode_filters_exclude" />
- </RadioGroup>
-
- <EditText
- android:id="@+id/etxtEpisodeFilterText"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:lines="8"
- android:minLines="1"
- android:maxLines="20"
- android:scrollbars="vertical"
- android:hint="@string/episode_filters_hint"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:cursorVisible="true"/>
-
- </LinearLayout>
-
- </ScrollView>
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:id="@+id/settings_fragment_container" />
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/flattr_auth.xml b/app/src/main/res/layout/flattr_auth.xml
deleted file mode 100644
index 9244b786d..000000000
--- a/app/src/main/res/layout/flattr_auth.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/txtvExplanation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="8dp"
- android:text="@string/flattr_auth_explanation" />
-
- <Button
- android:id="@+id/but_authenticate"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_margin="8dp"
- android:text="@string/authenticate_label" />
-
- <Button
- android:id="@+id/but_return_home"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:text="@string/return_home_label"
- android:visibility="gone" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/gpodnetauth_credentials.xml b/app/src/main/res/layout/gpodnetauth_credentials.xml
index f995ae4cc..e8948fc52 100644
--- a/app/src/main/res/layout/gpodnetauth_credentials.xml
+++ b/app/src/main/res/layout/gpodnetauth_credentials.xml
@@ -36,7 +36,7 @@
android:cursorVisible="true"
android:maxLines="1"
android:inputType="text"
- android:imeOptions="actionNext"
+ android:imeOptions="actionNext|flagNoFullscreen"
android:nextFocusForward="@id/etxtPassword"/>
<EditText
@@ -50,7 +50,7 @@
android:focusable="true"
android:focusableInTouchMode="true"
android:cursorVisible="true"
- android:imeOptions="actionGo"
+ android:imeOptions="actionGo|flagNoFullscreen"
android:imeActionLabel="@string/gpodnetauth_login_butLabel"/>
<Button
diff --git a/app/src/main/res/layout/gpodnetauth_device.xml b/app/src/main/res/layout/gpodnetauth_device.xml
index 5840fe955..1f38bf457 100644
--- a/app/src/main/res/layout/gpodnetauth_device.xml
+++ b/app/src/main/res/layout/gpodnetauth_device.xml
@@ -30,7 +30,8 @@
android:layout_height="wrap_content"
android:hint="@string/gpodnetauth_device_caption"
android:layout_below="@id/txtvDescription"
- android:layout_margin="8dp"/>
+ android:layout_margin="8dp"
+ android:imeOptions="flagNoFullscreen"/>
<TextView
android:id="@+id/txtvDeviceID"
@@ -53,7 +54,8 @@
android:layout_toEndOf="@id/txtvDeviceID"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
- android:layout_margin="8dp"/>
+ android:layout_margin="8dp"
+ android:imeOptions="flagNoFullscreen"/>
<Button
android:id="@+id/butCreateNewDevice"
diff --git a/app/src/main/res/layout/mediaplayerinfo_activity.xml b/app/src/main/res/layout/mediaplayerinfo_activity.xml
index c9e93e149..a6427e985 100644
--- a/app/src/main/res/layout/mediaplayerinfo_activity.xml
+++ b/app/src/main/res/layout/mediaplayerinfo_activity.xml
@@ -51,11 +51,13 @@
android:orientation="vertical">
- <RelativeLayout
+ <RelativeLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/scrubber_vertical_padding"
+ android:paddingBottom="@dimen/scrubber_vertical_padding">
- <TextView
+ <TextView
android:id="@+id/txtvPosition"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -67,9 +69,9 @@
android:text="@string/position_default_label"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/text_size_micro"
- tools:background="@android:color/holo_green_dark" />
+ tools:background="@android:color/holo_green_dark"/>
- <TextView
+ <TextView
android:id="@+id/txtvLength"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -81,9 +83,9 @@
android:text="@string/position_default_label"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/text_size_micro"
- tools:background="@android:color/holo_green_dark" />
+ tools:background="@android:color/holo_green_dark"/>
- <SeekBar
+ <SeekBar
android:id="@+id/sbPosition"
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -97,9 +99,9 @@
android:layout_toRightOf="@id/txtvPosition"
android:layout_toEndOf="@id/txtvPosition"
android:max="500"
- tools:background="@android:color/holo_green_dark" />
+ tools:background="@android:color/holo_green_dark"/>
- </RelativeLayout>
+ </RelativeLayout>
<RelativeLayout
android:id="@+id/player_control"
diff --git a/app/src/main/res/layout/nav_feedlistitem.xml b/app/src/main/res/layout/nav_feedlistitem.xml
index 9f19157fc..816870d1c 100644
--- a/app/src/main/res/layout/nav_feedlistitem.xml
+++ b/app/src/main/res/layout/nav_feedlistitem.xml
@@ -5,7 +5,12 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_iconwithtext_height"
- tools:background="@android:color/darker_gray">
+ android:paddingLeft="@dimen/listitem_icon_leftpadding"
+ android:paddingStart="@dimen/listitem_icon_leftpadding"
+ android:paddingRight="@dimen/listitem_icon_rightpadding"
+ android:paddingEnd="@dimen/listitem_icon_rightpadding"
+ tools:background="@android:color/darker_gray"
+ android:foreground="?attr/selectableItemBackground">
<ImageView
android:id="@+id/imgvCover"
@@ -20,8 +25,6 @@
android:scaleType="centerCrop"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
- android:layout_marginLeft="@dimen/listitem_icon_leftpadding"
- android:layout_marginStart="@dimen/listitem_icon_leftpadding"
tools:src="@drawable/ic_stat_antenna_default"
tools:background="@android:color/holo_green_dark"/>
@@ -31,8 +34,6 @@
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/list_vertical_padding"
android:layout_marginStart="@dimen/list_vertical_padding"
- android:layout_marginRight="@dimen/listitem_icon_rightpadding"
- android:layout_marginEnd="@dimen/listitem_icon_rightpadding"
android:lines="1"
android:textColor="?android:attr/textColorTertiary"
android:textSize="@dimen/text_size_navdrawer"
@@ -79,5 +80,4 @@
tools:text="Navigation feed item title"
tools:background="@android:color/holo_green_dark"/>
-
</RelativeLayout>
diff --git a/app/src/main/res/layout/nav_listitem.xml b/app/src/main/res/layout/nav_listitem.xml
index c140533e6..1332b5263 100644
--- a/app/src/main/res/layout/nav_listitem.xml
+++ b/app/src/main/res/layout/nav_listitem.xml
@@ -5,6 +5,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_iconwithtext_height"
+ android:foreground="?attr/selectableItemBackground"
tools:background="@android:color/darker_gray">
<ImageView
diff --git a/app/src/main/res/layout/onlinefeedview_header.xml b/app/src/main/res/layout/onlinefeedview_header.xml
index 4217322e4..057bfb379 100644
--- a/app/src/main/res/layout/onlinefeedview_header.xml
+++ b/app/src/main/res/layout/onlinefeedview_header.xml
@@ -1,88 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <ImageView
- android:id="@+id/imgvCover"
- android:layout_width="@dimen/thumbnail_length_onlinefeedview"
- android:layout_height="@dimen/thumbnail_length_onlinefeedview"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentTop="true"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
- android:layout_marginTop="16dp"
- android:contentDescription="@string/cover_label"
- tools:src="@drawable/ic_stat_antenna_default"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvTitle"
- style="@style/AntennaPod.TextView.Heading"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:layout_marginBottom="8dp"
- android:layout_marginRight="16dp"
- android:layout_marginEnd="16dp"
- android:layout_marginTop="16dp"
- android:layout_toRightOf="@id/imgvCover"
- android:layout_toEndOf="@id/imgvCover"
- android:ellipsize="end"
- android:gravity="center_vertical"
- android:maxLines="2"
- tools:text="Online feed title"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvAuthor"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtvTitle"
- android:layout_marginBottom="8dp"
- android:layout_marginRight="16dp"
- android:layout_marginEnd="16dp"
- android:layout_toRightOf="@id/imgvCover"
- android:layout_toEndOf="@id/imgvCover"
- android:ellipsize="end"
- android:lines="1"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_small"
- tools:text="Online feed author"
- tools:background="@android:color/holo_green_dark" />
-
- <LinearLayout
- android:layout_width="match_parent"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
android:layout_height="wrap_content"
- android:layout_below="@id/imgvCover"
- android:orientation="vertical">
+ android:layout_width="match_parent">
+ <include layout="@layout/feeditemlist_header"/>
- <Spinner
+ <Spinner
android:id="@+id/spinnerAlternateUrls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="16dp"
- android:layout_marginStart="16dp"
- android:layout_marginRight="16dp"
- android:layout_marginEnd="16dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
+ android:padding="8dp"
android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_micro" />
+ android:textSize="@dimen/text_size_micro"/>
- <Button
+ <Button
android:id="@+id/butSubscribe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:focusable="false"
- android:text="@string/subscribe_label" />
+ android:text="@string/subscribe_label"/>
- <TextView
+ <TextView
android:id="@+id/txtvDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -91,10 +36,22 @@
android:layout_marginStart="16dp"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
+ android:ellipsize="end"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/text_size_small"
tools:text="@string/design_time_lorem_ipsum"
tools:background="@android:color/holo_green_dark"/>
- </LinearLayout>
-</RelativeLayout> \ No newline at end of file
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
+ android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
+ android:textColor="?attr/colorAccent"
+ android:textSize="@dimen/text_size_small"
+ android:text="@string/episodes_label"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/opml_import.xml b/app/src/main/res/layout/opml_import.xml
index ac75cb8b3..9b2036228 100644
--- a/app/src/main/res/layout/opml_import.xml
+++ b/app/src/main/res/layout/opml_import.xml
@@ -15,14 +15,14 @@
tools:background="@android:color/darker_gray">
<TextView
- android:id="@+id/txtvHeadingExplanation1"
+ android:id="@+id/txtvHeadingExplanation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/AntennaPod.TextView.Heading"
android:text="@string/txtvfeedurl_label"/>
<TextView
- android:id="@+id/txtvExplanation1"
+ android:id="@+id/txtvExplanation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/opml_import_explanation_1"
@@ -39,52 +39,21 @@
android:text="@string/choose_file_from_filesystem" />
<View
- android:id="@+id/divider1"
+ android:id="@+id/divider"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:layout_margin="16dp"
android:background="?android:attr/listDivider"/>
<TextView
- android:id="@+id/txtvHeadingExplanation2"
+ android:id="@+id/txtvHeadingExplanationOpenWith"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/AntennaPod.TextView.Heading"
android:text="@string/txtvfeedurl_label"/>
<TextView
- android:id="@+id/txtvExplanation2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/opml_import_explanation_2"
- android:textSize="@dimen/text_size_medium"
- android:layout_marginTop="4dp"
- tools:background="@android:color/holo_green_dark" />
-
- <Button
- android:id="@+id/butChooseFileFromExternal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="8dp"
- android:text="@string/choose_file_from_external_application" />
-
- <View
- android:id="@+id/divider2"
- android:layout_width="fill_parent"
- android:layout_height="1dp"
- android:layout_margin="16dp"
- android:background="?android:attr/listDivider"/>
-
- <TextView
- android:id="@+id/txtvHeadingExplanation3"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/AntennaPod.TextView.Heading"
- android:text="@string/txtvfeedurl_label"/>
-
- <TextView
- android:id="@+id/txtvExplanation3"
+ android:id="@+id/txtvExplanationOpenWith"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/opml_import_explanation_3"
diff --git a/app/src/main/res/layout/queue_fragment.xml b/app/src/main/res/layout/queue_fragment.xml
index 71bf16d30..85b0df58c 100644
--- a/app/src/main/res/layout/queue_fragment.xml
+++ b/app/src/main/res/layout/queue_fragment.xml
@@ -27,14 +27,6 @@
android:layout_below="@id/divider"
android:scrollbars="vertical"/>
- <TextView
- android:id="@id/android:empty"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_centerInParent="true"
- android:gravity="center"
- android:text="@string/no_items_label" />
-
<ProgressBar
android:id="@+id/progLoading"
android:layout_width="wrap_content"
diff --git a/app/src/main/res/layout/quick_feed_discovery.xml b/app/src/main/res/layout/quick_feed_discovery.xml
new file mode 100644
index 000000000..ce5cfa65b
--- /dev/null
+++ b/app/src/main/res/layout/quick_feed_discovery.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.v7.widget.CardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:cardCornerRadius="4dp"
+ android:elevation="16dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:orientation="vertical">
+
+ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/discover"
+ android:textSize="18sp"
+ android:layout_marginBottom="8dp"
+ android:textColor="?android:attr/textColorPrimary"/>
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/discover_more"
+ android:gravity="end"
+ android:textAlignment="viewEnd"
+ android:textSize="18sp"
+ android:background="?android:attr/selectableItemBackground"
+ android:layout_marginBottom="8dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:layout_weight="1"
+ android:id="@+id/discover_more"
+ android:textColor="@color/antennapod_blue"/>
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <de.danoeh.antennapod.view.WrappingGridView
+ android:id="@+id/discover_grid"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:numColumns="4"
+ app:layout_columnWeight="1"
+ app:layout_rowWeight="1"
+ android:horizontalSpacing="4dp"
+ android:verticalSpacing="4dp"
+ android:scrollbars="none"
+ android:layout_marginTop="8dp"
+ android:layout_centerInParent="true"
+ android:layout_gravity="center_horizontal"/>
+
+ <ProgressBar
+ android:id="@+id/discover_progress_bar"
+ style="?android:attr/progressBarStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_centerInParent="true"
+ android:layout_marginTop="30dp"/>
+
+ <TextView
+ android:id="@+id/discover_error"
+ android:textColor="@color/md_edittext_error"
+ android:layout_width="match_parent"
+ android:layout_centerInParent="true"
+ android:layout_height="wrap_content" />
+
+ </RelativeLayout>
+
+ </LinearLayout>
+
+</android.support.v7.widget.CardView>
+
diff --git a/app/src/main/res/layout/quick_feed_discovery_item.xml b/app/src/main/res/layout/quick_feed_discovery_item.xml
new file mode 100644
index 000000000..6b0c98013
--- /dev/null
+++ b/app/src/main/res/layout/quick_feed_discovery_item.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <de.danoeh.antennapod.view.SquareImageView
+ android:id="@+id/discovery_cover"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:foreground="?android:attr/selectableItemBackground"/>
+
+</LinearLayout>
+
diff --git a/app/src/main/res/layout/simple_list_item_multiple_choice_on_start.xml b/app/src/main/res/layout/simple_list_item_multiple_choice_on_start.xml
new file mode 100644
index 000000000..3c03f71ea
--- /dev/null
+++ b/app/src/main/res/layout/simple_list_item_multiple_choice_on_start.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Based on simple_list_item_multiple_choice.xml
+ from The Android Open Source Project
+ This one puts the check box at the start of the view (rather than at the end).
+ -->
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:gravity="center_vertical"
+ android:drawableStart="?android:attr/listChoiceIndicatorMultiple"
+ android:drawableLeft="?android:attr/listChoiceIndicatorMultiple"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingRight="?android:attr/listPreferredItemPaddingRight"
+ />
diff --git a/app/src/main/res/layout/videoplayer_activity.xml b/app/src/main/res/layout/videoplayer_activity.xml
index ebea0c618..4de46810e 100644
--- a/app/src/main/res/layout/videoplayer_activity.xml
+++ b/app/src/main/res/layout/videoplayer_activity.xml
@@ -33,27 +33,27 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
- android:background="@drawable/overlay_button_circle_background"
+ android:background="@drawable/md_transparent"
android:contentDescription="@string/rewind_label"
- android:src="@drawable/ic_av_rewind_80dp" />
+ android:src="@drawable/ic_av_fast_rewind_white_80dp" />
<ImageButton
android:id="@+id/butPlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
- android:background="@drawable/overlay_button_circle_background"
+ android:background="@drawable/md_transparent"
android:contentDescription="@string/pause_label"
- android:src="@drawable/ic_av_pause_circle_outline_80dp" />
+ android:src="@drawable/ic_av_pause_white_80dp" />
<ImageButton
android:id="@+id/butFF"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
- android:background="@drawable/overlay_button_circle_background"
+ android:background="@drawable/md_transparent"
android:contentDescription="@string/fast_forward_label"
- android:src="@drawable/ic_av_fast_forward_80dp" />
+ android:src="@drawable/ic_av_fast_forward_white_80dp" />
</LinearLayout>
diff --git a/app/src/main/res/menu/advanced_search.xml b/app/src/main/res/menu/advanced_search.xml
new file mode 100644
index 000000000..297ebfce8
--- /dev/null
+++ b/app/src/main/res/menu/advanced_search.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/search_itunes"
+ android:title="@string/search_itunes_label" />
+ <item
+ android:id="@+id/search_gpodder"
+ android:title="@string/browse_gpoddernet_label" />
+ <item
+ android:id="@+id/search_fyyd"
+ android:title="@string/search_fyyd_label" />
+
+</menu>
diff --git a/app/src/main/res/menu/allepisodes_context.xml b/app/src/main/res/menu/allepisodes_context.xml
index 28493c5b6..907bc9334 100644
--- a/app/src/main/res/menu/allepisodes_context.xml
+++ b/app/src/main/res/menu/allepisodes_context.xml
@@ -9,9 +9,9 @@
<item
- android:id="@+id/mark_as_seen_item"
+ android:id="@+id/remove_new_flag_item"
android:menuCategory="container"
- android:title="@string/mark_as_seen_label" />
+ android:title="@string/remove_new_flag_label" />
<item
android:id="@+id/mark_read_item"
@@ -83,10 +83,4 @@
android:title="@string/share_file_label" />
</menu>
</item>
-
- <item
- android:id="@+id/support_item"
- android:menuCategory="container"
- android:title="@string/support_label" />
-
</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/episodes.xml b/app/src/main/res/menu/episodes.xml
index bbaabcd8b..23c8f862a 100644
--- a/app/src/main/res/menu/episodes.xml
+++ b/app/src/main/res/menu/episodes.xml
@@ -6,7 +6,7 @@
<item
android:id="@+id/action_search"
android:icon="?attr/action_search"
- custom:showAsAction="always"
+ custom:showAsAction="collapseActionView|ifRoom"
custom:actionViewClass="android.support.v7.widget.SearchView"
android:title="@string/search_label"/>
@@ -14,7 +14,7 @@
android:id="@+id/refresh_item"
android:title="@string/refresh_label"
android:menuCategory="container"
- custom:showAsAction="always"
+ custom:showAsAction="ifRoom"
android:icon="?attr/navigation_refresh"/>
<item
@@ -25,8 +25,8 @@
android:icon="?attr/navigation_accept"/>
<item
- android:id="@+id/mark_all_seen_item"
- android:title="@string/mark_all_seen_label"
+ android:id="@+id/remove_all_new_flags_item"
+ android:title="@string/remove_all_new_flags_label"
android:menuCategory="container"
custom:showAsAction="collapseActionView"
android:icon="?attr/navigation_accept"/>
diff --git a/app/src/main/res/menu/episodes_apply_action_speeddial.xml b/app/src/main/res/menu/episodes_apply_action_speeddial.xml
new file mode 100644
index 000000000..39083e41b
--- /dev/null
+++ b/app/src/main/res/menu/episodes_apply_action_speeddial.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- the order is opposite of the typical menu:
+ catered to FAB speed dial, which somehow shows the item in reverse.
+ E.g., item @id/delete_batch is the first in the xml,
+ visually it will be shown at the bottom of the list of actions.
+ -->
+ <item android:id="@+id/delete_batch"
+ android:icon="?attr/content_discard"
+ android:title="@string/delete_episode_label"
+ />
+ <item android:id="@+id/download_batch"
+ android:icon="?attr/av_download"
+ android:title="@string/download_label"
+ />
+ <item android:id="@+id/mark_unread_batch"
+ android:icon="?attr/navigation_cancel"
+ android:title="@string/mark_unread_label"
+ />
+ <item
+ android:id="@+id/mark_read_batch"
+ android:icon="?attr/navigation_accept"
+ android:title="@string/mark_read_label"
+ />
+ <item android:id="@+id/remove_from_queue_batch"
+ android:icon="?attr/content_remove_from_queue"
+ android:title="@string/remove_from_queue_label"
+ />
+ <item
+ android:id="@+id/add_to_queue_batch"
+ android:icon="?attr/content_new"
+ android:title="@string/add_to_queue_label"
+ />
+</menu>
diff --git a/app/src/main/res/menu/feedinfo.xml b/app/src/main/res/menu/feedinfo.xml
index 9fdd56b6c..300068007 100644
--- a/app/src/main/res/menu/feedinfo.xml
+++ b/app/src/main/res/menu/feedinfo.xml
@@ -9,12 +9,6 @@
android:visible="true">
</item>
<item
- android:id="@+id/support_item"
- custom:showAsAction="ifRoom|collapseActionView"
- android:title="@string/support_label"
- android:visible="false">
- </item>
- <item
android:id="@+id/share_link_item"
custom:showAsAction="collapseActionView"
android:title="@string/share_link_label">
diff --git a/app/src/main/res/menu/feeditem_options.xml b/app/src/main/res/menu/feeditem_options.xml
index 7e111d816..0801b79a1 100644
--- a/app/src/main/res/menu/feeditem_options.xml
+++ b/app/src/main/res/menu/feeditem_options.xml
@@ -92,12 +92,6 @@
</item>
<item
- android:id="@+id/support_item"
- custom:showAsAction="collapseActionView"
- android:title="@string/support_label">
- </item>
-
- <item
android:id="@+id/open_podcast"
custom:showAsAction="collapseActionView"
android:title="@string/open_podcast">
diff --git a/app/src/main/res/menu/feeditemlist_context.xml b/app/src/main/res/menu/feeditemlist_context.xml
index d3ec88bc7..df13cb027 100644
--- a/app/src/main/res/menu/feeditemlist_context.xml
+++ b/app/src/main/res/menu/feeditemlist_context.xml
@@ -24,6 +24,10 @@
android:id="@+id/remove_from_queue_item"
android:menuCategory="container"
android:title="@string/remove_from_queue_label" />
+ <item
+ android:id="@+id/remove_item"
+ android:menuCategory="container"
+ android:title="@string/delete_label" />
<item
android:id="@+id/add_to_favorites_item"
@@ -79,11 +83,4 @@
android:title="@string/share_file_label" />
</menu>
</item>
-
-
- <item
- android:id="@+id/support_item"
- android:menuCategory="container"
- android:title="@string/support_label" />
-
</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/feedlist.xml b/app/src/main/res/menu/feedlist.xml
index 3882cdff1..e62fc9d36 100644
--- a/app/src/main/res/menu/feedlist.xml
+++ b/app/src/main/res/menu/feedlist.xml
@@ -38,14 +38,6 @@
android:title="@string/search_label"/>
<item
- android:id="@+id/support_item"
- android:menuCategory="container"
- android:title="@string/support_label"
- android:visible="false"
- custom:showAsAction="collapseActionView">
- </item>
-
- <item
android:id="@+id/visit_website_item"
android:icon="?attr/location_web_site"
android:menuCategory="container"
diff --git a/app/src/main/res/menu/mediaplayer.xml b/app/src/main/res/menu/mediaplayer.xml
index 98c7478a6..44d511ee4 100644
--- a/app/src/main/res/menu/mediaplayer.xml
+++ b/app/src/main/res/menu/mediaplayer.xml
@@ -78,11 +78,4 @@
android:title="@string/share_file_label" />
</menu>
</item>
- <item
- android:id="@+id/support_item"
- custom:showAsAction="collapseActionView"
- android:title="@string/support_label"
- android:visible="false">
- </item>
-
</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/nav_feed_context.xml b/app/src/main/res/menu/nav_feed_context.xml
index 4da40441f..7fdee5661 100644
--- a/app/src/main/res/menu/nav_feed_context.xml
+++ b/app/src/main/res/menu/nav_feed_context.xml
@@ -2,9 +2,9 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:id="@+id/mark_all_seen_item"
+ android:id="@+id/remove_all_new_flags_item"
android:menuCategory="container"
- android:title="@string/mark_all_seen_label" />
+ android:title="@string/remove_all_new_flags_label" />
<item
android:id="@+id/mark_all_read_item"
diff --git a/app/src/main/res/menu/opml_selection_options.xml b/app/src/main/res/menu/opml_selection_options.xml
index 26d2a0519..8b3310dc2 100644
--- a/app/src/main/res/menu/opml_selection_options.xml
+++ b/app/src/main/res/menu/opml_selection_options.xml
@@ -4,14 +4,14 @@
<item
android:id="@id/select_all_item"
- android:icon="?attr/ic_check_box_outline"
+ android:icon="?attr/ic_select_all"
android:title="@string/select_all_label"
custom:showAsAction="ifRoom">
</item>
<item
android:id="@id/deselect_all_item"
- android:icon="?attr/ic_check_box"
+ android:icon="?attr/ic_select_none"
android:title="@string/deselect_all_label"
custom:showAsAction="ifRoom">
</item>
diff --git a/app/src/main/res/menu/queue.xml b/app/src/main/res/menu/queue.xml
index 7b82cbef3..a4e511eb8 100644
--- a/app/src/main/res/menu/queue.xml
+++ b/app/src/main/res/menu/queue.xml
@@ -24,13 +24,6 @@
android:title="@string/search_label"/>
<item
- android:id="@+id/clear_queue"
- android:title="@string/clear_queue_label"
- android:menuCategory="container"
- custom:showAsAction="collapseActionView"
- android:icon="?attr/navigation_accept"/>
-
- <item
android:id="@+id/queue_sort"
android:title="@string/sort">
@@ -42,10 +35,10 @@
<menu>
<item
android:id="@+id/queue_sort_date_asc"
- android:title="@string/ascending"/>
+ android:title="@string/sort_old_to_new"/>
<item
android:id="@+id/queue_sort_date_desc"
- android:title="@string/descending"/>
+ android:title="@string/sort_new_to_old"/>
</menu>
</item>
@@ -103,13 +96,29 @@
<menu>
<item
android:id="@+id/queue_sort_smart_shuffle_asc"
- android:title="@string/ascending"/>
+ android:title="@string/sort_old_to_new"/>
<item
android:id="@+id/queue_sort_smart_shuffle_desc"
- android:title="@string/descending"/>
+ android:title="@string/sort_new_to_old"/>
</menu>
</item>
+
+ <item
+ android:id="@+id/queue_keep_sorted"
+ android:title="@string/keep_sorted"
+ android:checkable="true" />
</menu>
</item>
+ <item
+ android:id="@+id/clear_queue"
+ android:title="@string/clear_queue_label"
+ custom:showAsAction="collapseActionView"
+ android:icon="?attr/navigation_accept"/>
+
+ <item
+ android:id="@+id/episode_actions"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/batch_edit" />
+
</menu>
diff --git a/app/src/main/res/menu/queue_context.xml b/app/src/main/res/menu/queue_context.xml
index e93d808c1..e1c3e6216 100644
--- a/app/src/main/res/menu/queue_context.xml
+++ b/app/src/main/res/menu/queue_context.xml
@@ -26,6 +26,10 @@
android:id="@+id/remove_from_queue_item"
android:menuCategory="container"
android:title="@string/remove_from_queue_label" />
+ <item
+ android:id="@+id/remove_item"
+ android:menuCategory="container"
+ android:title="@string/delete_label" />
<item
android:id="@+id/add_to_favorites_item"
@@ -80,10 +84,4 @@
android:title="@string/share_file_label" />
</menu>
</item>
- <item
- android:id="@+id/support_item"
- android:menuCategory="container"
- android:title="@string/support_label" />
-
-
</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/subscriptions.xml b/app/src/main/res/menu/subscriptions.xml
new file mode 100644
index 000000000..f39e0ac97
--- /dev/null
+++ b/app/src/main/res/menu/subscriptions.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/subscription_num_columns"
+ android:title="@string/subscription_num_columns"
+ custom:showAsAction="never">
+ <menu>
+ <item
+ android:id="@+id/subscription_num_columns_2"
+ android:checkable="true"
+ android:title="2"/>
+ <item
+ android:id="@+id/subscription_num_columns_3"
+ android:checkable="true"
+ android:title="3"/>
+ <item
+ android:id="@+id/subscription_num_columns_4"
+ android:checkable="true"
+ android:title="4"/>
+ <item
+ android:id="@+id/subscription_num_columns_5"
+ android:checkable="true"
+ android:title="5"/>
+ </menu>
+ </item>
+</menu>
diff --git a/app/src/main/res/values-w300dp/dimens-fabspeeddial.xml b/app/src/main/res/values-w300dp/dimens-fabspeeddial.xml
new file mode 100644
index 000000000..e531395c0
--- /dev/null
+++ b/app/src/main/res/values-w300dp/dimens-fabspeeddial.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- increase FAB speed dial label's max width if the screen is wide enough
+ (300dp ~ 1.875 inch, devices with 3.5-inch screens have a width of ~ 1.9in
+ so the setup is applicable for most phones)
+ -->
+ <dimen name="sd_label_max_width">240dp</dimen>
+</resources>
diff --git a/app/src/main/res/xml/feed_settings.xml b/app/src/main/res/xml/feed_settings.xml
new file mode 100644
index 000000000..5fd6b2038
--- /dev/null
+++ b/app/src/main/res/xml/feed_settings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <SwitchPreference
+ android:key="keepUpdated"
+ android:title="@string/keep_updated"
+ android:summary="@string/keep_updated_summary"/>
+
+ <Preference
+ android:key="authentication"
+ android:title="@string/authentication_label"
+ android:summary="@string/authentication_descr"/>
+
+ <ListPreference
+ android:entries="@array/spnAutoDeleteItems"
+ android:entryValues="@array/spnAutoDeleteValues"
+ android:title="@string/auto_delete_label"
+ android:key="autoDelete"/>
+
+ <PreferenceCategory android:title="@string/auto_download_settings_label">
+ <SwitchPreference
+ android:key="autoDownload"
+ android:title="@string/auto_download_label"/>
+ <Preference
+ android:key="episodeFilter"
+ android:title="@string/episode_filters_label"
+ android:summary="@string/episode_filters_description"/>
+ </PreferenceCategory>
+</PreferenceScreen>
diff --git a/app/src/main/res/xml/preferences_autodownload.xml b/app/src/main/res/xml/preferences_autodownload.xml
index b5e3182f0..a4967c839 100644
--- a/app/src/main/res/xml/preferences_autodownload.xml
+++ b/app/src/main/res/xml/preferences_autodownload.xml
@@ -14,6 +14,7 @@
android:entries="@array/episode_cache_size_entries"
android:key="prefEpisodeCacheSize"
android:title="@string/pref_episode_cache_title"
+ android:summary="@string/pref_episode_cache_summary"
android:entryValues="@array/episode_cache_size_values"
app:useStockLayout="true"/>
<ListPreference
@@ -30,11 +31,6 @@
android:summary="@string/pref_automatic_download_on_battery_sum"
android:defaultValue="true"/>
<SwitchPreference
- android:key="prefEnableAutoDownloadOnMobile"
- android:title="@string/pref_autodl_allow_on_mobile_title"
- android:summary="@string/pref_autodl_allow_on_mobile_sum"
- android:defaultValue="false"/>
- <SwitchPreference
android:key="prefEnableAutoDownloadWifiFilter"
android:title="@string/pref_autodl_wifi_filter_title"
android:summary="@string/pref_autodl_wifi_filter_sum"/>
diff --git a/app/src/main/res/xml/preferences_flattr.xml b/app/src/main/res/xml/preferences_flattr.xml
deleted file mode 100644
index 6b4c38a0b..000000000
--- a/app/src/main/res/xml/preferences_flattr.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android">
-
- <PreferenceScreen
- android:key="pref_flattr_authenticate"
- android:summary="@string/pref_flattr_auth_sum"
- android:title="@string/pref_flattr_auth_title">
- <intent android:action=".activities.FlattrAuthActivity"/>
- </PreferenceScreen>
-
- <Preference
- android:key="prefAutoFlattrPrefs"
- android:summary="@string/pref_auto_flattr_sum"
- android:title="@string/pref_auto_flattr_title"/>
- <Preference
- android:key="prefRevokeAccess"
- android:summary="@string/pref_revokeAccess_sum"
- android:title="@string/pref_revokeAccess_title"/>
-
-</PreferenceScreen>
diff --git a/app/src/main/res/xml/preferences_integrations.xml b/app/src/main/res/xml/preferences_integrations.xml
index c0fd299ec..716f6c476 100644
--- a/app/src/main/res/xml/preferences_integrations.xml
+++ b/app/src/main/res/xml/preferences_integrations.xml
@@ -1,12 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
-
- <Preference
- android:key="prefFlattrSettings"
- android:title="@string/flattr_label"
- android:summary="@string/flattr_summary" />
+ xmlns:android="http://schemas.android.com/apk/res/android">
<Preference
android:key="prefGpodderSettings"
diff --git a/app/src/main/res/xml/preferences_network.xml b/app/src/main/res/xml/preferences_network.xml
index c37a99465..9d1ce28c6 100644
--- a/app/src/main/res/xml/preferences_network.xml
+++ b/app/src/main/res/xml/preferences_network.xml
@@ -16,10 +16,11 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/download_pref_details">
- <SwitchPreference
- android:defaultValue="false"
- android:enabled="true"
- android:key="prefMobileUpdate"
+ <MultiSelectListPreference
+ android:defaultValue="@array/mobile_update_default_value"
+ android:entries="@array/mobile_update_entries"
+ android:entryValues="@array/mobile_update_values"
+ android:key="prefMobileUpdateTypes"
android:summary="@string/pref_mobileUpdate_sum"
android:title="@string/pref_mobileUpdate_title"/>
<de.danoeh.antennapod.preferences.NumberPickerPreference
diff --git a/app/src/main/res/xml/preferences_playback.xml b/app/src/main/res/xml/preferences_playback.xml
index 9182df600..d609d3daa 100644
--- a/app/src/main/res/xml/preferences_playback.xml
+++ b/app/src/main/res/xml/preferences_playback.xml
@@ -46,7 +46,7 @@
app:useStockLayout="true"/>
</PreferenceCategory>
- <PreferenceCategory android:title="@string/buttons">
+ <PreferenceCategory android:title="@string/playback_control">
<SwitchPreference
android:defaultValue="false"
android:enabled="true"
@@ -71,6 +71,11 @@
android:key="prefPlaybackSpeedLauncher"
android:summary="@string/pref_playback_speed_sum"
android:title="@string/pref_playback_speed_title"/>
+ <SwitchPreference
+ android:defaultValue="false"
+ android:key="prefPlaybackTimeRespectsSpeed"
+ android:summary="@string/pref_playback_time_respects_speed_sum"
+ android:title="@string/pref_playback_time_respects_speed_title"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/queue_label">
@@ -110,7 +115,7 @@
<PreferenceCategory android:title="@string/media_player">
<ListPreference
- android:defaultValue="sonic"
+ android:defaultValue="exoplayer"
android:entries="@array/media_player_options"
android:key="prefMediaPlayer"
android:title="@string/media_player"
diff --git a/app/src/main/res/xml/preferences_storage.xml b/app/src/main/res/xml/preferences_storage.xml
index fe48cc99c..9f394ad12 100644
--- a/app/src/main/res/xml/preferences_storage.xml
+++ b/app/src/main/res/xml/preferences_storage.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:search="http://schemas.android.com/apk/com.bytehamster.lib.preferencesearch">
<Preference
android:title="@string/choose_data_directory"
@@ -25,6 +25,12 @@
android:key="prefFavoriteKeepsEpisode"
android:summary="@string/pref_favorite_keeps_episodes_sum"
android:title="@string/pref_favorite_keeps_episodes_title"/>
+ <SwitchPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefDeleteRemovesFromQueue"
+ android:summary="@string/pref_delete_removes_from_queue_sum"
+ android:title="@string/pref_delete_removes_from_queue_title"/>
<PreferenceCategory android:title="@string/import_export_pref">
<Preference
@@ -38,6 +44,7 @@
android:title="@string/html_export_label"/>
<Preference
android:key="importExport"
+ search:keywords="@string/import_export_search_keywords"
android:title="@string/import_export"/>
</PreferenceCategory>
</PreferenceScreen>
diff --git a/app/src/main/templates/about.html b/app/src/main/templates/about.html
index cc3a24e62..05d1b6e28 100644
--- a/app/src/main/templates/about.html
+++ b/app/src/main/templates/about.html
@@ -104,11 +104,6 @@ by Google, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt
</div>
<div class="card">
-<h2>flattr4j <a href="http://www.shredzone.org/projects/flattr4j/wiki">(Link)</a></h2>
-licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
-</div>
-
-<div class="card">
<h2>Glide <a href="https://github.com/bumptech/glide/">(Link)</a></h2>
licensed under the Simplified BSD license <a href="LICENSE_GLIDE.txt">(View)</a>
</div>
diff --git a/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java b/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java
index eab085479..ae8e20575 100644
--- a/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java
+++ b/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java
@@ -455,6 +455,7 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
return context.getTheme().resolveAttribute(attr, value, true) ? value.resourceId : 0;
}
+ @NonNull
private Pair<Bitmap, Integer> fetchArt(@NonNull MediaDescriptionCompat description) {
Bitmap iconBitmap = description.getIconBitmap();
Uri iconUri = description.getIconUri();
diff --git a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
index b9b4e891f..c9d52df0c 100644
--- a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
+++ b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
@@ -4,13 +4,14 @@ import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.fragment.preferences.PlaybackPreferencesFragment;
/**
* Implements functions from PreferenceController that are flavor dependent.
*/
public class PreferenceControllerFlavorHelper {
- static void setupFlavoredUI(PreferenceController.PreferenceUI ui) {
+ public static void setupFlavoredUI(PlaybackPreferencesFragment ui) {
//checks whether Google Play Services is installed on the device (condition necessary for Cast support)
ui.findPreference(UserPreferences.PREF_CAST_ENABLED).setOnPreferenceChangeListener((preference, o) -> {
if (o instanceof Boolean && ((Boolean) o)) {
diff --git a/app/src/play/play b/app/src/play/play
new file mode 120000
index 000000000..e9d641154
--- /dev/null
+++ b/app/src/play/play
@@ -0,0 +1 @@
+../main/play \ No newline at end of file