summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/build.gradle99
-rw-r--r--app/proguard.cfg13
-rw-r--r--app/sampledata/episodes.json34
-rw-r--r--app/sampledata/inplaylist2
-rw-r--r--app/sampledata/secondaryaction3
-rw-r--r--app/src/androidTest/java/de/test/antennapod/AntennaPodTestRunner.java18
-rw-r--r--app/src/androidTest/java/de/test/antennapod/NthMatcher.java38
-rw-r--r--app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java38
-rw-r--r--app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java46
-rw-r--r--app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java32
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java16
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java1
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java9
-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.java204
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java216
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java285
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java35
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java11
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/URIUtilTest.java1
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java1
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/service/download/NanoHTTPD.java152
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/AtomGenerator.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/FeedGenerator.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/GeneratorUtil.java3
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/RSS2Generator.java8
-rw-r--r--app/src/free/java/de/danoeh/antennapod/config/CastCallbackImpl.java2
-rw-r--r--app/src/free/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java2
-rw-r--r--app/src/main/AndroidManifest.xml43
-rw-r--r--app/src/main/assets/LICENSE_SIL.txt91
-rwxr-xr-xapp/src/main/assets/logo.pngbin58799 -> 60183 bytes
-rw-r--r--app/src/main/java/de/danoeh/antennapod/PodcastApp.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java154
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java53
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java299
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java364
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FlattrAuthActivity.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java190
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java130
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java249
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java91
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java158
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java17
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java95
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java97
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java50
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java38
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java182
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java40
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java84
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java43
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java113
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/CoverTarget.java58
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java23
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java27
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java43
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java40
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java51
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java32
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java23
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/AuthenticationDialog.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java45
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java110
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java14
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java25
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java114
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java63
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java53
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java124
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java55
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java109
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java122
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java64
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java35
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java30
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java97
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java75
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastTopListFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java48
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java107
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java757
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/SwitchCompatPreference.java37
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java80
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java245
-rw-r--r--app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/AspectRatioVideoView.java22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java5
-rw-r--r--app/src/main/play/ar/listing/fulldescription2
-rw-r--r--app/src/main/play/bg/listing/fulldescription43
-rw-r--r--app/src/main/play/ca/listing/fulldescription68
-rw-r--r--app/src/main/play/ca/listing/video0
-rw-r--r--app/src/main/play/contactPhone0
-rw-r--r--app/src/main/play/cs-CZ/listing/video0
-rw-r--r--app/src/main/play/da-DK/listing/video0
-rw-r--r--app/src/main/play/de-DE/listing/video0
-rw-r--r--app/src/main/play/de/listing/fulldescription4
-rw-r--r--app/src/main/play/el/listing/fulldescription26
-rw-r--r--app/src/main/play/en-US/listing/featureGraphic/feature-graphic.pngbin0 -> 60183 bytes
-rw-r--r--app/src/main/play/en-US/listing/video0
-rw-r--r--app/src/main/play/es-ES/listing/video0
-rw-r--r--app/src/main/play/es/listing/fulldescription2
-rw-r--r--app/src/main/play/fa/listing/fulldescription4
-rw-r--r--app/src/main/play/fr-FR/listing/video0
-rw-r--r--app/src/main/play/he_IL/listing/fulldescription62
-rw-r--r--app/src/main/play/hi-IN/listing/video0
-rw-r--r--app/src/main/play/it-IT/listing/video0
-rw-r--r--app/src/main/play/it/listing/fulldescription38
-rw-r--r--app/src/main/play/it_IT/listing/fulldescription24
-rw-r--r--app/src/main/play/iw-IL/listing/video0
-rw-r--r--app/src/main/play/ja-JP/listing/video0
-rw-r--r--app/src/main/play/ko-KR/listing/video0
-rw-r--r--app/src/main/play/ms_MY/listing/fulldescription43
-rw-r--r--app/src/main/play/nb_NO/listing/fulldescription8
-rw-r--r--app/src/main/play/nl-NL/listing/video0
-rw-r--r--app/src/main/play/pl-PL/listing/video0
-rw-r--r--app/src/main/play/pt-BR/listing/video0
-rw-r--r--app/src/main/play/pt-PT/listing/video0
-rw-r--r--app/src/main/play/ro/listing/video0
-rw-r--r--app/src/main/play/ru-RU/listing/video0
-rw-r--r--app/src/main/play/sl_SI/listing/fulldescription43
-rw-r--r--app/src/main/play/sv-SE/listing/video0
-rw-r--r--app/src/main/play/tr-TR/listing/video0
-rw-r--r--app/src/main/play/uk/listing/video0
-rw-r--r--app/src/main/play/vi/listing/fulldescription8
-rw-r--r--app/src/main/play/zh-CN/listing/video0
-rw-r--r--app/src/main/res/layout-v14/authentication_dialog.xml87
-rw-r--r--app/src/main/res/layout-v14/directory_chooser.xml114
-rw-r--r--app/src/main/res/layout-v14/download_authentication_activity.xml98
-rw-r--r--app/src/main/res/layout-v14/opml_selection.xml61
-rw-r--r--app/src/main/res/layout-v14/time_dialog.xml67
-rw-r--r--app/src/main/res/layout/about.xml4
-rw-r--r--app/src/main/res/layout/all_episodes_fragment.xml8
-rw-r--r--app/src/main/res/layout/audio_controls.xml7
-rw-r--r--app/src/main/res/layout/authentication_dialog.xml61
-rw-r--r--app/src/main/res/layout/cover_fragment.xml3
-rw-r--r--app/src/main/res/layout/directory_chooser.xml67
-rw-r--r--app/src/main/res/layout/download_authentication_activity.xml55
-rw-r--r--app/src/main/res/layout/downloaded_episodeslist_item.xml89
-rw-r--r--app/src/main/res/layout/downloadlist_item.xml7
-rw-r--r--app/src/main/res/layout/downloadlog_item.xml17
-rw-r--r--app/src/main/res/layout/ellipsize_start_listitem.xml21
-rw-r--r--app/src/main/res/layout/external_player_fragment.xml152
-rw-r--r--app/src/main/res/layout/feedinfo.xml250
-rw-r--r--app/src/main/res/layout/feeditem_fragment.xml10
-rw-r--r--app/src/main/res/layout/feeditemlist_header.xml35
-rw-r--r--app/src/main/res/layout/feeditemlist_item.xml30
-rw-r--r--app/src/main/res/layout/feedsettings.xml218
-rw-r--r--app/src/main/res/layout/gpodnet_podcast_listitem.xml7
-rw-r--r--app/src/main/res/layout/gpodnet_tag_listitem.xml3
-rw-r--r--app/src/main/res/layout/gpodnetauth_credentials.xml6
-rw-r--r--app/src/main/res/layout/gpodnetauth_device.xml17
-rw-r--r--app/src/main/res/layout/import_export_activity.xml34
-rw-r--r--app/src/main/res/layout/itemdescription_listitem.xml4
-rw-r--r--app/src/main/res/layout/itunes_podcast_listitem.xml3
-rw-r--r--app/src/main/res/layout/main.xml2
-rw-r--r--app/src/main/res/layout/mediaplayerinfo_activity.xml27
-rw-r--r--app/src/main/res/layout/nav_feedlistitem.xml12
-rw-r--r--app/src/main/res/layout/nav_list.xml9
-rw-r--r--app/src/main/res/layout/nav_listitem.xml8
-rw-r--r--app/src/main/res/layout/new_episodes_listitem.xml48
-rw-r--r--app/src/main/res/layout/numberpicker.xml16
-rw-r--r--app/src/main/res/layout/onlinefeedview_header.xml10
-rw-r--r--app/src/main/res/layout/opml_import.xml2
-rw-r--r--app/src/main/res/layout/opml_selection.xml54
-rw-r--r--app/src/main/res/layout/player_widget.xml52
-rw-r--r--app/src/main/res/layout/preference_switch_layout.xml9
-rw-r--r--app/src/main/res/layout/queue_listitem.xml22
-rw-r--r--app/src/main/res/layout/searchlist_item.xml14
-rw-r--r--app/src/main/res/layout/secondary_action.xml3
-rw-r--r--app/src/main/res/layout/simplechapter_item.xml5
-rw-r--r--app/src/main/res/layout/splash.xml14
-rw-r--r--app/src/main/res/layout/statistics_listitem.xml10
-rw-r--r--app/src/main/res/layout/subscription_item.xml2
-rw-r--r--app/src/main/res/layout/time_dialog.xml9
-rw-r--r--app/src/main/res/layout/videoplayer_activity.xml14
-rw-r--r--app/src/main/res/menu/allepisodes_context.xml6
-rw-r--r--app/src/main/res/menu/downloads_completed.xml3
-rw-r--r--app/src/main/res/menu/feedlist.xml3
-rw-r--r--app/src/main/res/menu/mediaplayer.xml8
-rw-r--r--app/src/main/res/menu/queue.xml19
-rw-r--r--app/src/main/res/xml/preferences.xml361
-rw-r--r--app/src/main/res/xml/preferences_autodownload.xml41
-rw-r--r--app/src/main/res/xml/preferences_flattr.xml21
-rw-r--r--app/src/main/res/xml/preferences_gpodder.xml35
-rw-r--r--app/src/main/res/xml/preferences_integrations.xml16
-rw-r--r--app/src/main/res/xml/preferences_network.xml42
-rw-r--r--app/src/main/res/xml/preferences_playback.xml130
-rw-r--r--app/src/main/res/xml/preferences_storage.xml43
-rw-r--r--app/src/main/res/xml/preferences_user_interface.xml70
-rw-r--r--app/src/main/templates/about.html100
-rw-r--r--app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java30
239 files changed, 5697 insertions, 4577 deletions
diff --git a/app/build.gradle b/app/build.gradle
index ad388bd02..a79ad180e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,7 +1,6 @@
import org.apache.tools.ant.filters.ReplaceTokens
apply plugin: "com.android.application"
-apply plugin: "me.tatarka.retrolambda"
apply plugin: 'com.github.triplet.play'
apply plugin: 'com.getkeepsafe.dexcount'
@@ -15,7 +14,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.1'
+ classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
}
}
@@ -44,7 +43,7 @@ android {
versionCode getMyVersionCode()
versionName "${getMyVersionName()}"
testApplicationId "de.test.antennapod"
- testInstrumentationRunner "de.test.antennapod.AntennaPodTestRunner"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
generatedDensities = []
}
@@ -84,9 +83,17 @@ android {
applicationIdSuffix ".debug"
resValue "string", "provider_authority", "de.danoeh.antennapod.debug.provider"
buildConfigField STRING, FLATTR_APP_KEY, mFlattrAppKey
- buildConfigField STRING, FLATTR_APP_SECRET, mFlattrAppSecret
+ buildConfigField STRING, FLATTR_APP_SECRET, mFlattrAppSecret
+ dexcount {
+ if (project.hasProperty("enableDexcountInDebug")) {
+ runOnEachPackage enableDexcountInDebug.toBoolean()
+ } else { // default to not running dexcount
+ runOnEachPackage false
+ }
+ }
}
release {
+ resValue "string", "provider_authority", "de.danoeh.antennapod.provider"
minifyEnabled true
proguardFile "proguard.cfg"
signingConfig signingConfigs.releaseConfig
@@ -113,10 +120,17 @@ android {
additionalParameters "--no-version-vectors"
}
+ testOptions {
+ animationsDisabled = true
+ }
+
+ flavorDimensions "market"
productFlavors {
free {
+ dimension "market"
}
play {
+ dimension "market"
}
}
@@ -125,59 +139,60 @@ android {
}
}
-configurations {
- freeDebugCompile
- freeReleaseCompile
- playDebugCompile
- playReleaseCompile
-}
-
dependencies {
- freeDebugCompile project(path: ":core", configuration: "freeDebug")
- freeReleaseCompile project(path: ":core", configuration: "freeRelease")
+ freeImplementation project(":core")
// free build hack: skip some dependencies
if (!doFreeBuild()) {
- playDebugCompile project(path: ":core", configuration: "playDebug")
- playReleaseCompile project(path: ":core", configuration: "playRelease")
+ playImplementation project(":core")
} else {
System.out.println("app: free build hack, skipping some dependencies")
}
- compile "com.android.support:support-v4:$supportVersion"
- compile "com.android.support:appcompat-v7:$supportVersion"
- compile "com.android.support:design:$supportVersion"
- compile "com.android.support:gridlayout-v7:$supportVersion"
- compile "com.android.support:percent:$supportVersion"
- compile "com.android.support:recyclerview-v7:$supportVersion"
- compile "org.apache.commons:commons-lang3:$commonslangVersion"
- compile("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
+ implementation "com.android.support:support-v4:$supportVersion"
+ implementation "com.android.support:appcompat-v7:$supportVersion"
+ implementation "com.android.support:design:$supportVersion"
+ implementation "com.android.support:preference-v14:$supportVersion"
+ implementation "com.android.support:gridlayout-v7:$supportVersion"
+ implementation "com.android.support:percent:$supportVersion"
+ implementation "com.android.support:recyclerview-v7:$supportVersion"
+ compileOnly 'com.google.android.wearable:wearable:2.2.0'
+ implementation "org.apache.commons:commons-lang3:$commonslangVersion"
+ implementation("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
exclude group: "org.json", module: "json"
}
- compile "commons-io:commons-io:$commonsioVersion"
- compile "org.jsoup:jsoup:$jsoupVersion"
- compile "com.github.bumptech.glide:glide:$glideVersion"
- compile "com.squareup.okhttp3:okhttp:$okhttpVersion"
- compile "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
- compile "com.squareup.okio:okio:$okioVersion"
- compile "de.greenrobot:eventbus:$eventbusVersion"
- compile "io.reactivex:rxandroid:$rxAndroidVersion"
- compile "io.reactivex:rxjava:$rxJavaVersion"
- // And ProGuard rules for RxJava!
- compile "com.artemzin.rxjava:proguard-rules:$rxJavaRulesVersion"
- compile "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyVersion"
- compile "com.joanzapata.iconify:android-iconify-material:$iconifyVersion"
- compile("com.afollestad.material-dialogs:commons:$materialDialogsVersion") {
+ implementation "commons-io:commons-io:$commonsioVersion"
+ implementation "org.jsoup:jsoup:$jsoupVersion"
+ implementation "com.github.bumptech.glide:glide:$glideVersion"
+ annotationProcessor "com.github.bumptech.glide:compiler:$glideVersion"
+ implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
+ implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
+ implementation "com.squareup.okio:okio:$okioVersion"
+ implementation "de.greenrobot:eventbus:$eventbusVersion"
+ implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
+ implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
+
+ implementation "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyVersion"
+ implementation "com.joanzapata.iconify:android-iconify-material:$iconifyVersion"
+ implementation("com.afollestad.material-dialogs:commons:$materialDialogsVersion") {
transitive = true
}
- compile "com.yqritc:recyclerview-flexibledivider:$recyclerviewFlexibledividerVersion"
- compile("com.githang:viewpagerindicator:2.5@aar") {
+ implementation "com.yqritc:recyclerview-flexibledivider:$recyclerviewFlexibledividerVersion"
+ implementation("com.githang:viewpagerindicator:2.5.1@aar") {
exclude module: "support-v4"
}
- compile "com.github.shts:TriangleLabelView:$triangleLabelViewVersion"
+ implementation "com.github.shts:TriangleLabelView:$triangleLabelViewVersion"
+
+ implementation "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
- compile "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
+ implementation 'com.github.mfietz:fyydlin:v0.4.1'
+ implementation 'com.github.ByteHamster:SearchPreference:v1.0.8'
- compile 'com.github.mfietz:fyydlin:v0.3'
+ androidTestImplementation "com.jayway.android.robotium:robotium-solo:$robotiumSoloVersion"
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-intents:3.0.2'
+ androidTestImplementation 'com.android.support.test:runner:1.0.2'
+ androidTestImplementation 'com.android.support.test:rules:1.0.2'
}
play {
diff --git a/app/proguard.cfg b/app/proguard.cfg
index 01b1708f7..6bb98dc9e 100644
--- a/app/proguard.cfg
+++ b/app/proguard.cfg
@@ -71,8 +71,6 @@
-dontwarn android.support.v7.**
-dontwarn com.google.android.wearable.**
--keepattributes *Annotation*
-
-keep class org.shredzone.flattr4j.** { *; }
-dontwarn org.shredzone.flattr4j.**
@@ -94,6 +92,7 @@
-keepclassmembers class ** {
public void onEvent*(**);
}
+-keep class de.danoeh.antennapod.core.event.*
# android-iconify
-keep class com.joanzapata.** { *; }
@@ -125,3 +124,13 @@
-keep class com.squareup.moshi.** { *; }
-keep interface com.squareup.moshi.** { *; }
-keep public class retrofit2.adapter.rxjava.RxJavaCallAdapterFactory { *; }
+
+# awaitility
+-dontwarn java.beans.BeanInfo
+-dontwarn java.beans.Introspector
+-dontwarn java.beans.IntrospectionException
+-dontwarn java.beans.PropertyDescriptor
+-dontwarn java.lang.management.ManagementFactory
+-dontwarn java.lang.management.ThreadInfo
+-dontwarn java.lang.management.ThreadMXBean
+
diff --git a/app/sampledata/episodes.json b/app/sampledata/episodes.json
new file mode 100644
index 000000000..209cbf180
--- /dev/null
+++ b/app/sampledata/episodes.json
@@ -0,0 +1,34 @@
+{
+ "data": [
+ {
+ "title": "FLOSS Weekly 482: PyPI",
+ "status_label": "NEW",
+ "duration": "00:52:40",
+ "published_at": "2. May"
+ },
+ {
+ "title": "FLOSS Weekly 479: Pidgin",
+ "status_label": " ",
+ "duration": "01:08:08",
+ "published_at": "11. Apr"
+ },
+ {
+ "title": "Linux Outlaws 370 - Stay Free, Stay Open Source",
+ "status_label": "NEW",
+ "duration": "02:52:51",
+ "published_at": "29. Dec 2014"
+ },
+ {
+ "title": "Linux Outlaws 368 - The Dark Ages of Free Software",
+ "status_label": " ",
+ "duration": "02:26:54",
+ "published_at": "14. Dec 2014"
+ },
+ {
+ "title": "Linux Outlaws 365 - Last Stand",
+ "status_label": " ",
+ "duration": "00:39:59",
+ "published_at": "3. Nov 2014"
+ }
+ ]
+}
diff --git a/app/sampledata/inplaylist b/app/sampledata/inplaylist
new file mode 100644
index 000000000..e78406d75
--- /dev/null
+++ b/app/sampledata/inplaylist
@@ -0,0 +1,2 @@
+@null
+@drawable/ic_list_grey600_24dp \ No newline at end of file
diff --git a/app/sampledata/secondaryaction b/app/sampledata/secondaryaction
new file mode 100644
index 000000000..26083bc9c
--- /dev/null
+++ b/app/sampledata/secondaryaction
@@ -0,0 +1,3 @@
+@drawable/ic_play_arrow_grey600_36dp
+@drawable/ic_file_download_grey600_24dp
+@drawable/ic_cancel_grey600_24dp \ No newline at end of file
diff --git a/app/src/androidTest/java/de/test/antennapod/AntennaPodTestRunner.java b/app/src/androidTest/java/de/test/antennapod/AntennaPodTestRunner.java
deleted file mode 100644
index c321e6494..000000000
--- a/app/src/androidTest/java/de/test/antennapod/AntennaPodTestRunner.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package de.test.antennapod;
-
-import android.test.InstrumentationTestRunner;
-import android.test.suitebuilder.TestSuiteBuilder;
-
-import junit.framework.TestSuite;
-
-public class AntennaPodTestRunner extends InstrumentationTestRunner {
-
- @Override
- public TestSuite getAllTests() {
- return new TestSuiteBuilder(AntennaPodTestRunner.class)
- .includeAllPackagesUnderHere()
- .excludePackages("de.test.antennapod.gpodnet")
- .build();
- }
-
-}
diff --git a/app/src/androidTest/java/de/test/antennapod/NthMatcher.java b/app/src/androidTest/java/de/test/antennapod/NthMatcher.java
new file mode 100644
index 000000000..f9ecacda5
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/NthMatcher.java
@@ -0,0 +1,38 @@
+package de.test.antennapod;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class NthMatcher {
+ public static <T> Matcher<T> first(final Matcher<T> matcher) {
+ return nth(matcher, 1);
+ }
+
+ public static <T> Matcher<T> second(final Matcher<T> matcher) {
+ return nth(matcher, 2);
+ }
+
+ private static <T> Matcher<T> nth(final Matcher<T> matcher, final int index) {
+ return new BaseMatcher<T>() {
+ AtomicInteger count = new AtomicInteger(0);
+
+ @Override
+ public boolean matches(final Object item) {
+ if (matcher.matches(item)) {
+ if (count.incrementAndGet() == index) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void describeTo(final Description description) {
+ description.appendText("should return first matching item");
+ }
+ };
+ }
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java b/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java
new file mode 100644
index 000000000..ced0d7a28
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java
@@ -0,0 +1,38 @@
+package de.test.antennapod.feed;
+
+import android.test.AndroidTestCase;
+
+import de.danoeh.antennapod.core.feed.FeedItem;
+
+public class FeedItemTest extends AndroidTestCase {
+ private static final String TEXT_LONG = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
+ private static final String TEXT_SHORT = "Lorem ipsum";
+
+ /**
+ * If one of `description` or `content:encoded` is null, use the other one.
+ */
+ public void testShownotesNullValues() throws Exception {
+ testShownotes(null, TEXT_LONG);
+ testShownotes(TEXT_LONG, null);
+ }
+
+ /**
+ * If `description` is reasonably longer than `content:encoded`, use `description`.
+ */
+ public void testShownotesLength() throws Exception {
+ testShownotes(TEXT_SHORT, TEXT_LONG);
+ testShownotes(TEXT_LONG, TEXT_SHORT);
+ }
+
+ /**
+ * Checks if the shownotes equal TEXT_LONG, using the given `description` and `content:encoded`
+ * @param description Description of the feed item
+ * @param contentEncoded `content:encoded` of the feed item
+ */
+ private void testShownotes(String description, String contentEncoded) throws Exception {
+ FeedItem item = new FeedItem();
+ item.setDescription(description);
+ item.setContentEncoded(contentEncoded);
+ assertEquals(TEXT_LONG, item.loadShownotes().call());
+ }
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java b/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java
index 14a3b27b0..91e31e73c 100644
--- a/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java
@@ -1,113 +1,127 @@
package de.test.antennapod.gpodnet;
-import android.test.AndroidTestCase;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import android.support.test.runner.AndroidJUnit4;
import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetDevice;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetTag;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import static java.util.Collections.singletonList;
/**
* Test class for GpodnetService
*/
-public class GPodnetServiceTest extends AndroidTestCase {
+@Ignore
+@RunWith(AndroidJUnit4.class)
+public class GPodnetServiceTest {
private GpodnetService service;
private static final String USER = "";
private static final String PW = "";
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ protected void setUp() {
service = new GpodnetService();
}
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
private void authenticate() throws GpodnetServiceException {
service.authenticate(USER, PW);
}
+ @Test
public void testUploadSubscription() throws GpodnetServiceException {
authenticate();
- ArrayList<String> l = new ArrayList<String>();
+ ArrayList<String> l = new ArrayList<>();
l.add("http://bitsundso.de/feed");
service.uploadSubscriptions(USER, "radio", l);
}
+ @Test
public void testUploadSubscription2() throws GpodnetServiceException {
authenticate();
- ArrayList<String> l = new ArrayList<String>();
+ ArrayList<String> l = new ArrayList<>();
l.add("http://bitsundso.de/feed");
l.add("http://gamesundso.de/feed");
service.uploadSubscriptions(USER, "radio", l);
}
+ @Test
public void testUploadChanges() throws GpodnetServiceException {
authenticate();
String[] URLS = {"http://bitsundso.de/feed", "http://gamesundso.de/feed", "http://cre.fm/feed/mp3/", "http://freakshow.fm/feed/m4a/"};
List<String> subscriptions = Arrays.asList(URLS[0], URLS[1]);
- List<String> removed = Arrays.asList(URLS[0]);
+ List<String> removed = singletonList(URLS[0]);
List<String> added = Arrays.asList(URLS[2], URLS[3]);
service.uploadSubscriptions(USER, "radio", subscriptions);
service.uploadChanges(USER, "radio", added, removed);
}
+ @Test
public void testGetSubscriptionChanges() throws GpodnetServiceException {
authenticate();
service.getSubscriptionChanges(USER, "radio", 1362322610L);
}
+ @Test
public void testGetSubscriptionsOfUser()
throws GpodnetServiceException {
authenticate();
service.getSubscriptionsOfUser(USER);
}
+ @Test
public void testGetSubscriptionsOfDevice()
throws GpodnetServiceException {
authenticate();
service.getSubscriptionsOfDevice(USER, "radio");
}
+ @Test
public void testConfigureDevices() throws GpodnetServiceException {
authenticate();
service.configureDevice(USER, "foo", "This is an updated caption",
GpodnetDevice.DeviceType.LAPTOP);
}
+ @Test
public void testGetDevices() throws GpodnetServiceException {
authenticate();
service.getDevices(USER);
}
+ @Test
public void testGetSuggestions() throws GpodnetServiceException {
authenticate();
service.getSuggestions(10);
}
+ @Test
public void testTags() throws GpodnetServiceException {
service.getTopTags(20);
}
+ @Test
public void testPodcastForTags() throws GpodnetServiceException {
List<GpodnetTag> tags = service.getTopTags(20);
service.getPodcastsForTag(tags.get(1),
10);
}
+ @Test
public void testSearch() throws GpodnetServiceException {
service.searchPodcasts("linux", 64);
}
+ @Test
public void testToplist() throws GpodnetServiceException {
service.getPodcastToplist(10);
}
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 ee454ce8a..6908e2ec7 100644
--- a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
@@ -17,7 +17,6 @@ import javax.xml.parsers.ParserConfigurationException;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedImage;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.syndication.handler.FeedHandler;
@@ -32,8 +31,8 @@ import de.test.antennapod.util.syndication.feedgenerator.RSS2Generator;
public class FeedHandlerTest extends InstrumentationTestCase {
private static final String FEEDS_DIR = "testfeeds";
- File file = null;
- OutputStream outputStream = null;
+ private File file = null;
+ private OutputStream outputStream = null;
protected void setUp() throws Exception {
super.setUp();
@@ -82,15 +81,7 @@ public class FeedHandlerTest extends InstrumentationTestCase {
assertEquals(feed.getLink(), parsedFeed.getLink());
assertEquals(feed.getDescription(), parsedFeed.getDescription());
assertEquals(feed.getPaymentLink(), parsedFeed.getPaymentLink());
-
- if (feed.getImage() != null) {
- FeedImage image = feed.getImage();
- FeedImage parsedImage = parsedFeed.getImage();
- assertNotNull(parsedImage);
-
- assertEquals(image.getTitle(), parsedImage.getTitle());
- assertEquals(image.getDownload_url(), parsedImage.getDownload_url());
- }
+ assertEquals(feed.getImageUrl(), parsedFeed.getImageUrl());
if (feed.getItems() != null) {
assertNotNull(parsedFeed.getItems());
@@ -119,14 +110,7 @@ public class FeedHandlerTest extends InstrumentationTestCase {
assertEquals(media.getMime_type(), parsedMedia.getMime_type());
}
- if (item.hasItemImage()) {
- assertTrue(parsedItem.hasItemImage());
- FeedImage image = item.getImage();
- FeedImage parsedImage = parsedItem.getImage();
-
- assertEquals(image.getTitle(), parsedImage.getTitle());
- assertEquals(image.getDownload_url(), parsedImage.getDownload_url());
- }
+ assertEquals(item.getImageUrl(), parsedFeed.getImageUrl());
if (item.getChapters() != null) {
assertNotNull(parsedItem.getChapters());
@@ -158,14 +142,10 @@ public class FeedHandlerTest extends InstrumentationTestCase {
}
private Feed createTestFeed(int numItems, boolean withImage, boolean withFeedMedia, boolean withChapters) {
- FeedImage image = null;
- if (withImage) {
- image = new FeedImage(0, "image", null, "http://example.com/picture", false);
- }
Feed feed = new Feed(0, null, "title", "http://example.com", "This is the description",
- "http://example.com/payment", "Daniel", "en", null, "http://example.com/feed", image, file.getAbsolutePath(),
+ "http://example.com/payment", "Daniel", "en", null, "http://example.com/feed", "http://example.com/picture", file.getAbsolutePath(),
"http://example.com/feed", true);
- feed.setItems(new ArrayList<FeedItem>());
+ feed.setItems(new ArrayList<>());
for (int i = 0; i < numItems; i++) {
FeedItem item = new FeedItem(0, "item-" + i, "http://example.com/item-" + i,
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
index 9ac92c2f9..2f53ea8a6 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
@@ -23,8 +23,8 @@ import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.feed.MediaType;
-import de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer;
import de.danoeh.antennapod.core.service.playback.LocalPSMP;
+import de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.playback.Playable;
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 6ab6e5c61..8be57a074 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
@@ -9,10 +9,10 @@ import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.service.playback.PlaybackServiceTaskManager;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.playback.Playable;
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
index 5e5eb1e8b..5cd4e9906 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
@@ -27,12 +27,12 @@ import static de.test.antennapod.storage.DBTestUtils.saveFeedlist;
public class DBCleanupTests extends InstrumentationTestCase {
private static final String TAG = "DBTasksTest";
- protected static final int EPISODE_CACHE_SIZE = 5;
+ static final int EPISODE_CACHE_SIZE = 5;
private final int cleanupAlgorithm;
- protected Context context;
+ Context context;
- protected File destFolder;
+ private File destFolder;
public DBCleanupTests() {
this.cleanupAlgorithm = UserPreferences.EPISODE_CLEANUP_DEFAULT;
@@ -104,9 +104,9 @@ public class DBCleanupTests extends InstrumentationTestCase {
}
}
- protected void populateItems(final int numItems, Feed feed, List<FeedItem> items,
- List<File> files, int itemState, boolean addToQueue,
- boolean addToFavorites) throws IOException {
+ void populateItems(final int numItems, Feed feed, List<FeedItem> items,
+ List<File> files, int itemState, boolean addToQueue,
+ boolean addToFavorites) throws IOException {
for (int i = 0; i < numItems; i++) {
Date itemDate = new Date(numItems - i);
Date playbackCompletionDate = null;
@@ -145,9 +145,9 @@ public class DBCleanupTests extends InstrumentationTestCase {
final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2;
Feed feed = new Feed("url", null, "title");
- List<FeedItem> items = new ArrayList<FeedItem>();
+ List<FeedItem> items = new ArrayList<>();
feed.setItems(items);
- List<File> files = new ArrayList<File>();
+ List<File> files = new ArrayList<>();
populateItems(NUM_ITEMS, feed, items, files, FeedItem.UNPLAYED, false, false);
DBTasks.performAutoCleanup(context);
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java
index 3bd508eaf..d602d150b 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java
@@ -5,7 +5,6 @@ import android.test.FlakyTest;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
import de.danoeh.antennapod.core.feed.Feed;
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
index 785d32e93..9cd7689ba 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
@@ -5,7 +5,6 @@ import android.test.FlakyTest;
import android.test.InstrumentationTestCase;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -18,6 +17,8 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
+import static java.util.Collections.singletonList;
+
/**
* Test class for DBTasks
*/
@@ -100,7 +101,7 @@ public class DBTasksTest extends InstrumentationTestCase {
assertTrue(feed.getId() != 0);
final long feedID = feed.getId();
feed.setId(0);
- List<Long> itemIDs = new ArrayList<Long>();
+ List<Long> itemIDs = new ArrayList<>();
for (FeedItem item : feed.getItems()) {
assertTrue(item.getId() != 0);
itemIDs.add(item.getId());
@@ -125,7 +126,7 @@ public class DBTasksTest extends InstrumentationTestCase {
public void testUpdateFeedMediaUrlResetState() {
final Feed feed = new Feed("url", null, "title");
FeedItem item = new FeedItem(0, "item", "id", "link", new Date(), FeedItem.PLAYED, feed);
- feed.setItems(Arrays.asList(item));
+ feed.setItems(singletonList(item));
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -138,7 +139,7 @@ public class DBTasksTest extends InstrumentationTestCase {
FeedMedia media = new FeedMedia(item, "url", 1024, "mime/type");
item.setMedia(media);
- feed.setItems(Arrays.asList(item));
+ feed.setItems(singletonList(item));
final Feed newFeed = DBTasks.updateFeed(context, feed)[0];
assertTrue(feed != newFeed);
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 d02efa521..a577e5e36 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java
@@ -19,8 +19,9 @@ import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
/**
* Utility methods for DB* tests.
*/
-public class DBTestUtils {
+class DBTestUtils {
+ private DBTestUtils(){}
/**
* Use this method when tests don't involve chapters.
*/
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 40083e507..427cc8ddd 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
@@ -15,12 +15,9 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedImage;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.feed.SimpleChapter;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
@@ -124,90 +121,14 @@ public class DBWriterTest extends InstrumentationTestCase {
assertNull(media.getFile_url());
}
- public void testDeleteFeed() throws IOException, ExecutionException, InterruptedException, TimeoutException {
+ public void testDeleteFeed() throws ExecutionException, InterruptedException, IOException, TimeoutException {
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
- // create Feed image
- File imgFile = new File(destFolder, "image");
- assertTrue(imgFile.createNewFile());
- FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
- image.setOwner(feed);
- feed.setImage(image);
-
- List<File> itemFiles = new ArrayList<File>();
- // create items with downloaded media files
- for (int i = 0; i < 10; i++) {
- FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed, true);
- feed.getItems().add(item);
-
- File enc = new File(destFolder, "file " + i);
- assertTrue(enc.createNewFile());
- itemFiles.add(enc);
-
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0, 0);
- item.setMedia(media);
-
- item.setChapters(new ArrayList<Chapter>());
- item.getChapters().add(new SimpleChapter(0, "item " + i, item, "example.com"));
- }
-
- PodDBAdapter adapter = PodDBAdapter.getInstance();
- adapter.open();
- adapter.setCompleteFeed(feed);
- adapter.close();
-
- assertTrue(feed.getId() != 0);
- assertTrue(feed.getImage().getId() != 0);
- for (FeedItem item : feed.getItems()) {
- assertTrue(item.getId() != 0);
- assertTrue(item.getMedia().getId() != 0);
- assertTrue(item.getChapters().get(0).getId() != 0);
- }
-
- DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
-
- // check if files still exist
- assertFalse(imgFile.exists());
- for (File f : itemFiles) {
- assertFalse(f.exists());
- }
-
- adapter = PodDBAdapter.getInstance();
- adapter.open();
- Cursor c = adapter.getFeedCursor(feed.getId());
- assertEquals(0, c.getCount());
- c.close();
- c = adapter.getImageCursor(String.valueOf(image.getId()));
- assertEquals(0, c.getCount());
- c.close();
- for (FeedItem item : feed.getItems()) {
- c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
- assertEquals(0, c.getCount());
- c.close();
- c = adapter.getSingleFeedMediaCursor(item.getMedia().getId());
- assertEquals(0, c.getCount());
- c.close();
- c = adapter.getSimpleChaptersOfFeedItemCursor(item);
- assertEquals(0, c.getCount());
- c.close();
- }
- adapter.close();
- }
-
- public void testDeleteFeedNoImage() throws ExecutionException, InterruptedException, IOException, TimeoutException {
- File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
- assertNotNull(destFolder);
-
- Feed feed = new Feed("url", null, "title");
- feed.setItems(new ArrayList<>());
-
- feed.setImage(null);
-
- List<File> itemFiles = new ArrayList<File>();
+ List<File> itemFiles = new ArrayList<>();
// create items with downloaded media files
for (int i = 0; i < 10; i++) {
FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
@@ -261,13 +182,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", null, "title");
feed.setItems(null);
-
- // create Feed image
- File imgFile = new File(destFolder, "image");
- assertTrue(imgFile.createNewFile());
- FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
- image.setOwner(feed);
- feed.setImage(image);
+ feed.setImageUrl("url");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -275,21 +190,14 @@ public class DBWriterTest extends InstrumentationTestCase {
adapter.close();
assertTrue(feed.getId() != 0);
- assertTrue(feed.getImage().getId() != 0);
DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
- // check if files still exist
- assertFalse(imgFile.exists());
-
adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor c = adapter.getFeedCursor(feed.getId());
assertTrue(c.getCount() == 0);
c.close();
- c = adapter.getImageCursor(String.valueOf(image.getId()));
- assertTrue(c.getCount() == 0);
- c.close();
adapter.close();
}
@@ -300,12 +208,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
- // create Feed image
- File imgFile = new File(destFolder, "image");
- assertTrue(imgFile.createNewFile());
- FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
- image.setOwner(feed);
- feed.setImage(image);
+ feed.setImageUrl("url");
// create items
for (int i = 0; i < 10; i++) {
@@ -320,24 +223,18 @@ public class DBWriterTest extends InstrumentationTestCase {
adapter.close();
assertTrue(feed.getId() != 0);
- assertTrue(feed.getImage().getId() != 0);
for (FeedItem item : feed.getItems()) {
assertTrue(item.getId() != 0);
}
DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
- // check if files still exist
- assertFalse(imgFile.exists());
adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor c = adapter.getFeedCursor(feed.getId());
assertTrue(c.getCount() == 0);
c.close();
- c = adapter.getImageCursor(String.valueOf(image.getId()));
- assertTrue(c.getCount() == 0);
- c.close();
for (FeedItem item : feed.getItems()) {
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
assertTrue(c.getCount() == 0);
@@ -346,65 +243,6 @@ public class DBWriterTest extends InstrumentationTestCase {
adapter.close();
}
- public void testDeleteFeedWithItemImages() throws InterruptedException, ExecutionException, TimeoutException, IOException {
- File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
- assertNotNull(destFolder);
-
- Feed feed = new Feed("url", null, "title");
- feed.setItems(new ArrayList<>());
-
- // create Feed image
- File imgFile = new File(destFolder, "image");
- assertTrue(imgFile.createNewFile());
- FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
- image.setOwner(feed);
- feed.setImage(image);
-
- // create items with images
- for (int i = 0; i < 10; i++) {
- FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
- feed.getItems().add(item);
- File itemImageFile = new File(destFolder, "item-image-" + i);
- FeedImage itemImage = new FeedImage(0, "item-image" + i, itemImageFile.getAbsolutePath(), "url", true);
- item.setImage(itemImage);
- }
-
- PodDBAdapter adapter = PodDBAdapter.getInstance();
- adapter.open();
- adapter.setCompleteFeed(feed);
- adapter.close();
-
- assertTrue(feed.getId() != 0);
- assertTrue(feed.getImage().getId() != 0);
- for (FeedItem item : feed.getItems()) {
- assertTrue(item.getId() != 0);
- assertTrue(item.getImage().getId() != 0);
- }
-
- DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
-
- // check if files still exist
- assertFalse(imgFile.exists());
-
- adapter = PodDBAdapter.getInstance();
- adapter.open();
- Cursor c = adapter.getFeedCursor(feed.getId());
- assertTrue(c.getCount() == 0);
- c.close();
- c = adapter.getImageCursor(String.valueOf(image.getId()));
- assertTrue(c.getCount() == 0);
- c.close();
- for (FeedItem item : feed.getItems()) {
- c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
- assertTrue(c.getCount() == 0);
- c.close();
- c = adapter.getImageCursor(String.valueOf(item.getImage().getId()));
- assertEquals(0, c.getCount());
- c.close();
- }
- adapter.close();
- }
-
public void testDeleteFeedWithQueueItems() throws ExecutionException, InterruptedException, TimeoutException {
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
@@ -412,13 +250,9 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
- // create Feed image
- File imgFile = new File(destFolder, "image");
- FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
- image.setOwner(feed);
- feed.setImage(image);
+ feed.setImageUrl("url");
- List<File> itemFiles = new ArrayList<File>();
+ List<File> itemFiles = new ArrayList<>();
// create items with downloaded media files
for (int i = 0; i < 10; i++) {
FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
@@ -437,14 +271,13 @@ public class DBWriterTest extends InstrumentationTestCase {
adapter.close();
assertTrue(feed.getId() != 0);
- assertTrue(feed.getImage().getId() != 0);
for (FeedItem item : feed.getItems()) {
assertTrue(item.getId() != 0);
assertTrue(item.getMedia().getId() != 0);
}
- List<FeedItem> queue = new ArrayList<FeedItem>();
+ List<FeedItem> queue = new ArrayList<>();
queue.addAll(feed.getItems());
adapter.open();
adapter.setQueue(queue);
@@ -460,9 +293,6 @@ public class DBWriterTest extends InstrumentationTestCase {
Cursor c = adapter.getFeedCursor(feed.getId());
assertTrue(c.getCount() == 0);
c.close();
- c = adapter.getImageCursor(String.valueOf(image.getId()));
- assertTrue(c.getCount() == 0);
- c.close();
for (FeedItem item : feed.getItems()) {
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
assertTrue(c.getCount() == 0);
@@ -482,15 +312,11 @@ public class DBWriterTest extends InstrumentationTestCase {
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
- feed.setItems(new ArrayList<FeedItem>());
+ feed.setItems(new ArrayList<>());
- // create Feed image
- File imgFile = new File(destFolder, "image");
- FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
- image.setOwner(feed);
- feed.setImage(image);
+ feed.setImageUrl("url");
- List<File> itemFiles = new ArrayList<File>();
+ List<File> itemFiles = new ArrayList<>();
// create items with downloaded media files
for (int i = 0; i < 10; i++) {
FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
@@ -509,7 +335,6 @@ public class DBWriterTest extends InstrumentationTestCase {
adapter.close();
assertTrue(feed.getId() != 0);
- assertTrue(feed.getImage().getId() != 0);
for (FeedItem item : feed.getItems()) {
assertTrue(item.getId() != 0);
assertTrue(item.getMedia().getId() != 0);
@@ -522,9 +347,6 @@ public class DBWriterTest extends InstrumentationTestCase {
Cursor c = adapter.getFeedCursor(feed.getId());
assertTrue(c.getCount() == 0);
c.close();
- c = adapter.getImageCursor(String.valueOf(image.getId()));
- assertTrue(c.getCount() == 0);
- c.close();
for (FeedItem item : feed.getItems()) {
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
assertTrue(c.getCount() == 0);
@@ -539,7 +361,7 @@ public class DBWriterTest extends InstrumentationTestCase {
private FeedMedia playbackHistorySetup(Date playbackCompletionDate) {
final Context context = getInstrumentation().getTargetContext();
Feed feed = new Feed("url", null, "title");
- feed.setItems(new ArrayList<FeedItem>());
+ feed.setItems(new ArrayList<>());
FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
FeedMedia media = new FeedMedia(0, item, 10, 0, 1, "mime", null, "url", false, playbackCompletionDate, 0, 0);
feed.getItems().add(item);
@@ -598,7 +420,7 @@ public class DBWriterTest extends InstrumentationTestCase {
for (FeedItem item : feed.getItems()) {
assertTrue(item.getId() != 0);
}
- List<Future<?>> futures = new ArrayList<Future<?>>();
+ List<Future<?>> futures = new ArrayList<>();
for (FeedItem item : feed.getItems()) {
futures.add(DBWriter.addQueueItem(context, item));
}
@@ -791,7 +613,7 @@ public class DBWriterTest extends InstrumentationTestCase {
public void testMarkFeedRead() throws InterruptedException, ExecutionException, TimeoutException {
final int NUM_ITEMS = 10;
Feed feed = new Feed("url", null, "title");
- feed.setItems(new ArrayList<FeedItem>());
+ 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.UNPLAYED, feed);
feed.getItems().add(item);
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 bd9057b47..9a60b04b8 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
@@ -2,19 +2,18 @@ package de.test.antennapod.ui;
import android.content.Context;
import android.content.SharedPreferences;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
+import android.support.test.espresso.contrib.DrawerActions;
+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.widget.ListView;
-
import com.robotium.solo.Solo;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
+import com.robotium.solo.Timeout;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
+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;
@@ -22,26 +21,46 @@ import de.danoeh.antennapod.fragment.DownloadsFragment;
import de.danoeh.antennapod.fragment.EpisodesFragment;
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
import de.danoeh.antennapod.fragment.QueueFragment;
-import de.danoeh.antennapod.preferences.PreferenceController;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+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.intent.Intents.intended;
+import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static de.test.antennapod.NthMatcher.first;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
/**
* User interface tests for MainActivity
*/
-public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
+@RunWith(AndroidJUnit4.class)
+public class MainActivityTest {
private Solo solo;
private UITestUtils uiTestUtils;
-
private SharedPreferences prefs;
- public MainActivityTest() {
- super(MainActivity.class);
- }
+ @Rule
+ public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- Context context = getInstrumentation().getTargetContext();
+ @Before
+ public void setUp() throws IOException {
+ Intents.init();
+ Context context = mActivityRule.getActivity();
uiTestUtils = new UITestUtils(context);
uiTestUtils.setup();
@@ -54,30 +73,26 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
// override first launch preference
// do this BEFORE calling getActivity()!
- prefs = getInstrumentation().getTargetContext().getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE);
+ prefs = context.getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE);
prefs.edit().putBoolean(MainActivity.PREF_IS_FIRST_LAUNCH, false).commit();
- solo = new Solo(getInstrumentation(), getActivity());
+ solo = new Solo(getInstrumentation(), mActivityRule.getActivity());
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
uiTestUtils.tearDown();
solo.finishOpenedActivities();
-
+ Intents.release();
PodDBAdapter.deleteDatabase();
-
- // reset preferences
prefs.edit().clear().commit();
-
- super.tearDown();
}
private void openNavDrawer() {
- solo.clickOnImageButton(0);
- getInstrumentation().waitForIdleSync();
+ onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
}
+ @Test
public void testAddFeed() throws Exception {
uiTestUtils.addHostedFeedData();
final Feed feed = uiTestUtils.hostedFeeds.get(0);
@@ -89,14 +104,16 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
solo.waitForView(R.id.butSubscribe);
assertEquals(solo.getString(R.string.subscribe_label), solo.getButton(0).getText().toString());
solo.clickOnButton(0);
- solo.waitForText(solo.getString(R.string.subscribed_label));
+ assertTrue(solo.waitForText(solo.getString(R.string.open_podcast), 0, Timeout.getLargeTimeout(), false));
}
- @FlakyTest(tolerance = 3)
+
+ @Test
+ @FlakyTest
public void testClickNavDrawer() throws Exception {
uiTestUtils.addLocalFeedData(false);
- UserPreferences.setHiddenDrawerItems(new ArrayList<String>());
+ UserPreferences.setHiddenDrawerItems(new ArrayList<>());
// queue
openNavDrawer();
@@ -150,57 +167,60 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
return ((MainActivity) solo.getCurrentActivity()).getSupportActionBar().getTitle().toString();
}
- @SuppressWarnings("unchecked")
- @FlakyTest(tolerance = 3)
+
+ @Test
+ @FlakyTest
public void testGoToPreferences() {
openNavDrawer();
- solo.clickOnText(solo.getString(R.string.settings_label));
- solo.waitForActivity(PreferenceController.getPreferenceActivity());
+ onView(withText(R.string.settings_label)).perform(click());
+ intended(hasComponent(PreferenceActivity.class.getName()));
}
+ @Test
public void testDrawerPreferencesHideSomeElements() {
- UserPreferences.setHiddenDrawerItems(new ArrayList<String>());
+ UserPreferences.setHiddenDrawerItems(new ArrayList<>());
openNavDrawer();
- solo.clickLongOnText(solo.getString(R.string.queue_label));
- solo.waitForDialogToOpen();
- solo.clickOnText(solo.getString(R.string.episodes_label));
- solo.clickOnText(solo.getString(R.string.playback_history_label));
- solo.clickOnText(solo.getString(R.string.confirm_label));
- solo.waitForDialogToClose();
+ onView(first(withText(R.string.queue_label))).perform(longClick());
+ onView(withText(R.string.episodes_label)).perform(click());
+ onView(withText(R.string.playback_history_label)).perform(click());
+ onView(withText(R.string.confirm_label)).perform(click());
+
List<String> hidden = UserPreferences.getHiddenDrawerItems();
assertEquals(2, hidden.size());
assertTrue(hidden.contains(EpisodesFragment.TAG));
assertTrue(hidden.contains(PlaybackHistoryFragment.TAG));
}
+ @Test
public void testDrawerPreferencesUnhideSomeElements() {
List<String> hidden = Arrays.asList(PlaybackHistoryFragment.TAG, DownloadsFragment.TAG);
UserPreferences.setHiddenDrawerItems(hidden);
openNavDrawer();
- solo.clickLongOnText(solo.getString(R.string.queue_label));
- solo.waitForDialogToOpen();
- solo.clickOnText(solo.getString(R.string.downloads_label));
- solo.clickOnText(solo.getString(R.string.queue_label));
- solo.clickOnText(solo.getString(R.string.confirm_label));
- solo.waitForDialogToClose();
+ onView(first(withText(R.string.queue_label))).perform(longClick());
+
+ onView(withText(R.string.downloads_label)).perform(click());
+ onView(withText(R.string.queue_label)).perform(click());
+ onView(withText(R.string.confirm_label)).perform(click());
+
hidden = UserPreferences.getHiddenDrawerItems();
assertEquals(2, hidden.size());
assertTrue(hidden.contains(QueueFragment.TAG));
assertTrue(hidden.contains(PlaybackHistoryFragment.TAG));
}
+
+ @Test
public void testDrawerPreferencesHideAllElements() {
- UserPreferences.setHiddenDrawerItems(new ArrayList<String>());
- String[] titles = getInstrumentation().getTargetContext().getResources().getStringArray(R.array.nav_drawer_titles);
+ UserPreferences.setHiddenDrawerItems(new ArrayList<>());
+ String[] titles = mActivityRule.getActivity().getResources().getStringArray(R.array.nav_drawer_titles);
openNavDrawer();
- solo.clickLongOnText(solo.getString(R.string.queue_label));
- solo.waitForDialogToOpen();
+ onView(first(withText(R.string.queue_label))).perform(longClick());
for (String title : titles) {
- solo.clickOnText(title);
+ onView(first(withText(title))).perform(click());
}
- solo.clickOnText(solo.getString(R.string.confirm_label));
- solo.waitForDialogToClose();
+ onView(withText(R.string.confirm_label)).perform(click());
+
List<String> hidden = UserPreferences.getHiddenDrawerItems();
assertEquals(titles.length, hidden.size());
for (String tag : MainActivity.NAV_DRAWER_TAGS) {
@@ -208,21 +228,85 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
}
}
+ @Test
public void testDrawerPreferencesHideCurrentElement() {
- UserPreferences.setHiddenDrawerItems(new ArrayList<String>());
-
+ UserPreferences.setHiddenDrawerItems(new ArrayList<>());
openNavDrawer();
- String downloads = solo.getString(R.string.downloads_label);
- solo.clickOnText(downloads);
- solo.waitForView(android.R.id.list);
+ onView(withText(R.string.downloads_label)).perform(click());
openNavDrawer();
- solo.clickLongOnText(downloads);
- solo.waitForDialogToOpen();
- solo.clickOnText(downloads);
- solo.clickOnText(solo.getString(R.string.confirm_label));
- solo.waitForDialogToClose();
+
+ onView(first(withText(R.string.queue_label))).perform(longClick());
+ onView(first(withText(R.string.downloads_label))).perform(click());
+ onView(withText(R.string.confirm_label)).perform(click());
+
List<String> hidden = UserPreferences.getHiddenDrawerItems();
assertEquals(1, hidden.size());
assertTrue(hidden.contains(DownloadsFragment.TAG));
}
+
+ @Test
+ public void testBackButtonBehaviorGoToPage() {
+ openNavDrawer();
+ solo.clickOnText(solo.getString(R.string.settings_label));
+ solo.clickOnText(solo.getString(R.string.user_interface_label));
+ solo.clickOnText(solo.getString(R.string.pref_back_button_behavior_title));
+ solo.clickOnText(solo.getString(R.string.back_button_go_to_page));
+ solo.waitForDialogToOpen();
+ solo.clickOnText(solo.getString(R.string.subscriptions_label));
+ solo.clickOnText(solo.getString(R.string.confirm_label));
+ solo.goBackToActivity(MainActivity.class.getSimpleName());
+ solo.goBack();
+ assertEquals(solo.getString(R.string.subscriptions_label), getActionbarTitle());
+ }
+
+ @Test
+ public void testBackButtonBehaviorOpenDrawer() {
+ openNavDrawer();
+ solo.clickOnText(solo.getString(R.string.settings_label));
+ solo.clickOnText(solo.getString(R.string.user_interface_label));
+ solo.clickOnText(solo.getString(R.string.pref_back_button_behavior_title));
+ solo.clickOnText(solo.getString(R.string.back_button_open_drawer));
+ solo.goBackToActivity(MainActivity.class.getSimpleName());
+ solo.goBack();
+ assertTrue(((MainActivity)solo.getCurrentActivity()).isDrawerOpen());
+ }
+
+ @Test
+ public void testBackButtonBehaviorDoubleTap() {
+ openNavDrawer();
+ solo.clickOnText(solo.getString(R.string.settings_label));
+ solo.clickOnText(solo.getString(R.string.user_interface_label));
+ solo.clickOnText(solo.getString(R.string.pref_back_button_behavior_title));
+ solo.clickOnText(solo.getString(R.string.back_button_double_tap));
+ solo.goBackToActivity(MainActivity.class.getSimpleName());
+ solo.goBack();
+ solo.goBack();
+ assertTrue(solo.getCurrentActivity().isFinishing());
+ }
+
+ @Test
+ public void testBackButtonBehaviorPrompt() {
+ openNavDrawer();
+ solo.clickOnText(solo.getString(R.string.settings_label));
+ solo.clickOnText(solo.getString(R.string.user_interface_label));
+ solo.clickOnText(solo.getString(R.string.pref_back_button_behavior_title));
+ solo.clickOnText(solo.getString(R.string.back_button_show_prompt));
+ solo.goBackToActivity(MainActivity.class.getSimpleName());
+ solo.goBack();
+ solo.clickOnText(solo.getString(R.string.yes));
+ solo.waitForDialogToClose();
+ assertTrue(solo.getCurrentActivity().isFinishing());
+ }
+
+ @Test
+ public void testBackButtonBehaviorDefault() {
+ openNavDrawer();
+ solo.clickOnText(solo.getString(R.string.settings_label));
+ solo.clickOnText(solo.getString(R.string.user_interface_label));
+ solo.clickOnText(solo.getString(R.string.pref_back_button_behavior_title));
+ solo.clickOnText(solo.getString(R.string.back_button_default));
+ solo.goBackToActivity(MainActivity.class.getSimpleName());
+ solo.goBack();
+ assertTrue(solo.getCurrentActivity().isFinishing());
+ }
}
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java
index bfbeedd83..55ed998bb 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java
@@ -33,8 +33,8 @@ import de.danoeh.antennapod.core.storage.PodDBAdapter;
public class PlaybackSonicTest extends ActivityInstrumentationTestCase2<MainActivity> {
private static final String TAG = PlaybackTest.class.getSimpleName();
- public static final int EPISODES_DRAWER_LIST_INDEX = 1;
- public static final int QUEUE_DRAWER_LIST_INDEX = 0;
+ private static final int EPISODES_DRAWER_LIST_INDEX = 1;
+ private static final int QUEUE_DRAWER_LIST_INDEX = 0;
private Solo solo;
private UITestUtils uiTestUtils;
@@ -59,7 +59,7 @@ public class PlaybackSonicTest extends ActivityInstrumentationTestCase2<MainActi
.clear()
.putBoolean(UserPreferences.PREF_UNPAUSE_ON_HEADSET_RECONNECT, false)
.putBoolean(UserPreferences.PREF_PAUSE_ON_HEADSET_DISCONNECT, false)
- .putBoolean(UserPreferences.PREF_SONIC, true)
+ .putString(UserPreferences.PREF_MEDIA_PLAYER, "sonic")
.commit();
solo = new Solo(getInstrumentation(), getActivity());
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
index 661c2200b..74d59abd7 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
@@ -30,8 +30,8 @@ import de.danoeh.antennapod.core.storage.PodDBAdapter;
public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity> {
private static final String TAG = PlaybackTest.class.getSimpleName();
- public static final int EPISODES_DRAWER_LIST_INDEX = 1;
- public static final int QUEUE_DRAWER_LIST_INDEX = 0;
+ private static final int EPISODES_DRAWER_LIST_INDEX = 1;
+ private static final int QUEUE_DRAWER_LIST_INDEX = 0;
private Solo solo;
private UITestUtils uiTestUtils;
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 91928f01e..f217ecffa 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
@@ -1,16 +1,14 @@
package de.test.antennapod.ui;
-import android.content.Context;
+import android.content.SharedPreferences;
import android.content.res.Resources;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
+import android.preference.PreferenceManager;
+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 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;
@@ -18,36 +16,58 @@ 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;
-public class PreferencesTest extends ActivityInstrumentationTestCase2<PreferenceActivity> {
+import org.hamcrest.Matcher;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
- private static final String TAG = "PreferencesTest";
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+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.matcher.ViewMatchers.hasDescendant;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+public class PreferencesTest {
private Solo solo;
- private Context context;
private Resources res;
+ private SharedPreferences prefs;
- public PreferencesTest() {
- super(PreferenceActivity.class);
- }
+ @Rule
+ public ActivityTestRule<PreferenceActivity> mActivityRule = new ActivityTestRule<>(PreferenceActivity.class);
- @Override
- public void setUp() throws Exception {
- super.setUp();
- solo = new Solo(getInstrumentation(), getActivity());
+ @Before
+ public void setUp() {
+ solo = new Solo(getInstrumentation(), mActivityRule.getActivity());
Timeout.setSmallTimeout(500);
Timeout.setLargeTimeout(1000);
- context = getInstrumentation().getTargetContext();
- res = getActivity().getResources();
- UserPreferences.init(context);
+ res = mActivityRule.getActivity().getResources();
+ UserPreferences.init(mActivityRule.getActivity());
+
+ prefs = PreferenceManager.getDefaultSharedPreferences(mActivityRule.getActivity());
+ prefs.edit().clear();
+ prefs.edit().putBoolean(UserPreferences.PREF_ENABLE_AUTODL, true).commit();
}
- @Override
- public void tearDown() throws Exception {
+ @After
+ public void tearDown() {
solo.finishOpenedActivities();
- super.tearDown();
+ prefs.edit().clear();
}
+ @Test
public void testSwitchTheme() {
final int theme = UserPreferences.getTheme();
int otherTheme;
@@ -56,12 +76,13 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
} else {
otherTheme = R.string.pref_theme_title_light;
}
- solo.clickOnText(solo.getString(R.string.pref_set_theme_title));
- solo.waitForDialogToOpen();
- solo.clickOnText(solo.getString(otherTheme));
+ clickPreference(withText(R.string.user_interface_label));
+ clickPreference(withText(R.string.pref_set_theme_title));
+ onView(withText(otherTheme)).perform(click());
assertTrue(solo.waitForCondition(() -> UserPreferences.getTheme() != theme, Timeout.getLargeTimeout()));
}
+ @Test
public void testSwitchThemeBack() {
final int theme = UserPreferences.getTheme();
int otherTheme;
@@ -70,37 +91,34 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
} else {
otherTheme = R.string.pref_theme_title_light;
}
- solo.clickOnText(solo.getString(R.string.pref_set_theme_title));
- solo.waitForDialogToOpen(1000);
- solo.clickOnText(solo.getString(otherTheme));
+ clickPreference(withText(R.string.user_interface_label));
+ clickPreference(withText(R.string.pref_set_theme_title));
+ onView(withText(otherTheme)).perform(click());
assertTrue(solo.waitForCondition(() -> UserPreferences.getTheme() != theme, Timeout.getLargeTimeout()));
}
- public void testExpandNotification() {
- final int priority = UserPreferences.getNotifyPriority();
- solo.clickOnText(solo.getString(R.string.pref_expandNotify_title));
- assertTrue(solo.waitForCondition(() -> priority != UserPreferences.getNotifyPriority(), Timeout.getLargeTimeout()));
- solo.clickOnText(solo.getString(R.string.pref_expandNotify_title));
- assertTrue(solo.waitForCondition(() -> priority == UserPreferences.getNotifyPriority(), Timeout.getLargeTimeout()));
- }
-
+ @Test
public void testEnablePersistentPlaybackControls() {
final boolean persistNotify = UserPreferences.isPersistNotify();
- solo.clickOnText(solo.getString(R.string.pref_persistNotify_title));
+ clickPreference(withText(R.string.user_interface_label));
+ clickPreference(withText(R.string.pref_persistNotify_title));
assertTrue(solo.waitForCondition(() -> persistNotify != UserPreferences.isPersistNotify(), Timeout.getLargeTimeout()));
- solo.clickOnText(solo.getString(R.string.pref_persistNotify_title));
+ clickPreference(withText(R.string.pref_persistNotify_title));
assertTrue(solo.waitForCondition(() -> persistNotify == UserPreferences.isPersistNotify(), Timeout.getLargeTimeout()));
}
+ @Test
public void testSetLockscreenButtons() {
+ solo.clickOnText(solo.getString(R.string.user_interface_label));
+ solo.scrollDown();
String[] buttons = res.getStringArray(R.array.compact_notification_buttons_options);
solo.clickOnText(solo.getString(R.string.pref_compact_notification_buttons_title));
solo.waitForDialogToOpen(1000);
// First uncheck every checkbox
- for (int i=0; i<buttons.length; i++) {
- assertTrue(solo.searchText(buttons[i]));
- if (solo.isTextChecked(buttons[i])) {
- solo.clickOnText(buttons[i]);
+ for (String button : buttons) {
+ assertTrue(solo.searchText(button));
+ if (solo.isTextChecked(button)) {
+ solo.clickOnText(button);
}
}
// Now try to check all checkboxes
@@ -111,20 +129,26 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
assertTrue(!solo.isTextChecked(buttons[2]));
solo.clickOnText(solo.getString(R.string.confirm_label));
solo.waitForDialogToClose(1000);
- assertTrue(solo.waitForCondition(() -> UserPreferences.showRewindOnCompactNotification(), Timeout.getLargeTimeout()));
- assertTrue(solo.waitForCondition(() -> UserPreferences.showFastForwardOnCompactNotification(), Timeout.getLargeTimeout()));
+ assertTrue(solo.waitForCondition(UserPreferences::showRewindOnCompactNotification, Timeout.getLargeTimeout()));
+ assertTrue(solo.waitForCondition(UserPreferences::showFastForwardOnCompactNotification, Timeout.getLargeTimeout()));
assertTrue(solo.waitForCondition(() -> !UserPreferences.showSkipOnCompactNotification(), Timeout.getLargeTimeout()));
}
+ @Test
public void testEnqueueAtFront() {
+ solo.clickOnText(solo.getString(R.string.playback_pref));
final boolean enqueueAtFront = UserPreferences.enqueueAtFront();
+ solo.scrollDown();
+ solo.scrollDown();
solo.clickOnText(solo.getString(R.string.pref_queueAddToFront_title));
assertTrue(solo.waitForCondition(() -> enqueueAtFront != UserPreferences.enqueueAtFront(), Timeout.getLargeTimeout()));
solo.clickOnText(solo.getString(R.string.pref_queueAddToFront_title));
assertTrue(solo.waitForCondition(() -> enqueueAtFront == UserPreferences.enqueueAtFront(), Timeout.getLargeTimeout()));
}
+ @Test
public void testHeadPhonesDisconnect() {
+ solo.clickOnText(solo.getString(R.string.playback_pref));
final boolean pauseOnHeadsetDisconnect = UserPreferences.isPauseOnHeadsetDisconnect();
solo.clickOnText(solo.getString(R.string.pref_pauseOnHeadsetDisconnect_title));
assertTrue(solo.waitForCondition(() -> pauseOnHeadsetDisconnect != UserPreferences.isPauseOnHeadsetDisconnect(), Timeout.getLargeTimeout()));
@@ -132,10 +156,12 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
assertTrue(solo.waitForCondition(() -> pauseOnHeadsetDisconnect == UserPreferences.isPauseOnHeadsetDisconnect(), Timeout.getLargeTimeout()));
}
+ @Test
public void testHeadPhonesReconnect() {
+ solo.clickOnText(solo.getString(R.string.playback_pref));
if(UserPreferences.isPauseOnHeadsetDisconnect() == false) {
solo.clickOnText(solo.getString(R.string.pref_pauseOnHeadsetDisconnect_title));
- assertTrue(solo.waitForCondition(() -> UserPreferences.isPauseOnHeadsetDisconnect(), Timeout.getLargeTimeout()));
+ assertTrue(solo.waitForCondition(UserPreferences::isPauseOnHeadsetDisconnect, Timeout.getLargeTimeout()));
}
final boolean unpauseOnHeadsetReconnect = UserPreferences.isUnpauseOnHeadsetReconnect();
solo.clickOnText(solo.getString(R.string.pref_unpauseOnHeadsetReconnect_title));
@@ -144,10 +170,12 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
assertTrue(solo.waitForCondition(() -> unpauseOnHeadsetReconnect == UserPreferences.isUnpauseOnHeadsetReconnect(), Timeout.getLargeTimeout()));
}
+ @Test
public void testBluetoothReconnect() {
+ solo.clickOnText(solo.getString(R.string.playback_pref));
if(UserPreferences.isPauseOnHeadsetDisconnect() == false) {
solo.clickOnText(solo.getString(R.string.pref_pauseOnHeadsetDisconnect_title));
- assertTrue(solo.waitForCondition(() -> UserPreferences.isPauseOnHeadsetDisconnect(), Timeout.getLargeTimeout()));
+ assertTrue(solo.waitForCondition(UserPreferences::isPauseOnHeadsetDisconnect, Timeout.getLargeTimeout()));
}
final boolean unpauseOnBluetoothReconnect = UserPreferences.isUnpauseOnBluetoothReconnect();
solo.clickOnText(solo.getString(R.string.pref_unpauseOnBluetoothReconnect_title));
@@ -156,15 +184,21 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
assertTrue(solo.waitForCondition(() -> unpauseOnBluetoothReconnect == UserPreferences.isUnpauseOnBluetoothReconnect(), Timeout.getLargeTimeout()));
}
+ @Test
public void testContinuousPlayback() {
+ solo.clickOnText(solo.getString(R.string.playback_pref));
final boolean continuousPlayback = UserPreferences.isFollowQueue();
+ solo.scrollDown();
+ solo.scrollDown();
solo.clickOnText(solo.getString(R.string.pref_followQueue_title));
assertTrue(solo.waitForCondition(() -> continuousPlayback != UserPreferences.isFollowQueue(), Timeout.getLargeTimeout()));
solo.clickOnText(solo.getString(R.string.pref_followQueue_title));
assertTrue(solo.waitForCondition(() -> continuousPlayback == UserPreferences.isFollowQueue(), Timeout.getLargeTimeout()));
}
+ @Test
public void testAutoDelete() {
+ solo.clickOnText(solo.getString(R.string.storage_pref));
final boolean autoDelete = UserPreferences.isAutoDelete();
solo.clickOnText(solo.getString(R.string.pref_auto_delete_title));
assertTrue(solo.waitForCondition(() -> autoDelete != UserPreferences.isAutoDelete(), Timeout.getLargeTimeout()));
@@ -172,15 +206,17 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
assertTrue(solo.waitForCondition(() -> autoDelete == UserPreferences.isAutoDelete(), Timeout.getLargeTimeout()));
}
+ @Test
public void testPlaybackSpeeds() {
- solo.clickOnText(solo.getString(R.string.pref_playback_speed_title));
- solo.waitForDialogToOpen(1000);
+ clickPreference(withText(R.string.playback_pref));
+ clickPreference(withText(R.string.pref_playback_speed_title));
assertTrue(solo.searchText(res.getStringArray(R.array.playback_speed_values)[0]));
- solo.clickOnText(solo.getString(R.string.cancel_label));
- solo.waitForDialogToClose(1000);
+ onView(withText(R.string.cancel_label)).perform(click());
}
+ @Test
public void testPauseForInterruptions() {
+ solo.clickOnText(solo.getString(R.string.playback_pref));
final boolean pauseForFocusLoss = UserPreferences.shouldPauseForFocusLoss();
solo.clickOnText(solo.getString(R.string.pref_pausePlaybackForFocusLoss_title));
assertTrue(solo.waitForCondition(() -> pauseForFocusLoss != UserPreferences.shouldPauseForFocusLoss(), Timeout.getLargeTimeout()));
@@ -188,35 +224,40 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
assertTrue(solo.waitForCondition(() -> pauseForFocusLoss == UserPreferences.shouldPauseForFocusLoss(), Timeout.getLargeTimeout()));
}
+ @Test
public void testDisableUpdateInterval() {
+ solo.clickOnText(solo.getString(R.string.network_pref));
solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_sum));
solo.waitForDialogToOpen();
solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_Disable));
assertTrue(solo.waitForCondition(() -> UserPreferences.getUpdateInterval() == 0, 1000));
}
+ @Test
public void testSetUpdateInterval() {
- solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_title));
- solo.waitForDialogToOpen();
- solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
- solo.waitForDialogToOpen();
+ clickPreference(withText(R.string.network_pref));
+ clickPreference(withText(R.string.pref_autoUpdateIntervallOrTime_title));
+ onView(withText(R.string.pref_autoUpdateIntervallOrTime_Interval)).perform(click());
String search = "12 " + solo.getString(R.string.pref_update_interval_hours_plural);
- solo.clickOnText(search);
- solo.waitForDialogToClose();
+ onView(withText(search)).perform(click());
assertTrue(solo.waitForCondition(() -> UserPreferences.getUpdateInterval() ==
TimeUnit.HOURS.toMillis(12), Timeout.getLargeTimeout()));
}
+ @Test
public void testMobileUpdates() {
+ clickPreference(withText(R.string.network_pref));
final boolean mobileUpdates = UserPreferences.isAllowMobileUpdate();
- solo.clickOnText(solo.getString(R.string.pref_mobileUpdate_title));
+ clickPreference(withText(R.string.pref_mobileUpdate_title));
assertTrue(solo.waitForCondition(() -> mobileUpdates != UserPreferences.isAllowMobileUpdate(), Timeout.getLargeTimeout()));
- solo.clickOnText(solo.getString(R.string.pref_mobileUpdate_title));
+ clickPreference(withText(R.string.pref_mobileUpdate_title));
assertTrue(solo.waitForCondition(() -> mobileUpdates == UserPreferences.isAllowMobileUpdate(), Timeout.getLargeTimeout()));
}
+ @Test
public void testSetSequentialDownload() {
- solo.clickOnText(solo.getString(R.string.pref_parallel_downloads_title));
+ clickPreference(withText(R.string.network_pref));
+ clickPreference(withText(R.string.pref_parallel_downloads_title));
solo.waitForDialogToOpen();
solo.clearEditText(0);
solo.enterText(0, "1");
@@ -224,8 +265,10 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
assertTrue(solo.waitForCondition(() -> UserPreferences.getParallelDownloads() == 1, Timeout.getLargeTimeout()));
}
+ @Test
public void testSetParallelDownloads() {
- solo.clickOnText(solo.getString(R.string.pref_parallel_downloads_title));
+ clickPreference(withText(R.string.network_pref));
+ clickPreference(withText(R.string.pref_parallel_downloads_title));
solo.waitForDialogToOpen();
solo.clearEditText(0);
solo.enterText(0, "10");
@@ -233,71 +276,74 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
assertTrue(solo.waitForCondition(() -> UserPreferences.getParallelDownloads() == 10, Timeout.getLargeTimeout()));
}
+ @Test
public void testSetParallelDownloadsInvalidInput() {
- solo.clickOnText(solo.getString(R.string.pref_parallel_downloads_title));
+ clickPreference(withText(R.string.network_pref));
+ clickPreference(withText(R.string.pref_parallel_downloads_title));
solo.waitForDialogToOpen();
solo.clearEditText(0);
solo.enterText(0, "0");
- assertEquals("1", solo.getEditText(0).getText().toString());
+ assertEquals("", solo.getEditText(0).getText().toString());
solo.clearEditText(0);
solo.enterText(0, "100");
- assertEquals("50", solo.getEditText(0).getText().toString());
+ assertEquals("", solo.getEditText(0).getText().toString());
}
+ @Test
public void testSetEpisodeCache() {
String[] entries = res.getStringArray(R.array.episode_cache_size_entries);
String[] values = res.getStringArray(R.array.episode_cache_size_values);
String entry = entries[entries.length/2];
final int value = Integer.valueOf(values[values.length/2]);
- solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
- solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
- solo.clickOnText(solo.getString(R.string.pref_episode_cache_title));
+ clickPreference(withText(R.string.network_pref));
+ clickPreference(withText(R.string.pref_automatic_download_title));
+ clickPreference(withText(R.string.pref_episode_cache_title));
solo.waitForDialogToOpen();
solo.clickOnText(entry);
assertTrue(solo.waitForCondition(() -> UserPreferences.getEpisodeCacheSize() == value, Timeout.getLargeTimeout()));
}
+ @Test
public void testSetEpisodeCacheMin() {
String[] entries = res.getStringArray(R.array.episode_cache_size_entries);
String[] values = res.getStringArray(R.array.episode_cache_size_values);
String minEntry = entries[0];
final int minValue = Integer.valueOf(values[0]);
- solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
- solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
- if(!UserPreferences.isEnableAutodownload()) {
- solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
- }
- solo.clickOnText(solo.getString(R.string.pref_episode_cache_title));
+
+ clickPreference(withText(R.string.network_pref));
+ clickPreference(withText(R.string.pref_automatic_download_title));
+ clickPreference(withText(R.string.pref_episode_cache_title));
solo.waitForDialogToOpen(1000);
solo.scrollUp();
solo.clickOnText(minEntry);
assertTrue(solo.waitForCondition(() -> UserPreferences.getEpisodeCacheSize() == minValue, Timeout.getLargeTimeout()));
}
+ @Test
public void testSetEpisodeCacheMax() {
String[] entries = res.getStringArray(R.array.episode_cache_size_entries);
String[] values = res.getStringArray(R.array.episode_cache_size_values);
String maxEntry = entries[entries.length-1];
final int maxValue = Integer.valueOf(values[values.length-1]);
+ solo.clickOnText(solo.getString(R.string.network_pref));
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
- if(!UserPreferences.isEnableAutodownload()) {
- solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
- }
solo.clickOnText(solo.getString(R.string.pref_episode_cache_title));
solo.waitForDialogToOpen();
solo.clickOnText(maxEntry);
assertTrue(solo.waitForCondition(() -> UserPreferences.getEpisodeCacheSize() == maxValue, Timeout.getLargeTimeout()));
}
+ @Test
public void testAutomaticDownload() {
final boolean automaticDownload = UserPreferences.isEnableAutodownload();
- solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
- solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
- solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
+ clickPreference(withText(R.string.network_pref));
+ clickPreference(withText(R.string.pref_automatic_download_title));
+ clickPreference(withText(R.string.pref_automatic_download_title));
+
assertTrue(solo.waitForCondition(() -> automaticDownload != UserPreferences.isEnableAutodownload(), Timeout.getLargeTimeout()));
if(UserPreferences.isEnableAutodownload() == false) {
- solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
+ clickPreference(withText(R.string.pref_automatic_download_title));
}
assertTrue(solo.waitForCondition(() -> UserPreferences.isEnableAutodownload() == true, Timeout.getLargeTimeout()));
final boolean enableAutodownloadOnBattery = UserPreferences.isEnableAutodownloadOnBattery();
@@ -312,7 +358,10 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
assertTrue(solo.waitForCondition(() -> enableWifiFilter == UserPreferences.isEnableAutodownloadWifiFilter(), Timeout.getLargeTimeout()));
}
+ @Test
public void testEpisodeCleanupQueueOnly() {
+ solo.clickOnText(solo.getString(R.string.network_pref));
+ solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
solo.clickOnText(solo.getString(R.string.pref_episode_cleanup_title));
solo.waitForText(solo.getString(R.string.episode_cleanup_queue_removal));
solo.clickOnText(solo.getString(R.string.episode_cleanup_queue_removal));
@@ -323,7 +372,10 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
Timeout.getLargeTimeout()));
}
+ @Test
public void testEpisodeCleanupNeverAlg() {
+ solo.clickOnText(solo.getString(R.string.network_pref));
+ solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
solo.clickOnText(solo.getString(R.string.pref_episode_cleanup_title));
solo.waitForText(solo.getString(R.string.episode_cleanup_never));
solo.clickOnText(solo.getString(R.string.episode_cleanup_never));
@@ -334,7 +386,10 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
Timeout.getLargeTimeout()));
}
+ @Test
public void testEpisodeCleanupClassic() {
+ solo.clickOnText(solo.getString(R.string.network_pref));
+ solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
solo.clickOnText(solo.getString(R.string.pref_episode_cleanup_title));
solo.waitForText(solo.getString(R.string.episode_cleanup_after_listening));
solo.clickOnText(solo.getString(R.string.episode_cleanup_after_listening));
@@ -349,10 +404,14 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
Timeout.getLargeTimeout()));
}
+ @Test
public void testEpisodeCleanupNumDays() {
- solo.clickOnText(solo.getString(R.string.pref_episode_cleanup_title));
- solo.waitForText(solo.getString(R.string.episode_cleanup_after_listening));
- solo.clickOnText("5");
+ clickPreference(withText(R.string.network_pref));
+ clickPreference(withText(R.string.pref_automatic_download_title));
+ clickPreference(withText(R.string.pref_episode_cleanup_title));
+ solo.waitForDialogToOpen();
+ String search = res.getQuantityString(R.plurals.episode_cleanup_days_after_listening, 5, 5);
+ onView(withText(search)).perform(click());
assertTrue(solo.waitForCondition(() -> {
EpisodeCleanupAlgorithm alg = UserPreferences.getEpisodeCleanupAlgorithm();
if (alg instanceof APCleanupAlgorithm) {
@@ -364,12 +423,13 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
Timeout.getLargeTimeout()));
}
-
+ @Test
public void testRewindChange() {
int seconds = UserPreferences.getRewindSecs();
int deltas[] = res.getIntArray(R.array.seek_delta_values);
- solo.clickOnText(solo.getString(R.string.pref_rewind));
+ clickPreference(withText(R.string.playback_pref));
+ clickPreference(withText(R.string.pref_rewind));
solo.waitForDialogToOpen();
int currentIndex = Arrays.binarySearch(deltas, seconds);
@@ -377,21 +437,22 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
// Find next value (wrapping around to next)
int newIndex = (currentIndex + 1) % deltas.length;
-
- solo.clickOnText(String.valueOf(deltas[newIndex]) + " seconds");
- solo.clickOnButton("Confirm");
+ onView(withText(String.valueOf(deltas[newIndex]) + " seconds")).perform(click());
+ onView(withText("Confirm")).perform(click());
solo.waitForDialogToClose();
assertTrue(solo.waitForCondition(() -> UserPreferences.getRewindSecs() == deltas[newIndex],
Timeout.getLargeTimeout()));
}
+ @Test
public void testFastForwardChange() {
+ clickPreference(withText(R.string.playback_pref));
for (int i = 2; i > 0; i--) { // repeat twice to catch any error where fastforward is tracking rewind
int seconds = UserPreferences.getFastForwardSecs();
int deltas[] = res.getIntArray(R.array.seek_delta_values);
- solo.clickOnText(solo.getString(R.string.pref_fast_forward));
+ clickPreference(withText(R.string.pref_fast_forward));
solo.waitForDialogToOpen();
int currentIndex = Arrays.binarySearch(deltas, seconds);
@@ -400,12 +461,52 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
// Find next value (wrapping around to next)
int newIndex = (currentIndex + 1) % deltas.length;
- solo.clickOnText(String.valueOf(deltas[newIndex]) + " seconds");
- solo.clickOnButton("Confirm");
+ onView(withText(String.valueOf(deltas[newIndex]) + " seconds")).perform(click());
+ onView(withText("Confirm")).perform(click());
solo.waitForDialogToClose();
assertTrue(solo.waitForCondition(() -> UserPreferences.getFastForwardSecs() == deltas[newIndex],
Timeout.getLargeTimeout()));
}
}
+
+ @Test
+ public void testBackButtonBehaviorGoToPageSelector() {
+ clickPreference(withText(R.string.user_interface_label));
+ clickPreference(withText(R.string.pref_back_button_behavior_title));
+ solo.waitForDialogToOpen();
+ solo.clickOnText(solo.getString(R.string.back_button_go_to_page));
+ solo.waitForDialogToOpen();
+ solo.clickOnText(solo.getString(R.string.queue_label));
+ solo.clickOnText(solo.getString(R.string.confirm_label));
+ assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonBehavior() == UserPreferences.BackButtonBehavior.GO_TO_PAGE,
+ Timeout.getLargeTimeout()));
+ assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonGoToPage().equals(QueueFragment.TAG),
+ Timeout.getLargeTimeout()));
+ clickPreference(withText(R.string.pref_back_button_behavior_title));
+ solo.waitForDialogToOpen();
+ solo.clickOnText(solo.getString(R.string.back_button_go_to_page));
+ solo.waitForDialogToOpen();
+ solo.clickOnText(solo.getString(R.string.episodes_label));
+ solo.clickOnText(solo.getString(R.string.confirm_label));
+ assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonBehavior() == UserPreferences.BackButtonBehavior.GO_TO_PAGE,
+ Timeout.getLargeTimeout()));
+ assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonGoToPage().equals(EpisodesFragment.TAG),
+ Timeout.getLargeTimeout()));
+ clickPreference(withText(R.string.pref_back_button_behavior_title));
+ solo.waitForDialogToOpen();
+ solo.clickOnText(solo.getString(R.string.back_button_go_to_page));
+ solo.waitForDialogToOpen();
+ solo.clickOnText(solo.getString(R.string.subscriptions_label));
+ solo.clickOnText(solo.getString(R.string.confirm_label));
+ assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonBehavior() == UserPreferences.BackButtonBehavior.GO_TO_PAGE,
+ Timeout.getLargeTimeout()));
+ assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonGoToPage().equals(SubscriptionFragment.TAG),
+ 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 432d4a4e6..ff5374268 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
@@ -1,9 +1,7 @@
package de.test.antennapod.ui;
-import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
-import android.os.Build;
import android.util.Log;
import junit.framework.Assert;
@@ -20,14 +18,12 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedImage;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.fragment.ExternalPlayerFragment;
@@ -39,27 +35,25 @@ import de.test.antennapod.util.syndication.feedgenerator.RSS2Generator;
* Utility methods for UI tests.
* Starts a web server that hosts feeds, episodes and images.
*/
-@TargetApi(Build.VERSION_CODES.HONEYCOMB)
-public class UITestUtils {
+class UITestUtils {
private static final String TAG = UITestUtils.class.getSimpleName();
private static final String DATA_FOLDER = "test/UITestUtils";
- public static final int NUM_FEEDS = 5;
- public static final int NUM_ITEMS_PER_FEED = 10;
+ private static final int NUM_FEEDS = 5;
+ private static final int NUM_ITEMS_PER_FEED = 10;
- public static final int HOME_VIEW = (Build.VERSION.SDK_INT >= 11) ? android.R.id.home : R.id.home;
- public static final String TEST_FILE_NAME = "3sec.mp3";
+ private static final String TEST_FILE_NAME = "3sec.mp3";
- private Context context;
- private HTTPBin server = new HTTPBin();
+ private final Context context;
+ private final HTTPBin server = new HTTPBin();
private File destDir;
private File hostedFeedDir;
private File hostedMediaDir;
- public List<Feed> hostedFeeds = new ArrayList<Feed>();
+ public final List<Feed> hostedFeeds = new ArrayList<>();
public UITestUtils(Context context) {
this.context = context;
@@ -141,15 +135,12 @@ public class UITestUtils {
public void addHostedFeedData() throws IOException {
if (feedDataHosted) throw new IllegalStateException("addHostedFeedData was called twice on the same instance");
for (int i = 0; i < NUM_FEEDS; i++) {
- File bitmapFile = newBitmapFile("image" + i);
- FeedImage image = new FeedImage(0, "image " + i, null, hostFile(bitmapFile), false);
Feed feed = new Feed(0, null, "Title " + i, "http://example.com/" + i, "Description of feed " + i,
- "http://example.com/pay/feed" + i, "author " + i, "en", Feed.TYPE_RSS2, "feed" + i, image, null,
+ "http://example.com/pay/feed" + i, "author " + i, "en", Feed.TYPE_RSS2, "feed" + i, null, null,
"http://example.com/feed/src/" + i, false);
- image.setOwner(feed);
// create items
- List<FeedItem> items = new ArrayList<FeedItem>();
+ List<FeedItem> items = new ArrayList<>();
for (int j = 0; j < NUM_ITEMS_PER_FEED; j++) {
FeedItem item = new FeedItem(j, "Feed " + (i+1) + ": Item " + (j+1), "item" + j,
"http://example.com/feed" + i + "/item/" + j, new Date(), FeedItem.UNPLAYED, feed);
@@ -192,12 +183,6 @@ public class UITestUtils {
List<FeedItem> queue = new ArrayList<>();
for (Feed feed : hostedFeeds) {
feed.setDownloaded(true);
- if (feed.getImage() != null) {
- FeedImage image = feed.getImage();
- int fileId = Integer.parseInt(StringUtils.substringAfter(image.getDownload_url(), "files/"));
- image.setFile_url(server.accessFile(fileId).getAbsolutePath());
- image.setDownloaded(true);
- }
if (downloadEpisodes) {
for (FeedItem item : feed.getItems()) {
if (item.hasMedia()) {
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java
index 53fd7d7fd..45ba472ff 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java
@@ -38,9 +38,6 @@ public class UITestUtilsTest extends InstrumentationTestCase {
for (Feed feed : feeds) {
testUrlReachable(feed.getDownload_url());
- if (feed.getImage() != null) {
- testUrlReachable(feed.getImage().getDownload_url());
- }
for (FeedItem item : feed.getItems()) {
if (item.hasMedia()) {
testUrlReachable(item.getMedia().getDownload_url());
@@ -66,9 +63,6 @@ public class UITestUtilsTest extends InstrumentationTestCase {
for (Feed feed : uiTestUtils.hostedFeeds) {
assertTrue(feed.getId() != 0);
- if (feed.getImage() != null) {
- assertTrue(feed.getImage().getId() != 0);
- }
for (FeedItem item : feed.getItems()) {
assertTrue(item.getId() != 0);
if (item.hasMedia()) {
diff --git a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java b/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
index 13e8b9582..a36b3b65a 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
@@ -1,10 +1,12 @@
package de.test.antennapod.util;
+import android.test.AndroidTestCase;
+import android.text.TextUtils;
+
import java.io.File;
import java.io.IOException;
import de.danoeh.antennapod.core.util.FileNameGenerator;
-import android.test.AndroidTestCase;
public class FilenameGeneratorTest extends AndroidTestCase {
@@ -41,7 +43,12 @@ public class FilenameGeneratorTest extends AndroidTestCase {
public void testFeedTitleContainsDash() {
String result = FileNameGenerator.generateFileName("Left - Right");
- assertEquals("Left Right", result);
+ assertEquals("Left - Right", result);
+ }
+
+ public void testInvalidInput() {
+ String result = FileNameGenerator.generateFileName("???");
+ assertTrue(!TextUtils.isEmpty(result));
}
/**
diff --git a/app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java b/app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java
index fcfb16eb4..d564d0492 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java
@@ -1,8 +1,8 @@
package de.test.antennapod.util;
-import junit.framework.*;
+import junit.framework.TestCase;
-import de.danoeh.antennapod.core.util.*;
+import de.danoeh.antennapod.core.util.RewindAfterPauseUtils;
/**
* Tests for {@link RewindAfterPauseUtils}.
diff --git a/app/src/androidTest/java/de/test/antennapod/util/URIUtilTest.java b/app/src/androidTest/java/de/test/antennapod/util/URIUtilTest.java
index 7bdcfb898..2cca6b4dc 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/URIUtilTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/URIUtilTest.java
@@ -1,6 +1,7 @@
package de.test.antennapod.util;
import android.test.AndroidTestCase;
+
import de.danoeh.antennapod.core.util.URIUtil;
/**
diff --git a/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java b/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java
index aa197b6e1..1b444bfa9 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java
@@ -1,6 +1,7 @@
package de.test.antennapod.util;
import android.test.AndroidTestCase;
+
import de.danoeh.antennapod.core.util.URLChecker;
/**
diff --git a/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java b/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java
index 2f2c3fe5b..cde93fd7e 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java
@@ -45,11 +45,11 @@ public class HTTPBin extends NanoHTTPD {
private static final String MIME_HTML = "text/html";
private static final String MIME_PLAIN = "text/plain";
- private List<File> servedFiles;
+ private final List<File> servedFiles;
public HTTPBin() {
super(PORT);
- this.servedFiles = new ArrayList<File>();
+ this.servedFiles = new ArrayList<>();
}
/**
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 28ff6694e..61ff65809 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
@@ -88,15 +88,15 @@ public abstract class NanoHTTPD {
* This is required as the Keep-Alive HTTP connections would otherwise
* block the socket reading thread forever (or as long the browser is open).
*/
- public static final int SOCKET_READ_TIMEOUT = 5000;
+ private static final int SOCKET_READ_TIMEOUT = 5000;
/**
* Common mime type for dynamic content: plain text
*/
- public static final String MIME_PLAINTEXT = "text/plain";
+ private static final String MIME_PLAINTEXT = "text/plain";
/**
* Common mime type for dynamic content: html
*/
- public static final String MIME_HTML = "text/html";
+ private static final String MIME_HTML = "text/html";
/**
* Pseudo-Parameter to use to store the actual query string in the parameters map for later re-processing.
*/
@@ -104,7 +104,7 @@ public abstract class NanoHTTPD {
private final String hostname;
private final int myPort;
private ServerSocket myServerSocket;
- private Set<Socket> openConnections = new HashSet<Socket>();
+ private final Set<Socket> openConnections = new HashSet<>();
private Thread myThread;
/**
* Pluggable strategy for asynchronously executing requests.
@@ -118,14 +118,14 @@ public abstract class NanoHTTPD {
/**
* Constructs an HTTP server on given port.
*/
- public NanoHTTPD(int port) {
+ NanoHTTPD(int port) {
this(null, port);
}
/**
* Constructs an HTTP server on given hostname and port.
*/
- public NanoHTTPD(String hostname, int port) {
+ private NanoHTTPD(String hostname, int port) {
this.hostname = hostname;
this.myPort = port;
setTempFileManagerFactory(new DefaultTempFileManagerFactory());
@@ -168,44 +168,38 @@ public abstract class NanoHTTPD {
myServerSocket = new ServerSocket();
myServerSocket.bind((hostname != null) ? new InetSocketAddress(hostname, myPort) : new InetSocketAddress(myPort));
- myThread = new Thread(new Runnable() {
- @Override
- public void run() {
- do {
- try {
- final Socket finalAccept = myServerSocket.accept();
- registerConnection(finalAccept);
- finalAccept.setSoTimeout(SOCKET_READ_TIMEOUT);
- final InputStream inputStream = finalAccept.getInputStream();
- asyncRunner.exec(new Runnable() {
- @Override
- public void run() {
- OutputStream outputStream = null;
- try {
- outputStream = finalAccept.getOutputStream();
- TempFileManager tempFileManager = tempFileManagerFactory.create();
- HTTPSession session = new HTTPSession(tempFileManager, inputStream, outputStream, finalAccept.getInetAddress());
- while (!finalAccept.isClosed()) {
- session.execute();
- }
- } catch (Exception e) {
- // When the socket is closed by the client, we throw our own SocketException
- // to break the "keep alive" loop above.
- if (!(e instanceof SocketException && "NanoHttpd Shutdown".equals(e.getMessage()))) {
- e.printStackTrace();
- }
- } finally {
- safeClose(outputStream);
- safeClose(inputStream);
- safeClose(finalAccept);
- unRegisterConnection(finalAccept);
- }
+ myThread = new Thread(() -> {
+ do {
+ try {
+ final Socket finalAccept = myServerSocket.accept();
+ registerConnection(finalAccept);
+ finalAccept.setSoTimeout(SOCKET_READ_TIMEOUT);
+ final InputStream inputStream = finalAccept.getInputStream();
+ asyncRunner.exec(() -> {
+ OutputStream outputStream = null;
+ try {
+ outputStream = finalAccept.getOutputStream();
+ TempFileManager tempFileManager = tempFileManagerFactory.create();
+ HTTPSession session = new HTTPSession(tempFileManager, inputStream, outputStream, finalAccept.getInetAddress());
+ while (!finalAccept.isClosed()) {
+ session.execute();
}
- });
- } catch (IOException e) {
- }
- } while (!myServerSocket.isClosed());
- }
+ } catch (Exception e) {
+ // When the socket is closed by the client, we throw our own SocketException
+ // to break the "keep alive" loop above.
+ if (!(e instanceof SocketException && "NanoHttpd Shutdown".equals(e.getMessage()))) {
+ e.printStackTrace();
+ }
+ } finally {
+ safeClose(outputStream);
+ safeClose(inputStream);
+ safeClose(finalAccept);
+ unRegisterConnection(finalAccept);
+ }
+ });
+ } catch (IOException e) {
+ }
+ } while (!myServerSocket.isClosed());
});
myThread.setDaemon(true);
myThread.setName("NanoHttpd Main Listener");
@@ -232,7 +226,7 @@ public abstract class NanoHTTPD {
*
* @param socket the {@link Socket} for the connection.
*/
- public synchronized void registerConnection(Socket socket) {
+ private synchronized void registerConnection(Socket socket) {
openConnections.add(socket);
}
@@ -242,14 +236,14 @@ public abstract class NanoHTTPD {
* @param socket
* the {@link Socket} for the connection.
*/
- public synchronized void unRegisterConnection(Socket socket) {
+ private synchronized void unRegisterConnection(Socket socket) {
openConnections.remove(socket);
}
/**
* Forcibly closes all connections that are open.
*/
- public synchronized void closeAllConnections() {
+ private synchronized void closeAllConnections() {
for (Socket socket : openConnections) {
safeClose(socket);
}
@@ -259,7 +253,7 @@ public abstract class NanoHTTPD {
return myServerSocket == null ? -1 : myServerSocket.getLocalPort();
}
- public final boolean wasStarted() {
+ private boolean wasStarted() {
return myServerSocket != null && myThread != null;
}
@@ -294,7 +288,7 @@ public abstract class NanoHTTPD {
* @param session The HTTP session
* @return HTTP response, see class Response for details
*/
- public Response serve(IHTTPSession session) {
+ Response serve(IHTTPSession session) {
Map<String, String> files = new ArrayMap<>();
Method method = session.getMethod();
if (Method.PUT.equals(method) || Method.POST.equals(method)) {
@@ -318,7 +312,7 @@ public abstract class NanoHTTPD {
* @param str the percent encoded <code>String</code>
* @return expanded form of the input, for example "foo%20bar" becomes "foo bar"
*/
- protected String decodePercent(String str) {
+ private String decodePercent(String str) {
String decoded = null;
try {
decoded = URLDecoder.decode(str, "UTF8");
@@ -347,8 +341,8 @@ public abstract class NanoHTTPD {
* @param queryString a query string pulled from the URL.
* @return a map of <code>String</code> (parameter name) to <code>List&lt;String&gt;</code> (a list of the values supplied).
*/
- protected Map<String, List<String>> decodeParameters(String queryString) {
- Map<String, List<String>> parms = new ArrayMap<String, List<String>>();
+ private Map<String, List<String>> decodeParameters(String queryString) {
+ Map<String, List<String>> parms = new ArrayMap<>();
if (queryString != null) {
StringTokenizer st = new StringTokenizer(queryString, "&");
while (st.hasMoreTokens()) {
@@ -356,7 +350,7 @@ public abstract class NanoHTTPD {
int sep = e.indexOf('=');
String propertyName = (sep >= 0) ? decodePercent(e.substring(0, sep)).trim() : decodePercent(e).trim();
if (!parms.containsKey(propertyName)) {
- parms.put(propertyName, new ArrayList<String>());
+ parms.put(propertyName, new ArrayList<>());
}
String propertyValue = (sep >= 0) ? decodePercent(e.substring(sep + 1)) : null;
if (propertyValue != null) {
@@ -378,7 +372,7 @@ public abstract class NanoHTTPD {
*
* @param asyncRunner new strategy for handling threads.
*/
- public void setAsyncRunner(AsyncRunner asyncRunner) {
+ private void setAsyncRunner(AsyncRunner asyncRunner) {
this.asyncRunner = asyncRunner;
}
@@ -393,7 +387,7 @@ public abstract class NanoHTTPD {
*
* @param tempFileManagerFactory new strategy for handling temp files.
*/
- public void setTempFileManagerFactory(TempFileManagerFactory tempFileManagerFactory) {
+ private void setTempFileManagerFactory(TempFileManagerFactory tempFileManagerFactory) {
this.tempFileManagerFactory = tempFileManagerFactory;
}
@@ -448,9 +442,9 @@ public abstract class NanoHTTPD {
* themselves up when no longer needed.</p>
*/
public interface TempFile {
- OutputStream open() throws Exception;
+ OutputStream open();
- void delete() throws Exception;
+ void delete();
String getName();
}
@@ -490,7 +484,7 @@ public abstract class NanoHTTPD {
public DefaultTempFileManager() {
tmpdir = System.getProperty("java.io.tmpdir");
- tempFiles = new ArrayList<TempFile>();
+ tempFiles = new ArrayList<>();
}
@Override
@@ -528,12 +522,12 @@ public abstract class NanoHTTPD {
}
@Override
- public OutputStream open() throws Exception {
+ public OutputStream open() {
return fstream;
}
@Override
- public void delete() throws Exception {
+ public void delete() {
safeClose(fstream);
file.delete();
}
@@ -563,7 +557,7 @@ public abstract class NanoHTTPD {
/**
* Headers for the HTTP response. Use addHeader() to add lines.
*/
- private Map<String, String> header = new ArrayMap<String, String>();
+ private final Map<String, String> header = new ArrayMap<>();
/**
* The request method that spawned this response.
*/
@@ -616,7 +610,7 @@ public abstract class NanoHTTPD {
/**
* Sends given response to the socket.
*/
- protected void send(OutputStream outputStream) {
+ void send(OutputStream outputStream) {
String mime = mimeType;
SimpleDateFormat gmtFrmt = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT"));
@@ -661,13 +655,13 @@ public abstract class NanoHTTPD {
}
}
- protected void sendContentLengthHeaderIfNotAlreadyPresent(PrintWriter pw, Map<String, String> header, int size) {
+ void sendContentLengthHeaderIfNotAlreadyPresent(PrintWriter pw, Map<String, String> header, int size) {
if (!headerAlreadySent(header, "content-length")) {
pw.print("Content-Length: "+ size +"\r\n");
}
}
- protected void sendConnectionHeaderIfNotAlreadyPresent(PrintWriter pw, Map<String, String> header) {
+ void sendConnectionHeaderIfNotAlreadyPresent(PrintWriter pw, Map<String, String> header) {
if (!headerAlreadySent(header, "connection")) {
pw.print("Connection: keep-alive\r\n");
}
@@ -694,7 +688,7 @@ public abstract class NanoHTTPD {
outputStream.write(buff, 0, read);
outputStream.write(CRLF);
}
- outputStream.write(String.format("0\r\n\r\n").getBytes());
+ outputStream.write("0\r\n\r\n".getBytes());
}
private void sendAsFixedLength(OutputStream outputStream, int pending) throws IOException {
@@ -844,7 +838,7 @@ public abstract class NanoHTTPD {
public static final int BUFSIZE = 8192;
private final TempFileManager tempFileManager;
private final OutputStream outputStream;
- private PushbackInputStream inputStream;
+ private final PushbackInputStream inputStream;
private int splitbyte;
private int rlen;
private String uri;
@@ -865,7 +859,7 @@ public abstract class NanoHTTPD {
this.inputStream = new PushbackInputStream(inputStream, BUFSIZE);
this.outputStream = outputStream;
String remoteIp = inetAddress.isLoopbackAddress() || inetAddress.isAnyLocalAddress() ? "127.0.0.1" : inetAddress.getHostAddress().toString();
- headers = new ArrayMap<String, String>();
+ headers = new ArrayMap<>();
headers.put("remote-addr", remoteIp);
headers.put("http-client-ip", remoteIp);
@@ -909,16 +903,16 @@ public abstract class NanoHTTPD {
inputStream.unread(buf, splitbyte, rlen - splitbyte);
}
- parms = new ArrayMap<String, String>();
+ parms = new ArrayMap<>();
if(null == headers) {
- headers = new ArrayMap<String, String>();
+ headers = new ArrayMap<>();
}
// Create a BufferedReader for parsing the header.
BufferedReader hin = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, rlen)));
// Decode the header into parms and header java properties
- Map<String, String> pre = new ArrayMap<String, String>();
+ Map<String, String> pre = new ArrayMap<>();
decodeHeader(hin, pre, parms, headers);
method = Method.lookup(pre.get("method"));
@@ -1116,7 +1110,7 @@ public abstract class NanoHTTPD {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but next chunk does not start with boundary. Usage: GET /example/file.html");
}
boundarycount++;
- Map<String, String> item = new ArrayMap<String, String>();
+ Map<String, String> item = new ArrayMap<>();
mpline = in.readLine();
while (mpline != null && mpline.trim().length() > 0) {
int p = mpline.indexOf(':');
@@ -1131,7 +1125,7 @@ public abstract class NanoHTTPD {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but no content-disposition info found. Usage: GET /example/file.html");
}
StringTokenizer st = new StringTokenizer(contentDisposition, ";");
- Map<String, String> disposition = new ArrayMap<String, String>();
+ Map<String, String> disposition = new ArrayMap<>();
while (st.hasMoreTokens()) {
String token = st.nextToken().trim();
int p = token.indexOf('=');
@@ -1144,17 +1138,19 @@ public abstract class NanoHTTPD {
String value = "";
if (item.get("content-type") == null) {
+ StringBuilder tmp = new StringBuilder();
while (mpline != null && !mpline.contains(boundary)) {
mpline = in.readLine();
if (mpline != null) {
int d = mpline.indexOf(boundary);
if (d == -1) {
- value += mpline;
+ tmp.append(mpline);
} else {
- value += mpline.substring(0, d - 2);
+ tmp.append(mpline.substring(0, d - 2));
}
}
}
+ value = tmp.toString();
} else {
if (boundarycount > bpositions.length) {
throw new ResponseException(Response.Status.INTERNAL_ERROR, "Error processing request");
@@ -1196,7 +1192,7 @@ public abstract class NanoHTTPD {
private int[] getBoundaryPositions(ByteBuffer b, byte[] boundary) {
int matchcount = 0;
int matchbyte = -1;
- List<Integer> matchbytes = new ArrayList<Integer>();
+ List<Integer> matchbytes = new ArrayList<>();
for (int i = 0; i < b.limit(); i++) {
if (b.get(i) == boundary[matchcount]) {
if (matchcount == 0)
@@ -1326,7 +1322,9 @@ public abstract class NanoHTTPD {
}
public static class Cookie {
- private String n, v, e;
+ private final String n;
+ private final String v;
+ private final String e;
public Cookie(String name, String value, String expires) {
n = name;
@@ -1366,8 +1364,8 @@ public abstract class NanoHTTPD {
* @author LordFokas
*/
public class CookieHandler implements Iterable<String> {
- private ArrayMap<String, String> cookies = new ArrayMap<String, String>();
- private ArrayList<Cookie> queue = new ArrayList<Cookie>();
+ private final ArrayMap<String, String> cookies = new ArrayMap<>();
+ private final ArrayList<Cookie> queue = new ArrayList<>();
public CookieHandler(Map<String, String> httpHeaders) {
String raw = httpHeaders.get("cookie");
diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java
index 4e5d0297f..809b9769a 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java
@@ -1,7 +1,7 @@
package de.test.antennapod.util.syndication;
import android.test.InstrumentationTestCase;
-import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer;
+
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
@@ -9,6 +9,8 @@ import java.io.File;
import java.io.FileOutputStream;
import java.util.Map;
+import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer;
+
/**
* Test class for FeedDiscoverer
*/
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 bd3df0f9d..afe15f1b2 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
@@ -19,7 +19,7 @@ public class AtomGenerator implements FeedGenerator{
private static final String NS_ATOM = "http://www.w3.org/2005/Atom";
- public static final long FEATURE_USE_RFC3339LOCAL = 1;
+ private static final long FEATURE_USE_RFC3339LOCAL = 1;
@Override
public void writeFeed(Feed feed, OutputStream outputStream, String encoding, long flags) throws IOException {
diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/FeedGenerator.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/FeedGenerator.java
index fe5afd847..b63159384 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/FeedGenerator.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/FeedGenerator.java
@@ -1,10 +1,10 @@
package de.test.antennapod.util.syndication.feedgenerator;
-import de.danoeh.antennapod.core.feed.Feed;
-
import java.io.IOException;
import java.io.OutputStream;
+import de.danoeh.antennapod.core.feed.Feed;
+
/**
* Generates a machine-readable, platform-independent representation of a Feed object.
*/
@@ -24,5 +24,5 @@ public interface FeedGenerator {
* @param encoding The encoding to use. Must not be null.
* @param flags Optional argument for enabling implementation-dependent features.
*/
- public void writeFeed(Feed feed, OutputStream outputStream, String encoding, long flags) throws IOException;
+ void writeFeed(Feed feed, OutputStream outputStream, String encoding, long flags) throws IOException;
}
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 e7cbb1b42..89542d222 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
@@ -7,7 +7,8 @@ import java.io.IOException;
/**
* Utility methods for FeedGenerator
*/
-public class GeneratorUtil {
+class GeneratorUtil {
+ private GeneratorUtil(){}
public static void addPaymentLink(XmlSerializer xml, String paymentLink, boolean withNamespace) throws IOException {
String ns = (withNamespace) ? "http://www.w3.org/2005/Atom" : null;
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 27e89620d..f2d53799d 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
@@ -1,14 +1,16 @@
package de.test.antennapod.util.syndication.feedgenerator;
import android.util.Xml;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.util.DateUtils;
+
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.OutputStream;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.util.DateUtils;
+
/**
* Creates RSS 2.0 feeds. See FeedGenerator for more information.
*/
diff --git a/app/src/free/java/de/danoeh/antennapod/config/CastCallbackImpl.java b/app/src/free/java/de/danoeh/antennapod/config/CastCallbackImpl.java
index 5e714f02c..fb23dfa1a 100644
--- a/app/src/free/java/de/danoeh/antennapod/config/CastCallbackImpl.java
+++ b/app/src/free/java/de/danoeh/antennapod/config/CastCallbackImpl.java
@@ -2,6 +2,6 @@ package de.danoeh.antennapod.config;
import de.danoeh.antennapod.core.CastCallbacks;
-public class CastCallbackImpl implements CastCallbacks {
+class CastCallbackImpl implements CastCallbacks {
}
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 de604c7c4..4e2c40885 100644
--- a/app/src/free/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
+++ b/app/src/free/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
@@ -5,7 +5,7 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
/**
* Implements functions from PreferenceController that are flavor dependent.
*/
-public class PreferenceControllerFlavorHelper {
+class PreferenceControllerFlavorHelper {
static void setupFlavoredUI(PreferenceController.PreferenceUI ui) {
ui.findPreference(UserPreferences.PREF_CAST_ENABLED).setEnabled(false);
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d8c1ab137..cff85e905 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.danoeh.antennapod"
android:installLocation="auto"
- android:versionCode="1060401"
- android:versionName="1.6.4.1">
+ android:versionCode="1070195"
+ android:versionName="1.7.1">
<!--
Version code schema:
"1.2.3-SNAPSHOT" -> 1020300
@@ -33,11 +33,12 @@
<application
android:name="de.danoeh.antennapod.PodcastApp"
- android:icon="@drawable/ic_launcher"
+ android:icon="@mipmap/ic_launcher"
+ android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:backupAgent=".core.backup.OpmlBackupAgent"
android:restoreAnyVersion="true"
- android:logo="@drawable/ic_launcher">
+ android:logo="@mipmap/ic_launcher">
<meta-data android:name="com.google.android.gms.car.notification.SmallIcon"
android:resource="@drawable/ic_notification" />
<meta-data
@@ -97,7 +98,7 @@
android:launchMode="singleInstance"/>
<activity
- android:name=".activity.PreferenceActivityGingerbread"
+ android:name=".activity.PreferenceActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/settings_label">
<meta-data
@@ -106,24 +107,24 @@
</activity>
<activity
- android:name=".activity.PreferenceActivity"
- android:configChanges="keyboardHidden|orientation|screenSize"
- android:label="@string/settings_label">
- <meta-data
- android:name="android.support.PARENT_ACTIVITY"
- android:value="de.danoeh.antennapod.activity.MainActivity"/>
+ android:name=".activity.FeedInfoActivity"
+ android:label="@string/feed_info_label">
</activity>
- <activity android:name=".activity.FeedInfoActivity">
+ <activity
+ android:name=".activity.FeedSettingsActivity"
+ android:windowSoftInputMode="stateHidden"
+ android:label="@string/feed_settings_label">
</activity>
<service
- android:name=".service.PlayerWidgetService"
+ android:name=".core.service.PlayerWidgetJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
android:enabled="true"
android:exported="false">
</service>
- <receiver android:name=".receiver.PlayerWidget">
+ <receiver android:name=".core.receiver.PlayerWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
@@ -177,6 +178,13 @@
android:value="de.danoeh.antennapod.activity.PreferenceActivity"/>
</activity>
<activity
+ android:name=".activity.ImportExportActivity"
+ android:label="@string/import_export">
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value="de.danoeh.antennapod.activity.PreferenceActivity"/>
+ </activity>
+ <activity
android:name=".activity.OpmlImportFromPathActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/opml_import_label">
@@ -224,7 +232,8 @@
<activity
android:name=".activity.VideoplayerActivity"
- android:configChanges="keyboardHidden|orientation"
+ android:configChanges="keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize"
+ android:supportsPictureInPicture="true"
android:screenOrientation="sensorLandscape">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
@@ -383,10 +392,6 @@
</provider>
<meta-data
- android:name="de.danoeh.antennapod.core.glide.ApGlideModule"
- android:value="GlideModule" />
-
- <meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"/>
</application>
diff --git a/app/src/main/assets/LICENSE_SIL.txt b/app/src/main/assets/LICENSE_SIL.txt
new file mode 100644
index 000000000..f5ed6fa72
--- /dev/null
+++ b/app/src/main/assets/LICENSE_SIL.txt
@@ -0,0 +1,91 @@
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file
diff --git a/app/src/main/assets/logo.png b/app/src/main/assets/logo.png
index d0e988a6d..3b5261b28 100755
--- a/app/src/main/assets/logo.png
+++ b/app/src/main/assets/logo.png
Binary files differ
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
index f6a8db5fb..fde9af16f 100644
--- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
+++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
@@ -20,7 +20,7 @@ public class PodcastApp extends Application {
try {
Class.forName("de.danoeh.antennapod.config.ClientConfigurator");
} catch (Exception e) {
- throw new RuntimeException("ClientConfigurator not found");
+ throw new RuntimeException("ClientConfigurator not found", e);
}
}
@@ -41,10 +41,8 @@ public class PodcastApp extends Application {
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDropBox();
- if (Build.VERSION.SDK_INT >= 11) {
- builder.detectActivityLeaks();
- builder.detectLeakedClosableObjects();
- }
+ builder.detectActivityLeaks();
+ builder.detectLeakedClosableObjects();
if(Build.VERSION.SDK_INT >= 16) {
builder.detectLeakedRegistrationObjects();
}
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 1b42b274c..ecfdf24b0 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java
@@ -21,11 +21,10 @@ import java.nio.charset.Charset;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import rx.Observable;
-import rx.Subscriber;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Single;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Displays the 'about' screen
@@ -34,11 +33,9 @@ public class AboutActivity extends AppCompatActivity {
private static final String TAG = AboutActivity.class.getSimpleName();
- private WebView webview;
- private LinearLayout webviewContainer;
- private int depth = 0;
-
- private Subscription subscription;
+ private WebView webView;
+ private LinearLayout webViewContainer;
+ private Disposable disposable;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -46,28 +43,25 @@ public class AboutActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayShowHomeEnabled(true);
setContentView(R.layout.about);
- webviewContainer = (LinearLayout) findViewById(R.id.webvContainer);
- webview = (WebView) findViewById(R.id.webvAbout);
- webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
+ 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 >= 11
- && Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
- webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+ webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
- webview.setBackgroundColor(Color.TRANSPARENT);
+ webView.setBackgroundColor(Color.TRANSPARENT);
}
- webview.setWebViewClient(new WebViewClient() {
+ webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
- if(url.startsWith("http")) {
- depth++;
- return false;
- } else {
+ if (!url.startsWith("http")) {
url = url.replace("file:///android_asset/", "");
loadAsset(url);
return true;
}
+ return false;
}
});
@@ -75,69 +69,65 @@ public class AboutActivity extends AppCompatActivity {
}
private void loadAsset(String filename) {
- subscription = Observable.create(new Observable.OnSubscribe<String>() {
- @Override
- public void call(Subscriber<? super String> subscriber) {
- InputStream input = null;
- try {
- TypedArray res = AboutActivity.this.getTheme().obtainStyledAttributes(
- new int[] { android.R.attr.textColorPrimary });
- int colorResource = res.getColor(0, 0);
- String colorString = String.format("#%06X", 0xFFFFFF & colorResource);
- res.recycle();
- input = getAssets().open(filename);
- String webViewData = IOUtils.toString(input, Charset.defaultCharset());
- if(!webViewData.startsWith("<!DOCTYPE html>")) {
- //webViewData = webViewData.replace("\n\n", "</p><p>");
- webViewData = webViewData.replace("%", "&#37;");
- webViewData =
- "<!DOCTYPE html>" +
- "<html>" +
- "<head>" +
- " <meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\">" +
- " <style type=\"text/css\">" +
- " @font-face {" +
- " font-family: 'Roboto-Light';" +
- " src: url('file:///android_asset/Roboto-Light.ttf');" +
- " }" +
- " * {" +
- " color: %s;" +
- " font-family: roboto-Light;" +
- " font-size: 8pt;" +
- " }" +
- " </style>" +
- "</head><body><p>" + webViewData + "</p></body></html>";
- webViewData = webViewData.replace("\n", "<br/>");
- depth++;
- } else {
- depth = 0;
- }
- webViewData = String.format(webViewData, colorString);
- subscriber.onNext(webViewData);
- } catch (IOException e) {
- subscriber.onError(e);
- } finally {
- IOUtils.closeQuietly(input);
- }
- subscriber.onCompleted();
- }
- })
- .subscribeOn(Schedulers.newThread())
+ disposable = Single.create(subscriber -> {
+ InputStream input = null;
+ try {
+ TypedArray res = AboutActivity.this.getTheme().obtainStyledAttributes(
+ new int[] { R.attr.about_screen_font_color, R.attr.about_screen_background,
+ R.attr.about_screen_card_background, R.attr.about_screen_card_border});
+ String fontColor = String.format("#%06X", 0xFFFFFF & res.getColor(0, 0));
+ String backgroundColor = String.format("#%06X", 0xFFFFFF & res.getColor(1, 0));
+ String cardBackground = String.format("#%06X", 0xFFFFFF & res.getColor(2, 0));
+ String cardBorder = String.format("#%06X", 0xFFFFFF & res.getColor(3, 0));
+ res.recycle();
+ input = getAssets().open(filename);
+ String webViewData = IOUtils.toString(input, Charset.defaultCharset());
+ if (!webViewData.startsWith("<!DOCTYPE html>")) {
+ webViewData = webViewData.replace("%", "&#37;");
+ webViewData =
+ "<!DOCTYPE html>" +
+ "<html>" +
+ "<head>" +
+ " <meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\">" +
+ " <style type=\"text/css\">" +
+ " @font-face {" +
+ " font-family: 'Roboto-Light';" +
+ " src: url('file:///android_asset/Roboto-Light.ttf');" +
+ " }" +
+ " * {" +
+ " color: @fontcolor@;" +
+ " font-family: roboto-Light;" +
+ " font-size: 8pt;" +
+ " }" +
+ " </style>" +
+ "</head><body><p>" + webViewData + "</p></body></html>";
+ webViewData = webViewData.replace("\n", "<br/>");
+ }
+ webViewData = webViewData.replace("@fontcolor@", fontColor);
+ webViewData = webViewData.replace("@background@", backgroundColor);
+ webViewData = webViewData.replace("@card_background@", cardBackground);
+ webViewData = webViewData.replace("@card_border@", cardBorder);
+ subscriber.onSuccess(webViewData);
+ } catch (IOException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ subscriber.onError(e);
+ } finally {
+ IOUtils.closeQuietly(input);
+ }
+ })
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
- webviewData ->
- webview.loadDataWithBaseURL("file:///android_asset/", webviewData, "text/html", "utf-8", "about:blank"),
+ webViewData ->
+ webView.loadDataWithBaseURL("file:///android_asset/", webViewData.toString(), "text/html", "utf-8", "file:///android_asset/" + filename.toString()),
error -> Log.e(TAG, Log.getStackTraceString(error))
);
}
@Override
public void onBackPressed() {
- Log.d(TAG, "depth: " + depth);
- if(depth == 1) {
- loadAsset("about.html");
- } else if(depth > 1) {
- webview.goBack();
+ if (webView.canGoBack()) {
+ webView.goBack();
} else {
super.onBackPressed();
}
@@ -156,12 +146,12 @@ public class AboutActivity extends AppCompatActivity {
@Override
protected void onDestroy() {
super.onDestroy();
- if(subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
- if (webviewContainer != null && webview != null) {
- webviewContainer.removeAllViews();
- webview.destroy();
+ if (webViewContainer != null && webView != null) {
+ webViewContainer.removeAllViews();
+ webView.destroy();
}
}
}
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 ca214de9e..67dda01cf 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -6,41 +6,31 @@ import android.text.TextUtils;
import android.util.Log;
import android.view.View;
+import java.text.DecimalFormat;
import java.util.concurrent.atomic.AtomicBoolean;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
/**
* Activity for playing audio files.
*/
public class AudioplayerActivity extends MediaplayerInfoActivity {
- public static final String TAG = "AudioPlayerActivity";
+ private static final String TAG = "AudioPlayerActivity";
- private AtomicBoolean isSetup = new AtomicBoolean(false);
+ private final AtomicBoolean isSetup = new AtomicBoolean(false);
@Override
protected void onResume() {
super.onResume();
if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
- Intent intent = getIntent();
- Log.d(TAG, "Received VIEW intent: " + intent.getData().getPath());
- ExternalMedia media = new ExternalMedia(intent.getData().getPath(),
- MediaType.AUDIO);
- Intent launchIntent = new Intent(this, PlaybackService.class);
- launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
- launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED,
- true);
- launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, false);
- launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
- true);
- startService(launchIntent);
+ playExternalMedia(getIntent(), MediaType.AUDIO);
} else if (PlaybackService.isCasting()) {
Intent intent = PlaybackService.getPlayerActivityIntent(this);
- if (!intent.getComponent().getClassName().equals(AudioplayerActivity.class.getName())) {
+ if (intent.getComponent() != null &&
+ !intent.getComponent().getClassName().equals(AudioplayerActivity.class.getName())) {
saveCurrentFragment();
finish();
startActivity(intent);
@@ -95,7 +85,7 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
UserPreferences.setPlaybackSpeed(String.valueOf(speed));
}
}
- String speedStr = String.format("%.2fx", speed);
+ String speedStr = new DecimalFormat("0.00x").format(speed);
butPlaybackSpeed.setText(speedStr);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java
index a7e9b1e70..871e9c279 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java
@@ -13,9 +13,9 @@ import de.danoeh.antennapod.core.service.playback.PlaybackService;
* Activity for controlling the remote playback on a Cast device.
*/
public class CastplayerActivity extends MediaplayerInfoActivity {
- public static final String TAG = "CastPlayerActivity";
+ private static final String TAG = "CastPlayerActivity";
- private AtomicBoolean isSetup = new AtomicBoolean(false);
+ private final AtomicBoolean isSetup = new AtomicBoolean(false);
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
index 390d4cef8..33def125e 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
@@ -64,11 +64,11 @@ public class DirectoryChooserActivity extends AppCompatActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.directory_chooser);
- butConfirm = (Button) findViewById(R.id.butConfirm);
- butCancel = (Button) findViewById(R.id.butCancel);
- butNavUp = (ImageButton) findViewById(R.id.butNavUp);
- txtvSelectedFolder = (TextView) findViewById(R.id.txtvSelectedFolder);
- listDirectories = (ListView) findViewById(R.id.directory_list);
+ butConfirm = findViewById(R.id.butConfirm);
+ butCancel = findViewById(R.id.butCancel);
+ butNavUp = findViewById(R.id.butNavUp);
+ txtvSelectedFolder = findViewById(R.id.txtvSelectedFolder);
+ listDirectories = findViewById(R.id.directory_list);
butConfirm.setOnClickListener(new OnClickListener() {
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
index 41b2debdc..5e04d743d 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
@@ -3,15 +3,14 @@ package de.danoeh.antennapod.activity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v7.app.ActionBarActivity;
-import android.util.Log;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import org.apache.commons.lang3.Validate;
-import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadRequest;
@@ -23,8 +22,7 @@ import de.danoeh.antennapod.core.storage.DownloadRequester;
* Other arguments are optional.
* The activity's result will be the same DownloadRequest with the entered username and password.
*/
-public class DownloadAuthenticationActivity extends ActionBarActivity {
- private static final String TAG = "DownloadAuthenticationActivity";
+public class DownloadAuthenticationActivity extends AppCompatActivity {
/**
* The download request object that contains information about the resource that requires a username and a password
@@ -36,47 +34,39 @@ public class DownloadAuthenticationActivity extends ActionBarActivity {
*/
public static final String ARG_SEND_TO_DOWNLOAD_REQUESTER_BOOL = "send_to_downloadrequester";
- public static final String RESULT_REQUEST = "request";
+ private static final String RESULT_REQUEST = "request";
private EditText etxtUsername;
private EditText etxtPassword;
- private Button butConfirm;
- private Button butCancel;
- private TextView txtvDescription;
-
- private DownloadRequest request;
- private boolean sendToDownloadRequester;
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
- getSupportActionBar().hide();
- setContentView(R.layout.download_authentication_activity);
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.hide();
+ }
- etxtUsername = (EditText) findViewById(R.id.etxtUsername);
- etxtPassword = (EditText) findViewById(R.id.etxtPassword);
- butConfirm = (Button) findViewById(R.id.butConfirm);
- butCancel = (Button) findViewById(R.id.butCancel);
- txtvDescription = (TextView) findViewById(R.id.txtvDescription);
+ setContentView(R.layout.download_authentication_activity);
+ TextView txtvDescription = findViewById(R.id.txtvDescription);
+ etxtUsername = findViewById(R.id.etxtUsername);
+ etxtPassword = findViewById(R.id.etxtPassword);
+ Button butConfirm = findViewById(R.id.butConfirm);
+ Button butCancel = findViewById(R.id.butCancel);
Validate.isTrue(getIntent().hasExtra(ARG_DOWNLOAD_REQUEST), "Download request missing");
+ DownloadRequest request = getIntent().getParcelableExtra(ARG_DOWNLOAD_REQUEST);
+ boolean sendToDownloadRequester = getIntent().getBooleanExtra(ARG_SEND_TO_DOWNLOAD_REQUESTER_BOOL, false);
- request = getIntent().getParcelableExtra(ARG_DOWNLOAD_REQUEST);
- sendToDownloadRequester = getIntent().getBooleanExtra(ARG_SEND_TO_DOWNLOAD_REQUESTER_BOOL, false);
+ String newDescription = txtvDescription.getText() + ":\n\n" + request.getTitle();
+ txtvDescription.setText(newDescription);
if (savedInstanceState != null) {
etxtUsername.setText(savedInstanceState.getString("username"));
etxtPassword.setText(savedInstanceState.getString("password"));
}
- txtvDescription.setText(txtvDescription.getText() + ":\n\n" + request.getTitle());
-
- butCancel.setOnClickListener(v -> {
- setResult(Activity.RESULT_CANCELED);
- finish();
- });
-
butConfirm.setOnClickListener(v -> {
String username = etxtUsername.getText().toString();
String password = etxtPassword.getText().toString();
@@ -87,11 +77,16 @@ public class DownloadAuthenticationActivity extends ActionBarActivity {
setResult(Activity.RESULT_OK, result);
if (sendToDownloadRequester) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Sending request to DownloadRequester");
DownloadRequester.getInstance().download(DownloadAuthenticationActivity.this, request);
}
finish();
});
+
+ butCancel.setOnClickListener(v -> {
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ });
+
}
@Override
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 2a58d5104..bfa694e5c 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
@@ -2,30 +2,23 @@ package de.danoeh.antennapod.activity;
import android.content.ClipData;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
+import android.graphics.LightingColorFilter;
import android.net.Uri;
import android.os.Bundle;
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 android.widget.Toast;
import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
import com.joanzapata.iconify.Iconify;
import org.apache.commons.lang3.StringUtils;
@@ -33,24 +26,22 @@ import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
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.core.util.LangUtils;
import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText;
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Maybe;
+import io.reactivex.MaybeOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Displays information about a feed.
@@ -59,7 +50,6 @@ public class FeedInfoActivity extends AppCompatActivity {
public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
private static final String TAG = "FeedInfoActivity";
- private boolean autoDeleteChanged = false;
private Feed feed;
private ImageView imgvCover;
@@ -70,17 +60,8 @@ public class FeedInfoActivity extends AppCompatActivity {
private TextView lblAuthor;
private TextView txtvAuthor;
private TextView txtvUrl;
- 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 Subscription subscription;
+ private Disposable disposable;
private final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() {
@@ -88,56 +69,16 @@ public class FeedInfoActivity extends AppCompatActivity {
public void onClick(View v) {
if(feed != null && feed.getDownload_url() != null) {
String url = feed.getDownload_url();
- if (android.os.Build.VERSION.SDK_INT >= 11) {
- ClipData clipData = ClipData.newPlainText(url, url);
- android.content.ClipboardManager cm = (android.content.ClipboardManager) FeedInfoActivity.this
- .getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setPrimaryClip(clipData);
- } else {
- android.text.ClipboardManager cm = (android.text.ClipboardManager) FeedInfoActivity.this
- .getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setText(url);
- }
+ ClipData clipData = ClipData.newPlainText(url, url);
+ android.content.ClipboardManager cm = (android.content.ClipboardManager) FeedInfoActivity.this
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ cm.setPrimaryClip(clipData);
Toast t = Toast.makeText(FeedInfoActivity.this, R.string.copied_url_msg, Toast.LENGTH_SHORT);
t.show();
}
}
};
- private boolean authInfoChanged = false;
-
- private 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 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;
- }
- };
-
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getTheme());
@@ -146,54 +87,58 @@ public class FeedInfoActivity extends AppCompatActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1);
- imgvCover = (ImageView) findViewById(R.id.imgvCover);
- txtvTitle = (TextView) findViewById(R.id.txtvTitle);
- txtvDescription = (TextView) findViewById(R.id.txtvDescription);
- lblLanguage = (TextView) findViewById(R.id.lblLanguage);
- txtvLanguage = (TextView) findViewById(R.id.txtvLanguage);
- lblAuthor = (TextView) findViewById(R.id.lblAuthor);
- txtvAuthor = (TextView) findViewById(R.id.txtvAuthor);
- txtvUrl = (TextView) findViewById(R.id.txtvUrl);
- cbxAutoDownload = (CheckBox) findViewById(R.id.cbxAutoDownload);
- cbxKeepUpdated = (CheckBox) findViewById(R.id.cbxKeepUpdated);
- spnAutoDelete = (Spinner) findViewById(R.id.spnAutoDelete);
- etxtUsername = (EditText) findViewById(R.id.etxtUsername);
- etxtPassword = (EditText) findViewById(R.id.etxtPassword);
- etxtFilterText = (EditText) findViewById(R.id.etxtEpisodeFilterText);
- rdoFilterInclude = (RadioButton) findViewById(R.id.radio_filter_include);
- rdoFilterInclude.setOnClickListener(v -> {
- filterInclude = true;
- filterTextChanged = true;
- });
- rdoFilterExclude = (RadioButton) findViewById(R.id.radio_filter_exclude);
- rdoFilterExclude.setOnClickListener(v -> {
- filterInclude = false;
- filterTextChanged = true;
- });
+ imgvCover = findViewById(R.id.imgvCover);
+ txtvTitle = findViewById(R.id.txtvTitle);
+ TextView txtvAuthorHeader = findViewById(R.id.txtvAuthor);
+ ImageView 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));
+
+
+ txtvDescription = findViewById(R.id.txtvDescription);
+ lblLanguage = findViewById(R.id.lblLanguage);
+ txtvLanguage = findViewById(R.id.txtvLanguage);
+ lblAuthor = findViewById(R.id.lblAuthor);
+ txtvAuthor = findViewById(R.id.txtvDetailsAuthor);
+ txtvUrl = findViewById(R.id.txtvUrl);
txtvUrl.setOnClickListener(copyUrlToClipboard);
- subscription = Observable.fromCallable(()-> DBReader.getFeed(feedId))
- .subscribeOn(Schedulers.newThread())
+ disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
+ Feed feed = DBReader.getFeed(feedId);
+ if (feed != null) {
+ emitter.onSuccess(feed);
+ } else {
+ emitter.onComplete();
+ }
+ })
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
- if (result == null) {
- Log.e(TAG, "Activity was started with invalid arguments");
- finish();
- }
feed = result;
Log.d(TAG, "Language is " + feed.getLanguage());
Log.d(TAG, "Author is " + feed.getAuthor());
Log.d(TAG, "URL is " + feed.getDownload_url());
- FeedPreferences prefs = feed.getPreferences();
Glide.with(FeedInfoActivity.this)
.load(feed.getImageLocation())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
+ .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(FeedInfoActivity.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());
@@ -211,6 +156,7 @@ public class FeedInfoActivity extends AppCompatActivity {
if (!TextUtils.isEmpty(feed.getAuthor())) {
txtvAuthor.setText(feed.getAuthor());
+ txtvAuthorHeader.setText(feed.getAuthor());
} else {
lblAuthor.setVisibility(View.GONE);
txtvAuthor.setVisibility(View.GONE);
@@ -224,118 +170,21 @@ public class FeedInfoActivity extends AppCompatActivity {
txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}");
Iconify.addIcons(txtvUrl);
- cbxAutoDownload.setEnabled(UserPreferences.isEnableAutodownload());
- cbxAutoDownload.setChecked(prefs.getAutoDownload());
- cbxAutoDownload.setOnCheckedChangeListener((compoundButton, checked) -> {
- feed.getPreferences().setAutoDownload(checked);
- feed.savePreferences();
- updateAutoDownloadSettings();
- ApplyToEpisodesDialog dialog = new ApplyToEpisodesDialog(FeedInfoActivity.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();
}, error -> {
Log.d(TAG, Log.getStackTraceString(error));
finish();
+ }, () -> {
+ Log.e(TAG, "Activity was started with invalid arguments");
+ finish();
});
}
@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;
- }
- }
-
- @Override
public void onDestroy() {
super.onDestroy();
- if(subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
}
@@ -375,34 +224,4 @@ public class FeedInfoActivity extends AppCompatActivity {
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 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/FeedSettingsActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java
new file mode 100644
index 000000000..4698ed90e
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java
@@ -0,0 +1,364 @@
+package de.danoeh.antennapod.activity;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.LightingColorFilter;
+import android.net.Uri;
+import android.os.Bundle;
+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 io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+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 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;
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setTheme(UserPreferences.getTheme());
+ 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);
+ 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();
+ }
+ })
+ .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();
+ }, error -> {
+ Log.d(TAG, Log.getStackTraceString(error));
+ finish();
+ }, () -> {
+ Log.e(TAG, "Activity was started with invalid arguments");
+ finish();
+ });
+ }
+
+ @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;
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ @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
index be1c9f9e6..2b4384a02 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/FlattrAuthActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/FlattrAuthActivity.java
@@ -4,7 +4,7 @@ package de.danoeh.antennapod.activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -18,11 +18,10 @@ 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;
-import de.danoeh.antennapod.preferences.PreferenceController;
/** Guides the user through the authentication process */
-public class FlattrAuthActivity extends ActionBarActivity {
+public class FlattrAuthActivity extends AppCompatActivity {
private static final String TAG = "FlattrAuthActivity";
private TextView txtvExplanation;
@@ -42,9 +41,9 @@ public class FlattrAuthActivity extends ActionBarActivity {
if (BuildConfig.DEBUG) Log.d(TAG, "Activity created");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.flattr_auth);
- txtvExplanation = (TextView) findViewById(R.id.txtvExplanation);
- butAuthenticate = (Button) findViewById(R.id.but_authenticate);
- butReturn = (Button) findViewById(R.id.but_return_home);
+ 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);
@@ -104,7 +103,7 @@ public class FlattrAuthActivity extends ActionBarActivity {
switch (item.getItemId()) {
case android.R.id.home:
if (authSuccessful) {
- Intent intent = new Intent(this, PreferenceController.getPreferenceActivity());
+ Intent intent = new Intent(this, PreferenceActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
} else {
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
new file mode 100644
index 000000000..e6c9c37cc
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
@@ -0,0 +1,190 @@
+package de.danoeh.antennapod.activity;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.support.design.widget.Snackbar;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.MenuItem;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.channels.FileChannel;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.storage.PodDBAdapter;
+
+/**
+ * Displays the 'import/export' screen
+ */
+public class ImportExportActivity extends AppCompatActivity {
+ private static final int REQUEST_CODE_RESTORE = 43;
+ private static final int REQUEST_CODE_BACKUP_DOCUMENT = 44;
+ private static final String EXPORT_FILENAME = "AntennaPodBackup.db";
+ private static final String TAG = ImportExportActivity.class.getSimpleName();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setTheme(UserPreferences.getTheme());
+ super.onCreate(savedInstanceState);
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayShowHomeEnabled(true);
+ }
+ setContentView(R.layout.import_export_activity);
+
+ findViewById(R.id.button_export).setOnClickListener(view -> backup());
+ findViewById(R.id.button_import).setOnClickListener(view -> restore());
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ return true;
+ } else {
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private void backup() {
+ if (Build.VERSION.SDK_INT >= 19) {
+ Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .setType("application/x-sqlite3")
+ .putExtra(Intent.EXTRA_TITLE, EXPORT_FILENAME);
+
+ startActivityForResult(intent, REQUEST_CODE_BACKUP_DOCUMENT);
+ } else {
+ try {
+ File sd = Environment.getExternalStorageDirectory();
+ File backupDB = new File(sd, EXPORT_FILENAME);
+ writeBackupTo(new FileOutputStream(backupDB));
+ } catch (IOException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ Snackbar.make(findViewById(R.id.import_export_layout), e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ private void restore() {
+ if (Build.VERSION.SDK_INT >= 19) {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.setType("*/*");
+ startActivityForResult(intent, REQUEST_CODE_RESTORE);
+ } else {
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.setType("*/*");
+ startActivityForResult(Intent.createChooser(intent,
+ getString(R.string.import_select_file)), REQUEST_CODE_RESTORE);
+ }
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
+ if (resultCode != RESULT_OK || resultData == null) {
+ return;
+ }
+ Uri uri = resultData.getData();
+
+ if (requestCode == REQUEST_CODE_RESTORE) {
+ restoreFrom(uri);
+ } else if (requestCode == REQUEST_CODE_BACKUP_DOCUMENT) {
+ backupToDocument(uri);
+ }
+ }
+
+ private void restoreFrom(Uri inputUri) {
+ File currentDB = getDatabasePath(PodDBAdapter.DATABASE_NAME);
+ InputStream inputStream = null;
+ try {
+ inputStream = getContentResolver().openInputStream(inputUri);
+ FileUtils.copyInputStreamToFile(inputStream, currentDB);
+ displayImportSuccessDialog();
+ } catch (IOException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ Snackbar.make(findViewById(R.id.import_export_layout), e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show();
+ } finally {
+ IOUtils.closeQuietly(inputStream);
+ }
+ }
+
+ private void displayImportSuccessDialog() {
+ AlertDialog.Builder d = new AlertDialog.Builder(ImportExportActivity.this);
+ d.setMessage(R.string.import_ok);
+ d.setCancelable(false);
+ d.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
+ Intent intent = new Intent(getApplicationContext(), SplashActivity.class);
+ ComponentName cn = intent.getComponent();
+ Intent mainIntent = Intent.makeRestartActivityTask(cn);
+ startActivity(mainIntent);
+ });
+ d.show();
+ }
+
+ private void backupToDocument(Uri uri) {
+ ParcelFileDescriptor pfd = null;
+ FileOutputStream fileOutputStream = null;
+ try {
+ pfd = getContentResolver().openFileDescriptor(uri, "w");
+ fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
+ writeBackupTo(fileOutputStream);
+
+ Snackbar.make(findViewById(R.id.import_export_layout),
+ R.string.export_ok, Snackbar.LENGTH_SHORT).show();
+ } catch (IOException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ Snackbar.make(findViewById(R.id.import_export_layout), e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show();
+ } finally {
+ IOUtils.closeQuietly(fileOutputStream);
+
+ if (pfd != null) {
+ try {
+ pfd.close();
+ } catch (IOException e) {
+ Log.d(TAG, "Unable to close ParcelFileDescriptor");
+ }
+ }
+ }
+ }
+
+ private void writeBackupTo(FileOutputStream outFileStream) {
+ FileChannel src = null;
+ FileChannel dst = null;
+ try {
+ File currentDB = getDatabasePath(PodDBAdapter.DATABASE_NAME);
+
+ if (currentDB.exists()) {
+ src = new FileInputStream(currentDB).getChannel();
+ dst = outFileStream.getChannel();
+ dst.transferFrom(src, 0, src.size());
+
+ Snackbar.make(findViewById(R.id.import_export_layout),
+ R.string.export_ok, Snackbar.LENGTH_SHORT).show();
+ } else {
+ Snackbar.make(findViewById(R.id.import_export_layout),
+ "Can not access current database", Snackbar.LENGTH_SHORT).show();
+ }
+ } catch (IOException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ Snackbar.make(findViewById(R.id.import_export_layout), e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show();
+ } finally {
+ IOUtils.closeQuietly(src);
+ IOUtils.closeQuietly(dst);
+ }
+ }
+}
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 f0fcdca90..9f4fbe271 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -27,6 +27,7 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
+import android.widget.Toast;
import com.bumptech.glide.Glide;
@@ -42,17 +43,20 @@ 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;
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.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;
import de.danoeh.antennapod.fragment.AddFeedFragment;
@@ -64,12 +68,11 @@ 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.danoeh.antennapod.preferences.PreferenceController;
import de.greenrobot.event.EventBus;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* The activity that is shown when the user launches the app.
@@ -83,7 +86,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
public static final String PREF_NAME = "MainActivityPrefs";
public static final String PREF_IS_FIRST_LAUNCH = "prefMainActivityIsFirstLaunch";
- public static final String PREF_LAST_FRAGMENT_TAG = "prefMainActivityLastFragmentTag";
+ private static final String PREF_LAST_FRAGMENT_TAG = "prefMainActivityLastFragmentTag";
public static final String EXTRA_NAV_TYPE = "nav_type";
public static final String EXTRA_NAV_INDEX = "nav_index";
@@ -91,8 +94,8 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
public static final String EXTRA_FRAGMENT_ARGS = "fragment_args";
public static final String EXTRA_FEED_ID = "fragment_feed_id";
- public static final String SAVE_BACKSTACK_COUNT = "backstackCount";
- public static final String SAVE_TITLE = "title";
+ private static final String SAVE_BACKSTACK_COUNT = "backstackCount";
+ private static final String SAVE_TITLE = "title";
public static final String[] NAV_DRAWER_TAGS = {
QueueFragment.TAG,
@@ -119,7 +122,9 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
private ProgressDialog pd;
- private Subscription subscription;
+ private Disposable disposable;
+
+ private long lastBackButtonPressTime = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -128,7 +133,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
StorageUtils.checkStorageAvailability(this);
setContentView(R.layout.main);
- toolbar = (Toolbar) findViewById(R.id.toolbar);
+ toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@@ -140,8 +145,8 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
currentTitle = getTitle();
- drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- navList = (ListView) findViewById(R.id.nav_list);
+ drawerLayout = findViewById(R.id.drawer_layout);
+ navList = findViewById(R.id.nav_list);
navDrawer = findViewById(R.id.nav_layout);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close);
@@ -173,7 +178,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
findViewById(R.id.nav_settings).setOnClickListener(v -> {
drawerLayout.closeDrawer(navDrawer);
- startActivity(new Intent(MainActivity.this, PreferenceController.getPreferenceActivity()));
+ startActivity(new Intent(MainActivity.this, PreferenceActivity.class));
});
FragmentTransaction transaction = fm.beginTransaction();
@@ -201,6 +206,8 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
transaction.commit();
checkFirstLaunch();
+ NotificationUtils.createChannels(this);
+ UserPreferences.restartUpdateAlarm(false);
}
private void saveLastNavFragment(String tag) {
@@ -236,7 +243,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}
}
- public void showDrawerPreferencesDialog() {
+ private void showDrawerPreferencesDialog() {
final List<String> hiddenDrawerItems = UserPreferences.getHiddenDrawerItems();
String[] navLabels = new String[NAV_DRAWER_TAGS.length];
final boolean[] checked = new boolean[NAV_DRAWER_TAGS.length];
@@ -270,7 +277,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
return (navDrawerData != null) ? navDrawerData.feeds : null;
}
- public void loadFragment(int index, Bundle args) {
+ private void loadFragment(int index, Bundle args) {
Log.d(TAG, "loadFragment(index: " + index + ", args: " + args + ")");
if (index < navAdapter.getSubscriptionOffset()) {
String tag = navAdapter.getTags().get(index);
@@ -399,7 +406,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}
}
- private AdapterView.OnItemClickListener navListClickListener = new AdapterView.OnItemClickListener() {
+ private final AdapterView.OnItemClickListener navListClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int viewType = parent.getAdapter().getItemViewType(position);
@@ -410,7 +417,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}
};
- private AdapterView.OnItemLongClickListener newListLongClickListener = new AdapterView.OnItemLongClickListener() {
+ private final AdapterView.OnItemLongClickListener newListLongClickListener = new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if(position < navAdapter.getTags().size()) {
@@ -467,7 +474,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
protected void onResume() {
super.onResume();
StorageUtils.checkStorageAvailability(this);
- DBTasks.checkShouldRefreshFeeds(getApplicationContext());
+ AutoUpdateManager.checkShouldRefreshFeeds(getApplicationContext());
Intent intent = getIntent();
if (intent.hasExtra(EXTRA_FEED_ID) ||
@@ -484,8 +491,8 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
- if(subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
if(pd != null) {
pd.dismiss();
@@ -573,10 +580,29 @@ 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:
- DBWriter.markFeedSeen(feed.getId());
+ ConfirmationDialog markAllSeenConfirmationDialog = new ConfirmationDialog(this,
+ R.string.mark_all_seen_label,
+ R.string.mark_all_seen_confirmation_msg) {
+ @Override
+ public void onConfirmButtonPressed(DialogInterface dialog) {
+ dialog.dismiss();
+ DBWriter.markFeedSeen(feed.getId());
+ }
+ };
+ markAllSeenConfirmationDialog.createNewDialog().show();
return true;
case R.id.mark_all_read_item:
- DBWriter.markFeedRead(feed.getId());
+ ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(this,
+ R.string.mark_all_read_label,
+ R.string.mark_all_read_confirmation_msg) {
+
+ @Override
+ public void onConfirmButtonPressed(DialogInterface dialog) {
+ dialog.dismiss();
+ DBWriter.markFeedRead(feed.getId());
+ }
+ };
+ markAllReadConfirmationDialog.createNewDialog().show();
return true;
case R.id.rename_item:
new RenameFeedDialog(this, feed).show();
@@ -605,8 +631,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
remover.skipOnCompletion = true;
int playerStatus = PlaybackPreferences.getCurrentPlayerStatus();
if(playerStatus == PlaybackPreferences.PLAYER_STATUS_PLAYING) {
- sendBroadcast(new Intent(
- PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
+ IntentUtils.sendLocalBroadcast(MainActivity.this, PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
}
}
remover.executeAsync();
@@ -621,17 +646,47 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
@Override
public void onBackPressed() {
- if(isDrawerOpen()) {
+ if (isDrawerOpen()) {
drawerLayout.closeDrawer(navDrawer);
- } else {
+ } else if (getSupportFragmentManager().getBackStackEntryCount() != 0) {
super.onBackPressed();
+ } else {
+ switch (UserPreferences.getBackButtonBehavior()) {
+ case OPEN_DRAWER:
+ drawerLayout.openDrawer(navDrawer);
+ break;
+ case SHOW_PROMPT:
+ new AlertDialog.Builder(this)
+ .setMessage(R.string.close_prompt)
+ .setPositiveButton(R.string.yes, (dialogInterface, i) -> MainActivity.super.onBackPressed())
+ .setNegativeButton(R.string.no, null)
+ .setCancelable(false)
+ .show();
+ break;
+ case DOUBLE_TAP:
+ if (lastBackButtonPressTime < System.currentTimeMillis() - 2000) {
+ Toast.makeText(this, R.string.double_tap_toast, Toast.LENGTH_SHORT).show();
+ lastBackButtonPressTime = System.currentTimeMillis();
+ } else {
+ super.onBackPressed();
+ }
+ break;
+ case GO_TO_PAGE:
+ if (getLastNavFragment().equals(UserPreferences.getBackButtonGoToPage())) {
+ super.onBackPressed();
+ } else {
+ loadFragment(UserPreferences.getBackButtonGoToPage(), null);
+ }
+ break;
+ default: super.onBackPressed();
+ }
}
}
private DBReader.NavDrawerData navDrawerData;
private int selectedNavListIndex = 0;
- private NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
+ private final NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
@Override
public int getCount() {
if (navDrawerData != null) {
@@ -695,8 +750,8 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
};
private void loadData() {
- subscription = Observable.fromCallable(DBReader::getNavDrawerData)
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(DBReader::getNavDrawerData)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
boolean handleIntent = (navDrawerData == null);
@@ -721,6 +776,15 @@ 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;
+ }
+ }
+
public void onEventMainThread(ProgressEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
switch(event.action) {
@@ -744,14 +808,12 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
View parentLayout = findViewById(R.id.drawer_layout);
Snackbar snackbar = Snackbar.make(parentLayout, event.message, Snackbar.LENGTH_SHORT);
if(event.action != null) {
- snackbar.setAction(getString(R.string.undo), v -> {
- event.action.run();
- });
+ snackbar.setAction(getString(R.string.undo), v -> event.action.run());
}
snackbar.show();
}
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
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 21a0fa66f..1cddaa655 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -1,9 +1,11 @@
package de.danoeh.antennapod.activity;
+import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PixelFormat;
@@ -11,6 +13,9 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.Menu;
@@ -33,28 +38,36 @@ 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;
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.util.Consumer;
import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.Flavors;
+import de.danoeh.antennapod.core.util.Function;
+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.gui.PictureInPictureUtil;
+import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
import de.danoeh.antennapod.dialog.SleepTimerDialog;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
-import rx.Observable;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.functions.Action1;
-import rx.functions.Func1;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
@@ -65,23 +78,26 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
private static final String TAG = "MediaplayerActivity";
private static final String PREFS = "MediaPlayerActivityPreferences";
private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft";
+ private static final int REQUEST_CODE_STORAGE = 42;
- protected PlaybackController controller;
+ PlaybackController controller;
- protected TextView txtvPosition;
- protected TextView txtvLength;
- protected SeekBar sbPosition;
- protected ImageButton butRev;
- protected TextView txtvRev;
- protected ImageButton butPlay;
- protected ImageButton butFF;
- protected TextView txtvFF;
- protected ImageButton butSkip;
+ private TextView txtvPosition;
+ private TextView txtvLength;
+ SeekBar sbPosition;
+ private ImageButton butRev;
+ private TextView txtvRev;
+ private ImageButton butPlay;
+ private ImageButton butFF;
+ private TextView txtvFF;
+ private ImageButton butSkip;
- protected boolean showTimeLeft = false;
+ private boolean showTimeLeft = false;
private boolean isFavorite = false;
+ private Disposable disposable;
+
private PlaybackController newPlaybackController() {
return new PlaybackController(this, false) {
@@ -183,31 +199,31 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
};
}
- protected static TextView getTxtvFFFromActivity(MediaplayerActivity activity) {
+ private static TextView getTxtvFFFromActivity(MediaplayerActivity activity) {
return activity.txtvFF;
}
- protected static TextView getTxtvRevFromActivity(MediaplayerActivity activity) {
+ private static TextView getTxtvRevFromActivity(MediaplayerActivity activity) {
return activity.txtvRev;
}
- protected void onSetSpeedAbilityChanged() {
+ private void onSetSpeedAbilityChanged() {
Log.d(TAG, "onSetSpeedAbilityChanged()");
updatePlaybackSpeedButton();
}
- protected void onPlaybackSpeedChange() {
+ private void onPlaybackSpeedChange() {
updatePlaybackSpeedButtonText();
}
- protected void onServiceQueried() {
+ private void onServiceQueried() {
supportInvalidateOptionsMenu();
}
- protected void chooseTheme() {
+ void chooseTheme() {
setTheme(UserPreferences.getTheme());
}
- protected void setScreenOn(boolean enable) {
+ void setScreenOn(boolean enable) {
}
@Override
@@ -218,15 +234,16 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
Log.d(TAG, "onCreate()");
StorageUtils.checkStorageAvailability(this);
- orientation = getResources().getConfiguration().orientation;
getWindow().setFormat(PixelFormat.TRANSPARENT);
}
@Override
protected void onPause() {
- if(controller != null) {
- controller.reinitServiceIfPaused();
- controller.pause();
+ if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
+ if (controller != null) {
+ controller.reinitServiceIfPaused();
+ controller.pause();
+ }
}
super.onPause();
}
@@ -248,17 +265,12 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
*/
protected abstract void onBufferEnd();
- protected void onBufferUpdate(float progress) {
+ private void onBufferUpdate(float progress) {
if (sbPosition != null) {
- sbPosition.setSecondaryProgress((int) progress * sbPosition.getMax());
+ sbPosition.setSecondaryProgress((int) (progress * sbPosition.getMax()));
}
}
- /**
- * Current screen orientation.
- */
- protected int orientation;
-
@Override
protected void onStart() {
super.onStart();
@@ -266,6 +278,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
controller.release();
}
controller = newPlaybackController();
+ setupGUI();
+ loadMediaInfo();
+ onPositionObserverUpdate();
}
@Override
@@ -275,6 +290,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
controller.release();
controller = null; // prevent leak
}
+ if (disposable != null) {
+ disposable.dispose();
+ }
super.onStop();
}
@@ -316,11 +334,11 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
((FeedMedia) media).getItem().getFlattrStatus().flattrable()
);
- boolean hasWebsiteLink = media != null && media.getWebsiteLink() != null;
+ boolean hasWebsiteLink = ( getWebsiteLinkWithFallback(media) != null );
menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink);
boolean isItemAndHasLink = isFeedMedia &&
- ((FeedMedia) media).getItem() != null && ((FeedMedia) media).getItem().getLink() != null;
+ ShareUtils.hasLinkToShare(((FeedMedia) media).getItem());
menu.findItem(R.id.share_link_item).setVisible(isItemAndHasLink);
menu.findItem(R.id.share_link_with_position_item).setVisible(isItemAndHasLink);
@@ -368,7 +386,17 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
+
+ View cover = findViewById(R.id.imgvCover);
+ if (cover != null && Build.VERSION.SDK_INT >= 16) {
+ ActivityOptionsCompat options = ActivityOptionsCompat.
+ makeSceneTransitionAnimation(MediaplayerActivity.this,
+ cover, "coverTransition");
+ startActivity(intent, options.toBundle());
+ } else {
+ startActivity(intent);
+ }
+ finish();
return true;
} else {
if (media != null) {
@@ -546,7 +574,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
});
break;
case R.id.visit_website_item:
- Uri uri = Uri.parse(media.getWebsiteLink());
+ Uri uri = Uri.parse(getWebsiteLinkWithFallback(media));
startActivity(new Intent(Intent.ACTION_VIEW, uri));
break;
case R.id.support_item:
@@ -589,16 +617,36 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
}
}
+ private static String getWebsiteLinkWithFallback(Playable media) {
+ if (media == null) {
+ return null;
+ } else if (media.getWebsiteLink() != null) {
+ return media.getWebsiteLink();
+ } else if (media instanceof FeedMedia) {
+ return FeedItemUtil.getLinkWithFallback(((FeedMedia)media).getItem());
+ }
+ return null;
+ }
+
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume()");
StorageUtils.checkStorageAvailability(this);
- if(controller != null) {
+ 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();
+ }
+ }
+ }
+
/**
* Called by 'handleStatus()' when the PlaybackService is waiting for
* a video surface.
@@ -609,7 +657,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
protected abstract void clearStatusMsg();
- protected void onPositionObserverUpdate() {
+ void onPositionObserverUpdate() {
if (controller == null || txtvPosition == null || txtvLength == null) {
return;
}
@@ -645,12 +693,11 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
* to the PlaybackService to ensure that the activity has the right
* FeedMedia object.
*/
- protected boolean loadMediaInfo() {
+ boolean loadMediaInfo() {
Log.d(TAG, "loadMediaInfo()");
if(controller == null || controller.getMedia() == null) {
return false;
}
- Playable media = controller.getMedia();
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
onPositionObserverUpdate();
@@ -659,18 +706,18 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
return true;
}
- protected void updatePlaybackSpeedButton() {
+ void updatePlaybackSpeedButton() {
// Only meaningful on AudioplayerActivity, where it is overridden.
}
- protected void updatePlaybackSpeedButtonText() {
+ void updatePlaybackSpeedButtonText() {
// Only meaningful on AudioplayerActivity, where it is overridden.
}
/**
* Abstract directions to skip forward or back (rewind) and encapsulates behavior to get or set preference (including update of UI on the skip buttons).
*/
- static public enum SkipDirection {
+ public enum SkipDirection {
SKIP_FORWARD(
UserPreferences::getFastForwardSecs,
MediaplayerActivity::getTxtvFFFromActivity,
@@ -682,8 +729,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
R.string.pref_rewind);
private final Supplier<Integer> getPrefSecsFn;
- private final Func1<MediaplayerActivity, TextView> getTextViewFn;
- private final Action1<Integer> setPrefSecsFn;
+ private final Function<MediaplayerActivity, TextView> getTextViewFn;
+ private final Consumer<Integer> setPrefSecsFn;
private final int titleResourceID;
/**
@@ -695,7 +742,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
* @param setPrefSecsFn Handle to function that sets the preference (setting) for the skip delta value (and optionally updates the button label with the current values)
* @param titleResourceID ID of the resource string with the title for a view
*/
- SkipDirection(Supplier<Integer> getPrefSecsFn, Func1<MediaplayerActivity, TextView> getTextViewFn, Action1<Integer> setPrefSecsFn, int titleResourceID) {
+ SkipDirection(Supplier<Integer> getPrefSecsFn, Function<MediaplayerActivity, TextView> getTextViewFn, Consumer<Integer> setPrefSecsFn, int titleResourceID) {
this.getPrefSecsFn = getPrefSecsFn;
this.getTextViewFn = getTextViewFn;
this.setPrefSecsFn = setPrefSecsFn;
@@ -714,10 +761,10 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
* @param activity MediaplyerActivity that contains textview to update the display of the skip delta setting (or null if nothing to update)
*/
public void setPrefSkipSeconds(int seconds, @Nullable Activity activity) {
- setPrefSecsFn.call(seconds);
+ setPrefSecsFn.accept(seconds);
if (activity != null && activity instanceof MediaplayerActivity) {
- TextView tv = getTextViewFn.call((MediaplayerActivity)activity);
+ TextView tv = getTextViewFn.apply((MediaplayerActivity)activity);
if (tv != null) tv.setText(String.valueOf(seconds));
}
}
@@ -753,15 +800,15 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
builder.create().show();
}
- protected void setupGUI() {
+ void setupGUI() {
setContentView(getContentViewResourceId());
- sbPosition = (SeekBar) findViewById(R.id.sbPosition);
- txtvPosition = (TextView) findViewById(R.id.txtvPosition);
+ sbPosition = findViewById(R.id.sbPosition);
+ txtvPosition = findViewById(R.id.txtvPosition);
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
Log.d("timeleft", showTimeLeft ? "true" : "false");
- txtvLength = (TextView) findViewById(R.id.txtvLength);
+ txtvLength = findViewById(R.id.txtvLength);
if (txtvLength != null) {
txtvLength.setOnClickListener(v -> {
showTimeLeft = !showTimeLeft;
@@ -785,18 +832,18 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
});
}
- butRev = (ImageButton) findViewById(R.id.butRev);
- txtvRev = (TextView) findViewById(R.id.txtvRev);
+ butRev = findViewById(R.id.butRev);
+ txtvRev = findViewById(R.id.txtvRev);
if (txtvRev != null) {
txtvRev.setText(String.valueOf(UserPreferences.getRewindSecs()));
}
- butPlay = (ImageButton) findViewById(R.id.butPlay);
- butFF = (ImageButton) findViewById(R.id.butFF);
- txtvFF = (TextView) findViewById(R.id.txtvFF);
+ butPlay = findViewById(R.id.butPlay);
+ butFF = findViewById(R.id.butFF);
+ txtvFF = findViewById(R.id.txtvFF);
if (txtvFF != null) {
txtvFF.setText(String.valueOf(UserPreferences.getFastForwardSecs()));
}
- butSkip = (ImageButton) findViewById(R.id.butSkip);
+ butSkip = findViewById(R.id.butSkip);
// SEEKBAR SETUP
@@ -823,11 +870,12 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
}
if (butSkip != null) {
- butSkip.setOnClickListener(v -> sendBroadcast(new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE)));
+ butSkip.setOnClickListener(v ->
+ IntentUtils.sendLocalBroadcast(MediaplayerActivity.this, PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
}
}
- protected void onRewind() {
+ void onRewind() {
if (controller == null) {
return;
}
@@ -835,14 +883,15 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
}
- protected void onPlayPause() {
+ void onPlayPause() {
if(controller == null) {
return;
}
+ controller.init();
controller.playPause();
}
- protected void onFastForward() {
+ void onFastForward() {
if (controller == null) {
return;
}
@@ -852,7 +901,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
protected abstract int getContentViewResourceId();
- void handleError(int errorCode) {
+ private void handleError(int errorCode) {
final AlertDialog.Builder errorDialog = new AlertDialog.Builder(this);
errorDialog.setTitle(R.string.error_label);
errorDialog.setMessage(MediaPlayerError.getErrorString(this, errorCode));
@@ -865,7 +914,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
errorDialog.create().show();
}
- float prog;
+ private float prog;
@Override
public void onProgressChanged (SeekBar seekBar,int progress, boolean fromUser) {
@@ -896,22 +945,62 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
private void checkFavorite() {
Playable playable = controller.getMedia();
- if (playable != null && playable instanceof FeedMedia) {
- FeedItem feedItem = ((FeedMedia) playable).getItem();
- if (feedItem != null) {
- Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
- .subscribeOn(Schedulers.newThread())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- item -> {
- boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
- if (isFavorite != isFav) {
- isFavorite = isFav;
- invalidateOptionsMenu();
- }
- }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ if (!(playable instanceof FeedMedia)) {
+ return;
+ }
+ FeedItem feedItem = ((FeedMedia) playable).getItem();
+ if (feedItem == null) {
+ return;
+ }
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ disposable = Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ item -> {
+ boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
+ if (isFavorite != isFav) {
+ isFavorite = isFav;
+ invalidateOptionsMenu();
+ }
+ }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+
+ void playExternalMedia(Intent intent, MediaType type) {
+ if (intent == null || intent.getData() == null) {
+ return;
+ }
+ if (Build.VERSION.SDK_INT >= 23
+ && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
+ Toast.makeText(this, R.string.needs_storage_permission, Toast.LENGTH_LONG).show();
+ } else {
+ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
+ REQUEST_CODE_STORAGE);
}
+ return;
}
+
+ Log.d(TAG, "Received VIEW intent: " + intent.getData().getPath());
+ ExternalMedia media = new ExternalMedia(intent.getData().getPath(), type);
+
+ new PlaybackServiceStarter(this, media)
+ .startWhenPrepared(true)
+ .shouldStream(false)
+ .prepareImmediately(true)
+ .start();
}
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ if (requestCode == REQUEST_CODE_STORAGE) {
+ if (grantResults.length <= 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
+ Toast.makeText(this, R.string.needs_storage_permission, Toast.LENGTH_LONG).show();
+ }
+ }
+ }
}
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 b3cda69d3..a2389dabd 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
@@ -6,6 +6,7 @@ import android.content.Intent;
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;
@@ -45,8 +46,9 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
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.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;
@@ -60,28 +62,28 @@ 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.danoeh.antennapod.preferences.PreferenceController;
import de.greenrobot.event.EventBus;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Activity for playing files that do not require a video surface.
*/
public abstract class MediaplayerInfoActivity extends MediaplayerActivity implements NavDrawerActivity {
+ private static final String TAG = "MediaplayerInfoActivity";
+
private static final int POS_COVER = 0;
private static final int POS_DESCR = 1;
private static final int POS_CHAPTERS = 2;
private static final int NUM_CONTENT_FRAGMENTS = 3;
- final String TAG = "MediaplayerInfoActivity";
private static final String PREFS = "AudioPlayerActivityPreferences";
private static final String PREF_KEY_SELECTED_FRAGMENT_POSITION = "selectedFragmentPosition";
- public static final String[] NAV_DRAWER_TAGS = {
+ private static final String[] NAV_DRAWER_TAGS = {
QueueFragment.TAG,
EpisodesFragment.TAG,
SubscriptionFragment.TAG,
@@ -91,8 +93,8 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
NavListAdapter.SUBSCRIPTION_LIST_TAG
};
- protected Button butPlaybackSpeed;
- protected ImageButton butCastDisconnect;
+ Button butPlaybackSpeed;
+ ImageButton butCastDisconnect;
private DrawerLayout drawerLayout;
private NavListAdapter navAdapter;
private ListView navList;
@@ -104,7 +106,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
private ViewPager pager;
private MediaplayerInfoPagerAdapter pagerAdapter;
- private Subscription subscription;
+ private Disposable disposable;
@Override
protected void onPause() {
@@ -113,14 +115,20 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
}
@Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ supportPostponeEnterTransition();
+ }
+
+ @Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop()");
if(pagerAdapter != null) {
pagerAdapter.setController(null);
}
- if(subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
EventDistributor.getInstance().unregister(contentUpdate);
saveCurrentFragment();
@@ -145,7 +153,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
setTheme(UserPreferences.getNoTitleTheme());
}
- protected void saveCurrentFragment() {
+ void saveCurrentFragment() {
if(pager == null) {
return;
}
@@ -153,7 +161,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
prefs.edit()
.putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, pager.getCurrentItem())
- .commit();
+ .apply();
}
@Override
@@ -179,7 +187,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
pagerAdapter.onMediaChanged(media);
pagerAdapter.setController(controller);
}
- DBTasks.checkShouldRefreshFeeds(getApplicationContext());
+ AutoUpdateManager.checkShouldRefreshFeeds(getApplicationContext());
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
@@ -219,23 +227,23 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
@Override
protected void setupGUI() {
super.setupGUI();
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
findViewById(R.id.shadow).setVisibility(View.GONE);
- AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appBar);
+ AppBarLayout appBarLayout = findViewById(R.id.appBar);
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics());
appBarLayout.setElevation(px);
}
- drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- navList = (ListView) findViewById(R.id.nav_list);
+ drawerLayout = findViewById(R.id.drawer_layout);
+ navList = findViewById(R.id.nav_list);
navDrawer = findViewById(R.id.nav_layout);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close);
drawerToggle.setDrawerIndicatorEnabled(false);
- drawerLayout.setDrawerListener(drawerToggle);
+ drawerLayout.addDrawerListener(drawerToggle);
navAdapter = new NavListAdapter(itemAccess, this);
navList.setAdapter(navAdapter);
@@ -263,20 +271,22 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
findViewById(R.id.nav_settings).setOnClickListener(v -> {
drawerLayout.closeDrawer(navDrawer);
- startActivity(new Intent(MediaplayerInfoActivity.this, PreferenceController.getPreferenceActivity()));
+ startActivity(new Intent(MediaplayerInfoActivity.this, PreferenceActivity.class));
});
- butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
- butCastDisconnect = (ImageButton) findViewById(R.id.butCastDisconnect);
+ butPlaybackSpeed = findViewById(R.id.butPlaybackSpeed);
+ butCastDisconnect = findViewById(R.id.butCastDisconnect);
- pager = (ViewPager) findViewById(R.id.pager);
+ pager = findViewById(R.id.pager);
pagerAdapter = new MediaplayerInfoPagerAdapter(getSupportFragmentManager(), media);
pagerAdapter.setController(controller);
pager.setAdapter(pagerAdapter);
- CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator);
+ CirclePageIndicator pageIndicator = findViewById(R.id.page_indicator);
pageIndicator.setViewPager(pager);
loadLastFragment();
pager.onSaveInstanceState();
+
+ navList.post(this::supportStartPostponedEnterTransition);
}
@Override
@@ -297,7 +307,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
return true;
}
- public void notifyMediaPositionChanged() {
+ private void notifyMediaPositionChanged() {
if(pagerAdapter == null) {
return;
}
@@ -347,7 +357,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- return drawerToggle != null && drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
+ return (drawerToggle != null && drawerToggle.onOptionsItemSelected(item)) || super.onOptionsItemSelected(item);
}
@Override
@@ -387,12 +397,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
new RenameFeedDialog(this, feed).show();
return true;
case R.id.remove_item:
- final FeedRemover remover = new FeedRemover(this, feed) {
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
- }
- };
+ final FeedRemover remover = new FeedRemover(this, feed);
ConfirmationDialog conDialog = new ConfirmationDialog(this,
R.string.remove_feed_label,
getString(R.string.feed_delete_confirmation_msg, feed.getTitle())) {
@@ -404,12 +409,12 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
Playable playable = controller.getMedia();
if (playable != null && playable instanceof FeedMedia) {
FeedMedia media = (FeedMedia) playable;
- if (media.getItem().getFeed().getId() == feed.getId()) {
+ if (media.getItem() != null && media.getItem().getFeed() != null &&
+ media.getItem().getFeed().getId() == feed.getId()) {
Log.d(TAG, "Currently playing episode is about to be deleted, skipping");
remover.skipOnCompletion = true;
if(controller.getStatus() == PlayerStatus.PLAYING) {
- sendBroadcast(new Intent(
- PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
+ IntentUtils.sendLocalBroadcast(MediaplayerInfoActivity.this, PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
}
}
}
@@ -438,7 +443,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
}
}
- public void showDrawerPreferencesDialog() {
+ private void showDrawerPreferencesDialog() {
final List<String> hiddenDrawerItems = UserPreferences.getHiddenDrawerItems();
String[] navLabels = new String[NAV_DRAWER_TAGS.length];
final boolean[] checked = new boolean[NAV_DRAWER_TAGS.length];
@@ -467,8 +472,8 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
private DBReader.NavDrawerData navDrawerData;
private void loadData() {
- subscription = Observable.fromCallable(DBReader::getNavDrawerData)
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(DBReader::getNavDrawerData)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
navDrawerData = result;
@@ -483,14 +488,12 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
View parentLayout = findViewById(R.id.drawer_layout);
Snackbar snackbar = Snackbar.make(parentLayout, event.message, Snackbar.LENGTH_SHORT);
if (event.action != null) {
- snackbar.setAction(getString(R.string.undo), v -> {
- event.action.run();
- });
+ snackbar.setAction(getString(R.string.undo), v -> event.action.run());
}
snackbar.show();
}
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
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 f6bf11e66..73da9a834 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -5,8 +5,9 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
-import android.os.Looper;
+import android.support.annotation.UiThread;
import android.support.v4.app.NavUtils;
+import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
@@ -27,6 +28,7 @@ import android.widget.TextView;
import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@@ -55,7 +57,6 @@ 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;
@@ -65,11 +66,10 @@ 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 rx.Observable;
-import rx.Subscriber;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Downloads a feed from a feed URL and parses it. Subclasses can display the
@@ -84,7 +84,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
public static final String ARG_FEEDURL = "arg.feedurl";
// Optional argument: specify a title for the actionbar.
public static final String ARG_TITLE = "title";
- public static final int RESULT_ERROR = 2;
+ private static final int RESULT_ERROR = 2;
private static final String TAG = "OnlineFeedViewActivity";
private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE;
private volatile List<Feed> feeds;
@@ -98,23 +98,21 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
private Button subscribeButton;
- private Subscription download;
- private Subscription parser;
- private Subscription updater;
- private EventDistributor.EventListener listener = new EventDistributor.EventListener() {
+ private Disposable download;
+ private Disposable parser;
+ private Disposable updater;
+ private final EventDistributor.EventListener listener = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & EventDistributor.FEED_LIST_UPDATE) != 0) {
updater = Observable.fromCallable(DBReader::getFeedList)
- .subscribeOn(Schedulers.newThread())
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
feeds -> {
OnlineFeedViewActivity.this.feeds = feeds;
setSubscribeButtonState(feed);
- }, error -> {
- Log.e(TAG, Log.getStackTraceString(error));
- }
+ }, error -> Log.e(TAG, Log.getStackTraceString(error))
);
} else if ((arg & EVENTS) != 0) {
setSubscribeButtonState(feed);
@@ -131,10 +129,13 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
- if (getIntent() != null && getIntent().hasExtra(ARG_TITLE)) {
- getSupportActionBar().setTitle(getIntent().getStringExtra(ARG_TITLE));
+ if (actionBar != null && getIntent() != null && getIntent().hasExtra(ARG_TITLE)) {
+ actionBar.setTitle(getIntent().getStringExtra(ARG_TITLE));
}
StorageUtils.checkStorageAvailability(this);
@@ -144,9 +145,11 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
feedUrl = getIntent().getStringExtra(ARG_FEEDURL);
} else if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND)
|| TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
- feedUrl = (TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND))
+ feedUrl = TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND)
? getIntent().getStringExtra(Intent.EXTRA_TEXT) : getIntent().getDataString();
- getSupportActionBar().setTitle(R.string.add_feed_label);
+ if (actionBar != null) {
+ actionBar.setTitle(R.string.add_feed_label);
+ }
} else {
throw new IllegalArgumentException("Activity must be started with feedurl argument!");
}
@@ -210,13 +213,13 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
public void onDestroy() {
super.onDestroy();
if(updater != null) {
- updater.unsubscribe();
+ updater.dispose();
}
if(download != null) {
- download.unsubscribe();
+ download.dispose();
}
if(parser != null) {
- parser.unsubscribe();
+ parser.dispose();
}
}
@@ -265,18 +268,13 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
feed.getDownload_url(), "OnlineFeed", 0, Feed.FEEDFILETYPE_FEED, username, password,
true, null);
- download = Observable.create(new Observable.OnSubscribe<DownloadStatus>() {
- @Override
- public void call(Subscriber<? super DownloadStatus> subscriber) {
- feeds = DBReader.getFeedList();
- downloader = new HttpDownloader(request);
- downloader.call();
- Log.d(TAG, "Download was completed");
- subscriber.onNext(downloader.getResult());
- subscriber.onCompleted();
- }
+ download = Observable.fromCallable(() -> {
+ feeds = DBReader.getFeedList();
+ downloader = new HttpDownloader(request);
+ downloader.call();
+ return downloader.getResult();
})
- .subscribeOn(Schedulers.newThread())
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::checkDownloadResult,
error -> Log.e(TAG, Log.getStackTraceString(error)));
@@ -286,6 +284,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
if (status == null) {
Log.wtf(TAG, "DownloadStatus returned by Downloader was null");
finish();
+ return;
}
if (status.isCancelled()) {
return;
@@ -300,7 +299,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
} else {
String errorMsg = status.getReason().getErrorString(OnlineFeedViewActivity.this);
- if (errorMsg != null && status.getReasonDetailed() != null) {
+ if (status.getReasonDetailed() != null) {
errorMsg += " (" + status.getReasonDetailed() + ")";
}
showErrorDialog(errorMsg);
@@ -308,44 +307,43 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
private void parseFeed() {
- if (feed == null || feed.getFile_url() == null && feed.isDownloaded()) {
+ if (feed == null || (feed.getFile_url() == null && feed.isDownloaded())) {
throw new IllegalStateException("feed must be non-null and downloaded when parseFeed is called");
}
Log.d(TAG, "Parsing feed");
- parser = Observable.create(new Observable.OnSubscribe<FeedHandlerResult>() {
- @Override
- public void call(Subscriber<? super FeedHandlerResult> subscriber) {
- FeedHandler handler = new FeedHandler();
- try {
- FeedHandlerResult result = handler.parseFeed(feed);
- subscriber.onNext(result);
- } catch (UnsupportedFeedtypeException e) {
- Log.d(TAG, "Unsupported feed type detected");
- if (TextUtils.equals("html", e.getRootElement().toLowerCase())) {
- showFeedDiscoveryDialog(new File(feed.getFile_url()), feed.getDownload_url());
- } else {
- subscriber.onError(e);
- }
- } catch (Exception e) {
- Log.e(TAG, Log.getStackTraceString(e));
- subscriber.onError(e);
- } finally {
- boolean rc = new File(feed.getFile_url()).delete();
- Log.d(TAG, "Deleted feed source file. Result: " + rc);
- subscriber.onCompleted();
+ 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);
}
})
- .subscribeOn(Schedulers.newThread())
+ .subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
- beforeShowFeedInformation(result.feed);
- showFeedInformation(result.feed, result.alternateFeedUrls);
+ if(result != null) {
+ beforeShowFeedInformation(result.feed);
+ showFeedInformation(result.feed, result.alternateFeedUrls);
+ }
}, error -> {
String errorMsg = DownloadError.ERROR_PARSER_EXCEPTION.getErrorString(
OnlineFeedViewActivity.this) + " (" + error.getMessage() + ")";
showErrorDialog(errorMsg);
+ Log.d(TAG, "Feed parser exception: " + Log.getStackTraceString(error));
});
}
@@ -382,30 +380,30 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
this.feed = feed;
this.selectedDownloadUrl = feed.getDownload_url();
EventDistributor.getInstance().register(listener);
- ListView listView = (ListView) findViewById(R.id.listview);
- LayoutInflater inflater = (LayoutInflater)
- getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ ListView listView = findViewById(R.id.listview);
+ LayoutInflater inflater = LayoutInflater.from(this);
View header = inflater.inflate(R.layout.onlinefeedview_header, listView, false);
listView.addHeaderView(header);
listView.setAdapter(new FeedItemlistDescriptionAdapter(this, 0, feed.getItems()));
- ImageView cover = (ImageView) header.findViewById(R.id.imgvCover);
- TextView title = (TextView) header.findViewById(R.id.txtvTitle);
- TextView author = (TextView) header.findViewById(R.id.txtvAuthor);
- TextView description = (TextView) header.findViewById(R.id.txtvDescription);
- Spinner spAlternateUrls = (Spinner) header.findViewById(R.id.spinnerAlternateUrls);
+ ImageView cover = header.findViewById(R.id.imgvCover);
+ TextView title = header.findViewById(R.id.txtvTitle);
+ TextView author = header.findViewById(R.id.txtvAuthor);
+ TextView description = header.findViewById(R.id.txtvDescription);
+ Spinner spAlternateUrls = header.findViewById(R.id.spinnerAlternateUrls);
- subscribeButton = (Button) header.findViewById(R.id.butSubscribe);
+ subscribeButton = header.findViewById(R.id.butSubscribe);
- if (feed.getImage() != null && StringUtils.isNotBlank(feed.getImage().getDownload_url())) {
+ if (StringUtils.isNotBlank(feed.getImageUrl())) {
Glide.with(this)
- .load(feed.getImage().getDownload_url())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
+ .load(feed.getImageUrl())
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
.into(cover);
}
@@ -414,7 +412,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
description.setText(feed.getDescription());
subscribeButton.setOnClickListener(v -> {
- if(feed != null && feedInFeedlist(feed)) {
+ if(feedInFeedlist(feed)) {
Intent intent = new Intent(OnlineFeedViewActivity.this, MainActivity.class);
// feed.getId() is always 0, we have to retrieve the id from the feed list from
// the database
@@ -508,8 +506,8 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
return 0;
}
+ @UiThread
private void showErrorDialog(String errorMsg) {
- assert(Looper.myLooper() == Looper.getMainLooper()); // run on UI thread
if (!isFinishing() && !isPaused) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.error_label);
@@ -586,7 +584,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
private class FeedViewAuthenticationDialog extends AuthenticationDialog {
- private String feedUrl;
+ private final String feedUrl;
FeedViewAuthenticationDialog(Context context, int titleRes, String feedUrl) {
super(context, titleRes, true, false, null, null);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
index 355e0f372..72759c59c 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
@@ -39,9 +39,9 @@ public class OpmlFeedChooserActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.opml_selection);
- butConfirm = (Button) findViewById(R.id.butConfirm);
- butCancel = (Button) findViewById(R.id.butCancel);
- feedlist = (ListView) findViewById(R.id.feedlist);
+ butConfirm = findViewById(R.id.butConfirm);
+ butCancel = findViewById(R.id.butCancel);
+ feedlist = findViewById(R.id.feedlist);
feedlist.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listAdapter = new ArrayAdapter<>(this,
@@ -97,7 +97,7 @@ public class OpmlFeedChooserActivity extends AppCompatActivity {
}
private List<String> getTitleList() {
- List<String> result = new ArrayList<String>();
+ List<String> result = new ArrayList<>();
if (OpmlImportHolder.getReadElements() != null) {
for (OpmlElement element : OpmlImportHolder.getReadElements()) {
result.add(element.getText());
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
index 07b0b3cdb..c04ae051e 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
@@ -68,7 +68,7 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
}
}
- protected void importUri(@Nullable Uri uri) {
+ void importUri(@Nullable Uri uri) {
if(uri == null) {
new MaterialDialog.Builder(this)
.content(R.string.opml_import_error_no_file)
@@ -114,7 +114,7 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
}
/** Starts the import process. */
- protected void startImport() {
+ private void startImport() {
try {
Reader mReader = new InputStreamReader(getContentResolver().openInputStream(uri), LangUtils.UTF_8);
importWorker = new OpmlImportWorker(this, mReader) {
@@ -144,7 +144,7 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
}
}
- protected boolean finishWhenCanceled() {
+ boolean finishWhenCanceled() {
return false;
}
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 eb6b473d2..a63d3b735 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
@@ -36,26 +36,25 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.opml_import);
- final TextView txtvHeaderExplanation1 = (TextView) findViewById(R.id.txtvHeadingExplanation1);
- final TextView txtvExplanation1 = (TextView) findViewById(R.id.txtvExplanation1);
- final TextView txtvHeaderExplanation2 = (TextView) findViewById(R.id.txtvHeadingExplanation2);
- final TextView txtvExplanation2 = (TextView) findViewById(R.id.txtvExplanation2);
- final TextView txtvHeaderExplanation3 = (TextView) findViewById(R.id.txtvHeadingExplanation3);
+ 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);
- Button butChooseFilesystem = (Button) findViewById(R.id.butChooseFileFromFilesystem);
+ Button butChooseFilesystem = findViewById(R.id.butChooseFileFromFilesystem);
butChooseFilesystem.setOnClickListener(v -> chooseFileFromFilesystem());
- Button butChooseExternal = (Button) findViewById(R.id.butChooseFileFromExternal);
+ Button butChooseExternal = findViewById(R.id.butChooseFileFromExternal);
butChooseExternal.setOnClickListener(v -> chooseFileFromExternal());
int nextOption = 1;
String optionLabel = getString(R.string.opml_import_option);
intentPickAction = new Intent(Intent.ACTION_PICK);
- intentPickAction.setData(Uri.parse("file://"));
if(!IntentUtils.isCallable(getApplicationContext(), intentPickAction)) {
intentPickAction.setData(null);
- if(false == IntentUtils.isCallable(getApplicationContext(), intentPickAction)) {
+ if(!IntentUtils.isCallable(getApplicationContext(), intentPickAction)) {
txtvHeaderExplanation1.setVisibility(View.GONE);
txtvExplanation1.setVisibility(View.GONE);
findViewById(R.id.divider1).setVisibility(View.GONE);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java
index b01cf43e4..dc5570dc0 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java
@@ -14,6 +14,8 @@ import de.danoeh.antennapod.core.export.opml.OpmlElement;
*/
public class OpmlImportHolder {
+ private OpmlImportHolder(){}
+
private static ArrayList<OpmlElement> readElements;
public static ArrayList<OpmlElement> getReadElements() {
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 dd932814f..452e91bd3 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -1,19 +1,20 @@
package de.danoeh.antennapod.activity;
-import android.annotation.TargetApi;
-import android.app.Activity;
import android.content.Intent;
-import android.os.Build;
import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
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;
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;
@@ -24,25 +25,40 @@ import de.danoeh.antennapod.preferences.PreferenceController;
* PreferenceActivity for API 11+. In order to change the behavior of the preference UI, see
* PreferenceController.
*/
-public class PreferenceActivity extends AppCompatActivity {
+public class PreferenceActivity extends AppCompatActivity implements SearchPreferenceResultListener {
+ public static final String PARAM_RESOURCE = "resource";
private static WeakReference<PreferenceActivity> instance;
private PreferenceController preferenceController;
- private MainFragment prefFragment;
private final PreferenceController.PreferenceUI preferenceUI = new PreferenceController.PreferenceUI() {
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ 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 prefFragment.findPreference(key);
+ return fragment.findPreference(key);
+ }
+
+ @Override
+ public PreferenceScreen getPreferenceScreen() {
+ return fragment.getPreferenceScreen();
}
@Override
- public Activity getActivity() {
+ public AppCompatActivity getActivity() {
return PreferenceActivity.this;
}
};
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
protected void onCreate(Bundle savedInstanceState) {
// This must be the FIRST thing we do, otherwise other code may not have the
@@ -68,8 +84,21 @@ public class PreferenceActivity extends AppCompatActivity {
// since the MainFragment depends on the preferenceController already being created
preferenceController = new PreferenceController(preferenceUI);
- prefFragment = new MainFragment();
- getFragmentManager().beginTransaction().replace(R.id.content, prefFragment).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();
+ }
}
@Override
@@ -88,24 +117,40 @@ public class PreferenceActivity extends AppCompatActivity {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
- finish();
+ if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
+ finish();
+ } else {
+ getSupportFragmentManager().popBackStack();
+ }
return true;
default:
return false;
}
}
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- public static class MainFragment extends PreferenceFragment {
+ @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);
- addPreferencesFromResource(R.xml.preferences);
+ }
+
+ @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.preferenceController.onCreate();
+ if (activity != null && activity.preferenceController != null) {
+ activity.preferenceUI.setFragment(this);
+ activity.preferenceController.onCreate(screen);
}
}
@@ -114,15 +159,17 @@ public class PreferenceActivity extends AppCompatActivity {
super.onResume();
PreferenceActivity activity = instance.get();
if(activity != null && activity.preferenceController != null) {
- activity.preferenceController.onResume();
+ activity.setTitle(PreferenceController.getTitleOfPage(screen));
+ activity.preferenceUI.setFragment(this);
+ activity.preferenceController.onResume(screen);
}
}
@Override
public void onPause() {
PreferenceActivity activity = instance.get();
- if(activity != null && activity.preferenceController != null) {
- activity.preferenceController.onPause();
+ if (screen == R.xml.preferences_gpodder) {
+ activity.preferenceController.unregisterGpodnet();
}
super.onPause();
}
@@ -130,8 +177,8 @@ public class PreferenceActivity extends AppCompatActivity {
@Override
public void onStop() {
PreferenceActivity activity = instance.get();
- if(activity != null && activity.preferenceController != null) {
- activity.preferenceController.onStop();
+ if (screen == R.xml.preferences_storage) {
+ activity.preferenceController.unsubscribeExportSubscription();
}
super.onStop();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java
deleted file mode 100644
index 390bec15c..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.Intent;
-import android.content.res.Resources.Theme;
-import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.PreferenceScreen;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.preferences.PreferenceController;
-
-/**
- * PreferenceActivity for API 10. In order to change the behavior of the preference UI, see
- * PreferenceController.
- */
-public class PreferenceActivityGingerbread extends android.preference.PreferenceActivity {
- private static final String TAG = "PreferenceActivity";
- private final PreferenceController.PreferenceUI preferenceUI = new PreferenceController.PreferenceUI() {
-
- @SuppressWarnings("deprecation")
- @Override
- public Preference findPreference(CharSequence key) {
- return PreferenceActivityGingerbread.this.findPreference(key);
- }
-
- @Override
- public Activity getActivity() {
- return PreferenceActivityGingerbread.this;
- }
- };
- private PreferenceController preferenceController;
-
- @SuppressLint("NewApi")
- @SuppressWarnings("deprecation")
- @Override
- public void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
-
- addPreferencesFromResource(R.xml.preferences);
- preferenceController = new PreferenceController(preferenceUI);
- preferenceController.onCreate();
- }
-
-
- @Override
- protected void onResume() {
- super.onResume();
- preferenceController.onResume();
- }
-
- @Override
- protected void onPause() {
- preferenceController.onPause();
- super.onPause();
- }
-
- @Override
- protected void onStop() {
- preferenceController.onStop();
- super.onStop();
- }
-
- @Override
- protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
- theme.applyStyle(UserPreferences.getTheme(), true);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- preferenceController.onActivityResult(requestCode, resultCode, data);
- }
-
- @SuppressWarnings("deprecation")
- @Override
- public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
- Preference preference) {
- super.onPreferenceTreeClick(preferenceScreen, preference);
- if (preference != null)
- if (preference instanceof PreferenceScreen)
- if (((PreferenceScreen) preference).getDialog() != null)
- ((PreferenceScreen) preference)
- .getDialog()
- .getWindow()
- .getDecorView()
- .setBackgroundDrawable(
- this.getWindow().getDecorView()
- .getBackground().getConstantState()
- .newDrawable()
- );
- return false;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java
index b92ac8577..52102eee1 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java
@@ -1,23 +1,51 @@
package de.danoeh.antennapod.activity;
import android.content.Intent;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
+import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.app.AppCompatActivity;
+import android.widget.ProgressBar;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.storage.PodDBAdapter;
+import io.reactivex.Completable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
/**
- * Creator: vbarad
- * Date: 2016-12-03
- * Project: AntennaPod
+ * Shows the AntennaPod logo while waiting for the main activity to start
*/
-
public class SplashActivity extends AppCompatActivity {
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.splash);
+
+ ProgressBar progressBar = findViewById(R.id.progressBar);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ Drawable wrapDrawable = DrawableCompat.wrap(progressBar.getIndeterminateDrawable());
+ DrawableCompat.setTint(wrapDrawable, 0xffffffff);
+ progressBar.setIndeterminateDrawable(DrawableCompat.unwrap(wrapDrawable));
+ } else {
+ progressBar.getIndeterminateDrawable().setColorFilter(0xffffffff, PorterDuff.Mode.SRC_IN);
+ }
- Intent intent = new Intent(this, MainActivity.class);
- startActivity(intent);
- finish();
- }
+ Completable.create(subscriber -> {
+ // Trigger schema updates
+ PodDBAdapter.getInstance().open();
+ PodDBAdapter.getInstance().close();
+ subscriber.onComplete();
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(() -> {
+ Intent intent = new Intent(SplashActivity.this, MainActivity.class);
+ startActivity(intent);
+ finish();
+ });
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java
index b2ff43c43..37199ccf7 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java
@@ -20,10 +20,10 @@ import de.danoeh.antennapod.adapter.StatisticsListAdapter;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.Converter;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Displays the 'statistics' screen
@@ -35,7 +35,7 @@ public class StatisticsActivity extends AppCompatActivity
private static final String PREF_NAME = "StatisticsActivityPrefs";
private static final String PREF_COUNT_ALL = "countAll";
- private Subscription subscription;
+ private Disposable disposable;
private TextView totalTimeTextView;
private ListView feedStatisticsList;
private ProgressBar progressBar;
@@ -53,9 +53,9 @@ public class StatisticsActivity extends AppCompatActivity
prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
countAll = prefs.getBoolean(PREF_COUNT_ALL, false);
- totalTimeTextView = (TextView) findViewById(R.id.total_time);
- feedStatisticsList = (ListView) findViewById(R.id.statistics_list);
- progressBar = (ProgressBar) findViewById(R.id.progressBar);
+ totalTimeTextView = findViewById(R.id.total_time);
+ feedStatisticsList = findViewById(R.id.statistics_list);
+ progressBar = findViewById(R.id.progressBar);
listAdapter = new StatisticsListAdapter(this);
listAdapter.setCountAll(countAll);
feedStatisticsList.setAdapter(listAdapter);
@@ -119,21 +119,19 @@ public class StatisticsActivity extends AppCompatActivity
}
private void loadStatistics() {
- if (subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
- subscription = Observable.fromCallable(() -> DBReader.getStatistics(countAll))
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(() -> DBReader.getStatistics(countAll))
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
- if (result != null) {
- totalTimeTextView.setText(Converter
- .shortLocalizedDuration(this, countAll ? result.totalTimeCountAll : result.totalTime));
- listAdapter.update(result.feedTime);
- progressBar.setVisibility(View.GONE);
- totalTimeTextView.setVisibility(View.VISIBLE);
- feedStatisticsList.setVisibility(View.VISIBLE);
- }
+ totalTimeTextView.setText(Converter
+ .shortLocalizedDuration(this, countAll ? result.totalTimeCountAll : result.totalTime));
+ listAdapter.update(result.feedTime);
+ progressBar.setVisibility(View.GONE);
+ totalTimeTextView.setVisibility(View.VISIBLE);
+ feedStatisticsList.setVisibility(View.VISIBLE);
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
index d104a9e93..20e34cc52 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
@@ -42,7 +42,7 @@ public class StorageErrorActivity extends AppCompatActivity {
setContentView(R.layout.storage_error);
- Button btnChooseDataFolder = (Button) findViewById(R.id.btnChooseDataFolder);
+ Button btnChooseDataFolder = findViewById(R.id.btnChooseDataFolder);
btnChooseDataFolder.setOnClickListener(v -> {
if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
@@ -164,7 +164,7 @@ public class StorageErrorActivity extends AppCompatActivity {
startActivity(new Intent(this, MainActivity.class));
}
- private BroadcastReceiver mediaUpdate = new BroadcastReceiver() {
+ private final BroadcastReceiver mediaUpdate = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
index 8531a7356..78cc15b2c 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -7,14 +7,19 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.WindowCompat;
+import android.support.v7.app.ActionBar;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.SeekBar;
@@ -24,9 +29,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.MediaType;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
-import de.danoeh.antennapod.core.util.playback.ExternalMedia;
+import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.view.AspectRatioVideoView;
@@ -45,12 +51,13 @@ public class VideoplayerActivity extends MediaplayerActivity {
private VideoControlsHider videoControlsHider = new VideoControlsHider(this);
- private AtomicBoolean isSetup = new AtomicBoolean(false);
+ private final AtomicBoolean isSetup = new AtomicBoolean(false);
private LinearLayout controls;
private LinearLayout videoOverlay;
private AspectRatioVideoView videoview;
private ProgressBar progressIndicator;
+ private FrameLayout videoframe;
@Override
protected void chooseTheme() {
@@ -70,20 +77,8 @@ public class VideoplayerActivity extends MediaplayerActivity {
@Override
protected void onResume() {
super.onResume();
- if (getIntent().getAction() != null
- && getIntent().getAction().equals(Intent.ACTION_VIEW)) {
- Intent intent = getIntent();
- Log.d(TAG, "Received VIEW intent: " + intent.getData().getPath());
- ExternalMedia media = new ExternalMedia(intent.getData().getPath(),
- MediaType.VIDEO);
- Intent launchIntent = new Intent(this, PlaybackService.class);
- launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
- launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED,
- true);
- launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, false);
- launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
- true);
- startService(launchIntent);
+ if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
+ playExternalMedia(getIntent(), MediaType.VIDEO);
} else if (PlaybackService.isCasting()) {
Intent intent = PlaybackService.getPlayerActivityIntent(this);
if (!intent.getComponent().getClassName().equals(VideoplayerActivity.class.getName())) {
@@ -95,10 +90,27 @@ public class VideoplayerActivity extends MediaplayerActivity {
}
@Override
+ protected void onStop() {
+ super.onStop();
+ if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
+ videoControlsHider.stop();
+ }
+ }
+
+ @Override
+ public void onUserLeaveHint () {
+ if (!PictureInPictureUtil.isInPictureInPictureMode(this) && UserPreferences.getVideoBackgroundBehavior()
+ == UserPreferences.VideoBackgroundBehavior.PICTURE_IN_PICTURE) {
+ compatEnterPictureInPicture();
+ }
+ }
+
+ @Override
protected void onPause() {
- videoControlsHider.stop();
- if (controller != null && controller.getStatus() == PlayerStatus.PLAYING) {
- controller.pause();
+ if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
+ if (controller != null && controller.getStatus() == PlayerStatus.PLAYING) {
+ controller.pause();
+ }
}
super.onPause();
}
@@ -126,42 +138,38 @@ public class VideoplayerActivity extends MediaplayerActivity {
@Override
protected void setupGUI() {
- if(isSetup.getAndSet(true)) {
+ if (isSetup.getAndSet(true)) {
return;
}
super.setupGUI();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- controls = (LinearLayout) findViewById(R.id.controls);
- videoOverlay = (LinearLayout) findViewById(R.id.overlay);
- videoview = (AspectRatioVideoView) findViewById(R.id.videoview);
- progressIndicator = (ProgressBar) findViewById(R.id.progressIndicator);
+ controls = findViewById(R.id.controls);
+ videoOverlay = findViewById(R.id.overlay);
+ videoview = findViewById(R.id.videoview);
+ videoframe = findViewById(R.id.videoframe);
+ progressIndicator = findViewById(R.id.progressIndicator);
videoview.getHolder().addCallback(surfaceHolderCallback);
- videoview.setOnTouchListener(onVideoviewTouched);
+ videoframe.setOnTouchListener(onVideoviewTouched);
+ videoOverlay.setOnTouchListener((view, motionEvent) -> true); // To suppress touches directly below the slider
if (Build.VERSION.SDK_INT >= 16) {
videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
}
- if (Build.VERSION.SDK_INT >= 14) {
- videoOverlay.setFitsSystemWindows(true);
- }
+ videoOverlay.setFitsSystemWindows(true);
setupVideoControlsToggler();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
+
+ videoframe.getViewTreeObserver().addOnGlobalLayoutListener(() ->
+ videoview.setAvailableSize(videoframe.getWidth(), videoframe.getHeight()));
}
@Override
protected void onAwaitingVideoSurface() {
+ setupVideoAspectRatio();
if (videoSurfaceCreated && controller != null) {
Log.d(TAG, "Videosurface already created, setting videosurface now");
-
- Pair<Integer, Integer> videoSize = controller.getVideoSize();
- if (videoSize != null && videoSize.first > 0 && videoSize.second > 0) {
- Log.d(TAG, "Width,height of video: " + videoSize.first + ", " + videoSize.second);
- videoview.setVideoSize(videoSize.first, videoSize.second);
- } else {
- Log.e(TAG, "Could not determine video size");
- }
controller.setVideoSurface(videoview.getHolder());
}
}
@@ -180,8 +188,11 @@ public class VideoplayerActivity extends MediaplayerActivity {
progressIndicator.setVisibility(View.INVISIBLE);
}
- View.OnTouchListener onVideoviewTouched = (v, event) -> {
+ private final View.OnTouchListener onVideoviewTouched = (v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (PictureInPictureUtil.isInPictureInPictureMode(this)) {
+ return true;
+ }
videoControlsHider.stop();
toggleVideoControlsVisibility();
if (videoControlsShowing) {
@@ -194,11 +205,23 @@ public class VideoplayerActivity extends MediaplayerActivity {
};
@SuppressLint("NewApi")
- void setupVideoControlsToggler() {
+ private void setupVideoControlsToggler() {
videoControlsHider.stop();
videoControlsHider.start();
}
+ private void setupVideoAspectRatio() {
+ if (videoSurfaceCreated && controller != null) {
+ Pair<Integer, Integer> videoSize = controller.getVideoSize();
+ if (videoSize != null && videoSize.first > 0 && videoSize.second > 0) {
+ Log.d(TAG, "Width,height of video: " + videoSize.first + ", " + videoSize.second);
+ videoview.setVideoSize(videoSize.first, videoSize.second);
+ } else {
+ Log.e(TAG, "Could not determine video size");
+ }
+ }
+ }
+
private void toggleVideoControlsVisibility() {
if (videoControlsShowing) {
getSupportActionBar().hide();
@@ -247,14 +270,16 @@ public class VideoplayerActivity extends MediaplayerActivity {
Log.e(TAG, "Couldn't attach surface to mediaplayer - reference to service was null");
}
}
-
+ setupVideoAspectRatio();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "Videosurface was destroyed");
videoSurfaceCreated = false;
- if (controller != null && !destroyingDueToReload) {
+ if (controller != null && !destroyingDueToReload
+ && UserPreferences.getVideoBackgroundBehavior()
+ != UserPreferences.VideoBackgroundBehavior.CONTINUE_PLAYING) {
controller.notifyVideoSurfaceAbandoned();
}
}
@@ -263,6 +288,13 @@ public class VideoplayerActivity extends MediaplayerActivity {
@Override
protected void onReloadNotification(int notificationCode) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && PictureInPictureUtil.isInPictureInPictureMode(this)) {
+ if (notificationCode == PlaybackService.EXTRA_CODE_AUDIO
+ || notificationCode == PlaybackService.EXTRA_CODE_CAST) {
+ finish();
+ }
+ return;
+ }
if (notificationCode == PlaybackService.EXTRA_CODE_AUDIO) {
Log.d(TAG, "ReloadNotification received, switching to Audioplayer now");
destroyingDueToReload = true;
@@ -307,28 +339,31 @@ public class VideoplayerActivity extends MediaplayerActivity {
videoOverlay.startAnimation(animation);
controls.startAnimation(animation);
}
- if (Build.VERSION.SDK_INT >= 14) {
- videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
- }
+ videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
@SuppressLint("NewApi")
- private void hideVideoControls() {
- final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_out);
- if (animation != null) {
- videoOverlay.startAnimation(animation);
- controls.startAnimation(animation);
- }
- if (Build.VERSION.SDK_INT >= 14) {
- int videoviewFlag = (Build.VERSION.SDK_INT >= 16) ? View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION : 0;
- getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | videoviewFlag);
- videoOverlay.setFitsSystemWindows(true);
+ private void hideVideoControls(boolean showAnimation) {
+ if (showAnimation) {
+ final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_out);
+ if (animation != null) {
+ videoOverlay.startAnimation(animation);
+ controls.startAnimation(animation);
+ }
}
+ int videoviewFlag = (Build.VERSION.SDK_INT >= 16) ? View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION : 0;
+ getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | videoviewFlag);
+ videoOverlay.setFitsSystemWindows(true);
+
videoOverlay.setVisibility(View.GONE);
controls.setVisibility(View.GONE);
}
+ private void hideVideoControls() {
+ hideVideoControls(true);
+ }
+
@Override
protected int getContentViewResourceId() {
return R.layout.videoplayer_activity;
@@ -344,24 +379,53 @@ public class VideoplayerActivity extends MediaplayerActivity {
}
}
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ if (PictureInPictureUtil.supportsPictureInPicture(this)) {
+ menu.findItem(R.id.player_go_to_picture_in_picture).setVisible(true);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.player_go_to_picture_in_picture) {
+ compatEnterPictureInPicture();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void compatEnterPictureInPicture() {
+ if (PictureInPictureUtil.supportsPictureInPicture(this) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ getSupportActionBar().hide();
+ hideVideoControls(false);
+ enterPictureInPictureMode();
+ }
+ }
+
private static class VideoControlsHider extends Handler {
private static final int DELAY = 2500;
private WeakReference<VideoplayerActivity> activity;
- public VideoControlsHider(VideoplayerActivity activity) {
+ VideoControlsHider(VideoplayerActivity activity) {
this.activity = new WeakReference<>(activity);
}
private final Runnable hideVideoControls = () -> {
- VideoplayerActivity vpa = activity.get();
- if(vpa == null) {
+ VideoplayerActivity vpa = activity != null ? activity.get() : null;
+ if (vpa == null) {
return;
}
if (vpa.videoControlsShowing) {
Log.d(TAG, "Hiding video controls");
- vpa.getSupportActionBar().hide();
+ ActionBar actionBar = vpa.getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.hide();
+ }
vpa.hideVideoControls();
vpa.videoControlsShowing = false;
}
@@ -371,7 +435,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
this.postDelayed(hideVideoControls, DELAY);
}
- public void stop() {
+ void stop() {
this.removeCallbacks(hideVideoControls);
}
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 8ede947c5..8fcdb4371 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
@@ -45,8 +45,6 @@ import de.danoeh.antennapod.core.service.GpodnetSyncService;
public class GpodnetAuthenticationActivity extends AppCompatActivity {
private static final String TAG = "GpodnetAuthActivity";
- private static final String CURRENT_STEP = "current_step";
-
private ViewFlipper viewFlipper;
private static final int STEP_DEFAULT = -1;
@@ -61,7 +59,7 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
private volatile String password;
private volatile GpodnetDevice selectedDevice;
- View[] views;
+ private View[] views;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -72,7 +70,7 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
setContentView(R.layout.gpodnetauth_activity);
service = new GpodnetService();
- viewFlipper = (ViewFlipper) findViewById(R.id.viewflipper);
+ viewFlipper = findViewById(R.id.viewflipper);
LayoutInflater inflater = (LayoutInflater)
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
views = new View[]{
@@ -109,11 +107,11 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
}
private void setupLoginView(View view) {
- final EditText username = (EditText) view.findViewById(R.id.etxtUsername);
- final EditText password = (EditText) view.findViewById(R.id.etxtPassword);
- final Button login = (Button) view.findViewById(R.id.butLogin);
- final TextView txtvError = (TextView) view.findViewById(R.id.txtvError);
- final ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.progBarLogin);
+ final EditText username = view.findViewById(R.id.etxtUsername);
+ final EditText password = view.findViewById(R.id.etxtPassword);
+ final Button login = view.findViewById(R.id.butLogin);
+ final TextView txtvError = view.findViewById(R.id.txtvError);
+ final ProgressBar progressBar = view.findViewById(R.id.progBarLogin);
password.setOnEditorActionListener((v, actionID, event) ->
actionID == EditorInfo.IME_ACTION_GO && login.performClick());
@@ -171,23 +169,19 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
return null;
}
};
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- authTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, service);
- } else {
- authTask.execute();
- }
+ authTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, service);
}
});
}
private void setupDeviceView(View view) {
- final EditText deviceID = (EditText) view.findViewById(R.id.etxtDeviceID);
- final EditText caption = (EditText) view.findViewById(R.id.etxtCaption);
- final Button createNewDevice = (Button) view.findViewById(R.id.butCreateNewDevice);
- final Button chooseDevice = (Button) view.findViewById(R.id.butChooseExistingDevice);
- final TextView txtvError = (TextView) view.findViewById(R.id.txtvError);
- final ProgressBar progBarCreateDevice = (ProgressBar) view.findViewById(R.id.progbarCreateDevice);
- final Spinner spinnerDevices = (Spinner) view.findViewById(R.id.spinnerChooseDevice);
+ final EditText deviceID = view.findViewById(R.id.etxtDeviceID);
+ final EditText caption = view.findViewById(R.id.etxtCaption);
+ final Button createNewDevice = view.findViewById(R.id.butCreateNewDevice);
+ final Button chooseDevice = view.findViewById(R.id.butChooseExistingDevice);
+ final TextView txtvError = view.findViewById(R.id.txtvError);
+ final ProgressBar progBarCreateDevice = view.findViewById(R.id.progbarCreateDevice);
+ final Spinner spinnerDevices = view.findViewById(R.id.spinnerChooseDevice);
// load device list
@@ -352,8 +346,8 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
}
private void setupFinishView(View view) {
- final Button sync = (Button) view.findViewById(R.id.butSyncNow);
- final Button back = (Button) view.findViewById(R.id.butGoMainscreen);
+ final Button sync = view.findViewById(R.id.butSyncNow);
+ final Button back = view.findViewById(R.id.butGoMainscreen);
sync.setOnClickListener(v -> {
GpodnetSyncService.sendSyncIntent(GpodnetAuthenticationActivity.this);
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java
index c18564351..e6b42efcb 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java
@@ -3,7 +3,7 @@ package de.danoeh.antennapod.adapter;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.util.LongList;
-public interface ActionButtonCallback {
+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
index f0210f983..a915692d1 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
@@ -16,7 +16,7 @@ import de.danoeh.antennapod.core.storage.DownloadRequester;
* Utility methods for the action button that is displayed on the right hand side
* of a listitem.
*/
-public class ActionButtonUtils {
+class ActionButtonUtils {
private final int[] labels;
private final TypedArray drawables;
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 3e8bbc488..0b2b81edb 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.adapter;
import android.os.Build;
+import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
@@ -19,9 +20,7 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.bumptech.glide.Glide;
import com.joanzapata.iconify.Iconify;
-import com.nineoldandroids.view.ViewHelper;
import java.lang.ref.WeakReference;
@@ -29,13 +28,12 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
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;
import de.danoeh.antennapod.core.util.DateUtils;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.NetworkUtils;
+import de.danoeh.antennapod.core.util.ThemeUtils;
import de.danoeh.antennapod.fragment.ItemFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
@@ -52,7 +50,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
private final ActionButtonUtils actionButtonUtils;
private final boolean showOnlyNewEpisodes;
- private int position = -1;
+ private FeedItem selectedItem;
private final int playingBackGroundColor;
private final int normalBackGroundColor;
@@ -68,11 +66,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
this.actionButtonCallback = actionButtonCallback;
this.showOnlyNewEpisodes = showOnlyNewEpisodes;
- if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
- playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_dark);
- } else {
- playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_light);
- }
+ playingBackGroundColor = ThemeUtils.getColorFromAttr(mainActivity, R.attr.currently_playing_background);
normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent);
}
@@ -81,27 +75,26 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.new_episodes_listitem, parent, false);
Holder holder = new Holder(view);
- holder.container = (FrameLayout) view.findViewById(R.id.container);
- holder.content = (LinearLayout) view.findViewById(R.id.content);
- holder.placeholder = (TextView) view.findViewById(R.id.txtvPlaceholder);
- holder.title = (TextView) view.findViewById(R.id.txtvTitle);
+ holder.container = view.findViewById(R.id.container);
+ holder.content = view.findViewById(R.id.content);
+ holder.placeholder = view.findViewById(R.id.txtvPlaceholder);
+ holder.title = view.findViewById(R.id.txtvTitle);
if(Build.VERSION.SDK_INT >= 23) {
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
}
- holder.pubDate = (TextView) view
+ holder.pubDate = view
.findViewById(R.id.txtvPublished);
holder.statusUnread = view.findViewById(R.id.statusUnread);
- holder.butSecondary = (ImageButton) view
+ holder.butSecondary = view
.findViewById(R.id.butSecondaryAction);
- holder.queueStatus = (ImageView) view
+ holder.queueStatus = view
.findViewById(R.id.imgvInPlaylist);
- holder.progress = (ProgressBar) view
+ holder.progress = view
.findViewById(R.id.pbar_progress);
- holder.cover = (ImageView) view.findViewById(R.id.imgvCover);
- holder.txtvDuration = (TextView) view.findViewById(R.id.txtvDuration);
+ holder.cover = view.findViewById(R.id.imgvCover);
+ holder.txtvDuration = view.findViewById(R.id.txtvDuration);
holder.item = null;
holder.mainActivityRef = mainActivityRef;
- holder.position = -1;
// so we can grab this later
view.setTag(holder);
@@ -113,11 +106,10 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
final FeedItem item = itemAccess.getItem(position);
if (item == null) return;
holder.itemView.setOnLongClickListener(v -> {
- this.position = position;
+ this.selectedItem = item;
return false;
});
holder.item = item;
- holder.position = position;
holder.placeholder.setVisibility(View.VISIBLE);
holder.placeholder.setText(item.getFeed().getTitle());
holder.title.setText(item.getTitle());
@@ -129,9 +121,9 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.statusUnread.setVisibility(View.VISIBLE);
}
if(item.isPlayed()) {
- ViewHelper.setAlpha(holder.content, 0.5f);
+ holder.content.setAlpha(0.5f);
} else {
- ViewHelper.setAlpha(holder.content, 1.0f);
+ holder.content.setAlpha(1.0f);
}
FeedMedia media = item.getMedia();
@@ -174,7 +166,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.progress.setVisibility(View.VISIBLE);
}
} else {
- holder.progress.setVisibility(View.GONE);
+ holder.progress.setVisibility(View.INVISIBLE);
}
if(media.isCurrentlyPlaying()) {
@@ -183,7 +175,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.container.setBackgroundColor(normalBackGroundColor);
}
} else {
- holder.progress.setVisibility(View.GONE);
+ holder.progress.setVisibility(View.INVISIBLE);
holder.txtvDuration.setVisibility(View.GONE);
}
@@ -199,12 +191,17 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.butSecondary.setTag(item);
holder.butSecondary.setOnClickListener(secondaryActionListener);
- Glide.with(mainActivityRef.get())
- .load(item.getImageLocation())
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
- .into(new CoverTarget(item.getFeed().getImageLocation(), holder.placeholder, holder.cover, mainActivityRef.get()));
+ new CoverLoader(mainActivityRef.get())
+ .withUri(item.getImageLocation())
+ .withFallbackUri(item.getFeed().getImageLocation())
+ .withPlaceholderView(holder.placeholder)
+ .withCoverView(holder.cover)
+ .load();
+ }
+
+ @Nullable
+ public FeedItem getSelectedItem() {
+ return selectedItem;
}
@Override
@@ -218,17 +215,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
return itemAccess.getCount();
}
- public FeedItem getItem(int position) {
- return itemAccess.getItem(position);
- }
-
- public int getPosition() {
- int pos = position;
- position = -1; // reset
- return pos;
- }
-
- private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
+ private final View.OnClickListener secondaryActionListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
FeedItem item = (FeedItem) v.getTag();
@@ -253,7 +240,6 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
ImageButton butSecondary;
FeedItem item;
WeakReference<MainActivity> mainActivityRef;
- int position;
public Holder(View itemView) {
super(itemView);
@@ -266,18 +252,18 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
MainActivity mainActivity = mainActivityRef.get();
if (mainActivity != null) {
long[] ids = itemAccess.getItemsIds().toArray();
- mainActivity.loadChildFragment(ItemFragment.newInstance(ids, position));
+ mainActivity.loadChildFragment(ItemFragment.newInstance(ids, getAdapterPosition()));
}
}
@Override
public void onItemSelected() {
- ViewHelper.setAlpha(itemView, 0.5f);
+ itemView.setAlpha(0.5f);
}
@Override
public void onItemClear() {
- ViewHelper.setAlpha(itemView, 1.0f);
+ itemView.setAlpha(1.0f);
}
public FeedItem getFeedItem() { return item; }
@@ -303,6 +289,8 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
}
};
FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, null);
+
+ contextMenuInterface.setItemVisibility(R.id.mark_as_seen_item, item.isNew());
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
index d7bebb672..c3fac7e18 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.text.Layout;
import android.text.Selection;
@@ -8,7 +9,6 @@ import android.text.Spannable;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.text.util.Linkify;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -19,9 +19,9 @@ import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.ChapterUtils;
import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.ThemeUtils;
import de.danoeh.antennapod.core.util.playback.Playable;
public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
@@ -42,8 +42,9 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
this.media = media;
}
+ @NonNull
@Override
- public View getView(final int position, View convertView, ViewGroup parent) {
+ public View getView(final int position, View convertView, @NonNull ViewGroup parent) {
Holder holder;
Chapter sc = getItem(position);
@@ -56,12 +57,12 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
convertView = inflater.inflate(R.layout.simplechapter_item, parent, false);
holder.view = convertView;
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.title = convertView.findViewById(R.id.txtvTitle);
defaultTextColor = holder.title.getTextColors().getDefaultColor();
- holder.start = (TextView) convertView.findViewById(R.id.txtvStart);
- holder.link = (TextView) convertView.findViewById(R.id.txtvLink);
- holder.duration = (TextView) convertView.findViewById(R.id.txtvDuration);
- holder.butPlayChapter = (ImageButton) convertView.findViewById(R.id.butPlayChapter);
+ holder.start = convertView.findViewById(R.id.txtvStart);
+ holder.link = convertView.findViewById(R.id.txtvLink);
+ holder.duration = convertView.findViewById(R.id.txtvDuration);
+ holder.butPlayChapter = convertView.findViewById(R.id.butPlayChapter);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
@@ -120,7 +121,7 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
- } else if (action == MotionEvent.ACTION_DOWN){
+ } else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
@@ -139,23 +140,15 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
callback.onPlayChapterButtonClicked(position);
}
});
+
Chapter current = ChapterUtils.getCurrentChapter(media);
- if (current != null) {
- if (current == sc) {
- int playingBackGroundColor;
- if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
- playingBackGroundColor = ContextCompat.getColor(getContext(), R.color.highlight_dark);
- } else {
- playingBackGroundColor = ContextCompat.getColor(getContext(), R.color.highlight_light);
- }
- holder.view.setBackgroundColor(playingBackGroundColor);
- } else {
- holder.view.setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
- holder.title.setTextColor(defaultTextColor);
- holder.start.setTextColor(defaultTextColor);
- }
+ if (current == sc) {
+ int playingBackGroundColor = ThemeUtils.getColorFromAttr(getContext(), R.attr.currently_playing_background);
+ holder.view.setBackgroundColor(playingBackGroundColor);
} else {
- Log.w(TAG, "Could not find out what the current chapter is.");
+ holder.view.setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
+ holder.title.setTextColor(defaultTextColor);
+ holder.start.setTextColor(defaultTextColor);
}
return convertView;
@@ -172,7 +165,7 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
@Override
public int getCount() {
- if(media == null || media.getChapters() == null) {
+ if (media == null || media.getChapters() == null) {
return 0;
}
// ignore invalid chapters
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
new file mode 100644
index 000000000..54ecdae77
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
@@ -0,0 +1,113 @@
+package de.danoeh.antennapod.adapter;
+
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.RequestBuilder;
+import com.bumptech.glide.request.RequestOptions;
+import com.bumptech.glide.request.target.CustomViewTarget;
+
+import java.lang.ref.WeakReference;
+
+import com.bumptech.glide.request.transition.Transition;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
+
+public class CoverLoader {
+ private String uri;
+ private String fallbackUri;
+ private TextView txtvPlaceholder;
+ private ImageView imgvCover;
+ private MainActivity activity;
+ private int errorResource = -1;
+
+ public CoverLoader(MainActivity activity) {
+ this.activity = activity;
+ }
+
+ public CoverLoader withUri(String uri) {
+ this.uri = uri;
+ return this;
+ }
+
+ public CoverLoader withFallbackUri(String uri) {
+ fallbackUri = uri;
+ return this;
+ }
+
+ public CoverLoader withCoverView(ImageView coverView) {
+ imgvCover = coverView;
+ return this;
+ }
+
+ public CoverLoader withError(int errorResource) {
+ this.errorResource = errorResource;
+ return this;
+ }
+
+ public CoverLoader withPlaceholderView(TextView placeholderView) {
+ txtvPlaceholder = placeholderView;
+ return this;
+ }
+
+ public void load() {
+ RequestOptions options = new RequestOptions()
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate();
+
+ if (errorResource != -1) {
+ options = options.error(errorResource);
+ }
+
+ RequestBuilder builder = Glide.with(activity)
+ .load(uri)
+ .apply(options);
+
+ if (fallbackUri != null && txtvPlaceholder != null && imgvCover != null) {
+ builder = builder.error(Glide.with(activity)
+ .load(fallbackUri)
+ .apply(options));
+ }
+
+ builder.into(new CoverTarget(txtvPlaceholder, imgvCover));
+ }
+
+ class CoverTarget extends CustomViewTarget<ImageView, Drawable> {
+ private final WeakReference<TextView> placeholder;
+ private final WeakReference<ImageView> cover;
+
+ public CoverTarget(TextView txtvPlaceholder, ImageView imgvCover) {
+ super(imgvCover);
+ placeholder = new WeakReference<>(txtvPlaceholder);
+ cover = new WeakReference<>(imgvCover);
+ }
+
+ @Override
+ public void onLoadFailed(Drawable errorDrawable) {
+
+ }
+
+ @Override
+ public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
+ TextView txtvPlaceholder = placeholder.get();
+ if (txtvPlaceholder != null) {
+ txtvPlaceholder.setVisibility(View.INVISIBLE);
+ }
+ ImageView ivCover = cover.get();
+ ivCover.setImageDrawable(resource);
+ }
+
+ @Override
+ protected void onResourceCleared(@Nullable Drawable placeholder) {
+ ImageView ivCover = cover.get();
+ ivCover.setImageDrawable(placeholder);
+ }
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/CoverTarget.java b/app/src/main/java/de/danoeh/antennapod/adapter/CoverTarget.java
deleted file mode 100644
index 538af8c79..000000000
--- a/app/src/main/java/de/danoeh/antennapod/adapter/CoverTarget.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.resource.drawable.GlideDrawable;
-import com.bumptech.glide.request.animation.GlideAnimation;
-import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;
-
-import java.lang.ref.WeakReference;
-
-import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.glide.ApGlideSettings;
-
-class CoverTarget extends GlideDrawableImageViewTarget {
-
- private final WeakReference<String> fallback;
- private final WeakReference<TextView> placeholder;
- private final WeakReference<ImageView> cover;
- private final WeakReference<MainActivity> mainActivity;
-
- public CoverTarget(String fallbackUri, TextView txtvPlaceholder, ImageView imgvCover, MainActivity activity) {
- super(imgvCover);
- fallback = new WeakReference<>(fallbackUri);
- placeholder = new WeakReference<>(txtvPlaceholder);
- cover = new WeakReference<>(imgvCover);
- mainActivity = new WeakReference<>(activity);
- }
-
- @Override
- public void onLoadFailed(Exception e, Drawable errorDrawable) {
- String fallbackUri = fallback.get();
- TextView txtvPlaceholder = placeholder.get();
- ImageView imgvCover = cover.get();
- if (fallbackUri != null && txtvPlaceholder != null && imgvCover != null) {
- MainActivity activity = mainActivity.get();
- Glide.with(activity)
- .load(fallbackUri)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
- .into(new CoverTarget(null, txtvPlaceholder, imgvCover, activity));
- }
- }
-
- @Override
- public void onResourceReady(GlideDrawable drawable, GlideAnimation<? super GlideDrawable> anim) {
- super.onResourceReady(drawable, anim);
- TextView txtvPlaceholder = placeholder.get();
- if (txtvPlaceholder != null) {
- txtvPlaceholder.setVisibility(View.INVISIBLE);
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
index 4a53be9dc..1286d9dc7 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import android.support.annotation.NonNull;
import android.content.Intent;
import android.widget.Toast;
@@ -19,8 +20,10 @@ 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
@@ -80,13 +83,19 @@ public class DefaultActionButtonCallback implements ActionButtonCallback {
Toast.makeText(context, R.string.download_canceled_msg, Toast.LENGTH_LONG).show();
}
} else { // media is downloaded
- if (item.hasMedia() && item.getMedia().isCurrentlyPlaying()) {
- context.sendBroadcast(new Intent(PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
- }
- else if (item.hasMedia() && item.getMedia().isCurrentlyPaused()) {
- context.sendBroadcast(new Intent(PlaybackService.ACTION_RESUME_PLAY_CURRENT_EPISODE));
- }
- else {
+ 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);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
index e271b5eed..789c01a26 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -19,7 +19,6 @@ import com.joanzapata.iconify.widget.IconTextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedImage;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -29,11 +28,11 @@ import de.danoeh.antennapod.core.storage.DownloadRequestException;
/** Displays a list of DownloadStatus entries. */
public class DownloadLogAdapter extends BaseAdapter {
- private final String TAG = "DownloadLogAdapter";
+ private static final String TAG = "DownloadLogAdapter";
- private Context context;
+ private final Context context;
- private ItemAccess itemAccess;
+ private final ItemAccess itemAccess;
public DownloadLogAdapter(Context context, ItemAccess itemAccess) {
super();
@@ -50,15 +49,15 @@ public class DownloadLogAdapter extends BaseAdapter {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.downloadlog_item, parent, false);
- holder.icon = (IconTextView) convertView.findViewById(R.id.txtvIcon);
- holder.retry = (IconButton) convertView.findViewById(R.id.btnRetry);
- holder.date = (TextView) convertView.findViewById(R.id.txtvDate);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.icon = convertView.findViewById(R.id.txtvIcon);
+ holder.retry = convertView.findViewById(R.id.btnRetry);
+ holder.date = convertView.findViewById(R.id.txtvDate);
+ holder.title = convertView.findViewById(R.id.txtvTitle);
if(Build.VERSION.SDK_INT >= 23) {
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
}
- holder.type = (TextView) convertView.findViewById(R.id.txtvType);
- holder.reason = (TextView) convertView.findViewById(R.id.txtvReason);
+ holder.type = convertView.findViewById(R.id.txtvType);
+ holder.reason = convertView.findViewById(R.id.txtvReason);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
@@ -67,8 +66,6 @@ public class DownloadLogAdapter extends BaseAdapter {
holder.type.setText(R.string.download_type_feed);
} else if (status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
holder.type.setText(R.string.download_type_media);
- } else if (status.getFeedfileType() == FeedImage.FEEDFILETYPE_FEEDIMAGE) {
- holder.type.setText(R.string.download_type_image);
}
if (status.getTitle() != null) {
holder.title.setText(status.getTitle());
@@ -94,8 +91,7 @@ public class DownloadLogAdapter extends BaseAdapter {
}
holder.reason.setText(reasonText);
holder.reason.setVisibility(View.VISIBLE);
- if(status.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE &&
- !newerWasSuccessful(position, status.getFeedfileType(), status.getFeedfileId())) {
+ if(!newerWasSuccessful(position, status.getFeedfileType(), status.getFeedfileId())) {
holder.retry.setVisibility(View.VISIBLE);
holder.retry.setOnClickListener(clickListener);
ButtonHolder btnHolder;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
index 6907e467b..cd636af43 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
@@ -12,11 +12,12 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
-import com.nineoldandroids.view.ViewHelper;
+import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
+import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.DateUtils;
@@ -61,16 +62,16 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.downloaded_episodeslist_item,
parent, false);
- holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.imageView = convertView.findViewById(R.id.imgvImage);
+ holder.title = convertView.findViewById(R.id.txtvTitle);
if(Build.VERSION.SDK_INT >= 23) {
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
}
- holder.txtvSize = (TextView) convertView.findViewById(R.id.txtvSize);
- holder.queueStatus = (ImageView) convertView.findViewById(R.id.imgvInPlaylist);
- holder.pubDate = (TextView) convertView
+ holder.txtvSize = convertView.findViewById(R.id.txtvSize);
+ holder.queueStatus = convertView.findViewById(R.id.imgvInPlaylist);
+ holder.pubDate = convertView
.findViewById(R.id.txtvPublished);
- holder.butSecondary = (ImageButton) convertView
+ holder.butSecondary = convertView
.findViewById(R.id.butSecondaryAction);
convertView.setTag(holder);
} else {
@@ -79,17 +80,18 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
Glide.with(context)
.load(item.getImageLocation())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
.into(holder.imageView);
if(item.isPlayed()) {
- ViewHelper.setAlpha(convertView, 0.5f);
+ convertView.setAlpha(0.5f);
} else {
- ViewHelper.setAlpha(convertView, 1.0f);
+ convertView.setAlpha(1.0f);
}
holder.title.setText(item.getTitle());
@@ -99,10 +101,12 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
holder.pubDate.setText(pubDateStr);
FeedItem.State state = item.getState();
- if (state == FeedItem.State.PLAYING) {
+ if (state == FeedItem.State.PLAYING && PlaybackService.isRunning) {
holder.butSecondary.setEnabled(false);
+ holder.butSecondary.setAlpha(0.5f);
} else {
holder.butSecondary.setEnabled(true);
+ holder.butSecondary.setAlpha(1.0f);
}
holder.butSecondary.setFocusable(false);
holder.butSecondary.setTag(item);
@@ -111,7 +115,7 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
return convertView;
}
- private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
+ private final View.OnClickListener secondaryActionListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
FeedItem item = (FeedItem) v.getTag();
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java
index e1efdaa7b..b85d1d35d 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java
@@ -19,11 +19,11 @@ import de.danoeh.antennapod.core.util.ThemeUtils;
public class DownloadlistAdapter extends BaseAdapter {
- public static final int SELECTION_NONE = -1;
+ private static final int SELECTION_NONE = -1;
private int selectedItemIndex;
- private ItemAccess itemAccess;
- private Context context;
+ private final ItemAccess itemAccess;
+ private final Context context;
public DownloadlistAdapter(Context context,
ItemAccess itemAccess) {
@@ -59,14 +59,14 @@ public class DownloadlistAdapter extends BaseAdapter {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.downloadlist_item, parent, false);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
- holder.downloaded = (TextView) convertView
+ holder.title = convertView.findViewById(R.id.txtvTitle);
+ holder.downloaded = convertView
.findViewById(R.id.txtvDownloaded);
- holder.percent = (TextView) convertView
+ holder.percent = convertView
.findViewById(R.id.txtvPercent);
- holder.progbar = (ProgressBar) convertView
+ holder.progbar = convertView
.findViewById(R.id.progProgress);
- holder.butSecondary = (ImageButton) convertView
+ holder.butSecondary = convertView
.findViewById(R.id.butSecondaryAction);
convertView.setTag(holder);
@@ -105,7 +105,7 @@ public class DownloadlistAdapter extends BaseAdapter {
return convertView;
}
- private View.OnClickListener butSecondaryListener = new View.OnClickListener() {
+ private final View.OnClickListener butSecondaryListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Downloader downloader = (Downloader) v.getTag();
@@ -121,15 +121,6 @@ public class DownloadlistAdapter extends BaseAdapter {
ImageButton butSecondary;
}
- public int getSelectedItemIndex() {
- return selectedItemIndex;
- }
-
- public void setSelectedItemIndex(int selectedItemIndex) {
- this.selectedItemIndex = selectedItemIndex;
- notifyDataSetChanged();
- }
-
public interface ItemAccess {
int getCount();
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 35c42725c..738a0a636 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
@@ -17,13 +17,10 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.nineoldandroids.view.ViewHelper;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.DateUtils;
import de.danoeh.antennapod.core.util.LongList;
@@ -34,16 +31,16 @@ import de.danoeh.antennapod.core.util.ThemeUtils;
*/
public class FeedItemlistAdapter extends BaseAdapter {
- private ActionButtonCallback callback;
+ private final ActionButtonCallback callback;
private final ItemAccess itemAccess;
private final Context context;
- private boolean showFeedtitle;
- private int selectedItemIndex;
+ private final boolean showFeedtitle;
+ private final int selectedItemIndex;
/** true if played items should be made partially transparent */
- private boolean makePlayedItemsTransparent;
+ private final boolean makePlayedItemsTransparent;
private final ActionButtonUtils actionButtonUtils;
- public static final int SELECTION_NONE = -1;
+ private static final int SELECTION_NONE = -1;
private final int playingBackGroundColor;
private final int normalBackGroundColor;
@@ -62,11 +59,7 @@ public class FeedItemlistAdapter extends BaseAdapter {
this.actionButtonUtils = new ActionButtonUtils(context);
this.makePlayedItemsTransparent = makePlayedItemsTransparent;
- if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
- playingBackGroundColor = ContextCompat.getColor(context, R.color.highlight_dark);
- } else {
- playingBackGroundColor = ContextCompat.getColor(context, R.color.highlight_light);
- }
+ playingBackGroundColor = ThemeUtils.getColorFromAttr(context, R.attr.currently_playing_background);
normalBackGroundColor = ContextCompat.getColor(context, android.R.color.transparent);
}
@@ -97,24 +90,24 @@ public class FeedItemlistAdapter extends BaseAdapter {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.feeditemlist_item, parent, false);
- holder.container = (LinearLayout) convertView
+ holder.container = convertView
.findViewById(R.id.container);
- holder.title = (TextView) convertView.findViewById(R.id.txtvItemname);
+ holder.title = convertView.findViewById(R.id.txtvItemname);
if(Build.VERSION.SDK_INT >= 23) {
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
}
- holder.lenSize = (TextView) convertView
+ holder.lenSize = convertView
.findViewById(R.id.txtvLenSize);
- holder.butAction = (ImageButton) convertView
+ holder.butAction = convertView
.findViewById(R.id.butSecondaryAction);
- holder.published = (TextView) convertView
+ holder.published = convertView
.findViewById(R.id.txtvPublished);
- holder.inPlaylist = (ImageView) convertView
+ holder.inPlaylist = convertView
.findViewById(R.id.imgvInPlaylist);
- holder.type = (ImageView) convertView.findViewById(R.id.imgvType);
+ holder.type = convertView.findViewById(R.id.imgvType);
holder.statusUnread = convertView
.findViewById(R.id.statusUnread);
- holder.episodeProgress = (ProgressBar) convertView
+ holder.episodeProgress = convertView
.findViewById(R.id.pbar_episode_progress);
convertView.setTag(holder);
@@ -145,9 +138,9 @@ public class FeedItemlistAdapter extends BaseAdapter {
holder.statusUnread.setVisibility(View.INVISIBLE);
}
if(item.isPlayed() && makePlayedItemsTransparent) {
- ViewHelper.setAlpha(convertView, 0.5f);
+ convertView.setAlpha(0.5f);
} else {
- ViewHelper.setAlpha(convertView, 1.0f);
+ convertView.setAlpha(1.0f);
}
String pubDateStr = DateUtils.formatAbbrev(context, item.getPubDate());
@@ -157,7 +150,7 @@ public class FeedItemlistAdapter extends BaseAdapter {
FeedMedia media = item.getMedia();
if (media == null) {
- holder.episodeProgress.setVisibility(View.GONE);
+ holder.episodeProgress.setVisibility(View.INVISIBLE);
holder.inPlaylist.setVisibility(View.INVISIBLE);
holder.type.setVisibility(View.INVISIBLE);
holder.lenSize.setVisibility(View.INVISIBLE);
@@ -176,7 +169,7 @@ public class FeedItemlistAdapter extends BaseAdapter {
holder.episodeProgress.setProgress(itemAccess.getItemDownloadProgressPercent(item));
} else {
if(media.getPosition() == 0) {
- holder.episodeProgress.setVisibility(View.GONE);
+ holder.episodeProgress.setVisibility(View.INVISIBLE);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
index 5b205e91f..c10bb7638 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
@@ -34,9 +34,9 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> {
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.itemdescription_listitem, parent, false);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
- holder.pubDate = (TextView) convertView.findViewById(R.id.txtvPubDate);
- holder.description = (TextView) convertView.findViewById(R.id.txtvDescription);
+ holder.title = convertView.findViewById(R.id.txtvTitle);
+ holder.pubDate = convertView.findViewById(R.id.txtvPubDate);
+ holder.description = convertView.findViewById(R.id.txtvDescription);
convertView.setTag(holder);
} else {
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 465497b55..fbf6b804a 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -17,6 +17,7 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconTextView;
@@ -48,10 +49,10 @@ import de.danoeh.antennapod.fragment.SubscriptionFragment;
public class NavListAdapter extends BaseAdapter
implements SharedPreferences.OnSharedPreferenceChangeListener {
- public static final int VIEW_TYPE_COUNT = 3;
+ private static final int VIEW_TYPE_COUNT = 3;
public static final int VIEW_TYPE_NAV = 0;
public static final int VIEW_TYPE_SECTION_DIVIDER = 1;
- public static final int VIEW_TYPE_SUBSCRIPTION = 2;
+ private static final int VIEW_TYPE_SUBSCRIPTION = 2;
/**
* a tag used as a placeholder to indicate if the subscription list should be displayed or not
@@ -62,8 +63,8 @@ public class NavListAdapter extends BaseAdapter
private static List<String> tags;
private static String[] titles;
- private ItemAccess itemAccess;
- private WeakReference<Activity> activity;
+ private final ItemAccess itemAccess;
+ private final WeakReference<Activity> activity;
private boolean showSubscriptionList = true;
public NavListAdapter(ItemAccess itemAccess, Activity context) {
@@ -86,9 +87,7 @@ public class NavListAdapter extends BaseAdapter
private void loadItems() {
List<String> newTags = new ArrayList<>(Arrays.asList(MainActivity.NAV_DRAWER_TAGS));
List<String> hiddenFragments = UserPreferences.getHiddenDrawerItems();
- for(String hidden : hiddenFragments) {
- newTags.remove(hidden);
- }
+ newTags.removeAll(hiddenFragments);
if (newTags.contains(SUBSCRIPTION_LIST_TAG)) {
// we never want SUBSCRIPTION_LIST_TAG to be in 'tags'
@@ -214,7 +213,7 @@ public class NavListAdapter extends BaseAdapter
v = getFeedView(position, convertView, parent);
}
if (v != null && viewType != VIEW_TYPE_SECTION_DIVIDER) {
- TextView txtvTitle = (TextView) v.findViewById(R.id.txtvTitle);
+ TextView txtvTitle = v.findViewById(R.id.txtvTitle);
if (position == itemAccess.getSelectedItemIndex()) {
txtvTitle.setTypeface(null, Typeface.BOLD);
} else {
@@ -237,9 +236,9 @@ public class NavListAdapter extends BaseAdapter
convertView = inflater.inflate(R.layout.nav_listitem, parent, false);
- holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
- holder.count = (TextView) convertView.findViewById(R.id.txtvCount);
+ holder.image = convertView.findViewById(R.id.imgvCover);
+ holder.title = convertView.findViewById(R.id.txtvTitle);
+ holder.count = convertView.findViewById(R.id.txtvCount);
convertView.setTag(holder);
} else {
holder = (NavHolder) convertView.getTag();
@@ -327,10 +326,10 @@ public class NavListAdapter extends BaseAdapter
convertView = inflater.inflate(R.layout.nav_feedlistitem, parent, false);
- holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
- holder.failure = (IconTextView) convertView.findViewById(R.id.itxtvFailure);
- holder.count = (TextView) convertView.findViewById(R.id.txtvCount);
+ holder.image = convertView.findViewById(R.id.imgvCover);
+ holder.title = convertView.findViewById(R.id.txtvTitle);
+ holder.failure = convertView.findViewById(R.id.itxtvFailure);
+ holder.count = convertView.findViewById(R.id.txtvCount);
convertView.setTag(holder);
} else {
holder = (FeedHolder) convertView.getTag();
@@ -338,11 +337,12 @@ public class NavListAdapter extends BaseAdapter
Glide.with(context)
.load(feed.getImageLocation())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
.into(holder.image);
holder.title.setText(feed.getTitle());
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 c6ddc6c86..df8cafb9d 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
@@ -23,8 +23,8 @@ 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 com.nineoldandroids.view.ViewHelper;
import org.apache.commons.lang3.ArrayUtils;
@@ -41,6 +41,7 @@ import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.DateUtils;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.NetworkUtils;
+import de.danoeh.antennapod.core.util.ThemeUtils;
import de.danoeh.antennapod.fragment.ItemFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
@@ -51,7 +52,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
private static final String TAG = QueueRecyclerAdapter.class.getSimpleName();
- private WeakReference<MainActivity> mainActivity;
+ private final WeakReference<MainActivity> mainActivity;
private final ItemAccess itemAccess;
private final ActionButtonCallback actionButtonCallback;
private final ActionButtonUtils actionButtonUtils;
@@ -76,11 +77,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
this.itemTouchHelper = itemTouchHelper;
locked = UserPreferences.isQueueLocked();
- if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
- playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_dark);
- } else {
- playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_light);
- }
+ playingBackGroundColor = ThemeUtils.getColorFromAttr(mainActivity, R.attr.currently_playing_background);
normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent);
}
@@ -138,19 +135,19 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
public ViewHolder(View v) {
super(v);
- container = (FrameLayout) v.findViewById(R.id.container);
- dragHandle = (ImageView) v.findViewById(R.id.drag_handle);
- placeholder = (TextView) v.findViewById(R.id.txtvPlaceholder);
- cover = (ImageView) v.findViewById(R.id.imgvCover);
- title = (TextView) v.findViewById(R.id.txtvTitle);
+ container = v.findViewById(R.id.container);
+ dragHandle = v.findViewById(R.id.drag_handle);
+ placeholder = v.findViewById(R.id.txtvPlaceholder);
+ cover = v.findViewById(R.id.imgvCover);
+ title = v.findViewById(R.id.txtvTitle);
if(Build.VERSION.SDK_INT >= 23) {
title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
}
- pubDate = (TextView) v.findViewById(R.id.txtvPubDate);
- progressLeft = (TextView) v.findViewById(R.id.txtvProgressLeft);
- progressRight = (TextView) v.findViewById(R.id.txtvProgressRight);
- butSecondary = (ImageButton) v.findViewById(R.id.butSecondaryAction);
- progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
+ pubDate = v.findViewById(R.id.txtvPubDate);
+ progressLeft = v.findViewById(R.id.txtvProgressLeft);
+ progressRight = v.findViewById(R.id.txtvProgressRight);
+ butSecondary = v.findViewById(R.id.butSecondaryAction);
+ progressBar = v.findViewById(R.id.progressBar);
v.setTag(this);
v.setOnClickListener(this);
v.setOnCreateContextMenuListener(this);
@@ -198,12 +195,12 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
@Override
public void onItemSelected() {
- ViewHelper.setAlpha(itemView, 0.5f);
+ itemView.setAlpha(0.5f);
}
@Override
public void onItemClear() {
- ViewHelper.setAlpha(itemView, 1.0f);
+ itemView.setAlpha(1.0f);
}
public void bind(FeedItem item) {
@@ -280,7 +277,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
progressLeft.setText("");
}
progressRight.setText(Converter.getDurationStringLong(media.getDuration()));
- progressBar.setVisibility(View.GONE);
+ progressBar.setVisibility(View.INVISIBLE);
}
if(media.isCurrentlyPlaying()) {
@@ -295,17 +292,17 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
butSecondary.setTag(item);
butSecondary.setOnClickListener(secondaryActionListener);
- Glide.with(mainActivity.get())
- .load(item.getImageLocation())
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
- .into(new CoverTarget(item.getFeed().getImageLocation(), placeholder, cover, mainActivity.get()));
+ new CoverLoader(mainActivity.get())
+ .withUri(item.getImageLocation())
+ .withFallbackUri(item.getFeed().getImageLocation())
+ .withPlaceholderView(placeholder)
+ .withCoverView(cover)
+ .load();
}
}
- private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
+ private final View.OnClickListener secondaryActionListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
FeedItem item = (FeedItem) v.getTag();
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java
index 8e1aa24e0..45cb4af87 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java
@@ -11,8 +11,8 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
-import com.nineoldandroids.view.ViewHelper;
+import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedComponent;
@@ -62,13 +62,13 @@ public class SearchlistAdapter extends BaseAdapter {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.searchlist_item, parent, false);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.title = convertView.findViewById(R.id.txtvTitle);
if(Build.VERSION.SDK_INT >= 23) {
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
}
- holder.cover = (ImageView) convertView
+ holder.cover = convertView
.findViewById(R.id.imgvFeedimage);
- holder.subtitle = (TextView) convertView
+ holder.subtitle = convertView
.findViewById(R.id.txtvSubtitle);
convertView.setTag(holder);
@@ -82,11 +82,12 @@ public class SearchlistAdapter extends BaseAdapter {
Glide.with(context)
.load(feed.getImageLocation())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
.into(holder.cover);
} else if (component.getClass() == FeedItem.class) {
@@ -97,15 +98,16 @@ public class SearchlistAdapter extends BaseAdapter {
holder.subtitle.setText(result.getSubtitle());
}
- ViewHelper.setAlpha(convertView, item.isPlayed() ? 0.5f : 1.0f);
+ convertView.setAlpha(item.isPlayed() ? 0.5f : 1.0f);
Glide.with(context)
.load(item.getFeed().getImageLocation())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
.into(holder.cover);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
index c060083a6..31e82dbe0 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
@@ -13,6 +13,7 @@ import com.bumptech.glide.Glide;
import java.util.ArrayList;
import java.util.List;
+import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
@@ -23,8 +24,8 @@ import de.danoeh.antennapod.core.util.Converter;
* Adapter for the statistics list
*/
public class StatisticsListAdapter extends BaseAdapter {
- private Context context;
- List<DBReader.StatisticsItem> feedTime = new ArrayList<>();
+ private final Context context;
+ private List<DBReader.StatisticsItem> feedTime = new ArrayList<>();
private boolean countAll = true;
public StatisticsListAdapter(Context context) {
@@ -62,9 +63,9 @@ public class StatisticsListAdapter extends BaseAdapter {
convertView = inflater.inflate(R.layout.statistics_listitem, parent, false);
- holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
- holder.time = (TextView) convertView.findViewById(R.id.txtvTime);
+ holder.image = convertView.findViewById(R.id.imgvCover);
+ holder.title = convertView.findViewById(R.id.txtvTitle);
+ holder.time = convertView.findViewById(R.id.txtvTime);
convertView.setTag(holder);
} else {
holder = (StatisticsHolder) convertView.getTag();
@@ -72,11 +73,12 @@ public class StatisticsListAdapter extends BaseAdapter {
Glide.with(context)
.load(feed.getImageLocation())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
.into(holder.image);
holder.title.setText(feed.getTitle());
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java
index 6d19bfa6c..763dcb57d 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java
@@ -14,6 +14,7 @@ import com.bumptech.glide.Glide;
import java.lang.ref.WeakReference;
+import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.Feed;
@@ -50,7 +51,6 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
}
private int getAdjustedPosition(int origPosition) {
- assert(origPosition != getAddTilePosition());
return origPosition < getAddTilePosition() ? origPosition : origPosition - 1;
}
@@ -90,9 +90,9 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
LayoutInflater layoutInflater =
(LayoutInflater) mainActivityRef.get().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.subscription_item, parent, false);
- holder.feedTitle = (TextView) convertView.findViewById(R.id.txtvTitle);
- holder.imageView = (ImageView) convertView.findViewById(R.id.imgvCover);
- holder.count = (TriangleLabelView) convertView.findViewById(R.id.triangleCountView);
+ holder.feedTitle = convertView.findViewById(R.id.txtvTitle);
+ holder.imageView = convertView.findViewById(R.id.imgvCover);
+ holder.count = convertView.findViewById(R.id.triangleCountView);
convertView.setTag(holder);
@@ -109,7 +109,7 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
holder.count.setVisibility(View.INVISIBLE);
// when this holder is reused, we could else end up with a cover image
- Glide.clear(holder.imageView);
+ Glide.with(mainActivityRef.get()).clear(holder.imageView);
return convertView;
}
@@ -126,13 +126,13 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
} else {
holder.count.setVisibility(View.GONE);
}
- Glide.with(mainActivityRef.get())
- .load(feed.getImageLocation())
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
- .into(new CoverTarget(null, holder.feedTitle, holder.imageView, mainActivityRef.get()));
+
+ new CoverLoader(mainActivityRef.get())
+ .withUri(feed.getImageLocation())
+ .withPlaceholderView(holder.feedTitle)
+ .withCoverView(holder.imageView)
+ .withError(R.color.light_gray)
+ .load();
return convertView;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java
index aea3d583f..06c80e173 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java
@@ -10,6 +10,7 @@ import android.widget.TextView;
import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
@@ -40,10 +41,10 @@ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.gpodnet_podcast_listitem, parent, false);
- holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
- holder.subscribers = (TextView) convertView.findViewById(R.id.txtvSubscribers);
- holder.url = (TextView) convertView.findViewById(R.id.txtvUrl);
+ holder.image = convertView.findViewById(R.id.imgvCover);
+ holder.title = convertView.findViewById(R.id.txtvTitle);
+ holder.subscribers = convertView.findViewById(R.id.txtvSubscribers);
+ holder.url = convertView.findViewById(R.id.txtvUrl);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
@@ -52,11 +53,12 @@ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> {
if (StringUtils.isNotBlank(podcast.getLogoUrl())) {
Glide.with(convertView.getContext())
.load(podcast.getLogoUrl())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
.into(holder.image);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java
index b4eadefb5..52fca792e 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java
@@ -34,8 +34,8 @@ public class TagListAdapter extends ArrayAdapter<GpodnetTag> {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.gpodnet_tag_listitem, parent, false);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
- holder.usage = (TextView) convertView.findViewById(R.id.txtvUsage);
+ holder.title = convertView.findViewById(R.id.txtvTitle);
+ holder.usage = convertView.findViewById(R.id.txtvUsage);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
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 f1f8be559..2cf17c85f 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
@@ -12,6 +12,8 @@ import android.widget.TextView;
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;
@@ -80,10 +82,11 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
//Update the empty imageView with the image from the feed
Glide.with(context)
.load(podcast.imageUrl)
- .placeholder(R.color.light_gray)
- .diskCacheStrategy(DiskCacheStrategy.NONE)
- .fitCenter()
- .dontAnimate()
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .diskCacheStrategy(DiskCacheStrategy.NONE)
+ .fitCenter()
+ .dontAnimate())
.into(viewHolder.coverView);
//Feed the grid view
@@ -124,7 +127,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
* @param json object holding the podcast information
* @throws JSONException
*/
- public static Podcast fromSearch(JSONObject json) 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);
@@ -132,7 +135,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
}
public static Podcast fromSearch(SearchHit searchHit) {
- return new Podcast(searchHit.getTitle(), searchHit.getImageUrl(), searchHit.getXmlUrl());
+ return new Podcast(searchHit.getTitle(), searchHit.getThumbImageURL(), searchHit.getXmlUrl());
}
/**
@@ -162,7 +165,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
/**
* View holder object for the GridView
*/
- class PodcastViewHolder {
+ static class PodcastViewHolder {
/**
* ImageView holding the Podcast image
@@ -182,9 +185,9 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
* @param view GridView cell
*/
PodcastViewHolder(View view){
- coverView = (ImageView) view.findViewById(R.id.imgvCover);
- titleView = (TextView) view.findViewById(R.id.txtvTitle);
- urlView = (TextView) view.findViewById(R.id.txtvUrl);
+ coverView = view.findViewById(R.id.imgvCover);
+ titleView = view.findViewById(R.id.txtvTitle);
+ urlView = view.findViewById(R.id.txtvUrl);
}
}
}
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 192df8ca5..7c3c570a0 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
@@ -12,7 +12,7 @@ import de.danoeh.antennapod.core.export.ExportWriter;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.LangUtils;
-import rx.Observable;
+import io.reactivex.Observable;
/**
* Writes an OPML file into the export directory in the background.
@@ -23,15 +23,15 @@ public class ExportWorker {
private static final String TAG = "ExportWorker";
private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds";
- private ExportWriter exportWriter;
- private File output;
+ private final ExportWriter exportWriter;
+ private final File output;
public ExportWorker(ExportWriter exportWriter) {
this(exportWriter, new File(UserPreferences.getDataFolder(EXPORT_DIR),
DEFAULT_OUTPUT_NAME + "." + exportWriter.fileExtension()));
}
- public ExportWorker(ExportWriter exportWriter, @NonNull File output) {
+ private ExportWorker(ExportWriter exportWriter, @NonNull File output) {
this.exportWriter = exportWriter;
this.output = output;
}
@@ -57,7 +57,7 @@ public class ExportWorker {
subscriber.onError(e);
}
}
- subscriber.onCompleted();
+ subscriber.onComplete();
}
});
}
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
index 4449d82c2..ea5128102 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.asynctask;
-import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
@@ -16,9 +15,9 @@ import de.danoeh.antennapod.core.storage.DownloadRequester;
/** Queues items for download in the background. */
public class OpmlFeedQueuer extends AsyncTask<Void, Void, Void> {
- private Context context;
+ private final Context context;
private ProgressDialog progDialog;
- private int[] selection;
+ private final int[] selection;
public OpmlFeedQueuer(Context context, int[] selection) {
super();
@@ -56,13 +55,8 @@ public class OpmlFeedQueuer extends AsyncTask<Void, Void, Void> {
return null;
}
- @SuppressLint("NewApi")
public void executeAsync() {
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- executeOnExecutor(THREAD_POOL_EXECUTOR);
- } else {
- execute();
- }
+ executeOnExecutor(THREAD_POOL_EXECUTOR);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
index 62ea85811..13b95907f 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.asynctask;
-import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
@@ -21,12 +20,12 @@ public class OpmlImportWorker extends
AsyncTask<Void, Void, ArrayList<OpmlElement>> {
private static final String TAG = "OpmlImportWorker";
- private Context context;
+ private final Context context;
private Exception exception;
private ProgressDialog progDialog;
- private Reader mReader;
+ private final Reader mReader;
public OpmlImportWorker(Context context, Reader reader) {
super();
@@ -93,13 +92,8 @@ public class OpmlImportWorker extends
return exception != null;
}
- @SuppressLint("NewApi")
public void executeAsync() {
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- executeOnExecutor(THREAD_POOL_EXECUTOR);
- } else {
- execute();
- }
+ executeOnExecutor(THREAD_POOL_EXECUTOR);
}
}
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 f26f2ea76..4138738f6 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
@@ -6,7 +6,9 @@ import de.danoeh.antennapod.core.ClientConfig;
/**
* Configures the ClientConfig class of the core package.
*/
-public class ClientConfigurator {
+class ClientConfigurator {
+
+ private ClientConfigurator(){}
static {
ClientConfig.USER_AGENT = "AntennaPod/" + BuildConfig.VERSION_NAME;
diff --git a/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
index 1ab60ef61..eb70d8e0b 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.config;
import android.content.Context;
import android.content.Intent;
-
+import android.os.Build;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.AudioplayerActivity;
import de.danoeh.antennapod.activity.CastplayerActivity;
@@ -18,7 +18,11 @@ public class PlaybackServiceCallbacksImpl implements PlaybackServiceCallbacks {
return new Intent(context, CastplayerActivity.class);
}
if (mediaType == MediaType.VIDEO) {
- return new Intent(context, VideoplayerActivity.class);
+ Intent i = new Intent(context, VideoplayerActivity.class);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ }
+ return i;
} else {
return new Intent(context, AudioplayerActivity.class);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/AuthenticationDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/AuthenticationDialog.java
index 6f9e221ec..2c41b8cb8 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/AuthenticationDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/AuthenticationDialog.java
@@ -35,11 +35,11 @@ public abstract class AuthenticationDialog extends Dialog {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.authentication_dialog);
- final EditText etxtUsername = (EditText) findViewById(R.id.etxtUsername);
- final EditText etxtPassword = (EditText) findViewById(R.id.etxtPassword);
- final CheckBox saveUsernamePassword = (CheckBox) findViewById(R.id.chkSaveUsernamePassword);
- final Button butConfirm = (Button) findViewById(R.id.butConfirm);
- final Button butCancel = (Button) findViewById(R.id.butCancel);
+ final EditText etxtUsername = findViewById(R.id.etxtUsername);
+ final EditText etxtPassword = findViewById(R.id.etxtPassword);
+ final CheckBox saveUsernamePassword = findViewById(R.id.chkSaveUsernamePassword);
+ final Button butConfirm = findViewById(R.id.butConfirm);
+ final Button butCancel = findViewById(R.id.butCancel);
if (titleRes != 0) {
setTitle(titleRes);
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java
index 93425949c..c28342374 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java
@@ -29,9 +29,9 @@ public class AutoFlattrPreferenceDialog {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
@SuppressLint("InflateParams") View view = activity.getLayoutInflater().inflate(R.layout.autoflattr_preference_dialog, null);
- final CheckBox chkAutoFlattr = (CheckBox) view.findViewById(R.id.chkAutoFlattr);
- final SeekBar skbPercent = (SeekBar) view.findViewById(R.id.skbPercent);
- final TextView txtvStatus = (TextView) view.findViewById(R.id.txtvStatus);
+ 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());
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 ac073141d..07a64cde8 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.dialog;
+import android.app.AlertDialog;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -32,14 +33,14 @@ import de.danoeh.antennapod.core.util.LongList;
public class EpisodesApplyActionFragment extends Fragment {
- public String TAG = "EpisodeActionFragment";
+ public static final String TAG = "EpisodeActionFragment";
public static final int ACTION_QUEUE = 1;
- public static final int ACTION_MARK_PLAYED = 2;
- public static final int ACTION_MARK_UNPLAYED = 4;
- public static final int ACTION_DOWNLOAD = 8;
+ 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;
- public static final int ACTION_ALL = ACTION_QUEUE | ACTION_MARK_PLAYED | ACTION_MARK_UNPLAYED
+ private static final int ACTION_ALL = ACTION_QUEUE | ACTION_MARK_PLAYED | ACTION_MARK_UNPLAYED
| ACTION_DOWNLOAD | ACTION_REMOVE;
private ListView mListView;
@@ -84,7 +85,7 @@ public class EpisodesApplyActionFragment extends Fragment {
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.episodes_apply_action_fragment, container, false);
- mListView = (ListView) view.findViewById(android.R.id.list);
+ mListView = view.findViewById(android.R.id.list);
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
mListView.setOnItemClickListener((ListView, view1, position, rowId) -> {
long id = episodes.get(position).getId();
@@ -95,6 +96,28 @@ public class EpisodesApplyActionFragment extends Fragment {
}
refreshCheckboxes();
});
+ mListView.setOnItemLongClickListener((adapterView, view12, position, id) -> {
+ new AlertDialog.Builder(getActivity())
+ .setItems(R.array.batch_long_press_options, (dialogInterface, item) -> {
+ int direction;
+ if (item == 0) {
+ direction = -1;
+ } else {
+ direction = 1;
+ }
+
+ int currentPosition = position + direction;
+ while (currentPosition >= 0 && currentPosition < episodes.size()) {
+ long id1 = episodes.get(currentPosition).getId();
+ if (!checkedIds.contains(id1)) {
+ checkedIds.add(id1);
+ }
+ currentPosition += direction;
+ }
+ refreshCheckboxes();
+ }).show();
+ return true;
+ });
for(FeedItem episode : episodes) {
titles.add(episode.getTitle());
@@ -106,7 +129,7 @@ public class EpisodesApplyActionFragment extends Fragment {
checkAll();
int lastVisibleDiv = 0;
- btnAddToQueue = (Button) view.findViewById(R.id.btnAddToQueue);
+ btnAddToQueue = view.findViewById(R.id.btnAddToQueue);
if((actions & ACTION_QUEUE) != 0) {
btnAddToQueue.setOnClickListener(v -> queueChecked());
lastVisibleDiv = R.id.divider1;
@@ -114,7 +137,7 @@ public class EpisodesApplyActionFragment extends Fragment {
btnAddToQueue.setVisibility(View.GONE);
view.findViewById(R.id.divider1).setVisibility(View.GONE);
}
- btnMarkAsPlayed = (Button) view.findViewById(R.id.btnMarkAsPlayed);
+ btnMarkAsPlayed = view.findViewById(R.id.btnMarkAsPlayed);
if((actions & ACTION_MARK_PLAYED) != 0) {
btnMarkAsPlayed.setOnClickListener(v -> markedCheckedPlayed());
lastVisibleDiv = R.id.divider2;
@@ -122,7 +145,7 @@ public class EpisodesApplyActionFragment extends Fragment {
btnMarkAsPlayed.setVisibility(View.GONE);
view.findViewById(R.id.divider2).setVisibility(View.GONE);
}
- btnMarkAsUnplayed = (Button) view.findViewById(R.id.btnMarkAsUnplayed);
+ btnMarkAsUnplayed = view.findViewById(R.id.btnMarkAsUnplayed);
if((actions & ACTION_MARK_UNPLAYED) != 0) {
btnMarkAsUnplayed.setOnClickListener(v -> markedCheckedUnplayed());
lastVisibleDiv = R.id.divider3;
@@ -130,7 +153,7 @@ public class EpisodesApplyActionFragment extends Fragment {
btnMarkAsUnplayed.setVisibility(View.GONE);
view.findViewById(R.id.divider3).setVisibility(View.GONE);
}
- btnDownload = (Button) view.findViewById(R.id.btnDownload);
+ btnDownload = view.findViewById(R.id.btnDownload);
if((actions & ACTION_DOWNLOAD) != 0) {
btnDownload.setOnClickListener(v -> downloadChecked());
lastVisibleDiv = R.id.divider4;
@@ -138,7 +161,7 @@ public class EpisodesApplyActionFragment extends Fragment {
btnDownload.setVisibility(View.GONE);
view.findViewById(R.id.divider4).setVisibility(View.GONE);
}
- btnDelete = (Button) view.findViewById(R.id.btnDelete);
+ btnDelete = view.findViewById(R.id.btnDelete);
if((actions & ACTION_REMOVE) != 0) {
btnDelete.setOnClickListener(v -> deleteChecked());
} else {
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
index db6b48735..933ced0f9 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
@@ -8,6 +8,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
@@ -16,6 +17,9 @@ import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
* Creates a dialog that lets the user change the hostname for the gpodder.net service.
*/
public class GpodnetSetHostnameDialog {
+
+ private GpodnetSetHostnameDialog(){}
+
private static final String TAG = "GpodnetSetHostnameDialog";
public static AlertDialog createDialog(final Context context) {
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 0bd75b5b0..8f2629b43 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
@@ -29,21 +29,21 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.core.service.download.ProxyConfig;
+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 okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
-import rx.Observable;
-import rx.Subscriber;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
public class ProxyDialog {
private static final String TAG = "ProxyDialog";
- private Context context;
+ private final Context context;
private MaterialDialog dialog;
@@ -55,7 +55,7 @@ public class ProxyDialog {
private boolean testSuccessful = false;
private TextView txtvMessage;
- private Subscription subscription;
+ private Disposable disposable;
public ProxyDialog(Context context) {
this.context = context;
@@ -102,7 +102,7 @@ public class ProxyDialog {
.autoDismiss(false)
.build();
View view = dialog.getCustomView();
- spType = (Spinner) view.findViewById(R.id.spType);
+ spType = view.findViewById(R.id.spType);
String[] types = { Proxy.Type.DIRECT.name(), Proxy.Type.HTTP.name() };
ArrayAdapter<String> adapter = new ArrayAdapter<>(context,
android.R.layout.simple_spinner_item, types);
@@ -110,22 +110,22 @@ public class ProxyDialog {
spType.setAdapter(adapter);
ProxyConfig proxyConfig = UserPreferences.getProxyConfig();
spType.setSelection(adapter.getPosition(proxyConfig.type.name()));
- etHost = (EditText) view.findViewById(R.id.etHost);
+ etHost = view.findViewById(R.id.etHost);
if(!TextUtils.isEmpty(proxyConfig.host)) {
etHost.setText(proxyConfig.host);
}
etHost.addTextChangedListener(requireTestOnChange);
- etPort = (EditText) view.findViewById(R.id.etPort);
+ etPort = view.findViewById(R.id.etPort);
if(proxyConfig.port > 0) {
etPort.setText(String.valueOf(proxyConfig.port));
}
etPort.addTextChangedListener(requireTestOnChange);
- etUsername = (EditText) view.findViewById(R.id.etUsername);
+ etUsername = view.findViewById(R.id.etUsername);
if(!TextUtils.isEmpty(proxyConfig.username)) {
etUsername.setText(proxyConfig.username);
}
etUsername.addTextChangedListener(requireTestOnChange);
- etPassword = (EditText) view.findViewById(R.id.etPassword);
+ etPassword = view.findViewById(R.id.etPassword);
if(!TextUtils.isEmpty(proxyConfig.password)) {
etPassword.setText(proxyConfig.username);
}
@@ -146,7 +146,7 @@ public class ProxyDialog {
enableSettings(false);
}
});
- txtvMessage = (TextView) view.findViewById(R.id.txtvMessage);
+ txtvMessage = view.findViewById(R.id.txtvMessage);
checkValidity();
return dialog;
}
@@ -229,8 +229,8 @@ public class ProxyDialog {
}
private void test() {
- if(subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
if(!checkValidity()) {
setTestRequired(true);
@@ -243,48 +243,44 @@ public class ProxyDialog {
txtvMessage.setTextColor(textColorPrimary);
txtvMessage.setText("{fa-circle-o-notch spin} " + checking);
txtvMessage.setVisibility(View.VISIBLE);
- subscription = Observable.create(new Observable.OnSubscribe<Response>() {
- @Override
- public void call(Subscriber<? super Response> subscriber) {
- String type = (String) spType.getSelectedItem();
- String host = etHost.getText().toString();
- String port = etPort.getText().toString();
- String username = etUsername.getText().toString();
- String password = etPassword.getText().toString();
- int portValue = 8080;
- if(!TextUtils.isEmpty(port)) {
- portValue = Integer.valueOf(port);
- }
- SocketAddress address = InetSocketAddress.createUnresolved(host, portValue);
- Proxy.Type proxyType = Proxy.Type.valueOf(type.toUpperCase());
- Proxy proxy = new Proxy(proxyType, address);
- OkHttpClient.Builder builder = AntennapodHttpClient.newBuilder()
- .connectTimeout(10, TimeUnit.SECONDS)
- .proxy(proxy);
- builder.interceptors().clear();
- OkHttpClient client = builder.build();
- if(!TextUtils.isEmpty(username)) {
- String credentials = Credentials.basic(username, password);
- client.interceptors().add(chain -> {
- Request request = chain.request().newBuilder()
- .header("Proxy-Authorization", credentials).build();
- return chain.proceed(request);
- });
- }
- Request request = new Request.Builder()
- .url("http://www.google.com")
- .head()
- .build();
- try {
- Response response = client.newCall(request).execute();
- subscriber.onNext(response);
- } catch(IOException e) {
- subscriber.onError(e);
- }
- subscriber.onCompleted();
- }
- })
- .subscribeOn(Schedulers.newThread())
+ disposable = Single.create((SingleOnSubscribe<Response>) emitter -> {
+ String type = (String) spType.getSelectedItem();
+ String host = etHost.getText().toString();
+ String port = etPort.getText().toString();
+ String username = etUsername.getText().toString();
+ String password = etPassword.getText().toString();
+ int portValue = 8080;
+ if(!TextUtils.isEmpty(port)) {
+ portValue = Integer.valueOf(port);
+ }
+ SocketAddress address = InetSocketAddress.createUnresolved(host, portValue);
+ Proxy.Type proxyType = Proxy.Type.valueOf(type.toUpperCase());
+ Proxy proxy = new Proxy(proxyType, address);
+ OkHttpClient.Builder builder = AntennapodHttpClient.newBuilder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .proxy(proxy);
+ builder.interceptors().clear();
+ OkHttpClient client = builder.build();
+ if(!TextUtils.isEmpty(username)) {
+ String credentials = Credentials.basic(username, password);
+ client.interceptors().add(chain -> {
+ Request request = chain.request().newBuilder()
+ .header("Proxy-Authorization", credentials).build();
+ return chain.proceed(request);
+ });
+ }
+ Request request = new Request.Builder()
+ .url("http://www.google.com")
+ .head()
+ .build();
+ try {
+ Response response = client.newCall(request).execute();
+ emitter.onSuccess(response);
+ } catch(IOException e) {
+ emitter.onError(e);
+ }
+ })
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
response -> {
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 64fc1fda4..ece184035 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
@@ -17,6 +17,8 @@ import de.danoeh.antennapod.R;
public class RatingDialog {
+ private RatingDialog(){}
+
private static final String TAG = RatingDialog.class.getSimpleName();
private static final int AFTER_DAYS = 7;
@@ -54,7 +56,7 @@ public class RatingDialog {
}
}
- public static void rateNow() {
+ private static void rateNow() {
Context context = mContext.get();
if(context == null) {
return;
@@ -67,11 +69,11 @@ public class RatingDialog {
saveRated();
}
- public static boolean rated() {
+ private static boolean rated() {
return mPreferences.getBoolean(KEY_RATED, false);
}
- public static void saveRated() {
+ private 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 7d6a66a54..4b8601ec6 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
@@ -1,7 +1,6 @@
package de.danoeh.antennapod.dialog;
import android.content.Context;
-import android.support.design.widget.Snackbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
@@ -9,7 +8,6 @@ import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
-import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
@@ -26,7 +24,7 @@ public abstract class SleepTimerDialog {
private static final String TAG = SleepTimerDialog.class.getSimpleName();
- private Context context;
+ private final Context context;
private MaterialDialog dialog;
private EditText etxtTime;
@@ -63,11 +61,11 @@ public abstract class SleepTimerDialog {
dialog = builder.build();
View view = dialog.getView();
- etxtTime = (EditText) view.findViewById(R.id.etxtTime);
- spTimeUnit = (Spinner) view.findViewById(R.id.spTimeUnit);
- cbShakeToReset = (CheckBox) view.findViewById(R.id.cbShakeToReset);
- cbVibrate = (CheckBox) view.findViewById(R.id.cbVibrate);
- chAutoEnable = (CheckBox) view.findViewById(R.id.chAutoEnable);
+ etxtTime = view.findViewById(R.id.etxtTime);
+ spTimeUnit = view.findViewById(R.id.spTimeUnit);
+ cbShakeToReset = view.findViewById(R.id.cbShakeToReset);
+ cbVibrate = view.findViewById(R.id.cbVibrate);
+ chAutoEnable = view.findViewById(R.id.chAutoEnable);
etxtTime.setText(SleepTimerPreferences.lastTimerValue());
etxtTime.addTextChangedListener(new TextWatcher() {
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
index 6a975fe49..cf9a2907b 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
@@ -52,7 +52,7 @@ public class VariableSpeedDialog {
builder.neutralText(R.string.close_label);
builder.onPositive((dialog, which) -> {
if (Build.VERSION.SDK_INT >= 16) { // just to be safe
- UserPreferences.enableSonic(true);
+ UserPreferences.enableSonic();
if(showSpeedSelector) {
showSpeedSelectorDialog(context);
}
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 f14ebbdaf..ee2373da8 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -25,25 +25,25 @@ public class AddFeedFragment extends Fragment {
/**
* Preset value for url text field.
*/
- public static final String ARG_FEED_URL = "feedurl";
+ private static final String ARG_FEED_URL = "feedurl";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.addfeed, container, false);
- final EditText etxtFeedurl = (EditText) root.findViewById(R.id.etxtFeedurl);
+ final EditText etxtFeedurl = root.findViewById(R.id.etxtFeedurl);
Bundle args = getArguments();
if (args != null && args.getString(ARG_FEED_URL) != null) {
etxtFeedurl.setText(args.getString(ARG_FEED_URL));
}
- Button butSearchITunes = (Button) root.findViewById(R.id.butSearchItunes);
- Button butBrowserGpoddernet = (Button) root.findViewById(R.id.butBrowseGpoddernet);
- Button butSearchFyyd = (Button) root.findViewById(R.id.butSearchFyyd);
- Button butOpmlImport = (Button) root.findViewById(R.id.butOpmlImport);
- Button butConfirm = (Button) root.findViewById(R.id.butConfirm);
+ 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);
final MainActivity activity = (MainActivity) getActivity();
activity.getSupportActionBar().setTitle(R.string.add_feed_label);
@@ -66,4 +66,15 @@ public class AddFeedFragment extends Fragment {
return root;
}
+
+ @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);
+ }
}
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 bbfd1688d..ef522d3b3 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
@@ -4,6 +4,8 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
+import android.os.Handler;
+import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.LinearLayoutManager;
@@ -36,22 +38,22 @@ import de.danoeh.antennapod.core.feed.EventDistributor;
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.DownloadService;
import de.danoeh.antennapod.core.service.download.Downloader;
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.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 rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Shows unread or recently published episodes
@@ -69,24 +71,24 @@ public class AllEpisodesFragment extends Fragment {
private static final String PREF_SCROLL_POSITION = "scroll_position";
private static final String PREF_SCROLL_OFFSET = "scroll_offset";
- protected RecyclerView recyclerView;
- protected AllEpisodesRecycleAdapter listAdapter;
+ RecyclerView recyclerView;
+ AllEpisodesRecycleAdapter listAdapter;
private ProgressBar progLoading;
- protected List<FeedItem> episodes;
+ List<FeedItem> episodes;
private List<Downloader> downloaderList;
private boolean itemsLoaded = false;
private boolean viewsCreated = false;
private boolean isUpdatingFeeds;
- protected boolean isMenuInvalidationAllowed = false;
+ boolean isMenuInvalidationAllowed = false;
- protected Subscription subscription;
+ Disposable disposable;
private LinearLayoutManager layoutManager;
- protected boolean showOnlyNewEpisodes() { return false; }
- protected String getPrefName() { return DEFAULT_PREF_NAME; }
+ boolean showOnlyNewEpisodes() { return false; }
+ String getPrefName() { return DEFAULT_PREF_NAME; }
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -123,8 +125,8 @@ public class AllEpisodesFragment extends Fragment {
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
- if(subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
}
@@ -165,7 +167,7 @@ public class AllEpisodesFragment extends Fragment {
}
}
- protected void resetViewState() {
+ void resetViewState() {
viewsCreated = false;
listAdapter = null;
}
@@ -273,24 +275,24 @@ public class AllEpisodesFragment extends Fragment {
if(item.getItemId() == R.id.share_item) {
return true; // avoids that the position is reset when we need it in the submenu
}
- int pos = listAdapter.getPosition();
- if(pos < 0) {
- return false;
- }
- FeedItem selectedItem = itemAccess.getItem(pos);
+ FeedItem selectedItem = listAdapter.getSelectedItem();
if (selectedItem == null) {
- Log.i(TAG, "Selected item at position " + pos + " was null, ignoring selection");
+ Log.i(TAG, "Selected item was null, ignoring selection");
return super.onContextItemSelected(item);
}
- try {
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
+ // Mark as seen 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,
+ // i.e., there is context menu item for Mark as new
+ if (R.id.mark_as_seen_item == item.getItemId()) {
+ markItemAsSeenWithUndo(selectedItem);
return true;
}
+
+ return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
}
@Override
@@ -299,15 +301,15 @@ public class AllEpisodesFragment extends Fragment {
R.layout.all_episodes_fragment);
}
- protected View onCreateViewHelper(LayoutInflater inflater,
- ViewGroup container,
- Bundle savedInstanceState,
- int fragmentResource) {
+ View onCreateViewHelper(LayoutInflater inflater,
+ ViewGroup container,
+ Bundle savedInstanceState,
+ int fragmentResource) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(fragmentResource, container, false);
- recyclerView = (RecyclerView) root.findViewById(android.R.id.list);
+ recyclerView = root.findViewById(android.R.id.list);
RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
@@ -317,7 +319,7 @@ public class AllEpisodesFragment extends Fragment {
recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());
- progLoading = (ProgressBar) root.findViewById(R.id.progLoading);
+ progLoading = root.findViewById(R.id.progLoading);
if (!itemsLoaded) {
progLoading.setVisibility(View.VISIBLE);
@@ -346,7 +348,7 @@ public class AllEpisodesFragment extends Fragment {
updateShowOnlyEpisodesListViewState();
}
- protected AllEpisodesRecycleAdapter.ItemAccess itemAccess = new AllEpisodesRecycleAdapter.ItemAccess() {
+ private final AllEpisodesRecycleAdapter.ItemAccess itemAccess = new AllEpisodesRecycleAdapter.ItemAccess() {
@Override
public int getCount() {
@@ -444,7 +446,7 @@ public class AllEpisodesFragment extends Fragment {
}
}
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & EVENTS) != 0) {
@@ -459,16 +461,16 @@ public class AllEpisodesFragment extends Fragment {
private void updateShowOnlyEpisodesListViewState() {
}
- protected void loadItems() {
- if(subscription != null) {
- subscription.unsubscribe();
+ void loadItems() {
+ if (disposable != null) {
+ disposable.dispose();
}
if (viewsCreated && !itemsLoaded) {
recyclerView.setVisibility(View.GONE);
progLoading.setVisibility(View.VISIBLE);
}
- subscription = Observable.fromCallable(this::loadData)
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(this::loadData)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
recyclerView.setVisibility(View.VISIBLE);
@@ -483,8 +485,40 @@ public class AllEpisodesFragment extends Fragment {
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
- protected List<FeedItem> loadData() {
+ List<FeedItem> loadData() {
return DBReader.getRecentlyPublishedEpisodes(RECENT_EPISODES_LIMIT);
}
+ void markItemAsSeenWithUndo(FeedItem item) {
+ if (item == null) {
+ return;
+ }
+
+ Log.d(TAG, "markItemAsSeenWithUndo(" + item.getId() + ")");
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ // we're marking it as unplayed since the user didn't actually play it
+ // but they don't want it considered 'NEW' anymore
+ DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId());
+
+ final Handler h = new Handler(getActivity().getMainLooper());
+ 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.LENGTH_LONG);
+ snackbar.setAction(getString(R.string.undo), v -> {
+ DBWriter.markItemPlayed(FeedItem.NEW, item.getId());
+ // don't forget to cancel the thing that's going to remove the media
+ h.removeCallbacks(r);
+ });
+ snackbar.show();
+ h.postDelayed(r, (int)Math.ceil(snackbar.getDuration() * 1.05f));
+ }
+
}
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 1ba7ed557..4bba9b255 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -1,8 +1,6 @@
package de.danoeh.antennapod.fragment;
import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.util.Log;
@@ -12,9 +10,6 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
-import com.joanzapata.iconify.IconDrawable;
-import com.joanzapata.iconify.fonts.FontAwesomeIcons;
-
import java.util.List;
import de.danoeh.antennapod.R;
@@ -22,15 +17,14 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DownloadedEpisodesListAdapter;
import de.danoeh.antennapod.core.feed.EventDistributor;
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.storage.DBWriter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Displays all running downloads and provides a button to delete them
@@ -48,7 +42,7 @@ public class CompletedDownloadsFragment extends ListFragment {
private boolean viewCreated = false;
- private Subscription subscription;
+ private Disposable disposable;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -67,16 +61,16 @@ public class CompletedDownloadsFragment extends ListFragment {
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
- if(subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
}
@Override
public void onDetach() {
super.onDetach();
- if(subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
}
@@ -85,8 +79,8 @@ public class CompletedDownloadsFragment extends ListFragment {
super.onDestroyView();
listAdapter = null;
viewCreated = false;
- if(subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
}
@@ -140,18 +134,7 @@ public class CompletedDownloadsFragment extends ListFragment {
super.onCreateOptionsMenu(menu, inflater);
if(items != null) {
inflater.inflate(R.menu.downloads_completed, menu);
- MenuItem episodeActions = menu.findItem(R.id.episode_actions);
- if(items.size() > 0) {
- int[] attrs = {R.attr.action_bar_icon_color};
- TypedArray ta = getActivity().obtainStyledAttributes(UserPreferences.getTheme(), attrs);
- int textColor = ta.getColor(0, Color.GRAY);
- ta.recycle();
- episodeActions.setIcon(new IconDrawable(getActivity(),
- FontAwesomeIcons.fa_gears).color(textColor).actionBarSize());
- episodeActions.setVisible(true);
- } else {
- episodeActions.setVisible(false);
- }
+ menu.findItem(R.id.episode_actions).setVisible(items.size() > 0);
}
}
@@ -160,7 +143,7 @@ public class CompletedDownloadsFragment extends ListFragment {
switch (item.getItemId()) {
case R.id.episode_actions:
EpisodesApplyActionFragment fragment = EpisodesApplyActionFragment
- .newInstance(items, EpisodesApplyActionFragment.ACTION_REMOVE);
+ .newInstance(items, EpisodesApplyActionFragment.ACTION_REMOVE | EpisodesApplyActionFragment.ACTION_QUEUE);
((MainActivity) getActivity()).loadChildFragment(fragment);
return true;
default:
@@ -168,7 +151,7 @@ public class CompletedDownloadsFragment extends ListFragment {
}
}
- private DownloadedEpisodesListAdapter.ItemAccess itemAccess = new DownloadedEpisodesListAdapter.ItemAccess() {
+ private final DownloadedEpisodesListAdapter.ItemAccess itemAccess = new DownloadedEpisodesListAdapter.ItemAccess() {
@Override
public int getCount() {
return (items != null) ? items.size() : 0;
@@ -189,7 +172,7 @@ public class CompletedDownloadsFragment extends ListFragment {
}
};
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & EVENTS) != 0) {
@@ -199,21 +182,19 @@ public class CompletedDownloadsFragment extends ListFragment {
};
private void loadItems() {
- if(subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
if (items == null && viewCreated) {
setListShown(false);
}
- subscription = Observable.fromCallable(DBReader::getDownloadedItems)
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(DBReader::getDownloadedItems)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
- if (result != null) {
- items = result;
- if (viewCreated && getActivity() != null) {
- onFragmentLoaded();
- }
+ items = result;
+ if (viewCreated && getActivity() != null) {
+ onFragmentLoaded();
}
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
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 1d3fcefba..5a061c7e6 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -11,6 +11,7 @@ import android.widget.TextView;
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;
@@ -22,7 +23,6 @@ import de.danoeh.antennapod.core.util.playback.Playable;
public class CoverFragment extends Fragment implements MediaplayerInfoContentFragment {
private static final String TAG = "CoverFragment";
- private static final String ARG_PLAYABLE = "arg.playable";
private Playable media;
@@ -49,9 +49,9 @@ public class CoverFragment extends Fragment implements MediaplayerInfoContentFra
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
root = inflater.inflate(R.layout.cover_fragment, container, false);
- txtvPodcastTitle = (TextView) root.findViewById(R.id.txtvPodcastTitle);
- txtvEpisodeTitle = (TextView) root.findViewById(R.id.txtvEpisodeTitle);
- imgvCover = (ImageView) root.findViewById(R.id.imgvCover);
+ txtvPodcastTitle = root.findViewById(R.id.txtvPodcastTitle);
+ txtvEpisodeTitle = root.findViewById(R.id.txtvEpisodeTitle);
+ imgvCover = root.findViewById(R.id.imgvCover);
return root;
}
@@ -61,9 +61,10 @@ public class CoverFragment extends Fragment implements MediaplayerInfoContentFra
txtvEpisodeTitle.setText(media.getEpisodeTitle());
Glide.with(this)
.load(media.getImageLocation())
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .dontAnimate()
- .fitCenter()
+ .apply(new RequestOptions()
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .dontAnimate()
+ .fitCenter())
.into(imgvCover);
} else {
Log.w(TAG, "loadMediaInfo was called while media was null");
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 0a710196a..5ab6bac63 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.fragment;
+import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
@@ -10,19 +12,21 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
+import android.widget.TextView;
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.FeedMedia;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Shows the download log
@@ -37,7 +41,7 @@ public class DownloadLogFragment extends ListFragment {
private boolean viewsCreated = false;
private boolean itemsLoaded = false;
- private Subscription subscription;
+ private Disposable disposable;
@Override
public void onStart() {
@@ -51,8 +55,8 @@ public class DownloadLogFragment extends ListFragment {
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
}
@@ -82,7 +86,30 @@ public class DownloadLogFragment extends ListFragment {
getActivity().supportInvalidateOptionsMenu();
}
- private DownloadLogAdapter.ItemAccess itemAccess = new DownloadLogAdapter.ItemAccess() {
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ super.onListItemClick(l, v, position, id);
+
+ 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.isSuccessful()) {
+ message = status.getReasonDetailed();
+ }
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setTitle(R.string.download_error_details);
+ builder.setMessage(getString(R.string.download_error_details_message, message, url));
+ builder.setPositiveButton(android.R.string.ok, null);
+ Dialog dialog = builder.show();
+ ((TextView) dialog.findViewById(android.R.id.message)).setTextIsSelectable(true);
+ }
+
+ private final DownloadLogAdapter.ItemAccess itemAccess = new DownloadLogAdapter.ItemAccess() {
@Override
public int getCount() {
@@ -99,7 +126,7 @@ public class DownloadLogFragment extends ListFragment {
}
};
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
@@ -151,11 +178,11 @@ public class DownloadLogFragment extends ListFragment {
}
private void loadItems() {
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
- subscription = Observable.fromCallable(DBReader::getDownloadLog)
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(DBReader::getDownloadLog)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
if (result != null) {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
index 52a38ccb9..aa6029c84 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
@@ -25,7 +25,7 @@ public class DownloadsFragment extends Fragment {
public static final String ARG_SELECTED_TAB = "selected_tab";
public static final int POS_RUNNING = 0;
- public static final int POS_COMPLETED = 1;
+ private static final int POS_COMPLETED = 1;
public static final int POS_LOG = 2;
private static final String PREF_LAST_TAB_POSITION = "tab_position";
@@ -38,12 +38,12 @@ public class DownloadsFragment extends Fragment {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.pager_fragment, container, false);
- viewPager = (ViewPager)root.findViewById(R.id.viewpager);
+ viewPager = root.findViewById(R.id.viewpager);
DownloadsPagerAdapter pagerAdapter = new DownloadsPagerAdapter(getChildFragmentManager(), getResources());
viewPager.setAdapter(pagerAdapter);
// Give the TabLayout the ViewPager
- tabLayout = (TabLayout) root.findViewById(R.id.sliding_tabs);
+ tabLayout = root.findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
return root;
@@ -78,9 +78,9 @@ public class DownloadsFragment extends Fragment {
viewPager.setCurrentItem(lastPosition);
}
- public class DownloadsPagerAdapter extends FragmentPagerAdapter {
+ public static class DownloadsPagerAdapter extends FragmentPagerAdapter {
- Resources resources;
+ final Resources resources;
public DownloadsPagerAdapter(FragmentManager fm, Resources resources) {
super(fm);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java
index e2fbd91f3..0610bfd24 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java
@@ -21,10 +21,10 @@ public class EpisodesFragment extends Fragment {
public static final String TAG = "EpisodesFragment";
private static final String PREF_LAST_TAB_POSITION = "tab_position";
- public static final int POS_NEW_EPISODES = 0;
- public static final int POS_ALL_EPISODES = 1;
- public static final int POS_FAV_EPISODES = 2;
- public static final int TOTAL_COUNT = 3;
+ private static final int POS_NEW_EPISODES = 0;
+ private static final int POS_ALL_EPISODES = 1;
+ private static final int POS_FAV_EPISODES = 2;
+ private static final int TOTAL_COUNT = 3;
private TabLayout tabLayout;
@@ -46,11 +46,11 @@ public class EpisodesFragment extends Fragment {
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.episodes_label);
View rootView = inflater.inflate(R.layout.pager_fragment, container, false);
- viewPager = (ViewPager)rootView.findViewById(R.id.viewpager);
+ viewPager = rootView.findViewById(R.id.viewpager);
viewPager.setAdapter(new EpisodesPagerAdapter(getChildFragmentManager(), getResources()));
// Give the TabLayout the ViewPager
- tabLayout = (TabLayout) rootView.findViewById(R.id.sliding_tabs);
+ tabLayout = rootView.findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
return rootView;
@@ -79,7 +79,7 @@ public class EpisodesFragment extends Fragment {
public static class EpisodesPagerAdapter extends FragmentPagerAdapter {
private final Resources resources;
- private AllEpisodesFragment[] fragments = {
+ private final AllEpisodesFragment[] fragments = {
new NewEpisodesFragment(),
new AllEpisodesFragment(),
new FavoriteEpisodesFragment()
@@ -106,7 +106,7 @@ public class EpisodesFragment extends Fragment {
case POS_ALL_EPISODES:
return resources.getString(R.string.all_episodes_short_label);
case POS_NEW_EPISODES:
- return resources.getString(R.string.new_label);
+ return resources.getString(R.string.new_episodes_label);
case POS_FAV_EPISODES:
return resources.getString(R.string.favorite_episodes_label);
default:
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 1e385728a..de2f04590 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -1,6 +1,9 @@
package de.danoeh.antennapod.fragment;
+import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
+import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
@@ -13,12 +16,17 @@ 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.feed.MediaType;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.util.Converter;
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;
/**
* Fragment which is supposed to be displayed outside of the MediaplayerActivity
@@ -33,8 +41,8 @@ public class ExternalPlayerFragment extends Fragment {
private ImageButton butPlay;
private TextView mFeedName;
private ProgressBar mProgressBar;
-
private PlaybackController controller;
+ private Disposable disposable;
public ExternalPlayerFragment() {
super();
@@ -45,19 +53,26 @@ public class ExternalPlayerFragment extends Fragment {
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.external_player_fragment,
container, false);
- fragmentLayout = (ViewGroup) root.findViewById(R.id.fragmentLayout);
- imgvCover = (ImageView) root.findViewById(R.id.imgvCover);
- txtvTitle = (TextView) root.findViewById(R.id.txtvTitle);
- butPlay = (ImageButton) root.findViewById(R.id.butPlay);
- mFeedName = (TextView) root.findViewById(R.id.txtvAuthor);
- mProgressBar = (ProgressBar) root.findViewById(R.id.episodeProgress);
+ fragmentLayout = root.findViewById(R.id.fragmentLayout);
+ imgvCover = root.findViewById(R.id.imgvCover);
+ txtvTitle = root.findViewById(R.id.txtvTitle);
+ butPlay = root.findViewById(R.id.butPlay);
+ mFeedName = root.findViewById(R.id.txtvAuthor);
+ mProgressBar = root.findViewById(R.id.episodeProgress);
fragmentLayout.setOnClickListener(v -> {
Log.d(TAG, "layoutInfo was clicked");
if (controller != null && controller.getMedia() != null) {
- startActivity(PlaybackService.getPlayerActivityIntent(
- getActivity(), controller.getMedia()));
+ Intent intent = PlaybackService.getPlayerActivityIntent(getActivity(), controller.getMedia());
+
+ if (Build.VERSION.SDK_INT >= 16 && controller.getMedia().getMediaType() == MediaType.AUDIO) {
+ ActivityOptionsCompat options = ActivityOptionsCompat.
+ makeSceneTransitionAnimation(getActivity(), imgvCover, "coverTransition");
+ startActivity(intent, options.toBundle());
+ } else {
+ startActivity(intent);
+ }
}
});
return root;
@@ -68,10 +83,15 @@ public class ExternalPlayerFragment extends Fragment {
super.onActivityCreated(savedInstanceState);
controller = setupPlaybackController();
butPlay.setOnClickListener(v -> {
- if(controller != null) {
+ if (controller != null) {
controller.playPause();
}
});
+ loadMediaInfo();
+ }
+
+ public void connectToPlaybackService() {
+ controller.init();
}
private PlaybackController setupPlaybackController() {
@@ -112,9 +132,9 @@ public class ExternalPlayerFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
+ onPositionObserverUpdate();
+
controller.init();
- mProgressBar.setProgress((int)
- ((double) controller.getPosition() / controller.getDuration() * 100));
}
@Override
@@ -124,6 +144,9 @@ public class ExternalPlayerFragment extends Fragment {
if (controller != null) {
controller.release();
}
+ if (disposable != null) {
+ disposable.dispose();
+ }
}
@Override
@@ -144,7 +167,7 @@ public class ExternalPlayerFragment extends Fragment {
controller = setupPlaybackController();
if (butPlay != null) {
butPlay.setOnClickListener(v -> {
- if(controller != null) {
+ if (controller != null) {
controller.playPause();
}
});
@@ -154,50 +177,65 @@ public class ExternalPlayerFragment extends Fragment {
private boolean loadMediaInfo() {
Log.d(TAG, "Loading media info");
- if (controller != null && controller.serviceAvailable()) {
- Playable media = controller.getMedia();
- if (media != null) {
- txtvTitle.setText(media.getEpisodeTitle());
- mFeedName.setText(media.getFeedTitle());
- mProgressBar.setProgress((int)
- ((double) controller.getPosition() / controller.getDuration() * 100));
-
- Glide.with(getActivity())
- .load(media.getImageLocation())
+ if (controller == null) {
+ Log.w(TAG, "loadMediaInfo was called while PlaybackController was null!");
+ return false;
+ }
+
+ 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 -> updateUi((Playable) media),
+ error -> Log.e(TAG, Log.getStackTraceString(error)));
+ return true;
+ }
+
+ private void updateUi(Playable media) {
+ if (media != null) {
+ txtvTitle.setText(media.getEpisodeTitle());
+ mFeedName.setText(media.getFeedTitle());
+ onPositionObserverUpdate();
+
+ Glide.with(getActivity())
+ .load(media.getImageLocation())
+ .apply(new RequestOptions()
.placeholder(R.color.light_gray)
.error(R.color.light_gray)
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
.fitCenter()
- .dontAnimate()
- .into(imgvCover);
+ .dontAnimate())
+ .into(imgvCover);
- fragmentLayout.setVisibility(View.VISIBLE);
- if (controller.isPlayingVideoLocally()) {
- butPlay.setVisibility(View.GONE);
- } else {
- butPlay.setVisibility(View.VISIBLE);
- }
- return true;
+ fragmentLayout.setVisibility(View.VISIBLE);
+ if (controller.isPlayingVideoLocally()) {
+ butPlay.setVisibility(View.GONE);
} else {
- Log.w(TAG, "loadMediaInfo was called while the media object of playbackService was null!");
- return false;
+ butPlay.setVisibility(View.VISIBLE);
}
} else {
- Log.w(TAG, "loadMediaInfo was called while playbackService was null!");
- return false;
+ Log.w(TAG, "loadMediaInfo was called while the media object of playbackService was null!");
}
}
- private String getPositionString(int position, int duration) {
- return Converter.getDurationStringLong(position) + " / "
- + Converter.getDurationStringLong(duration);
- }
-
public PlaybackController getPlaybackControllerTestingOnly() {
return controller;
}
- public void onPositionObserverUpdate() {
+ private void onPositionObserverUpdate() {
+ if (controller.getPosition() == PlaybackService.INVALID_TIME
+ || controller.getDuration() == PlaybackService.INVALID_TIME) {
+ return;
+ }
mProgressBar.setProgress((int)
((double) controller.getPosition() / controller.getDuration() * 100));
}
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 234c8377d..70f82c2ec 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
@@ -26,7 +26,7 @@ import de.danoeh.antennapod.core.storage.DBWriter;
public class FavoriteEpisodesFragment extends AllEpisodesFragment {
- public static final String TAG = "FavoriteEpisodesFrag";
+ private static final String TAG = "FavoriteEpisodesFrag";
private static final String PREF_NAME = "PrefFavoriteEpisodesFragment";
@@ -62,8 +62,8 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment {
AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder)viewHolder;
Log.d(TAG, "remove(" + holder.getItemId() + ")");
- if (subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
FeedItem item = holder.getFeedItem();
if (item != null) {
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 7c1ec5ec1..dadc596e2 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
@@ -28,9 +28,9 @@ import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.mfietz.fyydlin.FyydClient;
import de.mfietz.fyydlin.FyydResponse;
import de.mfietz.fyydlin.SearchHit;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+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;
@@ -49,13 +49,13 @@ public class FyydSearchFragment extends Fragment {
private Button butRetry;
private TextView txtvEmpty;
- private FyydClient client = new FyydClient(AntennapodHttpClient.getHttpClient());
+ private final FyydClient client = new FyydClient(AntennapodHttpClient.getHttpClient());
/**
* List of podcasts retreived from the search
*/
private List<Podcast> searchResults;
- private Subscription subscription;
+ private Disposable disposable;
/**
* Constructor
@@ -75,7 +75,7 @@ public class FyydSearchFragment extends Fragment {
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
- gridView = (GridView) root.findViewById(R.id.gridView);
+ gridView = root.findViewById(R.id.gridView);
adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
gridView.setAdapter(adapter);
@@ -87,10 +87,10 @@ public class FyydSearchFragment extends Fragment {
intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, podcast.title);
startActivity(intent);
});
- progressBar = (ProgressBar) root.findViewById(R.id.progressBar);
- txtvError = (TextView) root.findViewById(R.id.txtvError);
- butRetry = (Button) root.findViewById(R.id.butRetry);
- txtvEmpty = (TextView) root.findViewById(android.R.id.empty);
+ 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;
}
@@ -98,8 +98,8 @@ public class FyydSearchFragment extends Fragment {
@Override
public void onDestroy() {
super.onDestroy();
- if (subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
adapter = null;
}
@@ -141,12 +141,12 @@ public class FyydSearchFragment extends Fragment {
}
private void search(String query) {
- if (subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
showOnlyProgressBar();
- subscription = client.searchPodcasts(query)
- .subscribeOn(Schedulers.newThread())
+ disposable = client.searchPodcasts(query, 10)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
progressBar.setVisibility(View.GONE);
@@ -169,12 +169,12 @@ public class FyydSearchFragment extends Fragment {
progressBar.setVisibility(View.VISIBLE);
}
- void processSearchResult(FyydResponse response) {
+ private void processSearchResult(FyydResponse response) {
adapter.clear();
if (!response.getData().isEmpty()) {
adapter.clear();
searchResults = new ArrayList<>();
- for (SearchHit searchHit : response.getData().values()) {
+ for (SearchHit searchHit : response.getData()) {
Podcast podcast = Podcast.fromSearch(searchHit);
searchResults.add(podcast);
}
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 a0586fe16..4ee7a06ad 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,6 @@ 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.v4.app.Fragment;
import android.util.Log;
@@ -34,15 +33,16 @@ 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 rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Displays the description of a Playable object in a Webview.
@@ -66,7 +66,7 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
private ShownotesProvider shownotesProvider;
private Playable media;
- private Subscription webViewLoader;
+ private Disposable webViewLoader;
/**
* URL that was selected via long-press.
@@ -112,15 +112,20 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
Bundle savedInstanceState) {
Log.d(TAG, "Creating view");
webvDescription = new WebView(getActivity().getApplicationContext());
- if (Build.VERSION.SDK_INT >= 11) {
- webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
- }
+ webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
TypedArray ta = getActivity().getTheme().obtainStyledAttributes(new int[]
{android.R.attr.colorBackground});
- int backgroundColor = ta.getColor(0, UserPreferences.getTheme() ==
- R.style.Theme_AntennaPod_Dark ? Color.BLACK : Color.WHITE);
+ boolean black = UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark
+ || UserPreferences.getTheme() == R.style.Theme_AntennaPod_TrueBlack;
+ int backgroundColor = ta.getColor(0, black ? Color.BLACK : Color.WHITE);
+
ta.recycle();
webvDescription.setBackgroundColor(backgroundColor);
+ if (!NetworkUtils.networkAvailable()) {
+ webvDescription.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
+ // Use cached resources, even if they have expired
+ }
webvDescription.getSettings().setUseWideViewPort(false);
webvDescription.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
webvDescription.getSettings().setLoadWithOverviewMode(true);
@@ -162,7 +167,7 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
super.onDestroy();
Log.d(TAG, "Fragment destroyed");
if (webViewLoader != null) {
- webViewLoader.unsubscribe();
+ webViewLoader.dispose();
}
if (webvDescription != null) {
webvDescription.removeAllViews();
@@ -193,7 +198,7 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
} else if (args.containsKey(ARG_FEEDITEM_ID)) {
long id = getArguments().getLong(ARG_FEEDITEM_ID);
Observable.defer(() -> Observable.just(DBReader.getFeedItem(id)))
- .subscribeOn(Schedulers.newThread())
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(feedItem -> {
shownotesProvider = feedItem;
@@ -203,7 +208,7 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
}
- private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
+ private final View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
@@ -238,17 +243,11 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
ShareUtils.shareLink(getActivity(), selectedURL);
break;
case R.id.copy_url_item:
- if (android.os.Build.VERSION.SDK_INT >= 11) {
- ClipData clipData = ClipData.newPlainText(selectedURL,
- selectedURL);
- android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity()
- .getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setPrimaryClip(clipData);
- } else {
- android.text.ClipboardManager cm = (android.text.ClipboardManager) getActivity()
- .getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setText(selectedURL);
- }
+ ClipData clipData = ClipData.newPlainText(selectedURL,
+ selectedURL);
+ android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity()
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ cm.setPrimaryClip(clipData);
Toast t = Toast.makeText(getActivity(),
R.string.copied_url_msg, Toast.LENGTH_SHORT);
t.show();
@@ -299,13 +298,13 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
private void load() {
Log.d(TAG, "load()");
if(webViewLoader != null) {
- webViewLoader.unsubscribe();
+ webViewLoader.dispose();
}
if(shownotesProvider == null) {
return;
}
- webViewLoader = Observable.defer(() -> Observable.just(loadData()))
- .subscribeOn(Schedulers.newThread())
+ webViewLoader = Observable.fromCallable(this::loadData)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
webvDescription.loadDataWithBaseURL(null, data, "text/html",
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 7939dcb23..bcca281d4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -31,6 +31,7 @@ import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconButton;
@@ -51,26 +52,27 @@ 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.service.download.Downloader;
+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.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 rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Displays information about a FeedItem and actions.
@@ -133,7 +135,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
private IconButton butAction2;
private Menu popupMenu;
- private Subscription subscription;
+ private Disposable disposable;
/**
* URL that was selected via long-press.
@@ -164,32 +166,36 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
super.onCreateView(inflater, container, savedInstanceState);
View layout = inflater.inflate(R.layout.feeditem_fragment, container, false);
- root = (ViewGroup) layout.findViewById(R.id.content_root);
+ root = layout.findViewById(R.id.content_root);
- LinearLayout header = (LinearLayout) root.findViewById(R.id.header);
+ LinearLayout header = root.findViewById(R.id.header);
if(feedItems.length > 0) {
header.setOnTouchListener((v, event) -> headerGestureDetector.onTouchEvent(event));
}
- txtvPodcast = (TextView) layout.findViewById(R.id.txtvPodcast);
+ txtvPodcast = layout.findViewById(R.id.txtvPodcast);
txtvPodcast.setOnClickListener(v -> openPodcast());
- txtvTitle = (TextView) layout.findViewById(R.id.txtvTitle);
+ txtvTitle = layout.findViewById(R.id.txtvTitle);
if(Build.VERSION.SDK_INT >= 23) {
txtvTitle.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
}
- txtvDuration = (TextView) layout.findViewById(R.id.txtvDuration);
- txtvPublished = (TextView) layout.findViewById(R.id.txtvPublished);
+ txtvDuration = layout.findViewById(R.id.txtvDuration);
+ txtvPublished = layout.findViewById(R.id.txtvPublished);
if (Build.VERSION.SDK_INT >= 14) { // ellipsize is causing problems on old versions, see #448
txtvTitle.setEllipsize(TextUtils.TruncateAt.END);
}
- webvDescription = (WebView) layout.findViewById(R.id.webvDescription);
- if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
- if (Build.VERSION.SDK_INT >= 11
- && Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+ webvDescription = layout.findViewById(R.id.webvDescription);
+ if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark ||
+ UserPreferences.getTheme() == R.style.Theme_AntennaPod_TrueBlack) {
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
webvDescription.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.black));
}
+ if (!NetworkUtils.networkAvailable()) {
+ webvDescription.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
+ // Use cached resources, even if they have expired
+ }
webvDescription.getSettings().setUseWideViewPort(false);
webvDescription.getSettings().setLayoutAlgorithm(
WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
@@ -210,12 +216,12 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
});
registerForContextMenu(webvDescription);
- imgvCover = (ImageView) layout.findViewById(R.id.imgvCover);
+ imgvCover = layout.findViewById(R.id.imgvCover);
imgvCover.setOnClickListener(v -> openPodcast());
- progbarDownload = (ProgressBar) layout.findViewById(R.id.progbarDownload);
- progbarLoading = (ProgressBar) layout.findViewById(R.id.progbarLoading);
- butAction1 = (IconButton) layout.findViewById(R.id.butAction1);
- butAction2 = (IconButton) layout.findViewById(R.id.butAction2);
+ progbarDownload = layout.findViewById(R.id.progbarDownload);
+ progbarLoading = layout.findViewById(R.id.progbarLoading);
+ butAction1 = layout.findViewById(R.id.butAction1);
+ butAction2 = layout.findViewById(R.id.butAction2);
butAction1.setOnClickListener(v -> {
if (item == null) {
@@ -280,8 +286,8 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
@Override
public void onDestroyView() {
super.onDestroyView();
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
if (webvDescription != null && root != null) {
root.removeView(webvDescription);
@@ -335,13 +341,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
openPodcast();
return true;
default:
- try {
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
- return true;
- }
+ return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item);
}
}
@@ -379,11 +379,12 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
Glide.with(getActivity())
.load(item.getImageLocation())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
.into(imgvCover);
progbarDownload.setVisibility(View.GONE);
@@ -434,6 +435,16 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
butAction1Text = R.string.download_label;
}
}
+
+ FeedItem.State state = item.getState();
+ if (butAction2Text == R.string.delete_label && state == FeedItem.State.PLAYING && PlaybackService.isRunning) {
+ butAction2.setEnabled(false);
+ butAction2.setAlpha(0.5f);
+ } else {
+ butAction2.setEnabled(true);
+ butAction2.setAlpha(1.0f);
+ }
+
if(butAction1Icon != null && butAction1Text != 0) {
butAction1.setText(butAction1Icon +"\u0020\u0020" + getActivity().getString(butAction1Text));
Iconify.addIcons(butAction1);
@@ -450,7 +461,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
}
}
- private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
+ private final View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
@@ -483,17 +494,11 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
ShareUtils.shareLink(getActivity(), selectedURL);
break;
case R.id.copy_url_item:
- if (android.os.Build.VERSION.SDK_INT >= 11) {
- ClipData clipData = ClipData.newPlainText(selectedURL,
- selectedURL);
- android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity()
- .getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setPrimaryClip(clipData);
- } else {
- android.text.ClipboardManager cm = (android.text.ClipboardManager) getActivity()
- .getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setText(selectedURL);
- }
+ ClipData clipData = ClipData.newPlainText(selectedURL,
+ selectedURL);
+ android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity()
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ cm.setPrimaryClip(clipData);
Toast t = Toast.makeText(getActivity(),
R.string.copied_url_msg, Toast.LENGTH_SHORT);
t.show();
@@ -558,7 +563,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
}
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & EVENTS) != 0) {
@@ -568,12 +573,12 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
};
private void load() {
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
progbarLoading.setVisibility(View.VISIBLE);
- subscription = Observable.fromCallable(this::loadInBackground)
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(this::loadInBackground)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
progbarLoading.setVisibility(View.GONE);
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 a118673a6..d9e318069 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -4,10 +4,7 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.res.TypedArray;
-import android.graphics.Color;
import android.graphics.LightingColorFilter;
-import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.view.MenuItemCompat;
@@ -22,15 +19,14 @@ import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ImageView;
-import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
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.fonts.FontAwesomeIcons;
import com.joanzapata.iconify.widget.IconTextView;
import org.apache.commons.lang3.Validate;
@@ -39,6 +35,7 @@ import java.util.List;
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;
@@ -56,7 +53,6 @@ import de.danoeh.antennapod.core.feed.FeedItemFilter;
import de.danoeh.antennapod.core.feed.FeedMedia;
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.service.download.DownloadService;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -72,10 +68,10 @@ import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.greenrobot.event.EventBus;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Displays a list of FeedItems.
@@ -89,9 +85,9 @@ public class ItemlistFragment extends ListFragment {
| EventDistributor.PLAYER_STATUS_UPDATE;
public static final String EXTRA_SELECTED_FEEDITEM = "extra.de.danoeh.antennapod.activity.selected_feeditem";
- public static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id";
+ private static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id";
- protected FeedItemlistAdapter adapter;
+ private FeedItemlistAdapter adapter;
private ContextMenu contextMenu;
private AdapterView.AdapterContextMenuInfo lastMenuInfo = null;
@@ -115,7 +111,7 @@ public class ItemlistFragment extends ListFragment {
private TextView txtvInformation;
- private Subscription subscription;
+ private Disposable disposable;
/**
* Creates new ItemlistFragment which shows the Feeditems of a specific
@@ -166,8 +162,8 @@ public class ItemlistFragment extends ListFragment {
super.onPause();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
}
@@ -223,13 +219,6 @@ public class ItemlistFragment extends ListFragment {
menu.findItem(R.id.share_link_item).setVisible(false);
menu.findItem(R.id.visit_website_item).setVisible(false);
}
- int[] attrs = { R.attr.action_bar_icon_color };
- TypedArray ta = getActivity().obtainStyledAttributes(UserPreferences.getTheme(), attrs);
- int textColor = ta.getColor(0, Color.GRAY);
- ta.recycle();
-
- menu.findItem(R.id.episode_actions).setIcon(new IconDrawable(getActivity(),
- FontAwesomeIcons.fa_gears).color(textColor).actionBarSize());
isUpdatingFeed = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
@@ -342,22 +331,7 @@ public class ItemlistFragment extends ListFragment {
return super.onContextItemSelected(item);
}
- try {
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
- } catch (DownloadRequestException e) {
- // context menu doesn't contain download functionality
- return true;
- }
- }
-
-
- @Override
- public void setListAdapter(ListAdapter adapter) {
- // This workaround prevents the ListFragment from setting a list adapter when its state is restored.
- // This is only necessary on API 10 because addFooterView throws an internal exception in this case.
- if (Build.VERSION.SDK_INT > 10 || insideOnFragmentLoaded) {
- super.setListAdapter(adapter);
- }
+ return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
}
@Override
@@ -417,7 +391,7 @@ public class ItemlistFragment extends ListFragment {
}
}
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
@@ -440,13 +414,10 @@ public class ItemlistFragment extends ListFragment {
}
- private boolean insideOnFragmentLoaded = false;
-
private void onFragmentLoaded() {
if(!isVisible()) {
return;
}
- insideOnFragmentLoaded = true;
if (adapter == null) {
setListAdapter(null);
setupHeaderView();
@@ -463,9 +434,6 @@ public class ItemlistFragment extends ListFragment {
if (feed != null && feed.getNextPageLink() == null && listFooter != null) {
getListView().removeFooterView(listFooter.getRoot());
}
-
- insideOnFragmentLoaded = false;
-
}
private void refreshHeaderView() {
@@ -509,13 +477,14 @@ public class ItemlistFragment extends ListFragment {
View header = inflater.inflate(R.layout.feeditemlist_header, lv, false);
lv.addHeaderView(header);
- txtvTitle = (TextView) header.findViewById(R.id.txtvTitle);
- TextView txtvAuthor = (TextView) header.findViewById(R.id.txtvAuthor);
- imgvBackground = (ImageView) header.findViewById(R.id.imgvBackground);
- imgvCover = (ImageView) header.findViewById(R.id.imgvCover);
- ImageButton butShowInfo = (ImageButton) header.findViewById(R.id.butShowInfo);
- txtvInformation = (TextView) header.findViewById(R.id.txtvInformation);
- txtvFailure = (IconTextView) header.findViewById(R.id.txtvFailure);
+ txtvTitle = header.findViewById(R.id.txtvTitle);
+ TextView txtvAuthor = header.findViewById(R.id.txtvAuthor);
+ imgvBackground = header.findViewById(R.id.imgvBackground);
+ imgvCover = header.findViewById(R.id.imgvCover);
+ ImageButton butShowInfo = header.findViewById(R.id.butShowInfo);
+ ImageButton butShowSettings = header.findViewById(R.id.butShowSettings);
+ txtvInformation = header.findViewById(R.id.txtvInformation);
+ txtvFailure = header.findViewById(R.id.txtvFailure);
txtvTitle.setText(feed.getTitle());
txtvAuthor.setText(feed.getAuthor());
@@ -526,10 +495,12 @@ public class ItemlistFragment extends ListFragment {
loadFeedImage();
- butShowInfo.setOnClickListener(v -> {
+ butShowInfo.setOnClickListener(v -> showFeedInfo());
+ imgvCover.setOnClickListener(v -> showFeedInfo());
+ butShowSettings.setOnClickListener(v -> {
if (viewsCreated && itemsLoaded) {
- Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class);
- startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID,
+ Intent startIntent = new Intent(getActivity(), FeedSettingsActivity.class);
+ startIntent.putExtra(FeedSettingsActivity.EXTRA_FEED_ID,
feed.getId());
startActivity(startIntent);
}
@@ -537,23 +508,34 @@ public class ItemlistFragment extends ListFragment {
headerCreated = true;
}
+ private void showFeedInfo() {
+ if (viewsCreated && itemsLoaded) {
+ Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class);
+ startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID,
+ feed.getId());
+ startActivity(startIntent);
+ }
+ }
+
private void loadFeedImage() {
Glide.with(getActivity())
.load(feed.getImageLocation())
- .placeholder(R.color.image_readability_tint)
- .error(R.color.image_readability_tint)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .transform(new FastBlurTransformation(getActivity()))
- .dontAnimate()
+ .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);
Glide.with(getActivity())
.load(feed.getImageLocation())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate())
.into(imgvCover);
}
@@ -583,7 +565,7 @@ public class ItemlistFragment extends ListFragment {
}
}
- private FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() {
+ private final FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() {
@Override
public FeedItem getItem(int position) {
@@ -629,11 +611,11 @@ public class ItemlistFragment extends ListFragment {
private void loadItems() {
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
- subscription = Observable.fromCallable(this::loadData)
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(this::loadData)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
if (result != null) {
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 43dedad25..a0e2ca22a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
@@ -36,13 +36,14 @@ import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+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 okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast;
@@ -69,13 +70,13 @@ public class ItunesSearchFragment extends Fragment {
*/
private List<Podcast> searchResults;
private List<Podcast> topList;
- private Subscription subscription;
+ private Disposable disposable;
/**
* Replace adapter data with provided search results from SearchTask.
* @param result List of Podcast objects containing search results
*/
- void updateData(List<Podcast> result) {
+ private void updateData(List<Podcast> result) {
this.searchResults = result;
adapter.clear();
if (result != null && result.size() > 0) {
@@ -109,7 +110,7 @@ public class ItunesSearchFragment extends Fragment {
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
- gridView = (GridView) root.findViewById(R.id.gridView);
+ gridView = root.findViewById(R.id.gridView);
adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
gridView.setAdapter(adapter);
@@ -127,7 +128,7 @@ public class ItunesSearchFragment extends Fragment {
} else {
gridView.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
- subscription = Observable.create((Observable.OnSubscribe<String>) subscriber -> {
+ disposable = Single.create((SingleOnSubscribe<String>) emitter -> {
OkHttpClient client = AntennapodHttpClient.getHttpClient();
Request.Builder httpReq = new Request.Builder()
.url(podcast.feedUrl)
@@ -139,17 +140,16 @@ public class ItunesSearchFragment extends Fragment {
JSONObject result = new JSONObject(resultString);
JSONObject results = result.getJSONArray("results").getJSONObject(0);
String feedUrl = results.getString("feedUrl");
- subscriber.onNext(feedUrl);
+ emitter.onSuccess(feedUrl);
} else {
String prefix = getString(R.string.error_msg_prefix);
- subscriber.onError(new IOException(prefix + response));
+ emitter.onError(new IOException(prefix + response));
}
} catch (IOException | JSONException e) {
- subscriber.onError(e);
+ emitter.onError(e);
}
- subscriber.onCompleted();
})
- .subscribeOn(Schedulers.newThread())
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(feedUrl -> {
progressBar.setVisibility(View.GONE);
@@ -170,10 +170,10 @@ public class ItunesSearchFragment extends Fragment {
});
}
});
- progressBar = (ProgressBar) root.findViewById(R.id.progressBar);
- txtvError = (TextView) root.findViewById(R.id.txtvError);
- butRetry = (Button) root.findViewById(R.id.butRetry);
- txtvEmpty = (TextView) root.findViewById(android.R.id.empty);
+ 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);
loadToplist();
@@ -183,8 +183,8 @@ public class ItunesSearchFragment extends Fragment {
@Override
public void onDestroy() {
super.onDestroy();
- if (subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
adapter = null;
}
@@ -228,15 +228,15 @@ public class ItunesSearchFragment extends Fragment {
}
private void loadToplist() {
- if (subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
gridView.setVisibility(View.GONE);
txtvError.setVisibility(View.GONE);
butRetry.setVisibility(View.GONE);
txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
- subscription = Observable.create((Observable.OnSubscribe<List<Podcast>>) subscriber -> {
+ 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();
@@ -268,15 +268,14 @@ public class ItunesSearchFragment extends Fragment {
}
else {
String prefix = getString(R.string.error_msg_prefix);
- subscriber.onError(new IOException(prefix + response));
+ emitter.onError(new IOException(prefix + response));
}
} catch (IOException | JSONException e) {
- subscriber.onError(e);
+ emitter.onError(e);
}
- subscriber.onNext(results);
- subscriber.onCompleted();
+ emitter.onSuccess(results);
})
- .subscribeOn(Schedulers.newThread())
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(podcasts -> {
progressBar.setVisibility(View.GONE);
@@ -293,15 +292,15 @@ public class ItunesSearchFragment extends Fragment {
}
private void search(String query) {
- if (subscription != null) {
- subscription.unsubscribe();
+ if (disposable != null) {
+ disposable.dispose();
}
gridView.setVisibility(View.GONE);
txtvError.setVisibility(View.GONE);
butRetry.setVisibility(View.GONE);
txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
- subscription = rx.Observable.create((Observable.OnSubscribe<List<Podcast>>) subscriber -> {
+ disposable = Single.create((SingleOnSubscribe<List<Podcast>>) subscriber -> {
String encodedQuery = null;
try {
encodedQuery = URLEncoder.encode(query, "UTF-8");
@@ -341,10 +340,9 @@ public class ItunesSearchFragment extends Fragment {
} catch (IOException | JSONException e) {
subscriber.onError(e);
}
- subscriber.onNext(podcasts);
- subscriber.onCompleted();
+ subscriber.onSuccess(podcasts);
})
- .subscribeOn(Schedulers.newThread())
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(podcasts -> {
progressBar.setVisibility(View.GONE);
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 183c10f3d..6695ba427 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -1,14 +1,10 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.os.Handler;
-import android.support.design.widget.Snackbar;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -18,10 +14,7 @@ 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.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.util.FeedItemUtil;
@@ -76,33 +69,7 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder)viewHolder;
-
- Log.d(TAG, "remove(" + holder.getItemId() + ")");
- if (subscription != null) {
- subscription.unsubscribe();
- }
- FeedItem item = holder.getFeedItem();
- // we're marking it as unplayed since the user didn't actually play it
- // but they don't want it considered 'NEW' anymore
- DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId());
-
- final Handler h = new Handler(getActivity().getMainLooper());
- final Runnable r = () -> {
- FeedMedia media = item.getMedia();
- if (media != null && media.hasAlmostEnded() && UserPreferences.isAutoDelete()) {
- DBWriter.deleteFeedMediaOfItem(getActivity(), media.getId());
- }
- };
-
- Snackbar snackbar = Snackbar.make(root, getString(R.string.marked_as_seen_label),
- Snackbar.LENGTH_LONG);
- snackbar.setAction(getString(R.string.undo), v -> {
- DBWriter.markItemPlayed(FeedItem.NEW, item.getId());
- // don't forget to cancel the thing that's going to remove the media
- h.removeCallbacks(r);
- });
- snackbar.show();
- h.postDelayed(r, (int)Math.ceil(snackbar.getDuration() * 1.05f));
+ markItemAsSeenWithUndo(holder.getFeedItem());
}
@Override
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 441f0096c..c2a9200c8 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -30,10 +30,10 @@ 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 rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
public class PlaybackHistoryFragment extends ListFragment {
@@ -50,7 +50,7 @@ public class PlaybackHistoryFragment extends ListFragment {
private List<Downloader> downloaderList;
- private Subscription subscription;
+ private Disposable disposable;
@Override
public void onAttach(Context context) {
@@ -107,16 +107,16 @@ public class PlaybackHistoryFragment extends ListFragment {
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
}
@Override
public void onDetach() {
super.onDetach();
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
}
@@ -199,7 +199,7 @@ public class PlaybackHistoryFragment extends ListFragment {
}
}
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
@@ -224,7 +224,7 @@ public class PlaybackHistoryFragment extends ListFragment {
getActivity().supportInvalidateOptionsMenu();
}
- private FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() {
+ private final FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() {
@Override
public int getItemDownloadProgressPercent(FeedItem item) {
@@ -269,11 +269,11 @@ public class PlaybackHistoryFragment extends ListFragment {
};
private void loadItems() {
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
- subscription = Observable.fromCallable(this::loadData)
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(this::loadData)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
if (result != null) {
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 fccb86076..faeabf75c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -21,7 +21,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
-import android.widget.Toast;
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
@@ -46,7 +45,6 @@ import de.danoeh.antennapod.core.service.download.Downloader;
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.Converter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
@@ -55,10 +53,10 @@ import de.danoeh.antennapod.core.util.QueueSorter;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.greenrobot.event.EventBus;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Shows all items in the queue
@@ -86,7 +84,7 @@ public class QueueFragment extends Fragment {
private static final String PREF_SCROLL_POSITION = "scroll_position";
private static final String PREF_SCROLL_OFFSET = "scroll_offset";
- private Subscription subscription;
+ private Disposable disposable;
private LinearLayoutManager layoutManager;
private ItemTouchHelper itemTouchHelper;
@@ -109,7 +107,6 @@ public class QueueFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
- recyclerView.setAdapter(recyclerAdapter);
loadItems(true);
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().registerSticky(this);
@@ -121,8 +118,8 @@ public class QueueFragment extends Fragment {
saveScrollPosition();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
}
@@ -328,6 +325,15 @@ public class QueueFragment extends Fragment {
case R.id.queue_sort_feed_title_desc:
QueueSorter.sort(getActivity(), QueueSorter.Rule.FEED_TITLE_DESC, true);
return true;
+ case R.id.queue_sort_random:
+ QueueSorter.sort(getActivity(), QueueSorter.Rule.RANDOM, true);
+ return true;
+ case R.id.queue_sort_smart_shuffle_asc:
+ QueueSorter.sort(getActivity(), QueueSorter.Rule.SMART_SHUFFLE_ASC, true);
+ return true;
+ case R.id.queue_sort_smart_shuffle_desc:
+ QueueSorter.sort(getActivity(), QueueSorter.Rule.SMART_SHUFFLE_DESC, true);
+ return true;
default:
return false;
}
@@ -363,13 +369,7 @@ public class QueueFragment extends Fragment {
DBWriter.moveQueueItemToBottom(selectedItem.getId(), true);
return true;
default:
- try {
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
- return true;
- }
+ return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
}
}
@@ -380,8 +380,8 @@ public class QueueFragment extends Fragment {
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.queue_label);
View root = inflater.inflate(R.layout.queue_fragment, container, false);
- infoBar = (TextView) root.findViewById(R.id.info_bar);
- recyclerView = (RecyclerView) root.findViewById(R.id.recyclerView);
+ infoBar = root.findViewById(R.id.info_bar);
+ recyclerView = root.findViewById(R.id.recyclerView);
RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
@@ -395,24 +395,36 @@ public class QueueFragment extends Fragment {
itemTouchHelper = new ItemTouchHelper(
new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT) {
+ // Position tracking whilst dragging
+ int dragFrom = -1;
+ int dragTo = -1;
+
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
+ int fromPosition = viewHolder.getAdapterPosition();
+ int toPosition = target.getAdapterPosition();
+
+ // Update tracked position
+ if(dragFrom == -1) {
+ dragFrom = fromPosition;
+ }
+ dragTo = toPosition;
+
int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();
- Log.d(TAG, "move(" + from + ", " + to + ")");
+ Log.d(TAG, "move(" + from + ", " + to + ") in memory");
if(from >= queue.size() || to >= queue.size()) {
return false;
}
queue.add(to, queue.remove(from));
recyclerAdapter.notifyItemMoved(from, to);
- DBWriter.moveQueueItem(from, to, true);
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
final int position = viewHolder.getAdapterPosition();
Log.d(TAG, "remove(" + position + ")");
@@ -459,19 +471,32 @@ public class QueueFragment extends Fragment {
RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
+ // Check if drag finished
+ if(dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) {
+ reallyMoved(dragFrom, dragTo);
+ }
+
+ dragFrom = dragTo = -1;
+
if (viewHolder instanceof QueueRecyclerAdapter.ItemTouchHelperViewHolder) {
QueueRecyclerAdapter.ItemTouchHelperViewHolder itemViewHolder =
(QueueRecyclerAdapter.ItemTouchHelperViewHolder) viewHolder;
itemViewHolder.onItemClear();
}
}
+
+ private void reallyMoved(int from, int to) {
+ // Write drag operation to database
+ Log.d(TAG, "Write to database move(" + from + ", " + to + ")");
+ DBWriter.moveQueueItem(from, to, true);
+ }
}
);
itemTouchHelper.attachToRecyclerView(recyclerView);
- txtvEmpty = (TextView) root.findViewById(android.R.id.empty);
+ txtvEmpty = root.findViewById(android.R.id.empty);
txtvEmpty.setVisibility(View.GONE);
- progLoading = (ProgressBar) root.findViewById(R.id.progLoading);
+ progLoading = root.findViewById(R.id.progLoading);
progLoading.setVisibility(View.VISIBLE);
return root;
@@ -507,19 +532,23 @@ public class QueueFragment extends Fragment {
private void refreshInfoBar() {
String info = queue.size() + getString(R.string.episodes_suffix);
if(queue.size() > 0) {
- long duration = 0;
+ long timeLeft = 0;
+ float playbackSpeed = Float.valueOf(UserPreferences.getPlaybackSpeed());
for(FeedItem item : queue) {
if(item.getMedia() != null) {
- duration += item.getMedia().getDuration();
+ timeLeft +=
+ (long) ((item.getMedia().getDuration() - item.getMedia().getPosition())
+ / playbackSpeed);
}
}
info += " \u2022 ";
- info += Converter.getDurationStringLocalized(getActivity(), duration);
+ info += getString(R.string.time_left_label);
+ info += Converter.getDurationStringLocalized(getActivity(), timeLeft);
}
infoBar.setText(info);
}
- private QueueRecyclerAdapter.ItemAccess itemAccess = new QueueRecyclerAdapter.ItemAccess() {
+ private final QueueRecyclerAdapter.ItemAccess itemAccess = new QueueRecyclerAdapter.ItemAccess() {
@Override
public int getCount() {
return queue != null ? queue.size() : 0;
@@ -579,7 +608,7 @@ public class QueueFragment extends Fragment {
}
};
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & EVENTS) != 0) {
@@ -594,16 +623,16 @@ public class QueueFragment extends Fragment {
private void loadItems(final boolean restoreScrollPosition) {
Log.d(TAG, "loadItems()");
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
if (queue == null) {
recyclerView.setVisibility(View.GONE);
txtvEmpty.setVisibility(View.GONE);
progLoading.setVisibility(View.VISIBLE);
}
- subscription = Observable.fromCallable(DBReader::getQueue)
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(DBReader::getQueue)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(items -> {
if(items != null) {
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 ba526edb3..66c59b7f7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
@@ -75,7 +75,7 @@ public class RunningDownloadsFragment extends ListFragment {
}
- private DownloadlistAdapter.ItemAccess itemAccess = new DownloadlistAdapter.ItemAccess() {
+ private final DownloadlistAdapter.ItemAccess itemAccess = new DownloadlistAdapter.ItemAccess() {
@Override
public int getCount() {
return (downloaderList != null) ? downloaderList.size() : 0;
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 f64b4c20a..8322a5573 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -24,10 +24,10 @@ import de.danoeh.antennapod.core.feed.FeedComponent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.SearchResult;
import de.danoeh.antennapod.core.storage.FeedSearcher;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Performs a search operation on all feeds or one specific feed and displays the search result.
@@ -44,7 +44,7 @@ public class SearchFragment extends ListFragment {
private boolean viewCreated = false;
private boolean itemsLoaded = false;
- private Subscription subscription;
+ private Disposable disposable;
/**
* Create a new SearchFragment that searches all feeds.
@@ -85,8 +85,8 @@ public class SearchFragment extends ListFragment {
@Override
public void onStop() {
super.onStop();
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
EventDistributor.getInstance().unregister(contentUpdate);
}
@@ -94,8 +94,8 @@ public class SearchFragment extends ListFragment {
@Override
public void onDetach() {
super.onDetach();
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
}
@@ -205,14 +205,14 @@ public class SearchFragment extends ListFragment {
private void search() {
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
if (viewCreated && !itemsLoaded) {
setListShown(false);
}
- subscription = Observable.fromCallable(this::performSearch)
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(this::performSearch)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
if (result != null) {
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 9626e6c2e..5f09be8ce 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
@@ -1,7 +1,6 @@
package de.danoeh.antennapod.fragment;
import android.content.DialogInterface;
-import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
@@ -26,11 +25,12 @@ import de.danoeh.antennapod.core.service.playback.PlaybackService;
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.IntentUtils;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Fragment for displaying feed subscriptions
@@ -48,7 +48,7 @@ public class SubscriptionFragment extends Fragment {
private int mPosition = -1;
- private Subscription subscription;
+ private Disposable disposable;
public SubscriptionFragment() {
}
@@ -68,7 +68,7 @@ public class SubscriptionFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_subscriptions, container, false);
- subscriptionGridLayout = (GridView) root.findViewById(R.id.subscriptions_grid);
+ subscriptionGridLayout = root.findViewById(R.id.subscriptions_grid);
registerForContextMenu(subscriptionGridLayout);
return root;
}
@@ -94,17 +94,17 @@ public class SubscriptionFragment extends Fragment {
@Override
public void onDestroy() {
super.onDestroy();
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
}
private void loadSubscriptions() {
- if(subscription != null) {
- subscription.unsubscribe();
+ if(disposable != null) {
+ disposable.dispose();
}
- subscription = Observable.fromCallable(DBReader::getNavDrawerData)
- .subscribeOn(Schedulers.newThread())
+ disposable = Observable.fromCallable(DBReader::getNavDrawerData)
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
navDrawerData = result;
@@ -152,18 +152,39 @@ public class SubscriptionFragment extends Fragment {
Feed feed = (Feed)selectedObject;
switch(item.getItemId()) {
case R.id.mark_all_seen_item:
- Observable.fromCallable(() -> DBWriter.markFeedSeen(feed.getId()))
- .subscribeOn(Schedulers.newThread())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> loadSubscriptions(),
- error -> Log.e(TAG, Log.getStackTraceString(error)));
+ 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();
return true;
case R.id.mark_all_read_item:
- Observable.fromCallable(() -> DBWriter.markFeedRead(feed.getId()))
- .subscribeOn(Schedulers.newThread())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> loadSubscriptions(),
- error -> Log.e(TAG, Log.getStackTraceString(error)));
+ ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(getActivity(),
+ 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();
return true;
case R.id.rename_item:
new RenameFeedDialog(getActivity(), feed).show();
@@ -190,8 +211,8 @@ public class SubscriptionFragment extends Fragment {
remover.skipOnCompletion = true;
int playerStatus = PlaybackPreferences.getCurrentPlayerStatus();
if(playerStatus == PlaybackPreferences.PLAYER_STATUS_PLAYING) {
- getActivity().sendBroadcast(new Intent(
- PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
+ IntentUtils.sendLocalBroadcast(getContext(), PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
+
}
}
remover.executeAsync();
@@ -210,7 +231,7 @@ public class SubscriptionFragment extends Fragment {
loadSubscriptions();
}
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((EVENTS & arg) != 0) {
@@ -220,7 +241,7 @@ public class SubscriptionFragment extends Fragment {
}
};
- private SubscriptionsAdapter.ItemAccess itemAccess = new SubscriptionsAdapter.ItemAccess() {
+ private final SubscriptionsAdapter.ItemAccess itemAccess = new SubscriptionsAdapter.ItemAccess() {
@Override
public int getCount() {
if (navDrawerData != null) {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
index aff5069c6..4dc114f9b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
@@ -20,7 +20,7 @@ import de.danoeh.antennapod.R;
*/
public class GpodnetMainFragment extends Fragment {
- public static final String TAG = "GpodnetMainFragment";
+ private static final String TAG = "GpodnetMainFragment";
private static final String PREF_LAST_TAB_POSITION = "tab_position";
private TabLayout tabLayout;
@@ -31,12 +31,12 @@ public class GpodnetMainFragment extends Fragment {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.pager_fragment, container, false);
- viewPager = (ViewPager)root.findViewById(R.id.viewpager);
+ viewPager = root.findViewById(R.id.viewpager);
GpodnetPagerAdapter pagerAdapter = new GpodnetPagerAdapter(getChildFragmentManager(), getResources());
viewPager.setAdapter(pagerAdapter);
// Give the TabLayout the ViewPager
- tabLayout = (TabLayout) root.findViewById(R.id.sliding_tabs);
+ tabLayout = root.findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
return root;
@@ -71,7 +71,7 @@ public class GpodnetMainFragment extends Fragment {
private static final int POS_TAGS = 1;
private static final int POS_SUGGESTIONS = 2;
- Resources resources;
+ final Resources resources;
public GpodnetPagerAdapter(FragmentManager fm, Resources resources) {
super(fm);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
index 15e9c9943..49851ebb4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
@@ -78,10 +78,10 @@ public abstract class PodcastListFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.gpodnet_podcast_list, container, false);
- gridView = (GridView) root.findViewById(R.id.gridView);
- progressBar = (ProgressBar) root.findViewById(R.id.progressBar);
- txtvError = (TextView) root.findViewById(R.id.txtvError);
- butRetry = (Button) root.findViewById(R.id.butRetry);
+ gridView = root.findViewById(R.id.gridView);
+ progressBar = root.findViewById(R.id.progressBar);
+ txtvError = root.findViewById(R.id.txtvError);
+ butRetry = root.findViewById(R.id.butRetry);
gridView.setOnItemClickListener((parent, view, position, id) ->
onPodcastSelected((GpodnetPodcast) gridView.getAdapter().getItem(position)));
@@ -91,7 +91,7 @@ public abstract class PodcastListFragment extends Fragment {
return root;
}
- protected void onPodcastSelected(GpodnetPodcast selection) {
+ private void onPodcastSelected(GpodnetPodcast selection) {
Log.d(TAG, "Selected podcast: " + selection.toString());
Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, selection.getUrl());
@@ -101,7 +101,7 @@ public abstract class PodcastListFragment extends Fragment {
protected abstract List<GpodnetPodcast> loadPodcastData(GpodnetService service) throws GpodnetServiceException;
- protected final void loadData() {
+ final void loadData() {
AsyncTask<Void, Void, List<GpodnetPodcast>> loaderTask = new AsyncTask<Void, Void, List<GpodnetPodcast>>() {
volatile Exception exception = null;
@@ -160,10 +160,6 @@ public abstract class PodcastListFragment extends Fragment {
}
};
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- loaderTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- loaderTask.execute();
- }
+ loaderTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastTopListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastTopListFragment.java
index 33a35fa90..4f963756c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastTopListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastTopListFragment.java
@@ -1,11 +1,11 @@
package de.danoeh.antennapod.fragment.gpodnet;
+import java.util.List;
+
import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast;
-import java.util.List;
-
/**
*
*/
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
index 613e06805..10bd636dd 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
@@ -73,7 +73,7 @@ public class SearchListFragment extends PodcastListFragment {
return service.searchPodcasts(query, 0);
}
- public void changeQuery(String query) {
+ private void changeQuery(String query) {
Validate.notNull(query);
this.query = query;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
index d2c7f32dd..1e46b1ac5 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
@@ -135,11 +135,7 @@ public class TagListFragment extends ListFragment {
}
}
};
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- loadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- loadTask.execute();
- }
+ loadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
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 57b7c359c..ffdfa9516 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
@@ -17,7 +17,7 @@ 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.storage.DownloadRequestException;
+import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.ShareUtils;
@@ -87,7 +87,7 @@ public class FeedItemMenuHandler {
mi.setItemVisibility(R.id.add_to_queue_item, false);
}
- if (!showExtendedMenu || selectedItem.getLink() == null) {
+ if (!showExtendedMenu || !ShareUtils.hasLinkToShare(selectedItem)) {
mi.setItemVisibility(R.id.visit_website_item, false);
mi.setItemVisibility(R.id.share_link_item, false);
mi.setItemVisibility(R.id.share_link_with_position_item, false);
@@ -155,10 +155,10 @@ public class FeedItemMenuHandler {
}
public static boolean onMenuItemClicked(Context context, int menuItemId,
- FeedItem selectedItem) throws DownloadRequestException {
+ FeedItem selectedItem) {
switch (menuItemId) {
case R.id.skip_episode_item:
- context.sendBroadcast(new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
+ IntentUtils.sendLocalBroadcast(context, PlaybackService.ACTION_SKIP_CURRENT_EPISODE);
break;
case R.id.remove_item:
DBWriter.deleteFeedMediaOfItem(context, selectedItem.getMedia().getId());
@@ -217,7 +217,7 @@ public class FeedItemMenuHandler {
DBWriter.setFeedItemAutoDownload(selectedItem, false);
break;
case R.id.visit_website_item:
- Uri uri = Uri.parse(selectedItem.getLink());
+ Uri uri = Uri.parse(FeedItemUtil.getLinkWithFallback(selectedItem));
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
if(IntentUtils.isCallable(context, intent)) {
context.startActivity(intent);
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 ab7d0e7c6..bd4fe9bcf 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -30,6 +30,9 @@ import de.danoeh.antennapod.core.util.ShareUtils;
* Handles interactions with the FeedItemMenu.
*/
public class FeedMenuHandler {
+
+ private FeedMenuHandler(){ }
+
private static final String TAG = "FeedMenuHandler";
public static boolean onCreateOptionsMenu(MenuInflater inflater, Menu menu) {
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
index ac703e13e..7b9fcad9b 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
@@ -19,8 +19,9 @@ public class MenuItemUtils extends de.danoeh.antennapod.core.menuhandler.MenuIte
public static void adjustTextColor(Context context, SearchView sv) {
if(Build.VERSION.SDK_INT < 14) {
- EditText searchEditText = (EditText) sv.findViewById(R.id.search_src_text);
- if(UserPreferences.getTheme() == de.danoeh.antennapod.R.style.Theme_AntennaPod_Dark) {
+ EditText searchEditText = sv.findViewById(R.id.search_src_text);
+ if (UserPreferences.getTheme() == de.danoeh.antennapod.R.style.Theme_AntennaPod_Dark
+ || UserPreferences.getTheme() == R.style.Theme_AntennaPod_TrueBlack) {
searchEditText.setTextColor(Color.WHITE);
} else {
searchEditText.setTextColor(Color.BLACK);
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java
new file mode 100644
index 000000000..b810cbfa6
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java
@@ -0,0 +1,48 @@
+package de.danoeh.antennapod.preferences;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.widget.TextView;
+
+import de.danoeh.antennapod.R;
+
+public class MasterSwitchPreference extends SwitchPreference {
+
+ public MasterSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public MasterSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public MasterSwitchPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MasterSwitchPreference(Context context) {
+ super(context);
+ }
+
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ TypedValue typedValue = new TypedValue();
+ getContext().getTheme().resolveAttribute(R.attr.master_switch_background, typedValue, true);
+ holder.itemView.setBackgroundColor(typedValue.data);
+
+ TextView title = (TextView) holder.findViewById(android.R.id.title);
+ if (title != null) {
+ title.setTypeface(title.getTypeface(), Typeface.BOLD);
+ }
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java
new file mode 100644
index 000000000..50e76838c
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java
@@ -0,0 +1,107 @@
+package de.danoeh.antennapod.preferences;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.text.InputFilter;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.EditText;
+
+import de.danoeh.antennapod.R;
+
+public class NumberPickerPreference extends Preference {
+ private Context context;
+ private int defaultValue = 0;
+ private int minValue = 0;
+ private int maxValue = Integer.MAX_VALUE;
+
+ public NumberPickerPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(context, attrs);
+ }
+
+ public NumberPickerPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs);
+ }
+
+ public NumberPickerPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs);
+ }
+
+ public NumberPickerPreference(Context context) {
+ super(context);
+ this.context = context;
+ }
+
+ private void init(Context context, AttributeSet attrs) {
+ this.context = context;
+
+ for (int i = 0; i < attrs.getAttributeCount(); i++) {
+ String name = attrs.getAttributeName(i);
+ String value = attrs.getAttributeValue(i);
+ switch (name) {
+ case "defaultValue":
+ defaultValue = Integer.parseInt(value);
+ break;
+ case "minValue":
+ minValue = Integer.parseInt(value);
+ break;
+ case "maxValue":
+ maxValue = Integer.parseInt(value);
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void onClick() {
+ super.onClick();
+
+ View view = View.inflate(context, R.layout.numberpicker, null);
+ EditText number = view.findViewById(R.id.number);
+ number.setText(getSharedPreferences().getString(getKey(), ""+defaultValue));
+ number.setFilters(new InputFilter[]{(source, start, end, dest, dstart, dend) -> {
+ try {
+ String newVal = dest.toString().substring(0, dstart) + dest.toString().substring(dend);
+ newVal = newVal.substring(0, dstart) + source.toString() + newVal.substring(dstart);
+ int input = Integer.parseInt(newVal);
+ if (input >= minValue && input <= maxValue) {
+ return null;
+ }
+ } catch (NumberFormatException nfe) {
+ nfe.printStackTrace();
+ }
+ return "";
+ }});
+
+ AlertDialog dialog = new AlertDialog.Builder(context)
+ .setTitle(getTitle())
+ .setView(view)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
+ try {
+ String numberString = number.getText().toString();
+ int value = Integer.parseInt(numberString);
+
+ if (value < minValue || value > maxValue) {
+ return;
+ }
+
+ getSharedPreferences().edit().putString(getKey(), "" + value).apply();
+
+ if (getOnPreferenceChangeListener() != null) {
+ getOnPreferenceChangeListener().onPreferenceChange(this, value);
+ }
+ } catch (NumberFormatException e) {
+ // Do not set value
+ }
+ })
+ .create();
+ dialog.show();
+ dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
index 1ca0d0109..31b2cbcb2 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
@@ -16,28 +16,28 @@ import android.net.Uri;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
-import android.preference.CheckBoxPreference;
-import android.preference.EditTextPreference;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceManager;
-import android.preference.PreferenceScreen;
+import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AlertDialog;
-import android.text.Editable;
+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.TextWatcher;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.Log;
-import android.widget.EditText;
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;
@@ -46,7 +46,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
-import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -55,13 +54,13 @@ 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.PreferenceActivityGingerbread;
import de.danoeh.antennapod.activity.StatisticsActivity;
import de.danoeh.antennapod.asynctask.ExportWorker;
-import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.export.ExportWriter;
import de.danoeh.antennapod.core.export.html.HtmlWriter;
import de.danoeh.antennapod.core.export.opml.OpmlWriter;
@@ -69,16 +68,19 @@ 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 rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+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.
@@ -88,19 +90,28 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
private static final String TAG = "PreferenceController";
- private static final String PREF_FLATTR_SETTINGS = "prefFlattrSettings";
+ 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 AUTO_DL_PREF_SCREEN = "prefAutoDownloadSettings";
private static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher";
- public static final String PREF_PLAYBACK_REWIND_DELTA_LAUNCHER = "prefPlaybackRewindDeltaLauncher";
- public static final String PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER = "prefPlaybackFastForwardDeltaLauncher";
+ 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";
@@ -126,7 +137,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
}
};
private CheckBoxPreference[] selectedNetworks;
- private Subscription subscription;
+ private Disposable disposable;
public PreferenceController(PreferenceUI ui) {
this.ui = ui;
@@ -134,30 +145,51 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
.registerOnSharedPreferenceChangeListener(this);
}
- /**
- * Returns the preference activity that should be used on this device.
- *
- * @return PreferenceActivity if the API level is greater than 10, PreferenceActivityGingerbread otherwise.
- */
- public static Class<? extends Activity> getPreferenceActivity() {
- if (Build.VERSION.SDK_INT > 10) {
- return PreferenceActivity.class;
- } else {
- return PreferenceActivityGingerbread.class;
- }
- }
-
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if(key.equals(UserPreferences.PREF_SONIC)) {
- CheckBoxPreference prefSonic = (CheckBoxPreference) ui.findPreference(UserPreferences.PREF_SONIC);
- if(prefSonic != null) {
- prefSonic.setChecked(sharedPreferences.getBoolean(UserPreferences.PREF_SONIC, false));
- }
+
+ }
+
+
+
+ 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;
}
}
- public void onCreate() {
+ private void setupInterfaceScreen() {
final Activity activity = ui.getActivity();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
@@ -172,22 +204,64 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
}
);
}
- ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setOnPreferenceClickListener(
- preference -> {
- FlattrUtils.revokeAccessToken(activity);
- checkItemVisibility();
+ 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(PreferenceController.PREF_ABOUT).setOnPreferenceClickListener(
- preference -> {
- activity.startActivity(new Intent(activity, AboutActivity.class));
+ });
+
+ ui.findPreference(UserPreferences.PREF_COMPACT_NOTIFICATION_BUTTONS)
+ .setOnPreferenceClickListener(preference -> {
+ showNotificationButtonsDialog();
return true;
- }
- );
- ui.findPreference(PreferenceController.STATISTICS).setOnPreferenceClickListener(
+ });
+
+ 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, StatisticsActivity.class));
+ activity.startActivity(new Intent(activity, ImportExportActivity.class));
return true;
}
);
@@ -195,6 +269,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
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 &&
@@ -228,130 +307,70 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
return true;
}
);
- ui.findPreference(UserPreferences.PREF_THEME)
- .setOnPreferenceChangeListener(
- (preference, newValue) -> {
- Intent i = new Intent(activity, MainActivity.class);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_ACTIVITY_NEW_TASK);
- } else {
- i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- }
- activity.finish();
- activity.startActivity(i);
- 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();
}
- );
- ui.findPreference(UserPreferences.PREF_HIDDEN_DRAWER_ITEMS)
- .setOnPreferenceClickListener(preference -> {
- showDrawerPreferencesDialog();
- return true;
- });
+ return true;
+ }
+ return false;
+ }
+ );
+ }
- ui.findPreference(UserPreferences.PREF_COMPACT_NOTIFICATION_BUTTONS)
- .setOnPreferenceClickListener(preference -> {
- showNotificationButtonsDialog();
+ 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(UserPreferences.PREF_UPDATE_INTERVAL)
+ ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS)
.setOnPreferenceClickListener(preference -> {
- showUpdateIntervalTimePreferencesDialog();
- return true;
- });
+ AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity,
+ new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() {
+ @Override
+ public void onCancelled() {
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL).setOnPreferenceChangeListener(
- (preference, newValue) -> {
- if (newValue instanceof Boolean) {
- boolean enabled = (Boolean) newValue;
- ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setEnabled(enabled);
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY).setEnabled(enabled);
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled(enabled);
- setSelectedNetworksEnabled(enabled && UserPreferences.isEnableAutodownloadWifiFilter());
- }
- 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_PARALLEL_DOWNLOADS)
- .setOnPreferenceChangeListener(
- (preference, o) -> {
- if (o instanceof String) {
- try {
- int value = Integer.parseInt((String) o);
- if (1 <= value && value <= 50) {
- setParallelDownloadsText(value);
- return true;
- }
- } catch (NumberFormatException e) {
- return false;
}
- }
- return false;
- }
- );
- // validate and set correct value: number of downloads between 1 and 50 (inclusive)
- final EditText ev = ((EditTextPreference) ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)).getEditText();
- ev.addTextChangedListener(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) {
- if (s.length() > 0) {
- try {
- int value = Integer.parseInt(s.toString());
- if (value <= 0) {
- ev.setText("1");
- } else if (value > 50) {
- ev.setText("50");
- }
- } catch (NumberFormatException e) {
- ev.setText("6");
- }
- ev.setSelection(ev.getText().length());
- }
- }
- });
- ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE)
- .setOnPreferenceChangeListener(
- (preference, o) -> {
- if (o instanceof String) {
- setEpisodeCacheSizeText(UserPreferences.readEpisodeCacheSize((String) o));
- }
- return true;
- }
- );
- 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);
+ @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,
@@ -399,45 +418,127 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(dialog -> updateGpodnetPreferenceScreen());
return true;
});
+ }
- ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS)
+ private void setupPlaybackScreen() {
+ final Activity activity = ui.getActivity();
+
+ ui.findPreference(PreferenceController.PREF_PLAYBACK_SPEED_LAUNCHER)
.setOnPreferenceClickListener(preference -> {
- AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity,
- new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() {
- @Override
- public void onCancelled() {
+ 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;
+ }
+ );
+ }
- @Override
- public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) {
- UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue);
- checkItemVisibility();
- }
- });
+ 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_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();
+ ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)
+ .setOnPreferenceChangeListener(
+ (preference, o) -> {
+ if (o instanceof Integer) {
+ setParallelDownloadsText((Integer) o);
+ }
+ return true;
}
- return true;
- }
- return false;
- }
- );
+ );
+ // 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;
@@ -469,11 +570,76 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
ui.getActivity().startActivity(Intent.createChooser(emailIntent, intentTitle));
return true;
});
- PreferenceControllerFlavorHelper.setupFlavoredUI(ui);
- buildEpisodeCleanupPreference();
- buildSmartMarkAsPlayedPreference();
- buildAutodownloadSelectedNetworsPreference();
- setSelectedNetworksEnabled(UserPreferences.isEnableAutodownloadWifiFilter());
+ }
+
+ 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) {
@@ -485,11 +651,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
final AlertDialog.Builder alert = new AlertDialog.Builder(context)
.setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
Observable<File> observable = new ExportWorker(exportWriter).exportObservable();
- subscription = observable.subscribeOn(Schedulers.newThread())
+ disposable = observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(output -> {
- alert.setTitle(R.string.opml_export_success_title);
- String message = context.getString(R.string.opml_export_success_sum) + output.toString();
+ 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(),
@@ -515,7 +681,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
alert.setTitle(R.string.export_error_label);
alert.setMessage(error.getMessage());
alert.show();
- }, () -> progressDialog.dismiss());
+ }, progressDialog::dismiss);
return true;
}
@@ -529,23 +695,42 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
}
}
- public void onResume() {
- checkItemVisibility();
- setUpdateIntervalText();
- setParallelDownloadsText(UserPreferences.getParallelDownloads());
- setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize());
- setDataFolderText();
- GpodnetPreferences.registerOnSharedPreferenceChangeListener(gpoddernetListener);
- updateGpodnetPreferenceScreen();
+ 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 onPause() {
+ public void unregisterGpodnet() {
GpodnetPreferences.unregisterOnSharedPreferenceChangeListener(gpoddernetListener);
}
- public void onStop() {
- if(subscription != null) {
- subscription.unsubscribe();
+ public void unsubscribeExportSubscription() {
+ if (disposable != null) {
+ disposable.dispose();
}
}
@@ -698,27 +883,32 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
}
}
+ private void setIntegrationsItemVisibility() {
+ ui.findPreference(PreferenceController.PREF_SCREEN_FLATTR).setEnabled(FlattrUtils.hasAPICredentials());
+ }
+
@SuppressWarnings("deprecation")
- private void checkItemVisibility() {
+ private void checkFlattrItemVisibility() {
boolean hasFlattrToken = FlattrUtils.hasToken();
- ui.findPreference(PreferenceController.PREF_FLATTR_SETTINGS).setEnabled(FlattrUtils.hasAPICredentials());
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);
+ }
- boolean autoDownload = UserPreferences.isEnableAutodownload();
+ 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());
+ }
- ui.findPreference(PREF_SEND_CRASH_REPORT).setEnabled(CrashReportWriter.getFile().exists());
-
- if (Build.VERSION.SDK_INT >= 16) {
- ui.findPreference(UserPreferences.PREF_SONIC).setEnabled(true);
- } else {
- Preference prefSonic = ui.findPreference(UserPreferences.PREF_SONIC);
- prefSonic.setSummary("[Android 4.1+]\n" + prefSonic.getSummary());
+ 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);
}
}
@@ -778,7 +968,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
}
}
- private void buildAutodownloadSelectedNetworsPreference() {
+ private static String blankIfNull(String val) {
+ return val == null ? "" : val;
+ }
+
+ private void buildAutodownloadSelectedNetworksPreference() {
final Activity activity = ui.getActivity();
if (selectedNetworks != null) {
@@ -788,67 +982,63 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
WifiManager wifiservice = (WifiManager) activity.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
List<WifiConfiguration> networks = wifiservice.getConfiguredNetworks();
- if (networks != null) {
- Collections.sort(networks, new Comparator<WifiConfiguration>() {
- @Override
- public int compare(WifiConfiguration x, WifiConfiguration y) {
- return x.SSID.compareTo(y.SSID);
+ 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);
}
- });
- selectedNetworks = new CheckBoxPreference[networks.size()];
- List<String> prefValues = Arrays.asList(UserPreferences
- .getAutodownloadSelectedNetworks());
- PreferenceScreen prefScreen = (PreferenceScreen) ui.findPreference(PreferenceController.AUTO_DL_PREF_SCREEN);
- 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);
+ UserPreferences.setAutodownloadSelectedNetworks(
+ prefValuesList.toArray(new String[prefValuesList.size()])
+ );
+ return true;
+ } else {
+ return false;
}
- } else {
- Log.e(TAG, "Couldn't get list of configure Wi-Fi networks");
+ };
+ // 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 = (PreferenceScreen) ui.findPreference(PreferenceController.AUTO_DL_PREF_SCREEN);
+ PreferenceScreen prefScreen = ui.getPreferenceScreen();
for (CheckBoxPreference network : selectedNetworks) {
if (network != null) {
@@ -1013,11 +1203,16 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
public interface PreferenceUI {
+ void setFragment(PreferenceFragmentCompat fragment);
+ PreferenceFragmentCompat getFragment();
+
/**
* Finds a preference based on its key.
*/
Preference findPreference(CharSequence key);
- Activity getActivity();
+ PreferenceScreen getPreferenceScreen();
+
+ AppCompatActivity getActivity();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/SwitchCompatPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/SwitchCompatPreference.java
deleted file mode 100644
index 10c11b88e..000000000
--- a/app/src/main/java/de/danoeh/antennapod/preferences/SwitchCompatPreference.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package de.danoeh.antennapod.preferences;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.os.Build;
-import android.preference.CheckBoxPreference;
-import android.util.AttributeSet;
-
-import de.danoeh.antennapod.R;
-
-public class SwitchCompatPreference extends CheckBoxPreference {
-
- public SwitchCompatPreference(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public SwitchCompatPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init();
- }
-
- public SwitchCompatPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- public SwitchCompatPreference(Context context) {
- super(context);
- init();
- }
-
- private void init() {
- setWidgetLayoutResource(R.layout.preference_switch_layout);
- }
-} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java b/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
deleted file mode 100644
index f0d4014ed..000000000
--- a/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package de.danoeh.antennapod.receiver;
-
-import java.util.Arrays;
-
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProvider;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.text.TextUtils;
-import android.util.Log;
-
-import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.service.PlayerWidgetService;
-
-public class PlayerWidget extends AppWidgetProvider {
- private static final String TAG = "PlayerWidget";
- private static final String PREFS_NAME = "PlayerWidgetPrefs";
- private static final String KEY_ENABLED = "WidgetEnabled";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "onReceive");
- super.onReceive(context, intent);
- // don't do anything if we're not enabled
- if (!isEnabled(context)) {
- return;
- }
-
- // these come from the PlaybackService when things should get updated
- if (TextUtils.equals(intent.getAction(), PlaybackService.FORCE_WIDGET_UPDATE)) {
- startUpdate(context);
- } else if (TextUtils.equals(intent.getAction(), PlaybackService.STOP_WIDGET_UPDATE)) {
- stopUpdate(context);
- }
- }
-
- @Override
- public void onEnabled(Context context) {
- super.onEnabled(context);
- Log.d(TAG, "Widget enabled");
- setEnabled(context, true);
- startUpdate(context);
- }
-
- @Override
- public void onUpdate(Context context, AppWidgetManager appWidgetManager,
- int[] appWidgetIds) {
- Log.d(TAG, "onUpdate() called with: " + "context = [" + context + "], appWidgetManager = [" + appWidgetManager + "], appWidgetIds = [" + Arrays.toString(appWidgetIds) + "]");
- startUpdate(context);
- }
-
- @Override
- public void onDisabled(Context context) {
- super.onDisabled(context);
- Log.d(TAG, "Widget disabled");
- setEnabled(context, false);
- stopUpdate(context);
- }
-
- private void startUpdate(Context context) {
- Log.d(TAG, "startUpdate() called with: " + "context = [" + context + "]");
- context.startService(new Intent(context, PlayerWidgetService.class));
- }
-
- private void stopUpdate(Context context) {
- Log.d(TAG, "stopUpdate() called with: " + "context = [" + context + "]");
- context.stopService(new Intent(context, PlayerWidgetService.class));
- }
-
- private boolean isEnabled(Context context) {
- SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
- return prefs.getBoolean(KEY_ENABLED, false);
- }
-
- private void setEnabled(Context context, boolean enabled) {
- SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
- prefs.edit().putBoolean(KEY_ENABLED, enabled).apply();
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
index a373c5353..c9bd973cb 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
@@ -22,8 +22,8 @@ public class SPAReceiver extends BroadcastReceiver{
private static final String TAG = "SPAReceiver";
public static final String ACTION_SP_APPS_QUERY_FEEDS = "de.danoeh.antennapdsp.intent.SP_APPS_QUERY_FEEDS";
- public static final String ACTION_SP_APPS_QUERY_FEEDS_REPSONSE = "de.danoeh.antennapdsp.intent.SP_APPS_QUERY_FEEDS_RESPONSE";
- public static final String ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA = "feeds";
+ private static final String ACTION_SP_APPS_QUERY_FEEDS_REPSONSE = "de.danoeh.antennapdsp.intent.SP_APPS_QUERY_FEEDS_RESPONSE";
+ private static final String ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA = "feeds";
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java b/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
deleted file mode 100644
index b5bfb1ae4..000000000
--- a/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
+++ /dev/null
@@ -1,245 +0,0 @@
-package de.danoeh.antennapod.service;
-
-import android.app.PendingIntent;
-import android.app.Service;
-import android.appwidget.AppWidgetManager;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Build;
-import android.os.IBinder;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.RemoteViews;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.MainActivity;
-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.receiver.MediaButtonReceiver;
-import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.service.playback.PlayerStatus;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.util.Converter;
-import de.danoeh.antennapod.core.util.playback.Playable;
-import de.danoeh.antennapod.fragment.QueueFragment;
-import de.danoeh.antennapod.receiver.PlayerWidget;
-
-/**
- * Updates the state of the player widget
- */
-public class PlayerWidgetService extends Service {
- private static final String TAG = "PlayerWidgetService";
-
- private PlaybackService playbackService;
-
- /**
- * Controls write access to playbackservice reference
- */
- private Object psLock;
-
- /**
- * True while service is updating the widget
- */
- private volatile boolean isUpdating;
-
- public PlayerWidgetService() {
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- Log.d(TAG, "Service created");
- isUpdating = false;
- psLock = new Object();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- Log.d(TAG, "Service is about to be destroyed");
- if (playbackService != null) {
- Playable playable = playbackService.getPlayable();
- if (playable != null && playable instanceof FeedMedia) {
- FeedMedia media = (FeedMedia) playable;
- if (media.hasAlmostEnded()) {
- Log.d(TAG, "smart mark as read");
- FeedItem item = media.getItem();
- DBWriter.markItemPlayed(item, FeedItem.PLAYED, false);
- DBWriter.removeQueueItem(this, item, false);
- DBWriter.addItemToPlaybackHistory(media);
- if (item.getFeed().getPreferences().getCurrentAutoDelete() &&
- (!item.isTagged(FeedItem.TAG_FAVORITE) || !UserPreferences.shouldFavoriteKeepEpisode())) {
- Log.d(TAG, "Delete " + media.toString());
- DBWriter.deleteFeedMediaOfItem(this, media.getId());
- }
- }
- }
- }
-
- try {
- unbindService(mConnection);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "IllegalArgumentException when trying to unbind service");
- }
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- if (!isUpdating) {
- if (playbackService == null && PlaybackService.isRunning) {
- bindService(new Intent(this, PlaybackService.class),
- mConnection, 0);
- } else {
- startViewUpdaterIfNotRunning();
- }
- } else {
- Log.d(TAG, "Service was called while updating. Ignoring update request");
- }
- return Service.START_NOT_STICKY;
- }
-
- private void updateViews() {
- isUpdating = true;
-
- ComponentName playerWidget = new ComponentName(this, PlayerWidget.class);
- AppWidgetManager manager = AppWidgetManager.getInstance(this);
- RemoteViews views = new RemoteViews(getPackageName(),
- R.layout.player_widget);
- PendingIntent startMediaplayer = PendingIntent.getActivity(this, 0,
- PlaybackService.getPlayerActivityIntent(this), 0);
-
- Intent startApp = new Intent(getBaseContext(), MainActivity.class);
- startApp.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startApp.putExtra(MainActivity.EXTRA_FRAGMENT_TAG, QueueFragment.TAG);
- PendingIntent startAppPending = PendingIntent.getActivity(getBaseContext(), 0, startApp, PendingIntent.FLAG_UPDATE_CURRENT);
-
- boolean nothingPlaying = false;
- if (playbackService != null) {
- final Playable media = playbackService.getPlayable();
- if (media != null) {
- PlayerStatus status = playbackService.getStatus();
- views.setOnClickPendingIntent(R.id.layout_left, startMediaplayer);
-
- views.setTextViewText(R.id.txtvTitle, media.getEpisodeTitle());
-
- String progressString = getProgressString();
- if (progressString != null) {
- views.setViewVisibility(R.id.txtvProgress, View.VISIBLE);
- views.setTextViewText(R.id.txtvProgress, progressString);
- }
-
- if (status == PlayerStatus.PLAYING) {
- views.setImageViewResource(R.id.butPlay, R.drawable.ic_pause_white_24dp);
- if (Build.VERSION.SDK_INT >= 15) {
- views.setContentDescription(R.id.butPlay, getString(R.string.pause_label));
- }
- } else {
- views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp);
- if (Build.VERSION.SDK_INT >= 15) {
- views.setContentDescription(R.id.butPlay, getString(R.string.play_label));
- }
- }
- views.setOnClickPendingIntent(R.id.butPlay,
- createMediaButtonIntent());
- } else {
- nothingPlaying = true;
- }
- } else {
- nothingPlaying = true;
- }
-
- if (nothingPlaying) {
- // start the app if they click anything
- views.setOnClickPendingIntent(R.id.layout_left, startAppPending);
- views.setOnClickPendingIntent(R.id.butPlay, startAppPending);
- views.setViewVisibility(R.id.txtvProgress, View.INVISIBLE);
- views.setTextViewText(R.id.txtvTitle,
- this.getString(R.string.no_media_playing_label));
- views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp);
- }
-
- manager.updateAppWidget(playerWidget, views);
- isUpdating = false;
- }
-
- /**
- * Creates an intent which fakes a mediabutton press
- */
- private PendingIntent createMediaButtonIntent() {
- KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- Intent startingIntent = new Intent(
- MediaButtonReceiver.NOTIFY_BUTTON_RECEIVER);
- startingIntent.putExtra(Intent.EXTRA_KEY_EVENT, event);
-
- return PendingIntent.getBroadcast(this, 0, startingIntent, 0);
- }
-
- private String getProgressString() {
- int position = playbackService.getCurrentPosition();
- int duration = playbackService.getDuration();
- if (position > 0 && duration > 0) {
- return Converter.getDurationStringLong(position) + " / "
- + Converter.getDurationStringLong(duration);
- } else {
- return null;
- }
- }
-
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- Log.d(TAG, "Connection to service established");
- synchronized (psLock) {
- if(service instanceof PlaybackService.LocalBinder) {
- playbackService = ((PlaybackService.LocalBinder) service).getService();
- startViewUpdaterIfNotRunning();
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- synchronized (psLock) {
- playbackService = null;
- Log.d(TAG, "Disconnected from service");
- }
- }
-
- };
-
- private void startViewUpdaterIfNotRunning() {
- if (!isUpdating) {
- ViewUpdater updateThread = new ViewUpdater(this);
- updateThread.start();
- }
- }
-
- class ViewUpdater extends Thread {
- private static final String THREAD_NAME = "ViewUpdater";
- private PlayerWidgetService service;
-
- public ViewUpdater(PlayerWidgetService service) {
- super();
- setName(THREAD_NAME);
- this.service = service;
-
- }
-
- @Override
- public void run() {
- synchronized (psLock) {
- service.updateViews();
- }
- }
-
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java b/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
index 75cbd8b5a..03958508d 100644
--- a/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
+++ b/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
@@ -33,7 +33,7 @@ public class SPAUtil {
* sent before.
*/
public static synchronized boolean sendSPAppsQueryFeedsIntent(Context context) {
- if (context == null) throw new IllegalArgumentException("context = null");
+ assert context != null : "context = null";
final Context appContext = context.getApplicationContext();
if (appContext == null) {
Log.wtf(TAG, "Unable to get application context");
diff --git a/app/src/main/java/de/danoeh/antennapod/view/AspectRatioVideoView.java b/app/src/main/java/de/danoeh/antennapod/view/AspectRatioVideoView.java
index f930c912a..e79389fb3 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/AspectRatioVideoView.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/AspectRatioVideoView.java
@@ -25,6 +25,8 @@ public class AspectRatioVideoView extends VideoView {
private int mVideoWidth;
private int mVideoHeight;
+ private float mAvailableWidth = -1;
+ private float mAvailableHeight = -1;
public AspectRatioVideoView(Context context) {
this(context, null);
@@ -48,8 +50,13 @@ public class AspectRatioVideoView extends VideoView {
return;
}
- float heightRatio = (float) mVideoHeight / (float) getHeight();
- float widthRatio = (float) mVideoWidth / (float) getWidth();
+ if (mAvailableWidth < 0 || mAvailableHeight < 0) {
+ mAvailableWidth = getWidth();
+ mAvailableHeight = getHeight();
+ }
+
+ float heightRatio = (float) mVideoHeight / mAvailableHeight;
+ float widthRatio = (float) mVideoWidth / mAvailableWidth;
int scaledHeight;
int scaledWidth;
@@ -94,4 +101,15 @@ public class AspectRatioVideoView extends VideoView {
invalidate();
}
+ /**
+ * Sets the maximum size that the view might expand to
+ * @param width
+ * @param height
+ */
+ public void setAvailableSize(float width, float height) {
+ mAvailableWidth = width;
+ mAvailableHeight = height;
+ requestLayout();
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java b/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java
index 27b6ee2bc..7ce33e11f 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java
@@ -1,13 +1,13 @@
package de.danoeh.antennapod.view;
import android.content.Context;
+import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
-import android.widget.ImageView;
/**
* From http://stackoverflow.com/a/19449488/6839
*/
-public class SquareImageView extends ImageView {
+public class SquareImageView extends AppCompatImageView {
public SquareImageView(Context context) {
super(context);
@@ -26,6 +26,7 @@ public class SquareImageView extends ImageView {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
+ //noinspection SuspiciousNameCombination
setMeasuredDimension(width, width);
}
diff --git a/app/src/main/play/ar/listing/fulldescription b/app/src/main/play/ar/listing/fulldescription
index 87b477fdc..27abb5532 100644
--- a/app/src/main/play/ar/listing/fulldescription
+++ b/app/src/main/play/ar/listing/fulldescription
@@ -1,4 +1,4 @@
-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>
+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.
diff --git a/app/src/main/play/bg/listing/fulldescription b/app/src/main/play/bg/listing/fulldescription
new file mode 100644
index 000000000..16a005e22
--- /dev/null
+++ b/app/src/main/play/bg/listing/fulldescription
@@ -0,0 +1,43 @@
+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
index 87b477fdc..0e8d76e5e 100644
--- a/app/src/main/play/ca/listing/fulldescription
+++ b/app/src/main/play/ca/listing/fulldescription
@@ -1,43 +1,43 @@
-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>
+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
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
+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
-Have a question or want to give us feedback?
+Teniu preguntes o voleu comentar-nos alguna cosa?
https://twitter.com/@AntennaPod
-Transifex is the place to help with translations:<br>
+Ens podeu ajudar amb les traduccions a Transifex:<br>
https://www.transifex.com/antennapod/antennapod
-Check out our Beta Testing programme to get the latest features first:<br>
+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/listing/video b/app/src/main/play/ca/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/ca/listing/video
+++ /dev/null
diff --git a/app/src/main/play/contactPhone b/app/src/main/play/contactPhone
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/contactPhone
+++ /dev/null
diff --git a/app/src/main/play/cs-CZ/listing/video b/app/src/main/play/cs-CZ/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/cs-CZ/listing/video
+++ /dev/null
diff --git a/app/src/main/play/da-DK/listing/video b/app/src/main/play/da-DK/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/da-DK/listing/video
+++ /dev/null
diff --git a/app/src/main/play/de-DE/listing/video b/app/src/main/play/de-DE/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/de-DE/listing/video
+++ /dev/null
diff --git a/app/src/main/play/de/listing/fulldescription b/app/src/main/play/de/listing/fulldescription
index e5d7ec72a..0e09c5c29 100644
--- a/app/src/main/play/de/listing/fulldescription
+++ b/app/src/main/play/de/listing/fulldescription
@@ -1,4 +1,4 @@
-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 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 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>
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.
@@ -24,7 +24,7 @@ STEUER DAS SYSTEM<br>
&#8226; Passe das Aussehen mit dem hellen oder dunklen Theme an<br>
&#8226; Sichere deine Abonnements mit gPodder.net oder über den OPML-Export
-<b>Trete der AntennaPod-Community bei!</b><br>
+<b>Tritt der AntennaPod-Community bei!</b><br>
AntennaPod wird aktiv von Freiwilligen weiterentwickelt. Auch du kannst bei der Entwicklung mit Quellcode oder Kommentaren mitwirken!
Wir verwenden GitHub für Funktionswünsche (Feature Requests), Fehlerberichte (Bug Reports) und zum Beisteuern von Code (Code Contributions).
diff --git a/app/src/main/play/el/listing/fulldescription b/app/src/main/play/el/listing/fulldescription
index 87b477fdc..f0ec3ae38 100644
--- a/app/src/main/play/el/listing/fulldescription
+++ b/app/src/main/play/el/listing/fulldescription
@@ -1,11 +1,11 @@
-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 είναι μία εφαρμογή διαχείρισης και εκτέλεσης podcasts που σας δίνει άμεση πρόσβαση σε εκατομμύρια δωρεάν και επί πληρωμή podcasts, από ανεξάρτητους podcasters έως μεγάλους εκδοτικούς οίκους όπως το BBC, NPR και CNN. Μπορείτε εύκολα να προσθέσετε, να εισάγετε και να εξάγετε τις ροές τους χρησιμοποιώντας τη βάση δεδομένων podcast του iTunes, αρχεία OPML ή απλά RSS URLs. Γλυτώστε προσπάθεια, μπαταρία και χρήση δεδομένων κινητής τηλεφωνίας με ισχυρές ρυθμίσεις αυτοματισμών για λήψη επεισοδίων (ορίστε τους χρόνους, τα διαστήματα και τα δίκτυα WiFi) και σβήστε επεισόδια (με βάση τα αγαπημένα σας και τις ρυθμίσεις καθυστέρησης).<br>
+Αλλά το πλέον σημαντικό: Κατεβάστε, κάντε stream ή βάλτε στη σειρά επεισόδια και απολαύστε τα όπως επιθυμήτε με ρυθμιζόμενη ταχύτητα αναπαραγωγής, υποστήριξη κεφάλαιων και χρονόμετρο απενεργοποίησης. Μπορείτε ακόμη και να δείξετε την αγάπη σας στους δημιουργούς περιεχομένου μέσω της ενσωμάτωσης του Flattr.
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
+Φτιαγμένο από λάτρη των podcast, το AntennaPod είναι ελεύθερο με όλες τις έννοιες της λέξης: ανοικτού λογισμικού, χωρίς κόστη, χωρίς διαφημίσεις.
-<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>
+<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>
@@ -24,20 +24,20 @@ CONTROL THE SYSTEM<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!
+<b>Ενταχθείτε στη κοινότητα του AntennaPod!</b><br>
+Το AntennaPod βρίσκεται υπό ενεργή ανάπτυξη από εθελοντές. Μπορείτε και εσείς να συνεισφέρετε, με κώδικα ή με κάποιο σχόλιο.
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
+Το 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>
+Το Google Group μας είναι το μέρος να μοιραστείτε τις ιδέες σας, τις αγαπημένες σας στιγμές ενασχόλησης με τα podcasts και ευγνωμοσύνη σε όλους τους εθελοντές:<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>
+Το Transifex είναι το μέρος για να βοηθήσετε με τις μεταφράσεις:<br>
https://www.transifex.com/antennapod/antennapod
-Check out our Beta Testing programme to get the latest features first:<br>
+Ελέγξτε το πρόγραμμά μας 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/featureGraphic/feature-graphic.png b/app/src/main/play/en-US/listing/featureGraphic/feature-graphic.png
new file mode 100644
index 000000000..3b5261b28
--- /dev/null
+++ b/app/src/main/play/en-US/listing/featureGraphic/feature-graphic.png
Binary files differ
diff --git a/app/src/main/play/en-US/listing/video b/app/src/main/play/en-US/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/en-US/listing/video
+++ /dev/null
diff --git a/app/src/main/play/es-ES/listing/video b/app/src/main/play/es-ES/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/es-ES/listing/video
+++ /dev/null
diff --git a/app/src/main/play/es/listing/fulldescription b/app/src/main/play/es/listing/fulldescription
index 2f1c8861a..96f914f26 100644
--- a/app/src/main/play/es/listing/fulldescription
+++ b/app/src/main/play/es/listing/fulldescription
@@ -1,4 +1,4 @@
-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>
+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.
diff --git a/app/src/main/play/fa/listing/fulldescription b/app/src/main/play/fa/listing/fulldescription
index 87b477fdc..0a005f962 100644
--- a/app/src/main/play/fa/listing/fulldescription
+++ b/app/src/main/play/fa/listing/fulldescription
@@ -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 یک نرم افزار مدیریت و پخش پادکست میباشد که به شما امکان دسترسی سریع به میلیون ها پادکست رایگان و پرداخت شده ، از طریق انتشارات بزرگ و مستقل مانند بی بی سی، 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.
diff --git a/app/src/main/play/fr-FR/listing/video b/app/src/main/play/fr-FR/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/fr-FR/listing/video
+++ /dev/null
diff --git a/app/src/main/play/he_IL/listing/fulldescription b/app/src/main/play/he_IL/listing/fulldescription
index b4ac8ca6c..4ccee5452 100644
--- a/app/src/main/play/he_IL/listing/fulldescription
+++ b/app/src/main/play/he_IL/listing/fulldescription
@@ -1,43 +1,43 @@
-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.
+היישומון אנטנה־פּוֹד הוא נגן ומנהל פודקאסטים שמעניק לך גישה ישירה למיליונים של פודקאסטים בחינם ובתשלום, החל ממגישי פודקאסטים עצמאיים ועד למפיצים גדולים כגון BBC,‏ NPR ו־CNN. ניתן להוסיף, לייבא ולייצא את ההזנות שלהם בקלות יחסית באמצעות מסד נתוני הפודקאסטים של iTunes, קובצי OPML או כתובות של RSS. מאפשר לך לחסוך במאמץ, סוללה ותקשורת נתונים עם פקדי אוטומציה להורדה של פרקים (לפי זמנים, הפרשי זמן ורשתות אלחוטיות) ומחיקה של פרקים (על בסיס הגדרות המועדפים וההשהיה שלך).<br>
+אבל הכי חשוב: ניתן להוריד, להזרים או לסדר רשימות של פרקים וליהנות מהם בכל דרך שמתאימה לך עם מהירויות נגינה משתנות, תמיכה במקטעים ומתזמן שינה. ניתן אפילו להביע את חיבתך ליוצרי התוכן עם שילוב של Flattr ביישומון.
מיוצרת על ידי חובבי פודקאסטים, אנטנהפוד הינה תוכנה חינמית בכל מובן המילה: קוד פתוח, ללא עלות וללא פרסומות.
-<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>
+<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
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
+הקבוצה שלנו ב־Google היא המקום לשתף את הרעיונות שלך, רגעי הפודקאסט המועדפים עליך ואת הערכתך לכל המתנדבים:<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>
+Transifex הוא המקום לסייע בתרגומים:<br>
https://www.transifex.com/antennapod/antennapod
-Check out our Beta Testing programme to get the latest features first:<br>
+מזמינים אותך לחקור את תכנית הבדיקות שלנו כדי לקבל את התכונות העדכניות ביותר לפני כולם:<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/video b/app/src/main/play/hi-IN/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/hi-IN/listing/video
+++ /dev/null
diff --git a/app/src/main/play/it-IT/listing/video b/app/src/main/play/it-IT/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/it-IT/listing/video
+++ /dev/null
diff --git a/app/src/main/play/it/listing/fulldescription b/app/src/main/play/it/listing/fulldescription
index 307f86117..3d0425660 100644
--- a/app/src/main/play/it/listing/fulldescription
+++ b/app/src/main/play/it/listing/fulldescription
@@ -1,36 +1,36 @@
-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 è 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.
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
+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; 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; 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; Take advantage of paged feeds (www.podlove.org/paged-feeds)
+&#8226; Approfitta dei <i>paged feeds</i> (www.podlove.org/paged-feeds)
-TIENI TRACCIA, CONDIVIDI & APPREZZA<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
+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; 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; 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; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
+&#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 is under active development by volunteers. You can contribute too, with code or with comment!
+AntennaPod è in fase attiva di sviluppo da parte di volontari. Anche te puoi contribuire, con codice o commenti!
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
+Per chiedere nuove funzioni, contribuire con del codice o segnalare problemi, puoi trovarci su GitHub:
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>
+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?
diff --git a/app/src/main/play/it_IT/listing/fulldescription b/app/src/main/play/it_IT/listing/fulldescription
index eb2abb40d..31fa64d69 100644
--- a/app/src/main/play/it_IT/listing/fulldescription
+++ b/app/src/main/play/it_IT/listing/fulldescription
@@ -1,28 +1,28 @@
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>
-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.
+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à.
<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; Gestisci la riproduzione da dove vuoi: widget sulla schermata Home, notifiche di sistema e controlli sugli auricolari e via bluetooth. <br>
+&#8226; Divertiti ad ascoltare nel modo che preferisci grazie alla velocità di riproduzione variabile, il supporto ai capitoli (MP3, VorbisComment e Podlove), la memorizzazione dell'avanzamento di riproduzione e un timer di spegnimento avanzato (scuoti per resettare, volume basso e rallentamento della velocità)<br>
&#8226; Accedi a feed e episodi protetti da password<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
+&#8226; Sfrutta i vantaggi dei paged feeds (www.podlove.org/paged-feeds)
TIENI TRACCIA, CONDIVIDI & APPREZZA<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; Tieni traccia del meglio del meglio segnando gli episodi come Preferiti<br>
+&#8226; Trova l'episodio specifico grazie alla cronologia di riproduzione o al sistema di ricerca (titoli e note dell'episodio)<br>
+&#8226; Condividi gli episodi e i feed tramite le avanzate opzioni social ed email, il servizio gPodder.net e l'esportazione in OPML<br>
&#8226; Supporta i creatori di contenuti tramite l'integrazione con Flattr e il flattring automatico
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; Prendi il controllo grazie ai download automatici: scegli i feed, escludi le reti mobili, seleziona reti WiFi specifiche, richiedi che il telefono sia in carica e imposta tempi e intervalli di aggiornamento<br>
+&#8226; Gestisci lo spazio impostando l'occupazione massima, la cancellazione intelligente (basata sui Preferiti e sullo stato di riproduzione) e selezionando la posizione che preferisci <br>
&#8226; Usa AntennaPod nella tua lingua (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
+&#8226; Adattati all'ambiente in cui ti trovi con i temi Chiaro e Scuro.<br>
+&#8226; Salva le sottoscrizioni grazie all'integrazione con gPodder.net e l'esportazione OPML
<b>Entra nella community di AntennaPod!</b><br>
AntennaPod è sviluppato da volontari. Anche tu puoi contribuire, con il codice o con dei commenti!
@@ -30,7 +30,7 @@ AntennaPod è sviluppato da volontari. Anche tu puoi contribuire, con il codice
GitHub è il posto nel quale fare richieste, segnalare bug e contribuire allo sviluppo:<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>
+Il nostro gruppo Google è il luogo ideale dove condividere le idee, stimolare momenti di podcasting e ringraziare tutti i volontari:<br>
https://groups.google.com/forum/#!forum/antennapod
Hai una domanda o vuoi darci un feedback?
diff --git a/app/src/main/play/iw-IL/listing/video b/app/src/main/play/iw-IL/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/iw-IL/listing/video
+++ /dev/null
diff --git a/app/src/main/play/ja-JP/listing/video b/app/src/main/play/ja-JP/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/ja-JP/listing/video
+++ /dev/null
diff --git a/app/src/main/play/ko-KR/listing/video b/app/src/main/play/ko-KR/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/ko-KR/listing/video
+++ /dev/null
diff --git a/app/src/main/play/ms_MY/listing/fulldescription b/app/src/main/play/ms_MY/listing/fulldescription
new file mode 100644
index 000000000..87b477fdc
--- /dev/null
+++ b/app/src/main/play/ms_MY/listing/fulldescription
@@ -0,0 +1,43 @@
+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
index 11bc6fd9f..460a880fe 100644
--- a/app/src/main/play/nb_NO/listing/fulldescription
+++ b/app/src/main/play/nb_NO/listing/fulldescription
@@ -18,7 +18,7 @@ FØLG MED, DEL OG SETT PRIS PÅ<br>
&#8226; Støtt innholdsskapere med Flattr-integrasjon gjennom automatisk &#171;flattring&#187;
KONTROLLER SYSTEMET<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; 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>
@@ -33,11 +33,11 @@ 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?
+Har du spørsmål eller vil du gi oss tilbakemelding?
https://twitter.com/@AntennaPod
-Transifex is the place to help with translations:<br>
+Transifex er stedet for å hjelpe til med oversettinger:<br>
https://www.transifex.com/antennapod/antennapod
-Check out our Beta Testing programme to get the latest features first:<br>
+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/video b/app/src/main/play/nl-NL/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/nl-NL/listing/video
+++ /dev/null
diff --git a/app/src/main/play/pl-PL/listing/video b/app/src/main/play/pl-PL/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/pl-PL/listing/video
+++ /dev/null
diff --git a/app/src/main/play/pt-BR/listing/video b/app/src/main/play/pt-BR/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/pt-BR/listing/video
+++ /dev/null
diff --git a/app/src/main/play/pt-PT/listing/video b/app/src/main/play/pt-PT/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/pt-PT/listing/video
+++ /dev/null
diff --git a/app/src/main/play/ro/listing/video b/app/src/main/play/ro/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/ro/listing/video
+++ /dev/null
diff --git a/app/src/main/play/ru-RU/listing/video b/app/src/main/play/ru-RU/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/ru-RU/listing/video
+++ /dev/null
diff --git a/app/src/main/play/sl_SI/listing/fulldescription b/app/src/main/play/sl_SI/listing/fulldescription
new file mode 100644
index 000000000..87b477fdc
--- /dev/null
+++ b/app/src/main/play/sl_SI/listing/fulldescription
@@ -0,0 +1,43 @@
+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/video b/app/src/main/play/sv-SE/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/sv-SE/listing/video
+++ /dev/null
diff --git a/app/src/main/play/tr-TR/listing/video b/app/src/main/play/tr-TR/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/tr-TR/listing/video
+++ /dev/null
diff --git a/app/src/main/play/uk/listing/video b/app/src/main/play/uk/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/uk/listing/video
+++ /dev/null
diff --git a/app/src/main/play/vi/listing/fulldescription b/app/src/main/play/vi/listing/fulldescription
index 87b477fdc..9519b5da1 100644
--- a/app/src/main/play/vi/listing/fulldescription
+++ b/app/src/main/play/vi/listing/fulldescription
@@ -3,7 +3,7 @@ But most importantly: Download, stream or queue episodes and enjoy them the way
Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-<b>All features:</b><br>
+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>
@@ -17,14 +17,14 @@ KEEP TRACK, SHARE & APPRECIATE<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>
+Đ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
-<b>Join the AntennaPod community!</b><br>
+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>
@@ -33,7 +33,7 @@ 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?
+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>
diff --git a/app/src/main/play/zh-CN/listing/video b/app/src/main/play/zh-CN/listing/video
deleted file mode 100644
index e69de29bb..000000000
--- a/app/src/main/play/zh-CN/listing/video
+++ /dev/null
diff --git a/app/src/main/res/layout-v14/authentication_dialog.xml b/app/src/main/res/layout-v14/authentication_dialog.xml
deleted file mode 100644
index 00e74c9e1..000000000
--- a/app/src/main/res/layout-v14/authentication_dialog.xml
+++ /dev/null
@@ -1,87 +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" >
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
-
- <EditText
- android:id="@+id/etxtUsername"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:layout_margin="16dp"
- android:hint="@string/username_label"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:cursorVisible="true"/>
-
- <EditText
- android:id="@+id/etxtPassword"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:layout_margin="16dp"
- android:inputType="textPassword"
- android:hint="@string/password_label"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:cursorVisible="true"/>
-
- <CheckBox
- android:id="@+id/chkSaveUsernamePassword"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="16dp"
- android:text="@string/save_username_password_label"/>
- </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_alignParentTop="true"
- android:layout_toLeftOf="@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_alignParentTop="true"
- android:layout_toRightOf="@id/horizontal_divider"
- android:background="?android:attr/selectableItemBackground"
- android:text="@string/confirm_label" />
- </RelativeLayout>
-
-</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout-v14/directory_chooser.xml b/app/src/main/res/layout-v14/directory_chooser.xml
deleted file mode 100644
index 14e2f6a38..000000000
--- a/app/src/main/res/layout-v14/directory_chooser.xml
+++ /dev/null
@@ -1,114 +0,0 @@
-<?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"
- tools:background="@android:color/darker_gray">
-
- <RelativeLayout
- android:id="@+id/footer"
- android:layout_width="fill_parent"
- android:layout_height="48dp"
- android:layout_alignParentBottom="true" >
-
- <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_alignParentTop="true"
- android:layout_toLeftOf="@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_alignParentTop="true"
- android:layout_toRightOf="@id/horizontal_divider"
- android:background="?android:attr/selectableItemBackground"
- android:text="@string/confirm_label" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/directory_info"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true" >
-
- <ImageButton
- android:id="@+id/butNavUp"
- android:contentDescription="@string/navigate_upwards_label"
- android:layout_width="60dp"
- android:layout_height="60dp"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:background="?attr/selectableItemBackground"
- android:src="?attr/navigation_up"
- tools:src="@drawable/navigation_up"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvSelectedFolderLabel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="8dp"
- android:layout_toRightOf="@id/butNavUp"
- android:text="@string/selected_folder_label"
- android:textStyle="bold"
- tools:background="@android:color/holo_green_dark">
- </TextView>
-
- <TextView
- android:id="@+id/txtvSelectedFolder"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/txtvSelectedFolderLabel"
- android:layout_margin="8dp"
- android:layout_toRightOf="@id/butNavUp"
- android:ellipsize="start"
- android:scrollHorizontally="true"
- android:singleLine="true"
- tools:text="/path/to/selected/folder"
- tools:background="@android:color/holo_green_dark"/>
-
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_below="@id/butNavUp"
- android:background="@color/holo_blue_light" />
- </RelativeLayout>
-
- <ListView
- android:id="@+id/directory_list"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_above="@id/footer"
- android:layout_below="@id/directory_info" />
-
-</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout-v14/download_authentication_activity.xml b/app/src/main/res/layout-v14/download_authentication_activity.xml
deleted file mode 100644
index f6925dc3a..000000000
--- a/app/src/main/res/layout-v14/download_authentication_activity.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/authentication_notification_title"
- android:layout_alignParentTop="true"
- android:textSize="@dimen/text_size_large"
- android:layout_margin="16dp"
- android:textColor="@color/holo_blue_light"
- android:textStyle="italic"/>
-
- <TextView
- android:id="@+id/txtvDescription"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/authentication_notification_msg"
- android:layout_below="@id/txtvTitle"
- android:textSize="@dimen/text_size_medium"
- android:textColor="?android:attr/textColorSecondary"
- android:layout_margin="16dp"/>
-
- <EditText
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="16dp"
- android:id="@+id/etxtUsername"
- android:hint="@string/username_label"
- android:layout_below="@id/txtvDescription"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:cursorVisible="true"/>
-
- <EditText
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="16dp"
- android:id="@+id/etxtPassword"
- android:hint="@string/password_label"
- android:inputType="textPassword"
- android:layout_below="@id/etxtUsername"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:cursorVisible="true"/>
-
- <RelativeLayout
- android:id="@+id/footer"
- android:layout_width="fill_parent"
- android:layout_height="48dp"
- android:focusableInTouchMode="true"
- android:layout_alignParentBottom="true">
-
- <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_alignParentTop="true"
- android:layout_toLeftOf="@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_alignParentTop="true"
- android:layout_toRightOf="@id/horizontal_divider"
- android:background="?android:attr/selectableItemBackground"
- android:text="@string/confirm_label"/>
- </RelativeLayout>
-
-
-</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout-v14/opml_selection.xml b/app/src/main/res/layout-v14/opml_selection.xml
deleted file mode 100644
index 3133debd1..000000000
--- a/app/src/main/res/layout-v14/opml_selection.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?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" >
-
- <RelativeLayout
- android:id="@+id/footer"
- android:layout_width="fill_parent"
- android:layout_height="48dp"
- android:layout_alignParentBottom="true" >
-
- <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_alignParentTop="true"
- android:layout_toLeftOf="@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_alignParentTop="true"
- android:layout_toRightOf="@id/horizontal_divider"
- android:background="?android:attr/selectableItemBackground"
- android:text="@string/confirm_label" />
- </RelativeLayout>
-
- <ListView
- android:id="@+id/feedlist"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_above="@id/footer"
- android:layout_alignParentTop="true"
- tools:listitem="@android:layout/simple_list_item_multiple_choice" >
- </ListView>
-
-</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout-v14/time_dialog.xml b/app/src/main/res/layout-v14/time_dialog.xml
deleted file mode 100644
index ba4249268..000000000
--- a/app/src/main/res/layout-v14/time_dialog.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:gravity="center">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
-
- <EditText
- android:id="@+id/etxtTime"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_margin="8dp"
- android:ems="2"
- android:hint="@string/enter_time_here_label"
- android:inputType="number"
- android:maxLength="2" >
-
- <requestFocus />
- </EditText>
-
- <Spinner
- android:id="@+id/spTimeUnit"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginTop="8dp" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/timer_about_to_expire_label"
- android:textSize="16sp" />
-
- <CheckBox
- android:id="@+id/cbShakeToReset"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/shake_to_reset_label" />
-
- <CheckBox
- android:id="@+id/cbVibrate"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/timer_vibration_label" />
-
- <CheckBox
- android:id="@+id/chAutoEnable"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/auto_enable_label" />
-
- </LinearLayout>
-
-</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/about.xml b/app/src/main/res/layout/about.xml
index 02e232d9a..42f5e1245 100644
--- a/app/src/main/res/layout/about.xml
+++ b/app/src/main/res/layout/about.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/webvContainer"
+ android:id="@+id/webViewContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<WebView
- android:id="@+id/webvAbout"
+ android:id="@+id/webViewAbout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
diff --git a/app/src/main/res/layout/all_episodes_fragment.xml b/app/src/main/res/layout/all_episodes_fragment.xml
index 5336fb8ce..89f900a1f 100644
--- a/app/src/main/res/layout/all_episodes_fragment.xml
+++ b/app/src/main/res/layout/all_episodes_fragment.xml
@@ -10,10 +10,12 @@
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:scrollbarStyle="outsideOverlay"
+ android:clipToPadding="false"
android:paddingTop="@dimen/list_vertical_padding"
android:paddingBottom="@dimen/list_vertical_padding"
- android:clipToPadding="false"/>
+ android:scrollbarStyle="outsideOverlay"
+ tools:itemCount="13"
+ tools:listitem="@layout/new_episodes_listitem" />
<ProgressBar
android:id="@+id/progLoading"
@@ -22,7 +24,7 @@
android:layout_gravity="center"
android:indeterminateOnly="true"
android:visibility="gone"
- tools:visibility="visible"
+ tools:visibility="gone"
tools:layout_width="match_parent"
tools:layout_height="64dp"
tools:background="@android:color/holo_red_light"/>
diff --git a/app/src/main/res/layout/audio_controls.xml b/app/src/main/res/layout/audio_controls.xml
index 852b6e922..f03e4c03f 100644
--- a/app/src/main/res/layout/audio_controls.xml
+++ b/app/src/main/res/layout/audio_controls.xml
@@ -21,6 +21,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
android:text="1.00x"/>
</LinearLayout>
@@ -35,6 +36,7 @@
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:gravity="center"
android:text="-"
android:textStyle="bold"
@@ -48,6 +50,7 @@
android:layout_height="32dp"
android:minWidth="0dp"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:gravity="center"
android:text="+"
android:textStyle="bold"
@@ -60,7 +63,9 @@
android:layout_width="match_parent"
android:layout_height="32dp"
android:layout_toRightOf="@id/butDecSpeed"
+ android:layout_toEndOf="@id/butDecSpeed"
android:layout_toLeftOf="@id/butIncSpeed"
+ android:layout_toStartOf="@id/butIncSpeed"
android:layout_centerVertical="true"
android:max="40"/>
@@ -79,6 +84,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="-12dp"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:orientation="horizontal"
android:gravity="center">
@@ -101,6 +107,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:orientation="horizontal"
android:gravity="center">
diff --git a/app/src/main/res/layout/authentication_dialog.xml b/app/src/main/res/layout/authentication_dialog.xml
index e18ab42eb..187045c63 100644
--- a/app/src/main/res/layout/authentication_dialog.xml
+++ b/app/src/main/res/layout/authentication_dialog.xml
@@ -1,14 +1,13 @@
<?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">
+ android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:orientation="vertical" >
<EditText
android:id="@+id/etxtUsername"
@@ -39,30 +38,54 @@
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="@string/save_username_password_label"/>
+ </LinearLayout>
+ <RelativeLayout
+ android:id="@+id/footer"
+ android:layout_width="fill_parent"
+ android:layout_height="48dp" >
- </LinearLayout>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:layout_alignParentTop="true"
+ android:background="?android:attr/dividerVertical" />
- <LinearLayout
- style="@android:style/ButtonBar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
+ <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/butConfirm"
- android:layout_width="0dp"
+ android:id="@+id/butCancel"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginRight="8dp"
- android:text="@string/confirm_label"
- android:layout_weight="1"/>
+ 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/butCancel"
- android:text="@string/cancel_label"
- android:layout_width="0dp"
+ android:id="@+id/butConfirm"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"/>
- </LinearLayout>
+ 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> \ No newline at end of file
diff --git a/app/src/main/res/layout/cover_fragment.xml b/app/src/main/res/layout/cover_fragment.xml
index 9ad1ff9c6..b1e93a195 100644
--- a/app/src/main/res/layout/cover_fragment.xml
+++ b/app/src/main/res/layout/cover_fragment.xml
@@ -16,6 +16,7 @@
android:scaleType="fitCenter"
app:layout_aspectRatio="100%"
app:layout_widthPercent="82%"
+ android:transitionName="coverTransition"
tools:src="@android:drawable/sym_def_app_icon" />
<LinearLayout
@@ -37,6 +38,7 @@
android:maxLines="2"
android:ellipsize="end"
android:text="Podcast"
+ android:textIsSelectable="true"
android:textColor="?android:attr/textColorSecondary" />
</LinearLayout>
@@ -60,6 +62,7 @@
android:maxLines="2"
android:ellipsize="end"
android:text="Episode"
+ android:textIsSelectable="true"
android:textColor="?android:attr/textColorPrimary" />
</LinearLayout>
diff --git a/app/src/main/res/layout/directory_chooser.xml b/app/src/main/res/layout/directory_chooser.xml
index 635a73cf4..5b9269607 100644
--- a/app/src/main/res/layout/directory_chooser.xml
+++ b/app/src/main/res/layout/directory_chooser.xml
@@ -2,30 +2,57 @@
<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" >
+ android:layout_height="match_parent"
+ tools:background="@android:color/darker_gray">
- <LinearLayout
+ <RelativeLayout
android:id="@+id/footer"
- style="@android:style/ButtonBar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:orientation="horizontal" >
+ android:layout_width="fill_parent"
+ android:layout_height="48dp"
+ android:layout_alignParentBottom="true" >
- <Button
- android:id="@+id/butConfirm"
- android:layout_width="0px"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/confirm_label" />
+ <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="0px"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"
+ 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" />
- </LinearLayout>
+
+ <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>
<RelativeLayout
android:id="@+id/directory_info"
@@ -39,6 +66,7 @@
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="?attr/selectableItemBackground"
android:src="?attr/navigation_up"
@@ -54,9 +82,10 @@
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:layout_toRightOf="@id/butNavUp"
+ android:layout_toEndOf="@id/butNavUp"
android:text="@string/selected_folder_label"
android:textStyle="bold"
- tools:background="@android:color/holo_blue_bright">
+ tools:background="@android:color/holo_green_dark">
</TextView>
<TextView
@@ -64,14 +93,16 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_below="@id/txtvSelectedFolderLabel"
android:layout_margin="8dp"
android:layout_toRightOf="@id/butNavUp"
+ android:layout_toEndOf="@id/butNavUp"
android:ellipsize="start"
android:scrollHorizontally="true"
android:singleLine="true"
tools:text="/path/to/selected/folder"
- tools:background="@android:color/holo_blue_bright"/>
+ tools:background="@android:color/holo_green_dark"/>
<View
android:id="@+id/divider"
diff --git a/app/src/main/res/layout/download_authentication_activity.xml b/app/src/main/res/layout/download_authentication_activity.xml
index 27604973a..3414a5e00 100644
--- a/app/src/main/res/layout/download_authentication_activity.xml
+++ b/app/src/main/res/layout/download_authentication_activity.xml
@@ -48,28 +48,55 @@
android:focusableInTouchMode="true"
android:cursorVisible="true"/>
- <LinearLayout
+ <RelativeLayout
android:id="@+id/footer"
- style="@android:style/ButtonBar"
android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:orientation="horizontal">
+ android:layout_height="48dp"
+ android:focusableInTouchMode="true"
+ android:layout_alignParentBottom="true">
- <Button
- android:id="@+id/butConfirm"
- android:layout_width="0px"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/confirm_label"/>
+ <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="0px"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"
+ 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"/>
- </LinearLayout>
+
+ <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>
</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/downloaded_episodeslist_item.xml b/app/src/main/res/layout/downloaded_episodeslist_item.xml
index 760b6b9db..66ae6c180 100644
--- a/app/src/main/res/layout/downloaded_episodeslist_item.xml
+++ b/app/src/main/res/layout/downloaded_episodeslist_item.xml
@@ -1,9 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
-
<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="@dimen/listitem_threeline_height"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
tools:background="@android:color/darker_gray">
@@ -14,68 +13,76 @@
android:layout_gravity="center_vertical"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:contentDescription="@string/cover_label"
android:scaleType="centerCrop"
tools:src="@drawable/ic_stat_antenna_default"
- tools:background="@android:color/holo_green_dark" />
+ tools:background="@android:color/holo_green_dark"/>
+
- <RelativeLayout
+ <LinearLayout
android:layout_width="0dp"
- android:layout_height="@dimen/thumbnail_length_downloaded_item"
+ android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/listitem_threeline_textleftpadding"
+ android:layout_marginStart="@dimen/listitem_threeline_textleftpadding"
android:layout_marginRight="@dimen/listitem_threeline_textrightpadding"
+ android:layout_marginEnd="@dimen/listitem_threeline_textrightpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:layout_weight="1"
+ android:orientation="vertical"
tools:background="@android:color/holo_red_dark">
<TextView
android:id="@+id/txtvTitle"
style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_centerVertical="true"
android:layout_marginBottom="4dp"
tools:text="Downloaded episode title"
- tools:background="@android:color/holo_green_dark" />
+ tools:background="@android:color/holo_green_dark"/>
- <TextView
- android:id="@+id/txtvSize"
- style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
- android:layout_width="wrap_content"
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentBottom="true"
- tools:text="23 MB"
- tools:background="@android:color/holo_green_dark" />
+ tools:background="@android:color/holo_red_dark" >
- <TextView
- android:id="@+id/txtvPublished"
- style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentBottom="true"
- android:layout_marginLeft="8dp"
- tools:text="Jan 23"
- tools:background="@android:color/holo_green_dark" />
+ <TextView
+ android:id="@+id/txtvSize"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ tools:text="23 MB"
+ tools:background="@android:color/holo_green_dark"/>
+
+ <View
+ android:layout_width="0dip"
+ android:layout_height="1dip"
+ android:layout_weight="1" />
+
+ <ImageView
+ android:id="@+id/imgvInPlaylist"
+ android:layout_width="@dimen/enc_icons_size"
+ android:layout_height="@dimen/enc_icons_size"
+ android:contentDescription="@string/in_queue_label"
+ android:src="?attr/stat_playlist"
+ android:visibility="visible"
+ tools:src="@drawable/ic_list_white_24dp"
+ tools:background="@android:color/holo_red_light"/>
- <ImageView
- android:id="@+id/imgvInPlaylist"
- android:layout_width="@dimen/enc_icons_size"
- android:layout_height="@dimen/enc_icons_size"
- android:layout_toLeftOf="@id/txtvPublished"
- android:layout_alignParentBottom="true"
- android:contentDescription="@string/in_queue_label"
- android:src="?attr/stat_playlist"
- android:visibility="visible"
- tools:src="@drawable/ic_list_white_24dp"
- tools:background="@android:color/holo_red_light" />
+ <TextView
+ android:id="@+id/txtvPublished"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
+ tools:text="Jan 23"
+ tools:background="@android:color/holo_green_dark"/>
- </RelativeLayout>
+ </LinearLayout>
+ </LinearLayout>
<include layout="@layout/vertical_list_divider"/>
diff --git a/app/src/main/res/layout/downloadlist_item.xml b/app/src/main/res/layout/downloadlist_item.xml
index e7694502b..668ec817a 100644
--- a/app/src/main/res/layout/downloadlist_item.xml
+++ b/app/src/main/res/layout/downloadlist_item.xml
@@ -2,13 +2,13 @@
<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="@dimen/listitem_threeline_height"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
tools:background="@android:color/darker_gray">
<LinearLayout
android:layout_width="0dp"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
@@ -17,6 +17,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:ellipsize="end"
android:lines="1"
@@ -48,6 +49,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:ellipsize="end"
android:lines="1"
android:textColor="?android:attr/textColorPrimary"
@@ -60,6 +62,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:ellipsize="end"
android:lines="1"
android:textColor="?android:attr/textColorPrimary"
diff --git a/app/src/main/res/layout/downloadlog_item.xml b/app/src/main/res/layout/downloadlog_item.xml
index 7b4773bca..505102ea4 100644
--- a/app/src/main/res/layout/downloadlog_item.xml
+++ b/app/src/main/res/layout/downloadlog_item.xml
@@ -8,14 +8,16 @@
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingBottom="8dp"
+ android:descendantFocusability="blocksDescendants"
tools:background="@android:color/darker_gray">
<com.joanzapata.iconify.widget.IconTextView
android:id="@+id/txtvIcon"
- android:layout_width="48dp"
- android:layout_height="48dp"
+ android:layout_width="48sp"
+ android:layout_height="48sp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:textSize="48sp"
android:gravity="center" />
@@ -25,7 +27,9 @@
android:layout_height="wrap_content"
android:layout_below="@id/txtvIcon"
android:layout_alignLeft="@id/txtvIcon"
+ android:layout_alignStart="@id/txtvIcon"
android:layout_alignRight="@id/txtvIcon"
+ android:layout_alignEnd="@id/txtvIcon"
android:layout_marginTop="8dp"
android:text="{fa-repeat}"
tools:text="↻" />
@@ -37,7 +41,9 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
tools:text="Media file"
tools:background="@android:color/holo_green_dark" />
@@ -49,8 +55,11 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/txtvIcon"
+ android:layout_toEndOf="@id/txtvIcon"
android:layout_toLeftOf="@id/txtvType"
+ android:layout_toStartOf="@id/txtvType"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
android:minLines="1"
android:maxLines="2"
@@ -63,8 +72,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/txtvIcon"
+ android:layout_toEndOf="@id/txtvIcon"
android:layout_below="@id/txtvTitle"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
tools:text="January 23"
tools:background="@android:color/holo_green_dark" />
@@ -75,7 +86,9 @@
android:layout_height="wrap_content"
android:layout_below="@id/txtvDate"
android:layout_toRightOf="@id/txtvIcon"
+ android:layout_toEndOf="@id/txtvIcon"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:textColor="?android:attr/textColorTertiary"
android:textSize="@dimen/text_size_micro"
tools:text="@string/design_time_downloaded_log_failure_reason"
diff --git a/app/src/main/res/layout/ellipsize_start_listitem.xml b/app/src/main/res/layout/ellipsize_start_listitem.xml
index f737b60d3..1b6c48152 100644
--- a/app/src/main/res/layout/ellipsize_start_listitem.xml
+++ b/app/src/main/res/layout/ellipsize_start_listitem.xml
@@ -1,23 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:background="@android:color/darker_gray">
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:background="@android:color/darker_gray">
<TextView
android:id="@+id/txtvTitle"
- android:textColor="?android:attr/textColorPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="@dimen/text_size_small"
- android:lines="1"
- android:singleLine="true"
android:layout_margin="16dp"
android:ellipsize="start"
- tools:text="List item title"
- tools:background="@android:color/holo_green_dark"/>
+ android:singleLine="true"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_small"
+ tools:background="@android:color/holo_green_dark"
+ tools:text="List item title" />
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/external_player_fragment.xml b/app/src/main/res/layout/external_player_fragment.xml
index fb7abde55..dc890807c 100644
--- a/app/src/main/res/layout/external_player_fragment.xml
+++ b/app/src/main/res/layout/external_player_fragment.xml
@@ -1,89 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
+<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fragmentLayout"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone">
+ android:layout_height="@dimen/external_player_height"
+ android:visibility="gone"
+ android:background="?attr/selectableItemBackground">
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="@dimen/external_player_height">
-
- <ImageView
- android:id="@+id/imgvCover"
- android:contentDescription="@string/cover_label"
- android:layout_width="@dimen/external_player_height"
- android:layout_height="@dimen/external_player_height"
- android:adjustViewBounds="true"
- android:cropToPadding="true"
- android:scaleType="centerCrop"
- tools:src="@drawable/ic_drag_vertical_white_48dp"
- tools:background="@android:color/holo_green_dark"
- android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"/>
+ <ImageView
+ android:id="@+id/imgvCover"
+ android:contentDescription="@string/cover_label"
+ android:layout_width="@dimen/external_player_height"
+ android:layout_height="@dimen/external_player_height"
+ android:adjustViewBounds="true"
+ android:cropToPadding="true"
+ android:scaleType="centerCrop"
+ tools:src="@drawable/ic_drag_vertical_white_48dp"
+ tools:background="@android:color/holo_green_dark"
+ android:transitionName="coverTransition"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"/>
- <ProgressBar
- android:id="@+id/episodeProgress"
- android:layout_width="match_parent"
- android:layout_height="4dp"
- android:layout_toRightOf="@id/imgvCover"
- android:layout_toEndOf="@id/imgvCover"
- android:layout_alignParentTop="true"
- style="?attr/progressBarTheme"
- android:indeterminate="false"
- tools:progress="100"/>
-
- <ImageButton
- android:id="@+id/butPlay"
- android:layout_width="52dp"
- android:layout_height="52dp"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:layout_below="@id/episodeProgress"
- android:layout_centerVertical="true"
- android:contentDescription="@string/pause_label"
- android:background="?attr/selectableItemBackground"
- tools:src="@drawable/ic_play_arrow_white_36dp"/>
+ <ProgressBar
+ android:id="@+id/episodeProgress"
+ android:layout_width="match_parent"
+ android:layout_height="4dp"
+ android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
+ android:layout_alignParentTop="true"
+ style="?attr/progressBarTheme"
+ android:indeterminate="false"
+ tools:progress="100"/>
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_marginBottom="26dp"
- android:layout_toRightOf="@id/imgvCover"
- android:layout_toEndOf="@id/imgvCover"
- android:layout_marginLeft="16dp"
- android:layout_marginStart="16dp"
- android:layout_toLeftOf="@id/butPlay"
- android:layout_toStartOf="@id/butPlay"
- style="@style/Base.TextAppearance.AppCompat.Body1"
- android:ellipsize="end"
- android:maxLines="1"
- tools:text="Episode title that is too long and will cause the text to wrap"/>
+ <ImageButton
+ android:id="@+id/butPlay"
+ android:layout_width="52dp"
+ android:layout_height="52dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
+ android:layout_below="@id/episodeProgress"
+ android:layout_centerVertical="true"
+ android:contentDescription="@string/pause_label"
+ android:background="?attr/selectableItemBackground"
+ android:src="?attr/av_play_big"
+ tools:src="@drawable/ic_play_arrow_white_36dp"/>
- <TextView
- android:id="@+id/txtvAuthor"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/episodeProgress"
- android:layout_marginTop="26dp"
- android:layout_toRightOf="@id/imgvCover"
- android:layout_toEndOf="@id/imgvCover"
- android:layout_marginLeft="16dp"
- android:layout_marginStart="16dp"
- android:layout_toLeftOf="@id/butPlay"
- android:layout_toStartOf="@id/butPlay"
- style="@style/TextAppearance.AppCompat.Body1"
- android:textColor="?android:attr/textColorSecondary"
- android:ellipsize="end"
- android:maxLines="1"
- tools:text="Episode author that is too long and will cause the text to wrap"/>
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="26dp"
+ android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
+ android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
+ android:layout_toLeftOf="@id/butPlay"
+ android:layout_toStartOf="@id/butPlay"
+ style="@style/Base.TextAppearance.AppCompat.Body1"
+ android:ellipsize="end"
+ android:maxLines="1"
+ tools:text="Episode title that is too long and will cause the text to wrap"/>
- </RelativeLayout>
+ <TextView
+ android:id="@+id/txtvAuthor"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/episodeProgress"
+ android:layout_marginTop="26dp"
+ android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
+ android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
+ android:layout_toLeftOf="@id/butPlay"
+ android:layout_toStartOf="@id/butPlay"
+ style="@style/TextAppearance.AppCompat.Body1"
+ android:textColor="?android:attr/textColorSecondary"
+ android:ellipsize="end"
+ android:maxLines="1"
+ tools:text="Episode author that is too long and will cause the text to wrap"/>
-</LinearLayout>
+</RelativeLayout>
diff --git a/app/src/main/res/layout/feedinfo.xml b/app/src/main/res/layout/feedinfo.xml
index 4b545e3cc..50061c4d8 100644
--- a/app/src/main/res/layout/feedinfo.xml
+++ b/app/src/main/res/layout/feedinfo.xml
@@ -6,48 +6,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <RelativeLayout
- android:id="@+id/header"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
- android:layout_marginTop="8dp">
-
- <ImageView
- android:id="@+id/imgvCover"
- android:contentDescription="@string/cover_label"
- android:layout_width="80dp"
- android:layout_height="80dp"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- tools:src="@drawable/ic_stat_antenna_default"
- tools:background="@android:color/holo_green_dark"/>
-
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_alignTop="@id/imgvCover"
- android:layout_toRightOf="@id/imgvCover"
- android:layout_alignBottom="@id/imgvCover"
- style="@style/AntennaPod.TextView.Heading"
- tools:text="Feed title"
- tools:background="@android:color/holo_green_dark"/>
-
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_below="@id/imgvCover"
- android:layout_marginTop="8dp"
- android:background="@color/holo_blue_light"/>
- </RelativeLayout>
+ <include layout="@layout/feeditemlist_header" />
<ScrollView
android:id="@+id/scrollView"
@@ -57,7 +16,8 @@
android:scrollbarStyle="outsideOverlay"
android:paddingLeft="16dp"
android:paddingRight="16dp"
- android:paddingBottom="8dp">
+ android:paddingBottom="8dp"
+ android:clipToPadding="false">
<LinearLayout
android:layout_width="match_parent"
@@ -76,7 +36,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_row="0"
app:layout_column="0"
@@ -86,9 +48,10 @@
tools:background="@android:color/holo_red_light"/>
<TextView
- android:id="@+id/txtvAuthor"
+ android:id="@+id/txtvDetailsAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:textIsSelectable="true"
app:layout_row="0"
app:layout_column="1"
tools:text="Daniel Oeh"
@@ -99,6 +62,7 @@
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"
@@ -111,6 +75,7 @@
android:id="@+id/txtvLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:textIsSelectable="true"
app:layout_row="1"
app:layout_column="1"
tools:text="English"
@@ -121,6 +86,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
app:layout_row="2"
app:layout_column="0"
android:lines="1"
@@ -133,6 +99,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingBottom="4dp"
+ android:background="?attr/selectableItemBackground"
app:layout_row="2"
app:layout_column="1"
app:layout_gravity="fill"
@@ -143,200 +110,6 @@
</android.support.v7.widget.GridLayout>
<TextView
- android:id="@+id/txtvSettings"
- style="@style/AntennaPod.TextView.Heading"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/podcast_settings_label"
- 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="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" />
-
- <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_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_marginBottom="8dp"
- app:layout_row="1"
- app:layout_column="0"
- android:text="@string/password_label"
- android:textColor="?android:attr/textColorPrimary"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:cursorVisible="true"/>
-
- <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.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"
- android:onClick="onRadioButtonClicked"/>
- <RadioButton android:id="@+id/radio_filter_exclude"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/episode_filters_exclude"
- android:onClick="onRadioButtonClicked"/>
- </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"/>
-
- <TextView
style="@style/AntennaPod.TextView.Heading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -348,6 +121,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
+ android:textIsSelectable="true"
android:text="@string/design_time_lorem_ipsum"
tools:background="@android:color/holo_green_dark"/>
diff --git a/app/src/main/res/layout/feeditem_fragment.xml b/app/src/main/res/layout/feeditem_fragment.xml
index a6ce221db..78c0b3b16 100644
--- a/app/src/main/res/layout/feeditem_fragment.xml
+++ b/app/src/main/res/layout/feeditem_fragment.xml
@@ -32,6 +32,7 @@
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:contentDescription="@string/cover_label"
android:gravity="center_vertical"
@@ -45,6 +46,7 @@
android:layout_height="wrap_content"
android:layout_alignTop="@id/imgvCover"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
tools:text="Podcast title"
tools:background="@android:color/holo_green_dark" />
@@ -54,6 +56,7 @@
android:layout_height="wrap_content"
android:layout_below="@id/txtvPodcast"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
android:textSize="16sp"
android:textColor="?android:attr/textColorPrimary"
android:ellipsize="end"
@@ -67,6 +70,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
android:layout_below="@id/txtvTitle"
tools:text="00:42:23"
tools:background="@android:color/holo_green_dark"/>
@@ -77,8 +81,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_below="@id/txtvTitle"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
tools:text="Jan 23"
tools:background="@android:color/holo_green_dark" />
@@ -98,7 +104,9 @@
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:orientation="horizontal"
tools:background="@android:color/holo_blue_bright">
@@ -108,6 +116,7 @@
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
android:layout_weight="1"
android:background="?attr/selectableItemBackground"
android:ellipsize="end"
@@ -123,6 +132,7 @@
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:layout_weight="1"
android:background="?attr/selectableItemBackground"
android:ellipsize="end"
diff --git a/app/src/main/res/layout/feeditemlist_header.xml b/app/src/main/res/layout/feeditemlist_header.xml
index 361b583c9..e1f451e9e 100644
--- a/app/src/main/res/layout/feeditemlist_header.xml
+++ b/app/src/main/res/layout/feeditemlist_header.xml
@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:background="@color/feed_image_bg"
tools:context="de.danoeh.antennapod.activity.MainActivity"
tools:background="@android:color/darker_gray">
@@ -18,10 +19,12 @@
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_centerVertical="true"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:contentDescription="@string/cover_label"
tools:src="@drawable/ic_stat_antenna_default"
@@ -29,18 +32,32 @@
<ImageButton
android:id="@+id/butShowInfo"
- android:layout_width="48dp"
- android:layout_height="48dp"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
- android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/show_info_label"
android:src="@drawable/ic_info_white_24dp"
tools:background="@android:color/holo_green_dark"/>
+ <ImageButton
+ android:id="@+id/butShowSettings"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/show_feed_settings_label"
+ android:src="@drawable/ic_settings_white_24dp"
+ tools:background="@android:color/holo_green_dark"
+ android:layout_below="@+id/butShowInfo"
+ android:layout_marginBottom="16dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"/>
+
<TextView
android:id="@+id/txtvTitle"
style="@style/AntennaPod.TextView.Heading"
@@ -49,9 +66,12 @@
android:layout_alignParentTop="true"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_toLeftOf="@id/butShowInfo"
+ android:layout_toStartOf="@id/butShowInfo"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
android:ellipsize="end"
android:maxLines="2"
android:shadowColor="@color/black"
@@ -62,13 +82,18 @@
<TextView
android:id="@+id/txtvAuthor"
- android:layout_width="wrap_content"
+ android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_below="@id/txtvTitle"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_toLeftOf="@id/butShowSettings"
+ android:layout_toStartOf="@id/butShowSettings"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
android:ellipsize="end"
android:lines="1"
android:shadowColor="@color/black"
@@ -76,7 +101,7 @@
android:textColor="@color/white"
android:textSize="@dimen/text_size_small"
tools:text="Podcast author"
- tools:background="@android:color/holo_green_dark" />
+ tools:background="@android:color/holo_green_dark"/>
<com.joanzapata.iconify.widget.IconTextView
android:id="@+id/txtvFailure"
diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml
index d2b85e7df..adf0748eb 100644
--- a/app/src/main/res/layout/feeditemlist_item.xml
+++ b/app/src/main/res/layout/feeditemlist_item.xml
@@ -5,7 +5,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
- android:layout_height="@dimen/listitem_threeline_height"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
tools:background="@android:color/darker_gray">
@@ -13,7 +13,10 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
android:layout_weight="1"
+ android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
tools:background="@android:color/holo_orange_dark">
<TextView
@@ -22,8 +25,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
- android:layout_marginTop="16dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
tools:text="NEW"
@@ -35,10 +38,11 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
- android:layout_marginBottom="8dp"
- android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginBottom="4dp"
android:layout_toLeftOf="@id/statusUnread"
+ android:layout_toStartOf="@id/statusUnread"
tools:text="Episode title"
tools:background="@android:color/holo_green_dark" />
@@ -48,6 +52,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_below="@id/txtvItemname"
tools:text="00:42:23"
tools:background="@android:color/holo_green_dark" />
@@ -57,8 +62,10 @@
android:layout_width="@dimen/enc_icons_size"
android:layout_height="@dimen/enc_icons_size"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_below="@id/txtvItemname"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
android:contentDescription="@string/in_queue_label"
android:src="?attr/stat_playlist"
android:visibility="visible"
@@ -71,7 +78,9 @@
android:layout_height="@dimen/enc_icons_size"
android:layout_below="@id/txtvItemname"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
android:layout_toLeftOf="@id/imgvInPlaylist"
+ android:layout_toStartOf="@id/imgvInPlaylist"
tools:ignore="ContentDescription"
tools:src="@drawable/ic_hearing_white_18dp"
tools:background="@android:color/holo_red_light" />
@@ -83,7 +92,9 @@
android:layout_height="wrap_content"
android:layout_below="@id/txtvItemname"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
android:layout_toLeftOf="@id/imgvType"
+ android:layout_toStartOf="@id/imgvType"
tools:text="Jan 23"
tools:background="@android:color/holo_green_dark" />
@@ -92,17 +103,18 @@
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_alignBottom="@id/txtvPublished"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
+ android:layout_toStartOf="@id/txtvPublished"
android:layout_toLeftOf="@id/txtvPublished"
+ android:layout_toEndOf="@id/txtvLenSize"
android:layout_toRightOf="@id/txtvLenSize"
- android:layout_alignTop="@id/txtvPublished"
- android:layout_alignBottom="@id/txtvPublished"
- tools:background="@android:color/holo_blue_light"
+ android:layoutDirection="ltr"
+ android:indeterminate="false"
android:max="100"
android:progress="42"
- android:indeterminate="false"
- />
+ tools:background="@android:color/holo_blue_light" />
</RelativeLayout>
diff --git a/app/src/main/res/layout/feedsettings.xml b/app/src/main/res/layout/feedsettings.xml
new file mode 100644
index 000000000..9e5f2245b
--- /dev/null
+++ b/app/src/main/res/layout/feedsettings.xml
@@ -0,0 +1,218 @@
+<?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
+ 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>
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/gpodnet_podcast_listitem.xml b/app/src/main/res/layout/gpodnet_podcast_listitem.xml
index bbe8e65d6..27a8bbdca 100644
--- a/app/src/main/res/layout/gpodnet_podcast_listitem.xml
+++ b/app/src/main/res/layout/gpodnet_podcast_listitem.xml
@@ -15,8 +15,10 @@
android:layout_width="@dimen/thumbnail_length_itemlist"
android:layout_height="@dimen/thumbnail_length_itemlist"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
android:adjustViewBounds="true"
android:contentDescription="@string/cover_label"
android:cropToPadding="true"
@@ -30,6 +32,7 @@
android:layout_height="wrap_content"
android:layout_alignTop="@id/txtvTitle"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:orientation="horizontal">
<ImageView
@@ -37,6 +40,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="-4dp"
+ android:layout_marginEnd="-4dp"
android:src="?attr/feed" />
<TextView
@@ -56,7 +60,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
android:layout_toLeftOf="@id/subscribers_container"
+ android:layout_toStartOf="@id/subscribers_container"
android:layout_alignTop="@id/imgvCover"
android:maxLines="2"
android:includeFontPadding="false"
@@ -69,6 +75,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
android:layout_below="@id/txtvTitle"
android:textSize="14sp"
android:textColor="?android:attr/textColorSecondary"
diff --git a/app/src/main/res/layout/gpodnet_tag_listitem.xml b/app/src/main/res/layout/gpodnet_tag_listitem.xml
index 9e545e59d..a377f9ba1 100644
--- a/app/src/main/res/layout/gpodnet_tag_listitem.xml
+++ b/app/src/main/res/layout/gpodnet_tag_listitem.xml
@@ -13,6 +13,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:lines="1"
@@ -25,7 +26,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginEnd="@dimen/listitem_threeline_horizontalpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
tools:text="301"
diff --git a/app/src/main/res/layout/gpodnetauth_credentials.xml b/app/src/main/res/layout/gpodnetauth_credentials.xml
index a290b682b..f995ae4cc 100644
--- a/app/src/main/res/layout/gpodnetauth_credentials.xml
+++ b/app/src/main/res/layout/gpodnetauth_credentials.xml
@@ -59,6 +59,7 @@
android:layout_height="wrap_content"
android:layout_below="@id/etxtPassword"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:text="@string/gpodnetauth_login_butLabel"
android:layout_margin="8dp"/>
@@ -68,7 +69,9 @@
android:layout_height="wrap_content"
android:layout_below="@id/etxtPassword"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_toLeftOf="@id/butLogin"
+ android:layout_toStartOf="@id/butLogin"
android:textColor="@color/download_failed_red"
android:textSize="@dimen/text_size_small"
android:maxLines="2"
@@ -84,7 +87,8 @@
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_alignTop="@+id/butLogin"
- android:layout_toLeftOf="@+id/butLogin"/>
+ android:layout_toLeftOf="@+id/butLogin"
+ android:layout_toStartOf="@+id/butLogin"/>
<TextView
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/gpodnetauth_device.xml b/app/src/main/res/layout/gpodnetauth_device.xml
index 38455f02c..5840fe955 100644
--- a/app/src/main/res/layout/gpodnetauth_device.xml
+++ b/app/src/main/res/layout/gpodnetauth_device.xml
@@ -41,7 +41,8 @@
android:textColor="?android:attr/textColorSecondary"
android:layout_margin="8dp"
android:layout_alignTop="@+id/etxtDeviceID"
- android:layout_alignLeft="@+id/etxtCaption"/>
+ android:layout_alignLeft="@+id/etxtCaption"
+ android:layout_alignStart="@+id/etxtCaption"/>
<EditText
android:id="@+id/etxtDeviceID"
@@ -49,7 +50,9 @@
android:layout_height="wrap_content"
android:layout_below="@id/etxtCaption"
android:layout_toRightOf="@id/txtvDeviceID"
+ android:layout_toEndOf="@id/txtvDeviceID"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_margin="8dp"/>
<Button
@@ -58,6 +61,7 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_below="@id/etxtDeviceID"
android:text="@string/gpodnetauth_device_butCreateNewDevice"/>
@@ -66,8 +70,10 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_below="@id/etxtDeviceID"
android:layout_toLeftOf="@id/butCreateNewDevice"
+ android:layout_toStartOf="@id/butCreateNewDevice"
android:textColor="@color/download_failed_red"
android:layout_margin="16dp"
android:textSize="@dimen/text_size_small"
@@ -80,6 +86,7 @@
android:layout_height="wrap_content"
android:layout_alignTop="@id/butCreateNewDevice"
android:layout_toLeftOf="@id/butCreateNewDevice"
+ android:layout_toStartOf="@id/butCreateNewDevice"
android:textColor="@color/download_failed_red"
android:textSize="@dimen/text_size_medium"
android:visibility="gone"
@@ -102,7 +109,9 @@
android:text="@string/gpodnetauth_device_butChoose"
android:layout_below="@+id/spinnerChooseDevice"
android:layout_alignLeft="@+id/butCreateNewDevice"
- android:layout_alignRight="@+id/butCreateNewDevice"/>
+ android:layout_alignStart="@+id/butCreateNewDevice"
+ android:layout_alignRight="@+id/butCreateNewDevice"
+ android:layout_alignEnd="@+id/butCreateNewDevice"/>
<Spinner
android:id="@+id/spinnerChooseDevice"
@@ -110,7 +119,9 @@
android:layout_height="wrap_content"
android:layout_below="@id/txtvChooseExistingDevice"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_margin="8dp"
- android:layout_alignParentRight="true"/>
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"/>
</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/import_export_activity.xml b/app/src/main/res/layout/import_export_activity.xml
new file mode 100644
index 000000000..97ff34e41
--- /dev/null
+++ b/app/src/main/res/layout/import_export_activity.xml
@@ -0,0 +1,34 @@
+<?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:orientation="vertical"
+ android:id="@+id/import_export_layout"
+ android:padding="8dp"
+ android:clipToPadding="false">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/import_export_warning"
+ android:gravity="center_horizontal"/>
+
+ <Button
+ android:text="@string/label_export"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/button_export"
+ android:layout_marginTop="24dp"/>
+
+ <Button
+ android:text="@string/label_import"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/button_import"/>
+ </LinearLayout>
+</ScrollView>
diff --git a/app/src/main/res/layout/itemdescription_listitem.xml b/app/src/main/res/layout/itemdescription_listitem.xml
index 51bc9a5eb..9d03e30a3 100644
--- a/app/src/main/res/layout/itemdescription_listitem.xml
+++ b/app/src/main/res/layout/itemdescription_listitem.xml
@@ -17,8 +17,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:textSize="14sp"
android:textColor="?android:textColorSecondary"
android:ellipsize="end"
@@ -31,8 +33,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@id/txtvPubDate"
+ android:layout_toStartOf="@id/txtvPubDate"
android:textSize="16sp"
android:textColor="?android:attr/textColorPrimary"
android:ellipsize="end"
diff --git a/app/src/main/res/layout/itunes_podcast_listitem.xml b/app/src/main/res/layout/itunes_podcast_listitem.xml
index 1e6e5a836..4848563b1 100644
--- a/app/src/main/res/layout/itunes_podcast_listitem.xml
+++ b/app/src/main/res/layout/itunes_podcast_listitem.xml
@@ -16,8 +16,10 @@
android:layout_width="@dimen/thumbnail_length_itemlist"
android:layout_height="@dimen/thumbnail_length_itemlist"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
android:adjustViewBounds="true"
android:contentDescription="@string/cover_label"
android:cropToPadding="true"
@@ -29,6 +31,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
android:layout_centerVertical="true"
android:orientation="vertical">
diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml
index c05132b42..6cabcdff2 100644
--- a/app/src/main/res/layout/main.xml
+++ b/app/src/main/res/layout/main.xml
@@ -6,7 +6,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ <RelativeLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/app/src/main/res/layout/mediaplayerinfo_activity.xml b/app/src/main/res/layout/mediaplayerinfo_activity.xml
index 0f68b503e..c9e93e149 100644
--- a/app/src/main/res/layout/mediaplayerinfo_activity.xml
+++ b/app/src/main/res/layout/mediaplayerinfo_activity.xml
@@ -47,6 +47,7 @@
android:paddingTop="8dp"
android:layout_alignParentBottom="true"
android:background="?attr/overlay_drawable"
+ android:layoutDirection="ltr"
android:orientation="vertical">
@@ -59,8 +60,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:text="@string/position_default_label"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/text_size_micro"
@@ -71,8 +74,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
android:text="@string/position_default_label"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/text_size_micro"
@@ -84,9 +89,13 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
android:layout_toLeftOf="@id/txtvLength"
+ android:layout_toStartOf="@id/txtvLength"
android:layout_toRightOf="@id/txtvPosition"
+ android:layout_toEndOf="@id/txtvPosition"
android:max="500"
tools:background="@android:color/holo_green_dark" />
@@ -106,13 +115,15 @@
android:layout_width="@dimen/audioplayer_playercontrols_length"
android:layout_height="@dimen/audioplayer_playercontrols_length"
android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
android:layout_centerHorizontal="true"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/pause_label"
- android:src="?attr/av_pause"
+ android:src="?attr/av_play"
android:scaleType="fitCenter"
- tools:src="@drawable/ic_pause_white_36dp"
+ tools:src="@drawable/ic_play_arrow_white_24dp"
tools:background="@android:color/holo_green_dark" />
<ImageButton
@@ -120,7 +131,9 @@
android:layout_width="@dimen/audioplayer_playercontrols_length"
android:layout_height="@dimen/audioplayer_playercontrols_length"
android:layout_toLeftOf="@id/butPlay"
+ android:layout_toStartOf="@id/butPlay"
android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/rewind_label"
android:src="?attr/av_rew_big"
@@ -134,7 +147,9 @@
android:layout_height="wrap_content"
android:layout_below="@id/butRev"
android:layout_alignLeft="@id/butRev"
+ android:layout_alignStart="@id/butRev"
android:layout_alignRight="@id/butRev"
+ android:layout_alignEnd="@id/butRev"
android:layout_marginTop="-8dp"
android:gravity="center"
android:text="30"
@@ -147,11 +162,13 @@
android:layout_width="@dimen/audioplayer_playercontrols_length"
android:layout_height="@dimen/audioplayer_playercontrols_length"
android:layout_toLeftOf="@id/butRev"
+ android:layout_toStartOf="@id/butRev"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/set_playback_speed_label"
android:src="?attr/av_fast_forward"
android:textSize="@dimen/text_size_medium"
android:textAllCaps="false"
+ android:maxLines="1"
tools:visibility="gone"
tools:background="@android:color/holo_green_dark" />
@@ -160,6 +177,7 @@
android:layout_width="@dimen/audioplayer_playercontrols_length"
android:layout_height="@dimen/audioplayer_playercontrols_length"
android:layout_toLeftOf="@id/butRev"
+ android:layout_toStartOf="@id/butRev"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/cast_disconnect_label"
android:src="?attr/ic_cast_disconnect"
@@ -174,7 +192,9 @@
android:layout_width="@dimen/audioplayer_playercontrols_length"
android:layout_height="@dimen/audioplayer_playercontrols_length"
android:layout_toRightOf="@id/butPlay"
+ android:layout_toEndOf="@id/butPlay"
android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/fast_forward_label"
android:src="?attr/av_ff_big"
@@ -188,7 +208,9 @@
android:layout_height="wrap_content"
android:layout_below="@id/butFF"
android:layout_alignLeft="@id/butFF"
+ android:layout_alignStart="@id/butFF"
android:layout_alignRight="@id/butFF"
+ android:layout_alignEnd="@id/butFF"
android:layout_marginTop="-8dp"
android:gravity="center"
android:text="30"
@@ -201,6 +223,7 @@
android:layout_width="@dimen/audioplayer_playercontrols_length"
android:layout_height="@dimen/audioplayer_playercontrols_length"
android:layout_toRightOf="@id/butFF"
+ android:layout_toEndOf="@id/butFF"
android:background="?attr/selectableItemBackground"
android:scaleType="fitCenter"
android:src="?attr/av_skip_big"
diff --git a/app/src/main/res/layout/nav_feedlistitem.xml b/app/src/main/res/layout/nav_feedlistitem.xml
index 18b5255aa..9f19157fc 100644
--- a/app/src/main/res/layout/nav_feedlistitem.xml
+++ b/app/src/main/res/layout/nav_feedlistitem.xml
@@ -5,7 +5,6 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_iconwithtext_height"
- android:paddingRight="@dimen/listitem_threeline_verticalpadding"
tools:background="@android:color/darker_gray">
<ImageView
@@ -14,6 +13,7 @@
android:layout_width="@dimen/thumbnail_length_navlist"
android:layout_height="@dimen/thumbnail_length_navlist"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:cropToPadding="true"
@@ -21,6 +21,7 @@
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"/>
@@ -29,10 +30,14 @@
android:layout_width="wrap_content"
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"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
tools:text="23"
tools:background="@android:color/holo_green_dark"/>
@@ -42,7 +47,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/txtvCount"
+ android:layout_toStartOf="@id/txtvCount"
android:layout_marginLeft="@dimen/list_vertical_padding"
+ android:layout_marginStart="@dimen/list_vertical_padding"
android:layout_alignWithParentIfMissing="true"
android:lines="1"
android:text="{fa-exclamation-circle}"
@@ -63,8 +70,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/listitem_iconwithtext_textleftpadding"
+ android:layout_marginStart="@dimen/listitem_iconwithtext_textleftpadding"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
android:layout_toLeftOf="@id/itxtvFailure"
+ android:layout_toStartOf="@id/itxtvFailure"
android:layout_alignWithParentIfMissing="true"
tools:text="Navigation feed item title"
tools:background="@android:color/holo_green_dark"/>
diff --git a/app/src/main/res/layout/nav_list.xml b/app/src/main/res/layout/nav_list.xml
index 7e72bb39b..2d044f548 100644
--- a/app/src/main/res/layout/nav_list.xml
+++ b/app/src/main/res/layout/nav_list.xml
@@ -15,7 +15,8 @@
android:layout_alignParentBottom="true"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/settings_label"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:focusable="true">
<ImageView
android:id="@+id/imgvCover"
@@ -23,6 +24,7 @@
android:layout_height="@dimen/thumbnail_length_navlist"
android:layout_marginBottom="4dp"
android:layout_marginLeft="@dimen/listitem_icon_leftpadding"
+ android:layout_marginStart="@dimen/listitem_icon_leftpadding"
android:layout_marginTop="4dp"
android:adjustViewBounds="true"
android:contentDescription="@string/cover_label"
@@ -31,13 +33,14 @@
android:scaleType="centerCrop"
android:src="?attr/ic_settings"
tools:background="@android:color/holo_orange_dark"
- tools:src="@android:drawable/sym_def_app_icon"></ImageView>
+ tools:src="@android:drawable/sym_def_app_icon" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="@string/settings_label"
@@ -69,5 +72,5 @@
android:paddingTop="@dimen/list_vertical_padding"
android:scrollbarStyle="outsideOverlay"
tools:background="@android:color/holo_purple"
- tools:listitem="@layout/nav_listitem"></ListView>
+ tools:listitem="@layout/nav_listitem" />
</RelativeLayout>
diff --git a/app/src/main/res/layout/nav_listitem.xml b/app/src/main/res/layout/nav_listitem.xml
index d62672c34..c140533e6 100644
--- a/app/src/main/res/layout/nav_listitem.xml
+++ b/app/src/main/res/layout/nav_listitem.xml
@@ -13,12 +13,14 @@
android:layout_width="@dimen/thumbnail_length_navlist"
android:layout_height="@dimen/thumbnail_length_navlist"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:cropToPadding="true"
android:scaleType="centerInside"
android:padding="4dp"
android:layout_marginLeft="@dimen/listitem_icon_leftpadding"
+ android:layout_marginStart="@dimen/listitem_icon_leftpadding"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
tools:src="@drawable/ic_new_releases_white_24dp"
@@ -36,8 +38,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/listitem_iconwithtext_textleftpadding"
+ android:layout_marginStart="@dimen/listitem_iconwithtext_textleftpadding"
android:layout_marginRight="48dp"
+ android:layout_marginEnd="48dp"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
tools:text="Navigation item title"
tools:background="@android:color/holo_green_dark"
/>
@@ -50,8 +55,11 @@
android:textColor="?android:attr/textColorTertiary"
android:textSize="@dimen/text_size_navdrawer"
android:layout_marginLeft="12dp"
+ android:layout_marginStart="12dp"
android:layout_marginRight="@dimen/listitem_icon_rightpadding"
+ android:layout_marginEnd="@dimen/listitem_icon_rightpadding"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
tools:text="23"
tools:background="@android:color/holo_green_dark"/>
diff --git a/app/src/main/res/layout/new_episodes_listitem.xml b/app/src/main/res/layout/new_episodes_listitem.xml
index 944711aec..150d692e7 100644
--- a/app/src/main/res/layout/new_episodes_listitem.xml
+++ b/app/src/main/res/layout/new_episodes_listitem.xml
@@ -10,10 +10,10 @@
<LinearLayout
android:id="@+id/content"
android:layout_width="match_parent"
- android:layout_height="@dimen/listitem_threeline_height"
+ android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:orientation="horizontal"
- tools:background="@android:color/darker_gray">
+ android:gravity="center_vertical">
<RelativeLayout
android:layout_width="wrap_content"
@@ -26,6 +26,7 @@
android:layout_gravity="center_vertical"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:background="@color/light_gray"
android:ellipsize="end"
@@ -37,24 +38,26 @@
android:layout_height="64dp"
android:layout_width="64dp"
android:layout_alignLeft="@id/txtvPlaceholder"
+ android:layout_alignStart="@id/txtvPlaceholder"
android:layout_alignTop="@id/txtvPlaceholder"
android:layout_alignRight="@id/txtvPlaceholder"
+ android:layout_alignEnd="@id/txtvPlaceholder"
android:layout_alignBottom="@id/txtvPlaceholder"
android:contentDescription="@string/cover_label"
- tools:src="@drawable/ic_stat_antenna_default"
- tools:background="@android:color/holo_green_dark" />
+ tools:src="@tools:sample/avatars" />
</RelativeLayout>
<RelativeLayout
android:layout_width="0dp"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:layout_marginLeft="@dimen/listitem_threeline_textleftpadding"
+ android:layout_marginStart="@dimen/listitem_threeline_textleftpadding"
android:layout_marginRight="@dimen/listitem_threeline_textrightpadding"
+ android:layout_marginEnd="@dimen/listitem_threeline_textrightpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
- android:layout_weight="1"
- tools:background="@android:color/white" >
+ android:layout_weight="1">
<TextView
@@ -63,8 +66,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
- android:layout_marginLeft="8dp"/>
+ android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
+ tools:text="@sample/episodes.json/data/status_label"/>
<TextView
android:id="@+id/txtvTitle"
@@ -72,10 +78,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@id/statusUnread"
- tools:text="Episode title"
- tools:background="@android:color/holo_green_dark" />
+ android:layout_toStartOf="@id/statusUnread"
+ tools:text="@sample/episodes.json/data/title" />
<RelativeLayout
android:id="@+id/bottom_bar"
@@ -84,8 +91,9 @@
android:layout_below="@id/txtvTitle"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
- tools:background="@android:color/holo_red_light" >
+ android:layout_alignParentEnd="true">
<TextView
android:id="@+id/txtvDuration"
@@ -93,19 +101,20 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
- tools:text="00:42:23"
- tools:background="@android:color/holo_blue_dark" />
+ android:layout_alignParentStart="true"
+ tools:text="@sample/episodes.json/data/duration" />
<ImageView
android:id="@+id/imgvInPlaylist"
android:layout_width="@dimen/enc_icons_size"
android:layout_height="@dimen/enc_icons_size"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:contentDescription="@string/in_queue_label"
android:src="?attr/stat_playlist"
- tools:src="@drawable/ic_list_grey600_24dp"
- tools:background="@android:color/black" />
+ tools:src="@sample/inplaylist" />
<TextView
android:id="@+id/txtvPublished"
@@ -114,17 +123,16 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@id/imgvInPlaylist"
+ android:layout_toStartOf="@id/imgvInPlaylist"
android:ellipsize="end"
- tools:text="Jan 23"
- tools:background="@android:color/holo_green_dark" />
+ tools:text="@sample/episodes.json/data/published_at" />
<ProgressBar
android:id="@+id/pbar_progress"
- style="?android:attr/progressBarStyleHorizontal"
+ style="?attr/progressBarTheme"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="4dp"
android:layout_below="@id/txtvDuration"
- android:layout_marginTop="-2dp"
android:max="100" />
</RelativeLayout>
diff --git a/app/src/main/res/layout/numberpicker.xml b/app/src/main/res/layout/numberpicker.xml
new file mode 100644
index 000000000..813326bd6
--- /dev/null
+++ b/app/src/main/res/layout/numberpicker.xml
@@ -0,0 +1,16 @@
+<?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"
+ android:padding="32dp">
+
+ <EditText
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="numberDecimal"
+ android:ems="10"
+ android:selectAllOnFocus="true"
+ android:id="@+id/number" />
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/onlinefeedview_header.xml b/app/src/main/res/layout/onlinefeedview_header.xml
index 491d955fb..4217322e4 100644
--- a/app/src/main/res/layout/onlinefeedview_header.xml
+++ b/app/src/main/res/layout/onlinefeedview_header.xml
@@ -10,6 +10,7 @@
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"
@@ -24,10 +25,13 @@
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"
@@ -41,7 +45,9 @@
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"
@@ -61,7 +67,9 @@
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_marginTop="8dp"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_micro" />
@@ -80,7 +88,9 @@
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="?android:attr/textColorSecondary"
android:textSize="@dimen/text_size_small"
tools:text="@string/design_time_lorem_ipsum"
diff --git a/app/src/main/res/layout/opml_import.xml b/app/src/main/res/layout/opml_import.xml
index 2a67e7ee1..ac75cb8b3 100644
--- a/app/src/main/res/layout/opml_import.xml
+++ b/app/src/main/res/layout/opml_import.xml
@@ -6,7 +6,7 @@
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="wrap_content"
android:orientation="vertical"
android:paddingTop="8dp"
android:paddingLeft="16dp"
diff --git a/app/src/main/res/layout/opml_selection.xml b/app/src/main/res/layout/opml_selection.xml
index d08ebd0bd..f8f37b5ac 100644
--- a/app/src/main/res/layout/opml_selection.xml
+++ b/app/src/main/res/layout/opml_selection.xml
@@ -4,28 +4,54 @@
android:layout_width="match_parent"
android:layout_height="match_parent" >
- <LinearLayout
+ <RelativeLayout
android:id="@+id/footer"
- style="@android:style/ButtonBar"
android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:orientation="horizontal" >
+ android:layout_height="48dp"
+ android:layout_alignParentBottom="true" >
- <Button
- android:id="@+id/butConfirm"
- android:layout_width="0px"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/confirm_label" />
+ <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="0px"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"
+ 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" />
- </LinearLayout>
+
+ <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>
<ListView
android:id="@+id/feedlist"
diff --git a/app/src/main/res/layout/player_widget.xml b/app/src/main/res/layout/player_widget.xml
deleted file mode 100644
index d9f442f96..000000000
--- a/app/src/main/res/layout/player_widget.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="@dimen/widget_margin" >
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#262C31" >
-
- <ImageButton
- android:id="@+id/butPlay"
- android:contentDescription="@string/play_label"
- android:layout_width="56dp"
- android:layout_height="match_parent"
- android:layout_alignParentRight="true"
- android:layout_margin="12dp"
- android:background="@drawable/borderless_button_dark"
- android:src="@drawable/ic_play_arrow_white_24dp" />
-
- <LinearLayout
- android:id="@+id/layout_left"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@id/butPlay"
- android:background="@drawable/borderless_button_dark"
- android:gravity="center_vertical"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="8dp"
- android:maxLines="1"
- android:text="@string/no_media_playing_label"
- android:textColor="@color/white"
- android:textSize="@dimen/text_size_medium"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/txtvProgress"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="8dp"
- android:textColor="?android:attr/textColorSecondary" />
- </LinearLayout>
- </RelativeLayout>
-
-</FrameLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/preference_switch_layout.xml b/app/src/main/res/layout/preference_switch_layout.xml
deleted file mode 100644
index 54fa74061..000000000
--- a/app/src/main/res/layout/preference_switch_layout.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<android.support.v7.widget.SwitchCompat
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/checkbox"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@null"
- android:clickable="false"
- android:focusable="false" /> \ No newline at end of file
diff --git a/app/src/main/res/layout/queue_listitem.xml b/app/src/main/res/layout/queue_listitem.xml
index 8de80e355..6b41b68d5 100644
--- a/app/src/main/res/layout/queue_listitem.xml
+++ b/app/src/main/res/layout/queue_listitem.xml
@@ -9,7 +9,7 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="@dimen/listitem_threeline_height"
+ android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:orientation="horizontal"
android:gravity="center_vertical"
@@ -60,7 +60,9 @@
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:layout_marginLeft="@dimen/listitem_threeline_textleftpadding"
+ android:layout_marginStart="@dimen/listitem_threeline_textleftpadding"
android:layout_marginRight="@dimen/listitem_threeline_textrightpadding"
+ android:layout_marginEnd="@dimen/listitem_threeline_textrightpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:layout_weight="1"
tools:background="@android:color/holo_red_dark">
@@ -73,9 +75,11 @@
android:layout_height="wrap_content"
android:lines="2"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="8dp"
- android:gravity="right|top"
+ android:layout_marginStart="8dp"
+ android:gravity="end|top"
android:text="Feb\n12"
tools:background="@android:color/holo_blue_light" />
@@ -85,7 +89,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/txtvPubDate"
+ android:layout_toStartOf="@id/txtvPubDate"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:text="Queue item title"
android:ellipsize="end"
@@ -98,7 +104,9 @@
android:layout_below="@id/txtvTitle"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
- android:layout_alignParentRight="true">
+ android:layout_alignParentStart="true"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true">
<TextView
android:id="@+id/txtvProgressLeft"
@@ -106,6 +114,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_marginBottom="0dp"
android:text="00:42:23"
tools:background="@android:color/holo_blue_light"/>
@@ -116,17 +125,18 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_marginBottom="0dp"
tools:text="Jan 23"
tools:background="@android:color/holo_green_dark" />
<ProgressBar
android:id="@+id/progressBar"
- style="?android:attr/progressBarStyleHorizontal"
+ style="?attr/progressBarTheme"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="4dp"
android:layout_below="@id/txtvProgressLeft"
- android:layout_marginTop="-2dp"
+ android:layoutDirection="ltr"
android:max="100"
tools:background="@android:color/holo_blue_light" />
diff --git a/app/src/main/res/layout/searchlist_item.xml b/app/src/main/res/layout/searchlist_item.xml
index a8b8e7b62..50374c737 100644
--- a/app/src/main/res/layout/searchlist_item.xml
+++ b/app/src/main/res/layout/searchlist_item.xml
@@ -2,18 +2,20 @@
<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="@dimen/listitem_threeline_height"
- tools:background="@android:color/darker_gray">
+ android:layout_height="wrap_content"
+ tools:background="@android:color/darker_gray"
+ android:paddingTop="@dimen/listitem_threeline_verticalpadding"
+ android:paddingBottom="@dimen/listitem_threeline_verticalpadding">
<ImageView
android:id="@+id/imgvFeedimage"
android:layout_width="@dimen/thumbnail_length_itemlist"
android:layout_height="@dimen/thumbnail_length_itemlist"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_centerVertical="true"
- android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
- android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
android:contentDescription="@string/cover_label"
android:scaleType="centerCrop"
tools:src="@drawable/ic_stat_antenna_default"
@@ -23,9 +25,11 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/listitem_iconwithtext_textleftpadding"
+ android:layout_marginStart="@dimen/listitem_iconwithtext_textleftpadding"
android:layout_marginRight="@dimen/listitem_threeline_verticalpadding"
- android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginEnd="@dimen/listitem_threeline_verticalpadding"
android:layout_toRightOf="@id/imgvFeedimage"
+ android:layout_toEndOf="@id/imgvFeedimage"
android:orientation="vertical"
tools:background="@android:color/holo_red_dark">
diff --git a/app/src/main/res/layout/secondary_action.xml b/app/src/main/res/layout/secondary_action.xml
index b2aea03f8..1f4d9e4e6 100644
--- a/app/src/main/res/layout/secondary_action.xml
+++ b/app/src/main/res/layout/secondary_action.xml
@@ -9,5 +9,4 @@
android:focusable="false"
android:focusableInTouchMode="false"
tools:ignore="ContentDescription"
- tools:src="@drawable/ic_play_arrow_grey600_36dp"
- tools:background="@android:color/holo_green_dark" />
+ tools:src="@sample/secondaryaction" />
diff --git a/app/src/main/res/layout/simplechapter_item.xml b/app/src/main/res/layout/simplechapter_item.xml
index 21bbc9545..0d02eac1a 100644
--- a/app/src/main/res/layout/simplechapter_item.xml
+++ b/app/src/main/res/layout/simplechapter_item.xml
@@ -2,7 +2,7 @@
<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="@dimen/listitem_threeline_height"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
tools:background="@android:color/darker_gray">
@@ -13,6 +13,7 @@
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
android:gravity="center_vertical"
tools:text="Start"
tools:background="@android:color/holo_green_dark" />
@@ -22,7 +23,9 @@
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginEnd="@dimen/listitem_threeline_horizontalpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:layout_weight="1"
android:gravity="center_vertical"
diff --git a/app/src/main/res/layout/splash.xml b/app/src/main/res/layout/splash.xml
new file mode 100644
index 000000000..71b6cd15a
--- /dev/null
+++ b/app/src/main/res/layout/splash.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ProgressBar
+ style="?android:attr/progressBarStyle"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:layout_margin="36dp"
+ android:id="@+id/progressBar"/>
+</RelativeLayout>
diff --git a/app/src/main/res/layout/statistics_listitem.xml b/app/src/main/res/layout/statistics_listitem.xml
index 20e01bf32..b186add9e 100644
--- a/app/src/main/res/layout/statistics_listitem.xml
+++ b/app/src/main/res/layout/statistics_listitem.xml
@@ -4,7 +4,10 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_iconwithtext_height"
+ android:paddingLeft="@dimen/listitem_threeline_verticalpadding"
+ android:paddingStart="@dimen/listitem_threeline_verticalpadding"
android:paddingRight="@dimen/listitem_threeline_verticalpadding"
+ android:paddingEnd="@dimen/listitem_threeline_verticalpadding"
tools:background="@android:color/darker_gray">
<ImageView
@@ -13,13 +16,13 @@
android:layout_width="@dimen/thumbnail_length_navlist"
android:layout_height="@dimen/thumbnail_length_navlist"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:cropToPadding="true"
android:scaleType="centerCrop"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
- android:layout_marginLeft="@dimen/listitem_icon_leftpadding"
tools:src="@drawable/ic_stat_antenna_default"
tools:background="@android:color/holo_green_dark"/>
@@ -28,10 +31,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/list_vertical_padding"
+ android:layout_marginStart="@dimen/list_vertical_padding"
android:lines="1"
android:textColor="?android:attr/textColorTertiary"
android:textSize="@dimen/text_size_navdrawer"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
tools:text="23"
tools:background="@android:color/holo_green_dark"/>
@@ -47,8 +52,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/listitem_iconwithtext_textleftpadding"
+ android:layout_marginStart="@dimen/listitem_iconwithtext_textleftpadding"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_toEndOf="@id/imgvCover"
android:layout_toLeftOf="@id/txtvTime"
+ android:layout_toStartOf="@id/txtvTime"
android:layout_alignWithParentIfMissing="true"
tools:text="Navigation feed item title"
tools:background="@android:color/holo_green_dark"/>
diff --git a/app/src/main/res/layout/subscription_item.xml b/app/src/main/res/layout/subscription_item.xml
index 8f0539dfa..502fa8672 100644
--- a/app/src/main/res/layout/subscription_item.xml
+++ b/app/src/main/res/layout/subscription_item.xml
@@ -11,7 +11,7 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="centerCrop"
- tools:src="@drawable/ic_launcher">
+ tools:src="@mipmap/ic_launcher_round">
</de.danoeh.antennapod.view.SquareImageView>
<com.joanzapata.iconify.widget.IconTextView
diff --git a/app/src/main/res/layout/time_dialog.xml b/app/src/main/res/layout/time_dialog.xml
index 0290ce708..ba4249268 100644
--- a/app/src/main/res/layout/time_dialog.xml
+++ b/app/src/main/res/layout/time_dialog.xml
@@ -8,7 +8,7 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:orientation="horizontal" >
<EditText
android:id="@+id/etxtTime"
@@ -18,9 +18,11 @@
android:layout_margin="8dp"
android:ems="2"
android:hint="@string/enter_time_here_label"
-
android:inputType="number"
- android:maxLength="2" />
+ android:maxLength="2" >
+
+ <requestFocus />
+ </EditText>
<Spinner
android:id="@+id/spTimeUnit"
@@ -28,7 +30,6 @@
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp" />
-
</LinearLayout>
<LinearLayout
diff --git a/app/src/main/res/layout/videoplayer_activity.xml b/app/src/main/res/layout/videoplayer_activity.xml
index 4db663e19..ebea0c618 100644
--- a/app/src/main/res/layout/videoplayer_activity.xml
+++ b/app/src/main/res/layout/videoplayer_activity.xml
@@ -3,7 +3,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:id="@+id/videoframe">
<de.danoeh.antennapod.view.AspectRatioVideoView
android:id="@+id/videoview"
@@ -24,6 +25,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
+ android:layoutDirection="ltr"
android:orientation="horizontal">
<ImageButton
@@ -67,6 +69,7 @@
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#80000000"
+ android:layoutDirection="ltr"
android:paddingTop="8dp">
<TextView
@@ -74,10 +77,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
android:layout_marginTop="4dp"
android:text="@string/position_default_label"
android:textColor="@color/white"
@@ -88,10 +94,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
android:layout_marginTop="4dp"
android:text="@string/position_default_label"
android:textColor="@color/white"
@@ -102,7 +111,10 @@
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/txtvLength"
+ android:layout_toStartOf="@+id/txtvLength"
android:layout_toRightOf="@+id/txtvPosition"
+ android:layout_toEndOf="@+id/txtvPosition"
+ android:layout_centerInParent="true"
android:max="500" />
</RelativeLayout>
diff --git a/app/src/main/res/menu/allepisodes_context.xml b/app/src/main/res/menu/allepisodes_context.xml
index 7398b9118..28493c5b6 100644
--- a/app/src/main/res/menu/allepisodes_context.xml
+++ b/app/src/main/res/menu/allepisodes_context.xml
@@ -7,6 +7,12 @@
android:menuCategory="container"
android:title="@string/skip_episode_label" />
+
+ <item
+ android:id="@+id/mark_as_seen_item"
+ android:menuCategory="container"
+ android:title="@string/mark_as_seen_label" />
+
<item
android:id="@+id/mark_read_item"
android:menuCategory="container"
diff --git a/app/src/main/res/menu/downloads_completed.xml b/app/src/main/res/menu/downloads_completed.xml
index dc2996893..a88d93913 100644
--- a/app/src/main/res/menu/downloads_completed.xml
+++ b/app/src/main/res/menu/downloads_completed.xml
@@ -6,7 +6,8 @@
<item
android:id="@+id/episode_actions"
android:menuCategory="container"
- android:title="@string/episode_actions"
+ android:title="@string/batch_edit"
+ android:icon="?attr/checkbox_multiple"
custom:showAsAction="always">
</item>
diff --git a/app/src/main/res/menu/feedlist.xml b/app/src/main/res/menu/feedlist.xml
index 0646dc70f..3882cdff1 100644
--- a/app/src/main/res/menu/feedlist.xml
+++ b/app/src/main/res/menu/feedlist.xml
@@ -12,7 +12,8 @@
<item
android:id="@+id/episode_actions"
android:menuCategory="container"
- android:title="@string/episode_actions"
+ android:icon="?attr/checkbox_multiple"
+ android:title="@string/batch_edit"
custom:showAsAction="always">
</item>
<item
diff --git a/app/src/main/res/menu/mediaplayer.xml b/app/src/main/res/menu/mediaplayer.xml
index 530eb3400..98c7478a6 100644
--- a/app/src/main/res/menu/mediaplayer.xml
+++ b/app/src/main/res/menu/mediaplayer.xml
@@ -41,6 +41,14 @@
android:title="@string/visit_website_label"
android:visible="false">
</item>
+
+ <item
+ android:id="@+id/player_go_to_picture_in_picture"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/player_go_to_picture_in_picture"
+ android:visible="false">
+ </item>
+
<item
android:id="@+id/share_item"
android:icon="?attr/social_share"
diff --git a/app/src/main/res/menu/queue.xml b/app/src/main/res/menu/queue.xml
index a5fe85865..7b82cbef3 100644
--- a/app/src/main/res/menu/queue.xml
+++ b/app/src/main/res/menu/queue.xml
@@ -90,6 +90,25 @@
android:title="@string/descending"/>
</menu>
</item>
+
+ <item
+ android:id="@+id/queue_sort_random"
+ android:title="@string/random">
+ </item>
+
+ <item
+ android:id="@+id/queue_sort_smart_shuffle"
+ android:title="@string/smart_shuffle">
+
+ <menu>
+ <item
+ android:id="@+id/queue_sort_smart_shuffle_asc"
+ android:title="@string/ascending"/>
+ <item
+ android:id="@+id/queue_sort_smart_shuffle_desc"
+ android:title="@string/descending"/>
+ </menu>
+ </item>
</menu>
</item>
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index e81115627..f45847e54 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -1,347 +1,58 @@
<?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:android="http://schemas.android.com/apk/res/android">
- <PreferenceCategory android:title="@string/user_interface_label">
- <com.afollestad.materialdialogs.prefs.MaterialListPreference
- android:entryValues="@array/theme_values"
- android:entries="@array/theme_options"
- android:title="@string/pref_set_theme_title"
- android:key="prefTheme"
- android:summary="@string/pref_set_theme_sum"
- android:defaultValue="0"
- app:useStockLayout="true"/>
- <PreferenceScreen
- android:key="prefDrawerSettings"
- android:summary="@string/pref_nav_drawer_sum"
- android:title="@string/pref_nav_drawer_title">
- <Preference
- android:key="prefHiddenDrawerItems"
- android:summary="@string/pref_nav_drawer_items_sum"
- android:title="@string/pref_nav_drawer_items_title" />
- <com.afollestad.materialdialogs.prefs.MaterialListPreference
- android:entryValues="@array/nav_drawer_feed_order_values"
- android:entries="@array/nav_drawer_feed_order_options"
- android:title="@string/pref_nav_drawer_feed_order_title"
- android:key="prefDrawerFeedOrder"
- android:summary="@string/pref_nav_drawer_feed_order_sum"
- android:defaultValue="0"
- app:useStockLayout="true"/>
- <com.afollestad.materialdialogs.prefs.MaterialListPreference
- android:entryValues="@array/nav_drawer_feed_counter_values"
- android:entries="@array/nav_drawer_feed_counter_options"
- android:title="@string/pref_nav_drawer_feed_counter_title"
- android:key="prefDrawerFeedIndicator"
- android:summary="@string/pref_nav_drawer_feed_counter_sum"
- android:defaultValue="0"
- app:useStockLayout="true"/>
- </PreferenceScreen>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="false"
- android:enabled="true"
- android:key="prefExpandNotify"
- android:summary="@string/pref_expandNotify_sum"
- android:title="@string/pref_expandNotify_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="true"
- android:enabled="true"
- android:key="prefPersistNotify"
- android:summary="@string/pref_persistNotify_sum"
- android:title="@string/pref_persistNotify_title"/>
- <Preference
- android:key="prefCompactNotificationButtons"
- android:summary="@string/pref_compact_notification_buttons_sum"
- android:title="@string/pref_compact_notification_buttons_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="true"
- android:enabled="true"
- android:key="prefLockscreenBackground"
- android:summary="@string/pref_lockscreen_background_sum"
- android:title="@string/pref_lockscreen_background_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="true"
- android:enabled="true"
- android:key="prefShowDownloadReport"
- android:summary="@string/pref_showDownloadReport_sum"
- android:title="@string/pref_showDownloadReport_title"/>
- </PreferenceCategory>
+ <com.bytehamster.lib.preferencesearch.SearchPreference
+ android:key="searchPreference" />
- <PreferenceCategory android:title="@string/queue_label">
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="false"
- android:enabled="true"
- android:key="prefQueueAddToFront"
- android:summary="@string/pref_queueAddToFront_sum"
- android:title="@string/pref_queueAddToFront_title"/>
- </PreferenceCategory>
+ <Preference
+ android:key="prefScreenInterface"
+ android:title="@string/user_interface_label"
+ android:icon="?attr/ic_cellphone_text" />
- <PreferenceCategory android:title="@string/playback_pref">
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="true"
- android:enabled="false"
- android:key="prefSonic"
- android:summary="@string/pref_sonic_message"
- android:title="@string/pref_sonic_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="true"
- android:enabled="true"
- android:key="prefPauseOnHeadsetDisconnect"
- android:summary="@string/pref_pauseOnDisconnect_sum"
- android:title="@string/pref_pauseOnHeadsetDisconnect_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="true"
- android:enabled="true"
- android:dependency="prefPauseOnHeadsetDisconnect"
- android:key="prefUnpauseOnHeadsetReconnect"
- android:summary="@string/pref_unpauseOnHeadsetReconnect_sum"
- android:title="@string/pref_unpauseOnHeadsetReconnect_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="false"
- android:enabled="true"
- android:dependency="prefPauseOnHeadsetDisconnect"
- android:key="prefUnpauseOnBluetoothReconnect"
- android:summary="@string/pref_unpauseOnBluetoothReconnect_sum"
- android:title="@string/pref_unpauseOnBluetoothReconnect_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="false"
- android:enabled="true"
- android:key="prefHardwareForwardButtonSkips"
- android:summary="@string/pref_hardwareForwardButtonSkips_sum"
- android:title="@string/pref_hardwareForwardButtonSkips_title"/>
- <Preference
- android:key="prefPlaybackFastForwardDeltaLauncher"
- android:summary="@string/pref_fast_forward_sum"
- android:title="@string/pref_fast_forward" />
- <Preference
- android:key="prefPlaybackRewindDeltaLauncher"
- android:summary="@string/pref_rewind_sum"
- android:title="@string/pref_rewind" />
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="false"
- android:enabled="true"
- android:key="prefHardwarePreviousButtonRestarts"
- android:summary="@string/pref_hardwarePreviousButtonRestarts_sum"
- android:title="@string/pref_hardwarePreviousButtonRestarts_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="true"
- android:enabled="true"
- android:key="prefFollowQueue"
- android:summary="@string/pref_followQueue_sum"
- android:title="@string/pref_followQueue_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="true"
- android:enabled="true"
- android:key="prefSkipKeepsEpisode"
- android:summary="@string/pref_skip_keeps_episodes_sum"
- android:title="@string/pref_skip_keeps_episodes_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="true"
- android:enabled="true"
- android:key="prefFavoriteKeepsEpisode"
- android:summary="@string/pref_favorite_keeps_episodes_sum"
- android:title="@string/pref_favorite_keeps_episodes_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="false"
- android:enabled="true"
- android:key="prefAutoDelete"
- android:summary="@string/pref_auto_delete_sum"
- android:title="@string/pref_auto_delete_title"/>
- <com.afollestad.materialdialogs.prefs.MaterialListPreference
- android:defaultValue="30"
- android:entries="@array/smart_mark_as_played_values"
- android:entryValues="@array/smart_mark_as_played_values"
- android:key="prefSmartMarkAsPlayedSecs"
- android:summary="@string/pref_smart_mark_as_played_sum"
- android:title="@string/pref_smart_mark_as_played_title"
- app:useStockLayout="true"/>
- <Preference
- android:key="prefPlaybackSpeedLauncher"
- android:summary="@string/pref_playback_speed_sum"
- android:title="@string/pref_playback_speed_title" />
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="false"
- android:enabled="true"
- android:key="prefPauseForFocusLoss"
- android:summary="@string/pref_pausePlaybackForFocusLoss_sum"
- android:title="@string/pref_pausePlaybackForFocusLoss_title" />
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="true"
- android:enabled="true"
- android:key="prefResumeAfterCall"
- android:summary="@string/pref_resumeAfterCall_sum"
- android:title="@string/pref_resumeAfterCall_title"/>
+ <Preference
+ android:key="prefScreenPlayback"
+ android:title="@string/playback_pref"
+ android:icon="?attr/av_play" />
- </PreferenceCategory>
- <PreferenceCategory android:title="@string/network_pref">
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="true"
- android:enabled="true"
- android:key="prefEnqueueDownloaded"
- android:summary="@string/pref_enqueue_downloaded_summary"
- android:title="@string/pref_enqueue_downloaded_title" />
- <Preference
- android:key="prefAutoUpdateIntervall"
- android:summary="@string/pref_autoUpdateIntervallOrTime_sum"
- android:title="@string/pref_autoUpdateIntervallOrTime_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="false"
- android:enabled="true"
- android:key="prefMobileUpdate"
- android:summary="@string/pref_mobileUpdate_sum"
- android:title="@string/pref_mobileUpdate_title"/>
- <com.afollestad.materialdialogs.prefs.MaterialListPreference
- android:defaultValue="-1"
- android:entries="@array/episode_cleanup_entries"
- android:key="prefEpisodeCleanup"
- android:title="@string/pref_episode_cleanup_title"
- android:summary="@string/pref_episode_cleanup_summary"
- android:entryValues="@array/episode_cleanup_values"
- app:useStockLayout="true"/>
- <com.afollestad.materialdialogs.prefs.MaterialEditTextPreference
- android:defaultValue="4"
- android:inputType="number"
- android:key="prefParallelDownloads"
- android:title="@string/pref_parallel_downloads_title"
- app:useStockLayout="true"/>
- <PreferenceScreen
- android:summary="@string/pref_automatic_download_sum"
- android:key="prefAutoDownloadSettings"
- android:title="@string/pref_automatic_download_title">
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:key="prefEnableAutoDl"
- android:title="@string/pref_automatic_download_title"
- android:defaultValue="false"/>
- <com.afollestad.materialdialogs.prefs.MaterialListPreference
- android:defaultValue="25"
- android:entries="@array/episode_cache_size_entries"
- android:key="prefEpisodeCacheSize"
- android:title="@string/pref_episode_cache_title"
- android:entryValues="@array/episode_cache_size_values"
- app:useStockLayout="true"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:key="prefEnableAutoDownloadOnBattery"
- android:title="@string/pref_automatic_download_on_battery_title"
- android:summary="@string/pref_automatic_download_on_battery_sum"
- android:defaultValue="true"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:key="prefEnableAutoDownloadOnMobile"
- android:title="@string/pref_autodl_allow_on_mobile_title"
- android:summary="@string/pref_autodl_allow_on_mobile_sum"
- android:defaultValue="false"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:key="prefEnableAutoDownloadWifiFilter"
- android:title="@string/pref_autodl_wifi_filter_title"
- android:summary="@string/pref_autodl_wifi_filter_sum"/>
- </PreferenceScreen>
- <Preference
- android:key="prefProxy"
- android:summary="@string/pref_proxy_sum"
- android:title="@string/pref_proxy_title" />
-
- </PreferenceCategory>
+ <Preference
+ android:key="prefScreenNetwork"
+ android:title="@string/network_pref"
+ android:icon="?attr/ic_swap" />
- <PreferenceCategory android:title="@string/services_label">
- <PreferenceScreen
- android:key="prefFlattrSettings"
- android:title="@string/flattr_label">
- <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="prefScreenIntegrations"
+ android:title="@string/integrations_label"
+ android:icon="?attr/ic_unfav" />
- <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>
- <PreferenceScreen
- android:key="prefGpodderSettings"
- android:title="@string/gpodnet_main_label">
+ <Preference
+ android:key="prefScreenStorage"
+ android:title="@string/storage_pref"
+ android:icon="?attr/storage" />
- <PreferenceScreen
- android:key="pref_gpodnet_authenticate"
- android:title="@string/pref_gpodnet_authenticate_title"
- android:summary="@string/pref_gpodnet_authenticate_sum">
- <intent android:action=".activity.gpoddernet.GpodnetAuthenticationActivity"/>
- </PreferenceScreen>
- <Preference
- android:key="pref_gpodnet_setlogin_information"
- android:title="@string/pref_gpodnet_setlogin_information_title"
- android:summary="@string/pref_gpodnet_setlogin_information_sum"/>
- <Preference
- android:key="pref_gpodnet_sync"
- android:title="@string/pref_gpodnet_sync_changes_title"
- android:summary="@string/pref_gpodnet_sync_changes_sum"/>
- <Preference
- android:key="pref_gpodnet_force_full_sync"
- android:title="@string/pref_gpodnet_full_sync_title"
- android:summary="@string/pref_gpodnet_full_sync_sum"/>
- <Preference
- android:key="pref_gpodnet_logout"
- android:title="@string/pref_gpodnet_logout_title"/>
- <Preference
- android:key="pref_gpodnet_hostname"
- android:title="@string/pref_gpodnet_sethostname_title"/>
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:key="pref_gpodnet_notifications"
- android:title="@string/pref_gpodnet_notifications_title"
- android:summary="@string/pref_gpodnet_notifications_sum"
- android:defaultValue="true"/>
- </PreferenceScreen>
- </PreferenceCategory>
- <PreferenceCategory android:title="@string/storage_pref">
- <Preference
- android:title="@string/choose_data_directory"
- android:key="prefChooseDataDir"/>
- <ListPreference
- android:entryValues="@array/image_cache_size_values"
- android:entries="@array/image_cache_size_options"
- android:title="@string/pref_image_cache_size_title"
- android:key="prefImageCacheSize"
- android:summary="@string/pref_image_cache_size_sum"
- android:defaultValue="100"/>
- </PreferenceCategory>
- <PreferenceCategory android:title="@string/other_pref">
- <Preference
- android:key="prefOpmlExport"
- android:title="@string/opml_export_label"/>
- <Preference
- android:key="prefHtmlExport"
- android:title="@string/html_export_label"/>
- <Preference
+ <Preference
android:key="statistics"
- android:title="@string/statistics_label"/>
- </PreferenceCategory>
+ android:title="@string/statistics_label"
+ android:icon="?attr/statistics" />
+
<PreferenceCategory android:title="@string/project_pref">
<Preference
android:key="prefFaq"
- android:title="@string/pref_faq"/>
+ android:title="@string/pref_faq"
+ android:icon="?attr/ic_question_answer" />
+
<Preference
android:key="prefKnownIssues"
- android:title="@string/pref_known_issues"/>
+ android:title="@string/pref_known_issues"
+ android:icon="?attr/ic_known_issues" />
<Preference
android:key="prefSendCrashReport"
android:title="@string/crash_report_title"
- android:summary="@string/crash_report_sum"/>
+ android:summary="@string/crash_report_sum"
+ android:icon="?attr/ic_bug" />
<Preference
android:key="prefAbout"
- android:title="@string/about_pref"/>
- </PreferenceCategory>
-
- <PreferenceCategory android:title="@string/experimental_pref">
- <de.danoeh.antennapod.preferences.SwitchCompatPreference
- android:defaultValue="false"
- android:enabled="true"
- android:key="prefCast"
- android:summary="@string/pref_cast_message"
- android:title="@string/pref_cast_title"/>
+ android:title="@string/about_pref"
+ android:icon="?attr/action_about" />
</PreferenceCategory>
-
</PreferenceScreen>
diff --git a/app/src/main/res/xml/preferences_autodownload.xml b/app/src/main/res/xml/preferences_autodownload.xml
new file mode 100644
index 000000000..b5e3182f0
--- /dev/null
+++ b/app/src/main/res/xml/preferences_autodownload.xml
@@ -0,0 +1,41 @@
+<?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">
+
+ <de.danoeh.antennapod.preferences.MasterSwitchPreference
+ android:key="prefEnableAutoDl"
+ android:title="@string/pref_automatic_download_title"
+ search:summary="@string/pref_automatic_download_sum"
+ android:defaultValue="false"/>
+ <ListPreference
+ android:defaultValue="25"
+ android:entries="@array/episode_cache_size_entries"
+ android:key="prefEpisodeCacheSize"
+ android:title="@string/pref_episode_cache_title"
+ android:entryValues="@array/episode_cache_size_values"
+ app:useStockLayout="true"/>
+ <ListPreference
+ android:defaultValue="-1"
+ android:entries="@array/episode_cleanup_entries"
+ android:key="prefEpisodeCleanup"
+ android:title="@string/pref_episode_cleanup_title"
+ android:summary="@string/pref_episode_cleanup_summary"
+ android:entryValues="@array/episode_cleanup_values"
+ app:useStockLayout="true"/>
+ <SwitchPreference
+ android:key="prefEnableAutoDownloadOnBattery"
+ android:title="@string/pref_automatic_download_on_battery_title"
+ 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"/>
+</PreferenceScreen>
diff --git a/app/src/main/res/xml/preferences_flattr.xml b/app/src/main/res/xml/preferences_flattr.xml
new file mode 100644
index 000000000..6b4c38a0b
--- /dev/null
+++ b/app/src/main/res/xml/preferences_flattr.xml
@@ -0,0 +1,21 @@
+<?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_gpodder.xml b/app/src/main/res/xml/preferences_gpodder.xml
new file mode 100644
index 000000000..5789f5f84
--- /dev/null
+++ b/app/src/main/res/xml/preferences_gpodder.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <PreferenceScreen
+ android:key="pref_gpodnet_authenticate"
+ android:title="@string/pref_gpodnet_authenticate_title"
+ android:summary="@string/pref_gpodnet_authenticate_sum">
+ <intent android:action=".activity.gpoddernet.GpodnetAuthenticationActivity"/>
+ </PreferenceScreen>
+ <Preference
+ android:key="pref_gpodnet_setlogin_information"
+ android:title="@string/pref_gpodnet_setlogin_information_title"
+ android:summary="@string/pref_gpodnet_setlogin_information_sum"/>
+ <Preference
+ android:key="pref_gpodnet_sync"
+ android:title="@string/pref_gpodnet_sync_changes_title"
+ android:summary="@string/pref_gpodnet_sync_changes_sum"/>
+ <Preference
+ android:key="pref_gpodnet_force_full_sync"
+ android:title="@string/pref_gpodnet_full_sync_title"
+ android:summary="@string/pref_gpodnet_full_sync_sum"/>
+ <Preference
+ android:key="pref_gpodnet_logout"
+ android:title="@string/pref_gpodnet_logout_title"/>
+ <Preference
+ android:key="pref_gpodnet_hostname"
+ android:title="@string/pref_gpodnet_sethostname_title"/>
+ <SwitchPreference
+ android:key="pref_gpodnet_notifications"
+ android:title="@string/pref_gpodnet_notifications_title"
+ android:summary="@string/pref_gpodnet_notifications_sum"
+ android:defaultValue="true"/>
+
+</PreferenceScreen>
diff --git a/app/src/main/res/xml/preferences_integrations.xml b/app/src/main/res/xml/preferences_integrations.xml
new file mode 100644
index 000000000..c0fd299ec
--- /dev/null
+++ b/app/src/main/res/xml/preferences_integrations.xml
@@ -0,0 +1,16 @@
+<?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" />
+
+ <Preference
+ android:key="prefGpodderSettings"
+ android:title="@string/gpodnet_main_label"
+ android:summary="@string/gpodnet_summary" />
+
+</PreferenceScreen>
diff --git a/app/src/main/res/xml/preferences_network.xml b/app/src/main/res/xml/preferences_network.xml
new file mode 100644
index 000000000..c37a99465
--- /dev/null
+++ b/app/src/main/res/xml/preferences_network.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:numberpicker="http://schemas.android.com/apk/de.danoeh.antennapod"
+ xmlns:search="http://schemas.android.com/apk/com.bytehamster.lib.preferencesearch">
+ <PreferenceCategory android:title="@string/automation">
+ <Preference
+ android:key="prefAutoUpdateIntervall"
+ android:summary="@string/pref_autoUpdateIntervallOrTime_sum"
+ android:title="@string/pref_autoUpdateIntervallOrTime_title"/>
+ <Preference
+ android:summary="@string/pref_automatic_download_sum"
+ android:key="prefAutoDownloadSettings"
+ android:title="@string/pref_automatic_download_title"
+ search:ignore="true" />
+ </PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/download_pref_details">
+ <SwitchPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefMobileUpdate"
+ android:summary="@string/pref_mobileUpdate_sum"
+ android:title="@string/pref_mobileUpdate_title"/>
+ <de.danoeh.antennapod.preferences.NumberPickerPreference
+ android:defaultValue="4"
+ numberpicker:minValue="1"
+ numberpicker:maxValue="50"
+ android:key="prefParallelDownloads"
+ android:title="@string/pref_parallel_downloads_title"/>
+ <SwitchPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:key="prefShowDownloadReport"
+ android:summary="@string/pref_showDownloadReport_sum"
+ android:title="@string/pref_showDownloadReport_title"/>
+ <Preference
+ android:key="prefProxy"
+ android:summary="@string/pref_proxy_sum"
+ android:title="@string/pref_proxy_title"/>
+ </PreferenceCategory>
+</PreferenceScreen>
diff --git a/app/src/main/res/xml/preferences_playback.xml b/app/src/main/res/xml/preferences_playback.xml
new file mode 100644
index 000000000..9182df600
--- /dev/null
+++ b/app/src/main/res/xml/preferences_playback.xml
@@ -0,0 +1,130 @@
+<?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">
+
+ <PreferenceCategory android:title="@string/interruptions">
+ <SwitchPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:key="prefPauseOnHeadsetDisconnect"
+ android:summary="@string/pref_pauseOnDisconnect_sum"
+ android:title="@string/pref_pauseOnHeadsetDisconnect_title"/>
+ <SwitchPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:dependency="prefPauseOnHeadsetDisconnect"
+ android:key="prefUnpauseOnHeadsetReconnect"
+ android:summary="@string/pref_unpauseOnHeadsetReconnect_sum"
+ android:title="@string/pref_unpauseOnHeadsetReconnect_title"/>
+ <SwitchPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:dependency="prefPauseOnHeadsetDisconnect"
+ android:key="prefUnpauseOnBluetoothReconnect"
+ android:summary="@string/pref_unpauseOnBluetoothReconnect_sum"
+ android:title="@string/pref_unpauseOnBluetoothReconnect_title"/>
+ <SwitchPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefPauseForFocusLoss"
+ android:summary="@string/pref_pausePlaybackForFocusLoss_sum"
+ android:title="@string/pref_pausePlaybackForFocusLoss_title"/>
+ <SwitchPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:key="prefResumeAfterCall"
+ android:summary="@string/pref_resumeAfterCall_sum"
+ android:title="@string/pref_resumeAfterCall_title"/>
+ <ListPreference
+ android:defaultValue="stop"
+ android:entries="@array/video_background_behavior_options"
+ android:entryValues="@array/video_background_behavior_values"
+ android:key="prefVideoBehavior"
+ android:summary="@string/pref_videoBehavior_sum"
+ android:title="@string/pref_videoBehavior_title"
+ app:useStockLayout="true"/>
+ </PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/buttons">
+ <SwitchPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefHardwareForwardButtonSkips"
+ android:summary="@string/pref_hardwareForwardButtonSkips_sum"
+ android:title="@string/pref_hardwareForwardButtonSkips_title"/>
+ <SwitchPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefHardwarePreviousButtonRestarts"
+ android:summary="@string/pref_hardwarePreviousButtonRestarts_sum"
+ android:title="@string/pref_hardwarePreviousButtonRestarts_title"/>
+ <Preference
+ android:key="prefPlaybackFastForwardDeltaLauncher"
+ android:summary="@string/pref_fast_forward_sum"
+ android:title="@string/pref_fast_forward"/>
+ <Preference
+ android:key="prefPlaybackRewindDeltaLauncher"
+ android:summary="@string/pref_rewind_sum"
+ android:title="@string/pref_rewind"/>
+ <Preference
+ android:key="prefPlaybackSpeedLauncher"
+ android:summary="@string/pref_playback_speed_sum"
+ android:title="@string/pref_playback_speed_title"/>
+ </PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/queue_label">
+ <SwitchPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:key="prefEnqueueDownloaded"
+ android:summary="@string/pref_enqueue_downloaded_summary"
+ android:title="@string/pref_enqueue_downloaded_title" />
+ <SwitchPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefQueueAddToFront"
+ android:summary="@string/pref_queueAddToFront_sum"
+ android:title="@string/pref_queueAddToFront_title"/>
+ <SwitchPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:key="prefFollowQueue"
+ android:summary="@string/pref_followQueue_sum"
+ android:title="@string/pref_followQueue_title"/>
+ <ListPreference
+ android:defaultValue="30"
+ android:entries="@array/smart_mark_as_played_values"
+ android:entryValues="@array/smart_mark_as_played_values"
+ android:key="prefSmartMarkAsPlayedSecs"
+ android:summary="@string/pref_smart_mark_as_played_sum"
+ android:title="@string/pref_smart_mark_as_played_title"
+ app:useStockLayout="true"/>
+ <SwitchPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:key="prefSkipKeepsEpisode"
+ android:summary="@string/pref_skip_keeps_episodes_sum"
+ android:title="@string/pref_skip_keeps_episodes_title"/>
+ </PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/media_player">
+ <ListPreference
+ android:defaultValue="sonic"
+ android:entries="@array/media_player_options"
+ android:key="prefMediaPlayer"
+ android:title="@string/media_player"
+ android:summary="@string/pref_media_player_message"
+ android:entryValues="@array/media_player_values"
+ app:useStockLayout="true"/>
+ </PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/experimental_pref">
+ <SwitchPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefCast"
+ android:summary="@string/pref_cast_message"
+ android:title="@string/pref_cast_title"/>
+ </PreferenceCategory>
+</PreferenceScreen>
diff --git a/app/src/main/res/xml/preferences_storage.xml b/app/src/main/res/xml/preferences_storage.xml
new file mode 100644
index 000000000..fe48cc99c
--- /dev/null
+++ b/app/src/main/res/xml/preferences_storage.xml
@@ -0,0 +1,43 @@
+<?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:title="@string/choose_data_directory"
+ android:key="prefChooseDataDir"/>
+ <ListPreference
+ android:entryValues="@array/image_cache_size_values"
+ android:entries="@array/image_cache_size_options"
+ android:title="@string/pref_image_cache_size_title"
+ android:key="prefImageCacheSize"
+ android:summary="@string/pref_image_cache_size_sum"
+ android:defaultValue="100"/>
+ <SwitchPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefAutoDelete"
+ android:summary="@string/pref_auto_delete_sum"
+ android:title="@string/pref_auto_delete_title"/>
+ <SwitchPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:key="prefFavoriteKeepsEpisode"
+ android:summary="@string/pref_favorite_keeps_episodes_sum"
+ android:title="@string/pref_favorite_keeps_episodes_title"/>
+
+ <PreferenceCategory android:title="@string/import_export_pref">
+ <Preference
+ android:key="prefOpmlExport"
+ android:title="@string/opml_export_label"/>
+ <Preference
+ android:key="prefOpmlImport"
+ android:title="@string/opml_import_label"/>
+ <Preference
+ android:key="prefHtmlExport"
+ android:title="@string/html_export_label"/>
+ <Preference
+ android:key="importExport"
+ android:title="@string/import_export"/>
+ </PreferenceCategory>
+</PreferenceScreen>
diff --git a/app/src/main/res/xml/preferences_user_interface.xml b/app/src/main/res/xml/preferences_user_interface.xml
new file mode 100644
index 000000000..1d970a5f7
--- /dev/null
+++ b/app/src/main/res/xml/preferences_user_interface.xml
@@ -0,0 +1,70 @@
+<?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">
+
+ <PreferenceCategory android:title="@string/appearance">
+ <ListPreference
+ android:entryValues="@array/theme_values"
+ android:entries="@array/theme_options"
+ android:title="@string/pref_set_theme_title"
+ android:key="prefTheme"
+ android:summary="@string/pref_set_theme_sum"
+ android:defaultValue="0"
+ app:useStockLayout="true"/>
+ <Preference
+ android:key="prefHiddenDrawerItems"
+ android:summary="@string/pref_nav_drawer_items_sum"
+ android:title="@string/pref_nav_drawer_items_title"/>
+ <ListPreference
+ android:entryValues="@array/nav_drawer_feed_order_values"
+ android:entries="@array/nav_drawer_feed_order_options"
+ android:title="@string/pref_nav_drawer_feed_order_title"
+ android:key="prefDrawerFeedOrder"
+ android:summary="@string/pref_nav_drawer_feed_order_sum"
+ android:defaultValue="0"
+ app:useStockLayout="true"/>
+ <ListPreference
+ android:entryValues="@array/nav_drawer_feed_counter_values"
+ android:entries="@array/nav_drawer_feed_counter_options"
+ android:title="@string/pref_nav_drawer_feed_counter_title"
+ android:key="prefDrawerFeedIndicator"
+ android:summary="@string/pref_nav_drawer_feed_counter_sum"
+ android:defaultValue="0"
+ app:useStockLayout="true"/>
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/external_elements">
+ <SwitchPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefExpandNotify"
+ android:summary="@string/pref_expandNotify_sum"
+ android:title="@string/pref_expandNotify_title"/>
+ <SwitchPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:key="prefPersistNotify"
+ android:summary="@string/pref_persistNotify_sum"
+ android:title="@string/pref_persistNotify_title"/>
+ <Preference
+ android:key="prefCompactNotificationButtons"
+ android:summary="@string/pref_compact_notification_buttons_sum"
+ android:title="@string/pref_compact_notification_buttons_title"/>
+ <SwitchPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:key="prefLockscreenBackground"
+ android:summary="@string/pref_lockscreen_background_sum"
+ android:title="@string/pref_lockscreen_background_title"/>
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/behavior">
+ <ListPreference
+ android:entryValues="@array/back_button_behavior_values"
+ android:entries="@array/back_button_behavior_options"
+ android:key="prefBackButtonBehavior"
+ android:title="@string/pref_back_button_behavior_title"
+ android:summary="@string/pref_back_button_behavior_sum"
+ android:defaultValue="default"
+ app:useStockLayout="true"/>
+ </PreferenceCategory>
+</PreferenceScreen>
diff --git a/app/src/main/templates/about.html b/app/src/main/templates/about.html
index 400727c46..cc3a24e62 100644
--- a/app/src/main/templates/about.html
+++ b/app/src/main/templates/about.html
@@ -8,30 +8,52 @@
font-family: 'Roboto-Light';
src: url('file:///android_asset/Roboto-Light.ttf');
}
+
+ html, body {
+ background: @background@;
+ margin: 0;
+ padding: 0;
+ }
* {
- color: %s;
+ color: @fontcolor@;
font-family: roboto-Light;
font-size: 12pt;
}
- header {
+ img#logo {
display: block;
margin-left: auto;
margin-right: auto;
- padding-bottom: 500px;
+ max-height: 200px;
+ max-height: 50vh;
+ max-width: 100%;
+ height: auto;
+ width: auto;
}
-
- versiontag {
- color: gray;
+
+ div#logobackground{
+ width: 100%;
+ background: #42a5f5;
+ }
+
+ .card {
+ background: @card_background@;
+ margin: 10px;
+ padding: 10px;
+ border: 1px solid @card_border@;
+ border-top-width: 0;
+ border-bottom-width: 2px;
}
h1 {
font-size: 15pt;
+ margin-left: 20px;
}
h2 {
font-size: 13pt;
+ margin-top: 0px;
}
a {
@@ -44,67 +66,117 @@
<title>About AntennaPod</title>
</head>
<body>
-<div id="header" align="center">
- <img src="file:///android_asset/logo.png" alt="Logo" width="100px" height="100px"/>
-
- <p>AntennaPod, Version @versionname@</p>
- <p>Commit: @commit@</p>
+<div id="logobackground">
+<img id="logo" src="file:///android_asset/logo.png" alt="Logo"/>
+</div>
- <p>Created by Daniel Oeh</p>
+<h1>AntennaPod</h1>
- <p>Copyright &copy; 2012-@year@ AntennaPod Contributors <a href="CONTRIBUTORS.txt">(View)</a></p>
+<div class="card">
+<table>
+<tr><td>Version:</td><td><b>@versionname@</b></td></tr>
+<tr><td>Commit:</td><td><b>@commit@</b></td></tr>
+</table>
+</div>
- <p>Licensed under the MIT License <a href="LICENSE.txt">(View)</a></p>
+<div class="card">
+Created by Daniel Oeh<br />
+Copyright &copy; 2012-@year@<br />
+AntennaPod Contributors <a href="CONTRIBUTORS.txt">(View)</a><br />
+Licensed under the MIT License <a href="LICENSE.txt">(View)</a>
</div>
+
<h1>Used libraries</h1>
+<div class="card">
<h2>Apache Commons <a href="http://commons.apache.org/">(Link)</a></h2>
by The Apache Software Foundation, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
+</div>
+<div class="card">
<h2>EventBus <a href="https://github.com/greenrobot/EventBus">(Link)</a></h2>
by greenrobot, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
+</div>
+
+<div class="card">
+<h2>ExoPlayer <a href="https://github.com/google/ExoPlayer">(Link)</a></h2>
+by Google, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
+</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>
+<div class="card">
<h2>Iconify <a href="https://github.com/JoanZapata/android-iconify">(Link)</a></h2>
by Joan Zapata, licensed under the Apache 2.0 license <a href="LICENSE_ANDROID_ICONIFY.txt">(View)</a>
+</div>
+<div class="card">
<h2>jsoup <a href="http://jsoup.org/">(Link)</a></h2>
licensed under the MIT license <a href="LICENSE_JSOUP.txt">(View)</a>
+</div>
+<div class="card">
<h2>Material Design Icons <a href="https://github.com/google/material-design-icons">(Link)</a></h2>
by Google, licensed under an Attribution-ShareAlike 4.0 International license <a href="LICENSE_MATERIAL_DESIGN_ICONS.txt">(View)</a>
+</div>
+
+<div class="card">
+<h2>Material Design Icons <a href="https://github.com/Templarian/MaterialDesign">(Link)</a></h2>
+by Templarian, licensed under the SIL Open Font License, Version 1.1 <a href="LICENSE_SIL.txt">(View)</a>
+</div>
+<div class="card">
<h2>Material Dialogs <a href="https://github.com/afollestad/material-dialogs">(Link)</a></h2>
by Aidan Michael Follestad, licensed under the MIT License <a href="LICENSE_MATERIAL_DIALOGS.txt">(View)</a>
+</div>
+<div class="card">
<h2>OkHttp <a href="https://github.com/square/okhttp">(Link)</a></h2>
by Square, licensed under the Apache 2.0 license <a href="LICENSE_OKHTTP.txt">(View)</a>
+</div>
+<div class="card">
<h2>Okio <a href="https://github.com/square/okio">(Link)</a></h2>
by Square, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
+</div>
+<div class="card">
<h2>Presto Client <a href="http://www.aocate.com/presto/">(Link)</a></h2>
licensed under the Apache 2.0 license <a href="LICENSE_PRESTO.txt">(View)</a>
+</div>
+<div class="card">
<h2>RecyclerView-FlexibleDivider <a href="https://github.com/yqritc/RecyclerView-FlexibleDivider">(Link)</a></h2>
licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
+</div>
+<div class="card">
<h2>RxAndroid <a href="https://github.com/ReactiveX/RxAndroid">(Link)</a></h2>
licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
+</div>
+<div class="card">
<h2>StackBlur <a href="https://github.com/kikoso/android-stackblur">(Link)</a></h2>
by Enrique L&oacute;pez Ma&ntilde;as, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
+</div>
+<div class="card">
<h2>Triangle Label View <a href="https://github.com/shts/TriangleLabelView">(Link)</a></h2>
by Shota Saito, licensed under the Apache 2.0 license <a href="LICENSE_TRIANGLE_LABEL_VIEW.txt">(View)</a>
+</div>
+<div class="card">
<h2>AntennaPod-AudioPlayer <a href="https://github.com/AntennaPod/AntennaPod-AudioPlayer/">(Link)</a></h2>
by the AntennaPod team, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
+</div>
</body>
</html>
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 7b07d3f84..eab085479 100644
--- a/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java
+++ b/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java
@@ -20,6 +20,7 @@ import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v7.app.MediaRouteControllerDialog;
import android.support.v7.graphics.Palette;
import android.support.v7.media.MediaRouter;
+import android.support.v7.widget.AppCompatImageView;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
@@ -34,16 +35,17 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import java.util.concurrent.ExecutionException;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
-import rx.Observable;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.schedulers.Schedulers;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
public class CustomMRControllerDialog extends MediaRouteControllerDialog {
public static final String TAG = "CustomMRContrDialog";
@@ -59,7 +61,7 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
private boolean viewsCreated = false;
- private Subscription fetchArtSubscription;
+ private Disposable fetchArtSubscription;
private MediaControllerCompat mediaController;
private MediaControllerCompat.Callback mediaControllerCallback;
@@ -68,7 +70,7 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
this(context, 0);
}
- public CustomMRControllerDialog(Context context, int theme) {
+ private CustomMRControllerDialog(Context context, int theme) {
super(context, theme);
mediaRouter = MediaRouter.getInstance(getContext());
token = mediaRouter.getMediaSessionToken();
@@ -203,7 +205,7 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
* http://stackoverflow.com/questions/18077325/scale-image-to-fill-imageview-width-and-keep-aspect-ratio
*/
if (landscape) {
- artView = new ImageView(getContext()) {
+ artView = new AppCompatImageView(getContext()) {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredWidth = widthMeasureSpec;
@@ -234,7 +236,7 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
MarginLayoutParamsCompat.setMarginStart(artParams,
getContext().getResources().getDimensionPixelSize(R.dimen.media_router_controller_playback_control_horizontal_spacing));
} else {
- artView = new ImageView(getContext()) {
+ artView = new AppCompatImageView(getContext()) {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredHeight = heightMeasureSpec;
@@ -326,7 +328,7 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
@Override
public void onDetachedFromWindow() {
if (fetchArtSubscription != null) {
- fetchArtSubscription.unsubscribe();
+ fetchArtSubscription.dispose();
fetchArtSubscription = null;
}
super.onDetachedFromWindow();
@@ -395,11 +397,11 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
}
if (fetchArtSubscription != null) {
- fetchArtSubscription.unsubscribe();
+ fetchArtSubscription.dispose();
}
fetchArtSubscription = Observable.fromCallable(() -> fetchArt(description))
- .subscribeOn(Schedulers.newThread())
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
fetchArtSubscription = null;
@@ -462,10 +464,10 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
} else if (iconUri != null) {
try {
art = Glide.with(getContext().getApplicationContext())
- .load(iconUri.toString())
.asBitmap()
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
+ .load(iconUri.toString())
+ .apply(RequestOptions.diskCacheStrategyOf(ApGlideSettings.AP_DISK_CACHE_STRATEGY))
+ .submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get();
} catch (InterruptedException | ExecutionException e) {
Log.e(TAG, "Image art load failed", e);