summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md8
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--ISSUE_TEMPLATE.md33
-rw-r--r--app/build.gradle20
-rw-r--r--app/proguard.cfg3
-rw-r--r--app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java119
-rw-r--r--app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java2
-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.java8
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java8
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java15
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java58
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java13
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java12
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java9
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java24
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java8
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/service/download/NanoHTTPD.java38
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--app/src/main/assets/LICENSE_ANTENNAPOD_AUDIOPLAYER.txt201
-rw-r--r--app/src/main/assets/LICENSE_APACHE-2.0.txt (renamed from app/src/main/assets/LICENSE_APACHE_COMMONS.txt)0
-rw-r--r--app/src/main/assets/LICENSE_EVENTBUS.txt202
-rw-r--r--app/src/main/assets/LICENSE_FLATTR4J.txt202
-rw-r--r--app/src/main/assets/LICENSE_FLEXIBLE_DIVIDER.txt201
-rw-r--r--app/src/main/assets/LICENSE_OKIO.txt202
-rw-r--r--app/src/main/assets/LICENSE_RX_ANDROID.txt200
-rw-r--r--app/src/main/assets/LICENSE_STACKBLUR.txt71
-rw-r--r--app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/PodcastApp.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/UpdateManager.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java670
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java106
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java50
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java640
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java98
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java28
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java196
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java199
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java25
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java199
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java199
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java57
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java44
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java30
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java49
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java51
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java133
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java201
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java52
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java77
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java76
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java77
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java68
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java190
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java273
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java108
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java388
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java27
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java54
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java31
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java56
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java587
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/SwitchCompatPreference.java37
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java8
-rw-r--r--app/src/main/res/drawable/shadow.xml7
-rw-r--r--app/src/main/res/layout/audio_controls.xml136
-rw-r--r--app/src/main/res/layout/audioplayer_activity.xml266
-rw-r--r--app/src/main/res/layout/choose_speed_dialog.xml45
-rw-r--r--app/src/main/res/layout/cover_fragment.xml66
-rw-r--r--app/src/main/res/layout/downloaded_episodeslist_item.xml19
-rw-r--r--app/src/main/res/layout/episodes_apply_action_fragment.xml103
-rw-r--r--app/src/main/res/layout/external_player_fragment.xml136
-rw-r--r--app/src/main/res/layout/feedinfo.xml93
-rw-r--r--app/src/main/res/layout/feeditem_fragment.xml132
-rw-r--r--app/src/main/res/layout/feeditem_fragment_header.xml136
-rw-r--r--app/src/main/res/layout/fragment_itunes_search.xml86
-rw-r--r--app/src/main/res/layout/gpodnet_podcast_listitem.xml20
-rw-r--r--app/src/main/res/layout/itemdescription_listitem.xml49
-rw-r--r--app/src/main/res/layout/itunes_podcast_listitem.xml86
-rw-r--r--app/src/main/res/layout/main.xml12
-rw-r--r--app/src/main/res/layout/nav_feedlistitem.xml2
-rw-r--r--app/src/main/res/layout/new_episodes_listitem.xml4
-rw-r--r--app/src/main/res/layout/preference_switch_layout.xml9
-rw-r--r--app/src/main/res/layout/queue_listitem.xml30
-rw-r--r--app/src/main/res/layout/storage_error.xml29
-rw-r--r--app/src/main/res/layout/videoplayer_activity.xml41
-rw-r--r--app/src/main/res/menu/directory_chooser.xml16
-rw-r--r--app/src/main/res/menu/downloads_completed.xml13
-rw-r--r--app/src/main/res/menu/episodes_apply_action_options.xml21
-rw-r--r--app/src/main/res/menu/feeditemlist_context.xml9
-rw-r--r--app/src/main/res/menu/feedlist.xml4
-rw-r--r--app/src/main/res/menu/itunes_search.xml13
-rw-r--r--app/src/main/res/menu/mediaplayer.xml27
-rw-r--r--app/src/main/res/xml/preferences.xml90
-rw-r--r--app/src/main/templates/about.html16
-rw-r--r--build.gradle27
-rw-r--r--changelog/ar.md16
-rw-r--r--changelog/az.md16
-rw-r--r--changelog/ca.md16
-rw-r--r--changelog/ca_ES.md347
-rw-r--r--changelog/cs_CZ.md16
-rw-r--r--changelog/da.md16
-rw-r--r--changelog/de.md16
-rw-r--r--changelog/el.md46
-rw-r--r--changelog/es.md20
-rw-r--r--changelog/es_ES.md16
-rw-r--r--changelog/fi.md16
-rw-r--r--changelog/fr.md54
-rw-r--r--changelog/he_IL.md16
-rw-r--r--changelog/hi_IN.md16
-rw-r--r--changelog/hu.md16
-rw-r--r--changelog/id.md16
-rw-r--r--changelog/it.md22
-rw-r--r--changelog/it_IT.md18
-rw-r--r--changelog/ja.md20
-rw-r--r--changelog/kn_IN.md16
-rw-r--r--changelog/ko.md16
-rw-r--r--changelog/ko_KR.md16
-rw-r--r--changelog/nb.md347
-rw-r--r--changelog/nb_NO.md82
-rw-r--r--changelog/nl.md25
-rw-r--r--changelog/no.md16
-rw-r--r--changelog/pl.md16
-rw-r--r--changelog/pl_PL.md16
-rw-r--r--changelog/pt.md50
-rw-r--r--changelog/pt_BR.md16
-rw-r--r--changelog/ro_RO.md16
-rw-r--r--changelog/ru_RU.md18
-rw-r--r--changelog/sv_SE.md16
-rw-r--r--changelog/tr.md26
-rw-r--r--changelog/uk_UA.md20
-rw-r--r--changelog/vi.md16
-rw-r--r--changelog/vi_VN.md16
-rw-r--r--changelog/zh_CN.md16
-rw-r--r--circle.yml10
-rw-r--r--core/build.gradle5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java39
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedFilter.java111
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java44
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java78
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java58
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java40
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java26
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java47
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java54
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java29
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java70
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java33
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java45
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java95
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java57
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APNullCleanupAlgorithm.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java35
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java23
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java80
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java34
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java15
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java156
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java16
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java31
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java20
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java18
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java24
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java140
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java11
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java4
-rw-r--r--core/src/main/res/drawable-hdpi-v11/stat_notify_sync.pngbin1012 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi-v11/stat_notify_sync_error.pngbin1103 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-hdpi/ic_av_fast_forward_80dp.pngbin0 -> 1228 bytes
-rwxr-xr-xcore/src/main/res/drawable-hdpi/ic_av_rewind_80dp.pngbin0 -> 1277 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_check_box_grey600_24dp.pngbin0 -> 584 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_check_box_outline_blank_grey600_24dp.pngbin0 -> 397 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_check_box_outline_blank_white_24dp.pngbin0 -> 340 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_check_box_white_24dp.pngbin0 -> 505 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_create_new_folder_grey600_24dp.pngbin0 -> 198 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_create_new_folder_white_24dp.pngbin0 -> 191 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_drag_vertical_grey600_48dp.9.pngbin0 -> 389 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_drag_vertical_grey600_48dp.pngbin246 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_drag_vertical_white_48dp.9.pngbin0 -> 361 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_drag_vertical_white_48dp.pngbin242 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-hdpi/ic_feed_grey600_24dp.pngbin2359 -> 1159 bytes
-rwxr-xr-xcore/src/main/res/drawable-hdpi/ic_feed_white_24dp.pngbin1663 -> 727 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_indeterminate_check_box_grey600_24dp.pngbin0 -> 405 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_indeterminate_check_box_white_24dp.pngbin0 -> 348 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sd_storage_grey600_36dp.pngbin0 -> 333 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sd_storage_white_36dp.pngbin0 -> 332 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_skip_grey600_36dp.pngbin0 -> 302 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_skip_white_36dp.pngbin0 -> 304 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sleep_grey600_24dp.pngbin0 -> 421 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sleep_off_grey600_24dp.pngbin0 -> 659 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sleep_off_white_24dp.pngbin0 -> 431 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sleep_white_24dp.pngbin0 -> 361 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sort_grey600_24dp.pngbin0 -> 264 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sort_white_24dp.pngbin0 -> 238 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_star_border_grey600_24dp.pngbin0 -> 637 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_star_border_white_24dp.pngbin0 -> 637 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_star_grey600_24dp.pngbin0 -> 460 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_star_white_24dp.pngbin0 -> 454 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/stat_notify_sync.pngbin674 -> 421 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/stat_notify_sync_error.pngbin708 -> 436 bytes
-rw-r--r--core/src/main/res/drawable-mdpi-v11/stat_notify_sync.pngbin732 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi-v11/stat_notify_sync_error.pngbin746 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-mdpi/ic_av_fast_forward_80dp.pngbin0 -> 760 bytes
-rwxr-xr-xcore/src/main/res/drawable-mdpi/ic_av_rewind_80dp.pngbin0 -> 853 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_check_box_grey600_24dp.pngbin0 -> 397 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_check_box_outline_blank_grey600_24dp.pngbin0 -> 254 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_check_box_outline_blank_white_24dp.pngbin0 -> 230 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_check_box_white_24dp.pngbin0 -> 331 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_create_new_folder_grey600_24dp.pngbin0 -> 152 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_create_new_folder_white_24dp.pngbin0 -> 149 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_drag_vertical_grey600_48dp.9.pngbin0 -> 253 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_drag_vertical_grey600_48dp.pngbin197 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_drag_vertical_white_48dp.9.pngbin0 -> 231 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_drag_vertical_white_48dp.pngbin193 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-mdpi/ic_feed_grey600_24dp.pngbin1566 -> 773 bytes
-rwxr-xr-xcore/src/main/res/drawable-mdpi/ic_feed_white_24dp.pngbin1156 -> 492 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_indeterminate_check_box_grey600_24dp.pngbin0 -> 259 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_indeterminate_check_box_white_24dp.pngbin0 -> 241 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sd_storage_grey600_36dp.pngbin0 -> 220 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sd_storage_white_36dp.pngbin0 -> 214 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_skip_grey600_36dp.pngbin0 -> 218 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_skip_white_36dp.pngbin0 -> 216 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sleep_grey600_24dp.pngbin0 -> 336 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sleep_off_grey600_24dp.pngbin0 -> 472 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sleep_off_white_24dp.pngbin0 -> 323 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sleep_white_24dp.pngbin0 -> 252 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sort_grey600_24dp.pngbin0 -> 193 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sort_white_24dp.pngbin0 -> 192 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_star_border_grey600_24dp.pngbin0 -> 410 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_star_border_white_24dp.pngbin0 -> 410 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_star_grey600_24dp.pngbin0 -> 307 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_star_white_24dp.pngbin0 -> 302 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/stat_notify_sync.pngbin628 -> 272 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/stat_notify_sync_error.pngbin627 -> 274 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi-v11/stat_notify_sync.pngbin1306 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi-v11/stat_notify_sync_error.pngbin1434 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-xhdpi/ic_av_fast_forward_80dp.pngbin0 -> 1968 bytes
-rwxr-xr-xcore/src/main/res/drawable-xhdpi/ic_av_rewind_80dp.pngbin0 -> 1992 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_check_box_grey600_24dp.pngbin0 -> 658 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_check_box_outline_blank_grey600_24dp.pngbin0 -> 406 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_check_box_outline_blank_white_24dp.pngbin0 -> 364 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_check_box_white_24dp.pngbin0 -> 526 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_create_new_folder_grey600_24dp.pngbin0 -> 248 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_create_new_folder_white_24dp.pngbin0 -> 239 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_drag_vertical_grey600_48dp.9.pngbin0 -> 548 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_drag_vertical_grey600_48dp.pngbin291 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_drag_vertical_white_48dp.9.pngbin0 -> 517 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_drag_vertical_white_48dp.pngbin286 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-xhdpi/ic_feed_grey600_24dp.pngbin3200 -> 1420 bytes
-rwxr-xr-xcore/src/main/res/drawable-xhdpi/ic_feed_white_24dp.pngbin2314 -> 910 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_indeterminate_check_box_grey600_24dp.pngbin0 -> 407 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_indeterminate_check_box_white_24dp.pngbin0 -> 370 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sd_storage_grey600_36dp.pngbin0 -> 403 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sd_storage_white_36dp.pngbin0 -> 404 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_skip_grey600_36dp.pngbin0 -> 364 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_skip_white_36dp.pngbin0 -> 368 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sleep_grey600_24dp.pngbin0 -> 494 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sleep_off_grey600_24dp.pngbin0 -> 769 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sleep_off_white_24dp.pngbin0 -> 486 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sleep_white_24dp.pngbin0 -> 367 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sort_grey600_24dp.pngbin0 -> 215 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sort_white_24dp.pngbin0 -> 212 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_star_border_grey600_24dp.pngbin0 -> 828 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_star_border_white_24dp.pngbin0 -> 821 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_star_grey600_24dp.pngbin0 -> 593 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_star_white_24dp.pngbin0 -> 582 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/stat_notify_sync.pngbin0 -> 475 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/stat_notify_sync_error.pngbin0 -> 533 bytes
-rwxr-xr-xcore/src/main/res/drawable-xxhdpi/ic_av_fast_forward_80dp.pngbin0 -> 3207 bytes
-rwxr-xr-xcore/src/main/res/drawable-xxhdpi/ic_av_rewind_80dp.pngbin0 -> 3502 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_check_box_grey600_24dp.pngbin0 -> 920 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_check_box_outline_blank_grey600_24dp.pngbin0 -> 582 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_check_box_outline_blank_white_24dp.pngbin0 -> 502 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_check_box_white_24dp.pngbin0 -> 800 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_create_new_folder_grey600_24dp.pngbin0 -> 343 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_create_new_folder_white_24dp.pngbin0 -> 339 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_drag_vertical_grey600_48dp.9.pngbin0 -> 853 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_drag_vertical_grey600_48dp.pngbin389 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_drag_vertical_white_48dp.9.pngbin0 -> 809 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_drag_vertical_white_48dp.pngbin386 -> 0 bytes
-rwxr-xr-xcore/src/main/res/drawable-xxhdpi/ic_feed_grey600_24dp.pngbin4754 -> 2087 bytes
-rwxr-xr-xcore/src/main/res/drawable-xxhdpi/ic_feed_white_24dp.pngbin3406 -> 1366 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_indeterminate_check_box_grey600_24dp.pngbin0 -> 580 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_indeterminate_check_box_white_24dp.pngbin0 -> 514 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sd_storage_grey600_36dp.pngbin0 -> 605 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sd_storage_white_36dp.pngbin0 -> 593 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_skip_grey600_36dp.pngbin0 -> 533 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_skip_white_36dp.pngbin0 -> 543 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sleep_grey600_24dp.pngbin0 -> 737 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sleep_off_grey600_24dp.pngbin0 -> 1113 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sleep_off_white_24dp.pngbin0 -> 664 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sleep_white_24dp.pngbin0 -> 509 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sort_grey600_24dp.pngbin0 -> 244 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sort_white_24dp.pngbin0 -> 241 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_star_border_grey600_24dp.pngbin0 -> 1227 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_star_border_white_24dp.pngbin0 -> 1222 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_star_grey600_24dp.pngbin0 -> 877 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_star_white_24dp.pngbin0 -> 870 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/stat_notify_sync.pngbin0 -> 705 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/stat_notify_sync_error.pngbin0 -> 761 bytes
-rwxr-xr-xcore/src/main/res/drawable-xxxhdpi/ic_av_fast_forward_80dp.pngbin0 -> 5878 bytes
-rwxr-xr-xcore/src/main/res/drawable-xxxhdpi/ic_av_rewind_80dp.pngbin0 -> 6299 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_create_new_folder_grey600_24dp.pngbin0 -> 466 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_create_new_folder_white_24dp.pngbin0 -> 463 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_drag_vertical_grey600_48dp.pngbin501 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_drag_vertical_white_48dp.pngbin498 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_sd_storage_grey600_36dp.pngbin0 -> 890 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_sd_storage_white_36dp.pngbin0 -> 890 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_skip_grey600_36dp.pngbin0 -> 737 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_skip_white_36dp.pngbin0 -> 749 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_sleep_grey600_24dp.pngbin0 -> 955 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_sleep_off_grey600_24dp.pngbin0 -> 1514 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_sleep_off_white_24dp.pngbin0 -> 882 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_sleep_white_24dp.pngbin0 -> 647 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_star_border_grey600_24dp.pngbin0 -> 1675 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_star_border_white_24dp.pngbin0 -> 1684 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_star_grey600_24dp.pngbin0 -> 1179 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.pngbin0 -> 1183 bytes
-rw-r--r--core/src/main/res/drawable/progress_bar_horizontal_dark.xml15
-rw-r--r--core/src/main/res/drawable/progress_bar_horizontal_light.xml15
-rw-r--r--core/src/main/res/values-az/strings.xml5
-rw-r--r--core/src/main/res/values-ca/strings.xml75
-rw-r--r--core/src/main/res/values-cs-rCZ/strings.xml65
-rw-r--r--core/src/main/res/values-da/strings.xml5
-rw-r--r--core/src/main/res/values-de/strings.xml70
-rw-r--r--core/src/main/res/values-es-rES/strings.xml55
-rw-r--r--core/src/main/res/values-es/strings.xml111
-rw-r--r--core/src/main/res/values-fr/strings.xml69
-rw-r--r--core/src/main/res/values-hi-rIN/strings.xml5
-rw-r--r--core/src/main/res/values-it-rIT/strings.xml8
-rw-r--r--core/src/main/res/values-iw-rIL/strings.xml6
-rw-r--r--core/src/main/res/values-ja/strings.xml74
-rw-r--r--core/src/main/res/values-ko/strings.xml93
-rw-r--r--core/src/main/res/values-nb/strings.xml31
-rw-r--r--core/src/main/res/values-nl/strings.xml83
-rw-r--r--core/src/main/res/values-pl-rPL/strings.xml159
-rw-r--r--core/src/main/res/values-pt-rBR/strings.xml7
-rw-r--r--core/src/main/res/values-pt/strings.xml164
-rw-r--r--core/src/main/res/values-ro-rRO/strings.xml5
-rw-r--r--core/src/main/res/values-ru/strings.xml41
-rw-r--r--core/src/main/res/values-sv-rSE/strings.xml66
-rw-r--r--core/src/main/res/values-tr/strings.xml29
-rw-r--r--core/src/main/res/values-uk-rUA/strings.xml76
-rw-r--r--core/src/main/res/values-zh-rCN/strings.xml39
-rw-r--r--core/src/main/res/values/arrays.xml19
-rw-r--r--core/src/main/res/values/attrs.xml15
-rw-r--r--core/src/main/res/values/dimens.xml6
-rw-r--r--core/src/main/res/values/strings.xml62
-rw-r--r--core/src/main/res/values/styles.xml68
-rw-r--r--description/ca_ES.txt42
-rw-r--r--description/de.txt21
-rwxr-xr-xdescription/en.txt23
-rw-r--r--description/es.txt23
-rw-r--r--description/fr.txt49
-rw-r--r--description/it.txt12
-rw-r--r--description/it_IT.txt2
-rw-r--r--description/ja.txt21
-rw-r--r--description/ko.txt70
-rw-r--r--description/nb.txt42
-rw-r--r--description/nb_NO.txt70
-rw-r--r--description/pt.txt31
-rw-r--r--description/uk_UA.txt19
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin52266 -> 53638 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties4
-rwxr-xr-xgradlew10
-rw-r--r--gradlew.bat2
402 files changed, 8293 insertions, 5359 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e3a210a9..72fa4bdb2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
Version 1.4.1
-------------
* Performance improvements
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5e6f1dbff..bcbf4e1d3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -10,6 +10,8 @@ How to report a bug
- Usually, you can make a screenshot of your smartphone by pressing [Power] + [Volume down] for a few seconds
- Please use the following **template**:
+**App version**: 1.x (from Google Play/F-Store/Custom build)
+
**Android version**: 5.x [Especially mention custom roms!]
**Devide model**:
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
new file mode 100644
index 000000000..e7b99c56d
--- /dev/null
+++ b/ISSUE_TEMPLATE.md
@@ -0,0 +1,33 @@
+---
+DELETE ME<br/>
+You don't need to adhere to the template strictly. Feel free to leave out information you feel is not important or does not make sense.
+
+If you are submitting a feature request, please read [this](https://github.com/AntennaPod/AntennaPod/blob/develop/CONTRIBUTING.md#how-to-submit-a-feature-request).
+In particular, please not only tell us that you want something (*what*), but also make suggestions *how* it should be implemented.
+
+---
+
+**App version:** 1.x (from Google Play/F-Store/Custom build)
+
+**Android version**: 5.x [Please mention if you are using a custom rom!]
+
+**Devide model**:
+
+**Expected behaviour**:
+
+**Current behaviour**:
+
+**First occured**: Version 1.x / about x days/weeks ago
+
+**Steps to reproduce**:
+
+1. This
+1. Than that
+1. Then
+
+**Environment**: [Settings you have changed, e.g. Auto Download. "Unusual" devices you use, e.g. Bluetooth headphones. Do you still use Prestissimo?]
+
+**Stacktrace/Logcat**:
+```
+[if available]
+```
diff --git a/app/build.gradle b/app/build.gradle
index 3f1584081..55c1080ae 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,10 +11,10 @@ repositories {
dependencies {
compile "com.android.support:support-v4:$supportVersion"
compile "com.android.support:appcompat-v7:$supportVersion"
- compile "com.android.support:gridlayout-v7:$supportVersion"
- compile "com.android.support:cardview-v7:$supportVersion"
compile "com.android.support:design:$supportVersion"
- compile "com.android.support:recyclerview-v7:22.2.+"
+ 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") {
exclude group: "org.json", module: "json"
@@ -31,11 +31,17 @@ dependencies {
compile "io.reactivex:rxjava:$rxJavaVersion"
// And ProGuard rules for RxJava!
compile "com.artemzin.rxjava:proguard-rules:$rxJavaRulesVersion"
- compile "com.joanzapata.iconify:android-iconify-fontawesome:2.1.0"
- compile "com.afollestad:material-dialogs:0.7.8.1"
- compile "com.yqritc:recyclerview-flexibledivider:1.2.6"
+ compile "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyVersion"
+ compile "com.joanzapata.iconify:android-iconify-material:$iconifyVersion"
+ compile("com.github.afollestad.material-dialogs:commons:$materialDialogsVersion") {
+ transitive = true
+ }
+ compile "com.yqritc:recyclerview-flexibledivider:$recyclerviewFlexibledividerVersion"
+ compile("com.githang:viewpagerindicator:2.5@aar") {
+ exclude module: "support-v4"
+ }
- compile "com.github.AntennaPod:AntennaPod-AudioPlayer:v1.0.2"
+ compile "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
compile project(":core")
}
diff --git a/app/proguard.cfg b/app/proguard.cfg
index ee9dace54..19ae36f36 100644
--- a/app/proguard.cfg
+++ b/app/proguard.cfg
@@ -102,3 +102,6 @@
**[] $VALUES;
public *;
}
+
+# for ViewPageIndicator problems (https://github.com/JakeWharton/ViewPagerIndicator/issues/366):
+-dontwarn com.viewpagerindicator.LinePageIndicator
diff --git a/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java b/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java
new file mode 100644
index 000000000..23a05ac8c
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java
@@ -0,0 +1,119 @@
+package de.test.antennapod.feed;
+
+import android.test.AndroidTestCase;
+
+import de.danoeh.antennapod.core.feed.FeedFilter;
+import de.danoeh.antennapod.core.feed.FeedItem;
+
+public class FeedFilterTest extends AndroidTestCase {
+
+ public void testNullFilter() throws Exception {
+ FeedFilter filter = new FeedFilter();
+ FeedItem item = new FeedItem();
+ item.setTitle("Hello world");
+
+ assertTrue(!filter.excludeOnly());
+ assertTrue(!filter.includeOnly());
+ assertEquals("", filter.getExcludeFilter());
+ assertEquals("", filter.getIncludeFilter());
+ assertTrue(filter.shouldAutoDownload(item));
+ }
+
+ public void testBasicIncludeFilter() throws Exception {
+ String includeFilter = "Hello";
+ FeedFilter filter = new FeedFilter(includeFilter, "");
+ FeedItem item = new FeedItem();
+ item.setTitle("Hello world");
+
+ FeedItem item2 = new FeedItem();
+ item2.setTitle("Don't include me");
+
+ assertTrue(!filter.excludeOnly());
+ assertTrue(filter.includeOnly());
+ assertEquals("", filter.getExcludeFilter());
+ assertEquals(includeFilter, filter.getIncludeFilter());
+ assertTrue(filter.shouldAutoDownload(item));
+ assertTrue(!filter.shouldAutoDownload(item2));
+ }
+
+ public void testBasicExcludeFilter() throws Exception {
+ String excludeFilter = "Hello";
+ FeedFilter filter = new FeedFilter("", excludeFilter);
+ FeedItem item = new FeedItem();
+ item.setTitle("Hello world");
+
+ FeedItem item2 = new FeedItem();
+ item2.setTitle("Item2");
+
+ assertTrue(filter.excludeOnly());
+ assertTrue(!filter.includeOnly());
+ assertEquals(excludeFilter, filter.getExcludeFilter());
+ assertEquals("", filter.getIncludeFilter());
+ assertTrue(!filter.shouldAutoDownload(item));
+ assertTrue(filter.shouldAutoDownload(item2));
+ }
+
+ public void testComplexIncludeFilter() throws Exception {
+ String includeFilter = "Hello \n\"Two words\"";
+ FeedFilter filter = new FeedFilter(includeFilter, "");
+ FeedItem item = new FeedItem();
+ item.setTitle("hello world");
+
+ FeedItem item2 = new FeedItem();
+ item2.setTitle("Two three words");
+
+ FeedItem item3 = new FeedItem();
+ item3.setTitle("One two words");
+
+ assertTrue(!filter.excludeOnly());
+ assertTrue(filter.includeOnly());
+ assertEquals("", filter.getExcludeFilter());
+ assertEquals(includeFilter, filter.getIncludeFilter());
+ assertTrue(filter.shouldAutoDownload(item));
+ assertTrue(!filter.shouldAutoDownload(item2));
+ assertTrue(filter.shouldAutoDownload(item3));
+ }
+
+ public void testComplexExcludeFilter() throws Exception {
+ String excludeFilter = "Hello \"Two words\"";
+ FeedFilter filter = new FeedFilter("", excludeFilter);
+ FeedItem item = new FeedItem();
+ item.setTitle("hello world");
+
+ FeedItem item2 = new FeedItem();
+ item2.setTitle("One three words");
+
+ FeedItem item3 = new FeedItem();
+ item3.setTitle("One two words");
+
+ assertTrue(filter.excludeOnly());
+ assertTrue(!filter.includeOnly());
+ assertEquals(excludeFilter, filter.getExcludeFilter());
+ assertEquals("", filter.getIncludeFilter());
+ assertTrue(!filter.shouldAutoDownload(item));
+ assertTrue(filter.shouldAutoDownload(item2));
+ assertTrue(!filter.shouldAutoDownload(item3));
+ }
+
+ public void testComboFilter() throws Exception {
+ String includeFilter = "Hello world";
+ String excludeFilter = "dislike";
+ FeedFilter filter = new FeedFilter(includeFilter, excludeFilter);
+
+ FeedItem download = new FeedItem();
+ download.setTitle("Hello everyone!");
+ // because, while it has words from the include filter it also has exclude words
+ FeedItem doNotDownload = new FeedItem();
+ doNotDownload.setTitle("I dislike the world");
+ // because it has no words from the include filter
+ FeedItem doNotDownload2 = new FeedItem();
+ doNotDownload2.setTitle("no words to include");
+
+ assertTrue(filter.hasExcludeFilter());
+ assertTrue(filter.hasIncludeFilter());
+ assertTrue(filter.shouldAutoDownload(download));
+ assertTrue(!filter.shouldAutoDownload(doNotDownload));
+ assertTrue(!filter.shouldAutoDownload(doNotDownload2));
+ }
+
+}
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 5836bb699..ee454ce8a 100644
--- a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
@@ -162,7 +162,7 @@ public class FeedHandlerTest extends InstrumentationTestCase {
if (withImage) {
image = new FeedImage(0, "image", null, "http://example.com/picture", false);
}
- Feed feed = new Feed(0, new Date(), "title", "http://example.com", "This is the description",
+ 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/feed", true);
feed.setItems(new ArrayList<FeedItem>());
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 d7a170c17..7862e986d 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
@@ -115,7 +115,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
private Playable writeTestPlayable(String downloadUrl, String fileUrl) {
final Context c = getInstrumentation().getTargetContext();
- Feed f = new Feed(0, new Date(), "f", "l", "d", null, null, null, null, "i", null, null, "l", false);
+ Feed f = new Feed(0, null, "f", "l", "d", null, null, null, null, "i", null, null, "l", false);
FeedPreferences prefs = new FeedPreferences(f.getId(), false, FeedPreferences.AutoDeleteAction.NO, null, null);
f.setPreferences(prefs);
f.setItems(new ArrayList<>());
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 f06d2f2a6..5c3d32960 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
@@ -48,7 +48,7 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
private List<FeedItem> writeTestQueue(String pref) {
final Context c = getInstrumentation().getTargetContext();
final int NUM_ITEMS = 10;
- Feed f = new Feed(0, new Date(), "title", "link", "d", null, null, null, null, "id", null, "null", "url", false);
+ Feed f = new Feed(0, null, "title", "link", "d", null, null, null, null, "id", null, "null", "url", false);
f.setItems(new ArrayList<>());
for (int i = 0; i < NUM_ITEMS; i++) {
f.getItems().add(new FeedItem(0, pref + i, pref + i, "link", new Date(), FeedItem.PLAYED, f));
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 afdaeead0..7300df395 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
@@ -87,7 +87,7 @@ public class DBCleanupTests extends InstrumentationTestCase {
public void testPerformAutoCleanupShouldDelete() throws IOException {
final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2;
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
List<FeedItem> items = new ArrayList<>();
feed.setItems(items);
List<File> files = new ArrayList<>();
@@ -143,7 +143,7 @@ public class DBCleanupTests extends InstrumentationTestCase {
public void testPerformAutoCleanupHandleUnplayed() throws IOException {
final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2;
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
List<FeedItem> items = new ArrayList<FeedItem>();
feed.setItems(items);
List<File> files = new ArrayList<File>();
@@ -159,7 +159,7 @@ public class DBCleanupTests extends InstrumentationTestCase {
public void testPerformAutoCleanupShouldNotDeleteBecauseInQueue() throws IOException {
final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2;
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
List<FeedItem> items = new ArrayList<>();
feed.setItems(items);
List<File> files = new ArrayList<>();
@@ -198,7 +198,7 @@ public class DBCleanupTests extends InstrumentationTestCase {
public void testPerformAutoCleanupShouldNotDeleteBecauseFavorite() throws IOException {
final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2;
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
List<FeedItem> items = new ArrayList<>();
feed.setItems(items);
List<File> files = new ArrayList<>();
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
index 18a8d63d1..7205b42c4 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
@@ -82,7 +82,7 @@ public class DBNullCleanupAlgorithmTest extends InstrumentationTestCase {
public void testPerformAutoCleanupShouldNotDelete() throws IOException {
final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2;
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
List<FeedItem> items = new ArrayList<>();
feed.setItems(items);
List<File> files = new ArrayList<>();
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 890897f43..3bd508eaf 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java
@@ -32,7 +32,7 @@ public class DBQueueCleanupAlgorithmTest extends DBCleanupTests {
public void testPerformAutoCleanupHandleUnplayed() throws IOException {
final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2;
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
List<FeedItem> items = new ArrayList<>();
feed.setItems(items);
List<File> files = new ArrayList<>();
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java
index 3988669ce..0fc3b1892 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java
@@ -54,10 +54,10 @@ public class DBReaderTest extends InstrumentationTestCase {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Feed feed1 = new Feed(0, new Date(), "A", "link", "d", null, null, null, "rss", "A", null, "", "", true);
- Feed feed2 = new Feed(0, new Date(), "b", "link", "d", null, null, null, "rss", "b", null, "", "", true);
- Feed feed3 = new Feed(0, new Date(), "C", "link", "d", null, null, null, "rss", "C", null, "", "", true);
- Feed feed4 = new Feed(0, new Date(), "d", "link", "d", null, null, null, "rss", "d", null, "", "", true);
+ Feed feed1 = new Feed(0, null, "A", "link", "d", null, null, null, "rss", "A", null, "", "", true);
+ Feed feed2 = new Feed(0, null, "b", "link", "d", null, null, null, "rss", "b", null, "", "", true);
+ Feed feed3 = new Feed(0, null, "C", "link", "d", null, null, null, "rss", "C", null, "", "", true);
+ Feed feed4 = new Feed(0, null, "d", "link", "d", null, null, null, "rss", "d", null, "", "", true);
adapter.setCompleteFeed(feed1);
adapter.setCompleteFeed(feed2);
adapter.setCompleteFeed(feed3);
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 1894d6585..5b2393d45 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
@@ -1,13 +1,9 @@
package de.test.antennapod.storage;
import android.content.Context;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
import android.test.FlakyTest;
import android.test.InstrumentationTestCase;
-import java.io.File;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@@ -15,14 +11,11 @@ import java.util.List;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
-import static de.test.antennapod.storage.DBTestUtils.saveFeedlist;
-
/**
* Test class for DBTasks
*/
@@ -57,7 +50,7 @@ public class DBTasksTest extends InstrumentationTestCase {
public void testUpdateFeedNewFeed() {
final int NUM_ITEMS = 10;
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
for (int i = 0; i < NUM_ITEMS; i++) {
feed.getItems().add(new FeedItem(0, "item " + i, "id " + i, "link " + i, new Date(), FeedItem.UNPLAYED, feed));
@@ -75,8 +68,8 @@ public class DBTasksTest extends InstrumentationTestCase {
/** Two feeds with the same title, but different download URLs should be treated as different feeds. */
public void testUpdateFeedSameTitle() {
- Feed feed1 = new Feed("url1", new Date(), "title");
- Feed feed2 = new Feed("url2", new Date(), "title");
+ Feed feed1 = new Feed("url1", null, "title");
+ Feed feed2 = new Feed("url2", null, "title");
feed1.setItems(new ArrayList<>());
feed2.setItems(new ArrayList<>());
@@ -91,7 +84,7 @@ public class DBTasksTest extends InstrumentationTestCase {
final int NUM_ITEMS_OLD = 10;
final int NUM_ITEMS_NEW = 10;
- final Feed feed = new Feed("url", new Date(), "title");
+ final Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
for (int i = 0; i < NUM_ITEMS_OLD; i++) {
feed.getItems().add(new FeedItem(0, "item " + i, "id " + i, "link " + i, new Date(i), FeedItem.PLAYED, feed));
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 0af8afa83..78b807710 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java
@@ -44,7 +44,7 @@ public class DBTestUtils {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
for (int i = 0; i < numFeeds; i++) {
- Feed f = new Feed(0, new Date(), "feed " + i, "link" + i, "descr", null, null,
+ Feed f = new Feed(0, null, "feed " + i, "link" + i, "descr", null, null,
null, null, "id" + i, null, null, "url" + i, false, new FlattrStatus(), false, null, null, false);
f.setItems(new ArrayList<>());
for (int j = 0; j < numItems; j++) {
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 d61d4ab52..0e1d19f7b 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
@@ -59,13 +59,14 @@ public class DBWriterTest extends InstrumentationTestCase {
adapter.close();
}
- public void testSetFeedMediaPlaybackInformation() throws IOException, ExecutionException, InterruptedException {
+ public void testSetFeedMediaPlaybackInformation()
+ throws IOException, ExecutionException, InterruptedException, TimeoutException {
final int POSITION = 50;
final long LAST_PLAYED_TIME = 1000;
final int PLAYED_DURATION = 60;
final int DURATION = 100;
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
List<FeedItem> items = new ArrayList<>();
feed.setItems(items);
FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.PLAYED, feed);
@@ -73,13 +74,13 @@ public class DBWriterTest extends InstrumentationTestCase {
FeedMedia media = new FeedMedia(0, item, DURATION, 1, 1, "mime_type", "dummy path", "download_url", true, null, 0, 0);
item.setMedia(media);
- DBWriter.setFeedItem(item).get();
+ DBWriter.setFeedItem(item).get(TIMEOUT, TimeUnit.SECONDS);
media.setPosition(POSITION);
media.setLastPlayedTime(LAST_PLAYED_TIME);
media.setPlayedDuration(PLAYED_DURATION);
- DBWriter.setFeedMediaPlaybackInformation(item.getMedia()).get();
+ DBWriter.setFeedMediaPlaybackInformation(item.getMedia()).get(TIMEOUT, TimeUnit.SECONDS);
FeedItem itemFromDb = DBReader.getFeedItem(item.getId());
FeedMedia mediaFromDb = itemFromDb.getMedia();
@@ -90,12 +91,13 @@ public class DBWriterTest extends InstrumentationTestCase {
assertEquals(DURATION, mediaFromDb.getDuration());
}
- public void testDeleteFeedMediaOfItemFileExists() throws IOException, ExecutionException, InterruptedException {
+ public void testDeleteFeedMediaOfItemFileExists()
+ throws IOException, ExecutionException, InterruptedException, TimeoutException {
File dest = new File(getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER), "testFile");
assertTrue(dest.createNewFile());
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
List<FeedItem> items = new ArrayList<>();
feed.setItems(items);
FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.PLAYED, feed);
@@ -112,7 +114,8 @@ public class DBWriterTest extends InstrumentationTestCase {
assertTrue(media.getId() != 0);
assertTrue(item.getId() != 0);
- DBWriter.deleteFeedMediaOfItem(getInstrumentation().getTargetContext(), media.getId()).get();
+ DBWriter.deleteFeedMediaOfItem(getInstrumentation().getTargetContext(), media.getId())
+ .get(TIMEOUT, TimeUnit.SECONDS);
media = DBReader.getFeedMedia(media.getId());
assertNotNull(media);
assertFalse(dest.exists());
@@ -124,7 +127,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
// create Feed image
@@ -189,6 +192,7 @@ public class DBWriterTest extends InstrumentationTestCase {
c.close();
c = adapter.getSimpleChaptersOfFeedItemCursor(item);
assertEquals(0, c.getCount());
+ c.close();
}
}
@@ -196,7 +200,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
feed.setImage(null);
@@ -252,7 +256,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(null);
// create Feed image
@@ -289,7 +293,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
// create Feed image
@@ -341,7 +345,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
// create Feed image
@@ -399,7 +403,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
// create Feed image
@@ -471,7 +475,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<FeedItem>());
// create Feed image
@@ -527,7 +531,7 @@ public class DBWriterTest extends InstrumentationTestCase {
private FeedMedia playbackHistorySetup(Date playbackCompletionDate) {
final Context context = getInstrumentation().getTargetContext();
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<FeedItem>());
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);
@@ -541,9 +545,10 @@ public class DBWriterTest extends InstrumentationTestCase {
return media;
}
- public void testAddItemToPlaybackHistoryNotPlayedYet() throws ExecutionException, InterruptedException {
+ public void testAddItemToPlaybackHistoryNotPlayedYet()
+ throws ExecutionException, InterruptedException, TimeoutException {
FeedMedia media = playbackHistorySetup(null);
- DBWriter.addItemToPlaybackHistory(media).get();
+ DBWriter.addItemToPlaybackHistory(media).get(TIMEOUT, TimeUnit.SECONDS);
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
media = DBReader.getFeedMedia(media.getId());
@@ -553,11 +558,12 @@ public class DBWriterTest extends InstrumentationTestCase {
assertNotNull(media.getPlaybackCompletionDate());
}
- public void testAddItemToPlaybackHistoryAlreadyPlayed() throws ExecutionException, InterruptedException {
+ public void testAddItemToPlaybackHistoryAlreadyPlayed()
+ throws ExecutionException, InterruptedException, TimeoutException {
final long OLD_DATE = 0;
FeedMedia media = playbackHistorySetup(new Date(OLD_DATE));
- DBWriter.addItemToPlaybackHistory(media).get();
+ DBWriter.addItemToPlaybackHistory(media).get(TIMEOUT, TimeUnit.SECONDS);
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
media = DBReader.getFeedMedia(media.getId());
@@ -570,7 +576,7 @@ public class DBWriterTest extends InstrumentationTestCase {
private Feed queueTestSetupMultipleItems(final int NUM_ITEMS) throws InterruptedException, ExecutionException, TimeoutException {
final Context context = getInstrumentation().getTargetContext();
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
for (int i = 0; i < NUM_ITEMS; i++) {
FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
@@ -597,7 +603,7 @@ public class DBWriterTest extends InstrumentationTestCase {
public void testAddQueueItemSingleItem() throws InterruptedException, ExecutionException, TimeoutException {
final Context context = getInstrumentation().getTargetContext();
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
@@ -621,7 +627,7 @@ public class DBWriterTest extends InstrumentationTestCase {
public void testAddQueueItemSingleItemAlreadyInQueue() throws InterruptedException, ExecutionException, TimeoutException {
final Context context = getInstrumentation().getTargetContext();
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
@@ -687,7 +693,7 @@ public class DBWriterTest extends InstrumentationTestCase {
public void testRemoveQueueItem() throws InterruptedException, ExecutionException, TimeoutException {
final int NUM_ITEMS = 10;
final Context context = getInstrumentation().getTargetContext();
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
for (int i = 0; i < NUM_ITEMS; i++) {
FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
@@ -732,7 +738,7 @@ public class DBWriterTest extends InstrumentationTestCase {
public void testMoveQueueItem() throws InterruptedException, ExecutionException, TimeoutException {
final int NUM_ITEMS = 10;
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
for (int i = 0; i < NUM_ITEMS; i++) {
FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
@@ -778,7 +784,7 @@ public class DBWriterTest extends InstrumentationTestCase {
public void testMarkFeedRead() throws InterruptedException, ExecutionException, TimeoutException {
final int NUM_ITEMS = 10;
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<FeedItem>());
for (int i = 0; i < NUM_ITEMS; i++) {
FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.UNPLAYED, feed);
@@ -804,7 +810,7 @@ public class DBWriterTest extends InstrumentationTestCase {
public void testMarkAllItemsReadSameFeed() throws InterruptedException, ExecutionException, TimeoutException {
final int NUM_ITEMS = 10;
- Feed feed = new Feed("url", new Date(), "title");
+ Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
for (int i = 0; i < NUM_ITEMS; i++) {
FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.UNPLAYED, feed);
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 4dae53a15..4e214cf81 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
@@ -51,6 +51,7 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
adapter.close();
// override first launch preference
+ // do this BEFORE calling getActivity()!
prefs = getInstrumentation().getTargetContext().getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE);
prefs.edit().putBoolean(MainActivity.PREF_IS_FIRST_LAUNCH, false).commit();
@@ -71,7 +72,8 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
}
private void openNavDrawer() {
- solo.clickOnScreen(50, 50);
+ solo.clickOnImageButton(0);
+ getInstrumentation().waitForIdleSync();
}
public void testAddFeed() throws Exception {
@@ -125,7 +127,7 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
assertEquals(solo.getString(R.string.add_feed_label), getActionbarTitle());
// podcasts
- ListView list = (ListView)solo.getView(R.id.nav_list);
+ ListView list = (ListView) solo.getView(R.id.nav_list);
for (int i = 0; i < uiTestUtils.hostedFeeds.size(); i++) {
Feed f = uiTestUtils.hostedFeeds.get(i);
solo.clickOnScreen(50, 50); // open nav drawer
@@ -137,9 +139,10 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
}
private String getActionbarTitle() {
- return ((MainActivity)solo.getCurrentActivity()).getMainActivtyActionBar().getTitle().toString();
+ return ((MainActivity) solo.getCurrentActivity()).getSupportActionBar().getTitle().toString();
}
+ @SuppressWarnings("unchecked")
@FlakyTest(tolerance = 3)
public void testGoToPreferences() {
openNavDrawer();
@@ -185,14 +188,14 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
openNavDrawer();
solo.clickLongOnText(solo.getString(R.string.queue_label));
solo.waitForDialogToOpen();
- for(String title : titles) {
+ for (String title : titles) {
solo.clickOnText(title);
}
solo.clickOnText(solo.getString(R.string.confirm_label));
solo.waitForDialogToClose();
List<String> hidden = UserPreferences.getHiddenDrawerItems();
assertEquals(titles.length, hidden.size());
- for(String tag : MainActivity.NAV_DRAWER_TAGS) {
+ for (String tag : MainActivity.NAV_DRAWER_TAGS) {
assertTrue(hidden.contains(tag));
}
}
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 c43757546..d4994fb1a 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java
@@ -1,7 +1,6 @@
package de.test.antennapod.ui;
import android.annotation.TargetApi;
-import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -10,7 +9,6 @@ import android.preference.PreferenceManager;
import android.test.ActivityInstrumentationTestCase2;
import android.test.FlakyTest;
import android.view.View;
-import android.widget.ImageButton;
import android.widget.ListView;
import com.robotium.solo.Solo;
@@ -21,15 +19,12 @@ import java.util.List;
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.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
-import de.danoeh.antennapod.core.util.playback.Playable;
-import de.danoeh.antennapod.core.util.playback.PlaybackController;
/**
* test cases for starting and ending playback from the MainActivity and AudioPlayerActivity
@@ -54,10 +49,11 @@ public class PlaybackSonicTest extends ActivityInstrumentationTestCase2<MainActi
public void setUp() throws Exception {
super.setUp();
- PodDBAdapter.deleteDatabase();
-
context = getInstrumentation().getTargetContext();
+ PodDBAdapter.init(context);
+ PodDBAdapter.deleteDatabase();
+
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit()
.clear()
@@ -90,7 +86,7 @@ public class PlaybackSonicTest extends ActivityInstrumentationTestCase2<MainActi
}
private void openNavDrawer() {
- solo.clickOnScreen(50, 50);
+ solo.clickOnImageButton(0);
getInstrumentation().waitForIdleSync();
}
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 195e3d250..5ce495f9a 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
@@ -46,10 +46,11 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity>
public void setUp() throws Exception {
super.setUp();
- PodDBAdapter.deleteDatabase();
-
context = getInstrumentation().getTargetContext();
+ PodDBAdapter.init(context);
+ PodDBAdapter.deleteDatabase();
+
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit()
.clear()
@@ -79,9 +80,9 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity>
super.tearDown();
}
-
private void openNavDrawer() {
- solo.clickOnScreen(50, 50);
+ solo.clickOnImageButton(0);
+ getInstrumentation().waitForIdleSync();
}
private void setContinuousPlaybackPreference(boolean value) {
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 fabc399ba..54741502c 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
@@ -3,17 +3,10 @@ package de.test.antennapod.ui;
import android.content.Context;
import android.content.res.Resources;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
-import com.robotium.solo.Condition;
import com.robotium.solo.Solo;
import com.robotium.solo.Timeout;
-import org.apache.commons.io.IOUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.R;
@@ -156,8 +149,8 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
public void testPlaybackSpeeds() {
solo.clickOnText(solo.getString(R.string.pref_playback_speed_title));
solo.waitForDialogToOpen(1000);
- assertTrue(solo.searchText(solo.getString(R.string.no_playback_plugin_title)));
- solo.clickOnText(solo.getString(R.string.close_label));
+ assertTrue(solo.searchText(res.getStringArray(R.array.playback_speed_values)[0]));
+ solo.clickOnText(solo.getString(R.string.cancel_label));
solo.waitForDialogToClose(1000);
}
@@ -230,6 +223,8 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
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));
solo.waitForDialogToOpen();
solo.clickOnText(entry);
@@ -241,6 +236,11 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
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));
solo.waitForDialogToOpen(1000);
solo.scrollUp();
@@ -248,12 +248,16 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
assertTrue(solo.waitForCondition(() -> UserPreferences.getEpisodeCacheSize() == minValue, Timeout.getLargeTimeout()));
}
-
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.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);
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 13abbb1cc..432d4a4e6 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
@@ -143,7 +143,7 @@ public class UITestUtils {
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, new Date(), "Title " + i, "http://example.com/" + i, "Description of feed " + i,
+ 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/feed/src/" + i, false);
image.setOwner(feed);
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 6c5a350de..53fd7d7fd 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java
@@ -1,15 +1,15 @@
package de.test.antennapod.ui;
import android.test.InstrumentationTestCase;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import org.apache.http.HttpStatus;
import java.io.File;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedItem;
+
/**
* Test for the UITestUtils. Makes sure that all URLs are reachable and that the class does not cause any crashes.
*/
@@ -55,7 +55,7 @@ public class UITestUtilsTest extends InstrumentationTestCase {
conn.setRequestMethod("GET");
conn.connect();
int rc = conn.getResponseCode();
- assertEquals(HttpStatus.SC_OK, rc);
+ assertEquals(HttpURLConnection.HTTP_OK, rc);
conn.disconnect();
}
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 4a5818479..28ff6694e 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
@@ -1,6 +1,21 @@
package de.test.antennapod.util.service.download;
-import java.io.*;
+import android.support.v4.util.ArrayMap;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.PushbackInputStream;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
@@ -14,7 +29,6 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -281,7 +295,7 @@ public abstract class NanoHTTPD {
* @return HTTP response, see class Response for details
*/
public Response serve(IHTTPSession session) {
- Map<String, String> files = new HashMap<String, String>();
+ Map<String, String> files = new ArrayMap<>();
Method method = session.getMethod();
if (Method.PUT.equals(method) || Method.POST.equals(method)) {
try {
@@ -334,7 +348,7 @@ public abstract class NanoHTTPD {
* @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 HashMap<String, List<String>>();
+ Map<String, List<String>> parms = new ArrayMap<String, List<String>>();
if (queryString != null) {
StringTokenizer st = new StringTokenizer(queryString, "&");
while (st.hasMoreTokens()) {
@@ -549,7 +563,7 @@ public abstract class NanoHTTPD {
/**
* Headers for the HTTP response. Use addHeader() to add lines.
*/
- private Map<String, String> header = new HashMap<String, String>();
+ private Map<String, String> header = new ArrayMap<String, String>();
/**
* The request method that spawned this response.
*/
@@ -851,7 +865,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 HashMap<String, String>();
+ headers = new ArrayMap<String, String>();
headers.put("remote-addr", remoteIp);
headers.put("http-client-ip", remoteIp);
@@ -895,16 +909,16 @@ public abstract class NanoHTTPD {
inputStream.unread(buf, splitbyte, rlen - splitbyte);
}
- parms = new HashMap<String, String>();
+ parms = new ArrayMap<String, String>();
if(null == headers) {
- headers = new HashMap<String, String>();
+ headers = new ArrayMap<String, String>();
}
// 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 HashMap<String, String>();
+ Map<String, String> pre = new ArrayMap<String, String>();
decodeHeader(hin, pre, parms, headers);
method = Method.lookup(pre.get("method"));
@@ -1102,7 +1116,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 HashMap<String, String>();
+ Map<String, String> item = new ArrayMap<String, String>();
mpline = in.readLine();
while (mpline != null && mpline.trim().length() > 0) {
int p = mpline.indexOf(':');
@@ -1117,7 +1131,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 HashMap<String, String>();
+ Map<String, String> disposition = new ArrayMap<String, String>();
while (st.hasMoreTokens()) {
String token = st.nextToken().trim();
int p = token.indexOf('=');
@@ -1352,7 +1366,7 @@ public abstract class NanoHTTPD {
* @author LordFokas
*/
public class CookieHandler implements Iterable<String> {
- private HashMap<String, String> cookies = new HashMap<String, String>();
+ private ArrayMap<String, String> cookies = new ArrayMap<String, String>();
private ArrayList<Cookie> queue = new ArrayList<Cookie>();
public CookieHandler(Map<String, String> httpHeaders) {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ae2e69b5c..36067d52e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.danoeh.antennapod"
- android:versionCode="1040104"
- android:versionName="1.4.1.4">
+ android:versionCode="1050009"
+ android:versionName="1.5.0.9">
<!--
Version code schema:
"1.2.3-SNAPSHOT" -> 1020300
diff --git a/app/src/main/assets/LICENSE_ANTENNAPOD_AUDIOPLAYER.txt b/app/src/main/assets/LICENSE_ANTENNAPOD_AUDIOPLAYER.txt
deleted file mode 100644
index 8dada3eda..000000000
--- a/app/src/main/assets/LICENSE_ANTENNAPOD_AUDIOPLAYER.txt
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "{}"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright {yyyy} {name of copyright owner}
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_APACHE_COMMONS.txt b/app/src/main/assets/LICENSE_APACHE-2.0.txt
index d64569567..d64569567 100644
--- a/app/src/main/assets/LICENSE_APACHE_COMMONS.txt
+++ b/app/src/main/assets/LICENSE_APACHE-2.0.txt
diff --git a/app/src/main/assets/LICENSE_EVENTBUS.txt b/app/src/main/assets/LICENSE_EVENTBUS.txt
deleted file mode 100644
index d64569567..000000000
--- a/app/src/main/assets/LICENSE_EVENTBUS.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_FLATTR4J.txt b/app/src/main/assets/LICENSE_FLATTR4J.txt
deleted file mode 100644
index d64569567..000000000
--- a/app/src/main/assets/LICENSE_FLATTR4J.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_FLEXIBLE_DIVIDER.txt b/app/src/main/assets/LICENSE_FLEXIBLE_DIVIDER.txt
deleted file mode 100644
index 5c304d1a4..000000000
--- a/app/src/main/assets/LICENSE_FLEXIBLE_DIVIDER.txt
+++ /dev/null
@@ -1,201 +0,0 @@
-Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "{}"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright {yyyy} {name of copyright owner}
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_OKIO.txt b/app/src/main/assets/LICENSE_OKIO.txt
deleted file mode 100644
index d64569567..000000000
--- a/app/src/main/assets/LICENSE_OKIO.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_RX_ANDROID.txt b/app/src/main/assets/LICENSE_RX_ANDROID.txt
deleted file mode 100644
index 4fe2d187f..000000000
--- a/app/src/main/assets/LICENSE_RX_ANDROID.txt
+++ /dev/null
@@ -1,200 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_STACKBLUR.txt b/app/src/main/assets/LICENSE_STACKBLUR.txt
deleted file mode 100644
index b66736ccb..000000000
--- a/app/src/main/assets/LICENSE_STACKBLUR.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-Apache License, Version 2.0
-
-Version 2.0, January 2004
-
-http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
-"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
-
-"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
-
-"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
-
-"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
-
-"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
-
-"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
-
-"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
-
-"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
-
-"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
-
-"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
-
-2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
-
-3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
-
-4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
-
-You must give any other recipients of the Work or Derivative Works a copy of this License; and
-You must cause any modified files to carry prominent notices stating that You changed the files; and
-You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
-If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
-
-You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
-5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
-
-6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
-
-8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work
-To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
-
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java b/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java
index 17942a93c..ea2166674 100644
--- a/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java
+++ b/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java
@@ -34,8 +34,11 @@ public class CrashReportWriter implements Thread.UncaughtExceptionHandler {
out = new PrintWriter(new FileWriter(path));
out.println("[ Environment ]");
out.println("Android version: " + Build.VERSION.RELEASE);
+ out.println("OS version: " + System.getProperty("os.version"));
out.println("AntennaPod version: " + BuildConfig.VERSION_NAME);
- out.println("Phone model: " + Build.MODEL);
+ out.println("Model: " + Build.MODEL);
+ out.println("Device: " + Build.DEVICE);
+ out.println("Product: " + Build.PRODUCT);
out.println();
out.println("[ StackTrace ]");
ex.printStackTrace(out);
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
index 835f43f40..829a49a15 100644
--- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
+++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
@@ -6,6 +6,7 @@ import android.os.StrictMode;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.fonts.FontAwesomeModule;
+import com.joanzapata.iconify.fonts.MaterialModule;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
@@ -56,12 +57,13 @@ public class PodcastApp extends Application {
singleton = this;
PodDBAdapter.init(this);
- UpdateManager.init(this);
UserPreferences.init(this);
+ UpdateManager.init(this);
PlaybackPreferences.init(this);
NetworkUtils.init(this);
EventDistributor.getInstance();
Iconify.with(new FontAwesomeModule());
+ Iconify.with(new MaterialModule());
SPAUtil.sendSPAppsQueryFeedsIntent(this);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/UpdateManager.java b/app/src/main/java/de/danoeh/antennapod/UpdateManager.java
index b1d7fffc8..0b3c43381 100644
--- a/app/src/main/java/de/danoeh/antennapod/UpdateManager.java
+++ b/app/src/main/java/de/danoeh/antennapod/UpdateManager.java
@@ -5,14 +5,18 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.util.Log;
+import org.antennapod.audio.MediaPlayer;
+
import java.io.File;
import java.util.List;
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.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
@@ -83,6 +87,11 @@ public class UpdateManager {
}
}.start();
}
+ if(oldVersionCode < 1050004) {
+ if(MediaPlayer.isPrestoLibraryInstalled(context) && Build.VERSION.SDK_INT >= 16) {
+ UserPreferences.enableSonic(true);
+ }
+ }
}
}
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 220724af4..b4e8d4d71 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -1,54 +1,44 @@
package de.danoeh.antennapod.activity;
+import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
-import android.content.res.TypedArray;
-import android.graphics.drawable.BitmapDrawable;
-import android.os.Bundle;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.design.widget.AppBarLayout;
import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.app.ListFragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
+import android.util.TypedValue;
import android.view.ContextMenu;
-import android.view.Gravity;
-import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.ScaleAnimation;
import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.ImageButton;
import android.widget.ListView;
-import android.widget.PopupWindow;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import com.bumptech.glide.Glide;
+import com.viewpagerindicator.CirclePageIndicator;
-import org.apache.commons.lang3.ArrayUtils;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.adapter.ChapterListAdapter;
+import de.danoeh.antennapod.adapter.ChaptersListAdapter;
import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
-import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
-import de.danoeh.antennapod.core.feed.SimpleChapter;
-import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
@@ -57,8 +47,14 @@ import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.fragment.AddFeedFragment;
+import de.danoeh.antennapod.fragment.ChaptersFragment;
import de.danoeh.antennapod.fragment.CoverFragment;
+import de.danoeh.antennapod.fragment.DownloadsFragment;
+import de.danoeh.antennapod.fragment.EpisodesFragment;
import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
+import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
+import de.danoeh.antennapod.fragment.QueueFragment;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
import de.danoeh.antennapod.preferences.PreferenceController;
import rx.Observable;
@@ -69,85 +65,40 @@ import rx.schedulers.Schedulers;
/**
* Activity for playing audio files.
*/
-public class AudioplayerActivity extends MediaplayerActivity implements ItemDescriptionFragment.ItemDescriptionFragmentCallback,
- NavDrawerActivity {
+public class AudioplayerActivity extends MediaplayerActivity implements NavDrawerActivity {
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;
- private static final int POS_NONE = -1;
final String TAG = "AudioplayerActivity";
private static final String PREFS = "AudioPlayerActivityPreferences";
private static final String PREF_KEY_SELECTED_FRAGMENT_POSITION = "selectedFragmentPosition";
- private static final String PREF_PLAYABLE_ID = "playableId";
+
+ public static final String[] NAV_DRAWER_TAGS = {
+ QueueFragment.TAG,
+ EpisodesFragment.TAG,
+ DownloadsFragment.TAG,
+ PlaybackHistoryFragment.TAG,
+ AddFeedFragment.TAG
+ };
+
+ private AtomicBoolean isSetup = new AtomicBoolean(false);
private DrawerLayout drawerLayout;
private NavListAdapter navAdapter;
private ListView navList;
- private AdapterView.AdapterContextMenuInfo lastMenuInfo = null;
private View navDrawer;
private ActionBarDrawerToggle drawerToggle;
+ private int mPosition = -1;
- private Fragment[] detachedFragments;
-
- private CoverFragment coverFragment;
- private ItemDescriptionFragment descriptionFragment;
- private ListFragment chapterFragment;
-
- private Fragment currentlyShownFragment;
- private int currentlyShownPosition = -1;
- private int lastShownPosition = POS_NONE;
- /**
- * Used if onResume was called without loadMediaInfo.
- */
- private int savedPosition = -1;
-
- private TextView txtvTitle;
- private Button butPlaybackSpeed;
- private ImageButton butNavChaptersShownotes;
- private ImageButton butShowCover;
+ private Playable media;
+ private ViewPager pager;
+ private AudioplayerPagerAdapter pagerAdapter;
private Subscription subscription;
- private PopupWindow popupWindow;
-
- private void resetFragmentView() {
- FragmentTransaction fT = getSupportFragmentManager().beginTransaction();
-
- if (coverFragment != null) {
- Log.d(TAG, "Removing cover fragment");
- fT.remove(coverFragment);
- }
- if (descriptionFragment != null) {
- Log.d(TAG, "Removing description fragment");
- fT.remove(descriptionFragment);
- }
- if (chapterFragment != null) {
- Log.d(TAG, "Removing chapter fragment");
- fT.remove(chapterFragment);
- }
- if (currentlyShownFragment != null) {
- Log.d(TAG, "Removing currently shown fragment");
- fT.remove(currentlyShownFragment);
- }
- for (int i = 0; i < detachedFragments.length; i++) {
- Fragment f = detachedFragments[i];
- if (f != null) {
- Log.d(TAG, "Removing detached fragment");
- fT.remove(f);
- }
- }
- fT.commit();
- currentlyShownFragment = null;
- coverFragment = null;
- descriptionFragment = null;
- chapterFragment = null;
- currentlyShownPosition = -1;
- detachedFragments = new Fragment[NUM_CONTENT_FRAGMENTS];
- }
-
@Override
protected void onStop() {
super.onStop();
@@ -156,91 +107,48 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
subscription.unsubscribe();
}
EventDistributor.getInstance().unregister(contentUpdate);
+ saveCurrentFragment();
}
@Override
- protected void chooseTheme() {
- setTheme(UserPreferences.getNoTitleTheme());
+ public void onDestroy() {
+ super.onDestroy();
+ // don't risk creating memory leaks
+ navAdapter = null;
+ drawerToggle = null;
+ pager = null;
+ pagerAdapter = null;
}
@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- detachedFragments = new Fragment[NUM_CONTENT_FRAGMENTS];
+ protected void chooseTheme() {
+ setTheme(UserPreferences.getNoTitleTheme());
}
- private void savePreferences() {
+ private void saveCurrentFragment() {
+ if(pager == null) {
+ return;
+ }
Log.d(TAG, "Saving preferences");
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
- SharedPreferences.Editor editor = prefs.edit();
- if (currentlyShownPosition >= 0 && controller != null
- && controller.getMedia() != null) {
- editor.putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION,
- currentlyShownPosition);
- editor.putString(PREF_PLAYABLE_ID, controller.getMedia()
- .getIdentifier().toString());
- } else {
- editor.putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, -1);
- editor.putString(PREF_PLAYABLE_ID, "");
- }
- editor.commit();
-
- savedPosition = currentlyShownPosition;
+ prefs.edit()
+ .putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, pager.getCurrentItem())
+ .commit();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- drawerToggle.onConfigurationChanged(newConfig);
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- // super.onSaveInstanceState(outState); would cause crash
- Log.d(TAG, "onSaveInstanceState");
- }
-
- @Override
- protected void onPause() {
- savePreferences();
- resetFragmentView();
- super.onPause();
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- restoreFromPreferences();
+ if(drawerToggle != null) {
+ drawerToggle.onConfigurationChanged(newConfig);
+ }
}
- /**
- * Tries to restore the selected fragment position from the Activity's
- * preferences.
- *
- * @return true if restoreFromPrefernces changed the activity's state
- */
- private boolean restoreFromPreferences() {
+ private void loadLastFragment() {
Log.d(TAG, "Restoring instance state");
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
- int savedPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION,
- -1);
- String playableId = prefs.getString(PREF_PLAYABLE_ID, "");
-
- if (savedPosition != -1
- && controller != null
- && controller.getMedia() != null
- && controller.getMedia().getIdentifier().toString()
- .equals(playableId)) {
- switchToFragment(savedPosition);
- return true;
- } else if (controller == null || controller.getMedia() == null) {
- Log.d(TAG, "Couldn't restore from preferences: controller or media was null");
- } else {
- Log.d(TAG, "Couldn't restore from preferences: savedPosition was -1 or saved identifier and playable identifier didn't match.\nsavedPosition: "
- + savedPosition + ", id: " + playableId);
-
- }
- return false;
+ int lastPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, -1);
+ pager.setCurrentItem(lastPosition);
}
@Override
@@ -260,8 +168,9 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
true);
startService(launchIntent);
}
- if (savedPosition != -1) {
- switchToFragment(savedPosition);
+ if(pagerAdapter != null && controller != null && controller.getMedia() != media) {
+ media = controller.getMedia();
+ pagerAdapter.onMediaChanged(media);
}
EventDistributor.getInstance().register(contentUpdate);
@@ -292,147 +201,28 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
@Override
protected void clearStatusMsg() {
// TODO Hide progress bar here
-
}
- /**
- * Changes the currently displayed fragment.
- *
- * @param pos Must be POS_COVER, POS_DESCR, or POS_CHAPTERS
- */
- private void switchToFragment(int pos) {
- Log.d(TAG, "Switching contentView to position " + pos);
- if (currentlyShownPosition != pos && controller != null) {
- Playable media = controller.getMedia();
- if (media != null) {
- FragmentTransaction ft = getSupportFragmentManager()
- .beginTransaction();
- if (currentlyShownFragment != null) {
- detachedFragments[currentlyShownPosition] = currentlyShownFragment;
- ft.detach(currentlyShownFragment);
- }
- switch (pos) {
- case POS_COVER:
- if (coverFragment == null) {
- Log.i(TAG, "Using new coverfragment");
- coverFragment = CoverFragment.newInstance(media);
- }
- currentlyShownFragment = coverFragment;
- break;
- case POS_DESCR:
- if (descriptionFragment == null) {
- descriptionFragment = ItemDescriptionFragment
- .newInstance(media, true, true);
- }
- currentlyShownFragment = descriptionFragment;
- break;
- case POS_CHAPTERS:
- if (chapterFragment == null) {
- chapterFragment = new ListFragment() {
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- // add padding
- final ListView lv = getListView();
- lv.setClipToPadding(false);
- final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
- lv.setPadding(0, vertPadding, 0, vertPadding);
- }
- };
- chapterFragment.setListAdapter(new ChapterListAdapter(
- AudioplayerActivity.this, 0, media
- .getChapters(), media, position -> {
- Chapter chapter = (Chapter)
- chapterFragment.getListAdapter().getItem(position);
- controller.seekToChapter(chapter);
- }
- ));
- }
- currentlyShownFragment = chapterFragment;
- break;
- }
- if (currentlyShownFragment != null) {
- lastShownPosition = currentlyShownPosition;
- currentlyShownPosition = pos;
- if (detachedFragments[pos] != null) {
- Log.d(TAG, "Reattaching fragment at position " + pos);
- ft.attach(detachedFragments[pos]);
- } else {
- ft.add(R.id.contentView, currentlyShownFragment);
- }
- ft.disallowAddToBackStack();
- ft.commit();
- updateNavButtonDrawable();
- }
- }
- }
- }
-
- /**
- * Switches to the fragment that was displayed before the current one or the description fragment
- * if no fragment was previously displayed.
- */
- public void switchToLastFragment() {
- if (lastShownPosition != POS_NONE) {
- switchToFragment(lastShownPosition);
- } else {
- switchToFragment(POS_DESCR);
- }
- }
-
- private void updateNavButtonDrawable() {
-
- final int[] buttonTexts = new int[]{R.string.show_shownotes_label,
- R.string.show_chapters_label};
-
- final TypedArray drawables = obtainStyledAttributes(new int[]{
- R.attr.navigation_shownotes, R.attr.navigation_chapters});
- final Playable media = controller.getMedia();
- if (butNavChaptersShownotes != null && butShowCover != null && media != null) {
-
- butNavChaptersShownotes.setTag(R.id.imageloader_key, null);
- setNavButtonVisibility();
- switch (currentlyShownPosition) {
- case POS_COVER:
- butShowCover.setVisibility(View.GONE);
- if (lastShownPosition == POS_CHAPTERS) {
- butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(1));
- butNavChaptersShownotes.setContentDescription(getString(buttonTexts[1]));
- } else {
- butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(0));
- butNavChaptersShownotes.setContentDescription(getString(buttonTexts[0]));
- }
- break;
- case POS_DESCR:
- butShowCover.setVisibility(View.VISIBLE);
- butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(1));
- butNavChaptersShownotes.setContentDescription(getString(buttonTexts[1]));
- break;
- case POS_CHAPTERS:
- butShowCover.setVisibility(View.VISIBLE);
- butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(0));
- butNavChaptersShownotes.setContentDescription(getString(buttonTexts[0]));
- break;
- }
- }
- drawables.recycle();
- }
@Override
protected void setupGUI() {
+ if(isSetup.getAndSet(true)) {
+ return;
+ }
super.setupGUI();
- resetFragmentView();
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);
+ 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);
navDrawer = findViewById(R.id.nav_layout);
- butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
- butNavChaptersShownotes = (ImageButton) findViewById(R.id.butNavChaptersShownotes);
- butShowCover = (ImageButton) findViewById(R.id.butCover);
- txtvTitle = (TextView) findViewById(R.id.txtvTitle);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close);
drawerToggle.setDrawerIndicatorEnabled(false);
@@ -450,6 +240,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
}
drawerLayout.closeDrawer(navDrawer);
});
+ navList.setOnItemLongClickListener((parent, view, position, id) -> {
+ if (position < navAdapter.getTags().size()) {
+ showDrawerPreferencesDialog();
+ return true;
+ } else {
+ mPosition = position;
+ return false;
+ }
+ });
registerForContextMenu(navList);
drawerToggle.syncState();
@@ -458,128 +257,13 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
startActivity(new Intent(AudioplayerActivity.this, PreferenceController.getPreferenceActivity()));
});
- butNavChaptersShownotes.setOnClickListener(v -> {
- if (currentlyShownPosition == POS_CHAPTERS) {
- switchToFragment(POS_DESCR);
- } else if (currentlyShownPosition == POS_DESCR) {
- switchToFragment(POS_CHAPTERS);
- } else if (currentlyShownPosition == POS_COVER) {
- switchToLastFragment();
- }
- });
-
- butShowCover.setOnClickListener(v -> switchToFragment(POS_COVER));
-
- butPlaybackSpeed.setOnClickListener(v -> {
- if (controller != null && controller.canSetPlaybackSpeed()) {
- String[] availableSpeeds = UserPreferences
- .getPlaybackSpeedArray();
- String currentSpeed = UserPreferences.getPlaybackSpeed();
-
- // Provide initial value in case the speed list has changed
- // out from under us
- // and our current speed isn't in the new list
- String newSpeed;
- if (availableSpeeds.length > 0) {
- newSpeed = availableSpeeds[0];
- } else {
- newSpeed = "1.0";
- }
-
- for (int i = 0; i < availableSpeeds.length; i++) {
- if (availableSpeeds[i].equals(currentSpeed)) {
- if (i == availableSpeeds.length - 1) {
- newSpeed = availableSpeeds[0];
- } else {
- newSpeed = availableSpeeds[i + 1];
- }
- break;
- }
- }
- UserPreferences.setPlaybackSpeed(newSpeed);
- controller.setPlaybackSpeed(Float.parseFloat(newSpeed));
- }
- });
-
- butPlaybackSpeed.setOnLongClickListener(v -> {
-
- String[] availableSpeeds = getResources().getStringArray(R.array.playback_speed_values);
- String currentSpeed = UserPreferences.getPlaybackSpeed();
-
- LayoutInflater inflater = getLayoutInflater();
- View popupView = inflater.inflate(R.layout.choose_speed_dialog, null);
- TextView txtvSelectedSpeed = (TextView) popupView.findViewById(R.id.txtvSelectedSpeed);
- SeekBar sbSelectSpeed = (SeekBar) popupView.findViewById(R.id.sbSelectSpeed);
-
- txtvSelectedSpeed.setText(currentSpeed);
- int progress = ArrayUtils.indexOf(availableSpeeds, currentSpeed);
- int max = Math.max(progress, ArrayUtils.indexOf(availableSpeeds, "2.50"));
- sbSelectSpeed.setMax(max);
- sbSelectSpeed.setProgress(progress);
- sbSelectSpeed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- txtvSelectedSpeed.setText(availableSpeeds[progress]);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- String selectedSpeed = availableSpeeds[sbSelectSpeed.getProgress()];
- UserPreferences.setPlaybackSpeed(selectedSpeed);
- controller.setPlaybackSpeed(Float.parseFloat(selectedSpeed));
- if (popupWindow != null && popupWindow.isShowing()) {
- popupWindow.dismiss();
- }
- ScaleAnimation anim = new ScaleAnimation(1.0f, 1.33f, 1.0f, 1.33f,
- butPlaybackSpeed.getWidth()/2, butPlaybackSpeed.getHeight()/2);
- anim.setDuration(150);
- anim.setRepeatMode(ScaleAnimation.REVERSE);
- anim.setRepeatCount(1);
- anim.setInterpolator(new LinearInterpolator());
- butPlaybackSpeed.startAnimation(anim);
- }
- });
- popupWindow = new PopupWindow(popupView,
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- true);
- popupWindow.setBackgroundDrawable(new BitmapDrawable());
- popupWindow.setOutsideTouchable(true);
- popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);
- return true;
- });
- }
-
- private void setNavButtonVisibility() {
- if (butNavChaptersShownotes != null) {
- if (controller != null) {
- Playable media = controller.getMedia();
- if (media != null) {
- if (media.getChapters() != null || currentlyShownPosition == POS_COVER) {
- butNavChaptersShownotes.setVisibility(View.VISIBLE);
- return;
- }
- }
- }
- butNavChaptersShownotes.setVisibility(View.GONE);
- }
-
- }
-
- @Override
- protected void onPlaybackSpeedChange() {
- super.onPlaybackSpeedChange();
- updateButPlaybackSpeed();
- }
-
- private void updateButPlaybackSpeed() {
- if (controller != null && controller.canSetPlaybackSpeed()) {
- butPlaybackSpeed.setText(UserPreferences.getPlaybackSpeed());
- }
+ pager = (ViewPager) findViewById(R.id.pager);
+ pagerAdapter = new AudioplayerPagerAdapter(getSupportFragmentManager());
+ pager.setAdapter(pagerAdapter);
+ CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator);
+ pageIndicator.setViewPager(pager);
+ loadLastFragment();
+ pager.onSaveInstanceState();
}
@Override
@@ -593,49 +277,23 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
if (!super.loadMediaInfo()) {
return false;
}
- final Playable media = controller.getMedia();
- if (media == null) {
- return false;
- }
- txtvTitle.setText(media.getEpisodeTitle());
- getSupportActionBar().setTitle("");
- Glide.with(this)
- .load(media.getImageUri())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
- .into(butShowCover);
-
- setNavButtonVisibility();
-
- if (currentlyShownPosition == -1) {
- if (!restoreFromPreferences()) {
- switchToFragment(POS_COVER);
- }
- }
- if (currentlyShownFragment instanceof AudioplayerContentFragment) {
- ((AudioplayerContentFragment) currentlyShownFragment)
- .onDataSetChanged(media);
- }
-
- if (controller == null
- || !controller.canSetPlaybackSpeed()) {
- butPlaybackSpeed.setVisibility(View.GONE);
- } else {
- butPlaybackSpeed.setVisibility(View.VISIBLE);
+ if(controller.getMedia() != media) {
+ media = controller.getMedia();
+ pagerAdapter.onMediaChanged(media);
}
-
- updateButPlaybackSpeed();
return true;
}
public void notifyMediaPositionChanged() {
- if (chapterFragment != null) {
- ArrayAdapter<SimpleChapter> adapter = (ArrayAdapter<SimpleChapter>) chapterFragment
- .getListAdapter();
- adapter.notifyDataSetChanged();
+ if(pagerAdapter == null) {
+ return;
+ }
+ ChaptersFragment chaptersFragment = pagerAdapter.getChaptersFragment();
+ if(chaptersFragment != null) {
+ ChaptersListAdapter adapter = (ChaptersListAdapter) chaptersFragment.getListAdapter();
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
}
}
@@ -659,7 +317,6 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
clearStatusMsg();
}
- @Override
public PlaybackController getPlaybackController() {
return controller;
}
@@ -669,10 +326,6 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer);
}
- public interface AudioplayerContentFragment {
- void onDataSetChanged(Playable media);
- }
-
@Override
protected int getContentViewResourceId() {
return R.layout.audioplayer_activity;
@@ -704,24 +357,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
menu.setHeaderTitle(feed.getTitle());
// episodes are not loaded, so we cannot check if the podcast has new or unplayed ones!
-
- // we may need to reference this elsewhere...
- lastMenuInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
}
@Override
public boolean onContextItemSelected(MenuItem item) {
- AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
-
- if(menuInfo == null) {
- menuInfo = lastMenuInfo;
- }
-
- if(menuInfo.targetView.getParent() instanceof ListView == false
- || ((ListView)menuInfo.targetView.getParent()).getId() != R.id.nav_list) {
+ final int position = mPosition;
+ mPosition = -1; // reset
+ if(position < 0) {
return false;
}
- int position = menuInfo.position;
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
switch(item.getItemId()) {
case R.id.mark_all_seen_item:
@@ -768,6 +412,47 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
}
}
+ @Override
+ public void onBackPressed() {
+ if(isDrawerOpen()) {
+ drawerLayout.closeDrawer(navDrawer);
+ } else if (pager == null || pager.getCurrentItem() == 0) {
+ // If the user is currently looking at the first step, allow the system to handle the
+ // Back button. This calls finish() on this activity and pops the back stack.
+ super.onBackPressed();
+ } else {
+ // Otherwise, select the previous step.
+ pager.setCurrentItem(pager.getCurrentItem() - 1);
+ }
+ }
+
+ public 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];
+ for (int i = 0; i < NAV_DRAWER_TAGS.length; i++) {
+ String tag = NAV_DRAWER_TAGS[i];
+ navLabels[i] = navAdapter.getLabel(tag);
+ if (!hiddenDrawerItems.contains(tag)) {
+ checked[i] = true;
+ }
+ }
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.drawer_preferences);
+ builder.setMultiChoiceItems(navLabels, checked, (dialog, which, isChecked) -> {
+ if (isChecked) {
+ hiddenDrawerItems.remove(NAV_DRAWER_TAGS[which]);
+ } else {
+ hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]);
+ }
+ });
+ builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
+ UserPreferences.setHiddenDrawerItems(hiddenDrawerItems);
+ });
+ builder.setNegativeButton(R.string.cancel_label, null);
+ builder.create().show();
+ }
private DBReader.NavDrawerData navDrawerData;
@@ -810,7 +495,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
@Override
public Feed getItem(int position) {
- if (navDrawerData != null && position < navDrawerData.feeds.size()) {
+ if (navDrawerData != null && 0 <= position && position < navDrawerData.feeds.size()) {
return navDrawerData.feeds.get(position);
} else {
return null;
@@ -833,9 +518,80 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
}
@Override
+ public int getNumberOfDownloadedItems() {
+ return (navDrawerData != null) ? navDrawerData.numDownloadedItems : 0;
+ }
+
+ @Override
+ public int getReclaimableItems() {
+ return (navDrawerData != null) ? navDrawerData.reclaimableSpace : 0;
+ }
+
+ @Override
public int getFeedCounter(long feedId) {
return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0;
}
};
+ public interface AudioplayerContentFragment {
+ void onMediaChanged(Playable media);
+ }
+
+ private class AudioplayerPagerAdapter extends FragmentStatePagerAdapter {
+
+ public AudioplayerPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ private CoverFragment coverFragment;
+ private ItemDescriptionFragment itemDescriptionFragment;
+ private ChaptersFragment chaptersFragment;
+
+ public void onMediaChanged(Playable media) {
+ if(coverFragment != null) {
+ coverFragment.onMediaChanged(media);
+ }
+ if(itemDescriptionFragment != null) {
+ itemDescriptionFragment.onMediaChanged(media);
+ }
+ if(chaptersFragment != null) {
+ chaptersFragment.onMediaChanged(media);
+ }
+ }
+
+ @Nullable
+ public ChaptersFragment getChaptersFragment() {
+ return chaptersFragment;
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ Log.d(TAG, "getItem(" + position + ")");
+ switch (position) {
+ case POS_COVER:
+ if(coverFragment == null) {
+ coverFragment = CoverFragment.newInstance(media);
+ }
+ return coverFragment;
+ case POS_DESCR:
+ if(itemDescriptionFragment == null) {
+ itemDescriptionFragment = ItemDescriptionFragment.newInstance(media, true, true);
+ }
+ return itemDescriptionFragment;
+ case POS_CHAPTERS:
+ if(chaptersFragment == null) {
+ chaptersFragment = ChaptersFragment.newInstance(media, controller);
+ }
+ return chaptersFragment;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return NUM_CONTENT_FRAGMENTS;
+ }
+ }
+
}
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 25dc64232..62e85120d 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
@@ -6,8 +6,8 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.FileObserver;
import android.support.v4.app.NavUtils;
-import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -34,7 +34,8 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
* Let's the user choose a directory on the storage device. The selected folder
* will be sent back to the starting activity as an activity result.
*/
-public class DirectoryChooserActivity extends ActionBarActivity {
+public class DirectoryChooserActivity extends AppCompatActivity {
+
private static final String TAG = "DirectoryChooserActivit";
private static final String CREATE_DIRECTORY_NAME = "AntennaPod";
@@ -250,8 +251,7 @@ public class DirectoryChooserActivity extends ActionBarActivity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.new_folder_item)
- .setVisible(isValidFile(selectedDir));
+ menu.findItem(R.id.new_folder_item).setVisible(isValidFile(selectedDir));
return true;
}
@@ -333,4 +333,5 @@ public class DirectoryChooserActivity extends ActionBarActivity {
private boolean isValidFile(File file) {
return file != null && file.isDirectory() && file.canRead() && file.canWrite();
}
+
}
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 80883e4ae..9116decb0 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
@@ -18,9 +18,9 @@ import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.CheckBox;
-import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
+import android.widget.RadioButton;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
@@ -32,6 +32,7 @@ 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.preferences.UserPreferences;
@@ -61,8 +62,13 @@ public class FeedInfoActivity extends ActionBarActivity {
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 final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() {
@Override
@@ -100,9 +106,21 @@ public class FeedInfoActivity extends ActionBarActivity {
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;
+ });
txtvUrl.setOnClickListener(copyUrlToClipboard);
@@ -151,15 +169,18 @@ public class FeedInfoActivity extends ActionBarActivity {
cbxAutoDownload.setEnabled(UserPreferences.isEnableAutodownload());
cbxAutoDownload.setChecked(prefs.getAutoDownload());
- cbxAutoDownload.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
- feed.getPreferences().setAutoDownload(checked);
- feed.savePreferences(FeedInfoActivity.this);
- ApplyToEpisodesDialog dialog = new ApplyToEpisodesDialog(FeedInfoActivity.this,
- feed, checked);
- dialog.createNewDialog().show();
- }
+ cbxAutoDownload.setOnCheckedChangeListener((compoundButton, checked) -> {
+ feed.getPreferences().setAutoDownload(checked);
+ feed.savePreferences(FeedInfoActivity.this);
+ 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(FeedInfoActivity.this);
});
spnAutoDelete.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
@@ -184,6 +205,7 @@ public class FeedInfoActivity extends ActionBarActivity {
feed.getPreferences().setAutoDeleteAction(auto_delete_action);// p
autoDeleteChanged = true;
}
+
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Another interface callback
@@ -197,8 +219,27 @@ public class FeedInfoActivity extends ActionBarActivity {
etxtUsername.addTextChangedListener(authTextWatcher);
etxtPassword.addTextChangedListener(authTextWatcher);
- supportInvalidateOptionsMenu();
+ 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();
} else {
Log.e(TAG, "Activity was started with invalid arguments");
}
@@ -227,6 +268,25 @@ public class FeedInfoActivity extends ActionBarActivity {
}
};
+ 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 onPause() {
super.onPause();
@@ -237,11 +297,24 @@ public class FeedInfoActivity extends ActionBarActivity {
prefs.setUsername(etxtUsername.getText().toString());
prefs.setPassword(etxtPassword.getText().toString());
}
- if (authInfoChanged || autoDeleteChanged) {
+ 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;
}
}
@@ -282,6 +355,15 @@ public class FeedInfoActivity extends ActionBarActivity {
}
}
+ 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;
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 211b895d0..bd7da7c03 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -8,8 +8,6 @@ import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.DataSetObserver;
import android.media.AudioManager;
-import android.media.Rating;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -17,12 +15,12 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
+import android.util.TypedValue;
import android.view.ContextMenu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -73,7 +71,7 @@ import rx.schedulers.Schedulers;
/**
* The activity that is shown when the user launches the app.
*/
-public class MainActivity extends ActionBarActivity implements NavDrawerActivity {
+public class MainActivity extends AppCompatActivity implements NavDrawerActivity {
private static final String TAG = "MainActivity";
@@ -127,7 +125,13 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
- getSupportActionBar().setElevation(3.0f);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ findViewById(R.id.shadow).setVisibility(View.GONE);
+ int elevation = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4,
+ getResources().getDisplayMetrics());
+ getSupportActionBar().setElevation(elevation);
+ }
currentTitle = getTitle();
@@ -220,6 +224,9 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
if (prefs.getBoolean(PREF_IS_FIRST_LAUNCH, true)) {
new Handler().postDelayed(() -> drawerLayout.openDrawer(navDrawer), 1500);
+ // for backward compatibility, we only change defaults for fresh installs
+ UserPreferences.setUpdateInterval(12);
+
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(PREF_IS_FIRST_LAUNCH, false);
edit.commit();
@@ -254,10 +261,6 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
builder.create().show();
}
- public ActionBar getMainActivtyActionBar() {
- return getSupportActionBar();
- }
-
public boolean isDrawerOpen() {
return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer);
}
@@ -365,10 +368,6 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
getSupportFragmentManager().popBackStack();
}
- public Toolbar getToolbar() {
- return toolbar;
- }
-
private int getSelectedNavListIndex() {
String currentFragment = getLastNavFragment();
if(currentFragment == null) {
@@ -593,8 +592,16 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
}
}
+ @Override
+ public void onBackPressed() {
+ if(isDrawerOpen()) {
+ drawerLayout.closeDrawer(navDrawer);
+ } else {
+ super.onBackPressed();
+ }
+ }
+
private DBReader.NavDrawerData navDrawerData;
- private AsyncTask<Void, Void, DBReader.NavDrawerData> loadTask;
private int selectedNavListIndex = 0;
private NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
@@ -609,7 +616,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
@Override
public Feed getItem(int position) {
- if (navDrawerData != null && position < navDrawerData.feeds.size()) {
+ if (navDrawerData != null && 0 <= position && position < navDrawerData.feeds.size()) {
return navDrawerData.feeds.get(position);
} else {
return null;
@@ -632,10 +639,19 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
}
@Override
+ public int getNumberOfDownloadedItems() {
+ return (navDrawerData != null) ? navDrawerData.numDownloadedItems : 0;
+ }
+
+ @Override
+ public int getReclaimableItems() {
+ return (navDrawerData != null) ? navDrawerData.reclaimableSpace : 0;
+ }
+
+ @Override
public int getFeedCounter(long feedId) {
return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0;
}
-
};
private void loadData() {
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 c53a5257b..0d878b556 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -1,32 +1,44 @@
package de.danoeh.antennapod.activity;
-import android.content.DialogInterface;
+import android.annotation.TargetApi;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.graphics.Color;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v4.view.ViewCompat;
import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-
import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
+import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
+import com.bumptech.glide.Glide;
+import com.joanzapata.iconify.IconDrawable;
+import com.joanzapata.iconify.fonts.FontAwesomeIcons;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.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.Converter;
import de.danoeh.antennapod.core.util.ShareUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
@@ -34,25 +46,37 @@ 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.dialog.SleepTimerDialog;
+import de.danoeh.antennapod.dialog.VariableSpeedDialog;
+import rx.Observable;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.schedulers.Schedulers;
+
/**
* Provides general features which are both needed for playing audio and video
* files.
*/
-public abstract class MediaplayerActivity extends ActionBarActivity
- implements OnSeekBarChangeListener {
+public abstract class MediaplayerActivity extends AppCompatActivity implements OnSeekBarChangeListener {
private static final String TAG = "MediaplayerActivity";
+ private static final String PREFS = "MediaPlayerActivityPreferences";
+ private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft";
protected PlaybackController controller;
protected TextView txtvPosition;
protected TextView txtvLength;
protected SeekBar sbPosition;
- protected ImageButton butPlay;
+ protected Button butPlaybackSpeed;
protected ImageButton butRev;
protected TextView txtvRev;
+ protected ImageButton butPlay;
protected ImageButton butFF;
protected TextView txtvFF;
+ protected ImageButton butSkip;
+
+ protected boolean showTimeLeft = false;
+
+ private boolean isFavorite = false;
private PlaybackController newPlaybackController() {
return new PlaybackController(this, false) {
@@ -152,7 +176,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
}
protected void onPlaybackSpeedChange() {
-
+ updateButPlaybackSpeed();
}
protected void onServiceQueried() {
@@ -182,8 +206,10 @@ public abstract class MediaplayerActivity extends ActionBarActivity
@Override
protected void onPause() {
super.onPause();
- controller.reinitServiceIfPaused();
- controller.pause();
+ if(controller != null) {
+ controller.reinitServiceIfPaused();
+ controller.pause();
+ }
}
/**
@@ -205,8 +231,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
protected void onBufferUpdate(float progress) {
if (sbPosition != null) {
- sbPosition.setSecondaryProgress((int) progress
- * sbPosition.getMax());
+ sbPosition.setSecondaryProgress((int) progress * sbPosition.getMax());
}
}
@@ -233,10 +258,17 @@ public abstract class MediaplayerActivity extends ActionBarActivity
}
}
+ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+ @Override
+ public void onTrimMemory(int level) {
+ super.onTrimMemory(level);
+ Glide.get(this).trimMemory(level);
+ }
+
@Override
- protected void onDestroy() {
- super.onDestroy();
- Log.d(TAG, "onDestroy()");
+ public void onLowMemory() {
+ super.onLowMemory();
+ Glide.get(this).clearMemory();
}
@Override
@@ -250,18 +282,23 @@ public abstract class MediaplayerActivity extends ActionBarActivity
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
+ if (controller == null) {
+ return false;
+ }
Playable media = controller.getMedia();
menu.findItem(R.id.support_item).setVisible(
media != null && media.getPaymentLink() != null &&
(media instanceof FeedMedia) &&
+ ((FeedMedia) media).getItem() != null &&
((FeedMedia) media).getItem().getFlattrStatus().flattrable()
);
boolean hasWebsiteLink = media != null && media.getWebsiteLink() != null;
menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink);
- boolean isItemAndHasLink = media != null && (media instanceof FeedMedia) && ((FeedMedia) media).getItem().getLink() != null;
+ boolean isItemAndHasLink = media != null && (media instanceof FeedMedia) &&
+ ((FeedMedia) media).getItem() != null && ((FeedMedia) media).getItem().getLink() != null;
menu.findItem(R.id.share_link_item).setVisible(isItemAndHasLink);
menu.findItem(R.id.share_link_with_position_item).setVisible(isItemAndHasLink);
@@ -271,16 +308,37 @@ public abstract class MediaplayerActivity extends ActionBarActivity
menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink);
- menu.findItem(R.id.skip_episode_item).setVisible(media != null);
+ menu.findItem(R.id.add_to_favorites_item).setVisible(false);
+ menu.findItem(R.id.remove_from_favorites_item).setVisible(false);
+ if(media != null && media instanceof FeedMedia) {
+ menu.findItem(R.id.add_to_favorites_item).setVisible(!isFavorite);
+ menu.findItem(R.id.remove_from_favorites_item).setVisible(isFavorite);
+ }
+
boolean sleepTimerSet = controller.sleepTimerActive();
boolean sleepTimerNotSet = controller.sleepTimerNotActive();
menu.findItem(R.id.set_sleeptimer_item).setVisible(sleepTimerNotSet);
menu.findItem(R.id.disable_sleeptimer_item).setVisible(sleepTimerSet);
+
+ if (this instanceof AudioplayerActivity) {
+ int[] attrs = {R.attr.action_bar_icon_color};
+ TypedArray ta = obtainStyledAttributes(UserPreferences.getTheme(), attrs);
+ int textColor = ta.getColor(0, Color.GRAY);
+ ta.recycle();
+ menu.findItem(R.id.audio_controls).setIcon(new IconDrawable(this,
+ FontAwesomeIcons.fa_sliders).color(textColor).actionBarSize());
+ } else {
+ menu.findItem(R.id.audio_controls).setVisible(false);
+ }
+
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ if (controller == null) {
+ return false;
+ }
Playable media = controller.getMedia();
if (item.getItemId() == android.R.id.home) {
Intent intent = new Intent(MediaplayerActivity.this,
@@ -289,84 +347,235 @@ public abstract class MediaplayerActivity extends ActionBarActivity
| Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
return true;
- } else if (media != null) {
- switch (item.getItemId()) {
- case R.id.disable_sleeptimer_item:
- if (controller.serviceAvailable()) {
-
- MaterialDialog.Builder stDialog = new MaterialDialog.Builder(this);
- stDialog.title(R.string.sleep_timer_label);
- stDialog.content(getString(R.string.time_left_label)
- + Converter.getDurationStringLong((int) controller
- .getSleepTimerTimeLeft()));
- stDialog.positiveText(R.string.disable_sleeptimer_label);
- stDialog.negativeText(R.string.cancel_label);
- stDialog.callback(new MaterialDialog.ButtonCallback() {
+ } else {
+ if (media != null) {
+ switch (item.getItemId()) {
+ case R.id.add_to_favorites_item:
+ if(media instanceof FeedMedia) {
+ FeedItem feedItem = ((FeedMedia)media).getItem();
+ if(feedItem != null) {
+ DBWriter.addFavoriteItem(feedItem);
+ isFavorite = true;
+ invalidateOptionsMenu();
+ Toast.makeText(this, R.string.added_to_favorites, Toast.LENGTH_SHORT)
+ .show();
+ }
+ }
+ break;
+ case R.id.remove_from_favorites_item:
+ if(media instanceof FeedMedia) {
+ FeedItem feedItem = ((FeedMedia)media).getItem();
+ if(feedItem != null) {
+ DBWriter.removeFavoriteItem(feedItem);
+ isFavorite = false;
+ invalidateOptionsMenu();
+ Toast.makeText(this, R.string.removed_from_favorites, Toast.LENGTH_SHORT)
+ .show();
+ }
+ }
+ break;
+ case R.id.disable_sleeptimer_item:
+ if (controller.serviceAvailable()) {
+
+ MaterialDialog.Builder stDialog = new MaterialDialog.Builder(this);
+ stDialog.title(R.string.sleep_timer_label);
+ stDialog.content(getString(R.string.time_left_label)
+ + Converter.getDurationStringLong((int) controller
+ .getSleepTimerTimeLeft()));
+ stDialog.positiveText(R.string.disable_sleeptimer_label);
+ stDialog.negativeText(R.string.cancel_label);
+ stDialog.callback(new MaterialDialog.ButtonCallback() {
+ @Override
+ public void onPositive(MaterialDialog dialog) {
+ dialog.dismiss();
+ controller.disableSleepTimer();
+ }
+
+ @Override
+ public void onNegative(MaterialDialog dialog) {
+ dialog.dismiss();
+ }
+ });
+ stDialog.build().show();
+ }
+ break;
+ case R.id.set_sleeptimer_item:
+ if (controller.serviceAvailable()) {
+ SleepTimerDialog td = new SleepTimerDialog(this) {
+ @Override
+ public void onTimerSet(long millis, boolean shakeToReset, boolean vibrate) {
+ controller.setSleepTimer(millis, shakeToReset, vibrate);
+ }
+ };
+ td.createNewDialog().show();
+ }
+ break;
+ case R.id.audio_controls:
+ MaterialDialog dialog = new MaterialDialog.Builder(this)
+ .title(R.string.audio_controls)
+ .customView(R.layout.audio_controls, true)
+ .neutralText(R.string.close_label)
+ .onNeutral((dialog1, which) -> {
+ final SeekBar left = (SeekBar) dialog1.findViewById(R.id.volume_left);
+ final SeekBar right = (SeekBar) dialog1.findViewById(R.id.volume_right);
+ UserPreferences.setVolume(left.getProgress(), right.getProgress());
+ })
+ .show();
+ final SeekBar barPlaybackSpeed = (SeekBar) dialog.findViewById(R.id.playback_speed);
+ final Button butDecSpeed = (Button) dialog.findViewById(R.id.butDecSpeed);
+ butDecSpeed.setOnClickListener(v -> {
+ if(controller != null && controller.canSetPlaybackSpeed()) {
+ barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 2);
+ } else {
+ VariableSpeedDialog.showGetPluginDialog(this);
+ }
+ });
+ final Button butIncSpeed = (Button) dialog.findViewById(R.id.butIncSpeed);
+ butIncSpeed.setOnClickListener(v -> {
+ if(controller != null && controller.canSetPlaybackSpeed()) {
+ barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 2);
+ } else {
+ VariableSpeedDialog.showGetPluginDialog(this);
+ }
+ });
+
+ final TextView txtvPlaybackSpeed = (TextView) dialog.findViewById(R.id.txtvPlaybackSpeed);
+ float currentSpeed = 1.0f;
+ try {
+ currentSpeed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
+ } catch (NumberFormatException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ UserPreferences.setPlaybackSpeed(String.valueOf(currentSpeed));
+ }
+
+ txtvPlaybackSpeed.setText(String.format("%.2fx", currentSpeed));
+ barPlaybackSpeed.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if(controller != null && controller.canSetPlaybackSpeed()) {
+ float playbackSpeed = (progress + 10) / 20.0f;
+ controller.setPlaybackSpeed(playbackSpeed);
+ String speed = String.format("%.2f", playbackSpeed);
+ UserPreferences.setPlaybackSpeed(speed);
+ txtvPlaybackSpeed.setText(speed + "x");
+ } else if(fromUser) {
+ float speed = Float.valueOf(UserPreferences.getPlaybackSpeed());
+ barPlaybackSpeed.post(() -> {
+ barPlaybackSpeed.setProgress((int) (20 * speed) - 10);
+ });
+ }
+ }
+
@Override
- public void onPositive(MaterialDialog dialog) {
- dialog.dismiss();
- controller.disableSleepTimer();
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ if(controller != null && !controller.canSetPlaybackSpeed()) {
+ VariableSpeedDialog.showGetPluginDialog(MediaplayerActivity.this);
+ }
}
@Override
- public void onNegative(MaterialDialog dialog) {
- dialog.dismiss();
+ public void onStopTrackingTouch(SeekBar seekBar) {
}
});
- stDialog.build().show();
- }
- break;
- case R.id.set_sleeptimer_item:
- if (controller.serviceAvailable()) {
- SleepTimerDialog td = new SleepTimerDialog(this) {
+ barPlaybackSpeed.setProgress((int) (20 * currentSpeed) - 10);
+
+ final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
+ barLeftVolume.setProgress(100);
+ final SeekBar barRightVolume = (SeekBar) dialog.findViewById(R.id.volume_right);
+ barRightVolume.setProgress(100);
+ final CheckBox stereoToMono = (CheckBox) dialog.findViewById(R.id.stereo_to_mono);
+ stereoToMono.setChecked(UserPreferences.stereoToMono());
+ if (controller != null && !controller.canDownmix()) {
+ stereoToMono.setEnabled(false);
+ String sonicOnly = getString(R.string.sonic_only);
+ stereoToMono.setText(stereoToMono.getText() + " [" + sonicOnly + "]");
+ }
+
+ barLeftVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
- public void onTimerSet(long millis, boolean shakeToReset, boolean vibrate) {
- controller.setSleepTimer(millis, shakeToReset, vibrate);
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ float leftVolume = 1.0f, rightVolume = 1.0f;
+ if (progress < 100) {
+ leftVolume = progress / 100.0f;
+ }
+ if (barRightVolume.getProgress() < 100) {
+ rightVolume = barRightVolume.getProgress() / 100.0f;
+ }
+ controller.setVolume(leftVolume, rightVolume);
}
- };
- td.createNewDialog().show();
- }
- break;
- case R.id.visit_website_item:
- Uri uri = Uri.parse(media.getWebsiteLink());
- startActivity(new Intent(Intent.ACTION_VIEW, uri));
- break;
- case R.id.support_item:
- if (media instanceof FeedMedia) {
- DBTasks.flattrItemIfLoggedIn(this, ((FeedMedia) media).getItem());
- }
- break;
- case R.id.share_link_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem());
- }
- break;
- case R.id.share_download_url_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem());
- }
- break;
- case R.id.share_link_with_position_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem(), true);
- }
- break;
- case R.id.share_download_url_with_position_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem(), true);
- }
- break;
- case R.id.skip_episode_item:
- sendBroadcast(new Intent(
- PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
- break;
- default:
- return false;
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ barRightVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ float leftVolume = 1.0f, rightVolume = 1.0f;
+ if (progress < 100) {
+ rightVolume = progress / 100.0f;
+ }
+ if (barLeftVolume.getProgress() < 100) {
+ leftVolume = barLeftVolume.getProgress() / 100.0f;
+ }
+ controller.setVolume(leftVolume, rightVolume);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ stereoToMono.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ UserPreferences.stereoToMono(isChecked);
+ if (controller != null) {
+ controller.setDownmix(isChecked);
+ }
+ });
+ break;
+ case R.id.visit_website_item:
+ Uri uri = Uri.parse(media.getWebsiteLink());
+ startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ break;
+ case R.id.support_item:
+ if (media instanceof FeedMedia) {
+ DBTasks.flattrItemIfLoggedIn(this, ((FeedMedia) media).getItem());
+ }
+ break;
+ case R.id.share_link_item:
+ if (media instanceof FeedMedia) {
+ ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem());
+ }
+ break;
+ case R.id.share_download_url_item:
+ if (media instanceof FeedMedia) {
+ ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem());
+ }
+ break;
+ case R.id.share_link_with_position_item:
+ if (media instanceof FeedMedia) {
+ ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem(), true);
+ }
+ break;
+ case R.id.share_download_url_with_position_item:
+ if (media instanceof FeedMedia) {
+ ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem(), true);
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+ } else {
+ return false;
}
- return true;
- } else {
- return false;
}
}
@@ -375,7 +584,9 @@ public abstract class MediaplayerActivity extends ActionBarActivity
super.onResume();
Log.d(TAG, "onResume()");
StorageUtils.checkStorageAvailability(this);
- controller.init();
+ if(controller != null) {
+ controller.init();
+ }
}
/**
@@ -389,26 +600,31 @@ public abstract class MediaplayerActivity extends ActionBarActivity
protected abstract void clearStatusMsg();
protected void onPositionObserverUpdate() {
- if (controller != null) {
- int currentPosition = controller.getPosition();
- int duration = controller.getDuration();
- Log.d(TAG, "currentPosition " + Converter
- .getDurationStringLong(currentPosition));
- if (currentPosition != PlaybackService.INVALID_TIME
- && duration != PlaybackService.INVALID_TIME
- && controller.getMedia() != null) {
- txtvPosition.setText(Converter
- .getDurationStringLong(currentPosition));
- txtvLength.setText(Converter.getDurationStringLong(duration));
- updateProgressbarPosition(currentPosition, duration);
- } else {
- Log.w(TAG, "Could not react to position observer update because of invalid time");
- }
+ if (controller == null || txtvPosition == null || txtvLength == null) {
+ return;
+ }
+ int currentPosition = controller.getPosition();
+ int duration = controller.getDuration();
+ Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition));
+ if (currentPosition == PlaybackService.INVALID_TIME ||
+ duration == PlaybackService.INVALID_TIME) {
+ Log.w(TAG, "Could not react to position observer update because of invalid time");
+ return;
}
+ txtvPosition.setText(Converter.getDurationStringLong(currentPosition));
+ if (showTimeLeft) {
+ txtvLength.setText("-" + Converter.getDurationStringLong(duration - currentPosition));
+ } else {
+ txtvLength.setText(Converter.getDurationStringLong(duration));
+ }
+ updateProgressbarPosition(currentPosition, duration);
}
private void updateProgressbarPosition(int position, int duration) {
- Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration +")");
+ Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")");
+ if(sbPosition == null) {
+ return;
+ }
float progress = ((float) position) / duration;
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
}
@@ -422,16 +638,23 @@ public abstract class MediaplayerActivity extends ActionBarActivity
protected boolean loadMediaInfo() {
Log.d(TAG, "loadMediaInfo()");
Playable media = controller.getMedia();
+ SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
+ showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
if (media != null) {
- txtvPosition.setText(Converter.getDurationStringLong((media
- .getPosition())));
-
- if (media.getDuration() != 0) {
- txtvLength.setText(Converter.getDurationStringLong(media
- .getDuration()));
- float progress = ((float) media.getPosition())
- / media.getDuration();
- sbPosition.setProgress((int) (progress * sbPosition.getMax()));
+ onPositionObserverUpdate();
+ checkFavorite();
+ if(butPlaybackSpeed != null) {
+ if (controller == null) {
+ butPlaybackSpeed.setVisibility(View.GONE);
+ } else {
+ butPlaybackSpeed.setVisibility(View.VISIBLE);
+ if (controller.canSetPlaybackSpeed()) {
+ ViewCompat.setAlpha(butPlaybackSpeed, 1.0f);
+ } else {
+ ViewCompat.setAlpha(butPlaybackSpeed, 0.5f);
+ }
+ }
+ updateButPlaybackSpeed();
}
return true;
} else {
@@ -443,18 +666,45 @@ public abstract class MediaplayerActivity extends ActionBarActivity
setContentView(getContentViewResourceId());
sbPosition = (SeekBar) findViewById(R.id.sbPosition);
txtvPosition = (TextView) 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);
- butPlay = (ImageButton) findViewById(R.id.butPlay);
+ txtvLength.setOnClickListener(v -> {
+ showTimeLeft = !showTimeLeft;
+ Playable media = controller.getMedia();
+ if (media == null) {
+ return;
+ }
+
+ String length;
+ if (showTimeLeft) {
+ length = "-" + Converter.getDurationStringLong(media.getDuration() - media.getPosition());
+ } else {
+ length = Converter.getDurationStringLong(media.getDuration());
+ }
+ txtvLength.setText(length);
+
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(PREF_SHOW_TIME_LEFT, showTimeLeft);
+ editor.apply();
+ Log.d("timeleft on click", showTimeLeft ? "true" : "false");
+ });
+
+ butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
butRev = (ImageButton) findViewById(R.id.butRev);
txtvRev = (TextView) findViewById(R.id.txtvRev);
- if(txtvRev != null) {
+ 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);
- if(txtvFF != null) {
+ if (txtvFF != null) {
txtvFF.setText(String.valueOf(UserPreferences.getFastFowardSecs()));
}
+ butSkip = (ImageButton) findViewById(R.id.butSkip);
// SEEKBAR SETUP
@@ -462,91 +712,123 @@ public abstract class MediaplayerActivity extends ActionBarActivity
// BUTTON SETUP
- butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
+ if(butPlaybackSpeed != null) {
+ butPlaybackSpeed.setOnClickListener(v -> {
+ if (controller == null) {
+ return;
+ }
+ if (controller.canSetPlaybackSpeed()) {
+ String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
+ String currentSpeed = UserPreferences.getPlaybackSpeed();
+
+ // Provide initial value in case the speed list has changed
+ // out from under us
+ // and our current speed isn't in the new list
+ String newSpeed;
+ if (availableSpeeds.length > 0) {
+ newSpeed = availableSpeeds[0];
+ } else {
+ newSpeed = "1.00";
+ }
- if (butFF != null) {
- butFF.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- int curr = controller.getPosition();
- controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
+ for (int i = 0; i < availableSpeeds.length; i++) {
+ if (availableSpeeds[i].equals(currentSpeed)) {
+ if (i == availableSpeeds.length - 1) {
+ newSpeed = availableSpeeds[0];
+ } else {
+ newSpeed = availableSpeeds[i + 1];
+ }
+ break;
+ }
+ }
+ UserPreferences.setPlaybackSpeed(newSpeed);
+ controller.setPlaybackSpeed(Float.parseFloat(newSpeed));
+ } else {
+ VariableSpeedDialog.showGetPluginDialog(this);
}
});
- butFF.setOnLongClickListener(new View.OnLongClickListener() {
+ butPlaybackSpeed.setOnLongClickListener(v -> {
+ VariableSpeedDialog.showDialog(this);
+ return true;
+ });
+ }
+
+ if (butRev != null) {
+ butRev.setOnClickListener(v -> {
+ int curr = controller.getPosition();
+ controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
+ });
+ butRev.setOnLongClickListener(new View.OnLongClickListener() {
int choice;
@Override
public boolean onLongClick(View v) {
int checked = 0;
- int rewindSecs = UserPreferences.getFastFowardSecs();
+ int rewindSecs = UserPreferences.getRewindSecs();
final int[] values = getResources().getIntArray(R.array.seek_delta_values);
final String[] choices = new String[values.length];
- for(int i=0; i < values.length; i++) {
+ for (int i = 0; i < values.length; i++) {
if (rewindSecs == values[i]) {
checked = i;
}
- choices[i] = String.valueOf(values[i]) + " "
- + getString(R.string.time_seconds);
+ choices[i] = String.valueOf(values[i]) + " " + getString(R.string.time_seconds);
}
choice = values[checked];
AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this);
- builder.setTitle(R.string.pref_fast_forward);
+ builder.setTitle(R.string.pref_rewind);
builder.setSingleChoiceItems(choices, checked,
(dialog, which) -> {
choice = values[which];
});
builder.setNegativeButton(R.string.cancel_label, null);
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
- UserPreferences.setPrefFastForwardSecs(choice);
- txtvFF.setText(String.valueOf(choice));
+ UserPreferences.setPrefRewindSecs(choice);
+ if(txtvRev != null){
+ txtvRev.setText(String.valueOf(choice));
+ }
});
builder.create().show();
return true;
}
});
}
- if (butRev != null) {
- butRev.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- int curr = controller.getPosition();
- controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
- }
+
+ butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
+
+ if (butFF != null) {
+ butFF.setOnClickListener(v -> {
+ int curr = controller.getPosition();
+ controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
});
- butRev.setOnLongClickListener(new View.OnLongClickListener() {
+ butFF.setOnLongClickListener(new View.OnLongClickListener() {
int choice;
@Override
public boolean onLongClick(View v) {
int checked = 0;
- int rewindSecs = UserPreferences.getRewindSecs();
+ int rewindSecs = UserPreferences.getFastFowardSecs();
final int[] values = getResources().getIntArray(R.array.seek_delta_values);
final String[] choices = new String[values.length];
- for(int i=0; i < values.length; i++) {
+ for (int i = 0; i < values.length; i++) {
if (rewindSecs == values[i]) {
checked = i;
}
- choices[i] = String.valueOf(values[i]) + " "
- + getString(R.string.time_seconds);
+ choices[i] = String.valueOf(values[i]) + " " + getString(R.string.time_seconds);
}
choice = values[checked];
AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this);
- builder.setTitle(R.string.pref_rewind);
+ builder.setTitle(R.string.pref_fast_forward);
builder.setSingleChoiceItems(choices, checked,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- choice = values[which];
- }
+ (dialog, which) -> {
+ choice = values[which];
});
builder.setNegativeButton(R.string.cancel_label, null);
- builder.setPositiveButton(R.string.confirm_label, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- UserPreferences.setPrefRewindSecs(choice);
- txtvRev.setText(String.valueOf(choice));
+ builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
+ UserPreferences.setPrefFastForwardSecs(choice);
+ if(txtvFF != null) {
+ txtvFF.setText(String.valueOf(choice));
}
});
builder.create().show();
@@ -555,6 +837,11 @@ public abstract class MediaplayerActivity extends ActionBarActivity
});
}
+ if (butSkip != null) {
+ butSkip.setOnClickListener(v -> {
+ sendBroadcast(new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
+ });
+ }
}
protected abstract int getContentViewResourceId();
@@ -562,15 +849,11 @@ public abstract class MediaplayerActivity extends ActionBarActivity
void handleError(int errorCode) {
final AlertDialog.Builder errorDialog = new AlertDialog.Builder(this);
errorDialog.setTitle(R.string.error_label);
- errorDialog
- .setMessage(MediaPlayerError.getErrorString(this, errorCode));
+ errorDialog.setMessage(MediaPlayerError.getErrorString(this, errorCode));
errorDialog.setNeutralButton("OK",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- finish();
- }
+ (dialog, which) -> {
+ dialog.dismiss();
+ finish();
}
);
errorDialog.create().show();
@@ -579,11 +862,21 @@ public abstract class MediaplayerActivity extends ActionBarActivity
float prog;
@Override
- public void onProgressChanged(SeekBar seekBar, int progress,
- boolean fromUser) {
- if (controller != null) {
- prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser,
- txtvPosition);
+ public void onProgressChanged (SeekBar seekBar,int progress, boolean fromUser) {
+ if (controller == null || txtvLength == null) {
+ return;
+ }
+ prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser, txtvPosition);
+ if (showTimeLeft && prog != 0) {
+ int duration = controller.getDuration();
+ String length = "-" + Converter.getDurationStringLong(duration - (int) (prog * duration));
+ txtvLength.setText(length);
+ }
+ }
+
+ private void updateButPlaybackSpeed() {
+ if (controller != null && butPlaybackSpeed != null) {
+ butPlaybackSpeed.setText(UserPreferences.getPlaybackSpeed() + "x");
}
}
@@ -601,4 +894,23 @@ public abstract class MediaplayerActivity extends ActionBarActivity
}
}
+ 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();
+ }
+ });
+ }
+ }
+ }
+
}
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 8c2b7f838..c7426c006 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -35,7 +35,6 @@ import org.jsoup.nodes.Document;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -258,7 +257,7 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
private void startFeedDownload(String url, String username, String password) {
Log.d(TAG, "Starting feed download");
url = URLChecker.prepareURL(url);
- feed = new Feed(url, new Date(0));
+ feed = new Feed(url, null);
if (username != null && password != null) {
feed.setPreferences(new FeedPreferences(0, false, FeedPreferences.AutoDeleteAction.GLOBAL, username, password));
}
@@ -410,7 +409,7 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
subscribeButton.setOnClickListener(v -> {
try {
- Feed f = new Feed(selectedDownloadUrl, new Date(0), feed.getTitle());
+ Feed f = new Feed(selectedDownloadUrl, null, feed.getTitle());
f.setPreferences(feed.getPreferences());
this.feed = f;
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 d974e0e1b..46dabec12 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
@@ -1,16 +1,27 @@
package de.danoeh.antennapod.activity;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Environment;
+import android.support.v4.app.ActivityCompat;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.asynctask.OpmlFeedQueuer;
-import de.danoeh.antennapod.asynctask.OpmlImportWorker;
-import de.danoeh.antennapod.core.opml.OpmlElement;
+import com.afollestad.materialdialogs.MaterialDialog;
+
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.asynctask.OpmlFeedQueuer;
+import de.danoeh.antennapod.asynctask.OpmlImportWorker;
+import de.danoeh.antennapod.core.opml.OpmlElement;
+import de.danoeh.antennapod.core.util.LangUtils;
+
/**
* Base activity for Opml Import - e.g. with code what to do afterwards
* */
@@ -19,22 +30,23 @@ public class OpmlImportBaseActivity extends ActionBarActivity {
private static final String TAG = "OpmlImportBaseActivity";
private OpmlImportWorker importWorker;
- /**
+ private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5;
+ private Uri uri;
+
+ /**
* Handles the choices made by the user in the OpmlFeedChooserActivity and
* starts the OpmlFeedQueuer if necessary.
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received result");
+ Log.d(TAG, "Received result");
if (resultCode == RESULT_CANCELED) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Activity was cancelled");
- if (finishWhenCanceled())
- finish();
+ Log.d(TAG, "Activity was cancelled");
+ if (finishWhenCanceled()) {
+ finish();
+ }
} else {
- int[] selected = data
- .getIntArrayExtra(OpmlFeedChooserActivity.EXTRA_SELECTED_ITEMS);
+ int[] selected = data.getIntArrayExtra(OpmlFeedChooserActivity.EXTRA_SELECTED_ITEMS);
if (selected != null && selected.length > 0) {
OpmlFeedQueuer queuer = new OpmlFeedQueuer(this, selected) {
@@ -50,35 +62,75 @@ public class OpmlImportBaseActivity extends ActionBarActivity {
};
queuer.executeAsync();
} else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "No items were selected");
+ Log.d(TAG, "No items were selected");
}
}
}
- /** Starts the import process. */
- protected void startImport(Reader reader) {
+ protected void importUri(Uri uri) {
+ this.uri = uri;
+ if(uri.toString().contains(Environment.getExternalStorageDirectory().toString())) {
+ int permission = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE);
+ if (permission != PackageManager.PERMISSION_GRANTED) {
+ requestPermission();
+ return;
+ }
+ }
+ startImport();
+ }
+
+ private void requestPermission() {
+ String[] permissions = { android.Manifest.permission.READ_EXTERNAL_STORAGE };
+ ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_READ_EXTERNAL_STORAGE);
+ }
- if (reader != null) {
- importWorker = new OpmlImportWorker(this, reader) {
+ @Override
+ public void onRequestPermissionsResult(int requestCode,
+ String[] permissions,
+ int[] grantResults) {
+ if (requestCode != PERMISSION_REQUEST_READ_EXTERNAL_STORAGE) {
+ return;
+ }
+ if (grantResults.length > 0 && ArrayUtils.contains(grantResults, PackageManager.PERMISSION_GRANTED)) {
+ startImport();
+ } else {
+ new MaterialDialog.Builder(this)
+ .content(R.string.opml_import_ask_read_permission)
+ .positiveText(android.R.string.ok)
+ .negativeText(R.string.cancel_label)
+ .onPositive((dialog, which) -> requestPermission())
+ .onNegative((dialog, which) -> finish())
+ .show();
+ }
+ }
+
+ /** Starts the import process. */
+ protected void startImport() {
+ try {
+ Reader mReader = new InputStreamReader(getContentResolver().openInputStream(uri), LangUtils.UTF_8);
+ importWorker = new OpmlImportWorker(this, mReader) {
@Override
protected void onPostExecute(ArrayList<OpmlElement> result) {
super.onPostExecute(result);
if (result != null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Parsing was successful");
+ Log.d(TAG, "Parsing was successful");
OpmlImportHolder.setReadElements(result);
startActivityForResult(new Intent(
OpmlImportBaseActivity.this,
OpmlFeedChooserActivity.class), 0);
} else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Parser error occurred");
+ Log.d(TAG, "Parser error occurred");
}
}
};
importWorker.executeAsync();
+ } catch (Exception e) {
+ Log.d(TAG, Log.getStackTraceString(e));
+ new MaterialDialog.Builder(this)
+ .content("Cannot open OPML file: " + e.getMessage())
+ .positiveText(android.R.string.ok)
+ .show();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java
index 46e5f0e8e..ab4b0d0ee 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java
@@ -2,25 +2,14 @@ package de.danoeh.antennapod.activity;
import android.net.Uri;
import android.os.Bundle;
-import android.support.v7.app.AlertDialog;
-import android.util.Log;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.LangUtils;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.net.URL;
/** Lets the user start the OPML-import process. */
public class OpmlImportFromIntentActivity extends OpmlImportBaseActivity {
private static final String TAG = "OpmlImportFromIntentAct";
-
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getTheme());
@@ -28,15 +17,8 @@ public class OpmlImportFromIntentActivity extends OpmlImportBaseActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- try {
- Uri uri = getIntent().getData();
-
- Reader mReader = new InputStreamReader(getContentResolver().openInputStream(uri), LangUtils.UTF_8);
- startImport(mReader);
- } catch (Exception e) {
- new AlertDialog.Builder(this).setMessage("Cannot open XML - Reason: " + e.getMessage()).show();
- }
-
+ Uri uri = getIntent().getData();
+ importUri(uri);
}
@Override
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 6e3991739..15d97cc2c 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
@@ -11,16 +11,9 @@ import android.view.View;
import android.widget.Button;
import android.widget.TextView;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.LangUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
/**
@@ -114,19 +107,6 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
}
}
- private void startImport(File file) {
- Reader mReader = null;
- try {
- mReader = new InputStreamReader(new FileInputStream(file),
- LangUtils.UTF_8);
- Log.d(TAG, "Parsing " + file.toString());
- startImport(mReader);
- } catch (FileNotFoundException e) {
- Log.d(TAG, "File not found which really should be there");
- // this should never happen as it is a file we have just chosen
- }
- }
-
/*
* Creates an implicit intent to launch a file manager which lets
* the user choose a specific OPML-file to import from.
@@ -155,13 +135,7 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == CHOOSE_OPML_FILE) {
Uri uri = data.getData();
-
- try {
- Reader mReader = new InputStreamReader(getContentResolver().openInputStream(uri), LangUtils.UTF_8);
- startImport(mReader);
- } catch (FileNotFoundException e) {
- Log.d(TAG, "File not found");
- }
+ importUri(uri);
}
}
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 7f975b3c8..e980764ec 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
@@ -1,30 +1,109 @@
package de.danoeh.antennapod.activity;
+import android.Manifest;
+import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.Bundle;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
+import android.widget.Button;
+
+import com.afollestad.materialdialogs.MaterialDialog;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
-import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.StorageUtils;
/** Is show if there is now external storage available. */
-public class StorageErrorActivity extends ActionBarActivity {
+public class StorageErrorActivity extends AppCompatActivity {
+
private static final String TAG = "StorageErrorActivity";
+ private static final String[] EXTERNAL_STORAGE_PERMISSIONS = {
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE };
+ private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 42;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
setContentView(R.layout.storage_error);
- }
+
+ Button btnChooseDataFolder = (Button) 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) {
+ showChooseDataFolderDialog();
+ } else {
+ openDirectoryChooser();
+ }
+ });
+ if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
+ int readPermission = ActivityCompat.checkSelfPermission(this,
+ Manifest.permission.READ_EXTERNAL_STORAGE);
+ int writePermission = ActivityCompat.checkSelfPermission(this,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ if (readPermission != PackageManager.PERMISSION_GRANTED ||
+ writePermission != PackageManager.PERMISSION_GRANTED) {
+ requestPermission();
+ }
+ }
+ }
+
+ private void requestPermission() {
+ ActivityCompat.requestPermissions(this, EXTERNAL_STORAGE_PERMISSIONS,
+ PERMISSION_REQUEST_EXTERNAL_STORAGE);
+ }
+
+ private void openDirectoryChooser() {
+ Intent intent = new Intent(this, DirectoryChooserActivity.class);
+ startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode,
+ String[] permissions,
+ int[] grantResults) {
+ if (requestCode != PERMISSION_REQUEST_EXTERNAL_STORAGE || grantResults.length != 2) {
+ return;
+ }
+ if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||
+ grantResults[1] != PackageManager.PERMISSION_GRANTED) {
+ new MaterialDialog.Builder(this)
+ .content(R.string.choose_data_directory_permission_rationale)
+ .positiveText(android.R.string.ok)
+ .onPositive((dialog, which) -> requestPermission())
+ .onNegative((dialog, which) -> finish())
+ .show();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (StorageUtils.storageAvailable()) {
+ leaveErrorState();
+ } else {
+ registerReceiver(mediaUpdate, new IntentFilter(Intent.ACTION_MEDIA_MOUNTED));
+ }
+ }
@Override
protected void onPause() {
@@ -32,18 +111,102 @@ public class StorageErrorActivity extends ActionBarActivity {
try {
unregisterReceiver(mediaUpdate);
} catch (IllegalArgumentException e) {
-
+ Log.e(TAG, Log.getStackTraceString(e));
}
}
- @Override
- protected void onResume() {
- super.onResume();
- if (StorageUtils.storageAvailable(this)) {
- leaveErrorState();
- } else {
- registerReceiver(mediaUpdate, new IntentFilter(
- Intent.ACTION_MEDIA_MOUNTED));
+ // see PreferenceController.showChooseDataFolderDialog()
+ private void showChooseDataFolderDialog() {
+ File dataFolder = UserPreferences.getDataFolder(null);
+ if(dataFolder == null) {
+ new MaterialDialog.Builder(this)
+ .title(R.string.error_label)
+ .content(R.string.external_storage_error_msg)
+ .neutralText(android.R.string.ok)
+ .show();
+ return;
+ }
+ String dataFolderPath = dataFolder.getAbsolutePath();
+ int selectedIndex = -1;
+ File[] mediaDirs = ContextCompat.getExternalFilesDirs(this, null);
+ List<String> folders = new ArrayList<>(mediaDirs.length);
+ List<CharSequence> choices = new ArrayList<>(mediaDirs.length);
+ for(int i=0; i < mediaDirs.length; i++) {
+ if(mediaDirs[i] == null) {
+ continue;
+ }
+ String path = mediaDirs[i].getAbsolutePath();
+ folders.add(path);
+ if(dataFolderPath.equals(path)) {
+ selectedIndex = i;
+ }
+ int index = path.indexOf("Android");
+ String choice;
+ if(index >= 0) {
+ choice = path.substring(0, index);
+ } else {
+ choice = path;
+ }
+ long bytes = StorageUtils.getFreeSpaceAvailable(path);
+ String freeSpace = String.format(getString(R.string.free_space_label),
+ Converter.byteToString(bytes));
+ choices.add(Html.fromHtml("<html><small>" + choice + " [" + freeSpace + "]"
+ + "</small></html>"));
+ }
+ if(choices.size() == 0) {
+ new MaterialDialog.Builder(this)
+ .title(R.string.error_label)
+ .content(R.string.external_storage_error_msg)
+ .neutralText(android.R.string.ok)
+ .show();
+ return;
+ }
+ MaterialDialog dialog = new MaterialDialog.Builder(this)
+ .title(R.string.choose_data_directory)
+ .content(R.string.choose_data_directory_message)
+ .items(choices.toArray(new CharSequence[choices.size()]))
+ .itemsCallbackSingleChoice(selectedIndex, (dialog1, itemView, which, text) -> {
+ String folder = folders.get(which);
+ UserPreferences.setDataFolder(folder);
+ leaveErrorState();
+ return true;
+ })
+ .negativeText(R.string.cancel_label)
+ .cancelable(true)
+ .build();
+ dialog.show();
+ }
+
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == Activity.RESULT_OK &&
+ requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
+ String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
+
+ File path;
+ if (dir != null) {
+ path = new File(dir);
+ } else {
+ path = getExternalFilesDir(null);
+ }
+ String message = null;
+ if(!path.exists()) {
+ message = String.format(getString(R.string.folder_does_not_exist_error), dir);
+ } else if(!path.canRead()) {
+ message = String.format(getString(R.string.folder_not_readable_error), dir);
+ } else if(!path.canWrite()) {
+ message = String.format(getString(R.string.folder_not_writable_error), dir);
+ }
+
+ if(message == null) {
+ Log.d(TAG, "Setting data folder: " + dir);
+ UserPreferences.setDataFolder(dir);
+ leaveErrorState();
+ } else {
+ AlertDialog.Builder ab = new AlertDialog.Builder(this);
+ ab.setMessage(message);
+ ab.setPositiveButton(android.R.string.ok, null);
+ ab.show();
+ }
}
}
@@ -58,13 +221,10 @@ public class StorageErrorActivity extends ActionBarActivity {
public void onReceive(Context context, Intent intent) {
if (TextUtils.equals(intent.getAction(), Intent.ACTION_MEDIA_MOUNTED)) {
if (intent.getBooleanExtra("read-only", true)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Media was mounted; Finishing activity");
+ Log.d(TAG, "Media was mounted; Finishing activity");
leaveErrorState();
} else {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Media seemed to have been mounted read only");
+ Log.d(TAG, "Media seemed to have been mounted read only");
}
}
}
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 60eb290b5..ee459dbc6 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -3,9 +3,9 @@ package de.danoeh.antennapod.activity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
import android.support.v4.view.WindowCompat;
import android.util.Log;
import android.util.Pair;
@@ -19,7 +19,9 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.SeekBar;
-import de.danoeh.antennapod.BuildConfig;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
@@ -39,8 +41,12 @@ public class VideoplayerActivity extends MediaplayerActivity {
*/
private boolean videoControlsShowing = true;
private boolean videoSurfaceCreated = false;
- private VideoControlsHider videoControlsToggler;
+ private VideoControlsHider videoControlsHider = new VideoControlsHider(this);
+
+ private AtomicBoolean isSetup = new AtomicBoolean(false);
+
+ private LinearLayout controls;
private LinearLayout videoOverlay;
private AspectRatioVideoView videoview;
private ProgressBar progressIndicator;
@@ -61,25 +67,12 @@ public class VideoplayerActivity extends MediaplayerActivity {
}
@Override
- protected void onPause() {
- super.onPause();
- if (videoControlsToggler != null) {
- videoControlsToggler.cancel(true);
- }
- if (controller != null && controller.getStatus() == PlayerStatus.PLAYING) {
- controller.pause();
- }
- }
-
- @Override
protected void onResume() {
super.onResume();
if (getIntent().getAction() != null
&& getIntent().getAction().equals(Intent.ACTION_VIEW)) {
Intent intent = getIntent();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received VIEW intent: "
- + intent.getData().getPath());
+ 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);
@@ -94,6 +87,22 @@ public class VideoplayerActivity extends MediaplayerActivity {
}
@Override
+ protected void onPause() {
+ super.onPause();
+ videoControlsHider.stop();
+ if (controller != null && controller.getStatus() == PlayerStatus.PLAYING) {
+ controller.pause();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ videoControlsHider.stop();
+ videoControlsHider = null;
+ }
+
+ @Override
protected boolean loadMediaInfo() {
if (!super.loadMediaInfo()) {
return false;
@@ -104,14 +113,17 @@ public class VideoplayerActivity extends MediaplayerActivity {
getSupportActionBar().setTitle(media.getFeedTitle());
return true;
}
-
return false;
}
@Override
protected void setupGUI() {
+ 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);
@@ -133,14 +145,11 @@ public class VideoplayerActivity extends MediaplayerActivity {
@Override
protected void onAwaitingVideoSurface() {
if (videoSurfaceCreated) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Videosurface already created, setting videosurface now");
+ Log.d(TAG, "Videosurface already created, setting videosurface now");
Pair<Integer, Integer> videoSize = controller.getVideoSize();
if (videoSize != null && videoSize.first > 0 && videoSize.second > 0) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Width,height of video: " + videoSize.first + ", " + videoSize.second);
+ 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");
@@ -156,7 +165,6 @@ public class VideoplayerActivity extends MediaplayerActivity {
} else {
progressIndicator.setVisibility(View.INVISIBLE);
}
-
}
@Override
@@ -164,38 +172,23 @@ public class VideoplayerActivity extends MediaplayerActivity {
progressIndicator.setVisibility(View.INVISIBLE);
}
- View.OnTouchListener onVideoviewTouched = new View.OnTouchListener() {
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- if (videoControlsToggler != null) {
- videoControlsToggler.cancel(true);
- }
- toggleVideoControlsVisibility();
- if (videoControlsShowing) {
- setupVideoControlsToggler();
- }
-
- return true;
- } else {
- return false;
+ View.OnTouchListener onVideoviewTouched = (v, event) -> {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ videoControlsHider.stop();
+ toggleVideoControlsVisibility();
+ if (videoControlsShowing) {
+ setupVideoControlsToggler();
}
+ return true;
+ } else {
+ return false;
}
};
@SuppressLint("NewApi")
void setupVideoControlsToggler() {
- if (videoControlsToggler != null) {
- videoControlsToggler.cancel(true);
- }
- videoControlsToggler = new VideoControlsHider();
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- videoControlsToggler
- .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- videoControlsToggler.execute();
- }
+ videoControlsHider.stop();
+ videoControlsHider.start();
}
private void toggleVideoControlsVisibility() {
@@ -209,46 +202,6 @@ public class VideoplayerActivity extends MediaplayerActivity {
videoControlsShowing = !videoControlsShowing;
}
- /**
- * Hides the videocontrols after a certain period of time.
- */
- public class VideoControlsHider extends AsyncTask<Void, Void, Void> {
- @Override
- protected void onCancelled() {
- videoControlsToggler = null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- videoControlsToggler = null;
- }
-
- private static final int WAITING_INTERVALL = 5000;
- private static final String TAG = "VideoControlsToggler";
-
- @Override
- protected void onProgressUpdate(Void... values) {
- if (videoControlsShowing) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Hiding video controls");
- getSupportActionBar().hide();
- hideVideoControls();
- videoControlsShowing = false;
- }
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- try {
- Thread.sleep(WAITING_INTERVALL);
- } catch (InterruptedException e) {
- return null;
- }
- publishProgress();
- return null;
- }
-
- }
private final SurfaceHolder.Callback surfaceHolderCallback = new SurfaceHolder.Callback() {
@Override
@@ -259,15 +212,13 @@ public class VideoplayerActivity extends MediaplayerActivity {
@Override
public void surfaceCreated(SurfaceHolder holder) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Videoview holder created");
+ Log.d(TAG, "Videoview holder created");
videoSurfaceCreated = true;
if (controller.getStatus() == PlayerStatus.PLAYING) {
if (controller.serviceAvailable()) {
controller.setVideoSurface(holder);
} else {
- Log.e(TAG,
- "Could'nt attach surface to mediaplayer - reference to service was null");
+ Log.e(TAG, "Could'nt attach surface to mediaplayer - reference to service was null");
}
}
@@ -275,8 +226,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Videosurface was destroyed");
+ Log.d(TAG, "Videosurface was destroyed");
videoSurfaceCreated = false;
controller.notifyVideoSurfaceAbandoned();
}
@@ -286,9 +236,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
@Override
protected void onReloadNotification(int notificationCode) {
if (notificationCode == PlaybackService.EXTRA_CODE_AUDIO) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "ReloadNotification received, switching to Audioplayer now");
+ Log.d(TAG, "ReloadNotification received, switching to Audioplayer now");
finish();
startActivity(new Intent(this, AudioplayerActivity.class));
}
@@ -297,9 +245,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
super.onStartTrackingTouch(seekBar);
- if (videoControlsToggler != null) {
- videoControlsToggler.cancel(true);
- }
+ videoControlsHider.stop();
}
@Override
@@ -321,12 +267,11 @@ public class VideoplayerActivity extends MediaplayerActivity {
@SuppressLint("NewApi")
private void showVideoControls() {
videoOverlay.setVisibility(View.VISIBLE);
- butPlay.setVisibility(View.VISIBLE);
- final Animation animation = AnimationUtils.loadAnimation(this,
- R.anim.fade_in);
+ controls.setVisibility(View.VISIBLE);
+ final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_in);
if (animation != null) {
videoOverlay.startAnimation(animation);
- butPlay.startAnimation(animation);
+ controls.startAnimation(animation);
}
if (Build.VERSION.SDK_INT >= 14) {
videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
@@ -335,11 +280,10 @@ public class VideoplayerActivity extends MediaplayerActivity {
@SuppressLint("NewApi")
private void hideVideoControls() {
- final Animation animation = AnimationUtils.loadAnimation(this,
- R.anim.fade_out);
+ final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_out);
if (animation != null) {
videoOverlay.startAnimation(animation);
- butPlay.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;
@@ -348,7 +292,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
videoOverlay.setFitsSystemWindows(true);
}
videoOverlay.setVisibility(View.GONE);
- butPlay.setVisibility(View.GONE);
+ controls.setVisibility(View.GONE);
}
@Override
@@ -356,7 +300,6 @@ public class VideoplayerActivity extends MediaplayerActivity {
return R.layout.videoplayer_activity;
}
-
@Override
protected void setScreenOn(boolean enable) {
super.setScreenOn(enable);
@@ -366,4 +309,38 @@ public class VideoplayerActivity extends MediaplayerActivity {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
+
+ private static class VideoControlsHider extends Handler {
+
+ private static final int DELAY = 5000;
+
+ private WeakReference<VideoplayerActivity> activity;
+
+ public VideoControlsHider(VideoplayerActivity activity) {
+ this.activity = new WeakReference<>(activity);
+ }
+
+ private final Runnable hideVideoControls = () -> {
+ VideoplayerActivity vpa = activity.get();
+ if(vpa == null) {
+ return;
+ }
+ if (vpa.videoControlsShowing) {
+ Log.d(TAG, "Hiding video controls");
+ vpa.getSupportActionBar().hide();
+ vpa.hideVideoControls();
+ vpa.videoControlsShowing = false;
+ }
+ };
+
+ public void start() {
+ this.postDelayed(hideVideoControls, DELAY);
+ }
+
+ public void stop() {
+ this.removeCallbacks(hideVideoControls);
+ }
+
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java
index 1ea7daaa3..935a0dcd4 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java
@@ -47,9 +47,10 @@ public class AdapterUtils {
- media.getPosition()));
}
} else if (!media.isDownloaded()) {
+ Log.d(TAG, "size: " + media.getSize());
if (media.getSize() > 0) {
txtvPos.setText(Converter.byteToString(media.getSize()));
- } else if(false == media.checkedOnSizeButUnknown()) {
+ } else if(NetworkUtils.isDownloadAllowed() && false == media.checkedOnSizeButUnknown()) {
txtvPos.setText("{fa-spinner}");
Iconify.addIcons(txtvPos);
NetworkUtils.getFeedMediaSizeObservable(media)
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
index f120aa1d5..6d4fc6f1e 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
@@ -2,9 +2,9 @@ package de.danoeh.antennapod.adapter;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
-import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@@ -15,7 +15,6 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -36,6 +35,8 @@ 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.fragment.ItemFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
@@ -70,11 +71,11 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
this.showOnlyNewEpisodes = showOnlyNewEpisodes;
if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
- playingBackGroundColor = mainActivity.getResources().getColor(R.color.highlight_dark);
+ playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_dark);
} else {
- playingBackGroundColor = mainActivity.getResources().getColor(R.color.highlight_light);
+ playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_light);
}
- normalBackGroundColor = mainActivity.getResources().getColor(android.R.color.transparent);
+ normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent);
}
@Override
@@ -118,8 +119,8 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.placeholder.setVisibility(View.VISIBLE);
holder.placeholder.setText(item.getFeed().getTitle());
holder.title.setText(item.getTitle());
- holder.pubDate.setText(DateUtils.formatDateTime(mainActivityRef.get(),
- item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL));
+ String pubDateStr = DateUtils.formatAbbrev(mainActivityRef.get(), item.getPubDate());
+ holder.pubDate.setText(pubDateStr);
if (showOnlyNewEpisodes || false == item.isNew()) {
holder.statusUnread.setVisibility(View.INVISIBLE);
} else {
@@ -134,7 +135,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
} else if (media.getSize() > 0) {
holder.txtvDuration.setText(Converter.byteToString(media.getSize()));
- } else if(false == media.checkedOnSizeButUnknown()) {
+ } else if(NetworkUtils.isDownloadAllowed() && false == media.checkedOnSizeButUnknown()) {
holder.txtvDuration.setText("{fa-spinner}");
Iconify.addIcons(holder.txtvDuration);
NetworkUtils.getFeedMediaSizeObservable(media)
@@ -329,8 +330,8 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
item1.setVisible(visible);
}
};
- FeedItemMenuHandler.onPrepareMenu(mainActivityRef.get(), contextMenuInterface, item, true,
- null);
+ FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true,
+ itemAccess.getQueueIds(), itemAccess.getFavoritesIds());
}
}
@@ -345,6 +346,10 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
boolean isInQueue(FeedItem item);
+ LongList getQueueIds();
+
+ LongList getFavoritesIds();
+
}
/**
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java
deleted file mode 100644
index cf0532cf1..000000000
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java
+++ /dev/null
@@ -1,199 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import android.content.Context;
-import android.text.Layout;
-import android.text.Selection;
-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;
-import android.view.View.OnTouchListener;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ImageButton;
-import android.widget.TextView;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.util.ChapterUtils;
-import de.danoeh.antennapod.core.util.Converter;
-import de.danoeh.antennapod.core.util.playback.Playable;
-
-import java.util.List;
-
-public class ChapterListAdapter extends ArrayAdapter<Chapter> {
-
- private static final String TAG = "ChapterListAdapter";
-
- private List<Chapter> chapters;
- private Playable media;
-
- private int defaultTextColor;
- private final Callback callback;
-
- public ChapterListAdapter(Context context, int textViewResourceId,
- List<Chapter> objects, Playable media, Callback callback) {
- super(context, textViewResourceId, objects);
- this.chapters = objects;
- this.media = media;
- this.callback = callback;
- }
-
- @Override
- public View getView(final int position, View convertView, ViewGroup parent) {
- Holder holder;
-
- Chapter sc = getItem(position);
-
- // Inflate Layout
- if (convertView == null) {
- holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- convertView = inflater.inflate(R.layout.simplechapter_item, parent, false);
- holder.title = (TextView) 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.butPlayChapter = (ImageButton) convertView.findViewById(R.id.butPlayChapter);
- convertView.setTag(holder);
- } else {
- holder = (Holder) convertView.getTag();
-
- }
-
- holder.title.setText(sc.getTitle());
- holder.start.setText(Converter.getDurationStringLong((int) sc
- .getStart()));
- if (sc.getLink() != null) {
- holder.link.setVisibility(View.VISIBLE);
- holder.link.setText(sc.getLink());
- Linkify.addLinks(holder.link, Linkify.WEB_URLS);
- } else {
- holder.link.setVisibility(View.GONE);
- }
- holder.link.setMovementMethod(null);
- holder.link.setOnTouchListener(new OnTouchListener() {
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- // from
- // http://stackoverflow.com/questions/7236840/android-textview-linkify-intercepts-with-parent-view-gestures
- TextView widget = (TextView) v;
- Object text = widget.getText();
- if (text instanceof Spanned) {
- Spannable buffer = (Spannable) text;
-
- int action = event.getAction();
-
- if (action == MotionEvent.ACTION_UP
- || action == MotionEvent.ACTION_DOWN) {
- int x = (int) event.getX();
- int y = (int) event.getY();
-
- x -= widget.getTotalPaddingLeft();
- y -= widget.getTotalPaddingTop();
-
- x += widget.getScrollX();
- y += widget.getScrollY();
-
- Layout layout = widget.getLayout();
- int line = layout.getLineForVertical(y);
- int off = layout.getOffsetForHorizontal(line, x);
-
- ClickableSpan[] link = buffer.getSpans(off, off,
- ClickableSpan.class);
-
- if (link.length != 0) {
- if (action == MotionEvent.ACTION_UP) {
- link[0].onClick(widget);
- } else if (action == MotionEvent.ACTION_DOWN) {
- Selection.setSelection(buffer,
- buffer.getSpanStart(link[0]),
- buffer.getSpanEnd(link[0]));
- }
- return true;
- }
- }
-
- }
-
- return false;
-
- }
- });
- holder.butPlayChapter.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (callback != null) {
- callback.onPlayChapterButtonClicked(position);
- }
- }
- });
- Chapter current = ChapterUtils.getCurrentChapter(media);
- if (current != null) {
- if (current == sc) {
- holder.title.setTextColor(convertView.getResources().getColor(
- R.color.holo_blue_light));
- holder.start.setTextColor(convertView.getResources().getColor(
- R.color.holo_blue_light));
- } else {
- holder.title.setTextColor(defaultTextColor);
- holder.start.setTextColor(defaultTextColor);
- }
- } else {
- Log.w(TAG, "Could not find out what the current chapter is.");
- }
-
- return convertView;
- }
-
- static class Holder {
- TextView title;
- TextView start;
- TextView link;
- ImageButton butPlayChapter;
- }
-
- @Override
- public int getCount() {
- // ignore invalid chapters
- int counter = 0;
- if (chapters != null) {
- for (Chapter chapter : chapters) {
- if (!ignoreChapter(chapter)) {
- counter++;
- }
- }
- }
- return counter;
- }
-
- private boolean ignoreChapter(Chapter c) {
- return media.getDuration() > 0 && media.getDuration() < c.getStart();
- }
-
- @Override
- public Chapter getItem(int position) {
- int i = 0;
- for (Chapter chapter : chapters) {
- if (!ignoreChapter(chapter)) {
- if (i == position) {
- return chapter;
- } else {
- i++;
- }
- }
- }
- return super.getItem(position);
- }
-
- public static interface Callback {
- public void onPlayChapterButtonClicked(int position);
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
new file mode 100644
index 000000000..8bde1097b
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
@@ -0,0 +1,199 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.support.v4.content.ContextCompat;
+import android.text.Layout;
+import android.text.Selection;
+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;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
+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.playback.Playable;
+
+public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
+
+ private static final String TAG = "ChapterListAdapter";
+
+ private Playable media;
+
+ private int defaultTextColor;
+ private final Callback callback;
+
+ public ChaptersListAdapter(Context context, int textViewResourceId, Callback callback) {
+ super(context, textViewResourceId);
+ this.callback = callback;
+ }
+
+ public void setMedia(Playable media) {
+ this.media = media;
+ }
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+ Holder holder;
+
+ Chapter sc = getItem(position);
+
+ // Inflate Layout
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ convertView = inflater.inflate(R.layout.simplechapter_item, parent, false);
+ holder.view = convertView;
+ holder.title = (TextView) 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.butPlayChapter = (ImageButton) convertView.findViewById(R.id.butPlayChapter);
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+
+ }
+
+ holder.title.setText(sc.getTitle());
+ holder.start.setText(Converter.getDurationStringLong((int) sc
+ .getStart()));
+ if (sc.getLink() != null) {
+ holder.link.setVisibility(View.VISIBLE);
+ holder.link.setText(sc.getLink());
+ Linkify.addLinks(holder.link, Linkify.WEB_URLS);
+ } else {
+ holder.link.setVisibility(View.GONE);
+ }
+ holder.link.setMovementMethod(null);
+ holder.link.setOnTouchListener((v, event) -> {
+ // from
+ // http://stackoverflow.com/questions/7236840/android-textview-linkify-intercepts-with-parent-view-gestures
+ TextView widget = (TextView) v;
+ Object text = widget.getText();
+ if (text instanceof Spanned) {
+ Spannable buffer = (Spannable) text;
+
+ int action = event.getAction();
+
+ if (action == MotionEvent.ACTION_UP
+ || action == MotionEvent.ACTION_DOWN) {
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+
+ x -= widget.getTotalPaddingLeft();
+ y -= widget.getTotalPaddingTop();
+
+ x += widget.getScrollX();
+ y += widget.getScrollY();
+
+ Layout layout = widget.getLayout();
+ int line = layout.getLineForVertical(y);
+ int off = layout.getOffsetForHorizontal(line, x);
+
+ ClickableSpan[] link = buffer.getSpans(off, off,
+ ClickableSpan.class);
+
+ if (link.length != 0) {
+ if (action == MotionEvent.ACTION_UP) {
+ link[0].onClick(widget);
+ } else if (action == MotionEvent.ACTION_DOWN) {
+ Selection.setSelection(buffer,
+ buffer.getSpanStart(link[0]),
+ buffer.getSpanEnd(link[0]));
+ }
+ return true;
+ }
+ }
+
+ }
+
+ return false;
+
+ });
+ holder.butPlayChapter.setOnClickListener(v -> {
+ if (callback != null) {
+ 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);
+ }
+ } else {
+ Log.w(TAG, "Could not find out what the current chapter is.");
+ }
+
+ return convertView;
+ }
+
+ static class Holder {
+ View view;
+ TextView title;
+ TextView start;
+ TextView link;
+ ImageButton butPlayChapter;
+ }
+
+ @Override
+ public int getCount() {
+ if(media == null || media.getChapters() == null) {
+ return 0;
+ }
+ // ignore invalid chapters
+ int counter = 0;
+ for (Chapter chapter : media.getChapters()) {
+ if (!ignoreChapter(chapter)) {
+ counter++;
+ }
+ }
+ return counter;
+ }
+
+ private boolean ignoreChapter(Chapter c) {
+ return media.getDuration() > 0 && media.getDuration() < c.getStart();
+ }
+
+ @Override
+ public Chapter getItem(int position) {
+ int i = 0;
+ for (Chapter chapter : media.getChapters()) {
+ if (!ignoreChapter(chapter)) {
+ if (i == position) {
+ return chapter;
+ } else {
+ i++;
+ }
+ }
+ }
+ return super.getItem(position);
+ }
+
+ public interface Callback {
+ void onPlayChapterButtonClicked(int position);
+ }
+
+}
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 efdf1a3c9..469a807e1 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
@@ -6,6 +6,8 @@ import android.content.Intent;
import android.support.v7.app.AlertDialog;
import android.widget.Toast;
+import com.afollestad.materialdialogs.MaterialDialog;
+
import org.apache.commons.lang3.Validate;
import de.danoeh.antennapod.R;
@@ -99,40 +101,33 @@ public class DefaultActionButtonCallback implements ActionButtonCallback {
}
private void confirmMobileDownload(final Context context, final FeedItem item) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
builder
- .setTitle(R.string.confirm_mobile_download_dialog_title)
- .setMessage(context.getText(R.string.confirm_mobile_download_dialog_message))
- .setPositiveButton(context.getText(R.string.confirm_mobile_download_dialog_enable_temporarily),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- allowMobileDownloadsTimestamp = System.currentTimeMillis();
- try {
- DBTasks.downloadFeedItems(context, item);
- Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage());
- }
- }
- });
+ .title(R.string.confirm_mobile_download_dialog_title)
+ .content(R.string.confirm_mobile_download_dialog_message)
+ .positiveText(context.getText(R.string.confirm_mobile_download_dialog_enable_temporarily))
+ .onPositive((dialog, which) -> {
+ allowMobileDownloadsTimestamp = System.currentTimeMillis();
+ try {
+ DBTasks.downloadFeedItems(context, item);
+ Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage());
+ }
+ });
LongList queueIds = DBReader.getQueueIDList();
if(!queueIds.contains(item.getId())) {
- builder.setNeutralButton(context.getText(R.string.confirm_mobile_download_dialog_only_add_to_queue),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- onlyAddToQueueTimeStamp = System.currentTimeMillis();
- DBWriter.addQueueItem(context, item);
- Toast.makeText(context, R.string.added_to_queue_label, Toast.LENGTH_SHORT).show();
- }
- })
- .setMessage(context.getText(R.string.confirm_mobile_download_dialog_message_not_in_queue));
- } else {
- builder.setMessage(context.getText(R.string.confirm_mobile_download_dialog_message));
+ builder
+ .content(R.string.confirm_mobile_download_dialog_message_not_in_queue)
+ .neutralText(R.string.confirm_mobile_download_dialog_only_add_to_queue)
+ .onNeutral((dialog, which) -> {
+ onlyAddToQueueTimeStamp = System.currentTimeMillis();
+ DBWriter.addQueueItem(context, item);
+ Toast.makeText(context, R.string.added_to_queue_label, Toast.LENGTH_SHORT).show();
+ });
}
- builder.create()
- .show();
+ builder.show();
}
+
}
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 9d7a509cf..9ff80424c 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import android.support.v4.content.ContextCompat;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -13,8 +14,6 @@ import android.widget.Toast;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconButton;
-import java.util.Date;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.Feed;
@@ -76,14 +75,14 @@ public class DownloadLogAdapter extends BaseAdapter {
status.getCompletionDate().getTime(),
System.currentTimeMillis(), 0, 0));
if (status.isSuccessful()) {
- holder.icon.setTextColor(convertView.getResources().getColor(
+ holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(),
R.color.download_success_green));
holder.icon.setText("{fa-check-circle}");
Iconify.addIcons(holder.icon);
holder.retry.setVisibility(View.GONE);
holder.reason.setVisibility(View.GONE);
} else {
- holder.icon.setTextColor(convertView.getResources().getColor(
+ holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(),
R.color.download_failed_red));
holder.icon.setText("{fa-times-circle}");
Iconify.addIcons(holder.icon);
@@ -123,9 +122,8 @@ public class DownloadLogAdapter extends BaseAdapter {
if(holder.typeId == Feed.FEEDFILETYPE_FEED) {
Feed feed = DBReader.getFeed(holder.id);
if (feed != null) {
- feed.setLastUpdate(new Date(0)); // force refresh
try {
- DBTasks.refreshFeed(context, feed);
+ DBTasks.forceRefreshFeed(context, feed);
} catch (DownloadRequestException e) {
e.printStackTrace();
}
@@ -134,12 +132,16 @@ public class DownloadLogAdapter extends BaseAdapter {
}
} else if(holder.typeId == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
FeedMedia media = DBReader.getFeedMedia(holder.id);
- try {
- DBTasks.downloadFeedItems(context, media.getItem());
- Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage());
+ if (media != null) {
+ try {
+ DBTasks.downloadFeedItems(context, media.getItem());
+ Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage());
+ }
+ } else {
+ Log.wtf(TAG, "Could not find media for id: " + holder.id);
}
} else {
Log.wtf(TAG, "Unexpected type id: " + holder.typeId);
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 2b1eccea5..53dedd496 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
@@ -1,7 +1,6 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
-import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -11,12 +10,12 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.DateUtils;
/**
* Shows a list of downloaded episodes
@@ -26,13 +25,10 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
private final Context context;
private final ItemAccess itemAccess;
- private final int imageSize;
-
public DownloadedEpisodesListAdapter(Context context, ItemAccess itemAccess) {
super();
this.context = context;
this.itemAccess = itemAccess;
- this.imageSize = (int) context.getResources().getDimension(R.dimen.thumbnail_length_downloaded_item);
}
@Override
@@ -53,7 +49,7 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder;
- final FeedItem item = (FeedItem) getItem(position);
+ final FeedItem item = getItem(position);
if (item == null) return null;
if (convertView == null) {
@@ -62,43 +58,44 @@ 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.txtvSize = (TextView) convertView.findViewById(R.id.txtvSize);
+ holder.queueStatus = (ImageView) convertView.findViewById(R.id.imgvInPlaylist);
holder.pubDate = (TextView) convertView
.findViewById(R.id.txtvPublished);
holder.butSecondary = (ImageButton) convertView
.findViewById(R.id.butSecondaryAction);
- holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
- holder.txtvSize = (TextView) convertView.findViewById(R.id.txtvSize);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
}
+ Glide.with(context)
+ .load(item.getImageUri())
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
+ .into(holder.imageView);
+
holder.title.setText(item.getTitle());
- holder.pubDate.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL));
holder.txtvSize.setText(Converter.byteToString(item.getMedia().getSize()));
- FeedItem.State state = item.getState();
+ holder.queueStatus.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.GONE);
+ String pubDateStr = DateUtils.formatAbbrev(context, item.getPubDate());
+ holder.pubDate.setText(pubDateStr);
+ FeedItem.State state = item.getState();
if (state == FeedItem.State.PLAYING) {
holder.butSecondary.setEnabled(false);
} else {
holder.butSecondary.setEnabled(true);
}
-
holder.butSecondary.setFocusable(false);
holder.butSecondary.setTag(item);
holder.butSecondary.setOnClickListener(secondaryActionListener);
-
- Glide.with(context)
- .load(item.getImageUri())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
- .into(holder.imageView);
-
return convertView;
}
@@ -112,10 +109,11 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
static class Holder {
- TextView title;
- TextView pubDate;
ImageView imageView;
+ TextView title;
TextView txtvSize;
+ ImageView queueStatus;
+ TextView pubDate;
ImageButton butSecondary;
}
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 206d07f0f..4a0ff1f12 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -74,7 +75,7 @@ public class DownloadlistAdapter extends BaseAdapter {
}
if (position == selectedItemIndex) {
- convertView.setBackgroundColor(convertView.getResources().getColor(
+ convertView.setBackgroundColor(ContextCompat.getColor(convertView.getContext(),
ThemeUtils.getSelectionBackgroundColor()));
} else {
convertView.setBackgroundResource(0);
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 1972e675e..7ca8d6a31 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.adapter;
import android.content.Context;
import android.content.res.TypedArray;
-import android.text.format.DateUtils;
+import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -21,7 +21,9 @@ 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.ThemeUtils;
/**
@@ -57,8 +59,12 @@ public class FeedItemlistAdapter extends BaseAdapter {
this.actionButtonUtils = new ActionButtonUtils(context);
this.makePlayedItemsTransparent = makePlayedItemsTransparent;
- playingBackGroundColor = context.getResources().getColor(R.color.highlight_light);
- normalBackGroundColor = context.getResources().getColor(android.R.color.transparent);
+ 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);
+ }
+ normalBackGroundColor = ContextCompat.getColor(context, android.R.color.transparent);
}
@Override
@@ -113,8 +119,8 @@ public class FeedItemlistAdapter extends BaseAdapter {
if (!(getItemViewType(position) == Adapter.IGNORE_ITEM_VIEW_TYPE)) {
convertView.setVisibility(View.VISIBLE);
if (position == selectedItemIndex) {
- convertView.setBackgroundColor(convertView.getResources()
- .getColor(ThemeUtils.getSelectionBackgroundColor()));
+ convertView.setBackgroundColor(ContextCompat.getColor(convertView.getContext(),
+ ThemeUtils.getSelectionBackgroundColor()));
} else {
convertView.setBackgroundResource(0);
}
@@ -138,8 +144,8 @@ public class FeedItemlistAdapter extends BaseAdapter {
ViewHelper.setAlpha(convertView, 1.0f);
}
- holder.published.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL));
-
+ String pubDateStr = DateUtils.formatAbbrev(context, item.getPubDate());
+ holder.published.setText(pubDateStr);
FeedMedia media = item.getMedia();
if (media == null) {
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 9011c8b02..5b205e91f 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
@@ -6,11 +6,13 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.FeedItem;
import java.util.List;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.util.DateUtils;
+
/**
* List adapter for showing a list of FeedItems with their title and description.
*/
@@ -33,6 +35,7 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> {
.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);
convertView.setTag(holder);
@@ -41,15 +44,20 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> {
}
holder.title.setText(item.getTitle());
+ holder.pubDate.setText(DateUtils.formatAbbrev(getContext(), item.getPubDate()));
if (item.getDescription() != null) {
- holder.description.setText(item.getDescription());
+ String description = item.getDescription()
+ .replaceAll("\n", " ")
+ .replaceAll("\\s+", " ")
+ .trim();
+ holder.description.setText(description);
}
-
return convertView;
}
static class Holder {
TextView title;
+ TextView pubDate;
TextView description;
}
}
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 183c1a44e..6d7e6dcac 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -6,6 +6,7 @@ import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.preference.PreferenceManager;
+import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -15,7 +16,7 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconTextView;
import org.apache.commons.lang3.ArrayUtils;
@@ -208,7 +209,8 @@ public class NavListAdapter extends BaseAdapter
holder.title.setText(title);
- if (tags.get(position).equals(QueueFragment.TAG)) {
+ String tag = tags.get(position);
+ if (tag.equals(QueueFragment.TAG)) {
int queueSize = itemAccess.getQueueSize();
if (queueSize > 0) {
holder.count.setVisibility(View.VISIBLE);
@@ -216,7 +218,7 @@ public class NavListAdapter extends BaseAdapter
} else {
holder.count.setVisibility(View.GONE);
}
- } else if (tags.get(position).equals(EpisodesFragment.TAG)) {
+ } else if (tag.equals(EpisodesFragment.TAG)) {
int unreadItems = itemAccess.getNumberOfNewItems();
if (unreadItems > 0) {
holder.count.setVisibility(View.VISIBLE);
@@ -224,6 +226,26 @@ public class NavListAdapter extends BaseAdapter
} else {
holder.count.setVisibility(View.GONE);
}
+ } else if(tag.equals(DownloadsFragment.TAG) && UserPreferences.isEnableAutodownload()) {
+ int epCacheSize = UserPreferences.getEpisodeCacheSize();
+ // don't count episodes that can be reclaimed
+ int spaceUsed = itemAccess.getNumberOfDownloadedItems() -
+ itemAccess.getReclaimableItems();
+
+ if (epCacheSize > 0 && spaceUsed >= epCacheSize) {
+ holder.count.setText("{md-disc-full 150%}");
+ Iconify.addIcons(holder.count);
+ holder.count.setVisibility(View.VISIBLE);
+ holder.count.setOnClickListener(v -> {
+ new AlertDialog.Builder(context)
+ .setTitle(R.string.episode_cache_full_title)
+ .setMessage(R.string.episode_cache_full_message)
+ .setPositiveButton(android.R.string.ok, (dialog, which) -> {})
+ .show();
+ });
+ } else {
+ holder.count.setVisibility(View.GONE);
+ }
} else {
holder.count.setVisibility(View.GONE);
}
@@ -316,6 +338,8 @@ public class NavListAdapter extends BaseAdapter
int getSelectedItemIndex();
int getQueueSize();
int getNumberOfNewItems();
+ int getNumberOfDownloadedItems();
+ int getReclaimableItems();
int getFeedCounter(long feedId);
}
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 3e4dd4deb..aa3368258 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
@@ -3,10 +3,11 @@ package de.danoeh.antennapod.adapter;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
import android.support.v4.view.MotionEventCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
-import android.text.format.DateUtils;
+import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@@ -38,6 +39,7 @@ 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.fragment.ItemFragment;
@@ -76,11 +78,11 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
locked = UserPreferences.isQueueLocked();
if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
- playingBackGroundColor = mainActivity.getResources().getColor(R.color.highlight_dark);
+ playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_dark);
} else {
- playingBackGroundColor = mainActivity.getResources().getColor(R.color.highlight_light);
+ playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_light);
}
- normalBackGroundColor = mainActivity.getResources().getColor(android.R.color.transparent);
+ normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent);
}
public void setLocked(boolean locked) {
@@ -181,8 +183,8 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
item1.setVisible(visible);
}
};
- FeedItemMenuHandler.onPrepareMenu(mainActivity.get(), contextMenuInterface, item, true,
- itemAccess.getQueueIds());
+ FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true,
+ itemAccess.getQueueIds(), itemAccess.getFavoritesIds());
}
@Override
@@ -209,9 +211,21 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
FeedMedia media = item.getMedia();
title.setText(item.getTitle());
- String pubDateStr = DateUtils.formatDateTime(mainActivity.get(),
- item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL);
- pubDate.setText(pubDateStr.replace(" ", "\n"));
+ String pubDateStr = DateUtils.formatAbbrev(mainActivity.get(), item.getPubDate());
+ int index = 0;
+ if(countMatches(pubDateStr, ' ') == 1 || countMatches(pubDateStr, ' ') == 2) {
+ index = pubDateStr.lastIndexOf(' ');
+ } else if(countMatches(pubDateStr, '.') == 2) {
+ index = pubDateStr.lastIndexOf('.');
+ } else if(countMatches(pubDateStr, '-') == 2) {
+ index = pubDateStr.lastIndexOf('-');
+ } else if(countMatches(pubDateStr, '/') == 2) {
+ index = pubDateStr.lastIndexOf('/');
+ }
+ if(index > 0) {
+ pubDateStr = pubDateStr.substring(0, index+1).trim() + "\n" + pubDateStr.substring(index+1);
+ }
+ pubDate.setText(pubDateStr);
if (media != null) {
final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
@@ -238,7 +252,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
} else {
if(media.getSize() > 0) {
progressLeft.setText(Converter.byteToString(media.getSize()));
- } else if(false == media.checkedOnSizeButUnknown()) {
+ } else if(NetworkUtils.isDownloadAllowed() && false == media.checkedOnSizeButUnknown()) {
progressLeft.setText("{fa-spinner}");
Iconify.addIcons(progressLeft);
NetworkUtils.getFeedMediaSizeObservable(media)
@@ -337,6 +351,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
long getItemDownloadSize(FeedItem item);
int getItemDownloadProgressPercent(FeedItem item);
LongList getQueueIds();
+ LongList getFavoritesIds();
}
/**
@@ -360,4 +375,18 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
*/
void onItemClear();
}
+
+ // Oh Xiaomi, I hate you so much. How did you manage to fuck this up?
+ private static int countMatches(final CharSequence str, final char ch) {
+ if (TextUtils.isEmpty(str)) {
+ return 0;
+ }
+ int count = 0;
+ for (int i = 0; i < str.length(); i++) {
+ if (ch == str.charAt(i)) {
+ count++;
+ }
+ }
+ return count;
+ }
}
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 08ffdd197..47ac4c757 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
@@ -10,6 +10,7 @@ import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -65,6 +66,12 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
//Set the title
viewHolder.titleView.setText(podcast.title);
+ if(!podcast.feedUrl.contains("itunes.apple.com")) {
+ viewHolder.urlView.setText(podcast.feedUrl);
+ viewHolder.urlView.setVisibility(View.VISIBLE);
+ } else {
+ viewHolder.urlView.setVisibility(View.GONE);
+ }
//Update the empty imageView with the image from the feed
Glide.with(context)
@@ -94,6 +101,8 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
*/
public final TextView titleView;
+ public final TextView urlView;
+
/**
* Constructor
@@ -102,6 +111,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
PodcastViewHolder(View view){
coverView = (ImageView) view.findViewById(R.id.imgvCover);
titleView = (TextView) view.findViewById(R.id.txtvTitle);
+ urlView = (TextView) view.findViewById(R.id.txtvUrl);
}
}
@@ -124,16 +134,47 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
*/
public final String feedUrl;
+
+ private Podcast(String title, String imageUrl, String feedUrl) {
+ this.title = title;
+ this.imageUrl = imageUrl;
+ this.feedUrl = feedUrl;
+ }
+
+ /**
+ * Constructs a Podcast instance from a iTunes search result
+ *
+ * @param json object holding the podcast information
+ * @throws JSONException
+ */
+ public static Podcast fromSearch(JSONObject json) throws JSONException {
+ String title = json.getString("collectionName");
+ String imageUrl = json.getString("artworkUrl100");
+ String feedUrl = json.getString("feedUrl");
+ return new Podcast(title, imageUrl, feedUrl);
+ }
+
/**
- * Constructor.
+ * Constructs a Podcast instance from iTunes toplist entry
*
* @param json object holding the podcast information
* @throws JSONException
*/
- public Podcast(JSONObject json) throws JSONException {
- title = json.getString("collectionName");
- imageUrl = json.getString("artworkUrl100");
- feedUrl = json.getString("feedUrl");
+ public static Podcast fromToplist(JSONObject json) throws JSONException {
+ String title = json.getJSONObject("title").getString("label");
+ String imageUrl = null;
+ JSONArray images = json.getJSONArray("im:image");
+ for(int i=0; imageUrl == null && i < images.length(); i++) {
+ JSONObject image = images.getJSONObject(i);
+ String height = image.getJSONObject("attributes").getString("height");
+ if(Integer.valueOf(height) >= 100) {
+ imageUrl = image.getString("label");
+ }
+ }
+ String feedUrl = "https://itunes.apple.com/lookup?id=" +
+ json.getJSONObject("id").getJSONObject("attributes").getString("im:id");
+ return new Podcast(title, imageUrl, feedUrl);
}
+
}
}
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 00327bce0..cc27b6c9d 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
@@ -6,7 +6,6 @@ import android.content.Context;
import android.os.AsyncTask;
import java.util.Arrays;
-import java.util.Date;
import de.danoeh.antennapod.activity.OpmlImportHolder;
import de.danoeh.antennapod.core.R;
@@ -47,7 +46,7 @@ public class OpmlFeedQueuer extends AsyncTask<Void, Void, Void> {
for (int idx = 0; idx < selection.length; idx++) {
OpmlElement element = OpmlImportHolder.getReadElements().get(
selection[idx]);
- Feed feed = new Feed(element.getXmlUrl(), new Date(0),
+ Feed feed = new Feed(element.getXmlUrl(), null,
element.getText());
try {
requester.downloadFeed(context.getApplicationContext(), feed);
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 e867540e4..ac7a9efee 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -1,10 +1,11 @@
package de.danoeh.antennapod.dialog;
import android.content.res.TypedArray;
-import android.graphics.Color;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
+import android.support.v4.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -16,13 +17,8 @@ import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
-import com.joanzapata.iconify.Icon;
-import com.joanzapata.iconify.IconDrawable;
-import com.joanzapata.iconify.fonts.FontAwesomeIcons;
-
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -38,6 +34,14 @@ public class EpisodesApplyActionFragment extends Fragment {
public 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;
+ public static final int ACTION_REMOVE = 16;
+ public static final int ACTION_ALL = ACTION_QUEUE | ACTION_MARK_PLAYED | ACTION_MARK_UNPLAYED
+ | ACTION_DOWNLOAD | ACTION_REMOVE;
+
private ListView mListView;
private ArrayAdapter<String> mAdapter;
@@ -47,27 +51,26 @@ public class EpisodesApplyActionFragment extends Fragment {
private Button btnDownload;
private Button btnDelete;
- private final Map<Long,FeedItem> idMap;
- private final List<FeedItem> episodes;
+ private final Map<Long,FeedItem> idMap = new ArrayMap<>();
+ private final List<FeedItem> episodes = new ArrayList<>();
+ private int actions;
private final List<String> titles = new ArrayList();
private final LongList checkedIds = new LongList();
private MenuItem mSelectToggle;
- private int textColor;
-
- public EpisodesApplyActionFragment() {
- this.episodes = new ArrayList<>();
- this.idMap = new HashMap<>();
+ public static EpisodesApplyActionFragment newInstance(List<FeedItem> items) {
+ return newInstance(items, ACTION_ALL);
}
- public void setEpisodes(List<FeedItem> episodes) {
- this.episodes.clear();
- this.episodes.addAll(episodes);
- this.idMap.clear();
- for(FeedItem episode : episodes) {
- this.idMap.put(episode.getId(), episode);
+ public static EpisodesApplyActionFragment newInstance(List<FeedItem> items, int actions) {
+ EpisodesApplyActionFragment f = new EpisodesApplyActionFragment();
+ f.episodes.addAll(items);
+ for(FeedItem episode : items) {
+ f.idMap.put(episode.getId(), episode);
}
+ f.actions = actions;
+ return f;
}
@Override
@@ -102,16 +105,48 @@ public class EpisodesApplyActionFragment extends Fragment {
mListView.setAdapter(mAdapter);
checkAll();
+ int lastVisibleDiv = 0;
btnAddToQueue = (Button) view.findViewById(R.id.btnAddToQueue);
- btnAddToQueue.setOnClickListener(v -> queueChecked());
+ if((actions & ACTION_QUEUE) != 0) {
+ btnAddToQueue.setOnClickListener(v -> queueChecked());
+ lastVisibleDiv = R.id.divider1;
+ } else {
+ btnAddToQueue.setVisibility(View.GONE);
+ view.findViewById(R.id.divider1).setVisibility(View.GONE);
+ }
btnMarkAsPlayed = (Button) view.findViewById(R.id.btnMarkAsPlayed);
- btnMarkAsPlayed.setOnClickListener(v -> markedCheckedPlayed());
+ if((actions & ACTION_MARK_PLAYED) != 0) {
+ btnMarkAsPlayed.setOnClickListener(v -> markedCheckedPlayed());
+ lastVisibleDiv = R.id.divider2;
+ } else {
+ btnMarkAsPlayed.setVisibility(View.GONE);
+ view.findViewById(R.id.divider2).setVisibility(View.GONE);
+ }
btnMarkAsUnplayed = (Button) view.findViewById(R.id.btnMarkAsUnplayed);
- btnMarkAsUnplayed.setOnClickListener(v -> markedCheckedUnplayed());
+ if((actions & ACTION_MARK_UNPLAYED) != 0) {
+ btnMarkAsUnplayed.setOnClickListener(v -> markedCheckedUnplayed());
+ lastVisibleDiv = R.id.divider3;
+ } else {
+ btnMarkAsUnplayed.setVisibility(View.GONE);
+ view.findViewById(R.id.divider3).setVisibility(View.GONE);
+ }
btnDownload = (Button) view.findViewById(R.id.btnDownload);
- btnDownload.setOnClickListener(v -> downloadChecked());
+ if((actions & ACTION_DOWNLOAD) != 0) {
+ btnDownload.setOnClickListener(v -> downloadChecked());
+ lastVisibleDiv = R.id.divider4;
+ } else {
+ btnDownload.setVisibility(View.GONE);
+ view.findViewById(R.id.divider4).setVisibility(View.GONE);
+ }
btnDelete = (Button) view.findViewById(R.id.btnDelete);
- btnDelete.setOnClickListener(v -> deleteChecked());
+ if((actions & ACTION_REMOVE) != 0) {
+ btnDelete.setOnClickListener(v -> deleteChecked());
+ } else {
+ btnDelete.setVisibility(View.GONE);
+ if(lastVisibleDiv > 0) {
+ view.findViewById(lastVisibleDiv).setVisibility(View.GONE);
+ }
+ }
return view;
}
@@ -121,14 +156,6 @@ public class EpisodesApplyActionFragment extends Fragment {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.episodes_apply_action_options, menu);
- int[] attrs = { android.R.attr.textColor };
- TypedArray ta = getActivity().obtainStyledAttributes(attrs);
- textColor = ta.getColor(0, Color.GRAY);
- ta.recycle();
-
- menu.findItem(R.id.sort).setIcon(new IconDrawable(getActivity(),
- FontAwesomeIcons.fa_sort).color(textColor).actionBarSize());
-
mSelectToggle = menu.findItem(R.id.select_toggle);
mSelectToggle.setOnMenuItemClickListener(item -> {
if (checkedIds.size() == episodes.size()) {
@@ -138,23 +165,26 @@ public class EpisodesApplyActionFragment extends Fragment {
}
return true;
});
-
- menu.findItem(R.id.select_options).setIcon(new IconDrawable(getActivity(),
- FontAwesomeIcons.fa_caret_down).color(textColor).actionBarSize());
}
@Override
public void onPrepareOptionsMenu (Menu menu) {
- Icon icon;
- if(checkedIds.size() == episodes.size()) {
- icon = FontAwesomeIcons.fa_check_square_o;
- } else if(checkedIds.size() == 0) {
- icon = FontAwesomeIcons.fa_square_o;
+ // Prepare icon for select toggle button
+
+ int[] icon = new int[1];
+ if (checkedIds.size() == episodes.size()) {
+ icon[0] = R.attr.ic_check_box;
+ } else if (checkedIds.size() == 0) {
+ icon[0] = R.attr.ic_check_box_outline;
} else {
- icon = FontAwesomeIcons.fa_minus_square_o;
+ icon[0] = R.attr.ic_indeterminate_check_box;
}
- mSelectToggle.setIcon(new IconDrawable(getActivity(), icon).color(textColor).actionBarSize());
+ TypedArray a = getActivity().obtainStyledAttributes(icon);
+ Drawable iconDrawable = a.getDrawable(0);
+ a.recycle();
+
+ mSelectToggle.setIcon(iconDrawable);
}
@Override
@@ -187,6 +217,14 @@ public class EpisodesApplyActionFragment extends Fragment {
checkDownloaded(false);
resId = R.string.selected_not_downloaded_label;
break;
+ case R.id.check_queued:
+ checkQueued(true);
+ resId = R.string.selected_queued_label;
+ break;
+ case R.id.check_not_queued:
+ checkQueued(false);
+ resId = R.string.selected_not_queued_label;
+ break;
case R.id.sort_title_a_z:
sortByTitle(false);
return true;
@@ -308,6 +346,17 @@ public class EpisodesApplyActionFragment extends Fragment {
refreshCheckboxes();
}
+ private void checkQueued(boolean isQueued) {
+ for (FeedItem episode : episodes) {
+ if(episode.isTagged(FeedItem.TAG_QUEUE) == isQueued) {
+ checkedIds.add(episode.getId());
+ } else {
+ checkedIds.remove(episode.getId());
+ }
+ }
+ refreshCheckboxes();
+ }
+
private void refreshTitles() {
titles.clear();
for(FeedItem episode : episodes) {
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 4b512a48d..3ed82b9bd 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
@@ -21,107 +21,104 @@ import de.danoeh.antennapod.core.util.IntentUtils;
public class VariableSpeedDialog {
- private static final String TAG = VariableSpeedDialog.class.getSimpleName();
-
- private static final Intent playStoreIntent = new Intent(Intent.ACTION_VIEW,
- Uri.parse("market://details?id=com.falconware.prestissimo"));
-
- private VariableSpeedDialog() {
- }
-
- public static void showDialog(final Context context) {
- if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(context)
- || UserPreferences.useSonic()) {
- showSpeedSelectorDialog(context);
- } else {
- showGetPluginDialog(context);
- }
- }
-
- private static void showGetPluginDialog(final Context context) {
- MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
- builder.title(R.string.no_playback_plugin_title);
- builder.content(R.string.no_playback_plugin_or_sonic_msg);
- builder.positiveText(R.string.download_plugin_label);
- builder.negativeText(R.string.enable_sonic);
- builder.neutralText(R.string.close_label);
- builder.callback(new MaterialDialog.ButtonCallback() {
- @Override
- public void onPositive(MaterialDialog dialog) {
- try {
- context.startActivity(playStoreIntent);
- } catch (ActivityNotFoundException e) {
- // this is usually thrown on an emulator if the Android market is not installed
- Log.e(TAG, Log.getStackTraceString(e));
- }
- }
-
- @Override
- public void onNegative(MaterialDialog dialog) {
- if (Build.VERSION.SDK_INT >= 16) { // just to be safe
- UserPreferences.enableSonic(true);
- showSpeedSelectorDialog(context);
- }
- }
-
- @Override
- public void onNeutral(MaterialDialog dialog) {
- super.onNeutral(dialog);
- }
- });
- builder.forceStacking(true);
- MaterialDialog dialog = builder.show();
- if(!IntentUtils.isCallable(context.getApplicationContext(), playStoreIntent)) {
- View pos = dialog.getActionButton(DialogAction.POSITIVE);
- pos.setEnabled(false);
- }
- if (Build.VERSION.SDK_INT < 16) {
- View pos = dialog.getActionButton(DialogAction.NEGATIVE);
- pos.setEnabled(false);
- }
- }
-
- private static void showSpeedSelectorDialog(final Context context) {
- final String[] speedValues = context.getResources().getStringArray(
- R.array.playback_speed_values);
- // According to Java spec these get initialized to false on creation
- final boolean[] speedChecked = new boolean[speedValues.length];
-
- // Build the "isChecked" array so that multiChoice dialog is
- // populated correctly
- List<String> selectedSpeedList = Arrays.asList(UserPreferences
- .getPlaybackSpeedArray());
- for (int i = 0; i < speedValues.length; i++) {
- speedChecked[i] = selectedSpeedList.contains(speedValues[i]);
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.set_playback_speed_label);
- builder.setMultiChoiceItems(R.array.playback_speed_values,
- speedChecked, (dialog, which, isChecked) -> {
- speedChecked[which] = isChecked;
- });
- builder.setNegativeButton(android.R.string.cancel, null);
- builder.setPositiveButton(android.R.string.ok,
- (dialog, which) -> {
- int choiceCount = 0;
- for (int i = 0; i < speedChecked.length; i++) {
- if (speedChecked[i]) {
- choiceCount++;
- }
- }
- String[] newSpeedValues = new String[choiceCount];
- int newSpeedIndex = 0;
- for (int i = 0; i < speedChecked.length; i++) {
- if (speedChecked[i]) {
- newSpeedValues[newSpeedIndex++] = speedValues[i];
- }
- }
-
- UserPreferences.setPlaybackSpeedArray(newSpeedValues);
-
- });
- builder.create().show();
- }
+ private static final String TAG = VariableSpeedDialog.class.getSimpleName();
+
+ private static final Intent playStoreIntent = new Intent(Intent.ACTION_VIEW,
+ Uri.parse("market://details?id=com.falconware.prestissimo"));
+
+ private VariableSpeedDialog() {
+ }
+
+ public static void showDialog(final Context context) {
+ if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(context)
+ || UserPreferences.useSonic()
+ || Build.VERSION.SDK_INT >= 23) {
+ showSpeedSelectorDialog(context);
+ } else {
+ showGetPluginDialog(context, true);
+ }
+ }
+
+ public static void showGetPluginDialog(final Context context) {
+ showGetPluginDialog(context, false);
+ }
+
+ private static void showGetPluginDialog(final Context context, boolean showSpeedSelector) {
+ MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
+ builder.title(R.string.no_playback_plugin_title);
+ builder.content(R.string.no_playback_plugin_or_sonic_msg);
+ builder.positiveText(R.string.enable_sonic);
+ builder.negativeText(R.string.download_plugin_label);
+ builder.neutralText(R.string.close_label);
+ builder.onPositive((dialog, which) -> {
+ if (Build.VERSION.SDK_INT >= 16) { // just to be safe
+ UserPreferences.enableSonic(true);
+ if(showSpeedSelector) {
+ showSpeedSelectorDialog(context);
+ }
+ }
+ });
+ builder.onNegative((dialog, which) -> {
+ try {
+ context.startActivity(playStoreIntent);
+ } catch (ActivityNotFoundException e) {
+ // this is usually thrown on an emulator if the Android market is not installed
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ });
+ builder.forceStacking(true);
+ MaterialDialog dialog = builder.show();
+ if (Build.VERSION.SDK_INT < 16) {
+ View pos = dialog.getActionButton(DialogAction.POSITIVE);
+ pos.setEnabled(false);
+ }
+ if(!IntentUtils.isCallable(context.getApplicationContext(), playStoreIntent)) {
+ View pos = dialog.getActionButton(DialogAction.NEGATIVE);
+ pos.setEnabled(false);
+ }
+ }
+
+ private static void showSpeedSelectorDialog(final Context context) {
+ final String[] speedValues = context.getResources().getStringArray(
+ R.array.playback_speed_values);
+ // According to Java spec these get initialized to false on creation
+ final boolean[] speedChecked = new boolean[speedValues.length];
+
+ // Build the "isChecked" array so that multiChoice dialog is
+ // populated correctly
+ List<String> selectedSpeedList = Arrays.asList(UserPreferences
+ .getPlaybackSpeedArray());
+ for (int i = 0; i < speedValues.length; i++) {
+ speedChecked[i] = selectedSpeedList.contains(speedValues[i]);
+ }
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.set_playback_speed_label);
+ builder.setMultiChoiceItems(R.array.playback_speed_values,
+ speedChecked, (dialog, which, isChecked) -> {
+ speedChecked[which] = isChecked;
+ });
+ builder.setNegativeButton(android.R.string.cancel, null);
+ builder.setPositiveButton(android.R.string.ok,
+ (dialog, which) -> {
+ int choiceCount = 0;
+ for (int i = 0; i < speedChecked.length; i++) {
+ if (speedChecked[i]) {
+ choiceCount++;
+ }
+ }
+ String[] newSpeedValues = new String[choiceCount];
+ int newSpeedIndex = 0;
+ for (int i = 0; i < speedChecked.length; i++) {
+ if (speedChecked[i]) {
+ newSpeedValues[newSpeedIndex++] = speedValues[i];
+ }
+ }
+
+ UserPreferences.setPlaybackSpeedArray(newSpeedValues);
+
+ });
+ builder.create().show();
+ }
}
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 f6c80aa7c..d979dc382 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -45,7 +45,7 @@ public class AddFeedFragment extends Fragment {
Button butSearchITunes = (Button) root.findViewById(R.id.butSearchItunes);
final MainActivity activity = (MainActivity) getActivity();
- activity.getMainActivtyActionBar().setTitle(R.string.add_feed_label);
+ activity.getSupportActionBar().setTitle(R.string.add_feed_label);
butSearchITunes.setOnClickListener(new View.OnClickListener() {
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
index 37be8f020..273c75240 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
@@ -10,6 +10,7 @@ import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
+import android.support.v7.widget.SimpleItemAnimator;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -45,6 +46,7 @@ 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;
@@ -189,6 +191,9 @@ public class AllEpisodesFragment extends Fragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if(!isAdded()) {
+ return;
+ }
super.onCreateOptionsMenu(menu, inflater);
if (itemsLoaded) {
inflater.inflate(R.menu.new_episodes, menu);
@@ -303,6 +308,10 @@ public class AllEpisodesFragment extends Fragment {
View root = inflater.inflate(fragmentResource, container, false);
recyclerView = (RecyclerView) root.findViewById(android.R.id.list);
+ RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
+ if (animator instanceof SimpleItemAnimator) {
+ ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
+ }
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
@@ -348,7 +357,7 @@ public class AllEpisodesFragment extends Fragment {
@Override
public FeedItem getItem(int position) {
- if (episodes != null && position < episodes.size()) {
+ if (episodes != null && 0 <= position && position < episodes.size()) {
return episodes.get(position);
}
return null;
@@ -374,6 +383,34 @@ public class AllEpisodesFragment extends Fragment {
}
return false;
}
+
+ @Override
+ public LongList getQueueIds() {
+ LongList queueIds = new LongList();
+ if(episodes == null) {
+ return queueIds;
+ }
+ for(FeedItem item : episodes) {
+ if(item.isTagged(FeedItem.TAG_QUEUE)) {
+ queueIds.add(item.getId());
+ }
+ }
+ return queueIds;
+ }
+
+ @Override
+ public LongList getFavoritesIds() {
+ LongList favoritesIds = new LongList();
+ if(episodes == null) {
+ return favoritesIds;
+ }
+ for(FeedItem item : episodes) {
+ if(item.isTagged(FeedItem.TAG_FAVORITE)) {
+ favoritesIds.add(item.getId());
+ }
+ }
+ return favoritesIds;
+ }
};
public void onEventMainThread(FeedItemEvent event) {
@@ -397,14 +434,15 @@ public class AllEpisodesFragment extends Fragment {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if(update.feedIds.length > 0) {
- if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
+ if (isUpdatingFeeds != update.feedIds.length > 0) {
getActivity().supportInvalidateOptionsMenu();
- }
}
- if(update.mediaIds.length > 0) {
- if(listAdapter != null) {
- listAdapter.notifyDataSetChanged();
+ if(listAdapter != null && update.mediaIds.length > 0) {
+ for(long mediaId : update.mediaIds) {
+ int pos = FeedItemUtil.indexOfItemWithMediaId(episodes, mediaId);
+ if(pos >= 0) {
+ listAdapter.notifyItemChanged(pos);
+ }
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
new file mode 100644
index 000000000..96abdd835
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
@@ -0,0 +1,77 @@
+package de.danoeh.antennapod.fragment;
+
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.View;
+import android.widget.ListView;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
+import de.danoeh.antennapod.adapter.ChaptersListAdapter;
+import de.danoeh.antennapod.core.feed.Chapter;
+import de.danoeh.antennapod.core.util.playback.Playable;
+import de.danoeh.antennapod.core.util.playback.PlaybackController;
+
+
+public class ChaptersFragment extends ListFragment implements AudioplayerContentFragment {
+
+ private Playable media;
+ private PlaybackController controller;
+
+ private ChaptersListAdapter adapter;
+
+ public static ChaptersFragment newInstance(Playable media, PlaybackController controller) {
+ ChaptersFragment f = new ChaptersFragment();
+ f.media = media;
+ f.controller = controller;
+ return f;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ // add padding
+ final ListView lv = getListView();
+ lv.setClipToPadding(false);
+ final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
+ lv.setPadding(0, vertPadding, 0, vertPadding);
+
+ adapter = new ChaptersListAdapter(getActivity(), 0, pos -> {
+ Chapter chapter = (Chapter) getListAdapter().getItem(pos);
+ controller.seekToChapter(chapter);
+ });
+ setListAdapter(adapter);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ adapter.setMedia(media);
+ adapter.notifyDataSetChanged();
+ if(media == null || media.getChapters() == null) {
+ setEmptyText(getString(R.string.no_chapters_label));
+ } else {
+ setEmptyText(null);
+ }
+ }
+
+ public void onDestroy() {
+ super.onDestroy();
+ adapter = null;
+ }
+
+ @Override
+ public void onMediaChanged(Playable media) {
+ if(this.media == media || adapter == null) {
+ return;
+ }
+ this.media = media;
+ adapter.setMedia(media);
+ adapter.notifyDataSetChanged();
+ if(media == null || media.getChapters() == null || media.getChapters().size() == 0) {
+ setEmptyText(getString(R.string.no_items_label));
+ } else {
+ setEmptyText(null);
+ }
+ }
+}
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 a5568b16e..a53c85f1c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -1,12 +1,20 @@
package de.danoeh.antennapod.fragment;
-import android.app.Activity;
+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;
+import android.view.Menu;
+import android.view.MenuInflater;
+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;
@@ -14,8 +22,10 @@ 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.dialog.EpisodesApplyActionFragment;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
@@ -28,22 +38,21 @@ public class CompletedDownloadsFragment extends ListFragment {
private static final String TAG = CompletedDownloadsFragment.class.getSimpleName();
- private static final int EVENTS =
- EventDistributor.DOWNLOAD_HANDLED |
- EventDistributor.DOWNLOADLOG_UPDATE |
- EventDistributor.UNREAD_ITEMS_UPDATE;
+ private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
+ EventDistributor.DOWNLOADLOG_UPDATE |
+ EventDistributor.UNREAD_ITEMS_UPDATE;
private List<FeedItem> items;
private DownloadedEpisodesListAdapter listAdapter;
private boolean viewCreated = false;
- private boolean itemsLoaded = false;
private Subscription subscription;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
loadItems();
}
@@ -81,9 +90,9 @@ public class CompletedDownloadsFragment extends ListFragment {
}
@Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- if (viewCreated && itemsLoaded) {
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (viewCreated && items != null) {
onFragmentLoaded();
}
}
@@ -99,7 +108,7 @@ public class CompletedDownloadsFragment extends ListFragment {
lv.setPadding(0, vertPadding, 0, vertPadding);
viewCreated = true;
- if (itemsLoaded && getActivity() != null) {
+ if (items != null && getActivity() != null) {
onFragmentLoaded();
}
}
@@ -111,7 +120,6 @@ public class CompletedDownloadsFragment extends ListFragment {
if (item != null) {
((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(item.getId()));
}
-
}
private void onFragmentLoaded() {
@@ -121,6 +129,43 @@ public class CompletedDownloadsFragment extends ListFragment {
}
setListShown(true);
listAdapter.notifyDataSetChanged();
+ getActivity().supportInvalidateOptionsMenu();
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if(!isAdded()) {
+ return;
+ }
+ super.onCreateOptionsMenu(menu, inflater);
+ if(items != null) {
+ inflater.inflate(R.menu.downloads_completed, menu);
+ 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);
+ }
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.episode_actions:
+ EpisodesApplyActionFragment fragment = EpisodesApplyActionFragment
+ .newInstance(items, EpisodesApplyActionFragment.ACTION_REMOVE);
+ ((MainActivity) getActivity()).loadChildFragment(fragment);
+ return true;
+ default:
+ return false;
+ }
}
private DownloadedEpisodesListAdapter.ItemAccess itemAccess = new DownloadedEpisodesListAdapter.ItemAccess() {
@@ -131,7 +176,11 @@ public class CompletedDownloadsFragment extends ListFragment {
@Override
public FeedItem getItem(int position) {
- return (items != null) ? items.get(position) : null;
+ if (items != null && 0 <= position && position < items.size()) {
+ return items.get(position);
+ } else {
+ return null;
+ }
}
@Override
@@ -153,7 +202,7 @@ public class CompletedDownloadsFragment extends ListFragment {
if(subscription != null) {
subscription.unsubscribe();
}
- if (!itemsLoaded && viewCreated) {
+ if (items == null && viewCreated) {
setListShown(false);
}
subscription = Observable.fromCallable(() -> DBReader.getDownloadedItems())
@@ -162,7 +211,6 @@ public class CompletedDownloadsFragment extends ListFragment {
.subscribe(result -> {
if (result != null) {
items = result;
- itemsLoaded = true;
if (viewCreated && getActivity() != null) {
onFragmentLoaded();
}
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 a1667cce0..d3b97f9df 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -1,7 +1,5 @@
package de.danoeh.antennapod.fragment;
-import android.app.Activity;
-import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
@@ -9,13 +7,11 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
+import android.widget.TextView;
import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
-import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.AudioplayerActivity;
import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.util.playback.Playable;
@@ -23,17 +19,18 @@ import de.danoeh.antennapod.core.util.playback.Playable;
/**
* Displays the cover and the title of a FeedItem.
*/
-public class CoverFragment extends Fragment implements
- AudioplayerContentFragment {
+public class CoverFragment extends Fragment implements AudioplayerContentFragment {
+
private static final String TAG = "CoverFragment";
private static final String ARG_PLAYABLE = "arg.playable";
private Playable media;
+ private View root;
+ private TextView txtvPodcastTitle;
+ private TextView txtvEpisodeTitle;
private ImageView imgvCover;
- private boolean viewCreated = false;
-
public static CoverFragment newInstance(Playable item) {
CoverFragment f = new CoverFragment();
if (item != null) {
@@ -47,7 +44,6 @@ public class CoverFragment extends Fragment implements
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setRetainInstance(true);
Bundle args = getArguments();
if (args != null) {
media = args.getParcelable(ARG_PLAYABLE);
@@ -59,39 +55,23 @@ public class CoverFragment extends Fragment implements
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- View root = inflater.inflate(R.layout.cover_fragment, container, false);
+ 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);
- imgvCover.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Activity activity = getActivity();
- if (activity != null && activity instanceof AudioplayerActivity) {
- ((AudioplayerActivity)activity).switchToLastFragment();
- }
- }
- });
- viewCreated = true;
return root;
}
private void loadMediaInfo() {
if (media != null) {
- imgvCover.post(new Runnable() {
-
- @Override
- public void run() {
- Context c = getActivity();
- if (c != null) {
- Glide.with(c)
- .load(media.getImageUri())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .dontAnimate()
- .into(imgvCover);
- }
- }
- });
+ txtvPodcastTitle.setText(media.getFeedTitle());
+ txtvEpisodeTitle.setText(media.getEpisodeTitle());
+ Glide.with(this)
+ .load(media.getImageUri())
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .dontAnimate()
+ .fitCenter()
+ .into(imgvCover);
} else {
Log.w(TAG, "loadMediaInfo was called while media was null");
}
@@ -99,12 +79,10 @@ public class CoverFragment extends Fragment implements
@Override
public void onStart() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "On Start");
+ Log.d(TAG, "On Start");
super.onStart();
if (media != null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading media info");
+ Log.d(TAG, "Loading media info");
loadMediaInfo();
} else {
Log.w(TAG, "Unable to load media info: media was null");
@@ -112,12 +90,19 @@ public class CoverFragment extends Fragment implements
}
@Override
- public void onDataSetChanged(Playable media) {
- this.media = media;
- if (viewCreated) {
- loadMediaInfo();
- }
+ public void onDestroy() {
+ super.onDestroy();
+ // prevent memory leaks
+ root = null;
+ }
+ @Override
+ public void onMediaChanged(Playable media) {
+ if(!isAdded() || this.media == media) {
+ return;
+ }
+ this.media = media;
+ loadMediaInfo();
}
}
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 90cacd2e4..b470d379a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -91,7 +91,11 @@ public class DownloadLogFragment extends ListFragment {
@Override
public DownloadStatus getItem(int position) {
- return (downloadLog != null) ? downloadLog.get(position) : null;
+ if (downloadLog != null && 0 <= position && position < downloadLog.size()) {
+ return downloadLog.get(position);
+ } else {
+ return null;
+ }
}
};
@@ -107,6 +111,9 @@ public class DownloadLogFragment extends ListFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if(!isAdded()) {
+ return;
+ }
super.onCreateOptionsMenu(menu, inflater);
if (itemsLoaded) {
MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
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 7b02b4f18..80a9bf0b3 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -9,10 +9,10 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
+import android.widget.ProgressBar;
import android.widget.TextView;
import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
@@ -30,9 +30,10 @@ public class ExternalPlayerFragment extends Fragment {
private ViewGroup fragmentLayout;
private ImageView imgvCover;
- private ViewGroup layoutInfo;
private TextView txtvTitle;
private ImageButton butPlay;
+ private TextView mFeedName;
+ private ProgressBar mProgressBar;
private PlaybackController controller;
@@ -47,11 +48,12 @@ public class ExternalPlayerFragment extends Fragment {
container, false);
fragmentLayout = (ViewGroup) root.findViewById(R.id.fragmentLayout);
imgvCover = (ImageView) root.findViewById(R.id.imgvCover);
- layoutInfo = (ViewGroup) root.findViewById(R.id.layoutInfo);
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);
- layoutInfo.setOnClickListener(new OnClickListener() {
+ fragmentLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@@ -77,35 +79,8 @@ public class ExternalPlayerFragment extends Fragment {
return new PlaybackController(getActivity(), true) {
@Override
- public void setupGUI() {
- }
-
- @Override
public void onPositionObserverUpdate() {
- }
-
- @Override
- public void onReloadNotification(int code) {
- }
-
- @Override
- public void onBufferStart() {
- }
-
- @Override
- public void onBufferEnd() {
- }
-
- @Override
- public void onBufferUpdate(float progress) {
- }
-
- @Override
- public void onSleepTimerUpdate() {
- }
-
- @Override
- public void handleError(int code) {
+ ExternalPlayerFragment.this.onPositionObserverUpdate();
}
@Override
@@ -113,13 +88,6 @@ public class ExternalPlayerFragment extends Fragment {
return butPlay;
}
- @Override
- public void postStatusMsg(int msg) {
- }
-
- @Override
- public void clearStatusMsg() {
- }
@Override
public boolean loadMediaInfo() {
@@ -132,14 +100,6 @@ public class ExternalPlayerFragment extends Fragment {
}
@Override
- public void onAwaitingVideoSurface() {
- }
-
- @Override
- public void onServiceQueried() {
- }
-
- @Override
public void onShutdownNotification() {
playbackDone();
}
@@ -148,10 +108,6 @@ public class ExternalPlayerFragment extends Fragment {
public void onPlaybackEnd() {
playbackDone();
}
-
- @Override
- public void onPlaybackSpeedChange() {
- }
};
}
@@ -159,6 +115,8 @@ public class ExternalPlayerFragment extends Fragment {
public void onResume() {
super.onResume();
controller.init();
+ mProgressBar.setProgress((int)
+ ((double) controller.getPosition() / controller.getDuration() * 100));
}
@Override
@@ -199,6 +157,9 @@ public class ExternalPlayerFragment extends Fragment {
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.getImageUri())
@@ -234,4 +195,9 @@ public class ExternalPlayerFragment extends Fragment {
public PlaybackController getPlaybackControllerTestingOnly() {
return controller;
}
+
+ public void onPositionObserverUpdate() {
+ mProgressBar.setProgress((int)
+ ((double) controller.getPosition() / controller.getDuration() * 100));
+ }
}
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 faa4413bb..c1c1aab6c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -7,8 +7,9 @@ import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.graphics.Color;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@@ -20,12 +21,14 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.webkit.WebSettings.LayoutAlgorithm;
+import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.AudioplayerActivity;
+import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -36,11 +39,15 @@ 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;
/**
* Displays the description of a Playable object in a Webview.
*/
-public class ItemDescriptionFragment extends Fragment {
+public class ItemDescriptionFragment extends Fragment implements AudioplayerContentFragment {
private static final String TAG = "ItemDescriptionFragment";
@@ -59,8 +66,7 @@ public class ItemDescriptionFragment extends Fragment {
private ShownotesProvider shownotesProvider;
private Playable media;
-
- private AsyncTask<Void, Void, Void> webViewLoader;
+ private Subscription webViewLoader;
/**
* URL that was selected via long-press.
@@ -106,17 +112,17 @@ public class ItemDescriptionFragment extends Fragment {
Bundle savedInstanceState) {
Log.d(TAG, "Creating view");
webvDescription = new WebView(getActivity());
- 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.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
- }
- webvDescription.setBackgroundColor(getResources().getColor(
- R.color.black));
+ if (Build.VERSION.SDK_INT >= 11) {
+ 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);
+ ta.recycle();
+ webvDescription.setBackgroundColor(backgroundColor);
webvDescription.getSettings().setUseWideViewPort(false);
- webvDescription.getSettings().setLayoutAlgorithm(
- LayoutAlgorithm.NARROW_COLUMNS);
+ webvDescription.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
webvDescription.getSettings().setLoadWithOverviewMode(true);
webvDescription.setOnLongClickListener(webViewLongClickListener);
webvDescription.setWebViewClient(new WebViewClient() {
@@ -142,14 +148,7 @@ public class ItemDescriptionFragment extends Fragment {
super.onPageFinished(view, url);
Log.d(TAG, "Page finished");
// Restoring the scroll position might not always work
- view.postDelayed(new Runnable() {
-
- @Override
- public void run() {
- restoreFromPreference();
- }
-
- }, 50);
+ view.postDelayed(() -> restoreFromPreference(), 50);
}
});
@@ -159,26 +158,11 @@ public class ItemDescriptionFragment extends Fragment {
}
@Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- Log.d(TAG, "Fragment attached");
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- Log.d(TAG, "Fragment detached");
- if (webViewLoader != null) {
- webViewLoader.cancel(true);
- }
- }
-
- @Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Fragment destroyed");
if (webViewLoader != null) {
- webViewLoader.cancel(true);
+ webViewLoader.unsubscribe();
}
if (webvDescription != null) {
webvDescription.removeAllViews();
@@ -194,7 +178,6 @@ public class ItemDescriptionFragment extends Fragment {
Bundle args = getArguments();
saveState = args.getBoolean(ARG_SAVE_STATE, false);
highlightTimecodes = args.getBoolean(ARG_HIGHLIGHT_TIMECODES, false);
-
}
@Override
@@ -204,46 +187,21 @@ public class ItemDescriptionFragment extends Fragment {
if (args.containsKey(ARG_PLAYABLE)) {
media = args.getParcelable(ARG_PLAYABLE);
shownotesProvider = media;
- startLoader();
+ load();
} else if (args.containsKey(ARG_FEEDITEM_ID)) {
- AsyncTask<Void, Void, FeedItem> itemLoadTask = new AsyncTask<Void, Void, FeedItem>() {
-
- @Override
- protected FeedItem doInBackground(Void... voids) {
- return DBReader.getFeedItem(getArguments().getLong(ARG_FEEDITEM_ID));
- }
-
- @Override
- protected void onPostExecute(FeedItem feedItem) {
- super.onPostExecute(feedItem);
- shownotesProvider = feedItem;
- startLoader();
- }
- };
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- itemLoadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- itemLoadTask.execute();
- }
+ long id = getArguments().getLong(ARG_FEEDITEM_ID);
+ Observable.defer(() -> Observable.just(DBReader.getFeedItem(id)))
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(feedItem -> {
+ shownotesProvider = feedItem;
+ load();
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ });
}
-
-
- }
-
- @Override
- public void onResume() {
- super.onResume();
}
- @SuppressLint("NewApi")
- private void startLoader() {
- webViewLoader = createLoader();
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- webViewLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- webViewLoader.execute();
- }
- }
private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
@@ -338,49 +296,30 @@ public class ItemDescriptionFragment extends Fragment {
}
}
- private AsyncTask<Void, Void, Void> createLoader() {
- return new AsyncTask<Void, Void, Void>() {
- @Override
- protected void onCancelled() {
- super.onCancelled();
- webViewLoader = null;
- }
-
- String data;
-
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
- // /webvDescription.loadData(url, "text/html", "utf-8");
- webvDescription.loadDataWithBaseURL(null, data, "text/html",
- "utf-8", "about:blank");
- Log.d(TAG, "Webview loaded");
- webViewLoader = null;
- }
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- Log.d(TAG, "Loading Webview");
- try {
- Activity activity = getActivity();
- if (activity != null) {
- Timeline timeline = new Timeline(activity, shownotesProvider);
- data = timeline.processShownotes(highlightTimecodes);
- } else {
- cancel(true);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
+ private void load() {
+ Log.d(TAG, "load()");
+ if(webViewLoader != null) {
+ webViewLoader.unsubscribe();
+ }
+ if(shownotesProvider == null) {
+ return;
+ }
+ webViewLoader = Observable.defer(() -> Observable.just(loadData()))
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(data -> {
+ webvDescription.loadDataWithBaseURL(null, data, "text/html",
+ "utf-8", "about:blank");
+ Log.d(TAG, "Webview loaded");
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ });
+ }
- };
+ private String loadData() {
+ Timeline timeline = new Timeline(getActivity(), shownotesProvider);
+ String data = timeline.processShownotes(highlightTimecodes);
+ return data;
}
@Override
@@ -410,7 +349,7 @@ public class ItemDescriptionFragment extends Fragment {
}
private boolean restoreFromPreference() {
- if (saveState) {
+ if (!saveState) {
Log.d(TAG, "Restoring from preferences");
Activity activity = getActivity();
if (activity != null) {
@@ -433,15 +372,22 @@ public class ItemDescriptionFragment extends Fragment {
private void onTimecodeLinkSelected(String link) {
int time = Timeline.getTimecodeLinkTime(link);
- if (getActivity() != null && getActivity() instanceof ItemDescriptionFragmentCallback) {
- PlaybackController pc = ((ItemDescriptionFragmentCallback) getActivity()).getPlaybackController();
+ if (getActivity() != null && getActivity() instanceof AudioplayerActivity) {
+ PlaybackController pc = ((AudioplayerActivity) getActivity()).getPlaybackController();
if (pc != null) {
pc.seekTo(time);
}
}
}
- public interface ItemDescriptionFragmentCallback {
- public PlaybackController getPlaybackController();
+ @Override
+ public void onMediaChanged(Playable media) {
+ if(this.media == media || webvDescription == null) {
+ return;
+ }
+ this.media = media;
+ this.shownotesProvider = media;
+ load();
}
+
}
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 10d56d5cf..1382929af 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -4,35 +4,32 @@ import android.annotation.TargetApi;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
-import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
-import android.support.v4.util.Pair;
-import android.support.v7.widget.PopupMenu;
-import android.support.v7.widget.Toolbar;
+import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
-import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
-import android.widget.Button;
-import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
+import com.joanzapata.iconify.Iconify;
+import com.joanzapata.iconify.widget.IconButton;
import org.apache.commons.lang3.ArrayUtils;
@@ -43,6 +40,7 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
+import de.danoeh.antennapod.core.event.FavoritesEvent;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
@@ -57,6 +55,7 @@ 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.IntentUtils;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.ShareUtils;
@@ -97,11 +96,11 @@ public class ItemFragment extends Fragment {
private long itemID;
private FeedItem item;
private LongList queue;
+ private LongList favorites;
private String webviewData;
private List<Downloader> downloaderList;
private ViewGroup root;
- private View header;
private WebView webvDescription;
private TextView txtvTitle;
private TextView txtvDuration;
@@ -109,10 +108,9 @@ public class ItemFragment extends Fragment {
private ImageView imgvCover;
private ProgressBar progbarDownload;
private ProgressBar progbarLoading;
- private Button butAction1;
- private Button butAction2;
- private ImageButton butMore;
- private PopupMenu popupMenu;
+ private IconButton butAction1;
+ private IconButton butAction2;
+ private Menu popupMenu;
private Subscription subscription;
@@ -125,7 +123,7 @@ public class ItemFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
- setHasOptionsMenu(false);
+ setHasOptionsMenu(true);
itemID = getArguments().getLong(ARG_FEEDITEM, -1);
}
@@ -134,15 +132,12 @@ public class ItemFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
- ((MainActivity) getActivity()).getSupportActionBar().setTitle("");
- Toolbar toolbar = ((MainActivity) getActivity()).getToolbar();
View layout = inflater.inflate(R.layout.feeditem_fragment, container, false);
- header = inflater.inflate(R.layout.feeditem_fragment_header, toolbar, false);
root = (ViewGroup) layout.findViewById(R.id.content_root);
- txtvTitle = (TextView) header.findViewById(R.id.txtvTitle);
- txtvDuration = (TextView) header.findViewById(R.id.txtvDuration);
- txtvPublished = (TextView) header.findViewById(R.id.txtvPublished);
+ txtvTitle = (TextView) layout.findViewById(R.id.txtvTitle);
+ txtvDuration = (TextView) layout.findViewById(R.id.txtvDuration);
+ txtvPublished = (TextView) 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);
}
@@ -152,8 +147,7 @@ public class ItemFragment extends Fragment {
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
- webvDescription.setBackgroundColor(getResources().getColor(
- R.color.black));
+ webvDescription.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.black));
}
webvDescription.getSettings().setUseWideViewPort(false);
webvDescription.getSettings().setLayoutAlgorithm(
@@ -172,81 +166,43 @@ public class ItemFragment extends Fragment {
});
registerForContextMenu(webvDescription);
- imgvCover = (ImageView) header.findViewById(R.id.imgvCover);
- progbarDownload = (ProgressBar) header.findViewById(R.id.progbarDownload);
+ imgvCover = (ImageView) layout.findViewById(R.id.imgvCover);
+ progbarDownload = (ProgressBar) layout.findViewById(R.id.progbarDownload);
progbarLoading = (ProgressBar) layout.findViewById(R.id.progbarLoading);
- butAction1 = (Button) header.findViewById(R.id.butAction1);
- butAction2 = (Button) header.findViewById(R.id.butAction2);
- butMore = (ImageButton) header.findViewById(R.id.butMoreActions);
- popupMenu = new PopupMenu(getActivity(), butMore);
-
- butAction1.setOnClickListener(new View.OnClickListener() {
- DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getActivity());
-
- @Override
-
- public void onClick(View v) {
- if (item == null) {
- return;
- }
- actionButtonCallback.onActionButtonPressed(item);
- FeedMedia media = item.getMedia();
- if (media != null && media.isDownloaded()) {
- // playback was started, dialog should close itself
- ((MainActivity) getActivity()).dismissChildFragment();
- }
- }
- }
- );
+ butAction1 = (IconButton) layout.findViewById(R.id.butAction1);
+ butAction2 = (IconButton) layout.findViewById(R.id.butAction2);
- butAction2.setOnClickListener(v -> {
- if (item == null) {
- return;
- }
-
- if (item.hasMedia()) {
- FeedMedia media = item.getMedia();
- if (!media.isDownloaded()) {
- DBTasks.playMedia(getActivity(), media, true, true, true);
- ((MainActivity) getActivity()).dismissChildFragment();
- } else {
- DBWriter.deleteFeedMediaOfItem(getActivity(), media.getId());
- }
- } else if (item.getLink() != null) {
- Uri uri = Uri.parse(item.getLink());
- getActivity().startActivity(new Intent(Intent.ACTION_VIEW, uri));
- }
+ butAction1.setOnClickListener(v -> {
+ if (item == null) {
+ return;
}
- );
-
- butMore.setOnClickListener(v -> {
- if (item == null) {
- return;
- }
- popupMenu.getMenu().clear();
- popupMenu.inflate(R.menu.feeditem_options);
- if (item.hasMedia()) {
- FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue);
- } else {
- // these are already available via button1 and button2
- FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue,
- R.id.mark_read_item, R.id.visit_website_item);
- }
- popupMenu.show();
+ DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getActivity());
+ actionButtonCallback.onActionButtonPressed(item);
+ FeedMedia media = item.getMedia();
+ if (media != null && media.isDownloaded()) {
+ // playback was started, dialog should close itself
+ ((MainActivity) getActivity()).dismissChildFragment();
}
- );
+ });
- popupMenu.setOnMenuItemClickListener(menuItem -> {
+ butAction2.setOnClickListener(v -> {
+ if (item == null) {
+ return;
+ }
- try {
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
- return true;
+ if (item.hasMedia()) {
+ FeedMedia media = item.getMedia();
+ if (!media.isDownloaded()) {
+ DBTasks.playMedia(getActivity(), media, true, true, true);
+ ((MainActivity) getActivity()).dismissChildFragment();
+ } else {
+ DBWriter.deleteFeedMediaOfItem(getActivity(), media.getId());
}
+ } else if (item.getLink() != null) {
+ Uri uri = Uri.parse(item.getLink());
+ getActivity().startActivity(new Intent(Intent.ACTION_VIEW, uri));
}
- );
+ });
return layout;
}
@@ -254,8 +210,6 @@ public class ItemFragment extends Fragment {
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- Toolbar toolbar = ((MainActivity) getActivity()).getToolbar();
- toolbar.addView(header);
load();
}
@@ -279,7 +233,6 @@ public class ItemFragment extends Fragment {
@Override
public void onDestroyView() {
super.onDestroyView();
- resetViewState();
if(subscription != null) {
subscription.unsubscribe();
}
@@ -289,15 +242,37 @@ public class ItemFragment extends Fragment {
}
}
- private void resetViewState() {
- Toolbar toolbar = ((MainActivity) getActivity()).getToolbar();
- toolbar.removeView(header);
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if(!isAdded() || item == null) {
+ return;
+ }
+ inflater.inflate(R.menu.feeditem_options, menu);
+ popupMenu = menu;
+ if (item.hasMedia()) {
+ FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, queue, favorites);
+ } else {
+ // these are already available via button1 and button2
+ FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, queue, favorites,
+ R.id.mark_read_item, R.id.visit_website_item);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem menuItem) {
+ try {
+ return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
+ return true;
+ }
}
private final FeedItemMenuHandler.MenuInterface popupMenuInterface = new FeedItemMenuHandler.MenuInterface() {
@Override
public void setItemVisibility(int id, boolean visible) {
- MenuItem item = popupMenu.getMenu().findItem(id);
+ MenuItem item = popupMenu.findItem(id);
if (item != null) {
item.setVisible(visible);
}
@@ -319,11 +294,12 @@ public class ItemFragment extends Fragment {
Log.d(TAG, "updateAppearance item is null");
return;
}
-
+ getActivity().supportInvalidateOptionsMenu();
txtvTitle.setText(item.getTitle());
if (item.getPubDate() != null) {
- txtvPublished.setText(DateUtils.formatDateTime(getActivity(), item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL));
+ String pubDateStr = DateUtils.formatAbbrev(getActivity(), item.getPubDate());
+ txtvPublished.setText(pubDateStr);
}
Glide.with(getActivity())
@@ -335,7 +311,7 @@ public class ItemFragment extends Fragment {
.dontAnimate()
.into(imgvCover);
- progbarDownload.setVisibility(View.INVISIBLE);
+ progbarDownload.setVisibility(View.GONE);
if (item.hasMedia() && downloaderList != null) {
for (Downloader downloader : downloaderList) {
if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
@@ -347,54 +323,55 @@ public class ItemFragment extends Fragment {
}
FeedMedia media = item.getMedia();
+ String butAction1Icon = null;
+ int butAction1Text = 0;
+ String butAction2Icon = null;
+ int butAction2Text = 0;
if (media == null) {
- TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.navigation_accept,
- R.attr.location_web_site});
-
if (!item.isPlayed()) {
- butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(0), null, null, null);
- butAction1.setText(getActivity().getString(R.string.mark_read_label));
- butAction1.setVisibility(View.VISIBLE);
- } else {
- butAction1.setVisibility(View.INVISIBLE);
+ butAction1Icon = "{fa-check 24sp}";
+ butAction1Text = R.string.mark_read_label;
}
-
if (item.getLink() != null) {
- butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(1), null, null, null);
- butAction2.setText(getActivity().getString(R.string.visit_website_label));
- } else {
- butAction2.setEnabled(false);
+ butAction2Icon = "{md-web 24sp}";
+ butAction2Text = R.string.visit_website_label;
}
-
- drawables.recycle();
- } else {if(media.getDuration() > 0) {
+ } else {
+ if(media.getDuration() > 0) {
txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
}
-
boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
- TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.av_play,
- R.attr.av_download, R.attr.action_stream, R.attr.content_discard, R.attr.navigation_cancel});
-
if (!media.isDownloaded()) {
- butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(2), null, null, null);
- butAction2.setText(getActivity().getString(R.string.stream_label));
+ butAction2Icon = "{md-settings-input-antenna 24sp}";
+ butAction2Text = R.string.stream_label;
} else {
- butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(3), null, null, null);
- butAction2.setText(getActivity().getString(R.string.remove_episode_lable));
+ butAction2Icon = "{md-delete 24sp}";
+ butAction2Text = R.string.remove_label;
}
-
if (isDownloading) {
- butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(4), null, null, null);
- butAction1.setText(getActivity().getString(R.string.cancel_download_label));
+ butAction1Icon = "{md-cancel 24sp}";
+ butAction1Text = R.string.cancel_label;
} else if (media.isDownloaded()) {
- butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(0), null, null, null);
- butAction1.setText(getActivity().getString(R.string.play_label));
+ butAction1Icon = "{md-play-arrow 24sp}";
+ butAction1Text = R.string.play_label;
} else {
- butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(1), null, null, null);
- butAction1.setText(getActivity().getString(R.string.download_label));
+ butAction1Icon = "{md-file-download 24sp}";
+ butAction1Text = R.string.download_label;
}
-
- drawables.recycle();
+ }
+ if(butAction1Icon != null && butAction1Text != 0) {
+ butAction1.setText(butAction1Icon +"\u0020\u0020" + getActivity().getString(butAction1Text));
+ Iconify.addIcons(butAction1);
+ butAction1.setVisibility(View.VISIBLE);
+ } else {
+ butAction1.setVisibility(View.INVISIBLE);
+ }
+ if(butAction2Icon != null && butAction2Text != 0) {
+ butAction2.setText(butAction2Icon +"\u0020\u0020" + getActivity().getString(butAction2Text));
+ Iconify.addIcons(butAction2);
+ butAction2.setVisibility(View.VISIBLE);
+ } else {
+ butAction2.setVisibility(View.INVISIBLE);
}
}
@@ -481,6 +458,12 @@ public class ItemFragment extends Fragment {
}
}
+ public void onEventMainThread(FavoritesEvent event) {
+ if(event.item.getId() == itemID) {
+ load();
+ }
+ }
+
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
for(FeedItem item : event.items) {
@@ -524,8 +507,9 @@ public class ItemFragment extends Fragment {
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
- item = result.first;
- queue = result.second;
+ item = (FeedItem) result[0];
+ queue = (LongList) result[1];
+ favorites = (LongList) result[2];
if (!itemsLoaded) {
itemsLoaded = true;
onFragmentLoaded();
@@ -537,14 +521,25 @@ public class ItemFragment extends Fragment {
});
}
- private Pair<FeedItem,LongList> loadInBackground() {
- FeedItem data1 = DBReader.getFeedItem(itemID);
- if (data1 != null) {
- Timeline t = new Timeline(getActivity(), data1);
+ private Object[] loadInBackground() {
+ FeedItem feedItem = DBReader.getFeedItem(itemID);
+ if (feedItem != null) {
+ Timeline t = new Timeline(getActivity(), feedItem);
webviewData = t.processShownotes(false);
}
- LongList data2 = DBReader.getQueueIDList();
- return Pair.create(data1, data2);
+ LongList queue;
+ if(feedItem.isTagged(FeedItem.TAG_QUEUE)) {
+ queue = LongList.of(feedItem.getId());
+ } else {
+ queue = new LongList(0);
+ }
+ LongList favorites;
+ if(feedItem.isTagged(FeedItem.TAG_FAVORITE)) {
+ favorites = LongList.of(feedItem.getId());
+ } else {
+ favorites = new LongList(0);
+ }
+ return new Object[] { feedItem, queue, favorites };
}
}
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 09d2f5676..303d273bc 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -9,11 +9,8 @@ import android.graphics.Color;
import android.graphics.LightingColorFilter;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
-import android.support.v4.util.Pair;
import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.ContextMenu;
@@ -50,6 +47,7 @@ import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
+import de.danoeh.antennapod.core.event.FavoritesEvent;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
@@ -88,6 +86,7 @@ public class ItemlistFragment extends ListFragment {
private static final String TAG = "ItemlistFragment";
private static final int EVENTS = EventDistributor.UNREAD_ITEMS_UPDATE
+ | EventDistributor.FEED_LIST_UPDATE
| EventDistributor.PLAYER_STATUS_UPDATE;
public static final String EXTRA_SELECTED_FEEDITEM = "extra.de.danoeh.antennapod.activity.selected_feeditem";
@@ -100,6 +99,7 @@ public class ItemlistFragment extends ListFragment {
private long feedID;
private Feed feed;
private LongList queuedItemsIds;
+ private LongList favoritedItemsId;
private boolean itemsLoaded = false;
private boolean viewsCreated = false;
@@ -145,34 +145,26 @@ public class ItemlistFragment extends ListFragment {
@Override
public void onStart() {
super.onStart();
- EventDistributor.getInstance().register(contentUpdate);
- EventBus.getDefault().registerSticky(this);
if (viewsCreated && itemsLoaded) {
onFragmentLoaded();
}
}
@Override
- public void onStop() {
- super.onStop();
- EventDistributor.getInstance().unregister(contentUpdate);
- EventBus.getDefault().unregister(this);
- if(subscription != null) {
- subscription.unsubscribe();
- }
- }
-
- @Override
public void onResume() {
super.onResume();
- Log.d(TAG, "onResume()");
+ EventDistributor.getInstance().register(contentUpdate);
+ EventBus.getDefault().registerSticky(this);
+ ((MainActivity)getActivity()).getSupportActionBar().setTitle("");
updateProgressBarVisibility();
loadItems();
}
@Override
- public void onDetach() {
- super.onDetach();
+ public void onPause() {
+ super.onPause();
+ EventDistributor.getInstance().unregister(contentUpdate);
+ EventBus.getDefault().unregister(this);
if(subscription != null) {
subscription.unsubscribe();
}
@@ -203,6 +195,9 @@ public class ItemlistFragment extends ListFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if(!isAdded()) {
+ return;
+ }
super.onCreateOptionsMenu(menu, inflater);
if (itemsLoaded) {
@@ -257,8 +252,8 @@ public class ItemlistFragment extends ListFragment {
if (!FeedMenuHandler.onOptionsItemClicked(getActivity(), item, feed)) {
switch (item.getItemId()) {
case R.id.episode_actions:
- EpisodesApplyActionFragment fragment = new EpisodesApplyActionFragment();
- fragment.setEpisodes(feed.getItems());
+ EpisodesApplyActionFragment fragment = EpisodesApplyActionFragment
+ .newInstance(feed.getItems());
((MainActivity)getActivity()).loadChildFragment(fragment);
return true;
case R.id.remove_item:
@@ -330,7 +325,8 @@ public class ItemlistFragment extends ListFragment {
contextMenu = menu;
lastMenuInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
- FeedItemMenuHandler.onPrepareMenu(getActivity(), contextMenuInterface, item, true, queuedItemsIds);
+ FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, queuedItemsIds,
+ favoritedItemsId);
}
@Override
@@ -368,7 +364,6 @@ public class ItemlistFragment extends ListFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("");
registerForContextMenu(getListView());
@@ -380,9 +375,14 @@ public class ItemlistFragment extends ListFragment {
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
+ if(adapter == null) {
+ return;
+ }
FeedItem selection = adapter.getItem(position - l.getHeaderViewsCount());
if (selection != null) {
- ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(selection.getId()));
+ MainActivity activity = (MainActivity) getActivity();
+ activity.loadChildFragment(ItemFragment.newInstance(selection.getId()));
+ activity.getSupportActionBar().setTitle(feed.getTitle());
}
}
@@ -391,6 +391,11 @@ public class ItemlistFragment extends ListFragment {
loadItems();
}
+ public void onEvent(FavoritesEvent event) {
+ Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
+ loadItems();
+ }
+
public void onEvent(FeedEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
if(event.feedId == feedID) {
@@ -417,13 +422,11 @@ public class ItemlistFragment extends ListFragment {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if(update.feedIds.length > 0) {
+ if (isUpdatingFeed != event.update.feedIds.length > 0) {
updateProgressBarVisibility();
}
- if(update.mediaIds.length > 0) {
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
+ if(adapter != null && update.mediaIds.length > 0) {
+ adapter.notifyDataSetChanged();
}
}
@@ -549,15 +552,12 @@ public class ItemlistFragment extends ListFragment {
.dontAnimate()
.into(imgvCover);
- butShowInfo.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (viewsCreated && itemsLoaded) {
- Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class);
- startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID,
- feed.getId());
- startActivity(startIntent);
- }
+ butShowInfo.setOnClickListener(v -> {
+ if (viewsCreated && itemsLoaded) {
+ Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class);
+ startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID,
+ feed.getId());
+ startActivity(startIntent);
}
});
}
@@ -575,16 +575,13 @@ public class ItemlistFragment extends ListFragment {
View header = inflater.inflate(R.layout.more_content_list_footer, lv, false);
lv.addFooterView(header);
listFooter = new MoreContentListFooterUtil(header);
- listFooter.setClickListener(new MoreContentListFooterUtil.Listener() {
- @Override
- public void onClick() {
- if (feed != null) {
- try {
- DBTasks.loadNextPageOfFeed(getActivity(), feed, false);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage());
- }
+ listFooter.setClickListener(() -> {
+ if (feed != null) {
+ try {
+ DBTasks.loadNextPageOfFeed(getActivity(), feed, false);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage());
}
}
});
@@ -595,7 +592,11 @@ public class ItemlistFragment extends ListFragment {
@Override
public FeedItem getItem(int position) {
- return (feed != null) ? feed.getItemAtIndex(position) : null;
+ if (feed != null && 0 <= position && position < feed.getNumOfItems()) {
+ return feed.getItemAtIndex(position);
+ } else {
+ return null;
+ }
}
@Override
@@ -627,14 +628,14 @@ public class ItemlistFragment extends ListFragment {
if(subscription != null) {
subscription.unsubscribe();
}
-
subscription = Observable.fromCallable(() -> loadData())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
if (result != null) {
- feed = result.first;
- queuedItemsIds = result.second;
+ feed = (Feed) result[0];
+ queuedItemsIds = (LongList) result[1];
+ favoritedItemsId = (LongList) result[2];
itemsLoaded = true;
if (viewsCreated) {
onFragmentLoaded();
@@ -645,14 +646,15 @@ public class ItemlistFragment extends ListFragment {
});
}
- private Pair<Feed, LongList> loadData() {
+ private Object[] loadData() {
Feed feed = DBReader.getFeed(feedID);
if(feed != null && feed.getItemFilter() != null) {
FeedItemFilter filter = feed.getItemFilter();
feed.setItems(filter.filter(feed.getItems()));
}
LongList queuedItemsIds = DBReader.getQueueIDList();
- return Pair.create(feed, queuedItemsIds);
+ LongList favoritedItemsId = DBReader.getFavoriteIDList();
+ return new Object[] { feed, queuedItemsIds, favoritedItemsId };
}
}
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 72704245f..eb947dc2b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
@@ -1,22 +1,27 @@
package de.danoeh.antennapod.fragment;
import android.content.Intent;
-import android.content.res.Resources;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
+import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.SearchView;
+import android.util.Log;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
+import android.widget.Button;
import android.widget.GridView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.afollestad.materialdialogs.MaterialDialog;
+import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.Request;
+import com.squareup.okhttp.Response;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -26,31 +31,45 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.ClientConfig;
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import rx.Observable;
+import rx.Subscription;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.schedulers.Schedulers;
import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast;
//Searches iTunes store for given string and displays results in a list
public class ItunesSearchFragment extends Fragment {
- final String TAG = "ItunesSearchFragment";
- /**
- * Search input field
- */
- private SearchView searchView;
+
+ private static final String TAG = "ItunesSearchFragment";
+
+ private static final String API_URL = "https://itunes.apple.com/search?media=podcast&term=%s";
+
/**
* Adapter responsible with the search results
*/
private ItunesAdapter adapter;
+ private GridView gridView;
+ private ProgressBar progressBar;
+ private TextView txtvError;
+ private Button butRetry;
+ private TextView txtvEmpty;
/**
* List of podcasts retreived from the search
*/
private List<Podcast> searchResults;
+ private List<Podcast> topList;
+ private Subscription subscription;
/**
* Replace adapter data with provided search results from SearchTask.
@@ -59,13 +78,17 @@ public class ItunesSearchFragment extends Fragment {
void updateData(List<Podcast> result) {
this.searchResults = result;
adapter.clear();
-
- //ArrayAdapter.addAll() requires minsdk > 10
- for(Podcast p: result) {
- adapter.add(p);
+ if (result != null && result.size() > 0) {
+ gridView.setVisibility(View.VISIBLE);
+ txtvEmpty.setVisibility(View.GONE);
+ for (Podcast p : result) {
+ adapter.add(p);
+ }
+ adapter.notifyDataSetInvalidated();
+ } else {
+ gridView.setVisibility(View.GONE);
+ txtvEmpty.setVisibility(View.VISIBLE);
}
-
- adapter.notifyDataSetInvalidated();
}
/**
@@ -78,47 +101,105 @@ public class ItunesSearchFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- adapter = new ItunesAdapter(getActivity(), new ArrayList<Podcast>());
-
+ setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
- View view = inflater.inflate(R.layout.fragment_itunes_search, container, false);
- GridView gridView = (GridView) view.findViewById(R.id.gridView);
+ View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
+ gridView = (GridView) root.findViewById(R.id.gridView);
+ adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
gridView.setAdapter(adapter);
//Show information about the podcast when the list item is clicked
- gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- Intent intent = new Intent(getActivity(),
- OnlineFeedViewActivity.class);
-
- //Tell the OnlineFeedViewActivity where to go
- String url = searchResults.get(position).feedUrl;
- intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, url);
-
+ gridView.setOnItemClickListener((parent, view1, position, id) -> {
+ Podcast podcast = searchResults.get(position);
+ if (!podcast.feedUrl.contains("itunes.apple.com")) {
+ Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl);
intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, "iTunes");
startActivity(intent);
+ } else {
+ gridView.setVisibility(View.GONE);
+ progressBar.setVisibility(View.VISIBLE);
+ rx.Observable.create((Observable.OnSubscribe<String>) subscriber -> {
+ OkHttpClient client = AntennapodHttpClient.getHttpClient();
+ Request.Builder httpReq = new Request.Builder()
+ .url(podcast.feedUrl)
+ .header("User-Agent", ClientConfig.USER_AGENT);
+ try {
+ Response response = client.newCall(httpReq.build()).execute();
+ if (response.isSuccessful()) {
+ String resultString = response.body().string();
+ JSONObject result = new JSONObject(resultString);
+ JSONObject results = result.getJSONArray("results").getJSONObject(0);
+ String feedUrl = results.getString("feedUrl");
+ subscriber.onNext(feedUrl);
+ } else {
+ String prefix = getString(R.string.error_msg_prefix);
+ subscriber.onError(new IOException(prefix + response));
+ }
+ } catch (IOException | JSONException e) {
+ subscriber.onError(e);
+ }
+ subscriber.onCompleted();
+ })
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(feedUrl -> {
+ progressBar.setVisibility(View.GONE);
+ gridView.setVisibility(View.VISIBLE);
+ Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, feedUrl);
+ intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, "iTunes");
+ startActivity(intent);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ gridView.setVisibility(View.VISIBLE);
+ String prefix = getString(R.string.error_msg_prefix);
+ new MaterialDialog.Builder(getActivity())
+ .content(prefix + " " + error.getMessage())
+ .neutralText(android.R.string.ok)
+ .show();
+ });
}
});
+ 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);
+
+ loadToplist();
+
+ return root;
+ }
- //Configure search input view to be expanded by default with a visible submit button
- searchView = (SearchView) view.findViewById(R.id.itunes_search_view);
- searchView.setIconifiedByDefault(false);
- searchView.setIconified(false);
- searchView.setSubmitButtonEnabled(true);
- searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (subscription != null) {
+ subscription.unsubscribe();
+ }
+ adapter = null;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.itunes_search, menu);
+ MenuItem searchItem = menu.findItem(R.id.action_search);
+ final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
+ MenuItemUtils.adjustTextColor(getActivity(), sv);
+ sv.setQueryHint(getString(R.string.search_itunes_label));
+ sv.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
- //This prevents onQueryTextSubmit() from being called twice when keyboard is used
- //to submit the query.
- searchView.clearFocus();
- new SearchTask(s).execute();
- return false;
+ sv.clearFocus();
+ search(s);
+ return true;
}
@Override
@@ -126,88 +207,153 @@ public class ItunesSearchFragment extends Fragment {
return false;
}
});
-
- SearchView.SearchAutoComplete textField = (SearchView.SearchAutoComplete) searchView.findViewById(de.danoeh.antennapod.R.id.search_src_text);
- if(UserPreferences.getTheme() == de.danoeh.antennapod.R.style.Theme_AntennaPod_Dark) {
- textField.setTextColor(Resources.getSystem().getColor(android.R.color.white));
- } else {
- textField.setTextColor(Resources.getSystem().getColor(android.R.color.black));
- }
-
- return view;
- }
-
- /**
- * Search the iTunes store for podcasts using the given query
- */
- class SearchTask extends AsyncTask<Void,Void,Void> {
- /**
- * Incomplete iTunes API search URL
- */
- final String apiUrl = "https://itunes.apple.com/search?media=podcast&term=%s";
-
- /**
- * Search terms
- */
- final String query;
-
- /**
- * Search result
- */
- final List<Podcast> taskData = new ArrayList<>();
-
- /**
- * Constructor
- *
- * @param query Search string
- */
- public SearchTask(String query) {
- String encodedQuery = null;
- try {
- encodedQuery = URLEncoder.encode(query, "UTF-8");
- } catch(UnsupportedEncodingException e) {
- // this won't ever be thrown
- }
- if(encodedQuery != null) {
- this.query = encodedQuery;
- } else {
- this.query = query; // failsafe
+ MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ return true;
}
- }
- //Get the podcast data
- @Override
- protected Void doInBackground(Void... params) {
-
- //Spaces in the query need to be replaced with '+' character.
- String formattedUrl = String.format(apiUrl, query).replace(' ', '+');
-
- HttpClient client = new DefaultHttpClient();
- HttpGet get = new HttpGet(formattedUrl);
-
- try {
- HttpResponse response = client.execute(get);
- String resultString = EntityUtils.toString(response.getEntity());
- JSONObject result = new JSONObject(resultString);
- JSONArray j = result.getJSONArray("results");
-
- for (int i = 0; i < j.length(); i++){
- JSONObject podcastJson = j.getJSONObject(i);
- Podcast podcast = new Podcast(podcastJson);
- taskData.add(podcast);
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ if(searchResults != null) {
+ searchResults = null;
+ updateData(topList);
}
-
- } catch (IOException | JSONException e) {
- e.printStackTrace();
+ return true;
}
- return null;
+ });
+ }
+
+ private void loadToplist() {
+ if (subscription != null) {
+ subscription.unsubscribe();
}
+ 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 -> {
+ String lang = Locale.getDefault().getLanguage();
+ String url = "https://itunes.apple.com/" + lang + "/rss/toppodcasts/limit=25/explicit=true/json";
+ OkHttpClient client = AntennapodHttpClient.getHttpClient();
+ Request.Builder httpReq = new Request.Builder()
+ .url(url)
+ .header("User-Agent", ClientConfig.USER_AGENT);
+ List<Podcast> results = new ArrayList<>();
+ try {
+ Response response = client.newCall(httpReq.build()).execute();
+ if(!response.isSuccessful()) {
+ // toplist for language does not exist, fall back to united states
+ url = "https://itunes.apple.com/us/rss/toppodcasts/limit=25/explicit=true/json";
+ httpReq = new Request.Builder()
+ .url(url)
+ .header("User-Agent", ClientConfig.USER_AGENT);
+ response = client.newCall(httpReq.build()).execute();
+ }
+ if(response.isSuccessful()) {
+ String resultString = response.body().string();
+ JSONObject result = new JSONObject(resultString);
+ JSONObject feed = result.getJSONObject("feed");
+ JSONArray entries = feed.getJSONArray("entry");
+
+ for(int i=0; i < entries.length(); i++) {
+ JSONObject json = entries.getJSONObject(i);
+ Podcast podcast = Podcast.fromToplist(json);
+ results.add(podcast);
+ }
+ }
+ else {
+ String prefix = getString(R.string.error_msg_prefix);
+ subscriber.onError(new IOException(prefix + response));
+ }
+ } catch (IOException | JSONException e) {
+ subscriber.onError(e);
+ }
+ subscriber.onNext(results);
+ subscriber.onCompleted();
+ })
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(podcasts -> {
+ progressBar.setVisibility(View.GONE);
+ topList = podcasts;
+ updateData(topList);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ txtvError.setText(error.toString());
+ txtvError.setVisibility(View.VISIBLE);
+ butRetry.setOnClickListener(v -> loadToplist());
+ butRetry.setVisibility(View.VISIBLE);
+ });
+ }
- //Save the data and update the list
- @Override
- protected void onPostExecute(Void aVoid) {
- super.onPostExecute(aVoid);
- updateData(taskData);
+ private void search(String query) {
+ if (subscription != null) {
+ subscription.unsubscribe();
}
+ 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 -> {
+ String encodedQuery = null;
+ try {
+ encodedQuery = URLEncoder.encode(query, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // this won't ever be thrown
+ }
+ if (encodedQuery == null) {
+ encodedQuery = query; // failsafe
+ }
+
+ //Spaces in the query need to be replaced with '+' character.
+ String formattedUrl = String.format(API_URL, query).replace(' ', '+');
+
+ OkHttpClient client = AntennapodHttpClient.getHttpClient();
+ Request.Builder httpReq = new Request.Builder()
+ .url(formattedUrl)
+ .header("User-Agent", ClientConfig.USER_AGENT);
+ List<Podcast> podcasts = new ArrayList<>();
+ try {
+ Response response = client.newCall(httpReq.build()).execute();
+
+ if(response.isSuccessful()) {
+ String resultString = response.body().string();
+ JSONObject result = new JSONObject(resultString);
+ JSONArray j = result.getJSONArray("results");
+
+ for (int i = 0; i < j.length(); i++) {
+ JSONObject podcastJson = j.getJSONObject(i);
+ Podcast podcast = Podcast.fromSearch(podcastJson);
+ podcasts.add(podcast);
+ }
+ }
+ else {
+ String prefix = getString(R.string.error_msg_prefix);
+ subscriber.onError(new IOException(prefix + response));
+ }
+ } catch (IOException | JSONException e) {
+ subscriber.onError(e);
+ }
+ subscriber.onNext(podcasts);
+ subscriber.onCompleted();
+ })
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(podcasts -> {
+ progressBar.setVisibility(View.GONE);
+ updateData(podcasts);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ txtvError.setText(error.toString());
+ txtvError.setVisibility(View.VISIBLE);
+ butRetry.setOnClickListener(v -> search(query));
+ butRetry.setVisibility(View.VISIBLE);
+ });
}
+
}
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 b47a197c3..c5b77fae2 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.fragment;
-import android.app.Activity;
+import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
@@ -14,7 +14,6 @@ import android.view.View;
import android.widget.ListView;
import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
@@ -22,10 +21,10 @@ import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
+import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
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.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
@@ -50,16 +49,13 @@ public class PlaybackHistoryFragment extends ListFragment {
private boolean itemsLoaded = false;
private boolean viewsCreated = false;
- private AtomicReference<Activity> activity = new AtomicReference<Activity>();
-
private List<Downloader> downloaderList;
private Subscription subscription;
@Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- this.activity.set(activity);
+ public void onAttach(Context context) {
+ super.onAttach(context);
if (viewsCreated && itemsLoaded) {
onFragmentLoaded();
}
@@ -123,7 +119,6 @@ public class PlaybackHistoryFragment extends ListFragment {
if(subscription != null) {
subscription.unsubscribe();
}
- activity.set(null);
}
@Override
@@ -138,7 +133,7 @@ public class PlaybackHistoryFragment extends ListFragment {
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
if (adapter != null) {
- adapter.notifyDataSetChanged();
+ adapter.notifyDataSetChanged();
}
}
@@ -153,6 +148,9 @@ public class PlaybackHistoryFragment extends ListFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if(!isAdded()) {
+ return;
+ }
super.onCreateOptionsMenu(menu, inflater);
if (itemsLoaded) {
MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
@@ -210,7 +208,8 @@ public class PlaybackHistoryFragment extends ListFragment {
// played items shoudln't be transparent for this fragment since, *all* items
// in this fragment will, by definition, be played. So it serves no purpose and can make
// it harder to read.
- adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(activity.get()), true, false);
+ adapter = new FeedItemlistAdapter(getActivity(), itemAccess,
+ new DefaultActionButtonCallback(getActivity()), true, false);
setListAdapter(adapter);
}
setListShown(true);
@@ -244,7 +243,11 @@ public class PlaybackHistoryFragment extends ListFragment {
@Override
public FeedItem getItem(int position) {
- return (playbackHistory != null) ? playbackHistory.get(position) : null;
+ if (playbackHistory != null && 0 <= position && position < playbackHistory.size()) {
+ return playbackHistory.get(position);
+ } else {
+ return 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 46bbfd13c..b3f6c3534 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -10,6 +10,7 @@ import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
+import android.support.v7.widget.SimpleItemAnimator;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.LayoutInflater;
@@ -67,6 +68,7 @@ public class QueueFragment extends Fragment {
public static final String TAG = "QueueFragment";
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
+ EventDistributor.UNREAD_ITEMS_UPDATE | // sent when playback position is reset
EventDistributor.PLAYER_STATUS_UPDATE;
private TextView infoBar;
@@ -179,13 +181,15 @@ public class QueueFragment extends Fragment {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if (update.feedIds.length > 0) {
- if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
- getActivity().supportInvalidateOptionsMenu();
- }
- } else if (update.mediaIds.length > 0) {
- if (recyclerAdapter != null) {
- recyclerAdapter.notifyDataSetChanged();
+ if (isUpdatingFeeds != update.feedIds.length > 0) {
+ getActivity().supportInvalidateOptionsMenu();
+ }
+ if (recyclerAdapter != null && update.mediaIds.length > 0) {
+ for (long mediaId : update.mediaIds) {
+ int pos = FeedItemUtil.indexOfItemWithMediaId(queue, mediaId);
+ if (pos >= 0) {
+ recyclerAdapter.notifyItemChanged(pos);
+ }
}
}
}
@@ -232,6 +236,9 @@ public class QueueFragment extends Fragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if(!isAdded()) {
+ return;
+ }
super.onCreateOptionsMenu(menu, inflater);
if (queue != null) {
inflater.inflate(R.menu.queue, menu);
@@ -265,10 +272,17 @@ public class QueueFragment extends Fragment {
if (!super.onOptionsItemSelected(item)) {
switch (item.getItemId()) {
case R.id.queue_lock:
- boolean locked = !UserPreferences.isQueueLocked();
- UserPreferences.setQueueLocked(locked);
+ boolean newLockState = !UserPreferences.isQueueLocked();
+ UserPreferences.setQueueLocked(newLockState);
getActivity().supportInvalidateOptionsMenu();
- recyclerAdapter.setLocked(locked);
+ recyclerAdapter.setLocked(newLockState);
+ if (newLockState) {
+ Snackbar.make(getActivity().findViewById(R.id.content), R.string
+ .queue_locked, Snackbar.LENGTH_SHORT).show();
+ } else {
+ Snackbar.make(getActivity().findViewById(R.id.content), R.string
+ .queue_unlocked, Snackbar.LENGTH_SHORT).show();
+ }
return true;
case R.id.refresh_item:
List<Feed> feeds = ((MainActivity) getActivity()).getFeeds();
@@ -363,6 +377,10 @@ public class QueueFragment extends Fragment {
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);
+ RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
+ if (animator instanceof SimpleItemAnimator) {
+ ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
+ }
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());
@@ -500,7 +518,7 @@ public class QueueFragment extends Fragment {
@Override
public FeedItem getItem(int position) {
- if(queue != null && position < queue.size()) {
+ if (queue != null && 0 <= position && position < queue.size()) {
return queue.get(position);
}
return null;
@@ -550,6 +568,20 @@ public class QueueFragment extends Fragment {
public LongList getQueueIds() {
return queue != null ? LongList.of(FeedItemUtil.getIds(queue)) : new LongList(0);
}
+
+ @Override
+ public LongList getFavoritesIds() {
+ LongList favoritesIds = new LongList();
+ if(queue == null) {
+ return favoritesIds;
+ }
+ for(FeedItem item : queue) {
+ if(item.isTagged(FeedItem.TAG_FAVORITE)) {
+ favoritesIds.add(item.getId());
+ }
+ }
+ return favoritesIds;
+ }
};
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
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 d81d18640..ba526edb3 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
@@ -83,7 +83,11 @@ public class RunningDownloadsFragment extends ListFragment {
@Override
public Downloader getItem(int position) {
- return (downloaderList != null) ? downloaderList.get(position) : null;
+ if (downloaderList != null && 0 <= position && position < downloaderList.size()) {
+ return downloaderList.get(position);
+ } else {
+ return null;
+ }
}
@Override
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 43354ad28..dbd18163c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -4,7 +4,7 @@ import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.Menu;
@@ -116,7 +116,7 @@ public class SearchFragment extends ListFragment {
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
lv.setPadding(0, vertPadding, 0, vertPadding);
- ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle(R.string.search_label);
+ ((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.search_label);
viewCreated = true;
if (itemsLoaded) {
onFragmentLoaded();
@@ -192,7 +192,11 @@ public class SearchFragment extends ListFragment {
@Override
public SearchResult getItem(int position) {
- return (searchResults != null) ? searchResults.get(position) : null;
+ if (searchResults != null && 0 <= position && position < searchResults.size()) {
+ return searchResults.get(position);
+ } else {
+ return null;
+ }
}
};
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
index e2450f03d..d39829260 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
@@ -45,7 +45,7 @@ public class TagFragment extends PodcastListFragment {
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- ((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(tag.getTitle());
+ ((MainActivity) getActivity()).getSupportActionBar().setTitle(tag.getTitle());
}
@Override
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 5bd567a2f..338f02e61 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
@@ -80,7 +80,7 @@ public class TagListFragment extends ListFragment {
@Override
public void onResume() {
super.onResume();
- ((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(R.string.add_feed_label);
+ ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.add_feed_label);
}
@Override
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 0197cc88c..58fe8afbf 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
@@ -57,22 +57,25 @@ public class FeedItemMenuHandler {
* @param queueAccess Used for testing if the queue contains the selected item
* @return Returns true if selectedItem is not null.
*/
- public static boolean onPrepareMenu(Context context, MenuInterface mi, FeedItem selectedItem,
- boolean showExtendedMenu, LongList queueAccess) {
+ public static boolean onPrepareMenu(MenuInterface mi,
+ FeedItem selectedItem,
+ boolean showExtendedMenu,
+ LongList queueAccess,
+ LongList favorites) {
if (selectedItem == null) {
return false;
}
boolean hasMedia = selectedItem.getMedia() != null;
- boolean isPlaying = hasMedia
- && selectedItem.getState() == FeedItem.State.PLAYING;
-
- FeedItem.State state = selectedItem.getState();
+ boolean isPlaying = hasMedia && selectedItem.getState() == FeedItem.State.PLAYING;
if (!isPlaying) {
mi.setItemVisibility(R.id.skip_episode_item, false);
}
- boolean isInQueue = selectedItem.isTagged(FeedItem.TAG_QUEUE);
+ boolean isInQueue = false;
+ if(queueAccess != null) {
+ isInQueue = queueAccess.contains(selectedItem.getId());
+ }
if(queueAccess == null || queueAccess.size() == 0 || queueAccess.get(0) == selectedItem.getId()) {
mi.setItemVisibility(R.id.move_to_top_item, false);
}
@@ -123,7 +126,7 @@ public class FeedItemMenuHandler {
mi.setItemVisibility(R.id.support_item, false);
}
- boolean isFavorite = selectedItem.isTagged(FeedItem.TAG_FAVORITE);
+ boolean isFavorite = favorites != null && favorites.contains(selectedItem.getId());
mi.setItemVisibility(R.id.add_to_favorites_item, !isFavorite);
mi.setItemVisibility(R.id.remove_from_favorites_item, isFavorite);
@@ -137,9 +140,13 @@ public class FeedItemMenuHandler {
* @param excludeIds Menu item that should be excluded
* @return true if selectedItem is not null.
*/
- public static boolean onPrepareMenu(Context context, MenuInterface mi, FeedItem selectedItem,
- boolean showExtendedMenu, LongList queueAccess, int... excludeIds) {
- boolean rc = onPrepareMenu(context, mi, selectedItem, showExtendedMenu, queueAccess);
+ public static boolean onPrepareMenu(MenuInterface mi,
+ FeedItem selectedItem,
+ boolean showExtendedMenu,
+ LongList queueAccess,
+ LongList favorites,
+ int... excludeIds) {
+ boolean rc = onPrepareMenu(mi, selectedItem, showExtendedMenu, queueAccess, favorites);
if (rc && excludeIds != null) {
for (int id : excludeIds) {
mi.setItemVisibility(id, false);
@@ -178,7 +185,7 @@ public class FeedItemMenuHandler {
case R.id.mark_unread_item:
selectedItem.setPlayed(false);
DBWriter.markItemPlayed(selectedItem, FeedItem.UNPLAYED, false);
- if(GpodnetPreferences.loggedIn()) {
+ if(GpodnetPreferences.loggedIn() && selectedItem.getMedia() != null) {
GpodnetEpisodeAction actionNew = new GpodnetEpisodeAction.Builder(selectedItem, Action.NEW)
.currentDeviceId()
.currentTimestamp()
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 84da32a40..38030f4ea 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -5,15 +5,17 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AlertDialog;
+import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
@@ -61,13 +63,13 @@ public class FeedMenuHandler {
final Feed selectedFeed) throws DownloadRequestException {
switch (item.getItemId()) {
case R.id.refresh_item:
- DBTasks.refreshFeed(context, selectedFeed);
+ DBTasks.forceRefreshFeed(context, selectedFeed);
break;
case R.id.refresh_complete_item:
- DBTasks.refreshCompleteFeed(context, selectedFeed);
+ DBTasks.forceRefreshCompleteFeed(context, selectedFeed);
break;
- case R.id.hide_items:
- showHideDialog(context, selectedFeed);
+ case R.id.filter_items:
+ showFilterDialog(context, selectedFeed);
break;
case R.id.mark_all_read_item:
ConfirmationDialog conDialog = new ConfirmationDialog(context,
@@ -108,38 +110,38 @@ public class FeedMenuHandler {
return true;
}
- private static void showHideDialog(final Context context, final Feed feed) {
-
- final String[] items = context.getResources().getStringArray(R.array.episode_hide_options);
- final String[] values = context.getResources().getStringArray(R.array.episode_hide_values);
+ private static void showFilterDialog(final Context context, final Feed feed) {
+ final String[] items = context.getResources().getStringArray(R.array.episode_filter_options);
+ final String[] values = context.getResources().getStringArray(R.array.episode_filter_values);
final boolean[] checkedItems = new boolean[items.length];
- final List<String> hidden = new ArrayList<String>(Arrays.asList(feed.getItemFilter().getValues()));
+ final Set<String> filter = new HashSet<>(Arrays.asList(feed.getItemFilter().getValues()));
+ Iterator<String> it = filter.iterator();
+ while(it.hasNext()) {
+ // make sure we have no empty strings in the filter list
+ if(TextUtils.isEmpty(it.next())) {
+ it.remove();
+ }
+ }
for(int i=0; i < values.length; i++) {
String value = values[i];
- if(hidden.contains(value)) {
+ if(filter.contains(value)) {
checkedItems[i] = true;
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.hide_episodes_title);
- builder.setMultiChoiceItems(items, checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which, boolean isChecked) {
- if (isChecked) {
- hidden.add(values[which]);
- } else {
- hidden.remove(values[which]);
- }
+ builder.setTitle(R.string.filter);
+ builder.setMultiChoiceItems(items, checkedItems, (dialog, which, isChecked) -> {
+ if (isChecked) {
+ filter.add(values[which]);
+ } else {
+ filter.remove(values[which]);
}
});
- builder.setPositiveButton(R.string.confirm_label, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- feed.setHiddenItemProperties(hidden.toArray(new String[hidden.size()]));
- DBWriter.setFeedItemsFilter(feed.getId(), hidden);
- }
+ builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
+ feed.setItemFilter(filter.toArray(new String[filter.size()]));
+ DBWriter.setFeedItemsFilter(feed.getId(), filter);
});
builder.setNegativeButton(R.string.cancel_label, null);
builder.create().show();
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 cfc540fd6..0d2ff8a75 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
@@ -34,10 +34,10 @@ public class MenuItemUtils extends de.danoeh.antennapod.core.menuhandler.MenuIte
TypedArray ta = context.obtainStyledAttributes(lockIcons);
if (UserPreferences.isQueueLocked()) {
queueLock.setTitle(de.danoeh.antennapod.R.string.unlock_queue);
- queueLock.setIcon(ta.getDrawable(1));
+ queueLock.setIcon(ta.getDrawable(0));
} else {
queueLock.setTitle(de.danoeh.antennapod.R.string.lock_queue);
- queueLock.setIcon(ta.getDrawable(0));
+ queueLock.setIcon(ta.getDrawable(1));
}
}
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 94f5d822e..c563d278f 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
@@ -1,12 +1,13 @@
package de.danoeh.antennapod.preferences;
+import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.TimePickerDialog;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.net.wifi.WifiConfiguration;
@@ -18,6 +19,7 @@ import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
+import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
@@ -30,10 +32,15 @@ import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
+import org.apache.commons.lang3.ArrayUtils;
+
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.CrashReportWriter;
import de.danoeh.antennapod.R;
@@ -80,6 +87,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
private CheckBoxPreference[] selectedNetworks;
+ private static final String[] EXTERNAL_STORAGE_PERMISSIONS = {
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE };
+ private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 41;
+
public PreferenceController(PreferenceUI ui) {
this.ui = ui;
PreferenceManager.getDefaultSharedPreferences(ui.getActivity().getApplicationContext())
@@ -116,54 +128,51 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
// disable expanded notification option on unsupported android versions
ui.findPreference(PreferenceController.PREF_EXPANDED_NOTIFICATION).setEnabled(false);
ui.findPreference(PreferenceController.PREF_EXPANDED_NOTIFICATION).setOnPreferenceClickListener(
- new Preference.OnPreferenceClickListener() {
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- Toast toast = Toast.makeText(activity, R.string.pref_expand_notify_unsupport_toast, Toast.LENGTH_SHORT);
- toast.show();
- return true;
- }
+ preference -> {
+ Toast toast = Toast.makeText(activity,
+ R.string.pref_expand_notify_unsupport_toast, Toast.LENGTH_SHORT);
+ toast.show();
+ return true;
}
);
}
-
ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setOnPreferenceClickListener(
- new Preference.OnPreferenceClickListener() {
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- FlattrUtils.revokeAccessToken(activity);
- checkItemVisibility();
- return true;
- }
-
+ preference -> {
+ FlattrUtils.revokeAccessToken(activity);
+ checkItemVisibility();
+ return true;
}
);
-
ui.findPreference(PreferenceController.PREF_ABOUT).setOnPreferenceClickListener(
- new Preference.OnPreferenceClickListener() {
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- activity.startActivity(new Intent(
- activity, AboutActivity.class));
- return true;
- }
-
+ preference -> {
+ activity.startActivity(new Intent(activity, AboutActivity.class));
+ return true;
}
);
-
ui.findPreference(PreferenceController.PREF_OPML_EXPORT).setOnPreferenceClickListener(
- new Preference.OnPreferenceClickListener() {
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- new OpmlExportWorker(activity)
- .executeAsync();
-
- return true;
+ preference -> {
+ new OpmlExportWorker(activity).executeAsync();
+ return true;
+ }
+ );
+ ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
+ preference -> {
+ if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
+ Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ showChooseDataFolderDialog();
+ } else {
+ int readPermission = ActivityCompat.checkSelfPermission(
+ activity, Manifest.permission.READ_EXTERNAL_STORAGE);
+ int writePermission = ActivityCompat.checkSelfPermission(
+ activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ if (readPermission == PackageManager.PERMISSION_GRANTED &&
+ writePermission == PackageManager.PERMISSION_GRANTED) {
+ openDirectoryChooser();
+ } else {
+ requestPermission();
+ }
}
+ return true;
}
);
ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR)
@@ -180,88 +189,68 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
}
return true;
}
- }
- );
+ }
+ );
ui.findPreference(UserPreferences.PREF_THEME)
.setOnPreferenceChangeListener(
- new Preference.OnPreferenceChangeListener() {
-
- @Override
- public boolean onPreferenceChange(
- Preference preference, Object 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;
- }
+ (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(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- showDrawerPreferencesDialog();
- return true;
- }
+ .setOnPreferenceClickListener(preference -> {
+ showDrawerPreferencesDialog();
+ return true;
});
ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL)
- .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- showUpdateIntervalTimePreferencesDialog();
- return true;
- }
+ .setOnPreferenceClickListener(preference -> {
+ showUpdateIntervalTimePreferencesDialog();
+ return true;
});
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL)
- .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (newValue instanceof Boolean) {
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled((Boolean) newValue);
- setSelectedNetworksEnabled((Boolean) newValue && UserPreferences.isEnableAutodownloadWifiFilter());
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY).setEnabled((Boolean) newValue);
- }
- return true;
+ 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(
- new Preference.OnPreferenceChangeListener() {
-
- @Override
- public boolean onPreferenceChange(
- Preference preference, Object newValue) {
- if (newValue instanceof Boolean) {
- setSelectedNetworksEnabled((Boolean) newValue);
- return true;
- } else {
- return false;
- }
+ (preference, newValue) -> {
+ if (newValue instanceof Boolean) {
+ setSelectedNetworksEnabled((Boolean) newValue);
+ return true;
+ } else {
+ return false;
}
}
);
ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)
.setOnPreferenceChangeListener(
- new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object o) {
- if (o instanceof String) {
- try {
- int value = Integer.valueOf((String) o);
- if (1 <= value && value <= 50) {
- setParallelDownloadsText(value);
- return true;
- }
- } catch (NumberFormatException e) {
- return false;
+ (preference, o) -> {
+ if (o instanceof String) {
+ try {
+ int value = Integer.valueOf((String) o);
+ if (1 <= value && value <= 50) {
+ setParallelDownloadsText(value);
+ return true;
}
+ } catch (NumberFormatException e) {
+ return false;
}
- return false;
}
+ return false;
}
);
// validate and set correct value: number of downloads between 1 and 50 (inclusive)
@@ -294,111 +283,87 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
});
ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE)
.setOnPreferenceChangeListener(
- new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object o) {
- if (o instanceof String) {
- setEpisodeCacheSizeText(UserPreferences.readEpisodeCacheSize((String) o));
- }
- return true;
+ (preference, o) -> {
+ if (o instanceof String) {
+ setEpisodeCacheSizeText(UserPreferences.readEpisodeCacheSize((String) o));
}
+ return true;
}
);
ui.findPreference(PreferenceController.PREF_PLAYBACK_SPEED_LAUNCHER)
- .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- VariableSpeedDialog.showDialog(activity);
- return true;
- }
+ .setOnPreferenceClickListener(preference -> {
+ VariableSpeedDialog.showDialog(activity);
+ return true;
});
- ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- AuthenticationDialog dialog = new AuthenticationDialog(activity,
- R.string.pref_gpodnet_setlogin_information_title, false, false, GpodnetPreferences.getUsername(),
- null) {
-
- @Override
- protected void onConfirmed(String username, String password, boolean saveUsernamePassword) {
- GpodnetPreferences.setPassword(password);
- }
- };
- dialog.show();
- return true;
- }
- });
- ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- GpodnetPreferences.logout();
- Toast toast = Toast.makeText(activity, R.string.pref_gpodnet_logout_toast, Toast.LENGTH_SHORT);
- toast.show();
- updateGpodnetPreferenceScreen();
- return true;
- }
- });
- ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(new DialogInterface.OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- updateGpodnetPreferenceScreen();
- }
+ ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION)
+ .setOnPreferenceClickListener(preference -> {
+ AuthenticationDialog dialog = new AuthenticationDialog(activity,
+ R.string.pref_gpodnet_setlogin_information_title, false, false, GpodnetPreferences.getUsername(),
+ null) {
+
+ @Override
+ protected void onConfirmed(String username, String password, boolean saveUsernamePassword) {
+ GpodnetPreferences.setPassword(password);
+ }
+ };
+ dialog.show();
+ return true;
+ });
+ ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(
+ preference -> {
+ GpodnetPreferences.logout();
+ Toast toast = Toast.makeText(activity, R.string.pref_gpodnet_logout_toast, Toast.LENGTH_SHORT);
+ toast.show();
+ updateGpodnetPreferenceScreen();
+ return true;
+ });
+ ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setOnPreferenceClickListener(
+ preference -> {
+ GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(dialog -> updateGpodnetPreferenceScreen());
+ return true;
});
- return true;
- }
- });
- ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity,
- new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() {
- @Override
- public void onCancelled() {
+ ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS)
+ .setOnPreferenceClickListener(preference -> {
+ AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity,
+ new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() {
+ @Override
+ public void onCancelled() {
- }
+ }
- @Override
- public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) {
- UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue);
- checkItemVisibility();
- }
- });
- return true;
- }
- });
- ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE)
- .setOnPreferenceChangeListener(
- new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object o) {
- if (o instanceof String) {
- int newValue = Integer.valueOf((String) o) * 1024 * 1024;
- if (newValue != UserPreferences.getImageCacheSize()) {
- AlertDialog.Builder dialog = new AlertDialog.Builder(ui.getActivity());
- dialog.setTitle(android.R.string.dialog_alert_title);
- dialog.setMessage(R.string.pref_restart_required);
- dialog.setPositiveButton(android.R.string.ok, null);
- dialog.show();
- }
- return true;
+ @Override
+ public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) {
+ UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue);
+ checkItemVisibility();
}
- return false;
- }
+ });
+ return true;
+ });
+ ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE).setOnPreferenceChangeListener(
+ (preference, o) -> {
+ if (o instanceof String) {
+ int newValue = Integer.valueOf((String) o) * 1024 * 1024;
+ if (newValue != UserPreferences.getImageCacheSize()) {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(ui.getActivity());
+ dialog.setTitle(android.R.string.dialog_alert_title);
+ dialog.setMessage(R.string.pref_restart_required);
+ dialog.setPositiveButton(android.R.string.ok, null);
+ dialog.show();
}
- );
+ return true;
+ }
+ return false;
+ }
+ );
ui.findPreference("prefSendCrashReport").setOnPreferenceClickListener(preference -> {
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/plain");
- String to[] = { "Martin.Fietz@gmail.com" };
- emailIntent .putExtra(Intent.EXTRA_EMAIL, to);
+ emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"Martin.Fietz@gmail.com"});
+ emailIntent.putExtra(Intent.EXTRA_SUBJECT, "AntennaPod Crash Report");
+ emailIntent.putExtra(Intent.EXTRA_TEXT, "Please describe what you were doing when the app crashed");
// the attachment
- emailIntent .putExtra(Intent.EXTRA_STREAM, Uri.fromFile(CrashReportWriter.getFile()));
- // the mail subject
- emailIntent .putExtra(Intent.EXTRA_SUBJECT, "AntennaPod Crash Report");
+ emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(CrashReportWriter.getFile()));
String intentTitle = ui.getActivity().getString(R.string.send_email);
ui.getActivity().startActivity(Intent.createChooser(emailIntent, intentTitle));
return true;
@@ -411,6 +376,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
public void onResume() {
checkItemVisibility();
+ setUpdateIntervalText();
setParallelDownloadsText(UserPreferences.getParallelDownloads());
setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize());
setDataFolderText();
@@ -423,7 +389,12 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
- File path = new File(dir);
+ File path;
+ if(dir != null) {
+ path = new File(dir);
+ } else {
+ path = ui.getActivity().getExternalFilesDir(null);
+ }
String message = null;
final Context context= ui.getActivity().getApplicationContext();
if(!path.exists()) {
@@ -503,15 +474,19 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
final Resources res = ui.getActivity().getResources();
ListPreference pref = (ListPreference) ui.findPreference(UserPreferences.PREF_SMART_MARK_AS_PLAYED_SECS);
- String[] values = res.getStringArray(
- R.array.smart_mark_as_played_values);
+ String[] values = res.getStringArray(R.array.smart_mark_as_played_values);
String[] entries = new String[values.length];
for (int x = 0; x < values.length; x++) {
if(x == 0) {
entries[x] = res.getString(R.string.pref_smart_mark_as_played_disabled);
} else {
Integer v = Integer.parseInt(values[x]);
- entries[x] = res.getQuantityString(R.plurals.time_seconds_quantified, v, v);
+ if(v < 60) {
+ entries[x] = res.getQuantityString(R.plurals.time_seconds_quantified, v, v);
+ } else {
+ v /= 60;
+ entries[x] = res.getQuantityString(R.plurals.time_minutes_quantified, v, v);
+ }
}
}
pref.setEntries(entries);
@@ -527,21 +502,17 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
@SuppressWarnings("deprecation")
private void checkItemVisibility() {
-
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);
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
- .setEnabled(UserPreferences.isEnableAutodownload());
- setSelectedNetworksEnabled(UserPreferences.isEnableAutodownload()
- && UserPreferences.isEnableAutodownloadWifiFilter());
-
- ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY)
- .setEnabled(UserPreferences.isEnableAutodownload());
+ boolean autoDownload = UserPreferences.isEnableAutodownload();
+ 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);
+ setSelectedNetworksEnabled(autoDownload && UserPreferences.isEnableAutodownloadWifiFilter());
ui.findPreference("prefSendCrashReport").setEnabled(CrashReportWriter.getFile().exists());
@@ -553,6 +524,32 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
}
}
+ private void setUpdateIntervalText() {
+ Context context = ui.getActivity().getApplicationContext();
+ String val;
+ long interval = UserPreferences.getUpdateInterval();
+ if(interval > 0) {
+ int hours = (int) TimeUnit.MILLISECONDS.toHours(interval);
+ String hoursStr = context.getResources().getQuantityString(R.plurals.time_hours_quantified, hours, hours);
+ val = String.format(context.getString(R.string.pref_autoUpdateIntervallOrTime_every), hoursStr);
+ } else {
+ int[] timeOfDay = UserPreferences.getUpdateTimeOfDay();
+ if(timeOfDay.length == 2) {
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, timeOfDay[0]);
+ cal.set(Calendar.MINUTE, timeOfDay[1]);
+ String timeOfDayStr = DateFormat.getTimeFormat(context).format(cal.getTime());
+ val = String.format(context.getString(R.string.pref_autoUpdateIntervallOrTime_at),
+ timeOfDayStr);
+ } else {
+ val = context.getString(R.string.pref_smart_mark_as_played_disabled);
+ }
+ }
+ String summary = context.getString(R.string.pref_autoUpdateIntervallOrTime_sum) + "\n"
+ + String.format(context.getString(R.string.pref_current_value), val);
+ ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL).setSummary(summary);
+ }
+
private void setParallelDownloadsText(int downloads) {
final Resources res = ui.getActivity().getResources();
@@ -598,35 +595,31 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
List<String> prefValues = Arrays.asList(UserPreferences
.getAutodownloadSelectedNetworks());
PreferenceScreen prefScreen = (PreferenceScreen) ui.findPreference(PreferenceController.AUTO_DL_PREF_SCREEN);
- Preference.OnPreferenceClickListener clickListener = new Preference.OnPreferenceClickListener() {
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- if (preference instanceof CheckBoxPreference) {
- String key = preference.getKey();
- ArrayList<String> prefValuesList = new ArrayList<String>(
- 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 == false) {
- // remove network
- prefValuesList.remove(index);
- } else if (index < 0 && newValue == true) {
- prefValuesList.add(key);
- }
-
- UserPreferences.setAutodownloadSelectedNetworks(
- prefValuesList.toArray(new String[prefValuesList.size()])
- );
- return true;
- } else {
- return false;
+ Preference.OnPreferenceClickListener clickListener = preference -> {
+ if (preference instanceof CheckBoxPreference) {
+ String key = preference.getKey();
+ ArrayList<String> prefValuesList = new ArrayList<String>(
+ 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 == false) {
+ // remove network
+ prefValuesList.remove(index);
+ } else if (index < 0 && newValue == true) {
+ 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
@@ -673,7 +666,6 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
checked[i] = true;
}
}
-
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.drawer_preferences);
builder.setMultiChoiceItems(navTitles, checked, (dialog, which, isChecked) -> {
@@ -683,46 +675,78 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]);
}
});
- builder.setPositiveButton(R.string.confirm_label, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- UserPreferences.setHiddenDrawerItems(hiddenDrawerItems);
- }
+ builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
+ UserPreferences.setHiddenDrawerItems(hiddenDrawerItems);
});
builder.setNegativeButton(R.string.cancel_label, null);
builder.create().show();
}
+ // CHOOSE DATA FOLDER
+
+ private void requestPermission() {
+ ActivityCompat.requestPermissions(ui.getActivity(), EXTERNAL_STORAGE_PERMISSIONS,
+ PERMISSION_REQUEST_EXTERNAL_STORAGE);
+ }
+
+ private void openDirectoryChooser() {
+ Activity activity = ui.getActivity();
+ Intent intent = new Intent(activity, DirectoryChooserActivity.class);
+ activity.startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
+ }
+
private void showChooseDataFolderDialog() {
Context context = ui.getActivity();
- String dataFolder = UserPreferences.getDataFolder(null).getAbsolutePath();
+ File dataFolder = UserPreferences.getDataFolder(null);
+ if(dataFolder == null) {
+ new MaterialDialog.Builder(ui.getActivity())
+ .title(R.string.error_label)
+ .content(R.string.external_storage_error_msg)
+ .neutralText(android.R.string.ok)
+ .show();
+ return;
+ }
+ String dataFolderPath = dataFolder.getAbsolutePath();
int selectedIndex = -1;
File[] mediaDirs = ContextCompat.getExternalFilesDirs(context, null);
- String[] folders = new String[mediaDirs.length];
- CharSequence[] choices = new CharSequence[mediaDirs.length];
+ List<String> folders = new ArrayList<>(mediaDirs.length);
+ List<CharSequence> choices = new ArrayList<>(mediaDirs.length);
for(int i=0; i < mediaDirs.length; i++) {
- String path = folders[i] = mediaDirs[i].getAbsolutePath();
- if(dataFolder.equals(path)) {
+ if(mediaDirs[i] == null) {
+ continue;
+ }
+ String path = mediaDirs[i].getAbsolutePath();
+ folders.add(path);
+ if(dataFolderPath.equals(path)) {
selectedIndex = i;
}
int index = path.indexOf("Android");
+ String choice;
if(index >= 0) {
- choices[i] = path.substring(0, index);
+ choice = path.substring(0, index);
} else {
- choices[i] = path;
+ choice = path;
}
- long bytes = StorageUtils.getFreeSpaceAvailable();
+ long bytes = StorageUtils.getFreeSpaceAvailable(path);
String freeSpace = String.format(context.getString(R.string.free_space_label),
Converter.byteToString(bytes));
- choices[i] = Html.fromHtml("<html><small>" + choices[i]
- + " [" + freeSpace + "]" + "</small></html>");
+ choices.add(Html.fromHtml("<html><small>" + choice
+ + " [" + freeSpace + "]" + "</small></html>"));
+ }
+ if(choices.size() == 0) {
+ new MaterialDialog.Builder(ui.getActivity())
+ .title(R.string.error_label)
+ .content(R.string.external_storage_error_msg)
+ .neutralText(android.R.string.ok)
+ .show();
+ return;
}
MaterialDialog dialog = new MaterialDialog.Builder(ui.getActivity())
.title(R.string.choose_data_directory)
.content(R.string.choose_data_directory_message)
- .items(choices)
+ .items(choices.toArray(new CharSequence[choices.size()]))
.itemsCallbackSingleChoice(selectedIndex, (dialog1, itemView, which, text) -> {
- String folder = folders[which];
+ String folder = folders.get(which);
Log.d(TAG, "data folder: " + folder);
UserPreferences.setDataFolder(folder);
setDataFolderText();
@@ -734,6 +758,8 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
dialog.show();
}
+ // UPDATE TIME/INTERVAL DIALOG
+
private void showUpdateIntervalTimePreferencesDialog() {
final Context context = ui.getActivity();
@@ -743,47 +769,48 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
builder.positiveText(R.string.pref_autoUpdateIntervallOrTime_Interval);
builder.negativeText(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay);
builder.neutralText(R.string.pref_autoUpdateIntervallOrTime_Disable);
- builder.callback(new MaterialDialog.ButtonCallback() {
- @Override
- public void onPositive(MaterialDialog dialog) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
- final String[] values = context.getResources().getStringArray(R.array.update_intervall_values);
- final String[] entries = getUpdateIntervalEntries(values);
- builder.setSingleChoiceItems(entries, -1, (dialog1, which) -> {
- int hours = Integer.valueOf(values[which]);
- UserPreferences.setUpdateInterval(hours);
- dialog1.dismiss();
- });
- builder.setNegativeButton(context.getString(R.string.cancel_label), null);
- builder.show();
+ builder.onPositive((dialog, which) -> {
+ AlertDialog.Builder builder1 = new AlertDialog.Builder(context);
+ builder1.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
+ final String[] values = context.getResources().getStringArray(R.array.update_intervall_values);
+ final String[] entries = getUpdateIntervalEntries(values);
+ long currInterval = UserPreferences.getUpdateInterval();
+ int checkedItem = -1;
+ if(currInterval > 0) {
+ String currIntervalStr = String.valueOf(TimeUnit.MILLISECONDS.toHours(currInterval));
+ checkedItem = ArrayUtils.indexOf(values, currIntervalStr);
}
-
- @Override
- public void onNegative(MaterialDialog dialog) {
- int hourOfDay = 7, minute = 0;
- int[] updateTime = UserPreferences.getUpdateTimeOfDay();
- if (updateTime.length == 2) {
- hourOfDay = updateTime[0];
- minute = updateTime[1];
- }
- TimePickerDialog timePickerDialog = new TimePickerDialog(context,
+ builder1.setSingleChoiceItems(entries, checkedItem, (dialog1, which1) -> {
+ int hours = Integer.valueOf(values[which1]);
+ UserPreferences.setUpdateInterval(hours);
+ dialog1.dismiss();
+ setUpdateIntervalText();
+ });
+ builder1.setNegativeButton(context.getString(R.string.cancel_label), null);
+ builder1.show();
+ });
+ builder.onNegative((dialog, which) -> {
+ int hourOfDay = 7, minute = 0;
+ int[] updateTime = UserPreferences.getUpdateTimeOfDay();
+ if (updateTime.length == 2) {
+ hourOfDay = updateTime[0];
+ minute = updateTime[1];
+ }
+ TimePickerDialog timePickerDialog = new TimePickerDialog(context,
(view, selectedHourOfDay, selectedMinute) -> {
if (view.getTag() == null) { // onTimeSet() may get called twice!
view.setTag("TAGGED");
UserPreferences.setUpdateTimeOfDay(selectedHourOfDay, selectedMinute);
+ setUpdateIntervalText();
}
}, hourOfDay, minute, DateFormat.is24HourFormat(context));
- timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay));
- timePickerDialog.show();
- }
-
- @Override
- public void onNeutral(MaterialDialog dialog) {
- UserPreferences.setUpdateInterval(0);
- }
+ timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay));
+ timePickerDialog.show();
+ });
+ builder.onNeutral((dialog, which) -> {
+ UserPreferences.setUpdateInterval(0);
+ setUpdateIntervalText();
});
- builder.forceStacking(true);
builder.show();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/SwitchCompatPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/SwitchCompatPreference.java
new file mode 100644
index 000000000..10c11b88e
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/SwitchCompatPreference.java
@@ -0,0 +1,37 @@
+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/SPAReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
index ef6330f82..8201fe3e2 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
@@ -8,7 +8,6 @@ import android.util.Log;
import android.widget.Toast;
import java.util.Arrays;
-import java.util.Date;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
@@ -35,7 +34,7 @@ public class SPAReceiver extends BroadcastReceiver{
if (feedUrls != null) {
if (BuildConfig.DEBUG) Log.d(TAG, "Received feeds list: " + Arrays.toString(feedUrls));
for (String url : feedUrls) {
- Feed f = new Feed(url, new Date(0));
+ Feed f = new Feed(url, null);
try {
DownloadRequester.getInstance().downloadFeed(context, f);
} catch (DownloadRequestException e) {
diff --git a/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java b/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
index d61a189c2..323060f81 100644
--- a/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
+++ b/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
@@ -128,7 +128,7 @@ public class PlayerWidgetService extends Service {
views.setTextViewText(R.id.txtvTitle, media.getEpisodeTitle());
- String progressString = getProgressString(media);
+ String progressString = getProgressString();
if (progressString != null) {
views.setViewVisibility(R.id.txtvProgress, View.VISIBLE);
views.setTextViewText(R.id.txtvProgress, progressString);
@@ -181,9 +181,9 @@ public class PlayerWidgetService extends Service {
return PendingIntent.getBroadcast(this, 0, startingIntent, 0);
}
- private String getProgressString(Playable media) {
- int position = media.getPosition();
- int duration = media.getDuration();
+ private String getProgressString() {
+ int position = playbackService.getCurrentPosition();
+ int duration = playbackService.getDuration();
if (position > 0 && duration > 0) {
return Converter.getDurationStringLong(position) + " / "
+ Converter.getDurationStringLong(duration);
diff --git a/app/src/main/res/drawable/shadow.xml b/app/src/main/res/drawable/shadow.xml
new file mode 100644
index 000000000..fc5110e0b
--- /dev/null
+++ b/app/src/main/res/drawable/shadow.xml
@@ -0,0 +1,7 @@
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:startColor="@android:color/transparent"
+ android:endColor="#40000000"
+ android:angle="90" />
+</shape>
diff --git a/app/src/main/res/layout/audio_controls.xml b/app/src/main/res/layout/audio_controls.xml
new file mode 100644
index 000000000..852b6e922
--- /dev/null
+++ b/app/src/main/res/layout/audio_controls.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ android:text="@string/playback_speed"
+ android:textStyle="bold"/>
+
+ <TextView
+ android:id="@+id/txtvPlaybackSpeed"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="16dp"
+ android:text="1.00x"/>
+
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-12dp">
+
+ <Button
+ android:id="@+id/butDecSpeed"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_alignParentLeft="true"
+ android:gravity="center"
+ android:text="-"
+ android:textStyle="bold"
+ android:textColor="@color/status_progress"
+ android:textSize="24sp"
+ android:background="@drawable/borderless_button_dark"/>
+
+ <Button
+ android:id="@+id/butIncSpeed"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:minWidth="0dp"
+ android:layout_alignParentRight="true"
+ android:gravity="center"
+ android:text="+"
+ android:textStyle="bold"
+ android:textColor="@color/status_progress"
+ android:textSize="24sp"
+ android:background="@drawable/borderless_button_dark"/>
+
+ <SeekBar
+ android:id="@+id/playback_speed"
+ android:layout_width="match_parent"
+ android:layout_height="32dp"
+ android:layout_toRightOf="@id/butDecSpeed"
+ android:layout_toLeftOf="@id/butIncSpeed"
+ android:layout_centerVertical="true"
+ android:max="40"/>
+
+ </RelativeLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4dp"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ android:text="@string/volume"
+ android:textStyle="bold"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-12dp"
+ android:layout_marginLeft="8dp"
+ android:orientation="horizontal"
+ android:gravity="center">
+
+ <TextView
+ android:id="@+id/txtvLeft"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/left_short" />
+
+ <SeekBar
+ android:id="@+id/volume_left"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:max="100" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="8dp"
+ android:orientation="horizontal"
+ android:gravity="center">
+
+ <TextView
+ android:id="@+id/txtvRight"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/right_short" />
+
+ <SeekBar
+ android:id="@+id/volume_right"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:max="100"/>
+
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ android:text="@string/audio_effects"
+ android:textStyle="bold"/>
+
+ <CheckBox
+ android:id="@+id/stereo_to_mono"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-12dp"
+ android:text="@string/stereo_to_mono" />
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/audioplayer_activity.xml b/app/src/main/res/layout/audioplayer_activity.xml
index 379028c8e..fb4f995a2 100644
--- a/app/src/main/res/layout/audioplayer_activity.xml
+++ b/app/src/main/res/layout/audioplayer_activity.xml
@@ -1,219 +1,219 @@
<?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.v4.widget.DrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:background="@android:color/holo_red_dark">
- <LinearLayout
+ <RelativeLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="match_parent">
+
+ <android.support.design.widget.AppBarLayout
+ android:id="@+id/appBar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
- tools:background="@android:color/darker_gray">
+ tools:background="@android:color/darker_gray"/>
- <LinearLayout
+ <com.viewpagerindicator.CirclePageIndicator
+ android:id="@+id/page_indicator"
+ android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:paddingLeft="8dp"
- android:paddingRight="8dp">
-
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_weight="1"
- android:ellipsize="end"
- android:gravity="left"
- android:maxLines="2"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="16sp"
- tools:text="Audio title"
- tools:background="@android:color/holo_green_dark" />
-
- <ImageButton
- android:id="@+id/butCover"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_gravity="center_vertical"
- android:layout_marginLeft="8dp"
- android:background="?attr/selectableItemBackground"
- android:contentDescription="@string/show_cover_label"
- android:gravity="right"
- tools:src="@drawable/ic_stat_antenna_default"
- tools:background="@android:color/holo_green_dark" />
-
-
- </LinearLayout>
- </android.support.v7.widget.Toolbar>
-
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/content"
+ android:layout_marginTop="-12dp"
+ android:layout_marginBottom="4dp"
+ android:background="@android:color/transparent"
+ app:fillColor="?android:attr/textColorSecondary"
+ app:strokeColor="?android:attr/textColorSecondary"
+ app:radius="4dp" />
+
+ </android.support.design.widget.AppBarLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/playtime_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="?attr/non_transparent_background"
- android:foreground="?android:windowContentOverlay"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp"
+ android:layout_alignParentBottom="true"
+ android:background="?attr/overlay_drawable"
android:orientation="vertical">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/txtvPosition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="8dp"
+ android:text="@string/position_default_label"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_micro"
+ tools:background="@android:color/holo_green_dark" />
+
+ <TextView
+ android:id="@+id/txtvLength"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="8dp"
+ android:text="@string/position_default_label"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_micro"
+ tools:background="@android:color/holo_green_dark" />
+
+ <SeekBar
+ android:id="@+id/sbPosition"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_toLeftOf="@id/txtvLength"
+ android:layout_toRightOf="@id/txtvPosition"
+ android:max="500"
+ tools:background="@android:color/holo_green_dark" />
+
+ </RelativeLayout>
+
<RelativeLayout
android:id="@+id/player_control"
android:layout_width="match_parent"
- android:layout_height="@dimen/audioplayer_playercontrols_length"
- android:layout_alignParentBottom="true"
+ android:layout_height="wrap_content"
+ android:paddingTop="4dp"
+ android:paddingBottom="8dp"
android:background="?attr/overlay_background"
tools:background="@android:color/holo_purple">
<ImageButton
android:id="@+id/butPlay"
android:layout_width="@dimen/audioplayer_playercontrols_length"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
android:layout_centerHorizontal="true"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/pause_label"
android:src="?attr/av_pause"
+ android:scaleType="fitCenter"
tools:src="@drawable/ic_pause_white_36dp"
tools:background="@android:color/holo_green_dark" />
<ImageButton
android:id="@+id/butRev"
android:layout_width="@dimen/audioplayer_playercontrols_length"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
android:layout_toLeftOf="@id/butPlay"
+ android:layout_marginLeft="16dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/rewind_label"
android:src="?attr/av_rew_big"
+ android:scaleType="fitCenter"
tools:src="@drawable/ic_fast_rewind_white_36dp"
tools:background="@android:color/holo_blue_dark" />
<TextView
android:id="@+id/txtvRev"
android:layout_width="wrap_content"
- android:layout_height="32dp"
- android:layout_alignTop="@id/butRev"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/butRev"
android:layout_alignLeft="@id/butRev"
android:layout_alignRight="@id/butRev"
+ android:layout_marginTop="-8dp"
android:gravity="center"
android:text="30"
- android:textSize="8dp"
+ android:textSize="10sp"
+ android:textColor="?android:attr/textColorSecondary"
android:clickable="false"/>
+ <Button
+ android:id="@+id/butPlaybackSpeed"
+ android:layout_width="@dimen/audioplayer_playercontrols_length"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
+ android:layout_toLeftOf="@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"
+ tools:background="@android:color/holo_green_dark" />
+
<ImageButton
android:id="@+id/butFF"
android:layout_width="@dimen/audioplayer_playercontrols_length"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
android:layout_toRightOf="@id/butPlay"
+ android:layout_marginRight="16dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/fast_forward_label"
android:src="?attr/av_ff_big"
+ android:scaleType="fitCenter"
tools:src="@drawable/ic_fast_forward_white_36dp"
tools:background="@android:color/holo_blue_dark" />
<TextView
android:id="@+id/txtvFF"
android:layout_width="wrap_content"
- android:layout_height="32dp"
- android:layout_alignTop="@id/butFF"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/butFF"
android:layout_alignLeft="@id/butFF"
android:layout_alignRight="@id/butFF"
+ android:layout_marginTop="-8dp"
android:gravity="center"
android:text="30"
- android:textSize="8dp"
+ android:textSize="10sp"
+ android:textColor="?android:attr/textColorSecondary"
android:clickable="false"/>
- <Button
- android:id="@+id/butPlaybackSpeed"
- android:layout_width="@dimen/audioplayer_playercontrols_length"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/butFF"
- android:background="?attr/selectableItemBackground"
- android:contentDescription="@string/set_playback_speed_label"
- android:src="?attr/av_fast_forward"
- android:textSize="@dimen/text_size_medium"
- android:visibility="gone"
- tools:background="@android:color/holo_green_dark" />
-
<ImageButton
- android:id="@+id/butNavChaptersShownotes"
+ android:id="@+id/butSkip"
android:layout_width="@dimen/audioplayer_playercontrols_length"
- android:layout_height="match_parent"
- android:layout_toLeftOf="@id/butRev"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
+ android:layout_toRightOf="@id/butFF"
android:background="?attr/selectableItemBackground"
- android:scaleType="centerInside"
- android:src="@drawable/ic_toc_white_36dp"
- tools:background="@android:color/holo_green_dark" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/playtime_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_above="@id/player_control"
- android:layout_alignParentLeft="true"
- android:background="?attr/overlay_drawable">
-
- <TextView
- android:id="@+id/txtvPosition"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvLength"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_centerVertical="true"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro"
- tools:background="@android:color/holo_green_dark" />
-
- <SeekBar
- android:id="@+id/sbPosition"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:layout_toLeftOf="@id/txtvLength"
- android:layout_toRightOf="@id/txtvPosition"
- android:max="500"
+ android:scaleType="fitCenter"
+ android:src="?attr/av_skip_big"
+ android:contentDescription="@string/skip_episode_label"
+ tools:src="@drawable/ic_skip_white_36dp"
tools:background="@android:color/holo_green_dark" />
</RelativeLayout>
- <FrameLayout
- android:id="@+id/contentView"
- android:layout_width="match_parent"
- android:layout_height="0px"
- android:layout_above="@id/playtime_layout"
- android:layout_alignParentTop="true"
- android:foreground="?android:windowContentOverlay"
- tools:background="@android:color/holo_orange_light" />
+ </LinearLayout>
- </RelativeLayout>
+ <android.support.v4.view.ViewPager
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_above="@id/playtime_layout"
+ android:layout_below="@id/appBar"
+ android:foreground="?android:windowContentOverlay"
+ tools:background="@android:color/holo_orange_light" />
+ <View
+ android:id="@+id/shadow"
+ android:layout_width="match_parent"
+ android:layout_height="4dp"
+ android:layout_below="@id/appBar"
+ android:background="@drawable/shadow" />
- </LinearLayout>
+ </RelativeLayout>
<include layout="@layout/nav_list" />
diff --git a/app/src/main/res/layout/choose_speed_dialog.xml b/app/src/main/res/layout/choose_speed_dialog.xml
deleted file mode 100644
index 1b461c77e..000000000
--- a/app/src/main/res/layout/choose_speed_dialog.xml
+++ /dev/null
@@ -1,45 +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.support.v7.widget.CardView
- xmlns:card_view="http://schemas.android.com/apk/res-auto"
- android:id="@+id/card_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_margin="16dp"
- card_view:cardElevation="12dp"
- card_view:cardCornerRadius="4dp"
- card_view:cardUseCompatPadding="true"
- card_view:cardBackgroundColor="?attr/overlay_background">
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:gravity="center">
-
- <TextView
- android:id="@+id/txtvSelectedSpeed"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:textSize="22sp"
- android:textStyle="bold"/>
-
- <SeekBar
- android:id="@+id/sbSelectSpeed"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"/>
-
- </LinearLayout>
-
- </android.support.v7.widget.CardView>
-
-</LinearLayout>
diff --git a/app/src/main/res/layout/cover_fragment.xml b/app/src/main/res/layout/cover_fragment.xml
index 4bbdeae06..9ad1ff9c6 100644
--- a/app/src/main/res/layout/cover_fragment.xml
+++ b/app/src/main/res/layout/cover_fragment.xml
@@ -1,19 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+
+<android.support.percent.PercentRelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/cover_fragment_root"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
+ android:layout_height="match_parent">
<ImageView
android:id="@+id/imgvCover"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_centerInParent="true"
android:contentDescription="@string/cover_label"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:adjustViewBounds="true"
android:scaleType="fitCenter"
+ app:layout_aspectRatio="100%"
+ app:layout_widthPercent="82%"
tools:src="@android:drawable/sym_def_app_icon" />
-</RelativeLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:layout_above="@id/imgvCover">
+
+ <TextView
+ android:id="@+id/txtvPodcastTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:gravity="center"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:text="Podcast"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:layout_below="@id/imgvCover">
+
+ <TextView
+ android:id="@+id/txtvEpisodeTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:gravity="center"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:text="Episode"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ </LinearLayout>
+
+</android.support.percent.PercentRelativeLayout>
diff --git a/app/src/main/res/layout/downloaded_episodeslist_item.xml b/app/src/main/res/layout/downloaded_episodeslist_item.xml
index 6b5f7369a..760b6b9db 100644
--- a/app/src/main/res/layout/downloaded_episodeslist_item.xml
+++ b/app/src/main/res/layout/downloaded_episodeslist_item.xml
@@ -22,7 +22,7 @@
<RelativeLayout
android:layout_width="0dp"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/thumbnail_length_downloaded_item"
android:layout_marginLeft="@dimen/listitem_threeline_textleftpadding"
android:layout_marginRight="@dimen/listitem_threeline_textrightpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
@@ -48,7 +48,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
- android:layout_below="@id/txtvTitle"
+ android:layout_alignParentBottom="true"
tools:text="23 MB"
tools:background="@android:color/holo_green_dark" />
@@ -58,10 +58,23 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
- android:layout_below="@id/txtvTitle"
+ android:layout_alignParentBottom="true"
+ android:layout_marginLeft="8dp"
tools:text="Jan 23"
tools:background="@android:color/holo_green_dark" />
+ <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" />
+
</RelativeLayout>
<include layout="@layout/vertical_list_divider"/>
diff --git a/app/src/main/res/layout/episodes_apply_action_fragment.xml b/app/src/main/res/layout/episodes_apply_action_fragment.xml
index d63088662..e9a2e2e23 100644
--- a/app/src/main/res/layout/episodes_apply_action_fragment.xml
+++ b/app/src/main/res/layout/episodes_apply_action_fragment.xml
@@ -1,16 +1,16 @@
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<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">
<LinearLayout
android:id="@+id/bottomBar"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="68dp"
android:layout_alignParentBottom="true"
- android:orientation="horizontal"
android:gravity="center_vertical"
+ android:orientation="horizontal"
android:padding="4dp">
<Button
@@ -18,103 +18,98 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:background="@android:color/transparent"
android:drawableTop="?attr/content_new"
android:text="@string/add_to_queue_label"
- android:textSize="10sp"
- android:background="@android:color/transparent"/>
+ android:textSize="10sp" />
- <View xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:layout_margin="4dp"
- android:background="?android:attr/listDivider"
- tools:background="@android:color/holo_red_dark" />
+ <View
+ android:id="@+id/divider1"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
<Button
android:id="@+id/btnMarkAsPlayed"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:background="@android:color/transparent"
android:drawableTop="?attr/navigation_accept"
android:text="@string/mark_read_label"
- android:textSize="10sp"
- android:background="@android:color/transparent"/>
+ android:textSize="10sp" />
- <View xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:layout_margin="4dp"
- android:background="?android:attr/listDivider"
- tools:background="@android:color/holo_red_dark" />
+ <View
+ android:id="@+id/divider2"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
<Button
android:id="@+id/btnMarkAsUnplayed"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:background="@android:color/transparent"
android:drawableTop="?attr/navigation_cancel"
android:text="@string/mark_unread_label"
- android:textSize="10sp"
- android:background="@android:color/transparent"/>
+ android:textSize="10sp" />
- <View xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:layout_margin="4dp"
- android:background="?android:attr/listDivider"
- tools:background="@android:color/holo_red_dark" />
+ <View
+ android:id="@+id/divider3"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
<Button
android:id="@+id/btnDownload"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:background="@android:color/transparent"
android:drawableTop="?attr/av_download"
android:text="@string/download_label"
- android:textSize="10sp"
- android:background="@android:color/transparent"/>
+ android:textSize="10sp" />
- <View xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:layout_margin="4dp"
- android:background="?android:attr/listDivider"
- tools:background="@android:color/holo_red_dark" />
+ <View
+ android:id="@+id/divider4"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
<Button
android:id="@+id/btnDelete"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:background="@android:color/transparent"
android:drawableTop="?attr/content_discard"
android:text="@string/remove_episode_lable"
- android:textSize="10sp"
- android:background="@android:color/transparent"/>
+ android:textSize="10sp" />
</LinearLayout>
<View
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/listDivider"
- android:paddingBottom="4dp"
- android:layout_above="@id/bottomBar"
- tools:background="@android:color/holo_red_dark" />
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_above="@id/bottomBar"
+ android:background="?android:attr/listDivider"
+ android:paddingBottom="4dp"
+ tools:background="@android:color/holo_red_dark" />
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_above="@id/divider">
-
- </ListView>
-
+ android:layout_above="@id/divider"/>
</RelativeLayout>
diff --git a/app/src/main/res/layout/external_player_fragment.xml b/app/src/main/res/layout/external_player_fragment.xml
index ef83baa17..ac55b4c40 100644
--- a/app/src/main/res/layout/external_player_fragment.xml
+++ b/app/src/main/res/layout/external_player_fragment.xml
@@ -1,69 +1,89 @@
<?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:id="@+id/fragmentLayout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone"
- android:background="?attr/colorPrimary"
- tools:visibility="visible"
- tools:background="@android:color/darker_gray">
+<LinearLayout
+ 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">
- <View
+ <RelativeLayout
android:layout_width="match_parent"
- android:layout_height="2dp"
- android:background="@color/holo_blue_light"/>
+ android:layout_height="@dimen/external_player_height">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ <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"/>
- <RelativeLayout
- android:id="@+id/layoutInfo"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:background="?attr/selectableItemBackground">
+ <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"/>
- <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:layout_alignParentLeft="true"
- android:padding="4dp"
- android:adjustViewBounds="true"
- android:cropToPadding="true"
- android:scaleType="fitXY"
- 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_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"/>
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="match_parent"
- 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/imgvCover"
- android:ellipsize="end"
- android:maxLines="2"
- android:textSize="18sp"
- android:fontFamily="sans-serif-light"
- tools:text="Playback item title"
- tools:background="@android:color/holo_green_dark"/>
- </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"/>
<ImageButton
android:id="@+id/butPlay"
- android:contentDescription="@string/pause_label"
- android:layout_width="@dimen/external_player_height"
- android:layout_height="@dimen/external_player_height"
- android:background="?attr/selectableItemBackground"
- tools:src="@drawable/ic_play_arrow_white_36dp"
- tools:background="@android:color/holo_green_dark"/>
- </LinearLayout>
+ 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"/>
+
+ </RelativeLayout>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/app/src/main/res/layout/feedinfo.xml b/app/src/main/res/layout/feedinfo.xml
index 2b49b4b35..4b545e3cc 100644
--- a/app/src/main/res/layout/feedinfo.xml
+++ b/app/src/main/res/layout/feedinfo.xml
@@ -150,17 +150,6 @@
android:text="@string/podcast_settings_label"
android:layout_marginTop="8dp"/>
- <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" />
-
<android.support.v7.widget.GridLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -192,6 +181,17 @@
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"
@@ -266,6 +266,77 @@
</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"
diff --git a/app/src/main/res/layout/feeditem_fragment.xml b/app/src/main/res/layout/feeditem_fragment.xml
index 5e1b580d2..c18e5fd6c 100644
--- a/app/src/main/res/layout/feeditem_fragment.xml
+++ b/app/src/main/res/layout/feeditem_fragment.xml
@@ -1,13 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <LinearLayout
+ android:id="@+id/header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="?attr/colorPrimary"
+ android:gravity="center_horizontal"
+ android:orientation="vertical"
+ tools:background="@android:color/darker_gray">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="16dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp">
+
+ <ImageView
+ android:id="@+id/imgvCover"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:contentDescription="@string/cover_label"
+ android:gravity="center_vertical"
+ 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_marginLeft="16dp"
+ android:layout_alignTop="@id/imgvCover"
+ android:layout_toRightOf="@id/imgvCover"
+ android:includeFontPadding="false"
+ android:textSize="16sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:ellipsize="end"
+ android:maxLines="5"
+ tools:text="Podcast title"
+ tools:background="@android:color/holo_green_dark" />
+
+ <TextView
+ android:id="@+id/txtvDuration"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/imgvCover"
+ android:layout_below="@id/txtvTitle"
+ android:layout_marginLeft="16dp"
+ tools:text="00:42:23"
+ tools:background="@android:color/holo_green_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_below="@id/txtvTitle"
+ android:layout_marginLeft="8dp"
+ tools:text="Jan\n23"
+ tools:background="@android:color/holo_green_dark" />
+
+ </RelativeLayout>
+
+ <ProgressBar
+ android:id="@+id/progbarDownload"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:orientation="horizontal"
+ tools:background="@android:color/holo_blue_bright">
+
+ <com.joanzapata.iconify.widget.IconButton
+ android:id="@+id/butAction1"
+ android:layout_width="0dp"
+ android:layout_height="48dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="8dp"
+ android:layout_weight="1"
+ android:background="?attr/selectableItemBackground"
+ android:ellipsize="end"
+ android:gravity="center"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_small"
+ tools:text="Button 1"
+ tools:background="@android:color/holo_red_light" />
+
+ <com.joanzapata.iconify.widget.IconButton
+ android:id="@+id/butAction2"
+ android:layout_width="0dp"
+ android:layout_height="48dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="8dp"
+ android:layout_weight="1"
+ android:background="?attr/selectableItemBackground"
+ android:ellipsize="end"
+ android:gravity="center"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_small"
+ tools:text="Button 2"
+ tools:background="@android:color/holo_orange_dark" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="@color/light_gray"/>
+
+ </LinearLayout>
<WebView
android:id="@+id/webvDescription"
android:layout_width="match_parent"
+ android:layout_below="@id/header"
android:layout_height="match_parent"
android:foreground="?android:windowContentOverlay" />
@@ -22,4 +150,4 @@
android:layout_gravity="center"
android:indeterminate="true" />
</FrameLayout>
-</FrameLayout> \ No newline at end of file
+</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/feeditem_fragment_header.xml b/app/src/main/res/layout/feeditem_fragment_header.xml
deleted file mode 100644
index 2534dddbe..000000000
--- a/app/src/main/res/layout/feeditem_fragment_header.xml
+++ /dev/null
@@ -1,136 +0,0 @@
-<?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:id="@+id/header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:background="?attr/colorPrimary"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- tools:background="@android:color/darker_gray">
-
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:orientation="horizontal"
- android:paddingBottom="0dp">
-
- <ImageView
- android:id="@+id/imgvCover"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginTop="16dp"
- android:contentDescription="@string/cover_label"
- android:gravity="center_vertical"
- tools:src="@drawable/ic_stat_antenna_default"
- tools:background="@android:color/holo_green_dark" />
-
-
- <ImageButton
- android:id="@+id/butMoreActions"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:background="?attr/selectableItemBackground"
- android:contentDescription="@string/butAction_label"
- android:paddingTop="4dp"
- android:src="?attr/ic_action_overflow"
- tools:src="@drawable/ic_info_white_24dp"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvTitle"
- style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:layout_toLeftOf="@id/butMoreActions"
- android:layout_toRightOf="@id/imgvCover"
- android:maxLines="5"
- tools:text="Podcast title"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvDuration"
- style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/imgvCover"
- android:layout_below="@id/txtvTitle"
- android:layout_marginLeft="16dp"
- tools:text="00:42:23"
- tools:background="@android:color/holo_green_dark"/>
-
- <TextView
- android:id="@+id/txtvPublished"
- style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toLeftOf="@id/butMoreActions"
- android:layout_marginRight="8dp"
- tools:text="Jan 23"
- tools:background="@android:color/holo_green_dark"
- android:layout_below="@+id/txtvTitle"/>
-
- </RelativeLayout>
-
- <ProgressBar
- android:id="@+id/progbarDownload"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
- android:visibility="invisible" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:layout_marginRight="8dp"
- android:orientation="horizontal"
- tools:background="@android:color/holo_blue_bright">
-
- <Button
- android:id="@+id/butAction1"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:layout_gravity="center_vertical"
- android:layout_marginRight="8dp"
- android:layout_weight="1"
- android:background="?attr/selectableItemBackground"
- android:ellipsize="end"
- android:paddingTop="4dp"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_small"
- tools:text="Button 1"
- tools:background="@android:color/holo_red_light" />
-
- <Button
- android:id="@+id/butAction2"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:layout_gravity="center_vertical"
- android:layout_marginLeft="8dp"
- android:layout_weight="1"
- android:background="?attr/selectableItemBackground"
- android:ellipsize="end"
- android:paddingTop="4dp"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_small"
- tools:text="Button 2"
- tools:background="@android:color/holo_orange_dark" />
-
- </LinearLayout>
-
-
-</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_itunes_search.xml b/app/src/main/res/layout/fragment_itunes_search.xml
index e57c59554..0cc13f74c 100644
--- a/app/src/main/res/layout/fragment_itunes_search.xml
+++ b/app/src/main/res/layout/fragment_itunes_search.xml
@@ -1,26 +1,64 @@
-<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:context="de.danoeh.antennapod.activity.ITunesSearchActivity">
-<android.support.v7.widget.SearchView
- android:id="@+id/itunes_search_view"
- android:layout_height="wrap_content"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- />
-<GridView
- android:id="@+id/gridView"
- android:layout_below="@id/itunes_search_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipToPadding="false"
- android:columnWidth="400dp"
- android:gravity="center"
- android:horizontalSpacing="8dp"
- android:numColumns="auto_fit"
- android:paddingBottom="@dimen/list_vertical_padding"
- android:paddingTop="@dimen/list_vertical_padding"
- android:stretchMode="columnWidth"
- android:verticalSpacing="8dp"
- tools:listitem="@layout/gpodnet_podcast_listitem" />
+ android:layout_height="match_parent">
+
+ <GridView
+ android:id="@+id/gridView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:columnWidth="400dp"
+ android:gravity="center"
+ android:horizontalSpacing="8dp"
+ android:numColumns="auto_fit"
+ android:paddingBottom="@dimen/list_vertical_padding"
+ android:paddingTop="@dimen/list_vertical_padding"
+ android:stretchMode="columnWidth"
+ android:verticalSpacing="8dp"
+ tools:listitem="@layout/gpodnet_podcast_listitem" />
+
+ <TextView
+ android:id="@id/android:empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_centerInParent="true"
+ android:gravity="center"
+ android:visibility="gone"
+ android:text="@string/search_status_no_results" />
+
+ <ProgressBar
+ android:id="@+id/progressBar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:indeterminateOnly="true"
+ android:visibility="gone"/>
+
+ <TextView
+ android:id="@+id/txtvError"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:layout_margin="16dp"
+ android:textAlignment="center"
+ android:textSize="@dimen/text_size_small"
+ android:visibility="gone"
+ tools:visibility="visible"
+ tools:text="Error message"
+ tools:background="@android:color/holo_red_light" />
+
+ <Button
+ android:id="@+id/butRetry"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txtvError"
+ android:layout_centerHorizontal="true"
+ android:layout_margin="16dp"
+ android:text="@string/retry_label"
+ android:visibility="gone"
+ tools:visibility="visible"
+ tools:background="@android:color/holo_red_light" />
+
</RelativeLayout>
diff --git a/app/src/main/res/layout/gpodnet_podcast_listitem.xml b/app/src/main/res/layout/gpodnet_podcast_listitem.xml
index 84c6c280e..bbe8e65d6 100644
--- a/app/src/main/res/layout/gpodnet_podcast_listitem.xml
+++ b/app/src/main/res/layout/gpodnet_podcast_listitem.xml
@@ -3,7 +3,11 @@
<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"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingBottom="8dp"
tools:background="@android:color/darker_gray">
<ImageView
@@ -11,11 +15,8 @@
android:layout_width="@dimen/thumbnail_length_itemlist"
android:layout_height="@dimen/thumbnail_length_itemlist"
android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
- android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_alignParentTop="true"
android:layout_marginRight="8dp"
- android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:adjustViewBounds="true"
android:contentDescription="@string/cover_label"
android:cropToPadding="true"
@@ -29,7 +30,6 @@
android:layout_height="wrap_content"
android:layout_alignTop="@id/txtvTitle"
android:layout_alignParentRight="true"
- android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
android:orientation="horizontal">
<ImageView
@@ -52,15 +52,14 @@
<TextView
android:id="@+id/txtvTitle"
- style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/list_vertical_padding"
- android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
android:layout_toRightOf="@id/imgvCover"
android:layout_toLeftOf="@id/subscribers_container"
android:layout_alignTop="@id/imgvCover"
- android:lines="1"
+ android:maxLines="2"
+ android:includeFontPadding="false"
tools:text="Title"
tools:background="@android:color/holo_green_dark" />
@@ -69,7 +68,6 @@
style="android:style/TextAppearance.Small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
android:layout_toRightOf="@id/imgvCover"
android:layout_below="@id/txtvTitle"
android:textSize="14sp"
diff --git a/app/src/main/res/layout/itemdescription_listitem.xml b/app/src/main/res/layout/itemdescription_listitem.xml
index ca8f974bf..51bc9a5eb 100644
--- a/app/src/main/res/layout/itemdescription_listitem.xml
+++ b/app/src/main/res/layout/itemdescription_listitem.xml
@@ -1,30 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<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:orientation="vertical"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingBottom="8dp"
tools:background="@android:color/holo_orange_light">
<TextView
+ android:id="@+id/txtvPubDate"
+ style="@android:style/TextAppearance.Small"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="8dp"
+ android:textSize="14sp"
+ android:textColor="?android:textColorSecondary"
+ android:ellipsize="end"
+ android:lines="1"
+ tools:text="22 Jan 2016"
+ tools:background="@android:color/holo_green_dark" />
+
+ <TextView
android:id="@+id/txtvTitle"
- style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_margin="16dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_toLeftOf="@id/txtvPubDate"
+ android:textSize="16sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:ellipsize="end"
+ android:maxLines="2"
tools:text="Feed item title"
tools:background="@android:color/holo_green_dark" />
<TextView
android:id="@+id/txtvDescription"
- style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
- android:lines="3"
+ android:layout_below="@id/txtvTitle"
+ android:textSize="14sp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:ellipsize="end"
+ android:maxLines="3"
tools:text="Feed item description"
tools:background="@android:color/holo_green_dark" />
-</LinearLayout>
+
+</RelativeLayout>
diff --git a/app/src/main/res/layout/itunes_podcast_listitem.xml b/app/src/main/res/layout/itunes_podcast_listitem.xml
index 41b1f495f..1e6e5a836 100644
--- a/app/src/main/res/layout/itunes_podcast_listitem.xml
+++ b/app/src/main/res/layout/itunes_podcast_listitem.xml
@@ -1,38 +1,58 @@
<?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="@dimen/listitem_threeline_height"
-tools:background="@android:color/darker_gray">
-
-<ImageView
- android:id="@+id/imgvCover"
- android:layout_width="@dimen/thumbnail_length_itemlist"
- android:layout_height="@dimen/thumbnail_length_itemlist"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
- android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
- android:layout_marginRight="8dp"
- android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
- android:adjustViewBounds="true"
- android:contentDescription="@string/cover_label"
- android:cropToPadding="true"
- android:scaleType="fitXY"
- tools:src="@drawable/ic_stat_antenna_default"
- tools:background="@android:color/holo_green_dark" />
-
-<TextView
- android:id="@+id/txtvTitle"
- style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+<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="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
- android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
- android:layout_toRightOf="@id/imgvCover"
- android:maxLines="1"
- tools:text="Podcast title"
- tools:background="@android:color/holo_green_dark" />
+ android:paddingTop="8dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingBottom="8dp"
+ tools:background="@android:color/darker_gray">
+
+ <ImageView
+ android:id="@+id/imgvCover"
+ android:layout_width="@dimen/thumbnail_length_itemlist"
+ android:layout_height="@dimen/thumbnail_length_itemlist"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginRight="8dp"
+ android:adjustViewBounds="true"
+ android:contentDescription="@string/cover_label"
+ android:cropToPadding="true"
+ android:scaleType="fitXY"
+ tools:background="@android:color/holo_green_dark"
+ tools:src="@drawable/ic_stat_antenna_default" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/imgvCover"
+ android:layout_centerVertical="true"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:maxLines="2"
+ tools:background="@android:color/holo_green_dark"
+ tools:text="Podcast title" />
+
+ <TextView
+ android:id="@+id/txtvUrl"
+ style="android:style/TextAppearance.Small"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="14sp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:ellipsize="middle"
+ android:maxLines="2"
+ tools:text="http://www.example.com/feed"
+ tools:background="@android:color/holo_green_dark"/>
+
+ </LinearLayout>
+
</RelativeLayout>
diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml
index 46be5bc5f..c05132b42 100644
--- a/app/src/main/res/layout/main.xml
+++ b/app/src/main/res/layout/main.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.v4.widget.DrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
@@ -10,7 +11,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
<FrameLayout
android:id="@+id/playerFragment"
android:layout_width="match_parent"
@@ -27,6 +27,14 @@
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
tools:background="@android:color/holo_blue_dark" />
+
+ <View
+ android:id="@+id/shadow"
+ android:layout_width="match_parent"
+ android:layout_height="4dp"
+ android:layout_below="@id/toolbar"
+ android:background="@drawable/shadow" />
+
<FrameLayout
android:id="@+id/main_view"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/nav_feedlistitem.xml b/app/src/main/res/layout/nav_feedlistitem.xml
index f0cbb56c1..18b5255aa 100644
--- a/app/src/main/res/layout/nav_feedlistitem.xml
+++ b/app/src/main/res/layout/nav_feedlistitem.xml
@@ -17,7 +17,7 @@
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:cropToPadding="true"
- android:scaleType="fitXY"
+ android:scaleType="centerCrop"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:layout_marginLeft="@dimen/listitem_icon_leftpadding"
diff --git a/app/src/main/res/layout/new_episodes_listitem.xml b/app/src/main/res/layout/new_episodes_listitem.xml
index cde1b4aa6..0f1e873f3 100644
--- a/app/src/main/res/layout/new_episodes_listitem.xml
+++ b/app/src/main/res/layout/new_episodes_listitem.xml
@@ -33,8 +33,8 @@
<ImageView
android:id="@+id/imgvCover"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
+ android:layout_height="64dp"
+ android:layout_width="64dp"
android:layout_alignLeft="@id/txtvPlaceholder"
android:layout_alignTop="@id/txtvPlaceholder"
android:layout_alignRight="@id/txtvPlaceholder"
diff --git a/app/src/main/res/layout/preference_switch_layout.xml b/app/src/main/res/layout/preference_switch_layout.xml
new file mode 100644
index 000000000..54fa74061
--- /dev/null
+++ b/app/src/main/res/layout/preference_switch_layout.xml
@@ -0,0 +1,9 @@
+<?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 d950f11d2..8de80e355 100644
--- a/app/src/main/res/layout/queue_listitem.xml
+++ b/app/src/main/res/layout/queue_listitem.xml
@@ -12,17 +12,19 @@
android:layout_height="@dimen/listitem_threeline_height"
android:background="?attr/selectableItemBackground"
android:orientation="horizontal"
- android:paddingLeft="8dp"
android:gravity="center_vertical"
+ android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
tools:background="@android:color/darker_gray" >
<ImageView
android:id="@+id/drag_handle"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
+ android:layout_width="104dp"
+ android:layout_height="64dp"
android:layout_marginLeft="-16dp"
- android:layout_marginRight="-20dp"
- android:gravity="center"
+ android:layout_marginStart="-16dp"
+ android:layout_marginRight="-72dp"
+ android:layout_marginEnd="-72dp"
android:contentDescription="@string/drag_handle_content_description"
android:scaleType="fitXY"
android:src="?attr/dragview_background"
@@ -32,26 +34,22 @@
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dp">
+ android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp">
<TextView
android:id="@+id/txtvPlaceholder"
android:layout_width="@dimen/thumbnail_length_queue_item"
android:layout_height="@dimen/thumbnail_length_queue_item"
- android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
- android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
- android:layout_gravity="center_vertical"
+ android:layout_centerVertical="true"
android:gravity="center"
android:background="@color/light_gray"
android:maxLines="3"
android:ellipsize="end"/>
<ImageView
android:id="@+id/imgvCover"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignLeft="@id/txtvPlaceholder"
- android:layout_alignTop="@id/txtvPlaceholder"
- android:layout_alignRight="@id/txtvPlaceholder"
- android:layout_alignBottom="@id/txtvPlaceholder"
+ android:layout_width="@dimen/thumbnail_length_queue_item"
+ android:layout_height="@dimen/thumbnail_length_queue_item"
+ android:layout_centerVertical="true"
android:contentDescription="@string/cover_label"
tools:src="@drawable/ic_stat_antenna_default"
tools:background="@android:color/holo_green_dark"/>
@@ -77,7 +75,7 @@
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="8dp"
- android:gravity="right|bottom"
+ android:gravity="right|top"
android:text="Feb\n12"
tools:background="@android:color/holo_blue_light" />
diff --git a/app/src/main/res/layout/storage_error.xml b/app/src/main/res/layout/storage_error.xml
index c1ee77262..8ff28b3c1 100644
--- a/app/src/main/res/layout/storage_error.xml
+++ b/app/src/main/res/layout/storage_error.xml
@@ -1,25 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:padding="16dp">
<ImageView
android:id="@+id/imageView1"
android:contentDescription="@string/external_storage_error_msg"
- android:layout_width="30dp"
- android:layout_height="30dp"
- android:layout_centerHorizontal="true"
- android:layout_centerVertical="true"
- android:layout_margin="16dp"
- android:src="@android:drawable/stat_notify_sdcard_usb" />
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_margin="8dp"
+ android:src="?attr/ic_sd_storage" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@+id/imageView1"
- android:layout_centerHorizontal="true"
android:layout_margin="8dp"
android:text="@string/external_storage_error_msg" />
-</RelativeLayout> \ No newline at end of file
+ <Button
+ android:id="@+id/btnChooseDataFolder"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:text="@string/choose_data_directory"/>
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/videoplayer_activity.xml b/app/src/main/res/layout/videoplayer_activity.xml
index 766cd6e04..2e1097fb8 100644
--- a/app/src/main/res/layout/videoplayer_activity.xml
+++ b/app/src/main/res/layout/videoplayer_activity.xml
@@ -19,14 +19,41 @@
android:indeterminateOnly="true"
android:visibility="invisible" />
- <ImageButton
- android:id="@+id/butPlay"
+ <LinearLayout
+ android:id="@+id/controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:background="@drawable/overlay_button_circle_background"
- android:contentDescription="@string/pause_label"
- android:src="@drawable/ic_av_pause_circle_outline_80dp" />
+ android:orientation="horizontal">
+
+ <ImageButton
+ android:id="@+id/butRev"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:background="@drawable/overlay_button_circle_background"
+ android:contentDescription="@string/pause_label"
+ android:src="@drawable/ic_av_rewind_80dp" />
+
+ <ImageButton
+ android:id="@+id/butPlay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:background="@drawable/overlay_button_circle_background"
+ android:contentDescription="@string/pause_label"
+ android:src="@drawable/ic_av_pause_circle_outline_80dp" />
+
+ <ImageButton
+ android:id="@+id/butFF"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:background="@drawable/overlay_button_circle_background"
+ android:contentDescription="@string/pause_label"
+ android:src="@drawable/ic_av_fast_forward_80dp" />
+
+ </LinearLayout>
<LinearLayout
android:id="@+id/overlay"
@@ -77,7 +104,9 @@
android:layout_toLeftOf="@+id/txtvLength"
android:layout_toRightOf="@+id/txtvPosition"
android:max="500" />
+
</RelativeLayout>
+
</LinearLayout>
-</FrameLayout> \ No newline at end of file
+</FrameLayout>
diff --git a/app/src/main/res/menu/directory_chooser.xml b/app/src/main/res/menu/directory_chooser.xml
index 7735ffd2c..3f860d636 100644
--- a/app/src/main/res/menu/directory_chooser.xml
+++ b/app/src/main/res/menu/directory_chooser.xml
@@ -1,14 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:custom="http://schemas.android.com/apk/res-auto">
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto">
+
<item
android:id="@+id/new_folder_item"
android:title="@string/create_folder_label"
- custom:showAsAction="ifRoom|withText"/>
+ android:icon="?attr/ic_create_new_folder"
+ custom:showAsAction="ifRoom|withText" />
<item
android:id="@+id/set_to_default_folder_item"
- custom:showAsAction="collapseActionView"
- android:title="@string/set_to_default_folder"/>
-
+ android:title="@string/set_to_default_folder"
+ custom:showAsAction="collapseActionView" />
-</menu> \ No newline at end of file
+</menu>
diff --git a/app/src/main/res/menu/downloads_completed.xml b/app/src/main/res/menu/downloads_completed.xml
new file mode 100644
index 000000000..dc2996893
--- /dev/null
+++ b/app/src/main/res/menu/downloads_completed.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/episode_actions"
+ android:menuCategory="container"
+ android:title="@string/episode_actions"
+ custom:showAsAction="always">
+ </item>
+
+</menu>
diff --git a/app/src/main/res/menu/episodes_apply_action_options.xml b/app/src/main/res/menu/episodes_apply_action_options.xml
index 88bef8d1f..3df88046d 100644
--- a/app/src/main/res/menu/episodes_apply_action_options.xml
+++ b/app/src/main/res/menu/episodes_apply_action_options.xml
@@ -4,11 +4,10 @@
<item
android:id="@+id/sort"
+ android:icon="?attr/ic_sort"
android:title="@string/sort"
app:showAsAction="always">
<menu>
- <item android:id="@+id/sort_title"
- android:title="@string/sort_title"/>
<item android:id="@+id/sort_title_a_z"
android:title="@string/sort_title_a_z"/>
<item android:id="@+id/sort_title_z_a"
@@ -25,18 +24,12 @@
</item>
<item
- android:id="@+id/select_toggle"
- android:title="@string/select_all_label"
- app:showAsAction="always"/>
-
- <item
android:id="@+id/select_options"
- android:title="@string/all_label"
+ android:icon="?attr/ic_filter"
+ android:title="@string/filter"
app:showAsAction="always">
<menu>
- <item android:id="@+id/select_label"
- android:title="@string/select_label"/>
<item android:id="@+id/check_all"
android:title="@string/all_label"/>
<item android:id="@+id/check_none"
@@ -49,7 +42,15 @@
android:title="@string/downloaded_label"/>
<item android:id="@+id/check_not_downloaded"
android:title="@string/not_downloaded_label"/>
+ <item android:id="@+id/check_queued"
+ android:title="@string/queued_label"/>
+ <item android:id="@+id/check_not_queued"
+ android:title="@string/not_queued_label"/>
</menu>
</item>
+ <item
+ android:id="@+id/select_toggle"
+ android:title="@string/select_all_label"
+ app:showAsAction="always"/>
</menu>
diff --git a/app/src/main/res/menu/feeditemlist_context.xml b/app/src/main/res/menu/feeditemlist_context.xml
index 7b10e5cce..271cb96a7 100644
--- a/app/src/main/res/menu/feeditemlist_context.xml
+++ b/app/src/main/res/menu/feeditemlist_context.xml
@@ -26,6 +26,15 @@
android:title="@string/remove_from_queue_label" />
<item
+ android:id="@+id/add_to_favorites_item"
+ android:menuCategory="container"
+ android:title="@string/add_to_favorite_label" />
+ <item
+ android:id="@+id/remove_from_favorites_item"
+ android:menuCategory="container"
+ android:title="@string/remove_from_favorite_label" />
+
+ <item
android:id="@+id/reset_position"
android:menuCategory="container"
android:title="@string/reset_position" />
diff --git a/app/src/main/res/menu/feedlist.xml b/app/src/main/res/menu/feedlist.xml
index 54b90f5c6..ed03c08d6 100644
--- a/app/src/main/res/menu/feedlist.xml
+++ b/app/src/main/res/menu/feedlist.xml
@@ -3,10 +3,10 @@
xmlns:custom="http://schemas.android.com/apk/res-auto">
<item
- android:id="@+id/hide_items"
+ android:id="@+id/filter_items"
android:icon="?attr/ic_filter"
android:menuCategory="container"
- android:title="@string/hide_episodes_title"
+ android:title="@string/filter"
custom:showAsAction="always">
</item>
<item
diff --git a/app/src/main/res/menu/itunes_search.xml b/app/src/main/res/menu/itunes_search.xml
new file mode 100644
index 000000000..88fa36a4a
--- /dev/null
+++ b/app/src/main/res/menu/itunes_search.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/action_search"
+ android:icon="?attr/action_search"
+ custom:showAsAction="collapseActionView|ifRoom"
+ custom:actionViewClass="android.support.v7.widget.SearchView"
+ android:title="@string/search_label"/>
+
+</menu>
diff --git a/app/src/main/res/menu/mediaplayer.xml b/app/src/main/res/menu/mediaplayer.xml
index 053e68552..c4086bf5e 100644
--- a/app/src/main/res/menu/mediaplayer.xml
+++ b/app/src/main/res/menu/mediaplayer.xml
@@ -3,22 +3,35 @@
xmlns:custom="http://schemas.android.com/apk/res-auto">
<item
+ android:id="@+id/add_to_favorites_item"
+ android:icon="?attr/ic_fav"
+ android:title="@string/add_to_favorite_label"
+ custom:showAsAction="always">
+ </item>
+ <item
+ android:id="@+id/remove_from_favorites_item"
+ android:icon="?attr/ic_unfav"
+ android:title="@string/remove_from_favorite_label"
+ custom:showAsAction="always">
+ </item>
+
+ <item
android:id="@+id/disable_sleeptimer_item"
- android:icon="?attr/device_access_time"
+ android:icon="?attr/ic_sleep_off"
custom:showAsAction="always"
android:title="@string/sleep_timer_label">
</item>
<item
android:id="@+id/set_sleeptimer_item"
- custom:showAsAction="collapseActionView"
+ android:icon="?attr/ic_sleep"
+ custom:showAsAction="always"
android:title="@string/set_sleeptimer_label">
</item>
<item
- android:id="@+id/skip_episode_item"
- custom:showAsAction="collapseActionView"
- android:title="@string/skip_episode_label"
- android:visible="true">
+ android:id="@+id/audio_controls"
+ android:title="@string/audio_controls"
+ custom:showAsAction="always">
</item>
<item
@@ -30,7 +43,9 @@
</item>
<item
android:id="@+id/share_item"
+ android:icon="?attr/social_share"
android:menuCategory="container"
+ custom:showAsAction="ifRoom"
android:title="@string/share_label">
<menu>
<item
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index e9e9d48f7..3ecd79b1e 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory android:title="@string/user_interface_label">
<com.afollestad.materialdialogs.prefs.MaterialListPreference
@@ -8,7 +10,8 @@
android:title="@string/pref_set_theme_title"
android:key="prefTheme"
android:summary="@string/pref_set_theme_sum"
- android:defaultValue="0"/>
+ android:defaultValue="0"
+ app:useStockLayout="true"/>
<PreferenceScreen
android:key="prefDrawerSettings"
android:summary="@string/pref_nav_drawer_sum"
@@ -23,34 +26,36 @@
android:title="@string/pref_nav_drawer_feed_order_title"
android:key="prefDrawerFeedOrder"
android:summary="@string/pref_nav_drawer_feed_order_sum"
- android:defaultValue="0"/>
+ 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"/>
+ android:defaultValue="0"
+ app:useStockLayout="true"/>
</PreferenceScreen>
- <CheckBoxPreference
+ <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"/>
- <CheckBoxPreference
+ <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"/>
- <CheckBoxPreference
+ <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"/>
- <CheckBoxPreference
+ <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="true"
android:enabled="true"
android:key="prefShowDownloadReport"
@@ -59,7 +64,7 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/queue_label">
- <CheckBoxPreference
+ <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="false"
android:enabled="true"
android:key="prefQueueAddToFront"
@@ -69,45 +74,51 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/playback_pref">
- <CheckBoxPreference
+ <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"/>
- <CheckBoxPreference
+ <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"/>
- <CheckBoxPreference
+ <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"/>
- <CheckBoxPreference
+ <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"/>
- <CheckBoxPreference
+ <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"/>
- <CheckBoxPreference
+ <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"/>
- <CheckBoxPreference
+ <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="false"
android:enabled="true"
android:key="prefAutoDelete"
@@ -119,19 +130,20 @@
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"/>
+ 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" />
- <CheckBoxPreference
+ <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" />
- <CheckBoxPreference
+ <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="true"
android:enabled="true"
android:key="prefResumeAfterCall"
@@ -144,46 +156,47 @@
android:key="prefAutoUpdateIntervall"
android:summary="@string/pref_autoUpdateIntervallOrTime_sum"
android:title="@string/pref_autoUpdateIntervallOrTime_title"/>
- <CheckBoxPreference
+ <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"/>
-
+ 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"/>
- <com.afollestad.materialdialogs.prefs.MaterialListPreference
- android:defaultValue="20"
- android:entries="@array/episode_cache_size_entries"
- android:key="prefEpisodeCacheSize"
- android:title="@string/pref_episode_cache_title"
- android:entryValues="@array/episode_cache_size_values"/>
+ 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">
- <CheckBoxPreference
+ <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:key="prefEnableAutoDl"
android:title="@string/pref_automatic_download_title"
android:defaultValue="false"/>
- <CheckBoxPreference
+ <com.afollestad.materialdialogs.prefs.MaterialListPreference
+ android:defaultValue="20"
+ 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"/>
- <CheckBoxPreference
+ <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:key="prefEnableAutoDownloadWifiFilter"
android:title="@string/pref_autodl_wifi_filter_title"
android:summary="@string/pref_autodl_wifi_filter_sum"/>
@@ -256,14 +269,5 @@
android:title="@string/crash_report_title"
android:summary="@string/crash_report_sum"/>
</PreferenceCategory>
-
- <PreferenceCategory android:title="@string/experimental_pref">
- <CheckBoxPreference
- android:defaultValue="false"
- android:enabled="false"
- android:key="prefSonic"
- android:summary="@string/pref_sonic_message"
- android:title="@string/pref_sonic_title"/>
- </PreferenceCategory>
-
+
</PreferenceScreen>
diff --git a/app/src/main/templates/about.html b/app/src/main/templates/about.html
index 21599bdb8..222429b17 100644
--- a/app/src/main/templates/about.html
+++ b/app/src/main/templates/about.html
@@ -59,13 +59,13 @@
<h1>Used libraries</h1>
<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_COMMONS.txt">(View)</a>
+by The Apache Software Foundation, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<h2>EventBus <a href="https://github.com/greenrobot/EventBus">(Link)</a></h2>
-by greenrobot, licensed under the Apache 2.0 license <a href="LICENSE_EVENTBUS.txt">(View)</a>
+by greenrobot, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<h2>flattr4j <a href="http://www.shredzone.org/projects/flattr4j/wiki">(Link)</a></h2>
-licensed under the Apache 2.0 license <a href="LICENSE_FLATTR4J.txt">(View)</a>
+licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<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>
@@ -86,22 +86,22 @@ by Aidan Michael Follestad, licensed under the MIT License <a href="LICENSE_MATE
by Square, licensed under the Apache 2.0 license <a href="LICENSE_OKHTTP.txt">(View)</a>
<h2>Okio <a href="https://github.com/square/okio">(Link)</a></h2>
-by Square, licensed under the Apache 2.0 license <a href="LICENSE_OKIO.txt">(View)</a>
+by Square, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<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>
<h2>RecyclerView-FlexibleDivider <a href="https://github.com/yqritc/RecyclerView-FlexibleDivider">(Link)</a></h2>
-licensed under the Apache 2.0 license <a href="LICENSE_FLEXIBLE_DIVIDER.txt">(View)</a>
+licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<h2>RxAndroid <a href="https://github.com/ReactiveX/RxAndroid">(Link)</a></h2>
-licensed under the Apache 2.0 license <a href="LICENSE_RX_ANDROID.txt">(View)</a>
+licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<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_STACKBLUR.txt">(View)</a>
+by Enrique L&oacute;pez Ma&ntilde;as, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<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_ANTENNAPOD_AUDIOPLAYER.txt">(View)</a>
+by the AntennaPod team, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
</body>
</html>
diff --git a/build.gradle b/build.gradle
index 2a0fb0aa3..53ea77e5d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,8 +5,8 @@ buildscript {
jcenter()
}
dependencies {
- classpath "com.android.tools.build:gradle:1.3.1"
- classpath "me.tatarka:gradle-retrolambda:3.2.3"
+ classpath "com.android.tools.build:gradle:1.5.0"
+ classpath "me.tatarka:gradle-retrolambda:3.2.4"
classpath "me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2"
// Exclude the version that the android plugin depends on.
@@ -36,25 +36,30 @@ subprojects {
}
project.ext {
- compileSdkVersion = 22
- buildToolsVersion = "22.0.1"
+ compileSdkVersion = 23
+ buildToolsVersion = "23.0.2"
minSdkVersion = 10
- targetSdkVersion = 22
+ targetSdkVersion = 23
- supportVersion = "22.2.1"
+ supportVersion = "23.1.1"
commonsioVersion = "2.4"
commonslangVersion = "3.4"
eventbusVersion = "2.4.0"
flattr4jVersion = "2.12"
glideVersion = "3.6.1"
+ iconifyVersion = "2.1.1"
jsoupVersion = "1.7.3"
- rxAndroidVersion = "1.0.1"
- rxJavaVersion = "1.0.16"
- rxJavaRulesVersion = "1.0.16.1"
- okhttpVersion = "2.5.0"
+ materialDialogsVersion = "0.8.5.3@aar"
+ okhttpVersion = "2.7.4"
okioVersion = "1.6.0"
+ recyclerviewFlexibledividerVersion = "1.2.6"
+ rxAndroidVersion = "1.1.0"
+ rxJavaVersion = "1.1.0"
+ rxJavaRulesVersion = "1.1.0.0"
+
+ audioPlayerVersion = "v1.0.12"
}
task wrapper(type: Wrapper) {
- gradleVersion = "2.4"
+ gradleVersion = "2.11"
}
diff --git a/changelog/ar.md b/changelog/ar.md
index 06111059e..6b161ebf8 100644
--- a/changelog/ar.md
+++ b/changelog/ar.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/az.md b/changelog/az.md
index 06111059e..6b161ebf8 100644
--- a/changelog/az.md
+++ b/changelog/az.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/ca.md b/changelog/ca.md
index c1d5920d6..36d21ea43 100644
--- a/changelog/ca.md
+++ b/changelog/ca.md
@@ -1,5 +1,21 @@
Registre de canvis
====================
+Version 1.5.0
+--------------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+--------------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/ca_ES.md b/changelog/ca_ES.md
new file mode 100644
index 000000000..6b161ebf8
--- /dev/null
+++ b/changelog/ca_ES.md
@@ -0,0 +1,347 @@
+Change Log
+==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
+
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
+Version 1.4
+-----------
+* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
+* VIBRATE PERMISSION: Used optionally with the sleep timer
+* Native variable speed playback (experimental via options)
+* Improved sleep timer
+* Mark episodes as 'favorite'
+* Notification can skip episodes
+* Keep episodes when skipping them
+* Episode art on lock screen
+* Flexible episode cleanup
+* Rewind after pause
+* Usability improvements
+* Bug fixes
+
+Version 1.3
+-----------
+* Bulk actions on feed episodes (download, queue, delete)
+* Reduced space used by images
+* Automatic refresh at a certain time of day
+* Customizable indicators and sorting for feeds
+* Ability to share feeds
+* Improved auto download
+* Many fixes and usability improvements
+
+Version 1.2
+-----------
+* Optionally disable swiping and dragging in the queue
+* Resume playback after phone call
+* Filter episodes in the Podcast feed
+* Hide items in the Nav drawer
+* Customize times for fast forward and rewind
+* Resolved issues with opening some OPML files
+* Various bug fixes and usability improvements
+
+Version 1.1
+-----------
+* iTunes podcast integration
+* Swipe to remove items from the queue
+* Set the number of parallel downloads
+* Fix for gpodder.net on old devices
+* Fixed date problems for some feeds
+* Display improvements
+* Usability improvements
+* Several other bugfixes
+
+Version 1.0
+-----------
+* The queue can now be sorted
+* Added option to delete episode after playback
+* Fixed a bug that caused chapters to be displayed multiple times
+* Several other improvements and bugfixes
+
+
+Version 0.9.9.6
+---------------
+* Fixed problems related to variable playback speed plugins
+* Fixed automatic feed update problems
+* Several other bugfixes and improvements
+
+Version 0.9.9.5
+---------------
+* Added support for paged feeds
+* Improved user interface
+* Added Japanese and Turkish translations
+* Fixed more image loading problems
+* Other bugfixes and improvements
+
+Version 0.9.9.4
+---------------
+* Added option to keep notification and lockscreen controls when playback is paused
+* Fixed a bug where episode images were not loaded correctly
+* Fixed battery usage problems
+
+Version 0.9.9.3
+---------------
+* Fixed video playback problems
+* Improved image loading
+* Other bugfixes and improvements
+
+Version 0.9.9.2
+---------------
+* Added support for feed discovery if a website URL is entered
+* Added support for 'next'/'previous' media keys
+* Improved sleep timer
+* Timestamps in shownotes can now be used to jump to a specific position
+* Automatic Flattring is now configurable
+* Several bugfixes and improvements
+
+Version 0.9.9.1
+---------------
+* Several bugfixes and improvements
+
+Version 0.9.9.0
+---------------
+* New user interface
+* Failed downloads are now resumed when restarted
+* Added support for Podlove Alternate Feeds
+* Added support for "pcast"-protocol
+* Added backup & restore functionality. This feature has to be enabled in the Android settings in order to work
+* Several bugfixes and improvements
+
+Version 0.9.8.3
+---------------
+* Added support for password-protected feeds and episodes
+* Added support for more types of episode images
+* Added Hebrew translation
+* Several bugfixes and improvements
+
+Version 0.9.8.2
+---------------
+* Several bugfixes and improvements
+* Added Korean translation
+
+Version 0.9.8.1
+---------------
+* Added option to flattr an episode automatically after 80 percent of the episode have been played
+* Added Polish translation
+* Several bugfixes and improvements
+
+Version 0.9.8.0
+---------------
+* Added access to the gpodder.net directory
+* Added ability to sync podcast subscriptions with the gpodder.net service
+* Automatic download can now be turned on or off for specific podcasts
+* Added option to pause playback when another app is playing sounds
+* Added Dutch and Hindi translation
+* Resolved a problem with automatic podcast updates
+* Resolved a problem with the buttons' visibility in the episode screen
+* Resolved a problem where episodes would be re-downloaded unnecessarily
+* Several other bugfixes and usability improvements
+
+Version 0.9.7.5
+---------------
+* Reduced application startup time
+* Reduced memory usage
+* Added option to change the playback speed
+* Added Swedish translation
+* Several bugfixes and improvements
+
+Version 0.9.7.4
+---------------
+* Episode cache size can now be set to unlimited
+* Removing an episode in the queue via sliding can now be undone
+* Added support for Links in MP3 chapters
+* Added Czech(Czech Republic), Azerbaijani and Portuguese translations
+* Several bugfixes and improvements
+
+Version 0.9.7.3
+---------------
+* Bluetooth devices now display metadata during playback (requires AVRCP 1.3 or higher)
+* User interface improvements
+* Several bugfixes
+
+Version 0.9.7.2
+---------------
+* Automatic download can now be disabled
+* Added Italian (Italy) translation
+* Several bugfixes
+
+Version 0.9.7.1
+---------------
+* Added automatic download of new episodes
+* Added option to specify the number of downloaded episodes to keep on the device
+* Added support for playback of external media files
+* Several improvements and bugfixes
+* Added Catalan translation
+
+Version 0.9.7
+-------------
+* Improved user interface
+* OPML files can now be imported by selecting them in a file browser
+* The queue can now be organized via drag & drop
+* Added expandable notifications (only supported on Android 4.1 and above)
+* Added Danish, French, Romanian (Romania) and Ukrainian (Ukraine) translation (thanks to all translators!)
+* Several bugfixes and minor improvements
+
+Version 0.9.6.4
+---------------
+* Added Chinese translation (Thanks tupunco!)
+* Added Portuguese (Brazil) translation (Thanks mbaltar!)
+* Several bugfixes
+
+Version 0.9.6.3
+---------------
+* Added the ability change the location of AntennaPod's data folder
+* Added Spanish translation (Thanks frandavid100!)
+* Solved problems with several feeds
+
+Version 0.9.6.2
+---------------
+* Fixed import problems with some OPML files
+* Fixed download problems
+* AntennaPod now recognizes changes of episode information
+* Other improvements and bugfixes
+
+Version 0.9.6.1
+---------------
+* Added dark theme
+* Several bugfixes and improvements
+
+Version 0.9.6
+-------------
+* Added support for VorbisComment chapters
+* AntennaPod now shows items as 'in progress' when playback has started
+* Reduced memory usage
+* Added support for more feed types
+* Several bugfixes
+
+
+Version 0.9.5.3
+---------------
+* Fixed crash when trying to start playback on some devices
+* Fixed problems with some feeds
+* Other bugfixes and improvements
+
+Version 0.9.5.2
+---------------
+* Media player now doesn't use network bandwidth anymore if not in use
+* Other improvements and bugfixes
+
+Version 0.9.5.1
+---------------
+* Added playback history
+* Improved behavior of download report notifications
+* Improved support for headset controls
+* Bugfixes in the feed parser
+* Moved 'OPML import' button into the 'add feed' screen and the 'OPML export' button into the settings screen
+
+Version 0.9.5
+-------------
+* Experimental support for MP3 chapters
+* New menu options for the 'new' list and the queue
+* Auto-delete feature
+* Better Download error reports
+* Several Bugfixes
+
+Version 0.9.4.6
+---------------
+* Enabled support for small-screen devices
+* Disabling the sleep timer should now work again
+
+Version 0.9.4.5
+---------------
+* Added Russian translation (Thanks older!)
+* Added German translation
+* Several bugfixes
+
+Version 0.9.4.4
+---------------
+* Added player controls at the bottom of the main screen and the feedlist screens
+* Improved media playback
+
+Version 0.9.4.3
+---------------
+* Fixed several bugs in the feed parser
+* Improved behavior of download reports
+
+Version 0.9.4.2
+---------------
+* Fixed bug in the OPML importer
+* Reduced memory usage of images
+* Fixed download problems on some devices
+
+Version 0.9.4.1
+---------------
+* Changed behavior of download notifications
+
+Version 0.9.4
+-------------
+* Faster and more reliable downloads
+* Added lockscreen player controls for Android 4.x devices
+* Several bugfixes
+
+Version 0.9.3.1
+---------------
+* Added preference to hide feed items which don't have an episode
+* Improved image size for some some screen sizes
+* Added grid view for large screens
+* Several bugfixes
+
+Version 0.9.3
+-------------
+* MiroGuide integration
+* Bugfixes in the audio- and videoplayer
+* Automatically add feeds to the queue when they have been downloaded
+
+Version 0.9.2
+-------------
+* Bugfixes in the user interface
+* GUID and ID attributes are now recognized by the Feedparser
+* Stability improvements when adding several feeds at the same time
+* Fixed bugs that occured when adding certain feeds
+
+Version 0.9.1.1
+--------------------
+* Changed Flattr credentials
+* Improved layout of Feed information screen
+* AntennaPod is now open source! The source code is available at https://github.com/danieloeh/AntennaPod
+
+Version 0.9.1
+-----------------
+* Added support for links in SimpleChapters
+* Bugfix: Current Chapter wasn't always displayed correctly
+
+Version 0.9
+--------------
+
+* OPML export
+* Flattr integration
+* Sleep timer
+
+Version 0.8.2
+-------------
+
+* Added search
+* Improved OPML import experience
+* More bugfixes
+
+Version 0.8.1
+------------
+
+* Added support for SimpleChapters
+* OPML import \ No newline at end of file
diff --git a/changelog/cs_CZ.md b/changelog/cs_CZ.md
index 3523ac125..8d2a3216b 100644
--- a/changelog/cs_CZ.md
+++ b/changelog/cs_CZ.md
@@ -1,5 +1,21 @@
Seznam změn
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Opravy chyb
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/da.md b/changelog/da.md
index 72858a0b0..6ed718330 100644
--- a/changelog/da.md
+++ b/changelog/da.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/de.md b/changelog/de.md
index db3fcef98..3ba070abb 100644
--- a/changelog/de.md
+++ b/changelog/de.md
@@ -1,5 +1,21 @@
Änderungen
==========
+Version 1.5.0
+-------------
+* Schließe Episoden mit Hilfe von Schlüsselwörtern beim Automatischen Herunterladen aus
+* Schließe einzelne Feeds vom automatischen Aktualisieren aus
+* Verbesserter Audio-Player
+* Verbesserungen an der Benutzeroberfläche
+* Fehlerkorrekturen
+
+Version 1.4.1
+-------------
+* Performance-Verbesserungen
+* Tasten spulen nun vor oder zurück statt zur nächsten Episode zu springen
+* Einstellung, zur nächsten Episode zu springen statt vorzuspulen
+* Möglichkeit, Absturzberichte an Entwickler zu schicken
+* Hebe Episode hervor, die gerade abgespielt wird
+* Widget-Verbesserungen
Version 1.4.0.12
----------------
diff --git a/changelog/el.md b/changelog/el.md
index 57be32b28..500156297 100644
--- a/changelog/el.md
+++ b/changelog/el.md
@@ -1,36 +1,52 @@
Καταγραφή Αλλαγών
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Διορθώσεις σφαλμάτων
-Version 1.4.0.12
+Έκδοση 1.4.1
+-------------
+* Βελτιστοποίηση απόδοσης
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
+
+Έκδοση 1.4.0.12
----------------
* Fix for crash on Huawei devices (media buttons may not work)
-Version 1.4
+Έκδοση 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
* VIBRATE PERMISSION: Used optionally with the sleep timer
* Native variable speed playback (experimental via options)
* Βελτίωση χρονομετρητή ύπνου
-* Mark episodes as 'favorite'
+* Σήμανση επεισοδίων ως 'αγαπημένα'
* Notification can skip episodes
* Keep episodes when skipping them
-* Episode art on lock screen
-* Flexible episode cleanup
-* Rewind after pause
+* Εξώφυλλο επεισοδίου στην οθόνη κλειδώματος
+* Ευέλικτη εκκαθάριση επεισοδίων
+* Επαναφορά μετά από παύση
* Βελτιώσεις χρηστικότητας
-* Bug fixes
+* Διορθώσεις σφαλμάτων
-Version 1.3
+Έκδοση 1.3
-----------
* Bulk actions on feed episodes (download, queue, delete)
-* Reduced space used by images
-* Automatic refresh at a certain time of day
+* Ελαχιστοποίηση του αποθηκευτικού χώρου που δεσμεύουν οι εικόνες
+* Αυτόματη ανανέωση σε συγκεκριμένη ώρα της ημέρας
* Customizable indicators and sorting for feeds
-* Ability to share feeds
-* Improved auto download
-* Many fixes and usability improvements
+* Δυνατότητα διαμοιρασμού ροών
+* Βελτίωση αυτόματης λήψης
+* Αρκετές διορθώσεις και βελτιώσεις χρηστικότητας
-Version 1.2
+Έκδοση 1.2
-----------
* Optionally disable swiping and dragging in the queue
* Resume playback after phone call
@@ -38,7 +54,7 @@ Version 1.2
* Hide items in the Nav drawer
* Customize times for fast forward and rewind
* Resolved issues with opening some OPML files
-* Various bug fixes and usability improvements
+* Διάφορες διορθώσεις σφαλμάτων και βελτιώσεις χρηστικότητας
Έκδοση 1.1
-----------
diff --git a/changelog/es.md b/changelog/es.md
index 023cc4eae..9ead9a186 100644
--- a/changelog/es.md
+++ b/changelog/es.md
@@ -1,9 +1,25 @@
Registro de cambios
==========
+Versión 1.5.0
+-------------
+* Excluir episodios de la auto descarga usando palabras clave
+* Configurar que algunos feeds no se refresquen automáticamente
+* Reproductor mejorado
+* Interfaz de usuario mejorada
+* Corrección de fallos
-Version 1.4.0.12
+Versión 1.4.1
+-------------
+* Mejoras de rendimiento
+* Los botones hardware avanzan y retroceden en lugar de saltar episodio
+* Opción para saltar capítulos con el botón de avanzar
+* Opción para enviar reportes de fallo a los desarrolladores
+* Resaltar el episodio actual
+* Mejoras del widget
+
+Versión 1.4.0.12
----------------
-* Fix for crash on Huawei devices (media buttons may not work)
+* Arreglado cierre en dispositivos Huawei (los botones multimedia podría no funcionar)
Versión 1.4
-----------
diff --git a/changelog/es_ES.md b/changelog/es_ES.md
index 06111059e..6b161ebf8 100644
--- a/changelog/es_ES.md
+++ b/changelog/es_ES.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/fi.md b/changelog/fi.md
index 06111059e..6b161ebf8 100644
--- a/changelog/fi.md
+++ b/changelog/fi.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/fr.md b/changelog/fr.md
index 130774662..a582031fe 100644
--- a/changelog/fr.md
+++ b/changelog/fr.md
@@ -1,5 +1,21 @@
Nouveautés
==========
+Version 1.5.0
+-------------
+* Exclure du téléchargement automatique certains épisodes à partir de mots clés
+* Paramétrer les flux afin d'empêcher leur mise à jour automatique
+* Amélioration du lecteur audio
+* Amélioration de l'interface
+Corrections de bugs
+
+Version 1.4.1
+-------------
+* Amélioration des performances
+* Les boutons physiques font des sauts avant et arrière au lieu de changer d'épisode
+* Option pour que le bouton piste suivante change d'épisode
+* Option pour envoyer directement un rapports de crash aux développeurs
+* Mise en surbrillance de l'épisode en cours de lecture
+*Améliorations du Widget
Version 1.4.0.12
----------------
@@ -17,7 +33,7 @@ Vitesse de lecture native variable (option expérimentale)
Image de l’épisode sur l’écran de verrouillage
*Nettoyage flexible des épisodes
*Rembobiner après une pause
-* Améliorations dans l'interface utilisateur
+* Améliorations de l'interface utilisateur
Corrections de bugs
Version 1.3
@@ -25,30 +41,30 @@ Version 1.3
* Actions en masse sur les épisodes (téléchargement, mettre en liste, supprimer)
* Réduction de l'espace disque utilisé par les images
* Rafraîchissement automatique à un moment de la journée
-Les indicateurs et le tri des fils RSS sont personnalisables
+* Les indicateurs et le tri des fils RSS sont personnalisables
* Possibilité de partager les flux
* Amélioration du téléchargement automatique
* Corrections de multiples bogues et améliorations de l'interface
Version 1.2
-----------
-Désactiver la capacité à déplacer les éléments dans la liste
+* Option pour désactiver la capacité à déplacer les éléments dans la liste
* Reprendre la lecture après un appel téléphonique
-* Filtrer des épisodes dans les flux de podcasts
-Cacher des éléments dans le volet de navigation
-Personnaliser le délai pour l'avance rapide et retour arrière
-* Résolution de problèmes liés à l'ouverture de certains fichiers OPML
+* Filtrer les épisodes dans le flux
+* Cacher des éléments dans le volet de navigation
+* Personnaliser le délai pour l'avance rapide et retour arrière
+* Problèmes résolus lors de l'ouverture de certains fichiers OPML
* Corrections de bogues divers et améliorations de l'interface
Version 1.1
-----------
-Intégration avec iTunes podcast
-Glisser pour retirer les éléments de la liste
-* Définition du nombre de téléchargements simultanés
+* Intégration des podcast avec iTunes
+* Faire glisser pour retirer les éléments de la liste
+* Paramétrer le nombre de téléchargements simultanés
Corrections concernant gpodder.net sur certains vieux appareils
-* Problèmes résolus avec la date de certains flux
-* Améliorations dans l'affichage
-* Améliorations dans l'interface utilisateur
+* Problèmes résolus concernant la date de certains flux
+* Améliorations de l'affichage
+* Améliorations de l'interface utilisateur
* Autres corrections de bogues
Version 1.0
@@ -61,7 +77,7 @@ Version 1.0
Version 0.9.9.6
---------------
-* Résolution de problèmes liés aux plugins pour lecture à vitesse variable
+* Résolution de problèmes liés aux plugins pour la lecture à vitesse variable
* Résolution de problèmes liés à la mise à jour automatique des flux
* Correction de bogues et améliorations
@@ -87,7 +103,7 @@ Version 0.9.9.3
Version 0.9.9.2
---------------
-* Intégration d'un système de découverte de flux à partir d'une url de site web
+* Intégration d'un système de découverte de flux à partir de l'URL d'un site web
* Intégration du contrôle de lecture par les touches média "précédent"/"suivant"
* Système d'arrêt automatique amélioré
* Possibilité d'utiliser l'horodatage présent dans les notes d'épisode pour aller à une position spécifique dans la lecture
@@ -103,14 +119,14 @@ Version 0.9.9.0
* Nouvelle interface utilisateur
* Les téléchargements échoués reprennent désormais là où il s'étaient arrêtés
* Intégration de Podlove Alternate Feeds
-* Intégration de "pcast"-protocol
-* Intégration de la fonctionnalité de sauvegarde et restauration. Cette fonctionnalité doit être activés dans les réglages de Android pour fonctionner
+* Intégration du protocole "pcast"
+* Intégration d'une fonction de sauvegarde et restauration. Cette fonctionnalité doit être activés dans les réglages d'Android pour fonctionner
* Correction de bogues et améliorations
Version 0.9.8.3
---------------
* Intégration d'une fonctionnalité de protection par mot de passe pour les flux et les épisodes
-* Intégration de plus de types d'images d'épisodes
+* Support de plus de types d'images pour les épisodes
* Ajout de l'Hébreu
* Correction de bogues et améliorations
@@ -127,7 +143,7 @@ Version 0.9.8.1
Version 0.9.8.0
---------------
-* Accès ajouté à la bibliothèque de gpodder.net
+* Intégration de la bibliothèque gpodder.net
* Ajout de la synchronisation des podcasts via le service gpodder.net
* Le téléchargement automatique peut-être maintenant activé ou désactivé pour chaque podcast
* Ajout d'une option pour mettre en pause la lecture quand une autre application joue un son
diff --git a/changelog/he_IL.md b/changelog/he_IL.md
index 06111059e..6b161ebf8 100644
--- a/changelog/he_IL.md
+++ b/changelog/he_IL.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/hi_IN.md b/changelog/hi_IN.md
index 47e7d4cf6..8331dc78e 100644
--- a/changelog/hi_IN.md
+++ b/changelog/hi_IN.md
@@ -1,5 +1,21 @@
प्रवेश बदलें
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/hu.md b/changelog/hu.md
index 06111059e..6b161ebf8 100644
--- a/changelog/hu.md
+++ b/changelog/hu.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/id.md b/changelog/id.md
index 06111059e..6b161ebf8 100644
--- a/changelog/id.md
+++ b/changelog/id.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/it.md b/changelog/it.md
index f40778afd..4fb7bc348 100644
--- a/changelog/it.md
+++ b/changelog/it.md
@@ -1,11 +1,27 @@
Registro dei cambiamenti
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Correzioni di bug
+
+Versione 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
* Fix for crash on Huawei devices (media buttons may not work)
-Version 1.4
+Versione 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
* VIBRATE PERMISSION: Used optionally with the sleep timer
@@ -18,7 +34,7 @@ Version 1.4
* Flexible episode cleanup
* Rewind after pause
* Miglioramenti dell'usabilità
-* Bug fixes
+* Correzioni di bug
Versione 1.3
-----------
@@ -49,7 +65,7 @@ Versione 1.1
* Fixed date problems for some feeds
* Display improvements
* Miglioramenti dell'usabilità
-* Several other bugfixes
+* Diverse altre correzioni di bug
Version 1.0
-----------
diff --git a/changelog/it_IT.md b/changelog/it_IT.md
index 7fcf20302..c85c8791d 100644
--- a/changelog/it_IT.md
+++ b/changelog/it_IT.md
@@ -1,7 +1,23 @@
Registro dei cambiamenti
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Risoluzione bug
-Version 1.4.0.12
+Versione 1.4.1
+-------------
+* Miglioramento delle prestazioni
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
+
+Versione 1.4.0.12
----------------
* Fix for crash on Huawei devices (media buttons may not work)
diff --git a/changelog/ja.md b/changelog/ja.md
index 64fb28c66..147451829 100644
--- a/changelog/ja.md
+++ b/changelog/ja.md
@@ -1,9 +1,25 @@
変更ログ
==========
+バージョン 1.5.0
+-------------
+* キーワードで自動ダウンロードからエピソードを除外
+* フィードが自動的に更新されることを防止する設定
+* オーディオプレイヤーを改善しました
+* UI を改善しました
+* バグ修正
-Version 1.4.0.12
+バージョン 1.4.1
+-------------
+* パフォーマンスの改善
+* ハードウェアボタンでスキップの代わりに早送りと巻き戻しできます
+* 早送りボタンでスキップするオプション
+* 開発者に直接クラッシュレポートを送信するオプション
+* 現在再生しているエピソードをハイライト表示
+* ウィジェットの改善
+
+バージョン 1.4.0.12
----------------
-* Fix for crash on Huawei devices (media buttons may not work)
+* Huawei デバイスでのクラッシュを修正 (メディアボタンが動作しないことがあります)
バージョン 1.4
-----------
diff --git a/changelog/kn_IN.md b/changelog/kn_IN.md
index 06111059e..6b161ebf8 100644
--- a/changelog/kn_IN.md
+++ b/changelog/kn_IN.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/ko.md b/changelog/ko.md
index fea036846..06ea43201 100644
--- a/changelog/ko.md
+++ b/changelog/ko.md
@@ -1,5 +1,21 @@
변경 로그
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/ko_KR.md b/changelog/ko_KR.md
index 06111059e..6b161ebf8 100644
--- a/changelog/ko_KR.md
+++ b/changelog/ko_KR.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/nb.md b/changelog/nb.md
new file mode 100644
index 000000000..6b161ebf8
--- /dev/null
+++ b/changelog/nb.md
@@ -0,0 +1,347 @@
+Change Log
+==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
+
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
+Version 1.4
+-----------
+* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
+* VIBRATE PERMISSION: Used optionally with the sleep timer
+* Native variable speed playback (experimental via options)
+* Improved sleep timer
+* Mark episodes as 'favorite'
+* Notification can skip episodes
+* Keep episodes when skipping them
+* Episode art on lock screen
+* Flexible episode cleanup
+* Rewind after pause
+* Usability improvements
+* Bug fixes
+
+Version 1.3
+-----------
+* Bulk actions on feed episodes (download, queue, delete)
+* Reduced space used by images
+* Automatic refresh at a certain time of day
+* Customizable indicators and sorting for feeds
+* Ability to share feeds
+* Improved auto download
+* Many fixes and usability improvements
+
+Version 1.2
+-----------
+* Optionally disable swiping and dragging in the queue
+* Resume playback after phone call
+* Filter episodes in the Podcast feed
+* Hide items in the Nav drawer
+* Customize times for fast forward and rewind
+* Resolved issues with opening some OPML files
+* Various bug fixes and usability improvements
+
+Version 1.1
+-----------
+* iTunes podcast integration
+* Swipe to remove items from the queue
+* Set the number of parallel downloads
+* Fix for gpodder.net on old devices
+* Fixed date problems for some feeds
+* Display improvements
+* Usability improvements
+* Several other bugfixes
+
+Version 1.0
+-----------
+* The queue can now be sorted
+* Added option to delete episode after playback
+* Fixed a bug that caused chapters to be displayed multiple times
+* Several other improvements and bugfixes
+
+
+Version 0.9.9.6
+---------------
+* Fixed problems related to variable playback speed plugins
+* Fixed automatic feed update problems
+* Several other bugfixes and improvements
+
+Version 0.9.9.5
+---------------
+* Added support for paged feeds
+* Improved user interface
+* Added Japanese and Turkish translations
+* Fixed more image loading problems
+* Other bugfixes and improvements
+
+Version 0.9.9.4
+---------------
+* Added option to keep notification and lockscreen controls when playback is paused
+* Fixed a bug where episode images were not loaded correctly
+* Fixed battery usage problems
+
+Version 0.9.9.3
+---------------
+* Fixed video playback problems
+* Improved image loading
+* Other bugfixes and improvements
+
+Version 0.9.9.2
+---------------
+* Added support for feed discovery if a website URL is entered
+* Added support for 'next'/'previous' media keys
+* Improved sleep timer
+* Timestamps in shownotes can now be used to jump to a specific position
+* Automatic Flattring is now configurable
+* Several bugfixes and improvements
+
+Version 0.9.9.1
+---------------
+* Several bugfixes and improvements
+
+Version 0.9.9.0
+---------------
+* New user interface
+* Failed downloads are now resumed when restarted
+* Added support for Podlove Alternate Feeds
+* Added support for "pcast"-protocol
+* Added backup & restore functionality. This feature has to be enabled in the Android settings in order to work
+* Several bugfixes and improvements
+
+Version 0.9.8.3
+---------------
+* Added support for password-protected feeds and episodes
+* Added support for more types of episode images
+* Added Hebrew translation
+* Several bugfixes and improvements
+
+Version 0.9.8.2
+---------------
+* Several bugfixes and improvements
+* Added Korean translation
+
+Version 0.9.8.1
+---------------
+* Added option to flattr an episode automatically after 80 percent of the episode have been played
+* Added Polish translation
+* Several bugfixes and improvements
+
+Version 0.9.8.0
+---------------
+* Added access to the gpodder.net directory
+* Added ability to sync podcast subscriptions with the gpodder.net service
+* Automatic download can now be turned on or off for specific podcasts
+* Added option to pause playback when another app is playing sounds
+* Added Dutch and Hindi translation
+* Resolved a problem with automatic podcast updates
+* Resolved a problem with the buttons' visibility in the episode screen
+* Resolved a problem where episodes would be re-downloaded unnecessarily
+* Several other bugfixes and usability improvements
+
+Version 0.9.7.5
+---------------
+* Reduced application startup time
+* Reduced memory usage
+* Added option to change the playback speed
+* Added Swedish translation
+* Several bugfixes and improvements
+
+Version 0.9.7.4
+---------------
+* Episode cache size can now be set to unlimited
+* Removing an episode in the queue via sliding can now be undone
+* Added support for Links in MP3 chapters
+* Added Czech(Czech Republic), Azerbaijani and Portuguese translations
+* Several bugfixes and improvements
+
+Version 0.9.7.3
+---------------
+* Bluetooth devices now display metadata during playback (requires AVRCP 1.3 or higher)
+* User interface improvements
+* Several bugfixes
+
+Version 0.9.7.2
+---------------
+* Automatic download can now be disabled
+* Added Italian (Italy) translation
+* Several bugfixes
+
+Version 0.9.7.1
+---------------
+* Added automatic download of new episodes
+* Added option to specify the number of downloaded episodes to keep on the device
+* Added support for playback of external media files
+* Several improvements and bugfixes
+* Added Catalan translation
+
+Version 0.9.7
+-------------
+* Improved user interface
+* OPML files can now be imported by selecting them in a file browser
+* The queue can now be organized via drag & drop
+* Added expandable notifications (only supported on Android 4.1 and above)
+* Added Danish, French, Romanian (Romania) and Ukrainian (Ukraine) translation (thanks to all translators!)
+* Several bugfixes and minor improvements
+
+Version 0.9.6.4
+---------------
+* Added Chinese translation (Thanks tupunco!)
+* Added Portuguese (Brazil) translation (Thanks mbaltar!)
+* Several bugfixes
+
+Version 0.9.6.3
+---------------
+* Added the ability change the location of AntennaPod's data folder
+* Added Spanish translation (Thanks frandavid100!)
+* Solved problems with several feeds
+
+Version 0.9.6.2
+---------------
+* Fixed import problems with some OPML files
+* Fixed download problems
+* AntennaPod now recognizes changes of episode information
+* Other improvements and bugfixes
+
+Version 0.9.6.1
+---------------
+* Added dark theme
+* Several bugfixes and improvements
+
+Version 0.9.6
+-------------
+* Added support for VorbisComment chapters
+* AntennaPod now shows items as 'in progress' when playback has started
+* Reduced memory usage
+* Added support for more feed types
+* Several bugfixes
+
+
+Version 0.9.5.3
+---------------
+* Fixed crash when trying to start playback on some devices
+* Fixed problems with some feeds
+* Other bugfixes and improvements
+
+Version 0.9.5.2
+---------------
+* Media player now doesn't use network bandwidth anymore if not in use
+* Other improvements and bugfixes
+
+Version 0.9.5.1
+---------------
+* Added playback history
+* Improved behavior of download report notifications
+* Improved support for headset controls
+* Bugfixes in the feed parser
+* Moved 'OPML import' button into the 'add feed' screen and the 'OPML export' button into the settings screen
+
+Version 0.9.5
+-------------
+* Experimental support for MP3 chapters
+* New menu options for the 'new' list and the queue
+* Auto-delete feature
+* Better Download error reports
+* Several Bugfixes
+
+Version 0.9.4.6
+---------------
+* Enabled support for small-screen devices
+* Disabling the sleep timer should now work again
+
+Version 0.9.4.5
+---------------
+* Added Russian translation (Thanks older!)
+* Added German translation
+* Several bugfixes
+
+Version 0.9.4.4
+---------------
+* Added player controls at the bottom of the main screen and the feedlist screens
+* Improved media playback
+
+Version 0.9.4.3
+---------------
+* Fixed several bugs in the feed parser
+* Improved behavior of download reports
+
+Version 0.9.4.2
+---------------
+* Fixed bug in the OPML importer
+* Reduced memory usage of images
+* Fixed download problems on some devices
+
+Version 0.9.4.1
+---------------
+* Changed behavior of download notifications
+
+Version 0.9.4
+-------------
+* Faster and more reliable downloads
+* Added lockscreen player controls for Android 4.x devices
+* Several bugfixes
+
+Version 0.9.3.1
+---------------
+* Added preference to hide feed items which don't have an episode
+* Improved image size for some some screen sizes
+* Added grid view for large screens
+* Several bugfixes
+
+Version 0.9.3
+-------------
+* MiroGuide integration
+* Bugfixes in the audio- and videoplayer
+* Automatically add feeds to the queue when they have been downloaded
+
+Version 0.9.2
+-------------
+* Bugfixes in the user interface
+* GUID and ID attributes are now recognized by the Feedparser
+* Stability improvements when adding several feeds at the same time
+* Fixed bugs that occured when adding certain feeds
+
+Version 0.9.1.1
+--------------------
+* Changed Flattr credentials
+* Improved layout of Feed information screen
+* AntennaPod is now open source! The source code is available at https://github.com/danieloeh/AntennaPod
+
+Version 0.9.1
+-----------------
+* Added support for links in SimpleChapters
+* Bugfix: Current Chapter wasn't always displayed correctly
+
+Version 0.9
+--------------
+
+* OPML export
+* Flattr integration
+* Sleep timer
+
+Version 0.8.2
+-------------
+
+* Added search
+* Improved OPML import experience
+* More bugfixes
+
+Version 0.8.1
+------------
+
+* Added support for SimpleChapters
+* OPML import \ No newline at end of file
diff --git a/changelog/nb_NO.md b/changelog/nb_NO.md
index 1c8007023..d2630db92 100644
--- a/changelog/nb_NO.md
+++ b/changelog/nb_NO.md
@@ -1,9 +1,25 @@
Endringslogg
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Feilrettinger
-Version 1.4.0.12
+Versjon 1.4.1
+-------------
+Ytelsesforbedringer
+* Hardware-knapper bukes nå til hurtigfrem- og tilbakespoling istedenfor hopping
+* Valg for å la fremspolingsknappen hoppe
+* Valg for å sende kræsjrapporter direkte til utviklere
+* Markering av avspillende episode
+* Widget-forbedringer
+
+Versjon 1.4.0.12
----------------
-* Fix for crash on Huawei devices (media buttons may not work)
+* Fiks for feil med Huawei-enheter (medieknappene kan hende ikke fungerer)
Versjon 1.4
-----------
@@ -127,7 +143,7 @@ Versjon 0.9.8.1
Versjon 0.9.8.0
---------------
-* Added access to the gpodder.net directory
+* La til tilgang til gpodder.net-katalogen
* Added ability to sync podcast subscriptions with the gpodder.net service
* Automatic download can now be turned on or off for specific podcasts
* Added option to pause playback when another app is playing sounds
@@ -137,7 +153,7 @@ Versjon 0.9.8.0
* Resolved a problem where episodes would be re-downloaded unnecessarily
* Several other bugfixes and usability improvements
-Version 0.9.7.5
+Versjon 0.9.7.5
---------------
* Reduced application startup time
* Reduced memory usage
@@ -145,7 +161,7 @@ Version 0.9.7.5
* Added Swedish translation
* Flere feilrettinger og forbedringer
-Version 0.9.7.4
+Versjon 0.9.7.4
---------------
* Episode cache size can now be set to unlimited
* Removing an episode in the queue via sliding can now be undone
@@ -153,13 +169,13 @@ Version 0.9.7.4
* Added Czech(Czech Republic), Azerbaijani and Portuguese translations
* Flere feilrettinger og forbedringer
-Version 0.9.7.3
+Versjon 0.9.7.3
---------------
* Bluetooth devices now display metadata during playback (requires AVRCP 1.3 or higher)
* User interface improvements
* Several bugfixes
-Version 0.9.7.2
+Versjon 0.9.7.2
---------------
* Automatic download can now be disabled
* Added Italian (Italy) translation
@@ -173,7 +189,7 @@ Versjon 0.9.7.1
* Mange forbedringer og fiksing av feil
* Added Catalan translation
-Version 0.9.7
+Versjon 0.9.7
-------------
* Forbedret brukergrensesnitt
* OPML files can now be imported by selecting them in a file browser
@@ -182,31 +198,31 @@ Version 0.9.7
* La til dansk, fransk, romansk (Romania) og ukrainsk (Ukraina) oversettelse (tusen takk til alle oversettere!)
* Several bugfixes and minor improvements
-Version 0.9.6.4
+Versjon 0.9.6.4
---------------
* Added Chinese translation (Thanks tupunco!)
* Added Portuguese (Brazil) translation (Thanks mbaltar!)
* Several bugfixes
-Version 0.9.6.3
+Versjon 0.9.6.3
---------------
* Added the ability change the location of AntennaPod's data folder
* Added Spanish translation (Thanks frandavid100!)
* Solved problems with several feeds
-Version 0.9.6.2
+Versjon 0.9.6.2
---------------
* Fixed import problems with some OPML files
* Fixed download problems
* AntennaPod now recognizes changes of episode information
* Other improvements and bugfixes
-Version 0.9.6.1
+Versjon 0.9.6.1
---------------
* Added dark theme
* Flere feilrettinger og forbedringer
-Version 0.9.6
+Versjon 0.9.6
-------------
* Added support for VorbisComment chapters
* AntennaPod now shows items as 'in progress' when playback has started
@@ -215,18 +231,18 @@ Version 0.9.6
* Several bugfixes
-Version 0.9.5.3
+Versjon 0.9.5.3
---------------
* Fixed crash when trying to start playback on some devices
* Fixed problems with some feeds
* Andre feilrettinger og forbedringer
-Version 0.9.5.2
+Versjon 0.9.5.2
---------------
* Media player now doesn't use network bandwidth anymore if not in use
* Other improvements and bugfixes
-Version 0.9.5.1
+Versjon 0.9.5.1
---------------
* Added playback history
* Improved behavior of download report notifications
@@ -234,7 +250,7 @@ Version 0.9.5.1
* Bugfixes in the feed parser
* Moved 'OPML import' button into the 'add feed' screen and the 'OPML export' button into the settings screen
-Version 0.9.5
+Versjon 0.9.5
-------------
* Experimental support for MP3 chapters
* New menu options for the 'new' list and the queue
@@ -242,90 +258,90 @@ Version 0.9.5
* Better Download error reports
* Several Bugfixes
-Version 0.9.4.6
+Versjon 0.9.4.6
---------------
* Enabled support for small-screen devices
* Disabling the sleep timer should now work again
-Version 0.9.4.5
+Versjon 0.9.4.5
---------------
* Added Russian translation (Thanks older!)
* Added German translation
* Several bugfixes
-Version 0.9.4.4
+Versjon 0.9.4.4
---------------
* Added player controls at the bottom of the main screen and the feedlist screens
* Improved media playback
-Version 0.9.4.3
+Versjon 0.9.4.3
---------------
* Fixed several bugs in the feed parser
* Improved behavior of download reports
-Version 0.9.4.2
+Versjon 0.9.4.2
---------------
* Fixed bug in the OPML importer
* Reduced memory usage of images
* Fixed download problems on some devices
-Version 0.9.4.1
+Versjon 0.9.4.1
---------------
* Changed behavior of download notifications
-Version 0.9.4
+Versjon 0.9.4
-------------
* Faster and more reliable downloads
* Added lockscreen player controls for Android 4.x devices
* Several bugfixes
-Version 0.9.3.1
+Versjon 0.9.3.1
---------------
* Added preference to hide feed items which don't have an episode
* Improved image size for some some screen sizes
* Added grid view for large screens
* Several bugfixes
-Version 0.9.3
+Versjon 0.9.3
-------------
* MiroGuide integration
* Bugfixes in the audio- and videoplayer
* Automatically add feeds to the queue when they have been downloaded
-Version 0.9.2
+Versjon 0.9.2
-------------
* Bugfixes in the user interface
* GUID and ID attributes are now recognized by the Feedparser
* Stability improvements when adding several feeds at the same time
* Fixed bugs that occured when adding certain feeds
-Version 0.9.1.1
+Versjon 0.9.1.1
--------------------
* Changed Flattr credentials
* Improved layout of Feed information screen
* AntennaPod is now open source! The source code is available at https://github.com/danieloeh/AntennaPod
-Version 0.9.1
+Versjon 0.9.1
-----------------
* Added support for links in SimpleChapters
* Bugfix: Current Chapter wasn't always displayed correctly
-Version 0.9
+Versjon 0.9
--------------
* OPML export
* Flattr integration
* Sleep timer
-Version 0.8.2
+Versjon 0.8.2
-------------
* Added search
* Improved OPML import experience
* More bugfixes
-Version 0.8.1
+Versjon 0.8.1
------------
* Added support for SimpleChapters
-* OPML import \ No newline at end of file
+* OPML-import \ No newline at end of file
diff --git a/changelog/nl.md b/changelog/nl.md
index ba26825d6..cc634329c 100644
--- a/changelog/nl.md
+++ b/changelog/nl.md
@@ -1,16 +1,25 @@
Changelog
==========
-Version 1.4.1
+Versie 1.5.0
-------------
-* Performance improvements
-* Hardware buttons now ff and rewind instead of skipping
-* Option to have forward button skip
-* Option to send crash reports directly to developers
-* Highlight currently playing episode
+* Afleveringen uitsluiten bij automatisch downloaden op basis van zoekwoorden
+* Sluit specifieke feeds uit van automatische updates
+* Verbeterde mediaspeler
+* Verbeterde interface
+* Bugfixes
-Version 1.4.0.12
+Versie 1.4.1
+-------------
+* Verbeterde prestaties
+* Fysieke knoppen voor vooruit- en terugspeoelen ipv de aflevering overslaan
+* Optie 'Volgende' knop voor overslaan
+* Optie om crashrapport direct naar de ontwikkelaars te sturen
+* Duidelijke markering van huidige aflevering
+* Verbeterde widget
+
+Versie 1.4.0.12
----------------
-* Fix for crash on Huawei devices (media buttons may not work)
+* Oplossing voor crashes op Huawei toestellen (afspeelbediening werkt mogelijk niet)
Versie 1.4
-----------
diff --git a/changelog/no.md b/changelog/no.md
index 06111059e..6b161ebf8 100644
--- a/changelog/no.md
+++ b/changelog/no.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/pl.md b/changelog/pl.md
index 06111059e..6b161ebf8 100644
--- a/changelog/pl.md
+++ b/changelog/pl.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/pl_PL.md b/changelog/pl_PL.md
index 0d06d21b6..a34632883 100644
--- a/changelog/pl_PL.md
+++ b/changelog/pl_PL.md
@@ -1,5 +1,21 @@
Dziennik zmian
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/pt.md b/changelog/pt.md
index 6c1071d85..78d773aaf 100644
--- a/changelog/pt.md
+++ b/changelog/pt.md
@@ -1,5 +1,21 @@
Registo de alterações
==========
+Versão 1.5.0
+-------------
+* Exclusão de episódios da descarga automática usando palavras-chave
+* Configurar fontes para que não se atualizem atomaticamente
+* Melhorias no reprodutor áudio
+* Melhorias à interface
+* Diversas correções
+
+Versão 1.4.1
+-------------
+* Melhorias de desempenho
+* Os botões do dispositivo avançam/recuam no episódio em vez de avançar para o episódio seguinte
+* Opção para utilizar o botão do dispositivo para avançar de episódio
+* Opção para enviar os relatórios de erro para os programadores
+* Destaque automático do episódio em reprodução
+* Melhorias ao widget
Versão 1.4.0.12
----------------
@@ -22,12 +38,12 @@ Versão 1.4
Versão 1.3
-----------
-* Ações em lote nos episódios (transferir, colocar na fila, apagar)
+* Ações em lote nos episódios (descarga, colocar na fila, apagar)
* Redução do tamanho utilizado pelas imagens
* Atualização automática de fontes num dado período
* Indicadores e ordenação personalizada de fontes
* Possibilidade de partilhar fontes
-* Melhorias na transferência automática
+* Melhorias na descarga automática
* Diversas melhorias de usabilidade e correções
Versão 1.2
@@ -44,7 +60,7 @@ Versão 1.1
-----------
* Adicionada integração com o iTunes
* Deslize para remover os episódios da fila de reprodução
-* Possibilidade de definir o número de transferências simultâneas
+* Possibilidade de definir o número de descargas simultâneas
* Correções para gpodder.net em alguns dispositivos
* Corrigidos problemas de datas em algumas fontes
* Melhorias de exibição
@@ -101,7 +117,7 @@ Versão 0.9.9.1
Versão 0.9.9.0
---------------
* Nova interface
-* As transferências falhadas são retomadas ao reiniciar
+* As descargas falhadas são retomadas ao reiniciar
* Adicionado o suporte às fontes alternativas Podlove
* Adicionado o suporte ao protocolo pcast
* Adicionadas funcionalidades de backup e restauro. Esta opção tem que ser ativada nas definições do Android para funcionar
@@ -129,12 +145,12 @@ Versão 0.9.8.0
---------------
* Adição do acesso ao diretório gpodder.net
* Adicionada a possibilidade de sincronizar as subscrições com o gpodder.net
-* Adicionada a possibilidade de ativar ou desativar a transferência automática de podcasts específicos
+* Adicionada a possibilidade de ativar ou desativar a descarga automática para podcasts específicos
* Adicionada a possibilidade de colocar em pausa a reprodução se outra aplicação quiser reproduzir sons
* Adição da tradução em holandês e hindi
* Correção de erros com a transferência automática de podcasts
* Corrigido um erro com a visualização de botões no ecrã dos episódios
-* Corrigido um erro em que os episódios eram novamente transferidos sem haver essa necessidade
+* Corrigido um erro em que os episódios eram novamente descarregados sem haver essa necessidade
* Diversas correções e melhorias
Versão 0.9.7.5
@@ -161,14 +177,14 @@ Versão 0.9.7.3
Versão 0.9.7.2
---------------
-* Possibilidade de desativar as transferências automáticas
+* Possibilidade de desativar as descargas automáticas
* Adição da tradução em italiano (Itália)
* Diversas correções
Versão 0.9.7.1
---------------
-* Adicionada a possibilidade de transferência automática de episódios
-* Adicionada uma opção para especificar o número de episódios transferidos a manter no dispositivo
+* Adicionada a possibilidade de descarregar automaticamente os episódios
+* Adicionada uma opção para especificar o número de episódios descarregados a manter no dispositivo
* Adicionado o suporte à reprodução de ficheiros externos
* Diversas correções e melhorias
* Adição da tradução em catalão
@@ -197,7 +213,7 @@ Versão 0.9.6.3
Versão 0.9.6.2
---------------
* Corrigidos alguns erros de importação de ficheiros OPML
-* Corrigidos erros relacionados com transferências
+* Corrigidos erros nas descargas
* O AntennaPod já reconhece as alterações às informações dos episódios
* Diversas correções e melhorias
@@ -229,7 +245,7 @@ Versão 0.9.5.2
Versão 0.9.5.1
---------------
* Adicionado o histórico de reprodução
-* Melhorias nas notificações de transferências
+* Melhorias nas notificações de descargas
* Melhorias nos controlo dos auriculares
* Correção no processador de fontes
* Botão "Importação OPML" movido para o ecrã "Adicionar fonte e botão "Exportação OPML" para o ecrã de definições
@@ -239,7 +255,7 @@ Versão 0.9.5
*Adicionado suporte experimental a capítulos MP3
* Novo menu de opções para a lista de novos ficheiros e para a fila
* Adicionado a opção de eliminação automática
-* Melhoria nos relatórios de transferências
+* Melhoria nos relatórios de descargas
* Diversas correções
Versão 0.9.4.6
@@ -261,21 +277,21 @@ Versão 0.9.4.4
Versão 0.9.4.3
---------------
* Melhorias no processador de fontes
-* Melhorias nos relatórios de transferências
+* Melhorias nos relatórios de descargas
Versão 0.9.4.2
---------------
* Correção de erros no importador OPML
* Melhoria na utilização de memória para imagens
-* Corrigidos erros de transferências em alguns dispositivos
+* Corrigidos erros de descargas em alguns dispositivos
Versão 0.9.4.1
---------------
-* Melhorias nos relatórios de transferências
+* Melhorias nas notificações das descargas
Versão 0.9.4
-------------
-* Transferências mais rápidas e fiáveis
+* Descargas mais rápidas e mais fiáveis
* Adição de controlos do reprodutor para dispositivos com o Android 4.x
* Diversas correções
@@ -290,7 +306,7 @@ Versão 0.9.3
-------------
* Integração com o guia Miro
* Correções no reprodutor multimédia
-* Os episódios são adicionados à fila assim que forem transferidos
+* Os episódios são adicionados à fila assim que forem descarregados
Versão 0.9.2
-------------
diff --git a/changelog/pt_BR.md b/changelog/pt_BR.md
index 4e68fe0e4..728a302ea 100644
--- a/changelog/pt_BR.md
+++ b/changelog/pt_BR.md
@@ -1,5 +1,21 @@
Últimas modificações
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/ro_RO.md b/changelog/ro_RO.md
index d88c6a736..776d6a7b8 100644
--- a/changelog/ro_RO.md
+++ b/changelog/ro_RO.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/ru_RU.md b/changelog/ru_RU.md
index 10f120e4e..ea2c806e1 100644
--- a/changelog/ru_RU.md
+++ b/changelog/ru_RU.md
@@ -1,7 +1,23 @@
Список изменений
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
-Version 1.4.0.12
+Версия 1.4.1
+-------------
+* Улучшение производительности
+* Физические кнопки теперь осуществляют перемотку вперед и назад вместо пропуска
+* Возможность настройки пропуска для кнопки перемотки вперед
+* Возможность отправки отчетов о сбоях напрямую разработчикам
+* Выделение проигрываемого выпуска
+* Улучшения виджета
+
+Версия 1.4.0.12
----------------
* Fix for crash on Huawei devices (media buttons may not work)
diff --git a/changelog/sv_SE.md b/changelog/sv_SE.md
index 75a35c36f..9bffd2088 100644
--- a/changelog/sv_SE.md
+++ b/changelog/sv_SE.md
@@ -1,5 +1,21 @@
Ändringslogg
==========
+Version 1.5.0
+-------------
+* Exkludera episoder från automatisk nedladdning baserat på nyckelord
+* Flöden kan ställas in att inte uppdateras automatiskt
+* Förbättrad ljudspelare
+* Förbättrat gränssnitt
+* Buggfixar
+
+Version 1.4.1
+-------------
+Prestandaförbättringar
+* Hårdvaruknappar spolar nu fram och tillbaka istället för hoppar mellan episoder
+* Möjlighet att låta hårdvaruknapp hoppa till nästa episod
+* Möjlighet att sända krashrapporter direkt till utvecklarna
+* Den episod som spelas framhävs bättre
+* Widgetförbättringar
Version 1.4.0.12
----------------
diff --git a/changelog/tr.md b/changelog/tr.md
index f05d8b80e..af763c440 100644
--- a/changelog/tr.md
+++ b/changelog/tr.md
@@ -1,5 +1,21 @@
Yenilikler
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Hatalar düzeltildi
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
@@ -9,16 +25,16 @@ Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
* VIBRATE PERMISSION: Used optionally with the sleep timer
-* Native variable speed playback (experimental via options)
+* Doğal değişken çalma hızı (deneysel seçeneklerde)
* Zamanlayıcı geliştirildi
-* Mark episodes as 'favorite'
+* Bölümleri 'favori' olarak işaretleme
* Notification can skip episodes
* Keep episodes when skipping them
-* Episode art on lock screen
-* Flexible episode cleanup
+* Kilitli ekranda bölüm resmi
+* Esnek bölüm temizliği
* Rewind after pause
* Kullanılabilirlik geliştirmeleri
-* Bug fixes
+* Hatalar düzeltildi
Sürüm 1.3
-----------
diff --git a/changelog/uk_UA.md b/changelog/uk_UA.md
index 6d8cc7871..296ce10d6 100644
--- a/changelog/uk_UA.md
+++ b/changelog/uk_UA.md
@@ -1,9 +1,25 @@
Зміни
==========
+Версія 1.5.0
+-------------
+* Вилучення епізодів з автоматичного завантаження за ключовими словами
+* Налагодження каналів що дозволяє запобігти автоматичному поновленню
+* Покращення в аудіоплейері
+* Покращення інтерфейса користувача
+* Виправлення помилок
-Version 1.4.0.12
+Версія 1.4.1
+-------------
+* Поліпшення продуктивності
+* Апаратні кнопки для прямої та зворотньої перемотки тепер працюють замість перехода до наступного епізода
+* Можливість перехода до наступного епізода за натисканням кнопки перемотки
+* Можливість надсилати звіти про помилки розробникам
+* Підсвітлення епізода що зараз програється
+* Поліпшення віджета
+
+Версія 1.4.0.12
----------------
-* Fix for crash on Huawei devices (media buttons may not work)
+* Виправлення збоїв на пристроях Huawei (медіа кнопки можуть не робити)
Версія 1.4
-----------
diff --git a/changelog/vi.md b/changelog/vi.md
index 06111059e..6b161ebf8 100644
--- a/changelog/vi.md
+++ b/changelog/vi.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/vi_VN.md b/changelog/vi_VN.md
index 06111059e..6b161ebf8 100644
--- a/changelog/vi_VN.md
+++ b/changelog/vi_VN.md
@@ -1,5 +1,21 @@
Change Log
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/changelog/zh_CN.md b/changelog/zh_CN.md
index 7c0f7228b..2d62afad4 100644
--- a/changelog/zh_CN.md
+++ b/changelog/zh_CN.md
@@ -1,5 +1,21 @@
更新日志
==========
+Version 1.5.0
+-------------
+* Exclude episodes from auto download by keyword
+* Configure feeds to prevent them from refreshing automatically
+* Improved audio player
+* Improved UI
+* Bug fixes
+
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/circle.yml b/circle.yml
index abea320a5..e9fc82e7b 100644
--- a/circle.yml
+++ b/circle.yml
@@ -4,6 +4,16 @@ general:
machine:
java:
version: oraclejdk8
+dependencies:
+ cache_directories:
+ - ~/.android
+ - ~/android
+ pre:
+ - echo y | android update sdk --no-ui --all --filter "tools,platform-tools,android-23"
+ - echo y | android update sdk --no-ui --all --filter "build-tools-23.0.2"
+ override:
+ - echo override dependencies
+
test:
override:
- ./gradlew assembleDebug -PdisablePreDex \ No newline at end of file
diff --git a/core/build.gradle b/core/build.gradle
index 4ad4aa0ba..09d13a476 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -40,13 +40,12 @@ repositories {
dependencies {
compile "com.android.support:support-v4:$supportVersion"
compile "com.android.support:appcompat-v7:$supportVersion"
- compile "com.android.support:design:$supportVersion"
compile "org.apache.commons:commons-lang3:$commonslangVersion"
compile ("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
exclude group: "org.json", module: "json"
}
compile "commons-io:commons-io:$commonsioVersion"
- compile "com.jayway.android.robotium:robotium-solo:5.5.2"
+ compile "com.jayway.android.robotium:robotium-solo:5.5.3"
compile "org.jsoup:jsoup:$jsoupVersion"
compile "com.github.bumptech.glide:glide:$glideVersion"
compile "com.github.bumptech.glide:okhttp-integration:1.3.1"
@@ -57,5 +56,5 @@ dependencies {
compile "de.greenrobot:eventbus:$eventbusVersion"
compile "io.reactivex:rxandroid:$rxAndroidVersion"
- compile "com.github.AntennaPod:AntennaPod-AudioPlayer:v1.0.2"
+ compile "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java
index 5ea0ba904..690fbdfc6 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java
@@ -156,10 +156,9 @@ public class OpmlBackupAgent extends BackupAgentHelper {
ArrayList<OpmlElement> opmlElements = new OpmlReader().readDocument(reader);
mChecksum = digester == null ? null : digester.digest();
DownloadRequester downloader = DownloadRequester.getInstance();
- Date lastUpdated = new Date();
for (OpmlElement opmlElem : opmlElements) {
- Feed feed = new Feed(opmlElem.getXmlUrl(), lastUpdated, opmlElem.getText());
+ Feed feed = new Feed(opmlElem.getXmlUrl(), null, opmlElem.getText());
try {
downloader.downloadFeed(mContext, feed);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
index 0de046fe5..d2d7cbc73 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
@@ -44,10 +44,12 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
private String author;
private FeedImage image;
private List<FeedItem> items;
+
/**
- * Date of last refresh.
+ * String that identifies the last update (adopted from Last-Modified or ETag header)
*/
- private Date lastUpdate;
+ private String lastUpdate;
+
private FlattrStatus flattrStatus;
private String paymentLink;
/**
@@ -91,18 +93,14 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
/**
* This constructor is used for restoring a feed from the database.
*/
- public Feed(long id, Date lastUpdate, String title, String link, String description, String paymentLink,
+ public Feed(long id, String lastUpdate, String title, String link, String description, String paymentLink,
String author, String language, String type, String feedIdentifier, FeedImage image, String fileUrl,
String downloadUrl, boolean downloaded, FlattrStatus status, boolean paged, String nextPageLink,
String filter, boolean lastUpdateFailed) {
super(fileUrl, downloadUrl, downloaded);
this.id = id;
this.title = title;
- if (lastUpdate != null) {
- this.lastUpdate = (Date) lastUpdate.clone();
- } else {
- this.lastUpdate = null;
- }
+ this.lastUpdate = lastUpdate;
this.link = link;
this.description = description;
this.paymentLink = paymentLink;
@@ -126,7 +124,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
/**
* This constructor is used for test purposes and uses a default flattr status object.
*/
- public Feed(long id, Date lastUpdate, String title, String link, String description, String paymentLink,
+ public Feed(long id, String lastUpdate, String title, String link, String description, String paymentLink,
String author, String language, String type, String feedIdentifier, FeedImage image, String fileUrl,
String downloadUrl, boolean downloaded) {
this(id, lastUpdate, title, link, description, paymentLink, author, language, type, feedIdentifier, image,
@@ -138,7 +136,6 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
*/
public Feed() {
super();
- lastUpdate = new Date();
this.flattrStatus = new FlattrStatus();
}
@@ -146,9 +143,9 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
* This constructor is used for requesting a feed download (it must not be used for anything else!). It should NOT be
* used if the title of the feed is already known.
*/
- public Feed(String url, Date lastUpdate) {
+ public Feed(String url, String lastUpdate) {
super(null, url, false);
- this.lastUpdate = (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
+ this.lastUpdate = lastUpdate;
this.flattrStatus = new FlattrStatus();
}
@@ -156,7 +153,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
* This constructor is used for requesting a feed download (it must not be used for anything else!). It should be
* used if the title of the feed is already known.
*/
- public Feed(String url, Date lastUpdate, String title) {
+ public Feed(String url, String lastUpdate, String title) {
this(url, lastUpdate);
this.title = title;
this.flattrStatus = new FlattrStatus();
@@ -166,7 +163,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
* This constructor is used for requesting a feed download (it must not be used for anything else!). It should be
* used if the title of the feed is already known.
*/
- public Feed(String url, Date lastUpdate, String title, String username, String password) {
+ public Feed(String url, String lastUpdate, String title, String username, String password) {
this(url, lastUpdate, title);
preferences = new FeedPreferences(0, true, FeedPreferences.AutoDeleteAction.GLOBAL, username, password);
}
@@ -191,11 +188,9 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
int indexHide = cursor.getColumnIndex(PodDBAdapter.KEY_HIDE);
int indexLastUpdateFailed = cursor.getColumnIndex(PodDBAdapter.KEY_LAST_UPDATE_FAILED);
- Date lastUpdate = new Date(cursor.getLong(indexLastUpdate));
-
Feed feed = new Feed(
cursor.getLong(indexId),
- lastUpdate,
+ cursor.getString(indexLastUpdate),
cursor.getString(indexTitle),
cursor.getString(indexLink),
cursor.getString(indexDescription),
@@ -430,12 +425,12 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
this.items = list;
}
- public Date getLastUpdate() {
- return (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
+ public String getLastUpdate() {
+ return lastUpdate;
}
- public void setLastUpdate(Date lastUpdate) {
- this.lastUpdate = (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
+ public void setLastUpdate(String lastModified) {
+ this.lastUpdate = lastModified;
}
public String getFeedIdentifier() {
@@ -544,7 +539,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
return itemfilter;
}
- public void setHiddenItemProperties(String[] properties) {
+ public void setItemFilter(String[] properties) {
if (properties != null) {
this.itemfilter = new FeedItemFilter(properties);
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedFilter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedFilter.java
new file mode 100644
index 000000000..35abb8de6
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedFilter.java
@@ -0,0 +1,111 @@
+package de.danoeh.antennapod.core.feed;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class FeedFilter {
+
+ private static final String TAG = "FeedFilter";
+
+ private String includeFilter;
+ private String excludeFilter;
+
+ public FeedFilter() {
+ this("", "");
+ }
+
+ public FeedFilter(String includeFilter, String excludeFilter) {
+ // We're storing the strings and not the parsed terms because
+ // 1. It's easier to show the user exactly what they typed in this way
+ // (we don't have to recreate it)
+ // 2. We don't know if we'll actually be asked to parse anything anyways.
+ this.includeFilter = includeFilter;
+ this.excludeFilter = excludeFilter;
+ }
+
+ /**
+ * Parses the text in to a list of single words or quoted strings.
+ * Example: "One "Two Three"" returns ["One", "Two Three"]
+ * @param filter string to parse in to terms
+ * @return list of terms
+ */
+ private List<String> parseTerms(String filter) {
+ // from http://stackoverflow.com/questions/7804335/split-string-on-spaces-in-java-except-if-between-quotes-i-e-treat-hello-wor
+ List<String> list = new ArrayList<>();
+ Matcher m = Pattern.compile("([^\"]\\S*|\".+?\")\\s*").matcher(filter);
+ while (m.find())
+ list.add(m.group(1).replace("\"", ""));
+ return list;
+ }
+
+ /**
+ * @param item
+ * @return true if the item should be downloaded
+ */
+ public boolean shouldAutoDownload(FeedItem item) {
+
+ List<String> includeTerms = parseTerms(includeFilter);
+ List<String> excludeTerms = parseTerms(excludeFilter);
+
+ if (includeTerms.size() == 0 && excludeTerms.size() == 0) {
+ // nothing has been specified, so include everything
+ return true;
+ }
+
+ // check using lowercase so the users don't have to worry about case.
+ String title = item.getTitle().toLowerCase();
+
+ // if it's explicitly excluded, it shouldn't be autodownloaded
+ // even if it has include terms
+ for (String term : excludeTerms) {
+ if (title.contains(term.trim().toLowerCase())) {
+ return false;
+ }
+ }
+
+ for (String term : includeTerms) {
+ if (title.contains(term.trim().toLowerCase())) {
+ return true;
+ }
+ }
+
+ // now's the tricky bit
+ // if they haven't set an include filter, but they have set an exclude filter
+ // default to including, but if they've set both, then exclude
+ if (!hasIncludeFilter() && hasExcludeFilter()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public String getIncludeFilter() {
+ return includeFilter;
+ }
+
+ public String getExcludeFilter() { return excludeFilter; }
+
+ /**
+ * @return true if only include is set
+ */
+ public boolean includeOnly() {
+ return hasIncludeFilter() && !hasExcludeFilter();
+ }
+
+ /**
+ * @return true if only exclude is set
+ */
+ public boolean excludeOnly() {
+ return hasExcludeFilter() && !hasIncludeFilter();
+ }
+
+ public boolean hasIncludeFilter() {
+ return includeFilter.length() > 0;
+ }
+
+ public boolean hasExcludeFilter() {
+ return excludeFilter.length() > 0;
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
index c54cc1d5b..d8c32f55e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
@@ -11,6 +11,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.asynctask.ImageResource;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -75,7 +76,13 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
private List<Chapter> chapters;
private FeedImage image;
- private boolean autoDownload = true;
+ /*
+ * 0: auto download disabled
+ * 1: auto download enabled (default)
+ * > 1: auto download enabled, (approx.) timestamp of the last failed attempt
+ * where last digit denotes the number of failed attempts
+ */
+ private long autoDownload = 1;
/**
* Any tags assigned to this item
@@ -93,7 +100,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
* */
public FeedItem(long id, String title, String link, Date pubDate, String paymentLink, long feedId,
FlattrStatus flattrStatus, boolean hasChapters, FeedImage image, int state,
- String itemIdentifier, boolean autoDownload) {
+ String itemIdentifier, long autoDownload) {
this.id = id;
this.title = title;
this.link = link;
@@ -162,7 +169,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
FlattrStatus flattrStatus = new FlattrStatus(cursor.getLong(indexFlattrStatus));
int state = cursor.getInt(indexRead);
String itemIdentifier = cursor.getString(indexItemIdentifier);
- boolean autoDownload = cursor.getInt(indexAutoDownload) > 0;
+ long autoDownload = cursor.getLong(indexAutoDownload);
FeedItem item = new FeedItem(id, title, link, pubDate, paymentLink, feedId, flattrStatus,
hasChapters, null, state, itemIdentifier, autoDownload);
@@ -449,18 +456,37 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
}
public void setAutoDownload(boolean autoDownload) {
- this.autoDownload = autoDownload;
+ this.autoDownload = autoDownload ? 1 : 0;
}
public boolean getAutoDownload() {
- return this.autoDownload;
+ return this.autoDownload > 0;
+ }
+
+ public int getFailedAutoDownloadAttempts() {
+ if (autoDownload <= 1) {
+ return 0;
+ }
+ int failedAttempts = (int)(autoDownload % 10);
+ if (failedAttempts == 0) {
+ failedAttempts = 10;
+ }
+ return failedAttempts;
}
public boolean isAutoDownloadable() {
- return this.hasMedia() &&
- false == this.getMedia().isPlaying() &&
- false == this.getMedia().isDownloaded() &&
- this.getAutoDownload();
+ if (media == null || media.isPlaying() || media.isDownloaded() || autoDownload == 0) {
+ return false;
+ }
+ if (autoDownload == 1) {
+ return true;
+ }
+ int failedAttempts = getFailedAutoDownloadAttempts();
+ double magicValue = 1.767; // 1.767^(10[=#maxNumAttempts]-1) = 168 hours / 7 days
+ int millisecondsInHour = 3600000;
+ long waitingTime = (long) (Math.pow(magicValue, failedAttempts - 1) * millisecondsInHour);
+ long grace = TimeUnit.MINUTES.toMillis(5);
+ return System.currentTimeMillis() > (autoDownload + waitingTime - grace);
}
/**
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java
index d3d5dd0a1..fdde4b34c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java
@@ -8,73 +8,87 @@ import java.util.List;
import de.danoeh.antennapod.core.storage.DBReader;
public class FeedItemFilter {
+ private final String[] mProperties;
- private final String[] properties;
-
- private boolean hideUnplayed = false;
- private boolean hidePaused = false;
- private boolean hidePlayed = false;
- private boolean hideQueued = false;
- private boolean hideNotQueued = false;
- private boolean hideDownloaded = false;
- private boolean hideNotDownloaded = false;
+ private boolean showPlayed = false;
+ private boolean showUnplayed = false;
+ private boolean showPaused = false;
+ private boolean showQueued = false;
+ private boolean showNotQueued = false;
+ private boolean showDownloaded = false;
+ private boolean showNotDownloaded = false;
public FeedItemFilter(String properties) {
- this(TextUtils.split(",", properties));
+ this(TextUtils.split(properties, ","));
}
public FeedItemFilter(String[] properties) {
- this.properties = properties;
+ this.mProperties = properties;
for(String property : properties) {
// see R.arrays.feed_filter_values
switch(property) {
case "unplayed":
- hideUnplayed = true;
+ showUnplayed = true;
break;
case "paused":
- hidePaused = true;
+ showPaused = true;
break;
case "played":
- hidePlayed = true;
+ showPlayed = true;
break;
case "queued":
- hideQueued = true;
+ showQueued = true;
break;
case "not_queued":
- hideNotQueued = true;
+ showNotQueued = true;
break;
case "downloaded":
- hideDownloaded = true;
+ showDownloaded = true;
break;
case "not_downloaded":
- hideNotDownloaded = true;
+ showNotDownloaded = true;
break;
}
}
}
+ /**
+ * Run a list of feed items through the filter.
+ */
public List<FeedItem> filter(List<FeedItem> items) {
- if(properties.length == 0) {
- return items;
- }
- List<FeedItem> result = new ArrayList<FeedItem>();
+ if(mProperties.length == 0) return items;
+
+ List<FeedItem> result = new ArrayList<>();
+
+ // Check for filter combinations that will always return an empty list
+ // (e.g. requiring played and unplayed at the same time)
+ if (showPlayed && showUnplayed) return result;
+ if (showQueued && showNotQueued) return result;
+ if (showDownloaded && showNotDownloaded) return result;
+
for(FeedItem item : items) {
- if(hideUnplayed && false == item.isPlayed()) continue;
- if(hidePaused && item.getState() == FeedItem.State.IN_PROGRESS) continue;
- if(hidePlayed && item.isPlayed()) continue;
- boolean isQueued = DBReader.getQueueIDList().contains(item.getId());
- if(hideQueued && isQueued) continue;
- if(hideNotQueued && false == isQueued) continue;
- boolean isDownloaded = item.getMedia() != null && item.getMedia().isDownloaded();
- if(hideDownloaded && isDownloaded) continue;
- if(hideNotDownloaded && false == isDownloaded) continue;
+ // If the item does not meet a requirement, skip it.
+ if (showPlayed && !item.isPlayed()) continue;
+ if (showUnplayed && item.isPlayed()) continue;
+ if (showPaused && item.getState() != FeedItem.State.IN_PROGRESS) continue;
+
+ boolean queued = DBReader.getQueueIDList().contains(item.getId());
+ if (showQueued && !queued) continue;
+ if (showNotQueued && queued) continue;
+
+ boolean downloaded = item.getMedia() != null && item.getMedia().isDownloaded();
+ if (showDownloaded && !downloaded) continue;
+ if (showNotDownloaded && downloaded) continue;
+
+ // If the item reaches here, it meets all criteria
result.add(item);
}
+
return result;
}
public String[] getValues() {
- return properties.clone();
+ return mProperties.clone();
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
index 5a345b9d6..6b11e162e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
@@ -7,6 +7,8 @@ import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
import java.util.Date;
import java.util.List;
@@ -44,7 +46,7 @@ public class FeedMedia extends FeedFile implements Playable {
private int played_duration; // How many ms of this file have been played (for autoflattring)
private long size; // File size in Byte
private String mime_type;
- private volatile FeedItem item;
+ @Nullable private volatile FeedItem item;
private Date playbackCompletionDate;
// if null: unknown, will be checked
@@ -166,6 +168,10 @@ public class FeedMedia extends FeedFile implements Playable {
}
public void updateFromOther(FeedMedia other) {
+ // reset to new if feed item did link to a file before
+ if(TextUtils.isEmpty(download_url) && !TextUtils.isEmpty(other.download_url)) {
+ item.setNew();
+ }
super.updateFromOther(other);
if (other.size > 0) {
size = other.size;
@@ -260,7 +266,7 @@ public class FeedMedia extends FeedFile implements Playable {
public void setPosition(int position) {
this.position = position;
- if(position > 0 && item.isNew()) {
+ if(position > 0 && item != null && item.isNew()) {
this.item.setPlayed(false);
}
}
@@ -293,6 +299,7 @@ public class FeedMedia extends FeedFile implements Playable {
this.mime_type = mime_type;
}
+ @Nullable
public FeedItem getItem() {
return item;
}
@@ -340,7 +347,7 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(id);
- dest.writeLong(item.getId());
+ dest.writeLong(item != null ? item.getId() : 0L);
dest.writeInt(duration);
dest.writeInt(position);
@@ -356,7 +363,11 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public void writeToPreferences(Editor prefEditor) {
- prefEditor.putLong(PREF_FEED_ID, item.getFeed().getId());
+ if(item != null && item.getFeed() != null) {
+ prefEditor.putLong(PREF_FEED_ID, item.getFeed().getId());
+ } else {
+ prefEditor.putLong(PREF_FEED_ID, 0L);
+ }
prefEditor.putLong(PREF_MEDIA_ID, id);
}
@@ -375,11 +386,14 @@ public class FeedMedia extends FeedFile implements Playable {
// check if chapters are stored in db and not loaded yet.
if (item != null && item.hasChapters() && item.getChapters() == null) {
DBReader.loadChaptersOfFeedItem(item);
- } else if (item != null && item.getChapters() == null && !localFileAvailable()) {
- ChapterUtils.loadChaptersFromStreamUrl(this);
+ } else if (item != null && item.getChapters() == null) {
+ if(localFileAvailable()) {
+ ChapterUtils.loadChaptersFromFileUrl(this);
+ } else {
+ ChapterUtils.loadChaptersFromStreamUrl(this);
+ }
if (getChapters() != null && item != null) {
- DBWriter.setFeedItem(
- item);
+ DBWriter.setFeedItem(item);
}
}
}
@@ -389,10 +403,10 @@ public class FeedMedia extends FeedFile implements Playable {
if (item == null) {
return null;
}
- if (getItem().getTitle() != null) {
- return getItem().getTitle();
+ if (item.getTitle() != null) {
+ return item.getTitle();
} else {
- return getItem().getIdentifyingValue();
+ return item.getIdentifyingValue();
}
}
@@ -401,7 +415,7 @@ public class FeedMedia extends FeedFile implements Playable {
if (item == null) {
return null;
}
- return getItem().getChapters();
+ return item.getChapters();
}
@Override
@@ -409,15 +423,15 @@ public class FeedMedia extends FeedFile implements Playable {
if (item == null) {
return null;
}
- return getItem().getLink();
+ return item.getLink();
}
@Override
public String getFeedTitle() {
- if (item == null) {
+ if (item == null || item.getFeed() == null) {
return null;
}
- return getItem().getFeed().getTitle();
+ return item.getFeed().getTitle();
}
@Override
@@ -440,7 +454,7 @@ public class FeedMedia extends FeedFile implements Playable {
if (item == null) {
return null;
}
- return getItem().getPaymentLink();
+ return item.getPaymentLink();
}
@Override
@@ -455,7 +469,7 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public void saveCurrentPosition(SharedPreferences pref, int newPosition, long timeStamp) {
- if(item.isNew()) {
+ if(item != null && item.isNew()) {
DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId());
}
setPosition(newPosition);
@@ -478,7 +492,9 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public void setChapters(List<Chapter> chapters) {
- getItem().setChapters(chapters);
+ if(item != null) {
+ item.setChapters(chapters);
+ }
}
@Override
@@ -528,8 +544,10 @@ public class FeedMedia extends FeedFile implements Playable {
}
}
return builder.build();
- } else {
+ } else if(item != null) {
return item.getImageUri();
+ } else {
+ return null;
}
}
@@ -540,7 +558,7 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public void setDownloaded(boolean downloaded) {
super.setDownloaded(downloaded);
- if(downloaded) {
+ if(item != null && downloaded) {
item.setPlayed(false);
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
index ed568a6e5..faf23a37a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.core.feed;
import android.content.Context;
import android.database.Cursor;
+import android.support.annotation.NonNull;
import android.text.TextUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -13,8 +14,12 @@ import de.danoeh.antennapod.core.storage.PodDBAdapter;
*/
public class FeedPreferences {
+ @NonNull
+ private FeedFilter filter;
private long feedID;
private boolean autoDownload;
+ private boolean keepUpdated;
+
public enum AutoDeleteAction {
GLOBAL,
YES,
@@ -25,30 +30,63 @@ public class FeedPreferences {
private String password;
public FeedPreferences(long feedID, boolean autoDownload, AutoDeleteAction auto_delete_action, String username, String password) {
+ this(feedID, autoDownload, true, auto_delete_action, username, password, new FeedFilter());
+ }
+
+ public FeedPreferences(long feedID, boolean autoDownload, boolean keepUpdated, AutoDeleteAction auto_delete_action, String username, String password, @NonNull FeedFilter filter) {
this.feedID = feedID;
this.autoDownload = autoDownload;
+ this.keepUpdated = keepUpdated;
this.auto_delete_action = auto_delete_action;
this.username = username;
this.password = password;
+ this.filter = filter;
}
public static FeedPreferences fromCursor(Cursor cursor) {
int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID);
int indexAutoDownload = cursor.getColumnIndex(PodDBAdapter.KEY_AUTO_DOWNLOAD);
+ int indexAutoRefresh = cursor.getColumnIndex(PodDBAdapter.KEY_KEEP_UPDATED);
int indexAutoDeleteAction = cursor.getColumnIndex(PodDBAdapter.KEY_AUTO_DELETE_ACTION);
int indexUsername = cursor.getColumnIndex(PodDBAdapter.KEY_USERNAME);
int indexPassword = cursor.getColumnIndex(PodDBAdapter.KEY_PASSWORD);
+ int indexIncludeFilter = cursor.getColumnIndex(PodDBAdapter.KEY_INCLUDE_FILTER);
+ int indexExcludeFilter = cursor.getColumnIndex(PodDBAdapter.KEY_EXCLUDE_FILTER);
long feedId = cursor.getLong(indexId);
boolean autoDownload = cursor.getInt(indexAutoDownload) > 0;
+ boolean autoRefresh = cursor.getInt(indexAutoRefresh) > 0;
int autoDeleteActionIndex = cursor.getInt(indexAutoDeleteAction);
AutoDeleteAction autoDeleteAction = AutoDeleteAction.values()[autoDeleteActionIndex];
String username = cursor.getString(indexUsername);
String password = cursor.getString(indexPassword);
- return new FeedPreferences(feedId, autoDownload, autoDeleteAction, username, password);
+ String includeFilter = cursor.getString(indexIncludeFilter);
+ String excludeFilter = cursor.getString(indexExcludeFilter);
+ return new FeedPreferences(feedId, autoDownload, autoRefresh, autoDeleteAction, username, password, new FeedFilter(includeFilter, excludeFilter));
}
+ /**
+ * @return the filter for this feed
+ */
+ public FeedFilter getFilter() {
+ return filter;
+ }
+ public void setFilter(@NonNull FeedFilter filter) {
+ this.filter = filter;
+ }
+
+ /**
+ * @return true if this feed should be refreshed when everything else is being refreshed
+ * if false the feed should only be refreshed if requested directly.
+ */
+ public boolean getKeepUpdated() {
+ return keepUpdated;
+ }
+
+ public void setKeepUpdated(boolean keepUpdated) {
+ this.keepUpdated = keepUpdated;
+ }
/**
* Compare another FeedPreferences with this one. The feedID, autoDownload and AutoDeleteAction attribute are excluded from the
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
index d2a13f768..48f234917 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
@@ -10,8 +10,6 @@ import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.ClientProtocolException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -19,6 +17,7 @@ import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
@@ -602,10 +601,7 @@ public class GpodnetService {
checkStatusCode(response);
body = response.body();
result = getStringFromResponseBody(body);
- } catch (ClientProtocolException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- } catch (IOException e) {
+ } catch (Exception e) {
e.printStackTrace();
throw new GpodnetServiceException(e);
} finally {
@@ -652,12 +648,12 @@ public class GpodnetService {
private void checkStatusCode(@NonNull Response response)
throws GpodnetServiceException {
int responseCode = response.code();
- if (responseCode != HttpStatus.SC_OK) {
- if (responseCode == HttpStatus.SC_UNAUTHORIZED) {
+ if (responseCode != HttpURLConnection.HTTP_OK) {
+ if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
throw new GpodnetServiceAuthenticationException("Wrong username or password");
} else {
- throw new GpodnetServiceBadStatusCodeException(
- "Bad response code: " + responseCode, responseCode);
+ throw new GpodnetServiceBadStatusCodeException("Bad response code: "
+ + responseCode, responseCode);
}
}
}
@@ -739,13 +735,19 @@ public class GpodnetService {
List<String> added = new LinkedList<String>();
JSONArray jsonAdded = object.getJSONArray("add");
for (int i = 0; i < jsonAdded.length(); i++) {
- added.add(jsonAdded.getString(i));
+ String addedUrl = jsonAdded.getString(i);
+ // gpodder escapes colons unnecessarily
+ addedUrl = addedUrl.replace("%3A", ":");
+ added.add(addedUrl);
}
List<String> removed = new LinkedList<String>();
JSONArray jsonRemoved = object.getJSONArray("remove");
for (int i = 0; i < jsonRemoved.length(); i++) {
- removed.add(jsonRemoved.getString(i));
+ String removedUrl = jsonRemoved.getString(i);
+ // gpodder escapes colons unnecessarily
+ removedUrl = removedUrl.replace("%3A", ":");
+ removed.add(removedUrl);
}
long timestamp = object.getLong("timestamp");
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java
index e06a88d5c..5f096db14 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java
@@ -1,12 +1,13 @@
package de.danoeh.antennapod.core.gpoddernet.model;
+import android.support.v4.util.ArrayMap;
+
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
-import java.util.HashMap;
import java.util.Map;
public class GpodnetEpisodeActionPostResponse {
@@ -36,8 +37,8 @@ public class GpodnetEpisodeActionPostResponse {
public static GpodnetEpisodeActionPostResponse fromJSONObject(String objectString) throws JSONException {
final JSONObject object = new JSONObject(objectString);
final long timestamp = object.getLong("timestamp");
- Map<String, String> updatedUrls = new HashMap<String, String>();
JSONArray urls = object.getJSONArray("update_urls");
+ Map<String, String> updatedUrls = new ArrayMap<String, String>(urls.length());
for (int i = 0; i < urls.length(); i++) {
JSONArray urlPair = urls.getJSONArray(i);
updatedUrls.put(urlPair.getString(0), urlPair.getString(1));
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java
index 5a37efa5e..9bd1881e4 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java
@@ -1,10 +1,11 @@
package de.danoeh.antennapod.core.gpoddernet.model;
+import android.support.v4.util.ArrayMap;
+
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
-import java.util.HashMap;
import java.util.Map;
/**
@@ -37,7 +38,7 @@ public class GpodnetUploadChangesResponse {
public static GpodnetUploadChangesResponse fromJSONObject(String objectString) throws JSONException {
final JSONObject object = new JSONObject(objectString);
final long timestamp = object.getLong("timestamp");
- Map<String, String> updatedUrls = new HashMap<String, String>();
+ Map<String, String> updatedUrls = new ArrayMap<>();
JSONArray urls = object.getJSONArray("update_urls");
for (int i = 0; i < urls.length(); i++) {
JSONArray urlPair = urls.getJSONArray(i);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
index d6ac8496b..6c0aff15e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
@@ -20,7 +20,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -95,9 +94,12 @@ public class UserPreferences {
public static final String PREF_QUEUE_LOCKED = "prefQueueLocked";
public static final String IMAGE_CACHE_DEFAULT_VALUE = "100";
public static final int IMAGE_CACHE_SIZE_MINIMUM = 20;
+ public static final String PREF_LEFT_VOLUME = "prefLeftVolume";
+ public static final String PREF_RIGHT_VOLUME = "prefRightVolume";
// Experimental
public static final String PREF_SONIC = "prefSonic";
+ public static final String PREF_STEREO_TO_MONO = "PrefStereoToMono";
public static final String PREF_NORMALIZER = "prefNormalizer";
public static final int EPISODE_CLEANUP_QUEUE = -1;
public static final int EPISODE_CLEANUP_NULL = -2;
@@ -249,17 +251,37 @@ public class UserPreferences {
}
public static String getPlaybackSpeed() {
- return prefs.getString(PREF_PLAYBACK_SPEED, "1.0");
+ return prefs.getString(PREF_PLAYBACK_SPEED, "1.00");
}
public static String[] getPlaybackSpeedArray() {
return readPlaybackSpeedArray(prefs.getString(PREF_PLAYBACK_SPEED_ARRAY, null));
}
+ public static float getLeftVolume() {
+ int volume = prefs.getInt(PREF_LEFT_VOLUME, 100);
+ if(volume == 100) {
+ return 1.0f;
+ } else {
+ return (float) (1 - (Math.log(100 - volume) / Math.log(100)));
+ }
+ }
+
+ public static float getRightVolume() {
+ int volume = prefs.getInt(PREF_RIGHT_VOLUME, 100);
+ if(volume == 100) {
+ return 1.0f;
+ } else {
+ return (float) (1 - (Math.log(100 - volume) / Math.log(100)));
+ }
+ }
+
public static boolean shouldPauseForFocusLoss() {
return prefs.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, false);
}
+
+
public static long getUpdateInterval() {
String updateInterval = prefs.getString(PREF_UPDATE_INTERVAL, "0");
if(false == updateInterval.contains(":")) {
@@ -385,6 +407,15 @@ public class UserPreferences {
.apply();
}
+ public static void setVolume(int leftVolume, int rightVolume) {
+ assert(0 <= leftVolume && leftVolume <= 100);
+ assert(0 <= rightVolume && rightVolume <= 100);
+ prefs.edit()
+ .putInt(PREF_LEFT_VOLUME, leftVolume)
+ .putInt(PREF_RIGHT_VOLUME, rightVolume)
+ .apply();
+ }
+
public static void setAutodownloadSelectedNetworks(String[] value) {
prefs.edit()
.putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value))
@@ -472,7 +503,7 @@ public class UserPreferences {
// If this preference hasn't been set yet, return the default options
if (valueFromPrefs == null) {
String[] allSpeeds = context.getResources().getStringArray(R.array.playback_speed_values);
- List<String> speedList = new LinkedList<String>();
+ List<String> speedList = new ArrayList<>();
for (String speedStr : allSpeeds) {
float speed = Float.parseFloat(speedStr);
if (speed < 2.0001 && speed * 10 % 1 == 0) {
@@ -505,6 +536,16 @@ public class UserPreferences {
.apply();
}
+ public static boolean stereoToMono() {
+ return prefs.getBoolean(PREF_STEREO_TO_MONO, false);
+ }
+
+ public static void stereoToMono(boolean enable) {
+ prefs.edit()
+ .putBoolean(PREF_STEREO_TO_MONO, enable)
+ .apply();
+ }
+
public static EpisodeCleanupAlgorithm getEpisodeCleanupAlgorithm() {
int cleanupValue = Integer.valueOf(prefs.getString(PREF_EPISODE_CLEANUP, "-1"));
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java
index d5660f67e..d939c1007 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java
@@ -8,12 +8,11 @@ import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
+import android.support.v4.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -175,7 +174,7 @@ public class GpodnetSyncService extends Service {
for (String downloadUrl : changes.getAdded()) {
if (false == localSubscriptions.contains(downloadUrl) &&
false == localRemoved.contains(downloadUrl)) {
- Feed feed = new Feed(downloadUrl, new Date(0));
+ Feed feed = new Feed(downloadUrl, null);
DownloadRequester.getInstance().downloadFeed(this, feed);
}
}
@@ -226,7 +225,7 @@ public class GpodnetSyncService extends Service {
if(remoteActions.size() == 0) {
return;
}
- Map<Pair<String, String>, GpodnetEpisodeAction> localMostRecentPlayAction = new HashMap<Pair<String, String>, GpodnetEpisodeAction>();
+ Map<Pair<String, String>, GpodnetEpisodeAction> localMostRecentPlayAction = new ArrayMap<>();
for(GpodnetEpisodeAction action : localActions) {
Pair key = new Pair(action.getPodcast(), action.getEpisode());
GpodnetEpisodeAction mostRecent = localMostRecentPlayAction.get(key);
@@ -238,7 +237,7 @@ public class GpodnetSyncService extends Service {
}
// make sure more recent local actions are not overwritten by older remote actions
- Map<Pair<String, String>, GpodnetEpisodeAction> mostRecentPlayAction = new HashMap<Pair<String, String>, GpodnetEpisodeAction>();
+ Map<Pair<String, String>, GpodnetEpisodeAction> mostRecentPlayAction = new ArrayMap<>();
for (GpodnetEpisodeAction action : remoteActions) {
switch (action.getAction()) {
case NEW:
@@ -315,6 +314,7 @@ public class GpodnetSyncService extends Service {
.setContentIntent(activityIntent)
.setSmallIcon(R.drawable.stat_notify_sync_error)
.setAutoCancel(true)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
.build();
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(id, notification);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java
deleted file mode 100644
index 3efcf4da8..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package de.danoeh.antennapod.core.service.download;
-
-import android.util.Log;
-import de.danoeh.antennapod.core.BuildConfig;
-import org.apache.http.Header;
-import org.apache.http.HttpResponse;
-import org.apache.http.impl.client.DefaultRedirectHandler;
-import org.apache.http.protocol.HttpContext;
-
-import java.net.URI;
-
-public class APRedirectHandler extends DefaultRedirectHandler {
- // Identifier for logger
- private static final String TAG = "APRedirectHandler";
- // Header field, which has to be potentially fixed
- private static final String LOC = "Location";
- // Regular expressions for character strings, which should not appear in URLs
- private static final String CHi[] = { "\\{", "\\}", "\\|", "\\\\", "\\^", "~", "\\[", "\\]", "\\`"};
- private static final String CHo[] = { "%7B", "%7D", "%7C", "%5C", "%5E", "%7E", "%5B", "%5D", "%60"};
-
- /**
- * Workaround for broken URLs in redirection.
- * Proper solution involves LaxRedirectStrategy() which is not available in
- * current API yet.
- */
- @Override
- public URI getLocationURI(HttpResponse response, HttpContext context)
- throws org.apache.http.ProtocolException {
-
- Header h[] = response.getHeaders(LOC);
- if (h.length>0) {
- String s = h[0].getValue();
-
- // Fix broken URL
- for(int i=0; i<CHi.length;i++)
- s = s.replaceAll(CHi[i], CHo[i]);
-
- // If anything had to be fixed, then replace the header
- if (!s.equals(h[0].getValue()))
- {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Original URL: " + h[0].getValue());
-
- response.setHeader(LOC, s);
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Fixed URL: " + s);
- }
- }
-
- // call DefaultRedirectHandler with fixed URL
- return super.getLocationURI(response, context);
- }
-}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
index ed74e0fb6..b23819ef7 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
@@ -75,14 +75,14 @@ public class AntennapodHttpClient {
if(location.startsWith("/")) { // URL is not absolute, but relative
URL url = request.url();
location = url.getProtocol() + "://" + url.getHost() + location;
- } else if(!location.startsWith("http://") && !location.startsWith("https://")) {
+ } else if(!location.toLowerCase().startsWith("http://") &&
+ !location.toLowerCase().startsWith("https://")) {
// Reference is relative to current path
URL url = request.url();
String path = url.getPath();
String newPath = path.substring(0, path.lastIndexOf("/") + 1) + location;
location = url.getProtocol() + "://" + url.getHost() + newPath;
}
- Log.d(TAG, "New location: " + location);
try {
DBWriter.updateFeedDownloadURL(request.urlString(), location).get();
} catch (Exception e) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
index bc3006eea..7f40ea6e2 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
@@ -4,6 +4,7 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import de.danoeh.antennapod.core.feed.FeedFile;
import de.danoeh.antennapod.core.util.URLChecker;
@@ -15,7 +16,7 @@ public class DownloadRequest implements Parcelable {
private final String title;
private String username;
private String password;
- private long ifModifiedSince;
+ private String lastModified;
private boolean deleteOnFailure;
private final long feedfileId;
private final int feedfileType;
@@ -60,7 +61,7 @@ public class DownloadRequest implements Parcelable {
this.feedfileType = builder.feedfileType;
this.username = builder.username;
this.password = builder.password;
- this.ifModifiedSince = builder.ifModifiedSince;
+ this.lastModified = builder.lastModified;
this.deleteOnFailure = builder.deleteOnFailure;
this.arguments = (builder.arguments != null) ? builder.arguments : new Bundle();
}
@@ -71,7 +72,7 @@ public class DownloadRequest implements Parcelable {
title = in.readString();
feedfileId = in.readLong();
feedfileType = in.readInt();
- ifModifiedSince = in.readLong();
+ lastModified = in.readString();
deleteOnFailure = (in.readByte() > 0);
arguments = in.readBundle();
if (in.dataAvail() > 0) {
@@ -98,7 +99,7 @@ public class DownloadRequest implements Parcelable {
dest.writeString(title);
dest.writeLong(feedfileId);
dest.writeInt(feedfileType);
- dest.writeLong(ifModifiedSince);
+ dest.writeString(lastModified);
dest.writeByte((deleteOnFailure) ? (byte) 1 : 0);
dest.writeBundle(arguments);
if (username != null) {
@@ -127,7 +128,7 @@ public class DownloadRequest implements Parcelable {
DownloadRequest that = (DownloadRequest) o;
- if (ifModifiedSince != that.ifModifiedSince) return false;
+ if (lastModified != that.lastModified) return false;
if (deleteOnFailure != that.deleteOnFailure) return false;
if (feedfileId != that.feedfileId) return false;
if (feedfileType != that.feedfileType) return false;
@@ -143,7 +144,6 @@ public class DownloadRequest implements Parcelable {
if (title != null ? !title.equals(that.title) : that.title != null) return false;
if (username != null ? !username.equals(that.username) : that.username != null)
return false;
-
return true;
}
@@ -154,7 +154,7 @@ public class DownloadRequest implements Parcelable {
result = 31 * result + (title != null ? title.hashCode() : 0);
result = 31 * result + (username != null ? username.hashCode() : 0);
result = 31 * result + (password != null ? password.hashCode() : 0);
- result = 31 * result + (int)ifModifiedSince;
+ result = 31 * result + (lastModified != null ? lastModified.hashCode() : 0);
result = 31 * result + (deleteOnFailure ? 1 : 0);
result = 31 * result + (int) (feedfileId ^ (feedfileId >>> 32));
result = 31 * result + feedfileType;
@@ -234,13 +234,14 @@ public class DownloadRequest implements Parcelable {
this.password = password;
}
- public DownloadRequest setIfModifiedSince(long time) {
- this.ifModifiedSince = time;
+ public DownloadRequest setLastModified(@Nullable String lastModified) {
+ this.lastModified = lastModified;
return this;
}
- public long getIfModifiedSince() {
- return this.ifModifiedSince;
+ @Nullable
+ public String getLastModified() {
+ return lastModified;
}
public boolean isDeleteOnFailure() {
@@ -257,7 +258,7 @@ public class DownloadRequest implements Parcelable {
private String title;
private String username;
private String password;
- private long ifModifiedSince;
+ private String lastModified;
private boolean deleteOnFailure = false;
private long feedfileId;
private int feedfileType;
@@ -276,8 +277,8 @@ public class DownloadRequest implements Parcelable {
return this;
}
- public Builder ifModifiedSince(long time) {
- this.ifModifiedSince = time;
+ public Builder lastModified(String lastModified) {
+ this.lastModified = lastModified;
return this;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java
index f7e084e20..090c48ca0 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java
@@ -22,11 +22,11 @@ import android.util.Log;
import android.webkit.URLUtil;
import org.apache.commons.io.FileUtils;
-import org.apache.http.HttpStatus;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.IOException;
+import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@@ -188,7 +188,7 @@ public class DownloadService extends Service {
if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) {
postAuthenticationNotification(downloader.getDownloadRequest());
} else if (status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR
- && Integer.valueOf(status.getReasonDetailed()) == HttpStatus.SC_REQUESTED_RANGE_NOT_SATISFIABLE) {
+ && Integer.valueOf(status.getReasonDetailed()) == 416) {
Log.d(TAG, "Requested invalid range, restarting download from the beginning");
FileUtils.deleteQuietly(new File(downloader.getDownloadRequest().getDestination()));
@@ -198,11 +198,21 @@ public class DownloadService extends Service {
saveDownloadStatus(status);
handleFailedDownload(status, downloader.getDownloadRequest());
- // to make lists reload the failed item, we fake an item update
if(type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
long id = status.getFeedfileId();
FeedMedia media = DBReader.getFeedMedia(id);
- EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
+ if(media == null || media.getItem() == null) {
+ return;
+ }
+ FeedItem item = media.getItem();
+ boolean httpNotFound = status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR
+ && String.valueOf(HttpURLConnection.HTTP_NOT_FOUND).equals(status.getReasonDetailed());
+ boolean notEnoughSpace = status.getReason() == DownloadError.ERROR_NOT_ENOUGH_SPACE;
+ if (httpNotFound || notEnoughSpace) {
+ DBWriter.saveFeedItemAutoDownloadFailed(item).get();
+ }
+ // to make lists reload the failed item, we fake an item update
+ EventBus.getDefault().post(FeedItemEvent.updated(item));
}
}
} else {
@@ -340,7 +350,9 @@ public class DownloadService extends Service {
.setOngoing(true)
.setContentIntent(ClientConfig.downloadServiceCallbacks.getNotificationContentIntent(this))
.setLargeIcon(icon)
- .setSmallIcon(R.drawable.stat_notify_sync);
+ .setSmallIcon(R.drawable.stat_notify_sync)
+ .setVisibility(Notification.VISIBILITY_PUBLIC);
+
Log.d(TAG, "Notification set up");
}
@@ -354,7 +366,8 @@ public class DownloadService extends Service {
int numDownloads = requester.getNumberOfDownloads();
String downloadsLeft;
if (numDownloads > 0) {
- downloadsLeft = requester.getNumberOfDownloads() + getString(R.string.downloads_left);
+ downloadsLeft = getResources()
+ .getQuantityString(R.plurals.downloads_left, numDownloads, numDownloads);
} else {
downloadsLeft = getString(R.string.downloads_processing);
}
@@ -545,7 +558,9 @@ public class DownloadService extends Service {
.setContentIntent(
ClientConfig.downloadServiceCallbacks.getReportNotificationContentIntent(this)
)
- .setAutoCancel(true).build();
+ .setAutoCancel(true)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .build();
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(REPORT_ID, notification);
} else {
@@ -598,7 +613,8 @@ public class DownloadService extends Service {
.setSmallIcon(R.drawable.ic_stat_authentication)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_stat_authentication))
.setAutoCancel(true)
- .setContentIntent(ClientConfig.downloadServiceCallbacks.getAuthentificationNotificationContentIntent(DownloadService.this, downloadRequest));
+ .setContentIntent(ClientConfig.downloadServiceCallbacks.getAuthentificationNotificationContentIntent(DownloadService.this, downloadRequest))
+ .setVisibility(Notification.VISIBILITY_PUBLIC);
Notification n = builder.build();
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(downloadRequest.getSource().hashCode(), n);
@@ -814,7 +830,7 @@ public class DownloadService extends Service {
}
private Pair<DownloadRequest, FeedHandlerResult> parseFeed(DownloadRequest request) {
- Feed feed = new Feed(request.getSource(), new Date());
+ Feed feed = new Feed(request.getSource(), request.getLastModified());
feed.setFile_url(request.getDestination());
feed.setId(request.getFeedfileId());
feed.setDownloaded(true);
@@ -1032,11 +1048,13 @@ public class DownloadService extends Service {
throw new IllegalStateException(
"Could not find downloaded media object in database");
}
- boolean chaptersRead = false;
media.setDownloaded(true);
media.setFile_url(request.getDestination());
media.setHasEmbeddedPicture(null);
+ // check if file has chapters
+ ChapterUtils.loadChaptersFromFileUrl(media);
+
// Get duration
MediaMetadataRetriever mmr = null;
try {
@@ -1055,23 +1073,18 @@ public class DownloadService extends Service {
}
}
- if (media.getItem().getChapters() == null) {
- ChapterUtils.loadChaptersFromFileUrl(media);
- if (media.getItem().getChapters() != null) {
- chaptersRead = true;
- }
- }
+ final FeedItem item = media.getItem();
try {
// we've received the media, we don't want to autodownload it again
- FeedItem item = media.getItem();
- item.setAutoDownload(false);
-
- // update the db
- DBWriter.setFeedItem(item).get();
+ if(item != null) {
+ item.setAutoDownload(false);
+ DBWriter.setFeedItem(item).get();
+ }
DBWriter.setFeedMedia(media).get();
- if (!DBTasks.isInQueue(DownloadService.this, item.getId())) {
+
+ if (item != null && !DBTasks.isInQueue(DownloadService.this, item.getId())) {
DBWriter.addQueueItem(DownloadService.this, item).get();
}
} catch (ExecutionException e) {
@@ -1084,13 +1097,12 @@ public class DownloadService extends Service {
saveDownloadStatus(status);
- if(GpodnetPreferences.loggedIn()) {
- FeedItem item = media.getItem();
- GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, Action.DOWNLOAD)
- .currentDeviceId()
- .currentTimestamp()
- .build();
- GpodnetPreferences.enqueueEpisodeAction(action);
+ if(GpodnetPreferences.loggedIn() && item != null) {
+ GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, Action.DOWNLOAD)
+ .currentDeviceId()
+ .currentTimestamp()
+ .build();
+ GpodnetPreferences.enqueueEpisodeAction(action);
}
numberOfDownloads.decrementAndGet();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
index 9f54db477..e3a195253 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
@@ -8,10 +8,8 @@ import com.squareup.okhttp.Protocol;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
-import com.squareup.okhttp.internal.http.HttpDate;
import org.apache.commons.io.IOUtils;
-import org.apache.http.HttpStatus;
import java.io.BufferedInputStream;
import java.io.File;
@@ -29,6 +27,7 @@ import java.util.Date;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.feed.FeedImage;
+import de.danoeh.antennapod.core.util.DateUtils;
import de.danoeh.antennapod.core.util.DownloadError;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.URIUtil;
@@ -68,13 +67,19 @@ public class HttpDownloader extends Downloader {
final URI uri = URIUtil.getURIFromRequestUrl(request.getSource());
Request.Builder httpReq = new Request.Builder().url(uri.toURL())
.header("User-Agent", ClientConfig.USER_AGENT);
- if(request.getIfModifiedSince() > 0) {
- long threeDaysAgo = System.currentTimeMillis() - 1000*60*60*24*3;
- if(request.getIfModifiedSince() > threeDaysAgo) {
- Date date = new Date(request.getIfModifiedSince());
- String httpDate = HttpDate.format(date);
- Log.d(TAG, "addHeader(\"If-Modified-Since\", \"" + httpDate + "\")");
- httpReq.addHeader("If-Modified-Since", httpDate);
+ if(!TextUtils.isEmpty(request.getLastModified())) {
+ String lastModified = request.getLastModified();
+ Date lastModifiedDate = DateUtils.parse(lastModified);
+ if(lastModifiedDate != null) {
+ long threeDaysAgo = System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 3;
+ if (lastModifiedDate.getTime() > threeDaysAgo) {
+ Log.d(TAG, "addHeader(\"If-Modified-Since\", \"" + lastModified + "\")");
+ httpReq.addHeader("If-Modified-Since", lastModified);
+ }
+ } else {
+ String eTag = lastModified;
+ Log.d(TAG, "addHeader(\"If-None-Match\", \"" + eTag + "\")");
+ httpReq.addHeader("If-None-Match", eTag);
}
}
@@ -162,7 +167,7 @@ public class HttpDownloader extends Downloader {
return;
}
- if (!StorageUtils.storageAvailable(ClientConfig.applicationCallbacks.getApplicationInstance())) {
+ if (!StorageUtils.storageAvailable()) {
onFail(DownloadError.ERROR_DEVICE_NOT_FOUND, null);
return;
}
@@ -171,7 +176,7 @@ public class HttpDownloader extends Downloader {
String contentRangeHeader = (fileExists) ? response.header("Content-Range") : null;
- if (fileExists && response.code() == HttpStatus.SC_PARTIAL_CONTENT
+ if (fileExists && response.code() == HttpURLConnection.HTTP_PARTIAL
&& !TextUtils.isEmpty(contentRangeHeader)) {
String start = contentRangeHeader.substring("bytes ".length(),
contentRangeHeader.indexOf("-"));
@@ -236,6 +241,12 @@ public class HttpDownloader extends Downloader {
onFail(DownloadError.ERROR_IO_ERROR, "Download completed, but nothing was read");
return;
}
+ String lastModified = response.header("Last-Modified");
+ if(lastModified != null) {
+ request.setLastModified(lastModified);
+ } else {
+ request.setLastModified(response.header("ETag"));
+ }
onSuccess();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index 1313d9607..2be075a92 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -19,7 +19,7 @@ import android.os.Build;
import android.os.IBinder;
import android.os.Vibrator;
import android.preference.PreferenceManager;
-import android.support.v4.app.NotificationCompat;
+import android.support.v7.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -30,7 +30,6 @@ import android.widget.Toast;
import com.bumptech.glide.Glide;
import java.util.List;
-import java.util.concurrent.ExecutionException;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.R;
@@ -399,19 +398,25 @@ public class PlaybackService extends Service {
@Override
public void onSleepTimerAlmostExpired() {
- mediaPlayer.setVolume(0.1f);
+ float leftVolume = 0.1f * UserPreferences.getLeftVolume();
+ float rightVolume = 0.1f * UserPreferences.getRightVolume();
+ mediaPlayer.setVolume(leftVolume, rightVolume);
}
@Override
public void onSleepTimerExpired() {
mediaPlayer.pause(true, true);
- mediaPlayer.setVolume(1.0f);
+ float leftVolume = UserPreferences.getLeftVolume();
+ float rightVolume = UserPreferences.getRightVolume();
+ mediaPlayer.setVolume(leftVolume, rightVolume);
sendNotificationBroadcast(NOTIFICATION_TYPE_SLEEPTIMER_UPDATE, 0);
}
@Override
public void onSleepTimerReset() {
- mediaPlayer.setVolume(1.0f);
+ float leftVolume = UserPreferences.getLeftVolume();
+ float rightVolume = UserPreferences.getRightVolume();
+ mediaPlayer.setVolume(leftVolume, rightVolume);
}
@Override
@@ -808,14 +813,11 @@ public class PlaybackService extends Service {
.load(info.playable.getImageUri())
.asBitmap()
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .into(-1, -1) // this resizing would not be exact, so we have
- // scale the bitmap ourselves
+ .centerCrop()
+ .into(iconSize, iconSize)
.get();
- icon = Bitmap.createScaledBitmap(icon, iconSize, iconSize, true);
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
+ } catch(Throwable tr) {
+ Log.e(TAG, Log.getStackTraceString(tr));
}
}
}
@@ -835,7 +837,8 @@ public class PlaybackService extends Service {
String contentTitle = info.playable.getFeedTitle();
Notification notification = null;
- NotificationCompat.Builder notificationBuilder = new android.support.v7.app.NotificationCompat.Builder(
+ // Builder is v7, even if some not overwritten methods return its parent's v4 interface
+ NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(
PlaybackService.this)
.setContentTitle(contentTitle)
.setContentText(contentText)
@@ -1168,18 +1171,30 @@ public class PlaybackService extends Service {
public Playable getPlayable() { return mediaPlayer.getPlayable(); }
+ public boolean canSetSpeed() {
+ return mediaPlayer.canSetSpeed();
+ }
+
public void setSpeed(float speed) {
mediaPlayer.setSpeed(speed);
}
- public boolean canSetSpeed() {
- return mediaPlayer.canSetSpeed();
+ public void setVolume(float leftVolume, float rightVolume) {
+ mediaPlayer.setVolume(leftVolume, rightVolume);
}
public float getCurrentPlaybackSpeed() {
return mediaPlayer.getPlaybackSpeed();
}
+ public boolean canDownmix() {
+ return mediaPlayer.canDownmix();
+ }
+
+ public void setDownmix(boolean enable) {
+ mediaPlayer.setDownmix(enable);
+ }
+
public boolean isStartWhenPrepared() {
return mediaPlayer.isStartWhenPrepared();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
index 6ad376bf0..a82e82506 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
@@ -17,12 +17,13 @@ import android.support.v4.media.session.PlaybackStateCompat;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.Pair;
+import android.view.Display;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
+import android.view.WindowManager;
import com.bumptech.glide.Glide;
-import com.bumptech.glide.request.target.Target;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
@@ -292,20 +293,22 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration());
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
- if (p.getImageUri() != null) {
- if (UserPreferences.setLockscreenBackground()) {
- builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, p.getImageUri().toString());
- try {
- Bitmap art = Glide.with(context)
+
+ if (p.getImageUri() != null && UserPreferences.setLockscreenBackground()) {
+ builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, p.getImageUri().toString());
+ try {
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ Display display = wm.getDefaultDisplay();
+ Bitmap art = Glide.with(context)
.load(p.getImageUri())
.asBitmap()
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
+ .centerCrop()
+ .into(display.getWidth(), display.getHeight())
.get();
- builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, art);
- } catch (Exception e) {
- Log.e(TAG, Log.getStackTraceString(e));
- }
+ builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, art);
+ } catch (Throwable tr) {
+ Log.e(TAG, Log.getStackTraceString(tr));
}
}
mediaSession.setMetadata(builder.build());
@@ -320,13 +323,10 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
* This method is executed on an internal executor service.
*/
public void resume() {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- resumeSync();
- playerLock.unlock();
- }
+ executor.submit(() -> {
+ playerLock.lock();
+ resumeSync();
+ playerLock.unlock();
});
}
@@ -337,7 +337,15 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
AudioManager.AUDIOFOCUS_GAIN);
if (focusGained == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
acquireWifiLockIfNecessary();
- setSpeed(Float.parseFloat(UserPreferences.getPlaybackSpeed()));
+ float speed = 1.0f;
+ try {
+ speed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
+ } catch(NumberFormatException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ UserPreferences.setPlaybackSpeed(String.valueOf(speed));
+ }
+ setSpeed(speed);
+ setVolume(UserPreferences.getLeftVolume(), UserPreferences.getRightVolume());
if (playerStatus == PlayerStatus.PREPARED && media.getPosition() > 0) {
int newPosition = RewindAfterPauseUtils.calculatePositionWithRewind(
@@ -688,24 +696,39 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
* Sets the playback speed.
* This method is executed on an internal executor service.
*/
- public void setVolume(final float volume) {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- setVolumeSync(volume);
- }
- });
+ public void setVolume(final float volumeLeft, float volumeRight) {
+ executor.submit(() -> setVolumeSync(volumeLeft, volumeRight));
}
/**
* Sets the playback speed.
* This method is executed on the caller's thread.
*/
- private void setVolumeSync(float volume) {
+ private void setVolumeSync(float volumeLeft, float volumeRight) {
+ playerLock.lock();
+ if (media != null && media.getMediaType() == MediaType.AUDIO) {
+ mediaPlayer.setVolume(volumeLeft, volumeRight);
+ Log.d(TAG, "Media player volume was set to " + volumeLeft + " " + volumeRight);
+ }
+ playerLock.unlock();
+ }
+
+ /**
+ * Returns true if the mediaplayer can mix stereo down to mono
+ */
+ public boolean canDownmix() {
+ boolean retVal = false;
+ if (mediaPlayer != null && media != null && media.getMediaType() == MediaType.AUDIO) {
+ retVal = mediaPlayer.canDownmix();
+ }
+ return retVal;
+ }
+
+ public void setDownmix(boolean enable) {
playerLock.lock();
if (media != null && media.getMediaType() == MediaType.AUDIO) {
- mediaPlayer.setVolume(volume, volume);
- Log.d(TAG, "Media player volume was set to " + volume);
+ mediaPlayer.setDownmix(enable);
+ Log.d(TAG, "Media player downmix was set to " + enable);
}
playerLock.unlock();
}
@@ -958,6 +981,8 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
playerLock.lock();
releaseWifiLockIfNecessary();
+ boolean isPlaying = playerStatus == PlayerStatus.PLAYING;
+
if (playerStatus != PlayerStatus.INDETERMINATE) {
setPlayerStatus(PlayerStatus.INDETERMINATE, media);
}
@@ -966,7 +991,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
}
audioManager.abandonAudioFocus(audioFocusChangeListener);
- callback.endPlayback(true, wasSkipped);
+ callback.endPlayback(isPlaying, wasSkipped);
playerLock.unlock();
});
@@ -1125,9 +1150,13 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
private final org.antennapod.audio.MediaPlayer.OnErrorListener audioErrorListener = new org.antennapod.audio.MediaPlayer.OnErrorListener() {
@Override
- public boolean onError(org.antennapod.audio.MediaPlayer mp, int what,
- int extra) {
- return genericOnError(mp, what, extra);
+ public boolean onError(org.antennapod.audio.MediaPlayer mp, int what, int extra) {
+ if(mp.canFallback()) {
+ mp.fallback();
+ return true;
+ } else {
+ return genericOnError(mp, what, extra);
+ }
}
};
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
index 4e0c8a109..680fb8777 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
@@ -39,7 +39,7 @@ public class PlaybackServiceTaskManager {
/**
* Notification interval of widget updater in milliseconds.
*/
- public static final int WIDGET_UPDATER_NOTIFICATION_INTERVAL = 1500;
+ public static final int WIDGET_UPDATER_NOTIFICATION_INTERVAL = 1000;
private static final int SCHED_EX_POOL_SIZE = 2;
private final ScheduledThreadPoolExecutor schedExecutor;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java
index 446061ea6..fcd96826b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java
@@ -5,7 +5,6 @@ import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
-import android.util.FloatMath;
import android.util.Log;
public class ShakeListener implements SensorEventListener
@@ -50,8 +49,8 @@ public class ShakeListener implements SensorEventListener
float gY = event.values[1] / SensorManager.GRAVITY_EARTH;
float gZ = event.values[2] / SensorManager.GRAVITY_EARTH;
- float gForce = FloatMath.sqrt(gX*gX + gY*gY + gZ*gZ);
- if (gForce > 2.25f) {
+ double gForce = Math.sqrt(gX*gX + gY*gY + gZ*gZ);
+ if (gForce > 2.25) {
Log.d(TAG, "Detected shake " + gForce);
mSleepTimer.onShake();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java
index 0dc54fb6e..80703e22d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.core.storage;
import android.content.Context;
+import android.support.annotation.NonNull;
import android.util.Log;
import java.util.ArrayList;
@@ -28,30 +29,18 @@ public class APCleanupAlgorithm extends EpisodeCleanupAlgorithm {
this.numberOfDaysAfterPlayback = numberOfDaysAfterPlayback;
}
+ /**
+ * @return the number of episodes that *could* be cleaned up, if needed
+ */
+ public int getReclaimableItems()
+ {
+ return getCandidates().size();
+ }
+
@Override
public int performCleanup(Context context, int numberOfEpisodesToDelete) {
- List<FeedItem> candidates = new ArrayList<>();
- List<FeedItem> downloadedItems = DBReader.getDownloadedItems();
+ List<FeedItem> candidates = getCandidates();
List<FeedItem> delete;
- Calendar cal = Calendar.getInstance();
- cal.add(Calendar.DAY_OF_MONTH, -1 * numberOfDaysAfterPlayback);
- Date mostRecentDateForDeletion = cal.getTime();
- for (FeedItem item : downloadedItems) {
- if (item.hasMedia()
- && item.getMedia().isDownloaded()
- && !item.isTagged(FeedItem.TAG_QUEUE)
- && item.isPlayed()
- && !item.isTagged(FeedItem.TAG_FAVORITE)) {
- FeedMedia media = item.getMedia();
- // make sure this candidate was played at least the proper amount of days prior
- // to now
- if (media != null
- && media.getPlaybackCompletionDate() != null
- && media.getPlaybackCompletionDate().before(mostRecentDateForDeletion)) {
- candidates.add(item);
- }
- }
- }
Collections.sort(candidates, (lhs, rhs) -> {
Date l = lhs.getMedia().getPlaybackCompletionDate();
@@ -90,6 +79,32 @@ public class APCleanupAlgorithm extends EpisodeCleanupAlgorithm {
return counter;
}
+ @NonNull
+ private List<FeedItem> getCandidates() {
+ List<FeedItem> candidates = new ArrayList<>();
+ List<FeedItem> downloadedItems = DBReader.getDownloadedItems();
+ Calendar cal = Calendar.getInstance();
+ cal.add(Calendar.DAY_OF_MONTH, -1 * numberOfDaysAfterPlayback);
+ Date mostRecentDateForDeletion = cal.getTime();
+ for (FeedItem item : downloadedItems) {
+ if (item.hasMedia()
+ && item.getMedia().isDownloaded()
+ && !item.isTagged(FeedItem.TAG_QUEUE)
+ && item.isPlayed()
+ && !item.isTagged(FeedItem.TAG_FAVORITE)) {
+ FeedMedia media = item.getMedia();
+ // make sure this candidate was played at least the proper amount of days prior
+ // to now
+ if (media != null
+ && media.getPlaybackCompletionDate() != null
+ && media.getPlaybackCompletionDate().before(mostRecentDateForDeletion)) {
+ candidates.add(item);
+ }
+ }
+ }
+ return candidates;
+ }
+
@Override
public int getDefaultCleanupParameter() {
return getNumEpisodesToCleanup(0);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java
index 9e21a55f2..26dc027bf 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java
@@ -7,7 +7,9 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import de.danoeh.antennapod.core.feed.FeedFilter;
import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.PowerUtils;
@@ -54,7 +56,9 @@ public class APDownloadAlgorithm implements AutomaticDownloadAlgorithm {
candidates = new ArrayList<FeedItem>(queue.size() + newItems.size());
candidates.addAll(queue);
for(FeedItem newItem : newItems) {
- if(candidates.contains(newItem) == false) {
+ FeedPreferences feedPrefs = newItem.getFeed().getPreferences();
+ FeedFilter feedFilter = feedPrefs.getFilter();
+ if(candidates.contains(newItem) == false && feedFilter.shouldAutoDownload(newItem)) {
candidates.add(newItem);
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APNullCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APNullCleanupAlgorithm.java
index 132b61853..9cec62d83 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/APNullCleanupAlgorithm.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APNullCleanupAlgorithm.java
@@ -21,4 +21,9 @@ public class APNullCleanupAlgorithm extends EpisodeCleanupAlgorithm {
public int getDefaultCleanupParameter() {
return 0;
}
+
+ @Override
+ public int getReclaimableItems() {
+ return 0;
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java
index 234d6162c..baa9a986e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.core.storage;
import android.content.Context;
+import android.support.annotation.NonNull;
import android.util.Log;
import java.util.ArrayList;
@@ -22,19 +23,18 @@ public class APQueueCleanupAlgorithm extends EpisodeCleanupAlgorithm {
private static final String TAG = "APQueueCleanupAlgorithm";
+ /**
+ * @return the number of episodes that *could* be cleaned up, if needed
+ */
+ public int getReclaimableItems()
+ {
+ return getCandidates().size();
+ }
+
@Override
public int performCleanup(Context context, int numberOfEpisodesToDelete) {
- List<FeedItem> candidates = new ArrayList<>();
- List<FeedItem> downloadedItems = DBReader.getDownloadedItems();
+ List<FeedItem> candidates = getCandidates();
List<FeedItem> delete;
- for (FeedItem item : downloadedItems) {
- if (item.hasMedia()
- && item.getMedia().isDownloaded()
- && !item.isTagged(FeedItem.TAG_QUEUE)
- && !item.isTagged(FeedItem.TAG_FAVORITE)) {
- candidates.add(item);
- }
- }
// in the absence of better data, we'll sort by item publication date
Collections.sort(candidates, (lhs, rhs) -> {
@@ -74,6 +74,21 @@ public class APQueueCleanupAlgorithm extends EpisodeCleanupAlgorithm {
return counter;
}
+ @NonNull
+ private List<FeedItem> getCandidates() {
+ List<FeedItem> candidates = new ArrayList<>();
+ List<FeedItem> downloadedItems = DBReader.getDownloadedItems();
+ for (FeedItem item : downloadedItems) {
+ if (item.hasMedia()
+ && item.getMedia().isDownloaded()
+ && !item.isTagged(FeedItem.TAG_QUEUE)
+ && !item.isTagged(FeedItem.TAG_FAVORITE)) {
+ candidates.add(item);
+ }
+ }
+ return candidates;
+ }
+
@Override
public int getDefaultCleanupParameter() {
return getNumEpisodesToCleanup(0);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
index c34515118..68187306d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
@@ -1,13 +1,13 @@
package de.danoeh.antennapod.core.storage;
import android.database.Cursor;
+import android.support.v4.util.ArrayMap;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -229,7 +229,7 @@ public final class DBReader {
for(int i=0, len=itemIds.length; i < len; i++) {
ids[i] = String.valueOf(itemIds[i]);
}
- Map<Long,FeedMedia> result = new HashMap<>(itemIds.length);
+ Map<Long,FeedMedia> result = new ArrayMap<>(itemIds.length);
Cursor cursor = adapter.getFeedMediaCursor(ids);
try {
if (cursor.moveToFirst()) {
@@ -371,7 +371,7 @@ public final class DBReader {
/**
* Loads a list of FeedItems that are considered new.
- *
+ * Excludes items from feeds that do not have keep updated enabled.
* @return A list of FeedItems that are considered new.
*/
public static List<FeedItem> getNewItemsList() {
@@ -408,7 +408,7 @@ public final class DBReader {
return items;
}
- static LongList getFavoriteIDList() {
+ public static LongList getFavoriteIDList() {
Log.d(TAG, "getFavoriteIDList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -871,7 +871,7 @@ public final class DBReader {
ids[i] = String.valueOf(imageIds[i]);
}
Cursor cursor = adapter.getImageCursor(ids);
- Map<Long, FeedImage> result = new HashMap<>(cursor.getCount());
+ Map<Long, FeedImage> result = new ArrayMap<>(cursor.getCount());
try {
if ((cursor.getCount() == 0) || !cursor.moveToFirst()) {
return Collections.emptyMap();
@@ -1015,7 +1015,10 @@ public final class DBReader {
Collections.sort(feeds, comparator);
int queueSize = adapter.getQueueSize();
int numNewItems = adapter.getNumberOfNewItems();
- NavDrawerData result = new NavDrawerData(feeds, queueSize, numNewItems, feedCounters);
+ int numDownloadedItems = adapter.getNumberOfDownloadedEpisodes();
+
+ NavDrawerData result = new NavDrawerData(feeds, queueSize, numNewItems, numDownloadedItems,
+ feedCounters, UserPreferences.getEpisodeCleanupAlgorithm().getReclaimableItems());
adapter.close();
return result;
}
@@ -1024,16 +1027,22 @@ public final class DBReader {
public List<Feed> feeds;
public int queueSize;
public int numNewItems;
+ public int numDownloadedItems;
public LongIntMap feedCounters;
+ public int reclaimableSpace;
public NavDrawerData(List<Feed> feeds,
int queueSize,
int numNewItems,
- LongIntMap feedIndicatorValues) {
+ int numDownloadedItems,
+ LongIntMap feedIndicatorValues,
+ int reclaimableSpace) {
this.feeds = feeds;
this.queueSize = queueSize;
this.numNewItems = numNewItems;
+ this.numDownloadedItems = numDownloadedItems;
this.feedCounters = feedIndicatorValues;
+ this.reclaimableSpace = reclaimableSpace;
}
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
index 157e6d28c..ed593bb82 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
@@ -26,6 +26,7 @@ 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.feed.FeedPreferences;
import de.danoeh.antennapod.core.service.GpodnetSyncService;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
@@ -186,21 +187,30 @@ public final class DBTasks {
}
}
+ /**
+ * @param context
+ * @param feedList the list of feeds to refresh
+ */
private static void refreshFeeds(final Context context,
final List<Feed> feedList) {
for (Feed feed : feedList) {
- try {
- refreshFeed(context, feed);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DBWriter.addDownloadStatus(
- new DownloadStatus(feed, feed
- .getHumanReadableIdentifier(),
- DownloadError.ERROR_REQUEST_ERROR, false, e
- .getMessage()
- )
- );
+ FeedPreferences prefs = feed.getPreferences();
+ // feeds with !getKeepUpdated can only be refreshed
+ // directly from the FeedActivity
+ if (prefs.getKeepUpdated()) {
+ try {
+ refreshFeed(context, feed);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DBWriter.addDownloadStatus(
+ new DownloadStatus(feed, feed
+ .getHumanReadableIdentifier(),
+ DownloadError.ERROR_REQUEST_ERROR, false, e
+ .getMessage()
+ )
+ );
+ }
}
}
@@ -214,7 +224,28 @@ public final class DBTasks {
*/
public static void refreshCompleteFeed(final Context context, final Feed feed) {
try {
- refreshFeed(context, feed, true);
+ refreshFeed(context, feed, true, false);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DBWriter.addDownloadStatus(
+ new DownloadStatus(feed, feed
+ .getHumanReadableIdentifier(),
+ DownloadError.ERROR_REQUEST_ERROR, false, e
+ .getMessage()
+ )
+ );
+ }
+ }
+
+ /**
+ * Downloads all pages of the given feed even if feed has not been modified since last refresh
+ *
+ * @param context Used for requesting the download.
+ * @param feed The Feed object.
+ */
+ public static void forceRefreshCompleteFeed(final Context context, final Feed feed) {
+ try {
+ refreshFeed(context, feed, true, true);
} catch (DownloadRequestException e) {
e.printStackTrace();
DBWriter.addDownloadStatus(
@@ -238,11 +269,11 @@ public final class DBTasks {
public static void loadNextPageOfFeed(final Context context, Feed feed, boolean loadAllPages) throws DownloadRequestException {
if (feed.isPaged() && feed.getNextPageLink() != null) {
int pageNr = feed.getPageNr() + 1;
- Feed nextFeed = new Feed(feed.getNextPageLink(), new Date(), feed.getTitle() + "(" + pageNr + ")");
+ Feed nextFeed = new Feed(feed.getNextPageLink(), null, feed.getTitle() + "(" + pageNr + ")");
nextFeed.setPageNr(pageNr);
nextFeed.setPaged(true);
nextFeed.setId(feed.getId());
- DownloadRequester.getInstance().downloadFeed(context, nextFeed, loadAllPages);
+ DownloadRequester.getInstance().downloadFeed(context, nextFeed, loadAllPages, false);
} else {
Log.e(TAG, "loadNextPageOfFeed: Feed was either not paged or contained no nextPageLink");
}
@@ -258,12 +289,25 @@ public final class DBTasks {
public static void refreshFeed(Context context, Feed feed)
throws DownloadRequestException {
Log.d(TAG, "refreshFeed(feed.id: " + feed.getId() +")");
- refreshFeed(context, feed, false);
+ refreshFeed(context, feed, false, false);
}
- private static void refreshFeed(Context context, Feed feed, boolean loadAllPages) throws DownloadRequestException {
+ /**
+ * Refresh a specific feed even if feed has not been modified since last refresh
+ *
+ * @param context Used for requesting the download.
+ * @param feed The Feed object.
+ */
+ public static void forceRefreshFeed(Context context, Feed feed)
+ throws DownloadRequestException {
+ Log.d(TAG, "refreshFeed(feed.id: " + feed.getId() +")");
+ refreshFeed(context, feed, false, true);
+ }
+
+ private static void refreshFeed(Context context, Feed feed, boolean loadAllPages, boolean force)
+ throws DownloadRequestException {
Feed f;
- Date lastUpdate = feed.hasLastUpdateFailed() ? new Date(0) : feed.getLastUpdate();
+ String lastUpdate = feed.hasLastUpdateFailed() ? null : feed.getLastUpdate();
if (feed.getPreferences() == null) {
f = new Feed(feed.getDownload_url(), lastUpdate, feed.getTitle());
} else {
@@ -271,7 +315,7 @@ public final class DBTasks {
feed.getPreferences().getUsername(), feed.getPreferences().getPassword());
}
f.setId(feed.getId());
- DownloadRequester.getInstance().downloadFeed(context, f, loadAllPages);
+ DownloadRequester.getInstance().downloadFeed(context, f, loadAllPages, force);
}
/**
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
index efc0c882a..e728abc3b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
@@ -19,6 +19,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -222,6 +223,11 @@ public class DBWriter {
}
EventDistributor.getInstance().sendFeedUpdateBroadcast();
+ // we assume we also removed download log entries for the feed or its media files.
+ // especially important if download or refresh failed, as the user should not be able
+ // to retry these
+ EventDistributor.getInstance().sendDownloadLogUpdateBroadcast();
+
BackupManager backupManager = new BackupManager(context);
backupManager.dataChanged();
}
@@ -971,13 +977,32 @@ public class DBWriter {
* Sets the 'auto_download'-attribute of specific FeedItem.
*
* @param feedItem FeedItem.
+ * @param autoDownload true enables auto download, false disables it
*/
public static Future<?> setFeedItemAutoDownload(final FeedItem feedItem,
final boolean autoDownload) {
- Log.d(TAG, "FeedItem[id=" + feedItem.getId() + "] SET auto_download " + autoDownload);
return dbExec.submit(() -> {
final PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
+ adapter.setFeedItemAutoDownload(feedItem, autoDownload ? 1 : 0);
+ adapter.close();
+ EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
+ });
+ }
+
+ public static Future<?> saveFeedItemAutoDownloadFailed(final FeedItem feedItem) {
+ return dbExec.submit(() -> {
+ int failedAttempts = feedItem.getFailedAutoDownloadAttempts() + 1;
+ long autoDownload;
+ if(!feedItem.getAutoDownload() || failedAttempts >= 10) {
+ autoDownload = 0; // giving up, disable auto download
+ feedItem.setAutoDownload(false);
+ } else {
+ long now = System.currentTimeMillis();
+ autoDownload = (now / 10) * 10 + failedAttempts;
+ }
+ final PodDBAdapter adapter = PodDBAdapter.getInstance();
+ adapter.open();
adapter.setFeedItemAutoDownload(feedItem, autoDownload);
adapter.close();
EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
@@ -986,7 +1011,8 @@ public class DBWriter {
/**
* Sets the 'auto_download'-attribute of specific FeedItem.
- * @param feed This feed's episodes will be processed.
+ *
+ * @param feed This feed's episodes will be processed.
* @param autoDownload If true, auto download will be enabled for the feed's episodes. Else,
*/
public static Future<?> setFeedsItemsAutoDownload(final Feed feed,
@@ -1008,8 +1034,8 @@ public class DBWriter {
* @param filterValues Values that represent properties to filter by
*/
public static Future<?> setFeedItemsFilter(final long feedId,
- final List<String> filterValues) {
- Log.d(TAG, "setFeedFilter");
+ final Set<String> filterValues) {
+ Log.d(TAG, "setFeedItemsFilter() called with: " + "feedId = [" + feedId + "], filterValues = [" + filterValues + "]");
return dbExec.submit(() -> {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
index 0dc1dadeb..22c9538ca 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
@@ -88,7 +88,7 @@ public class DownloadRequester {
private void download(Context context, FeedFile item, FeedFile container, File dest,
boolean overwriteIfExists, String username, String password,
- long ifModifiedSince, boolean deleteOnFailure, Bundle arguments) {
+ String lastModified, boolean deleteOnFailure, Bundle arguments) {
final boolean partiallyDownloadedFileExists = item.getFile_url() != null;
if (isDownloadingFile(item)) {
Log.e(TAG, "URL " + item.getDownload_url()
@@ -129,7 +129,7 @@ public class DownloadRequester {
DownloadRequest.Builder builder = new DownloadRequest.Builder(dest.toString(), item)
.withAuthentication(username, password)
- .ifModifiedSince(ifModifiedSince)
+ .lastModified(lastModified)
.deleteOnFailure(deleteOnFailure)
.withArguments(arguments);
DownloadRequest request = builder.build();
@@ -162,24 +162,25 @@ public class DownloadRequester {
* @param feed Feed to download
* @param loadAllPages Set to true to download all pages
*/
- public synchronized void downloadFeed(Context context, Feed feed, boolean loadAllPages)
+ public synchronized void downloadFeed(Context context, Feed feed, boolean loadAllPages,
+ boolean force)
throws DownloadRequestException {
if (feedFileValid(feed)) {
String username = (feed.getPreferences() != null) ? feed.getPreferences().getUsername() : null;
String password = (feed.getPreferences() != null) ? feed.getPreferences().getPassword() : null;
- long ifModifiedSince = feed.isPaged() ? 0 : feed.getLastUpdate().getTime();
+ String lastModified = feed.isPaged() || force ? null : feed.getLastUpdate();
Bundle args = new Bundle();
args.putInt(REQUEST_ARG_PAGE_NR, feed.getPageNr());
args.putBoolean(REQUEST_ARG_LOAD_ALL_PAGES, loadAllPages);
download(context, feed, null, new File(getFeedfilePath(context),
- getFeedfileName(feed)), true, username, password, ifModifiedSince, true, args);
+ getFeedfileName(feed)), true, username, password, lastModified, true, args);
}
}
public synchronized void downloadFeed(Context context, Feed feed) throws DownloadRequestException {
- downloadFeed(context, feed, false);
+ downloadFeed(context, feed, false, false);
}
public synchronized void downloadMedia(Context context, FeedMedia feedmedia)
@@ -204,7 +205,7 @@ public class DownloadRequester {
getMediafilename(feedmedia));
}
download(context, feedmedia, feed,
- dest, false, username, password, 0, false, null);
+ dest, false, username, password, null, false, null);
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java
index 0f402745c..97cbdca33 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java
@@ -40,6 +40,11 @@ public abstract class EpisodeCleanupAlgorithm {
}
/**
+ * @return the number of episodes/items that *could* be cleaned up, if needed
+ */
+ public abstract int getReclaimableItems();
+
+ /**
* @param amountOfRoomNeeded the number of episodes we want to download
* @return the number of episodes to delete in order to make room
*/
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
index 97d91ccd3..5b7f5f720 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
@@ -10,12 +10,12 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.media.MediaMetadataRetriever;
-import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.event.ProgressEvent;
@@ -92,6 +92,7 @@ public class PodDBAdapter {
public static final String KEY_CHAPTER_TYPE = "type";
public static final String KEY_PLAYBACK_COMPLETION_DATE = "playback_completion_date";
public static final String KEY_AUTO_DOWNLOAD = "auto_download";
+ public static final String KEY_KEEP_UPDATED = "keep_updated";
public static final String KEY_AUTO_DELETE_ACTION = "auto_delete_action";
public static final String KEY_PLAYED_DURATION = "played_duration";
public static final String KEY_USERNAME = "username";
@@ -102,6 +103,8 @@ public class PodDBAdapter {
public static final String KEY_LAST_UPDATE_FAILED = "last_update_failed";
public static final String KEY_HAS_EMBEDDED_PICTURE = "has_embedded_picture";
public static final String KEY_LAST_PLAYED_TIME = "last_played_time";
+ public static final String KEY_INCLUDE_FILTER = "include_filter";
+ public static final String KEY_EXCLUDE_FILTER = "exclude_filter";
// Table names
public static final String TABLE_NAME_FEEDS = "Feeds";
@@ -128,6 +131,9 @@ public class PodDBAdapter {
+ KEY_FLATTR_STATUS + " INTEGER,"
+ KEY_USERNAME + " TEXT,"
+ KEY_PASSWORD + " TEXT,"
+ + KEY_INCLUDE_FILTER + " TEXT DEFAULT '',"
+ + KEY_EXCLUDE_FILTER + " TEXT DEFAULT '',"
+ + KEY_KEEP_UPDATED + " INTEGER DEFAULT 1,"
+ KEY_IS_PAGED + " INTEGER DEFAULT 0,"
+ KEY_NEXT_PAGE_LINK + " TEXT,"
+ KEY_HIDE + " TEXT,"
@@ -230,6 +236,7 @@ public class PodDBAdapter {
TABLE_NAME_FEEDS + "." + KEY_TYPE,
TABLE_NAME_FEEDS + "." + KEY_FEED_IDENTIFIER,
TABLE_NAME_FEEDS + "." + KEY_AUTO_DOWNLOAD,
+ TABLE_NAME_FEEDS + "." + KEY_KEEP_UPDATED,
TABLE_NAME_FEEDS + "." + KEY_FLATTR_STATUS,
TABLE_NAME_FEEDS + "." + KEY_IS_PAGED,
TABLE_NAME_FEEDS + "." + KEY_NEXT_PAGE_LINK,
@@ -238,6 +245,8 @@ public class PodDBAdapter {
TABLE_NAME_FEEDS + "." + KEY_HIDE,
TABLE_NAME_FEEDS + "." + KEY_LAST_UPDATE_FAILED,
TABLE_NAME_FEEDS + "." + KEY_AUTO_DELETE_ACTION,
+ TABLE_NAME_FEEDS + "." + KEY_INCLUDE_FILTER,
+ TABLE_NAME_FEEDS + "." + KEY_EXCLUDE_FILTER
};
/**
@@ -309,15 +318,11 @@ public class PodDBAdapter {
private PodDBAdapter() {}
- public synchronized PodDBAdapter open() {
- counter++;
+ public PodDBAdapter open() {
if (db == null || !db.isOpen() || db.isReadOnly()) {
Log.v(TAG, "Opening DB");
try {
db = dbHelper.getWritableDatabase();
- if(Build.VERSION.SDK_INT >= 11) {
- db.enableWriteAheadLogging();
- }
} catch (SQLException ex) {
Log.e(TAG, Log.getStackTraceString(ex));
db = dbHelper.getReadableDatabase();
@@ -326,13 +331,8 @@ public class PodDBAdapter {
return this;
}
- public synchronized void close() {
- counter--;
- if(counter == 0) {
- Log.v(TAG, "Closing DB");
- db.close();
- db = null;
- }
+ public void close() {
+ // do nothing
}
public static boolean deleteDatabase() {
@@ -368,7 +368,7 @@ public class PodDBAdapter {
values.put(KEY_FILE_URL, feed.getFile_url());
values.put(KEY_DOWNLOAD_URL, feed.getDownload_url());
values.put(KEY_DOWNLOADED, feed.isDownloaded());
- values.put(KEY_LASTUPDATE, feed.getLastUpdate().getTime());
+ values.put(KEY_LASTUPDATE, feed.getLastUpdate());
values.put(KEY_TYPE, feed.getType());
values.put(KEY_FEED_IDENTIFIER, feed.getFeedIdentifier());
@@ -401,16 +401,20 @@ public class PodDBAdapter {
}
ContentValues values = new ContentValues();
values.put(KEY_AUTO_DOWNLOAD, prefs.getAutoDownload());
+ values.put(KEY_KEEP_UPDATED, prefs.getKeepUpdated());
values.put(KEY_AUTO_DELETE_ACTION,prefs.getAutoDeleteAction().ordinal());
values.put(KEY_USERNAME, prefs.getUsername());
values.put(KEY_PASSWORD, prefs.getPassword());
+ values.put(KEY_INCLUDE_FILTER, prefs.getFilter().getIncludeFilter());
+ values.put(KEY_EXCLUDE_FILTER, prefs.getFilter().getExcludeFilter());
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(prefs.getFeedID())});
}
- public void setFeedItemFilter(long feedId, List<String> filterValues) {
+ public void setFeedItemFilter(long feedId, Set<String> filterValues) {
+ Log.d(TAG, "setFeedItemFilter() called with: " + "feedId = [" + feedId + "], " +
+ "filterValues = [" + TextUtils.join(",", filterValues) + "]");
ContentValues values = new ContentValues();
values.put(KEY_HIDE, TextUtils.join(",", filterValues));
- Log.d(TAG, TextUtils.join(",", filterValues));
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(feedId)});
}
@@ -802,7 +806,7 @@ public class PodDBAdapter {
return status.getId();
}
- public void setFeedItemAutoDownload(FeedItem feedItem, boolean autoDownload) {
+ public void setFeedItemAutoDownload(FeedItem feedItem, long autoDownload) {
ContentValues values = new ContentValues();
values.put(KEY_AUTO_DOWNLOAD, autoDownload);
db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?",
@@ -894,6 +898,10 @@ public class PodDBAdapter {
}
public void removeFeedMedia(FeedMedia media) {
+ // delete download log entries for feed media
+ db.delete(TABLE_NAME_DOWNLOAD_LOG, KEY_FEEDFILE + "=? AND " + KEY_FEEDFILETYPE +"=?",
+ new String[] { String.valueOf(media.getId()), String.valueOf(FeedMedia.FEEDFILETYPE_FEEDMEDIA) });
+
db.delete(TABLE_NAME_FEED_MEDIA, KEY_ID + "=?",
new String[]{String.valueOf(media.getId())});
}
@@ -938,6 +946,9 @@ public class PodDBAdapter {
removeFeedItem(item);
}
}
+ // delete download log entries for feed
+ db.delete(TABLE_NAME_DOWNLOAD_LOG, KEY_FEEDFILE + "=? AND " + KEY_FEEDFILETYPE +"=?",
+ new String[] { String.valueOf(feed.getId()), String.valueOf(Feed.FEEDFILETYPE_FEED) });
db.delete(TABLE_NAME_FEEDS, KEY_ID + "=?",
new String[]{String.valueOf(feed.getId())});
@@ -1120,13 +1131,6 @@ public class PodDBAdapter {
return c;
}
- public final Cursor getNewItemIdsCursor() {
- final String query = "SELECT " + KEY_ID
- + " FROM " + TABLE_NAME_FEED_ITEMS
- + " WHERE " + KEY_READ + "=" + FeedItem.NEW;
- return db.rawQuery(query, null);
- }
-
/**
* Returns a cursor which contains all items of a feed that are considered new.
* The returned cursor uses the FEEDITEM_SEL_FI_SMALL selection.
@@ -1143,13 +1147,19 @@ public class PodDBAdapter {
/**
* Returns a cursor which contains all feed items that are considered new.
+ * Excludes those feeds that do not have 'Keep Updated' enabled.
* The returned cursor uses the FEEDITEM_SEL_FI_SMALL selection.
*/
public final Cursor getNewItemsCursor() {
- final String query = "SELECT " + SEL_FI_SMALL_STR
- + " FROM " + TABLE_NAME_FEED_ITEMS
- + " WHERE " + KEY_READ + "=" + FeedItem.NEW
- + " ORDER BY " + KEY_PUBDATE + " DESC";
+ Object[] args = new String[] {
+ SEL_FI_SMALL_STR,
+ TABLE_NAME_FEED_ITEMS,
+ TABLE_NAME_FEEDS,
+ TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID,
+ TABLE_NAME_FEED_ITEMS + "." + KEY_READ + "=" + FeedItem.NEW + " AND " + TABLE_NAME_FEEDS + "." + KEY_KEEP_UPDATED + " > 0",
+ KEY_PUBDATE + " DESC"
+ };
+ final String query = String.format("SELECT %s FROM %s INNER JOIN %s ON %s WHERE %s ORDER BY %s", args);
Cursor c = db.rawQuery(query, null);
return c;
}
@@ -1266,25 +1276,31 @@ public class PodDBAdapter {
}
public final Cursor getFeedItemCursor(final String podcastUrl, final String episodeUrl) {
- final String query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS
- + " INNER JOIN " +
- TABLE_NAME_FEEDS + " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" +
- TABLE_NAME_FEEDS + "." + KEY_ID + " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER + "='" +
- episodeUrl + "' AND " + TABLE_NAME_FEEDS + "." + KEY_DOWNLOAD_URL + "='" + podcastUrl + "'";
+ String downloadUrl = DatabaseUtils.sqlEscapeString(podcastUrl);
+ String itemIdentifier = DatabaseUtils.sqlEscapeString(episodeUrl);
+ final String query = ""
+ + "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS
+ + " INNER JOIN " + TABLE_NAME_FEEDS
+ + " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
+ + " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER + "=" + itemIdentifier
+ + " AND " + TABLE_NAME_FEEDS + "." + KEY_DOWNLOAD_URL + "=" + downloadUrl;
return db.rawQuery(query, null);
}
public Cursor getImageAuthenticationCursor(final String imageUrl) {
- final String query = "SELECT " + KEY_USERNAME + "," + KEY_PASSWORD + " FROM "
- + TABLE_NAME_FEED_IMAGES + " INNER JOIN " + TABLE_NAME_FEEDS + " ON " +
- TABLE_NAME_FEED_IMAGES + "." + KEY_ID + "=" + TABLE_NAME_FEEDS + "." + KEY_IMAGE + " WHERE "
- + TABLE_NAME_FEED_IMAGES + "." + KEY_DOWNLOAD_URL + "='" + imageUrl + "' UNION SELECT "
- + KEY_USERNAME + "," + KEY_PASSWORD + " FROM " + TABLE_NAME_FEED_IMAGES + " INNER JOIN "
- + TABLE_NAME_FEED_ITEMS + " ON " + TABLE_NAME_FEED_IMAGES + "." + KEY_ID + "=" +
- TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE + " INNER JOIN " + TABLE_NAME_FEEDS + " ON "
- + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID + " WHERE "
- + TABLE_NAME_FEED_IMAGES + "." + KEY_DOWNLOAD_URL + "='" + imageUrl + "'";
- Log.d(TAG, "Query: " + query);
+ String downloadUrl = DatabaseUtils.sqlEscapeString(imageUrl);
+ final String query = ""
+ + "SELECT " + KEY_USERNAME + "," + KEY_PASSWORD + " FROM " + TABLE_NAME_FEED_IMAGES
+ + " INNER JOIN " + TABLE_NAME_FEEDS
+ + " ON " + TABLE_NAME_FEED_IMAGES + "." + KEY_ID + "=" + TABLE_NAME_FEEDS + "." + KEY_IMAGE
+ + " WHERE " + TABLE_NAME_FEED_IMAGES + "." + KEY_DOWNLOAD_URL + "=" + downloadUrl
+ + " UNION SELECT " + KEY_USERNAME + "," + KEY_PASSWORD
+ + " FROM " + TABLE_NAME_FEED_IMAGES
+ + " INNER JOIN " + TABLE_NAME_FEED_ITEMS
+ + " ON " + TABLE_NAME_FEED_IMAGES + "." + KEY_ID + "=" + TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE
+ + " INNER JOIN " + TABLE_NAME_FEEDS
+ + " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
+ + " WHERE " + TABLE_NAME_FEED_IMAGES + "." + KEY_DOWNLOAD_URL + "=" + downloadUrl;
return db.rawQuery(query, null);
}
@@ -1496,7 +1512,7 @@ public class PodDBAdapter {
*/
private static class PodDBHelper extends SQLiteOpenHelper {
- private final static int VERSION = 1040013;
+ private final static int VERSION = 1050004;
private Context context;
@@ -1740,6 +1756,58 @@ public class PodDBAdapter {
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_PUBDATE);
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_READ);
}
+ if (oldVersion < 1050003) {
+ // Migrates feed list filter data
+
+ db.beginTransaction();
+
+ // Change to intermediate values to avoid overwriting in the following find/replace
+ db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
+ "SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'unplayed', 'noplay')");
+ db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
+ "SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'not_queued', 'noqueue')");
+ db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
+ "SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'not_downloaded', 'nodl')");
+
+ // Replace played, queued, and downloaded with their opposites
+ db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
+ "SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'played', 'unplayed')");
+ db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
+ "SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'queued', 'not_queued')");
+ db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
+ "SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'downloaded', 'not_downloaded')");
+
+ // Now replace intermediates for unplayed, not queued, etc. with their opposites
+ db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
+ "SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'noplay', 'played')");
+ db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
+ "SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'noqueue', 'queued')");
+ db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
+ "SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'nodl', 'downloaded')");
+
+ // Paused doesn't have an opposite, so unplayed is the next best option
+ db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
+ "SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'paused', 'unplayed')");
+
+ db.setTransactionSuccessful();
+ db.endTransaction();
+
+ // and now get ready for autodownload filters
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ + " ADD COLUMN " + PodDBAdapter.KEY_INCLUDE_FILTER + " TEXT DEFAULT ''");
+
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ + " ADD COLUMN " + PodDBAdapter.KEY_EXCLUDE_FILTER + " TEXT DEFAULT ''");
+
+ // and now auto refresh
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ + " ADD COLUMN " + PodDBAdapter.KEY_KEEP_UPDATED + " INTEGER DEFAULT 1");
+ }
+ if (oldVersion < 1050004) {
+ // prevent old timestamps to be misinterpreted as ETags
+ db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS
+ +" SET " + PodDBAdapter.KEY_LASTUPDATE + "=NULL");
+ }
EventBus.getDefault().post(ProgressEvent.end());
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java
index 413a11f8e..9280db8a3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.core.syndication.handler;
+import android.support.v4.util.ArrayMap;
+
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Stack;
@@ -32,7 +32,7 @@ public class HandlerState {
/**
* Namespaces that have been defined so far.
*/
- protected HashMap<String, Namespace> namespaces;
+ protected Map<String, Namespace> namespaces;
protected Stack<Namespace> defaultNamespaces;
/**
* Buffer for saving characters.
@@ -42,16 +42,16 @@ public class HandlerState {
/**
* Temporarily saved objects.
*/
- protected HashMap<String, Object> tempObjects;
+ protected Map<String, Object> tempObjects;
public HandlerState(Feed feed) {
this.feed = feed;
- alternateUrls = new LinkedHashMap<String, String>();
+ alternateUrls = new ArrayMap<>();
items = new ArrayList<FeedItem>();
tagstack = new Stack<SyndElement>();
- namespaces = new HashMap<String, Namespace>();
+ namespaces = new ArrayMap<>();
defaultNamespaces = new Stack<Namespace>();
- tempObjects = new HashMap<String, Object>();
+ tempObjects = new ArrayMap<>();
}
public Feed getFeed() {
@@ -105,7 +105,7 @@ public class HandlerState {
alternateUrls.put(url, title);
}
- public HashMap<String, Object> getTempObjects() {
+ public Map<String, Object> getTempObjects() {
return tempObjects;
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java
index 6406295c1..99c4cd67a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.core.syndication.namespace;
+import android.text.TextUtils;
+
import org.xml.sax.Attributes;
import java.util.concurrent.TimeUnit;
@@ -17,6 +19,8 @@ public class NSITunes extends Namespace {
private static final String AUTHOR = "author";
public static final String DURATION = "duration";
+ public static final String SUBTITLE = "subtitle";
+ public static final String SUMMARY = "summary";
@Override
@@ -36,8 +40,10 @@ public class NSITunes extends Namespace {
} else {
// this is the feed image
// prefer to all other images
- image.setOwner(state.getFeed());
- state.getFeed().setImage(image);
+ if(!TextUtils.isEmpty(image.getDownload_url())) {
+ image.setOwner(state.getFeed());
+ state.getFeed().setImage(image);
+ }
}
}
@@ -63,13 +69,28 @@ public class NSITunes extends Namespace {
} else {
return;
}
-
state.getTempObjects().put(DURATION, duration);
} catch (NumberFormatException e) {
e.printStackTrace();
}
+ } else if (localName.equals(SUBTITLE)) {
+ String subtitle = state.getContentBuf().toString();
+ if (state.getCurrentItem() != null) {
+ if (TextUtils.isEmpty(state.getCurrentItem().getDescription())) {
+ state.getCurrentItem().setDescription(subtitle);
+ }
+ } else {
+ if (TextUtils.isEmpty(state.getFeed().getDescription())) {
+ state.getFeed().setDescription(subtitle);
+ }
+ }
+ } else if (localName.equals(SUMMARY)) {
+ String summary = state.getContentBuf().toString();
+ if (state.getCurrentItem() != null) {
+ state.getCurrentItem().setDescription(summary);
+ } else {
+ state.getFeed().setDescription(summary);
+ }
}
-
}
-
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java
index a690e7646..b23a142af 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java
@@ -4,7 +4,6 @@ import android.util.Log;
import org.xml.sax.Attributes;
-import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.feed.FeedImage;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
@@ -88,16 +87,15 @@ public class NSAtom extends Namespace {
size = Long.parseLong(strSize);
}
} catch (NumberFormatException e) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Length attribute could not be parsed.");
+ Log.d(TAG, "Length attribute could not be parsed.");
}
String type = attributes.getValue(LINK_TYPE);
if (SyndTypeUtils.enclosureTypeValid(type)
- || (type = SyndTypeUtils
- .getValidMimeTypeFromUrl(href)) != null) {
- state.getCurrentItem().setMedia(
- new FeedMedia(state.getCurrentItem(), href,
- size, type)
- );
+ || (type = SyndTypeUtils.getValidMimeTypeFromUrl(href)) != null) {
+ FeedItem currItem = state.getCurrentItem();
+ if(!currItem.hasMedia()) {
+ currItem.setMedia(new FeedMedia(currItem, href, size, type));
+ }
}
} else if (rel.equals(LINK_REL_PAYMENT)) {
state.getCurrentItem().setPaymentLink(href);
@@ -111,9 +109,11 @@ public class NSAtom extends Namespace {
* LINK_TYPE_HTML or LINK_TYPE_XHTML
*/
if ((type == null && state.getFeed().getLink() == null)
- || (type != null && (type.equals(LINK_TYPE_HTML) || type.equals(LINK_TYPE_XHTML)))) {
+ || (type != null && (type.equals(LINK_TYPE_HTML)
+ || type.equals(LINK_TYPE_XHTML)))) {
state.getFeed().setLink(href);
- } else if (type != null && (type.equals(LINK_TYPE_ATOM) || type.equals(LINK_TYPE_RSS))) {
+ } else if (type != null && (type.equals(LINK_TYPE_ATOM)
+ || type.equals(LINK_TYPE_RSS))) {
// treat as podlove alternate feed
String title = attributes.getValue(LINK_TITLE);
if (title == null) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
index 1a148673c..6b0f423df 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.core.util;
+import android.content.Context;
import android.util.Log;
import org.apache.commons.lang3.StringUtils;
@@ -7,6 +8,7 @@ import org.apache.commons.lang3.StringUtils;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
@@ -141,4 +143,20 @@ public class DateUtils {
format.setTimeZone(defaultTimezone);
return format.format(date);
}
+
+ public static String formatAbbrev(final Context context, final Date date) {
+ if(date == null) {
+ return "";
+ }
+ GregorianCalendar cal = new GregorianCalendar();
+ cal.add(GregorianCalendar.YEAR, -1);
+ // some padding, because no one really remembers what day of the month it is
+ cal.add(GregorianCalendar.DAY_OF_MONTH, 10);
+ boolean withinLastYear = date.after(cal.getTime());
+ int format = android.text.format.DateUtils.FORMAT_ABBREV_ALL;
+ if(withinLastYear) {
+ format |= android.text.format.DateUtils.FORMAT_NO_YEAR;
+ }
+ return android.text.format.DateUtils.formatDateTime(context, date.getTime(), format);
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java
index 3817d3361..892e5ff38 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java
@@ -29,6 +29,16 @@ public class FeedItemUtil {
return -1;
}
+ public static int indexOfItemWithMediaId(List<FeedItem> items, long mediaId) {
+ for(int i=0; i < items.size(); i++) {
+ FeedItem item = items.get(i);
+ if(item != null && item.getMedia() != null && item.getMedia().getId() == mediaId) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
public static long[] getIds(FeedItem... items) {
if(items == null || items.length == 0) {
return new long[0];
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java
index 07432d28a..287ec4d0c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java
@@ -1,14 +1,15 @@
package de.danoeh.antennapod.core.util;
+import android.support.v4.util.ArrayMap;
+
import java.nio.charset.Charset;
-import java.util.HashMap;
public class LangUtils {
public static final Charset UTF_8 = Charset.forName("UTF-8");
- private static HashMap<String, String> languages;
+ private static ArrayMap<String, String> languages;
static {
- languages = new HashMap<String, String>();
+ languages = new ArrayMap<>();
languages.put("af", "Afrikaans");
languages.put("sq", "Albanian");
languages.put("sq", "Albanian");
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java
index 248f2bf32..1ef81bf64 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java
@@ -1,14 +1,12 @@
package de.danoeh.antennapod.core.util;
import android.app.Activity;
-import android.content.Context;
import android.os.Build;
import android.os.StatFs;
import android.util.Log;
import java.io.File;
-import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -18,13 +16,12 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
public class StorageUtils {
private static final String TAG = "StorageUtils";
- public static boolean storageAvailable(Context context) {
+ public static boolean storageAvailable() {
File dir = UserPreferences.getDataFolder(null);
if (dir != null) {
return dir.exists() && dir.canRead() && dir.canWrite();
} else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Storage not available: data folder is null");
+ Log.d(TAG, "Storage not available: data folder is null");
return false;
}
}
@@ -39,7 +36,7 @@ public class StorageUtils {
* @return true if external storage is available
*/
public static boolean checkStorageAvailability(Activity activity) {
- boolean storageAvailable = storageAvailable(activity);
+ boolean storageAvailable = storageAvailable();
if (!storageAvailable) {
activity.finish();
activity.startActivity(ClientConfig.applicationCallbacks.getStorageErrorActivity(activity));
@@ -51,8 +48,19 @@ public class StorageUtils {
* Get the number of free bytes that are available on the external storage.
*/
public static long getFreeSpaceAvailable() {
- StatFs stat = new StatFs(UserPreferences.getDataFolder(
- null).getAbsolutePath());
+ File dataFolder = UserPreferences.getDataFolder(null);
+ if (dataFolder != null) {
+ return getFreeSpaceAvailable(dataFolder.getAbsolutePath());
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Get the number of free bytes that are available on the external storage.
+ */
+ public static long getFreeSpaceAvailable(String path) {
+ StatFs stat = new StatFs(path);
long availableBlocks;
long blockSize;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java
index b6beb5bf1..f0850e6df 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java
@@ -37,4 +37,9 @@ public class AudioPlayer extends MediaPlayer implements IPlayer {
protected boolean useSonic() {
return UserPreferences.useSonic();
}
+
+ @Override
+ protected boolean downmix() {
+ return UserPreferences.stereoToMono();
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java
index 147c7848d..d67153a4e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java
@@ -10,6 +10,8 @@ public interface IPlayer {
boolean canSetSpeed();
+ boolean canDownmix();
+
float getCurrentPitchStepsAdjustment();
int getCurrentPosition();
@@ -57,6 +59,8 @@ public interface IPlayer {
void setPlaybackSpeed(float f);
+ void setDownmix(boolean enable);
+
void setVolume(float left, float right);
void start();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
index a519fb555..27935978c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
@@ -11,6 +11,7 @@ import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.media.MediaPlayer;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
@@ -18,7 +19,6 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.SurfaceHolder;
-import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.SeekBar;
@@ -27,7 +27,6 @@ import android.widget.TextView;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -36,6 +35,7 @@ import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
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.service.playback.PlaybackServiceMediaPlayer;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
@@ -48,6 +48,7 @@ import de.danoeh.antennapod.core.util.playback.Playable.PlayableUtils;
* control playback instead of communicating with the PlaybackService directly.
*/
public abstract class PlaybackController {
+
private static final String TAG = "PlaybackController";
public static final int INVALID_TIME = -1;
@@ -78,16 +79,11 @@ public abstract class PlaybackController {
this.activity = activity;
this.reinitOnPause = reinitOnPause;
schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOLSIZE,
- new ThreadFactory() {
-
- @Override
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(Thread.MIN_PRIORITY);
- return t;
- }
+ r -> {
+ Thread t = new Thread(r);
+ t.setPriority(Thread.MIN_PRIORITY);
+ return t;
}, new RejectedExecutionHandler() {
-
@Override
public void rejectedExecution(Runnable r,
ThreadPoolExecutor executor) {
@@ -104,10 +100,10 @@ public abstract class PlaybackController {
*/
public void init() {
activity.registerReceiver(statusUpdate, new IntentFilter(
- PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
+ PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
activity.registerReceiver(notificationReceiver, new IntentFilter(
- PlaybackService.ACTION_PLAYER_NOTIFICATION));
+ PlaybackService.ACTION_PLAYER_NOTIFICATION));
activity.registerReceiver(shutdownReceiver, new IntentFilter(
PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
@@ -239,7 +235,7 @@ public abstract class PlaybackController {
return null;
}
- public abstract void setupGUI();
+
private void setupPositionObserver() {
if ((positionObserverFuture != null && positionObserverFuture
@@ -263,8 +259,6 @@ public abstract class PlaybackController {
}
}
- public abstract void onPositionObserverUpdate();
-
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
playbackService = ((PlaybackService.LocalBinder) service)
@@ -367,26 +361,31 @@ public abstract class PlaybackController {
}
};
- public abstract void onPlaybackSpeedChange();
+ public void setupGUI() {};
+
+ public void onPositionObserverUpdate() {};
+
- public abstract void onShutdownNotification();
+ public void onPlaybackSpeedChange() {};
+
+ public void onShutdownNotification() {};
/**
* Called when the currently displayed information should be refreshed.
*/
- public abstract void onReloadNotification(int code);
+ public void onReloadNotification(int code) {};
- public abstract void onBufferStart();
+ public void onBufferStart() {};
- public abstract void onBufferEnd();
+ public void onBufferEnd() {};
- public abstract void onBufferUpdate(float progress);
+ public void onBufferUpdate(float progress) {};
- public abstract void onSleepTimerUpdate();
+ public void onSleepTimerUpdate() {};
- public abstract void handleError(int code);
+ public void handleError(int code) {};
- public abstract void onPlaybackEnd();
+ public void onPlaybackEnd() {};
public void repeatHandleStatus() {
if (status != null && playbackService != null) {
@@ -417,7 +416,6 @@ public abstract class PlaybackController {
Log.d(TAG, "status: " + status.toString());
switch (status) {
-
case ERROR:
postStatusMsg(R.string.player_error_msg);
handleError(MediaPlayer.MEDIA_ERROR_UNKNOWN);
@@ -484,15 +482,19 @@ public abstract class PlaybackController {
}
}
- public abstract ImageButton getPlayButton();
+ public ImageButton getPlayButton() {
+ return null;
+ };
- public abstract void postStatusMsg(int msg);
+ public void postStatusMsg(int msg) {};
- public abstract void clearStatusMsg();
+ public void clearStatusMsg() {};
- public abstract boolean loadMediaInfo();
+ public boolean loadMediaInfo() {
+ return false;
+ };
- public abstract void onAwaitingVideoSurface();
+ public void onAwaitingVideoSurface() {};
/**
* Called when connection to playback service has been established or
@@ -526,7 +528,7 @@ public abstract class PlaybackController {
}
}
- public abstract void onServiceQueried();
+ public void onServiceQueried() {};
/**
* Should be used by classes which implement the OnSeekBarChanged interface.
@@ -573,37 +575,32 @@ public abstract class PlaybackController {
}
public OnClickListener newOnPlayButtonClickListener() {
- return new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (playbackService != null) {
- switch (status) {
- case PLAYING:
- playbackService.pause(true, reinitOnPause);
- break;
- case PAUSED:
- case PREPARED:
- playbackService.resume();
- break;
- case PREPARING:
- playbackService.setStartWhenPrepared(!playbackService
- .isStartWhenPrepared());
- if (reinitOnPause
- && playbackService.isStartWhenPrepared() == false) {
- playbackService.reinit();
- }
- break;
- case INITIALIZED:
- playbackService.setStartWhenPrepared(true);
- playbackService.prepare();
- break;
+ return v -> {
+ if (playbackService == null) {
+ Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!");
+ return;
+ }
+ switch (status) {
+ case PLAYING:
+ playbackService.pause(true, reinitOnPause);
+ break;
+ case PAUSED:
+ case PREPARED:
+ playbackService.resume();
+ break;
+ case PREPARING:
+ playbackService.setStartWhenPrepared(!playbackService
+ .isStartWhenPrepared());
+ if (reinitOnPause
+ && playbackService.isStartWhenPrepared() == false) {
+ playbackService.reinit();
}
- } else {
- Log.w(TAG,
- "Play/Pause button was pressed, but playbackservice was null!");
- }
+ break;
+ case INITIALIZED:
+ playbackService.setStartWhenPrepared(true);
+ playbackService.prepare();
+ break;
}
-
};
}
@@ -682,6 +679,11 @@ public abstract class PlaybackController {
}
public boolean canSetPlaybackSpeed() {
+ if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(activity.getApplicationContext())
+ || UserPreferences.useSonic()
+ || Build.VERSION.SDK_INT >= 23) {
+ return true;
+ }
return playbackService != null && playbackService.canSetSpeed();
}
@@ -691,6 +693,12 @@ public abstract class PlaybackController {
}
}
+ public void setVolume(float leftVolume, float rightVolume) {
+ if (playbackService != null) {
+ playbackService.setVolume(leftVolume, rightVolume);
+ }
+ }
+
public float getCurrentPlaybackSpeedMultiplier() {
if (canSetPlaybackSpeed()) {
return playbackService.getCurrentPlaybackSpeed();
@@ -699,6 +707,16 @@ public abstract class PlaybackController {
}
}
+ public boolean canDownmix() {
+ return playbackService != null && playbackService.canDownmix();
+ }
+
+ public void setDownmix(boolean enable) {
+ if(playbackService != null) {
+ playbackService.setDownmix(enable);
+ }
+ }
+
public boolean isPlayingVideo() {
if (playbackService != null) {
return PlaybackService.getCurrentMediaType() == MediaType.VIDEO;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
index 00f2e6f57..2eee1ac87 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
@@ -88,7 +88,7 @@ public class Timeline {
}
// replace ASCII line breaks with HTML ones if shownotes don't contain HTML line breaks already
- if(!LINE_BREAK_REGEX.matcher(shownotes).find()) {
+ if(!LINE_BREAK_REGEX.matcher(shownotes).find() && !shownotes.contains("<p>")) {
shownotes = shownotes.replace("\n", "<br />");
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java
index dc5270d8f..368379509 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java
@@ -17,6 +17,11 @@ public class VideoPlayer extends MediaPlayer implements IPlayer {
}
@Override
+ public boolean canDownmix() {
+ return false;
+ }
+
+ @Override
public float getCurrentPitchStepsAdjustment() {
return 1;
}
@@ -60,6 +65,12 @@ public class VideoPlayer extends MediaPlayer implements IPlayer {
throw new UnsupportedOperationException("Setting playback speed unsupported in video player");
}
+ @Override
+ public void setDownmix(boolean b) {
+ Log.e(TAG, "Setting downmix unsupported in video player");
+ throw new UnsupportedOperationException("Setting downmix unsupported in video player");
+ }
+
@Override
public void setVideoScalingMode(int mode) {
super.setVideoScalingMode(mode);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
index d148419fd..13cb9f002 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.core.util.syndication;
import android.net.Uri;
+import android.support.v4.util.ArrayMap;
import android.text.TextUtils;
import org.jsoup.Jsoup;
@@ -10,7 +11,6 @@ import org.jsoup.select.Elements;
import java.io.File;
import java.io.IOException;
-import java.util.LinkedHashMap;
import java.util.Map;
/**
@@ -46,7 +46,7 @@ public class FeedDiscoverer {
}
private Map<String, String> findLinks(Document document, String baseUrl) {
- Map<String, String> res = new LinkedHashMap<String, String>();
+ Map<String, String> res = new ArrayMap<>();
Elements links = document.head().getElementsByTag("link");
for (Element link : links) {
String rel = link.attr("rel");
diff --git a/core/src/main/res/drawable-hdpi-v11/stat_notify_sync.png b/core/src/main/res/drawable-hdpi-v11/stat_notify_sync.png
deleted file mode 100644
index 90b39c958..000000000
--- a/core/src/main/res/drawable-hdpi-v11/stat_notify_sync.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi-v11/stat_notify_sync_error.png b/core/src/main/res/drawable-hdpi-v11/stat_notify_sync_error.png
deleted file mode 100644
index 074cdee27..000000000
--- a/core/src/main/res/drawable-hdpi-v11/stat_notify_sync_error.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_av_fast_forward_80dp.png b/core/src/main/res/drawable-hdpi/ic_av_fast_forward_80dp.png
new file mode 100755
index 000000000..a32968a19
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_av_fast_forward_80dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_av_rewind_80dp.png b/core/src/main/res/drawable-hdpi/ic_av_rewind_80dp.png
new file mode 100755
index 000000000..e39de4dcf
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_av_rewind_80dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_check_box_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_check_box_grey600_24dp.png
new file mode 100644
index 000000000..e4e833242
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_check_box_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_check_box_outline_blank_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_check_box_outline_blank_grey600_24dp.png
new file mode 100644
index 000000000..4f1a804b3
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_check_box_outline_blank_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_check_box_outline_blank_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_check_box_outline_blank_white_24dp.png
new file mode 100644
index 000000000..6dbf83c58
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_check_box_outline_blank_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_check_box_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_check_box_white_24dp.png
new file mode 100644
index 000000000..d3f636f13
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_check_box_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_create_new_folder_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_create_new_folder_grey600_24dp.png
new file mode 100644
index 000000000..bfe98fd07
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_create_new_folder_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_create_new_folder_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_create_new_folder_white_24dp.png
new file mode 100644
index 000000000..a8b0ada87
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_create_new_folder_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_drag_vertical_grey600_48dp.9.png b/core/src/main/res/drawable-hdpi/ic_drag_vertical_grey600_48dp.9.png
new file mode 100644
index 000000000..f2d9906c6
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_drag_vertical_grey600_48dp.9.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_drag_vertical_grey600_48dp.png b/core/src/main/res/drawable-hdpi/ic_drag_vertical_grey600_48dp.png
deleted file mode 100644
index 17202c8d1..000000000
--- a/core/src/main/res/drawable-hdpi/ic_drag_vertical_grey600_48dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_drag_vertical_white_48dp.9.png b/core/src/main/res/drawable-hdpi/ic_drag_vertical_white_48dp.9.png
new file mode 100644
index 000000000..a2a91938d
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_drag_vertical_white_48dp.9.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_drag_vertical_white_48dp.png b/core/src/main/res/drawable-hdpi/ic_drag_vertical_white_48dp.png
deleted file mode 100644
index 48e221b86..000000000
--- a/core/src/main/res/drawable-hdpi/ic_drag_vertical_white_48dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_feed_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_feed_grey600_24dp.png
index 0c3bb0757..d1ad6629d 100755
--- a/core/src/main/res/drawable-hdpi/ic_feed_grey600_24dp.png
+++ b/core/src/main/res/drawable-hdpi/ic_feed_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_feed_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_feed_white_24dp.png
index 667300129..9ff662fca 100755
--- a/core/src/main/res/drawable-hdpi/ic_feed_white_24dp.png
+++ b/core/src/main/res/drawable-hdpi/ic_feed_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_indeterminate_check_box_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_indeterminate_check_box_grey600_24dp.png
new file mode 100644
index 000000000..62dd8ef48
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_indeterminate_check_box_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_indeterminate_check_box_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_indeterminate_check_box_white_24dp.png
new file mode 100644
index 000000000..5bb43b464
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_indeterminate_check_box_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sd_storage_grey600_36dp.png b/core/src/main/res/drawable-hdpi/ic_sd_storage_grey600_36dp.png
new file mode 100644
index 000000000..0890b2e5c
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sd_storage_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sd_storage_white_36dp.png b/core/src/main/res/drawable-hdpi/ic_sd_storage_white_36dp.png
new file mode 100644
index 000000000..d9bfcfbfb
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sd_storage_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-hdpi/ic_skip_grey600_36dp.png
new file mode 100644
index 000000000..edbc95b05
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_skip_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-hdpi/ic_skip_white_36dp.png
new file mode 100644
index 000000000..cbfb262d8
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_skip_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sleep_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_sleep_grey600_24dp.png
new file mode 100644
index 000000000..809066499
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sleep_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sleep_off_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_sleep_off_grey600_24dp.png
new file mode 100644
index 000000000..4496a320d
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sleep_off_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sleep_off_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_sleep_off_white_24dp.png
new file mode 100644
index 000000000..79684ab65
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sleep_off_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sleep_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_sleep_white_24dp.png
new file mode 100644
index 000000000..f0df6032c
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sleep_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sort_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_sort_grey600_24dp.png
new file mode 100644
index 000000000..0a52de9fe
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sort_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sort_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_sort_white_24dp.png
new file mode 100644
index 000000000..26014a542
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sort_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_star_border_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_star_border_grey600_24dp.png
new file mode 100644
index 000000000..006410bc3
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_star_border_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_star_border_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_star_border_white_24dp.png
new file mode 100644
index 000000000..27831192f
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_star_border_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_star_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_star_grey600_24dp.png
new file mode 100644
index 000000000..93f70a024
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_star_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_star_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_star_white_24dp.png
new file mode 100644
index 000000000..e8619b780
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_star_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/stat_notify_sync.png b/core/src/main/res/drawable-hdpi/stat_notify_sync.png
index bfb8110fe..ca6c68e4e 100644
--- a/core/src/main/res/drawable-hdpi/stat_notify_sync.png
+++ b/core/src/main/res/drawable-hdpi/stat_notify_sync.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/stat_notify_sync_error.png b/core/src/main/res/drawable-hdpi/stat_notify_sync_error.png
index b340a313e..84f19cd4e 100644
--- a/core/src/main/res/drawable-hdpi/stat_notify_sync_error.png
+++ b/core/src/main/res/drawable-hdpi/stat_notify_sync_error.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi-v11/stat_notify_sync.png b/core/src/main/res/drawable-mdpi-v11/stat_notify_sync.png
deleted file mode 100644
index 1be8677f1..000000000
--- a/core/src/main/res/drawable-mdpi-v11/stat_notify_sync.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi-v11/stat_notify_sync_error.png b/core/src/main/res/drawable-mdpi-v11/stat_notify_sync_error.png
deleted file mode 100644
index 30658c583..000000000
--- a/core/src/main/res/drawable-mdpi-v11/stat_notify_sync_error.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_av_fast_forward_80dp.png b/core/src/main/res/drawable-mdpi/ic_av_fast_forward_80dp.png
new file mode 100755
index 000000000..69b81c10d
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_av_fast_forward_80dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_av_rewind_80dp.png b/core/src/main/res/drawable-mdpi/ic_av_rewind_80dp.png
new file mode 100755
index 000000000..5355abfd6
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_av_rewind_80dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_check_box_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_check_box_grey600_24dp.png
new file mode 100644
index 000000000..a6bdce736
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_check_box_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_check_box_outline_blank_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_check_box_outline_blank_grey600_24dp.png
new file mode 100644
index 000000000..cd90223d1
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_check_box_outline_blank_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_check_box_outline_blank_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_check_box_outline_blank_white_24dp.png
new file mode 100644
index 000000000..8a014bda1
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_check_box_outline_blank_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_check_box_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_check_box_white_24dp.png
new file mode 100644
index 000000000..0811a3493
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_check_box_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_create_new_folder_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_create_new_folder_grey600_24dp.png
new file mode 100644
index 000000000..eeed34653
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_create_new_folder_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_create_new_folder_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_create_new_folder_white_24dp.png
new file mode 100644
index 000000000..3b9eaa827
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_create_new_folder_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_drag_vertical_grey600_48dp.9.png b/core/src/main/res/drawable-mdpi/ic_drag_vertical_grey600_48dp.9.png
new file mode 100644
index 000000000..0d8277204
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_drag_vertical_grey600_48dp.9.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_drag_vertical_grey600_48dp.png b/core/src/main/res/drawable-mdpi/ic_drag_vertical_grey600_48dp.png
deleted file mode 100644
index 31ef36bde..000000000
--- a/core/src/main/res/drawable-mdpi/ic_drag_vertical_grey600_48dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_drag_vertical_white_48dp.9.png b/core/src/main/res/drawable-mdpi/ic_drag_vertical_white_48dp.9.png
new file mode 100644
index 000000000..15d016e89
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_drag_vertical_white_48dp.9.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_drag_vertical_white_48dp.png b/core/src/main/res/drawable-mdpi/ic_drag_vertical_white_48dp.png
deleted file mode 100644
index 1c0e89e60..000000000
--- a/core/src/main/res/drawable-mdpi/ic_drag_vertical_white_48dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_feed_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_feed_grey600_24dp.png
index d46b325d8..3932b6eef 100755
--- a/core/src/main/res/drawable-mdpi/ic_feed_grey600_24dp.png
+++ b/core/src/main/res/drawable-mdpi/ic_feed_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_feed_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_feed_white_24dp.png
index ac94476c2..9c2a1eb6e 100755
--- a/core/src/main/res/drawable-mdpi/ic_feed_white_24dp.png
+++ b/core/src/main/res/drawable-mdpi/ic_feed_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_indeterminate_check_box_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_indeterminate_check_box_grey600_24dp.png
new file mode 100644
index 000000000..52812c42f
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_indeterminate_check_box_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_indeterminate_check_box_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_indeterminate_check_box_white_24dp.png
new file mode 100644
index 000000000..20a9fe5d7
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_indeterminate_check_box_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sd_storage_grey600_36dp.png b/core/src/main/res/drawable-mdpi/ic_sd_storage_grey600_36dp.png
new file mode 100644
index 000000000..f0c5ed4c3
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sd_storage_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sd_storage_white_36dp.png b/core/src/main/res/drawable-mdpi/ic_sd_storage_white_36dp.png
new file mode 100644
index 000000000..6595d2e1e
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sd_storage_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-mdpi/ic_skip_grey600_36dp.png
new file mode 100644
index 000000000..be0fcc765
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_skip_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-mdpi/ic_skip_white_36dp.png
new file mode 100644
index 000000000..893cf2c64
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_skip_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sleep_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_sleep_grey600_24dp.png
new file mode 100644
index 000000000..ea511bf2a
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sleep_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sleep_off_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_sleep_off_grey600_24dp.png
new file mode 100644
index 000000000..7f631ad86
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sleep_off_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sleep_off_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_sleep_off_white_24dp.png
new file mode 100644
index 000000000..795e318e3
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sleep_off_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sleep_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_sleep_white_24dp.png
new file mode 100644
index 000000000..4304a6bca
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sleep_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sort_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_sort_grey600_24dp.png
new file mode 100644
index 000000000..f527d0094
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sort_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sort_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_sort_white_24dp.png
new file mode 100644
index 000000000..e28dd4592
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sort_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_star_border_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_star_border_grey600_24dp.png
new file mode 100644
index 000000000..dd9d11ba0
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_star_border_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_star_border_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_star_border_white_24dp.png
new file mode 100644
index 000000000..104fb3c9d
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_star_border_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_star_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_star_grey600_24dp.png
new file mode 100644
index 000000000..af84b71f2
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_star_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_star_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_star_white_24dp.png
new file mode 100644
index 000000000..0ccebc7c8
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_star_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/stat_notify_sync.png b/core/src/main/res/drawable-mdpi/stat_notify_sync.png
index 03ce57a47..516b65bd9 100644
--- a/core/src/main/res/drawable-mdpi/stat_notify_sync.png
+++ b/core/src/main/res/drawable-mdpi/stat_notify_sync.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/stat_notify_sync_error.png b/core/src/main/res/drawable-mdpi/stat_notify_sync_error.png
index f849b5040..c3ed306cf 100644
--- a/core/src/main/res/drawable-mdpi/stat_notify_sync_error.png
+++ b/core/src/main/res/drawable-mdpi/stat_notify_sync_error.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi-v11/stat_notify_sync.png b/core/src/main/res/drawable-xhdpi-v11/stat_notify_sync.png
deleted file mode 100644
index b3bf21ffe..000000000
--- a/core/src/main/res/drawable-xhdpi-v11/stat_notify_sync.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi-v11/stat_notify_sync_error.png b/core/src/main/res/drawable-xhdpi-v11/stat_notify_sync_error.png
deleted file mode 100644
index 33582ef10..000000000
--- a/core/src/main/res/drawable-xhdpi-v11/stat_notify_sync_error.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_av_fast_forward_80dp.png b/core/src/main/res/drawable-xhdpi/ic_av_fast_forward_80dp.png
new file mode 100755
index 000000000..ed34e22a1
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_av_fast_forward_80dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_av_rewind_80dp.png b/core/src/main/res/drawable-xhdpi/ic_av_rewind_80dp.png
new file mode 100755
index 000000000..3dc7bf5cb
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_av_rewind_80dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_check_box_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_check_box_grey600_24dp.png
new file mode 100644
index 000000000..f7c205dd2
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_check_box_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_check_box_outline_blank_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_check_box_outline_blank_grey600_24dp.png
new file mode 100644
index 000000000..ea2ff8671
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_check_box_outline_blank_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_check_box_outline_blank_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_check_box_outline_blank_white_24dp.png
new file mode 100644
index 000000000..a615ee436
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_check_box_outline_blank_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_check_box_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_check_box_white_24dp.png
new file mode 100644
index 000000000..946cfea57
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_check_box_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_create_new_folder_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_create_new_folder_grey600_24dp.png
new file mode 100644
index 000000000..82f0ad458
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_create_new_folder_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_create_new_folder_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_create_new_folder_white_24dp.png
new file mode 100644
index 000000000..aa54623c8
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_create_new_folder_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_drag_vertical_grey600_48dp.9.png b/core/src/main/res/drawable-xhdpi/ic_drag_vertical_grey600_48dp.9.png
new file mode 100644
index 000000000..8f335e274
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_drag_vertical_grey600_48dp.9.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_drag_vertical_grey600_48dp.png b/core/src/main/res/drawable-xhdpi/ic_drag_vertical_grey600_48dp.png
deleted file mode 100644
index 3fd70af80..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_drag_vertical_grey600_48dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_drag_vertical_white_48dp.9.png b/core/src/main/res/drawable-xhdpi/ic_drag_vertical_white_48dp.9.png
new file mode 100644
index 000000000..ae9972926
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_drag_vertical_white_48dp.9.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_drag_vertical_white_48dp.png b/core/src/main/res/drawable-xhdpi/ic_drag_vertical_white_48dp.png
deleted file mode 100644
index 38a3dc3f4..000000000
--- a/core/src/main/res/drawable-xhdpi/ic_drag_vertical_white_48dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_feed_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_feed_grey600_24dp.png
index b25d64863..995aafb5c 100755
--- a/core/src/main/res/drawable-xhdpi/ic_feed_grey600_24dp.png
+++ b/core/src/main/res/drawable-xhdpi/ic_feed_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_feed_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_feed_white_24dp.png
index 3c3e74c1d..1495c4fa6 100755
--- a/core/src/main/res/drawable-xhdpi/ic_feed_white_24dp.png
+++ b/core/src/main/res/drawable-xhdpi/ic_feed_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_indeterminate_check_box_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_indeterminate_check_box_grey600_24dp.png
new file mode 100644
index 000000000..e67d41cc1
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_indeterminate_check_box_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_indeterminate_check_box_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_indeterminate_check_box_white_24dp.png
new file mode 100644
index 000000000..48e52d596
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_indeterminate_check_box_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sd_storage_grey600_36dp.png b/core/src/main/res/drawable-xhdpi/ic_sd_storage_grey600_36dp.png
new file mode 100644
index 000000000..48cc94622
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sd_storage_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sd_storage_white_36dp.png b/core/src/main/res/drawable-xhdpi/ic_sd_storage_white_36dp.png
new file mode 100644
index 000000000..b440536f6
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sd_storage_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-xhdpi/ic_skip_grey600_36dp.png
new file mode 100644
index 000000000..2e291dd19
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_skip_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-xhdpi/ic_skip_white_36dp.png
new file mode 100644
index 000000000..fa85f1899
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_skip_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sleep_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_sleep_grey600_24dp.png
new file mode 100644
index 000000000..ae0787a26
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sleep_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sleep_off_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_sleep_off_grey600_24dp.png
new file mode 100644
index 000000000..026224c5e
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sleep_off_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sleep_off_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_sleep_off_white_24dp.png
new file mode 100644
index 000000000..ef39d7279
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sleep_off_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sleep_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_sleep_white_24dp.png
new file mode 100644
index 000000000..07e156172
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sleep_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sort_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_sort_grey600_24dp.png
new file mode 100644
index 000000000..f2ef499ef
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sort_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sort_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_sort_white_24dp.png
new file mode 100644
index 000000000..68b0b7ad3
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sort_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_star_border_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_star_border_grey600_24dp.png
new file mode 100644
index 000000000..5160319b5
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_star_border_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_star_border_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_star_border_white_24dp.png
new file mode 100644
index 000000000..33f9727d3
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_star_border_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_star_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_star_grey600_24dp.png
new file mode 100644
index 000000000..7a09ebc33
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_star_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_star_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_star_white_24dp.png
new file mode 100644
index 000000000..288799f93
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_star_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/stat_notify_sync.png b/core/src/main/res/drawable-xhdpi/stat_notify_sync.png
new file mode 100644
index 000000000..ab02927fb
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/stat_notify_sync.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/stat_notify_sync_error.png b/core/src/main/res/drawable-xhdpi/stat_notify_sync_error.png
new file mode 100644
index 000000000..c1f483f71
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/stat_notify_sync_error.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_av_fast_forward_80dp.png b/core/src/main/res/drawable-xxhdpi/ic_av_fast_forward_80dp.png
new file mode 100755
index 000000000..f90617f45
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_av_fast_forward_80dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_av_rewind_80dp.png b/core/src/main/res/drawable-xxhdpi/ic_av_rewind_80dp.png
new file mode 100755
index 000000000..81709e0ae
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_av_rewind_80dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_check_box_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_check_box_grey600_24dp.png
new file mode 100644
index 000000000..5e52fa65e
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_check_box_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_check_box_outline_blank_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_check_box_outline_blank_grey600_24dp.png
new file mode 100644
index 000000000..9c8615618
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_check_box_outline_blank_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_check_box_outline_blank_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_check_box_outline_blank_white_24dp.png
new file mode 100644
index 000000000..565a755f3
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_check_box_outline_blank_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_check_box_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_check_box_white_24dp.png
new file mode 100644
index 000000000..7b1d9ea34
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_check_box_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_create_new_folder_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_create_new_folder_grey600_24dp.png
new file mode 100644
index 000000000..802fc6fa0
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_create_new_folder_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_create_new_folder_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_create_new_folder_white_24dp.png
new file mode 100644
index 000000000..91cbc73d1
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_create_new_folder_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_grey600_48dp.9.png b/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_grey600_48dp.9.png
new file mode 100644
index 000000000..88a800f24
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_grey600_48dp.9.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_grey600_48dp.png b/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_grey600_48dp.png
deleted file mode 100644
index 048b39f0e..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_grey600_48dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_white_48dp.9.png b/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_white_48dp.9.png
new file mode 100644
index 000000000..148891e6c
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_white_48dp.9.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_white_48dp.png b/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_white_48dp.png
deleted file mode 100644
index 1c79c9731..000000000
--- a/core/src/main/res/drawable-xxhdpi/ic_drag_vertical_white_48dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_feed_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_feed_grey600_24dp.png
index aacf24d28..ddfe32b53 100755
--- a/core/src/main/res/drawable-xxhdpi/ic_feed_grey600_24dp.png
+++ b/core/src/main/res/drawable-xxhdpi/ic_feed_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_feed_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_feed_white_24dp.png
index 625dbaa1f..4929a6a11 100755
--- a/core/src/main/res/drawable-xxhdpi/ic_feed_white_24dp.png
+++ b/core/src/main/res/drawable-xxhdpi/ic_feed_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_indeterminate_check_box_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_indeterminate_check_box_grey600_24dp.png
new file mode 100644
index 000000000..c2300b53b
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_indeterminate_check_box_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_indeterminate_check_box_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_indeterminate_check_box_white_24dp.png
new file mode 100644
index 000000000..66a710d8c
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_indeterminate_check_box_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sd_storage_grey600_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_sd_storage_grey600_36dp.png
new file mode 100644
index 000000000..4352dbc06
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sd_storage_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sd_storage_white_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_sd_storage_white_36dp.png
new file mode 100644
index 000000000..5e18ed274
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sd_storage_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_skip_grey600_36dp.png
new file mode 100644
index 000000000..00a55a0f8
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_skip_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_skip_white_36dp.png
new file mode 100644
index 000000000..ac38e6d42
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_skip_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sleep_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_sleep_grey600_24dp.png
new file mode 100644
index 000000000..f4bd9e94d
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sleep_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sleep_off_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_sleep_off_grey600_24dp.png
new file mode 100644
index 000000000..6c42d6051
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sleep_off_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sleep_off_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_sleep_off_white_24dp.png
new file mode 100644
index 000000000..b8e06f9b3
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sleep_off_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sleep_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_sleep_white_24dp.png
new file mode 100644
index 000000000..e2249c357
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sleep_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sort_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_sort_grey600_24dp.png
new file mode 100644
index 000000000..6cdc649ea
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sort_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sort_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_sort_white_24dp.png
new file mode 100644
index 000000000..56ea13fe2
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sort_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_star_border_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_star_border_grey600_24dp.png
new file mode 100644
index 000000000..6348e1997
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_star_border_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_star_border_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_star_border_white_24dp.png
new file mode 100644
index 000000000..aab4831ff
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_star_border_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_star_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_star_grey600_24dp.png
new file mode 100644
index 000000000..ef0294931
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_star_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_star_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_star_white_24dp.png
new file mode 100644
index 000000000..de4b7b29d
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_star_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/stat_notify_sync.png b/core/src/main/res/drawable-xxhdpi/stat_notify_sync.png
new file mode 100644
index 000000000..9cd2a53b4
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/stat_notify_sync.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/stat_notify_sync_error.png b/core/src/main/res/drawable-xxhdpi/stat_notify_sync_error.png
new file mode 100644
index 000000000..bb76c2756
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/stat_notify_sync_error.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_av_fast_forward_80dp.png b/core/src/main/res/drawable-xxxhdpi/ic_av_fast_forward_80dp.png
new file mode 100755
index 000000000..c9b68abf0
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_av_fast_forward_80dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_av_rewind_80dp.png b/core/src/main/res/drawable-xxxhdpi/ic_av_rewind_80dp.png
new file mode 100755
index 000000000..87b0756eb
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_av_rewind_80dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_create_new_folder_grey600_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_create_new_folder_grey600_24dp.png
new file mode 100644
index 000000000..baf7b6ef7
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_create_new_folder_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_create_new_folder_white_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_create_new_folder_white_24dp.png
new file mode 100644
index 000000000..aa103bfd0
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_create_new_folder_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_drag_vertical_grey600_48dp.png b/core/src/main/res/drawable-xxxhdpi/ic_drag_vertical_grey600_48dp.png
deleted file mode 100644
index 4819da3c1..000000000
--- a/core/src/main/res/drawable-xxxhdpi/ic_drag_vertical_grey600_48dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_drag_vertical_white_48dp.png b/core/src/main/res/drawable-xxxhdpi/ic_drag_vertical_white_48dp.png
deleted file mode 100644
index b5820d4fe..000000000
--- a/core/src/main/res/drawable-xxxhdpi/ic_drag_vertical_white_48dp.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_sd_storage_grey600_36dp.png b/core/src/main/res/drawable-xxxhdpi/ic_sd_storage_grey600_36dp.png
new file mode 100644
index 000000000..cf03bc3f1
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_sd_storage_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_sd_storage_white_36dp.png b/core/src/main/res/drawable-xxxhdpi/ic_sd_storage_white_36dp.png
new file mode 100644
index 000000000..2996619c9
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_sd_storage_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-xxxhdpi/ic_skip_grey600_36dp.png
new file mode 100644
index 000000000..94836e0c8
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_skip_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-xxxhdpi/ic_skip_white_36dp.png
new file mode 100644
index 000000000..a84f34228
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_skip_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_sleep_grey600_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_sleep_grey600_24dp.png
new file mode 100644
index 000000000..9c0116c60
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_sleep_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_grey600_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_grey600_24dp.png
new file mode 100644
index 000000000..e8141d0df
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_white_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_white_24dp.png
new file mode 100644
index 000000000..ca41ad5e6
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_sleep_white_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_sleep_white_24dp.png
new file mode 100644
index 000000000..29782e155
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_sleep_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_star_border_grey600_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_star_border_grey600_24dp.png
new file mode 100644
index 000000000..1109e95c8
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_star_border_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_star_border_white_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_star_border_white_24dp.png
new file mode 100644
index 000000000..086cb677c
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_star_border_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_star_grey600_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_star_grey600_24dp.png
new file mode 100644
index 000000000..dda3262ed
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_star_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.png
new file mode 100644
index 000000000..ba29292b0
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable/progress_bar_horizontal_dark.xml b/core/src/main/res/drawable/progress_bar_horizontal_dark.xml
new file mode 100644
index 000000000..73ad5b37c
--- /dev/null
+++ b/core/src/main/res/drawable/progress_bar_horizontal_dark.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@android:id/background">
+ <shape>
+ <solid android:color="#33FFFFFF"/>
+ </shape>
+ </item>
+ <item android:id="@android:id/progress">
+ <clip>
+ <shape>
+ <solid android:color="@color/holo_blue_dark"/>
+ </shape>
+ </clip>
+ </item>
+</layer-list>
diff --git a/core/src/main/res/drawable/progress_bar_horizontal_light.xml b/core/src/main/res/drawable/progress_bar_horizontal_light.xml
new file mode 100644
index 000000000..a1a7129e9
--- /dev/null
+++ b/core/src/main/res/drawable/progress_bar_horizontal_light.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@android:id/background">
+ <shape>
+ <solid android:color="#33212121"/>
+ </shape>
+ </item>
+ <item android:id="@android:id/progress">
+ <clip>
+ <shape>
+ <solid android:color="@color/holo_blue_light"/>
+ </shape>
+ </clip>
+ </item>
+</layer-list>
diff --git a/core/src/main/res/values-az/strings.xml b/core/src/main/res/values-az/strings.xml
index a2fbdd825..d305e8127 100644
--- a/core/src/main/res/values-az/strings.xml
+++ b/core/src/main/res/values-az/strings.xml
@@ -37,7 +37,6 @@
<string name="length_prefix">Müddət:\u0020</string>
<string name="size_prefix">Ölçü:\u0020</string>
<string name="processing_label">Hazırlaşma</string>
- <string name="loading_label">Yükləmə...</string>
<string name="close_label">Bağla</string>
<!--'Add Feed' Activity labels-->
<string name="feedurl_label">Kanalın URLı</string>
@@ -79,7 +78,6 @@
<string name="download_error_malformed_url">Yanlış URL</string>
<string name="download_error_io_error">IO xətasi</string>
<string name="download_error_request_error">Tələbin xətası</string>
- <string name="downloads_left">\u0020yükləmə galdı</string>
<string name="download_notification_title">Podkast məlumatların yüklənişi</string>
<string name="download_report_content">%1$d yükləmə uğurludur, %2$d uğursuzdur</string>
<string name="download_log_title_unknown">Naməlum başliğ</string>
@@ -177,7 +175,6 @@
<string name="select_all_label">Hamısını seç</string>
<string name="deselect_all_label">Seçimi ləğv et</string>
<string name="opml_export_label">OPML ixraçı</string>
- <string name="exporting_label">İxrac...</string>
<string name="export_error_label">İxracın xətası</string>
<string name="opml_export_success_sum">OPML fayl:\u0020 yazılıb</string>
<!--Sleep timer-->
@@ -202,10 +199,10 @@
<string name="folder_not_empty_dialog_msg">Seçilən qovluq boş deyil. Mediya yükləmələr və başka fayllar bu qovluqa yazılacaqlar. Necə olsa davam olsunmu?</string>
<string name="set_to_default_folder">Başlanğıc qovluqu seç</string>
<!--Online feed view-->
- <string name="downloading_label">Yükləmə...</string>
<!--Content descriptions for image buttons-->
<!--Feed information screen-->
<!--Progress information-->
<!--AntennaPodSP-->
<!--Rating dialog-->
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-ca/strings.xml b/core/src/main/res/values-ca/strings.xml
index 772742753..1821eeab7 100644
--- a/core/src/main/res/values-ca/strings.xml
+++ b/core/src/main/res/values-ca/strings.xml
@@ -22,6 +22,9 @@
<string name="playback_history_label">Historial de reproducció</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">Inici de sessió a gpodder.net</string>
+ <string name="free_space_label">%1$s lliures</string>
+ <string name="episode_cache_full_title">Caché d\'episodi completa</string>
+ <string name="episode_cache_full_message">S\'ha arribat al límit de la caché. Pots incrementar la capacitat de la caché a les Opcions</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Publicats recentment</string>
<string name="episode_filter_label">Mostra només els episodis nous</string>
@@ -66,7 +69,7 @@
<string name="length_prefix">Durada:\u0020</string>
<string name="size_prefix">Mida:\u0020</string>
<string name="processing_label">S\'està processant</string>
- <string name="loading_label">S\'està carregant...</string>
+ <string name="loading_label">Carregant...</string>
<string name="save_username_password_label">Desa nom d\'usuari i contrasenya</string>
<string name="close_label">Tanca</string>
<string name="retry_label">Reintenta</string>
@@ -78,7 +81,7 @@
<string name="feed_auto_download_global">Global</string>
<string name="feed_auto_download_always">Sempre</string>
<string name="feed_auto_download_never">Mai</string>
- <string name="send_label">Envia...</string>
+ <string name="send_label">Enviar...</string>
<string name="episode_cleanup_never">Mai</string>
<string name="episode_cleanup_queue_removal">Quan no està a la cua</string>
<string name="episode_cleanup_after_listening">Després d\'acabar</string>
@@ -101,7 +104,7 @@
<string name="mark_all_seen_label">Marca tot com a llegit</string>
<string name="show_info_label">Mostra informació</string>
<string name="remove_feed_label">Esborra podcast</string>
- <string name="share_label">Comparteix...</string>
+ <string name="share_label">Compartir...</string>
<string name="share_link_label">Comparteix l\'enllaç</string>
<string name="share_link_with_position_label">Comparteix enllaç amb posició</string>
<string name="share_feed_url_label">Comparteix adreça del canal</string>
@@ -136,7 +139,9 @@
<string name="added_to_queue_label">Afegit a la cua</string>
<string name="remove_from_queue_label">Suprimeix de la cua</string>
<string name="add_to_favorite_label">Afegit a Favorits</string>
+ <string name="added_to_favorites">Afegit a favorits</string>
<string name="remove_from_favorite_label">Suprimeix de Favorits</string>
+ <string name="removed_from_favorites">Tret de favorits</string>
<string name="visit_website_label">Visita el lloc web</string>
<string name="support_label">Comparteix amb Flattr</string>
<string name="enqueue_all_new">Posa-ho tot a la cua</string>
@@ -170,7 +175,10 @@
<string name="download_error_io_error">Error d\'E/S</string>
<string name="download_error_request_error">Error de petició</string>
<string name="download_error_db_access">Error d\'accés a la base de dades</string>
- <string name="downloads_left">\u0020Baixades pendents</string>
+ <plurals name="downloads_left">
+ <item quantity="one">%d baixada pendent</item>
+ <item quantity="other">%d baixades pendents</item>
+ </plurals>
<string name="downloads_processing">S\'estan processant les baixades</string>
<string name="download_notification_title">S\'estan baixant les dades del podcast</string>
<string name="download_report_content">%1$d baixades finalitzades, %2$d fallides</string>
@@ -202,6 +210,8 @@
<!--Queue operations-->
<string name="lock_queue">Bloqueja la cua</string>
<string name="unlock_queue">Desbloqueja la cua</string>
+ <string name="queue_locked">Cua bloquejada</string>
+ <string name="queue_unlocked">Cua no bloquejada</string>
<string name="clear_queue_label">Buida la cua</string>
<string name="undo">Desfés</string>
<string name="removed_from_queue">Ítem esborrat</string>
@@ -243,12 +253,13 @@
<!--Variable Speed-->
<string name="download_plugin_label">Baixa el connector</string>
<string name="no_playback_plugin_title">Connector no instal·lat</string>
- <string name="no_playback_plugin_or_sonic_msg">Perque la reproducció de velocitat variable funcioni, ha d\'instal lar el connector de tercers o activar el reproductor experimental Sonic [Android 4.1+].\n\nPrem \'Baixa el connector\' per baixar el connector gratuït de la Play Store.\n\nQualsevol problema que us trobeu amb l\'ús d\'aquest connector no són responsabilitat d\'AntennaPod i han de ser reportats al propietari del connector.</string>
+ <string name="no_playback_plugin_or_sonic_msg">Per a què funcioni la velocitat de reproducció variable, recomanem activar el Sonic Media Player integrat [Android 4.1+].\n\nPer una altra banda, pots baixar el plugin de tercers <i>Prestissimo</i> de la Play Store.\nQualsevol problema amb Prestissimo no és responsabilitat d\'AntennaPod i no haurà de ser reportat al seu propietari.</string>
<string name="set_playback_speed_label">Velocitats de reproducció</string>
<string name="enable_sonic">Activa Sonic</string>
<!--Empty list labels-->
<string name="no_items_label">No hi ha elements a la llista.</string>
<string name="no_feeds_label">No us heu subscrit a cap canal.</string>
+ <string name="no_chapters_label">Aquest episodi no té capítols</string>
<!--Preferences-->
<string name="other_pref">Altres</string>
<string name="about_pref">Quant a</string>
@@ -256,13 +267,19 @@
<string name="services_label">Serveis</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Neteja l\'episodi</string>
- <string name="pref_episode_cleanup_summary">Episodis que no estan a la cua i no són favorits haurien de ser escollits per eliminar-los si es requereix espai</string>
+ <string name="pref_episode_cleanup_summary">Episodis que no es troben a la cua i no són favorits haurien de ser candidats per ser esborrats si Auto Descàrrega necessita espai per nous episodis</string>
+ <string name="pref_pauseOnDisconnect_sum">Pausa la reproducció en desconnectar els auriculars o el bluetooth</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Continua la reproducció en connectar novament els auriculars</string>
+ <string name="pref_unpauseOnBluetoothReconnect_sum">Continua la reproducció en connectar novament el bluetooth</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Botó \'Endavant\' passa al següent</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Al prémer el botó de hardware \'Endavant\' passar al següent episodi en comptes d\'avançar a la reproducció</string>
<string name="pref_followQueue_sum">Salta al següent element de la cua en acabar la reproducció</string>
<string name="pref_auto_delete_sum">Suprimeix l\'episodi quan s\'acabi de reproduir</string>
<string name="pref_auto_delete_title">Esborrat automàtic</string>
<string name="pref_smart_mark_as_played_sum">Marca episodis com com reproduits, encara que quedi menys d\'una certa quantitat de segons de temps</string>
<string name="pref_smart_mark_as_played_title">Marcació intel·ligent com a reproduit</string>
+ <string name="pref_skip_keeps_episodes_sum">Mantenir episodis quan són passats de llarg</string>
+ <string name="pref_skip_keeps_episodes_title">Mantenir els episodis passats de llarg</string>
<string name="playback_pref">Reproducció</string>
<string name="network_pref">Xarxa</string>
<string name="pref_autoUpdateIntervallOrTime_title">Actualitza interval o horari del dia</string>
@@ -271,11 +288,14 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">Desactivar</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Establir interval</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Establir hora del dia</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">cada %1$s</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">als %1$s</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Només baixa fitxers a través d\'una xarxa sense fils</string>
<string name="pref_followQueue_title">Reproducció continuada</string>
<string name="pref_downloadMediaOnWifiOnly_title">Baixa a través de xarxes sense fils</string>
<string name="pref_pauseOnHeadsetDisconnect_title">Desconnexió d\'auriculars</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Connexió d\'auriculars</string>
+ <string name="pref_unpauseOnBluetoothReconnect_title">Connexió de bluetooth</string>
<string name="pref_mobileUpdate_title">Actualitzacions sobre xarxes mòbils</string>
<string name="pref_mobileUpdate_sum">Permet actualitzacions a través de xarxes mòbils.</string>
<string name="refreshing_label">S\'està actualitzant</string>
@@ -339,9 +359,13 @@
<string name="pref_smart_mark_as_played_disabled">Desactivar</string>
<string name="pref_image_cache_size_title">Mida de la memòria cau de les imatges</string>
<string name="pref_image_cache_size_sum">Mida de la memòria cau en el disc de les imatges.</string>
+ <string name="crash_report_title">Reportar tancament abrupte</string>
+ <string name="crash_report_sum">Enviar l\'últim report de tancament abrupte per e-mail</string>
+ <string name="send_email">Envia e-mail</string>
<string name="experimental_pref">Experimental</string>
<string name="pref_sonic_title">Reproductor multimèdia Sonic</string>
- <string name="pref_sonic_message">Utilitzeu la funció incorporada del reproductor multimèdia Sonic com a reemplaçament per Prestissimo</string>
+ <string name="pref_sonic_message">Fer servir el reproductor Sonic Media integrat en comptes del reproductor natiu d\'Android i Prestissimo</string>
+ <string name="pref_current_value">Valor actual: %1$s</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Activa la compartició automàtica per Flattr</string>
<string name="auto_flattr_after_percent">Comparteix per Flattr l\'episodi en haver-ne reproduït el %d per cent</string>
@@ -368,14 +392,15 @@
<string name="opml_import_error_dir_empty">El directori d\'importacions és buit.</string>
<string name="select_all_label">Selecciona-ho tot</string>
<string name="deselect_all_label">Deselecciona-ho tot</string>
- <string name="select_options_label">Sel·lecciona...</string>
+ <string name="select_options_label">Selecciona...</string>
<string name="choose_file_from_filesystem">Des de sistema d\'arxius local</string>
<string name="choose_file_from_external_application">Utilitza aplicació externa</string>
<string name="opml_export_label">Exportació OPML</string>
- <string name="exporting_label">S\'està exportant...</string>
+ <string name="exporting_label">Exportant...</string>
<string name="export_error_label">Error d\'exportació</string>
<string name="opml_export_success_title">S\'ha exportat l\'OPML correctament.</string>
<string name="opml_export_success_sum">El fitxer OPML s\'ha escrit a:\u0020</string>
+ <string name="opml_import_ask_read_permission">Per llegir arxius OPML és necessari accés a la memòria externa</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Defineix un temporitzador</string>
<string name="disable_sleeptimer_label">Desactiva el temporitzador</string>
@@ -433,11 +458,15 @@
<string name="selected_folder_label">Carpeta seleccionada:</string>
<string name="create_folder_label">Crea una carpeta</string>
<string name="choose_data_directory">Selecció de la carpeta de dades</string>
+ <string name="choose_data_directory_message">Selecciona l\'arrel del teu directori d\'informació. AntennaPod crearà els subdirectoris pertinents</string>
<string name="create_folder_msg">Voleu crear una nova carpeta amb el nom \"%1$s\"?</string>
<string name="create_folder_success">S\'ha creat la nova carpeta</string>
<string name="create_folder_error_no_write_access">No es pot escriure dins d\'aquesta carpeta</string>
<string name="create_folder_error_already_exists">La carpeta ja existeix</string>
<string name="create_folder_error">No s\'ha pogut crear la carpeta</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" no existeix</string>
+ <string name="folder_not_readable_error">\"%1$s\" no es pot llegir</string>
+ <string name="folder_not_writable_error">No es pot escriure a \"%1$s\"</string>
<string name="folder_not_empty_dialog_title">La carpeta no és buida</string>
<string name="folder_not_empty_dialog_msg">La carpeta que heu seleccionat no és buida. Les baixades i altres fitxers es copiaran directament a aquesta carpeta. Voleu continuar?</string>
<string name="set_to_default_folder">Selecciona la carpeta per defecte</string>
@@ -472,12 +501,20 @@
<!--Feed information screen-->
<string name="authentication_label">Autenticació</string>
<string name="authentication_descr">Canvieu el nom d\'usuari i contrasenya per a aquest podcast i els seus episodis.</string>
+ <string name="auto_download_settings_label">Opcions d\'Auto Descàrrega</string>
+ <string name="episode_filters_label">Filtre d\'episodis</string>
+ <string name="episode_filters_description">Llistat de termes usats per decidir si un episodi s\'ha d\'incloure o excloure en descarregar automàticament</string>
+ <string name="episode_filters_include">Incloure</string>
+ <string name="episode_filters_exclude">Excloure</string>
+ <string name="episode_filters_hint">Una paraula \n\"Diverses paraules\"</string>
+ <string name="keep_updated">Mantenir actualitzat</string>
<!--Progress information-->
<string name="progress_upgrading_database">Actualització de la base de dades</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">S\'estan important les subscripcions des de les apps de propòsit únic...</string>
<string name="search_itunes_label">Cerca a iTunes</string>
- <string name="select_label"><b>Seleccionar...</b></string>
+ <string name="select_label"><b>Selecciona...</b></string>
+ <string name="filter">Filtrar</string>
<string name="all_label">Tot</string>
<string name="selected_all_label">Selecciona tots els episodis</string>
<string name="none_label">Cap</string>
@@ -490,6 +527,10 @@
<string name="selected_downloaded_label">Selecciona episodis descarregats</string>
<string name="not_downloaded_label">No baixat</string>
<string name="selected_not_downloaded_label">Selecciona episodis sense descarregar</string>
+ <string name="queued_label">En cua</string>
+ <string name="selected_queued_label">Episodis en cua seleccionats</string>
+ <string name="not_queued_label">No a la cua</string>
+ <string name="selected_not_queued_label">Episodis seleccionats i no a la cua</string>
<string name="sort_title"><b>Ordena per...</b></string>
<string name="sort_title_a_z">Títol (A \u2192 Z)</string>
<string name="sort_title_z_a">Títol (Z \u2192 A)</string>
@@ -498,4 +539,18 @@
<string name="sort_duration_short_long">Duració (Curt \u2192 Llarg)</string>
<string name="sort_duration_long_short">Duration (Llarg \u2192 Curt)</string>
<!--Rating dialog-->
+ <string name="rating_title">T\'agrada AntennaPod?</string>
+ <string name="rating_message">Apreciaríem que et prenguessis un temps per valorar AntennaPod</string>
+ <string name="rating_never_label">Deixa\'m tranquil</string>
+ <string name="rating_later_label">Pregunta\'m més tard</string>
+ <string name="rating_now_label">I tant, fem-ho!</string>
+ <!--Audio controls-->
+ <string name="audio_controls">Controls d\'audio</string>
+ <string name="playback_speed">Velocitat de reproducció</string>
+ <string name="volume">Volum</string>
+ <string name="left_short">E</string>
+ <string name="right_short">D</string>
+ <string name="audio_effects">Efectes de so</string>
+ <string name="stereo_to_mono">Downmix: D\'estereo a mono</string>
+ <string name="sonic_only">Només Sonic</string>
</resources>
diff --git a/core/src/main/res/values-cs-rCZ/strings.xml b/core/src/main/res/values-cs-rCZ/strings.xml
index e220432b9..390fff60b 100644
--- a/core/src/main/res/values-cs-rCZ/strings.xml
+++ b/core/src/main/res/values-cs-rCZ/strings.xml
@@ -22,7 +22,9 @@
<string name="playback_history_label">Historie přehrávání</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">Login pro gpodder.net</string>
- <string name="free_space_label">%1$s volných</string>
+ <string name="free_space_label">%1$s volné</string>
+ <string name="episode_cache_full_title">Odkládací prostor pro epizody je plný</string>
+ <string name="episode_cache_full_message">Došlo k zaplnění limitu odkládacího prostoru pro epizody. Můžete navýšit vyhrazený prostor v Nastavení.</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Nedávno zveřejněné</string>
<string name="episode_filter_label">Zobrazit pouze nové epizody</string>
@@ -68,7 +70,7 @@
<string name="length_prefix">Délka:\u0020</string>
<string name="size_prefix">Velikost:\u0020</string>
<string name="processing_label">Zpracovávám</string>
- <string name="loading_label">Načítám...</string>
+ <string name="loading_label">Načítání</string>
<string name="save_username_password_label">Uložit uživatelské jméno a heslo</string>
<string name="close_label">Zavřít</string>
<string name="retry_label">Zkusit znovu</string>
@@ -80,7 +82,7 @@
<string name="feed_auto_download_global">Globální</string>
<string name="feed_auto_download_always">Vždy</string>
<string name="feed_auto_download_never">Nikdy</string>
- <string name="send_label">Odeslat...</string>
+ <string name="send_label">Odeslat</string>
<string name="episode_cleanup_never">Nikdy</string>
<string name="episode_cleanup_queue_removal">Pokud není ve frontě</string>
<string name="episode_cleanup_after_listening">Po dokončení</string>
@@ -104,7 +106,7 @@
<string name="mark_all_seen_label">Označit vše jako zobrazené</string>
<string name="show_info_label">Informace o zdroji</string>
<string name="remove_feed_label">Odstranit podcast</string>
- <string name="share_label">Sdílet...</string>
+ <string name="share_label">Sdílet</string>
<string name="share_link_label">Sdílet odkaz</string>
<string name="share_link_with_position_label">Sdílet odkaz s pozicí</string>
<string name="share_feed_url_label">Sdílet URL kanálu</string>
@@ -139,7 +141,9 @@
<string name="added_to_queue_label">Přidáno do fronty</string>
<string name="remove_from_queue_label">Odebrat z fronty</string>
<string name="add_to_favorite_label">Přidat k oblíbeným</string>
+ <string name="added_to_favorites">Přidáno k oblíbeným</string>
<string name="remove_from_favorite_label">Odebrat z obíbených</string>
+ <string name="removed_from_favorites">Odebráno z oblíbených</string>
<string name="visit_website_label">Navštívit stránku</string>
<string name="support_label">Flattrovat</string>
<string name="enqueue_all_new">Vše do fronty</string>
@@ -173,7 +177,11 @@
<string name="download_error_io_error">IO chyba</string>
<string name="download_error_request_error">Chyba požadavku</string>
<string name="download_error_db_access">Chyba přístupu do databáze</string>
- <string name="downloads_left">\u0020Stahování zbývá</string>
+ <plurals name="downloads_left">
+ <item quantity="one">%d čekající na stažení</item>
+ <item quantity="few">%d čekající na stažení</item>
+ <item quantity="other">%d čekajících na stažení</item>
+ </plurals>
<string name="downloads_processing">Probíhá stahování</string>
<string name="download_notification_title">Stahuji podcast data</string>
<string name="download_report_content">%1$d úspěšných stahování, %2$d selhalo</string>
@@ -205,6 +213,8 @@
<!--Queue operations-->
<string name="lock_queue">Zamknout frontu</string>
<string name="unlock_queue">Odemknout frontu</string>
+ <string name="queue_locked">Fronta zamknuta</string>
+ <string name="queue_unlocked">Fronta odemknuta</string>
<string name="clear_queue_label">Vyprázdnit frontu</string>
<string name="undo">Zpět</string>
<string name="removed_from_queue">Položka odebrána</string>
@@ -246,12 +256,13 @@
<!--Variable Speed-->
<string name="download_plugin_label">Stáhnout modul</string>
<string name="no_playback_plugin_title">Modul není nainstalován</string>
- <string name="no_playback_plugin_or_sonic_msg">Pro možnost měnit rychlost přehrávání musí být nainstalovaná knihovna třetí strany nebo povolen experimentální přehrávač Sonic [Android 4.1+].\n\nKlikněte na \"Stáhnout modul\" k jeho stažení z Obchodu Play.\n\nAntennaPod nenese žádnou odpovědnost za jakékoliv problémy způsobené tímto modulem. Chyby hlaste jeho vývojářům.</string>
+ <string name="no_playback_plugin_or_sonic_msg">Pro fungující proměnné rychlosti přehrávání doporučujeme povolit zabudovaný Sonic mediaplayer [Android 4.1+].\n\nAlternativně je možné z Obchodu Play stáhnout zásuvný modul třetí strany <i>Prestissimo</i>.\nAntennaPod nenese zodpovědnost za jakékoliv problémy s modulem Prestissimo a ty by měly být hlášeny jeho vývojářům.</string>
<string name="set_playback_speed_label">Rychlosti přehrávání</string>
<string name="enable_sonic">Povolit Sonic</string>
<!--Empty list labels-->
<string name="no_items_label">Žádné položky v seznamu.</string>
<string name="no_feeds_label">Zatím nebyly přidány žádné kanály.</string>
+ <string name="no_chapters_label">Tato epizoda nemá žádné kapitoly.</string>
<!--Preferences-->
<string name="other_pref">Ostatní</string>
<string name="about_pref">O aplikaci</string>
@@ -259,12 +270,12 @@
<string name="services_label">Služby</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Vyčistit epizody</string>
- <string name="pref_episode_cleanup_summary">Epizody které nejsou ve frontě a nejsou označeny jako oblíbené lze smazat pro uvolnění místa</string>
+ <string name="pref_episode_cleanup_summary">Epizody, které nejsou ve frontě a nejsou označeny za oblíbené by mělo být možné smazat, pokud bude funkce automatického stahování potřebovat místo pro nové epizody</string>
<string name="pref_pauseOnDisconnect_sum">Při odpojení sluchátek nebo bluetooth připojení pozastavit přehrávání.</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Pokračovat v přehrávání po připojení sluchátek</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Pokračovat v přehrávání po připojení bluetooth</string>
<string name="pref_hardwareForwardButtonSkips_title">Přeskočit tlačítkem vpřed</string>
- <string name="pref_hardwareForwardButtonSkips_sum">Po stlačení hardwarového tlačítka pro posun vpřed přeskočit na další skladbu</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Po stlačení hardwarového tlačítka pro posun vpřed místo přetočení vpřed přeskočit na další epizodu</string>
<string name="pref_followQueue_sum">Po přehrání položky z fronty přejít automaticky na další</string>
<string name="pref_auto_delete_sum">Smazat díl po jeho přehrání</string>
<string name="pref_auto_delete_title">Automatické mazání</string>
@@ -280,6 +291,8 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">Vypnout</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Nastavit interval</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Nastavit čas v průběhu dne</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">každých %1$s</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">v %1$s</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Stahovat soubory pouze pomocí WiFi</string>
<string name="pref_followQueue_title">Kontinuální přehrávání</string>
<string name="pref_downloadMediaOnWifiOnly_title">WiFi stahování</string>
@@ -354,7 +367,8 @@
<string name="send_email">Poslat email</string>
<string name="experimental_pref">Experimentální</string>
<string name="pref_sonic_title">Přehrávač médií Sonic</string>
- <string name="pref_sonic_message">Použít vestavěný přehrávač médií Sonic, jako náhradu za Prestissimo</string>
+ <string name="pref_sonic_message">Použít připojený sonic media player jako náhradu za výchozí přehrávač médií pro Android a Prestissimo</string>
+ <string name="pref_current_value">Aktuální hodnota: %1$s</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Povolit automatické flattrování</string>
<string name="auto_flattr_after_percent">Flattrovat díl jakmile bude odehráno %d procent</string>
@@ -381,14 +395,15 @@
<string name="opml_import_error_dir_empty">Adresář importu je prázdný.</string>
<string name="select_all_label">Označit vše</string>
<string name="deselect_all_label">Zrušit výběr</string>
- <string name="select_options_label">Vybrat ...</string>
+ <string name="select_options_label">Vybrat</string>
<string name="choose_file_from_filesystem">Z místního souborového systému</string>
<string name="choose_file_from_external_application">Použít externí aplikaci</string>
<string name="opml_export_label">OPML export</string>
- <string name="exporting_label">Exportuji...</string>
+ <string name="exporting_label">Export</string>
<string name="export_error_label">Chyba exportu</string>
<string name="opml_export_success_title">OPML export byl úspěšný.</string>
<string name="opml_export_success_sum">OPML soubor byl zapsán do:\u0020</string>
+ <string name="opml_import_ask_read_permission">Pro přečtení OPML souboru je vyžadován přístup k externímu úložišti</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Nastavit časovač vypnutí</string>
<string name="disable_sleeptimer_label">Deaktivovat časovač vypnutí</string>
@@ -450,6 +465,7 @@
<string name="create_folder_label">Vytvořit adresář</string>
<string name="choose_data_directory">Vybrat umístění dat</string>
<string name="choose_data_directory_message">Vyberte prosím váš výchozí datový adresář. AntennaPod vytvoří všechny potřebné podadresáře.</string>
+ <string name="choose_data_directory_permission_rationale">Ke změně datového adresáře je vyžadován přístup k externímu úložišti</string>
<string name="create_folder_msg">Vytvořit adresář \"%1$s\"?</string>
<string name="create_folder_success">Nový adresář vytvořen</string>
<string name="create_folder_error_no_write_access">Nelze zapisovat do adresáře</string>
@@ -469,7 +485,7 @@
<!--Online feed view-->
<string name="subscribe_label">Odebírat</string>
<string name="subscribed_label">Odebíráno</string>
- <string name="downloading_label">Stahuji...</string>
+ <string name="downloading_label">Stahování</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Zobrazit kapitoly</string>
<string name="show_shownotes_label">Zobrazit poznámky o pořadu</string>
@@ -492,12 +508,20 @@
<!--Feed information screen-->
<string name="authentication_label">Ověření</string>
<string name="authentication_descr">Změnit uživatelské jméno a heslo pro tento podcast a jeho epizody.</string>
+ <string name="auto_download_settings_label">Nastavení automatického stahování</string>
+ <string name="episode_filters_label">Filtr epizod</string>
+ <string name="episode_filters_description">Seznam pravidel použitých při rozhodování, jestli má být epizoda zahrnuta nebo vyřazena při automatickém stahování</string>
+ <string name="episode_filters_include">Zahrnout</string>
+ <string name="episode_filters_exclude">Vyřadit</string>
+ <string name="episode_filters_hint">Jednoslovné \n\"Víceslovné\"</string>
+ <string name="keep_updated">Udržovat aktuální</string>
<!--Progress information-->
<string name="progress_upgrading_database">Probíhá aktualizace databáze</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Importuji odběry z jednoúčelových aplikací...</string>
<string name="search_itunes_label">Prohledat iTunes</string>
- <string name="select_label"><b>Vybrat ...</b></string>
+ <string name="select_label"><b>Vybrat…</b></string>
+ <string name="filter">Filtr</string>
<string name="all_label">Vše</string>
<string name="selected_all_label">Vybrány všechny epizody</string>
<string name="none_label">Žádné</string>
@@ -510,7 +534,11 @@
<string name="selected_downloaded_label">Vybrány stažené epizody</string>
<string name="not_downloaded_label">Nestažené</string>
<string name="selected_not_downloaded_label">Vybrány nestažené epizody</string>
- <string name="sort_title"><b>Řadit podle ...</b></string>
+ <string name="queued_label">Ve frontě</string>
+ <string name="selected_queued_label">Vybrané epizody ve frontě</string>
+ <string name="not_queued_label">Mimo frontu</string>
+ <string name="selected_not_queued_label">Vybrané epizody mimo frontu</string>
+ <string name="sort_title"><b>Řadit dle</b></string>
<string name="sort_title_a_z">Názvu (A \u2192 Z)</string>
<string name="sort_title_z_a">Názvu (Z \u2192 A)</string>
<string name="sort_date_new_old">Data (Nové \u2192 Staré)</string>
@@ -523,4 +551,13 @@
<string name="rating_never_label">Neobtěžuj mě</string>
<string name="rating_later_label">Upozornit později</string>
<string name="rating_now_label">Jasně, s radostí!</string>
+ <!--Audio controls-->
+ <string name="audio_controls">Audio ovládání</string>
+ <string name="playback_speed">Rychlost přehrávání</string>
+ <string name="volume">Hlasitost</string>
+ <string name="left_short">L</string>
+ <string name="right_short">P</string>
+ <string name="audio_effects">Audio efekty</string>
+ <string name="stereo_to_mono">Downmix: Stereo na mono</string>
+ <string name="sonic_only">Pouze Sonic</string>
</resources>
diff --git a/core/src/main/res/values-da/strings.xml b/core/src/main/res/values-da/strings.xml
index 2c32ad5de..13f576bfe 100644
--- a/core/src/main/res/values-da/strings.xml
+++ b/core/src/main/res/values-da/strings.xml
@@ -52,7 +52,6 @@
<string name="length_prefix">Længde:\u0020</string>
<string name="size_prefix">Størrelse:\u0020</string>
<string name="processing_label">Behandler</string>
- <string name="loading_label">Indlæser...</string>
<string name="save_username_password_label">Gem brugernavn og kodeord</string>
<string name="close_label">Luk</string>
<string name="retry_label">Prøv igen</string>
@@ -112,7 +111,6 @@
<string name="download_error_io_error">IO fejl</string>
<string name="download_error_request_error">Anmode fejl</string>
<string name="download_error_db_access">Adgangsfejl i database</string>
- <string name="downloads_left">\u0020Downloads tilbage</string>
<string name="downloads_processing">Bearbejder downloads</string>
<string name="download_notification_title">Downloader podcast data</string>
<string name="download_report_content">%1$d downloads lykkedes, %2$d fejlet</string>
@@ -264,7 +262,6 @@
<string name="select_all_label">Vælg alt</string>
<string name="deselect_all_label">Fravælg alt</string>
<string name="opml_export_label">OPML eksport</string>
- <string name="exporting_label">Eksporterer...</string>
<string name="export_error_label">Eksport fejl</string>
<string name="opml_export_success_title">Opml eksport lykkedes.</string>
<string name="opml_export_success_sum">.opml filen var skrevet til:\u0020</string>
@@ -320,7 +317,6 @@
<!--Online feed view-->
<string name="subscribe_label">Abonner</string>
<string name="subscribed_label">Abonneret</string>
- <string name="downloading_label">Downloader...</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Vis kapitler</string>
<string name="show_shownotes_label">Vis shownoter</string>
@@ -347,4 +343,5 @@
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Importerer abonnementer fra single-purpose apps…</string>
<!--Rating dialog-->
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-de/strings.xml b/core/src/main/res/values-de/strings.xml
index 7cdd15146..bf7f1a435 100644
--- a/core/src/main/res/values-de/strings.xml
+++ b/core/src/main/res/values-de/strings.xml
@@ -16,13 +16,15 @@
<string name="add_new_feed_label">Podcast hinzufügen</string>
<string name="downloads_label">Downloads</string>
<string name="downloads_running_label">Aktiv</string>
- <string name="downloads_completed_label">Abgeschlossen</string>
+ <string name="downloads_completed_label">Beendet</string>
<string name="downloads_log_label">Log</string>
<string name="cancel_download_label">Download abbrechen</string>
<string name="playback_history_label">Zuletzt gespielt</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">gpodder.net Anmeldung</string>
<string name="free_space_label">%1$s frei</string>
+ <string name="episode_cache_full_title">Episodenspeicher voll</string>
+ <string name="episode_cache_full_message">Der Episodenspeicher ist voll. Du kannst die Größe des Episodenspeichers in den Einstellungen erhöhen.</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Zuletzt veröffentlicht</string>
<string name="episode_filter_label">Nur neue Episoden anzeigen</string>
@@ -67,7 +69,7 @@
<string name="length_prefix">Länge:\u0020</string>
<string name="size_prefix">Größe:\u0020</string>
<string name="processing_label">Verarbeite</string>
- <string name="loading_label">Lade ...</string>
+ <string name="loading_label">Wird geladen…</string>
<string name="save_username_password_label">Benutzername und Password merken</string>
<string name="close_label">Schließen</string>
<string name="retry_label">Erneut versuchen</string>
@@ -79,7 +81,7 @@
<string name="feed_auto_download_global">Global</string>
<string name="feed_auto_download_always">Immer</string>
<string name="feed_auto_download_never">Nie</string>
- <string name="send_label">Senden...</string>
+ <string name="send_label">Senden…</string>
<string name="episode_cleanup_never">Nie</string>
<string name="episode_cleanup_queue_removal">Wenn nicht in der Abspielliste</string>
<string name="episode_cleanup_after_listening">wenn fertig gespielt gespielt</string>
@@ -102,7 +104,7 @@
<string name="mark_all_seen_label">Alle als gesehen markieren</string>
<string name="show_info_label">Informationen anzeigen</string>
<string name="remove_feed_label">Podcast entfernen</string>
- <string name="share_label">Teile...</string>
+ <string name="share_label">Teilen…</string>
<string name="share_link_label">Webseiten-Link teilen</string>
<string name="share_link_with_position_label">Teile Link mit Zeitmarke</string>
<string name="share_feed_url_label">Teile URL des Podcasts</string>
@@ -137,7 +139,9 @@
<string name="added_to_queue_label">Zur Abspielliste hinzugefügt</string>
<string name="remove_from_queue_label">Aus der Abspielliste entfernen</string>
<string name="add_to_favorite_label">Zu Favoriten hinzufügen</string>
+ <string name="added_to_favorites">Zu Favoriten hinzugefügt</string>
<string name="remove_from_favorite_label">Aus Favoriten entfernen</string>
+ <string name="removed_from_favorites">Aus Favoriten entfernt</string>
<string name="visit_website_label">Webseite besuchen</string>
<string name="support_label">Flattrn</string>
<string name="enqueue_all_new">Alle zur Abspielliste hinzufügen</string>
@@ -171,7 +175,10 @@
<string name="download_error_io_error">E/A Error</string>
<string name="download_error_request_error">Anfragefehler</string>
<string name="download_error_db_access">Datenbankzugriffsfehler</string>
- <string name="downloads_left">\u0020Downloads übrig</string>
+ <plurals name="downloads_left">
+ <item quantity="one">%d Download übrig</item>
+ <item quantity="other">%d Downloads übrig</item>
+ </plurals>
<string name="downloads_processing">Verarbeite Downloads</string>
<string name="download_notification_title">Lade Podcast-Daten</string>
<string name="download_report_content">%1$d Downloads erfolgreich, %2$d fehlgeschlagen</string>
@@ -203,6 +210,8 @@
<!--Queue operations-->
<string name="lock_queue">Abspielliste sperren</string>
<string name="unlock_queue">Abspielliste entsperren</string>
+ <string name="queue_locked">Abspielliste gesperrt</string>
+ <string name="queue_unlocked">Abspielliste entsperrt</string>
<string name="clear_queue_label">Abspielliste leeren</string>
<string name="undo">Rückgängig</string>
<string name="removed_from_queue">Element entfernt</string>
@@ -244,20 +253,21 @@
<!--Variable Speed-->
<string name="download_plugin_label">Plugin herunterladen</string>
<string name="no_playback_plugin_title">Plugin nicht installiert</string>
- <string name="no_playback_plugin_or_sonic_msg">Damit die variable Wiedergabegeschwindigkeit funktioniert, musst du eine Drittanbieterbibliothek oder den experimentellen Sonic Player [Android 4.1+] heruntegeladen.\n\n Drücke \"Plugin herunterladen\", um ein kostenloses Plugin aus dem Play Store zu installieren.\n\nProbleme, die bei der Benutzung des Plugins auftreten, liegen nicht im Verantwortungsbereich von AntennaPod, und sollten dem Entwickler des Plugins gemeldet werden.</string>
+ <string name="no_playback_plugin_or_sonic_msg">Um variable Wiedergabegeschwindigkeit benutzen zu können, empfehlen wir, den integrierten Sonic Mediaplayer [Android 4.1+] zu aktivieren.\n\nAlternativ kannst du das kostenlose Plugin <i>Prestissimo</i> eines Drittanbieters aus dem Play Store herunterladen.\nProbleme mit Prestissimo liegen nicht im Verantwortungsbereich von AntennaPod und sollten dem Entwickler des Plugins gemeldet werden.</string>
<string name="set_playback_speed_label">Wiedergabegeschwindigkeiten</string>
<string name="enable_sonic">Sonic aktivieren</string>
<!--Empty list labels-->
<string name="no_items_label">Es sind keine Einträge in dieser Liste.</string>
<string name="no_feeds_label">Du hast noch keine Feeds abonniert.</string>
+ <string name="no_chapters_label">Diese Episode hat keine Kapitel.</string>
<!--Preferences-->
<string name="other_pref">Anderes</string>
<string name="about_pref">Über</string>
<string name="queue_label">Abspielliste</string>
<string name="services_label">Dienste</string>
<string name="flattr_label">Flattr</string>
- <string name="pref_episode_cleanup_title">Episodenaufräumer</string>
- <string name="pref_episode_cleanup_summary">Episoden, die nicht in der Abspielliste und nicht favorisiert sind, werden zum Aufräumen freigegeben, wenn Speicherplatz benötigt wird</string>
+ <string name="pref_episode_cleanup_title">Automatisches Löschen</string>
+ <string name="pref_episode_cleanup_summary">Episoden, die weder in Abspielliste noch favorisiert sind, können gelöscht werden, wenn beim automatischen Herunterladen Speicherplatz für neue Episoden gebraucht wird</string>
<string name="pref_pauseOnDisconnect_sum">Wiedergabe pausieren, wenn Kopfhörer ausgesteckt oder Bluetooth getrennt wird</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Wiedergabe fortsetzen, wenn Kopfhörer wieder eingesteckt werden</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Wiedergabe fortsetzen, wenn Bluetooth wieder verbunden ist</string>
@@ -278,6 +288,8 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">Deaktivieren</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Intervall einstellen</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Tageszeit festlegen</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">jede %1$s</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">um %1$s</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Lade Mediendateien nur über WiFi</string>
<string name="pref_followQueue_title">Durchgehendes Abspielen</string>
<string name="pref_downloadMediaOnWifiOnly_title">WiFi Medien-Download</string>
@@ -335,7 +347,7 @@
<string name="pref_gpodnet_sethostname_use_default_host">Standard-Host verwenden</string>
<string name="pref_expandNotify_title">Benachrichtigung erweitern</string>
<string name="pref_expandNotify_sum">Erweiterte Wiedergabebenachrichtigung mit Abspiel-, Pause- und Stop-Knöpfen anzeigen.</string>
- <string name="pref_persistNotify_title">Persistente Wiedergabesteurung</string>
+ <string name="pref_persistNotify_title">Persistente Wiedergabesteuerung</string>
<string name="pref_persistNotify_sum">Zeige Wiedergabebedienelemente in der Benachrichtigung und im Lockscreen an, während die Wiedergabe pausiert ist.</string>
<string name="pref_lockscreen_background_title">Lockscreen-Hintergrund einstellen</string>
<string name="pref_lockscreen_background_sum">Verwende das aktuelle Episodenbild als Lockscreen-Hintergrund. Es wird als Nebeneffekt auch in anderen Apps gezeigt.</string>
@@ -351,8 +363,9 @@
<string name="crash_report_sum">Sende den aktuellen Absturzbericht per E-Mail</string>
<string name="send_email">E-Mail senden</string>
<string name="experimental_pref">Experimentell</string>
- <string name="pref_sonic_title">Sonic Media Player</string>
- <string name="pref_sonic_message">Benutze den eingebauten Sonic Media Player als Ersatz für Prestissimo</string>
+ <string name="pref_sonic_title">Sonic Mediaplayer</string>
+ <string name="pref_sonic_message">Benutze den integrierten Sonic Mediaplayer als Ersatz für Androids eigenen Mediaplayer und Prestissimo</string>
+ <string name="pref_current_value">Aktueller Wert: %1$s</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Automatisches Flattrn aktivieren</string>
<string name="auto_flattr_after_percent">Flattr eine Episode, sobald %d Prozent gespielt worden sind</string>
@@ -379,14 +392,15 @@
<string name="opml_import_error_dir_empty">Der Import-Ordner ist leer.</string>
<string name="select_all_label">Alle auswählen</string>
<string name="deselect_all_label">Auswahl zurücksetzen</string>
- <string name="select_options_label">Wähle aus ...</string>
+ <string name="select_options_label">Auswählen…</string>
<string name="choose_file_from_filesystem">Vom lokalen Dateisystem</string>
<string name="choose_file_from_external_application">Verwende externe Anwendung</string>
<string name="opml_export_label">OPML Export</string>
- <string name="exporting_label">Exportiere...</string>
+ <string name="exporting_label">Exportiere…</string>
<string name="export_error_label">Exportfehler</string>
<string name="opml_export_success_title">OPML Export erfolgreich</string>
<string name="opml_export_success_sum">Die OPML Datei wurde unter dem folgenden Pfad gespeichert:\u0020</string>
+ <string name="opml_import_ask_read_permission">Zugriff auf externen Speicher wird benötigt, um die OPML Datei zu lesen</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Schlummerfunktion</string>
<string name="disable_sleeptimer_label">Schlummerfunktion deaktivieren</string>
@@ -445,6 +459,7 @@
<string name="create_folder_label">Neuer Ordner</string>
<string name="choose_data_directory">Datenordner auswählen</string>
<string name="choose_data_directory_message">Bitte wähle eine Basis für deinen Datenordner. AntennaPod erstellt automatisch die richtigen Unterverzeichnisse.</string>
+ <string name="choose_data_directory_permission_rationale">Zugriff auf den externen Speicher wird benötigt, um den Datenordner zu ändern</string>
<string name="create_folder_msg">Neuen Ordner mit Namen \"%1$s\" erstellen?</string>
<string name="create_folder_success">Neuer Ordner angelegt</string>
<string name="create_folder_error_no_write_access">Kann in diesem Ordner nicht schreiben</string>
@@ -464,7 +479,7 @@
<!--Online feed view-->
<string name="subscribe_label">Abonnieren</string>
<string name="subscribed_label">Abonniert</string>
- <string name="downloading_label">Lade herunter...</string>
+ <string name="downloading_label">Lade herunter…</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Kapitel anzeigen</string>
<string name="show_shownotes_label">Sendungsnotizen anzeigen</string>
@@ -487,12 +502,20 @@
<!--Feed information screen-->
<string name="authentication_label">Authentifizierung</string>
<string name="authentication_descr">Ändere den Benutzernamen und das Passwort für diesen Podcast und dessen Episoden.</string>
+ <string name="auto_download_settings_label">Einstellungen für Automatischen Download</string>
+ <string name="episode_filters_label">Episoden-Filter</string>
+ <string name="episode_filters_description">Liste von Wörtern, die dazu verwendet wird, Episoden beim automatischen Download einzubeziehen oder auszuschließen</string>
+ <string name="episode_filters_include">Einbeziehen</string>
+ <string name="episode_filters_exclude">Ausschließen</string>
+ <string name="episode_filters_hint">Einzelne Wörter\n\"Mehrere Wörter\"</string>
+ <string name="keep_updated">Aktuell halten</string>
<!--Progress information-->
<string name="progress_upgrading_database">Datenbank wird aktualisiert</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Importiere Abonnements aus Single-Purpose Apps</string>
<string name="search_itunes_label">iTunes durchsuchen</string>
- <string name="select_label"><b>Wähle aus ...</b></string>
+ <string name="select_label"><b>Wähle aus…</b></string>
+ <string name="filter">Filtern</string>
<string name="all_label">Alle</string>
<string name="selected_all_label">Alle Episoden ausgewählt</string>
<string name="none_label">Keine</string>
@@ -505,7 +528,11 @@
<string name="selected_downloaded_label">Heruntergeladene Episoden ausgewählt</string>
<string name="not_downloaded_label">Nicht heruntergeladen</string>
<string name="selected_not_downloaded_label">Nicht heruntergeladene Episoden ausgewählt</string>
- <string name="sort_title"><b>Sortieren nach ...</b></string>
+ <string name="queued_label">In Abspielliste</string>
+ <string name="selected_queued_label">Episoden in Abspielliste ausgewählt</string>
+ <string name="not_queued_label">Nicht in Abspielliste</string>
+ <string name="selected_not_queued_label">Episoden nicht in Abspielliste ausgewählt</string>
+ <string name="sort_title"><b>Sortiere nach…</b></string>
<string name="sort_title_a_z">Titel (A \u2192 Z)</string>
<string name="sort_title_z_a">Titel (Z \u2192 A)</string>
<string name="sort_date_new_old">Datum (neu \u2192 alt)</string>
@@ -513,9 +540,18 @@
<string name="sort_duration_short_long">Dauer (kurz \u2192 lang)</string>
<string name="sort_duration_long_short">Dauer (lang \u2192 kurz)</string>
<!--Rating dialog-->
- <string name="rating_title">Magst du AntennaPod?</string>
+ <string name="rating_title">Gefällt dir AntennaPod?</string>
<string name="rating_message">Wir würden uns freuen, wenn du dir kurz die Zeit nimmst, AntennaPod zu bewerten.</string>
<string name="rating_never_label">Lass mich in Ruhe</string>
<string name="rating_later_label">Erinnere mich später</string>
<string name="rating_now_label">Sicher, los geht\'s!</string>
+ <!--Audio controls-->
+ <string name="audio_controls">Audioregler</string>
+ <string name="playback_speed">Abspielgeschwindigkeit</string>
+ <string name="volume">Lautstärke</string>
+ <string name="left_short">L</string>
+ <string name="right_short">R</string>
+ <string name="audio_effects">Audioeffekte</string>
+ <string name="stereo_to_mono">Heruntermischen: Stereo zu Mono</string>
+ <string name="sonic_only">nur Sonic</string>
</resources>
diff --git a/core/src/main/res/values-es-rES/strings.xml b/core/src/main/res/values-es-rES/strings.xml
index 3cff046d0..7c851db62 100644
--- a/core/src/main/res/values-es-rES/strings.xml
+++ b/core/src/main/res/values-es-rES/strings.xml
@@ -3,43 +3,90 @@
<!--Activitiy and fragment titles-->
<string name="app_name">AntennaPod</string>
<string name="feeds_label">Canales</string>
+ <string name="add_feed_label">Añadir podcast</string>
<string name="podcasts_label">PODCASTS</string>
+ <string name="episodes_label">Episodios</string>
+ <string name="new_episodes_label">Nuevos episodios</string>
+ <string name="all_episodes_label">Todos los episodios</string>
+ <string name="all_episodes_short_label">Todos</string>
+ <string name="favorite_episodes_label">Favoritos</string>
<string name="new_label">Nuevos</string>
<string name="waiting_list_label">Lista de espera</string>
<string name="settings_label">Ajustes</string>
+ <string name="add_new_feed_label">Añadir podcast</string>
<string name="downloads_label">Descargas</string>
<string name="cancel_download_label">Cancelar descarga</string>
<string name="playback_history_label">Historial de reproducción</string>
+ <string name="gpodnet_main_label">gpodder.net</string>
+ <string name="gpodnet_auth_label">gpodder.net Login</string>
+ <string name="free_space_label">%1$s disponible</string>
<!--New episodes fragment-->
+ <string name="recently_published_episodes_label">Publicado recientemente</string>
+ <string name="episode_filter_label">Mostrar solo episodios nuevos</string>
<!--Main activity-->
+ <string name="drawer_open">Abrir menu</string>
+ <string name="drawer_close">Cerrar menu</string>
+ <string name="drawer_feed_order_unplayed_episodes">Ordenar por contador</string>
+ <string name="drawer_feed_order_alphabetical">Ordenar alfabéticamente</string>
+ <string name="drawer_feed_order_last_update">Ordenar por fecha de publicación</string>
+ <string name="drawer_feed_counter_new_unplayed">Numero de episodios nuevos y no escuchados</string>
+ <string name="drawer_feed_counter_new">Numero de nuevos episodios</string>
+ <string name="drawer_feed_counter_unplayed">Numero de episodios no escuchados</string>
+ <string name="drawer_feed_counter_none">Ningun</string>
<!--Webview actions-->
<string name="open_in_browser_label">Abrir en el navegador</string>
<string name="copy_url_label">Copiar URL</string>
<string name="share_url_label">Compartir URL</string>
<string name="copied_url_msg">URL copiada al portapapeles.</string>
+ <string name="go_to_position_label">Ir a esta posición</string>
<!--Playback history-->
<string name="clear_history_label">Limpiar el historial</string>
<!--Other-->
<string name="confirm_label">Confirmar</string>
<string name="cancel_label">Cancelar</string>
+ <string name="yes">Si</string>
+ <string name="no">No</string>
<string name="author_label">Autor</string>
<string name="language_label">Idioma</string>
+ <string name="url_label">URL</string>
<string name="error_label">Error</string>
<string name="error_msg_prefix">Ha ocurrido un error:</string>
<string name="refresh_label">Actualizar</string>
<string name="external_storage_error_msg">No se encuentra un almacenamiento externo. Asegúrese de que su almacenamiento externo esté montado para que la aplicación funcione correctamente.</string>
<string name="chapters_label">Capítulos</string>
<string name="shownotes_label">Notas del programa</string>
+ <string name="description_label">Descripción</string>
+ <string name="most_recent_prefix">Episodio mas recién:\u0020</string>
<string name="episodes_suffix">\u0020episodios</string>
<string name="length_prefix">Duración:\u0020</string>
<string name="size_prefix">Tamaño:\u0020</string>
<string name="processing_label">Procesando</string>
- <string name="loading_label">Cargando...</string>
+ <string name="save_username_password_label">Guardar nombre de usuario y contraseña</string>
+ <string name="close_label">Cerrar</string>
+ <string name="retry_label">Intentar de nuevo</string>
+ <string name="auto_download_label">Incluir en descargas automaticas</string>
+ <string name="auto_download_apply_to_items_title">Aplicar a los previos episodios</string>
+ <string name="feed_auto_download_global">Global</string>
+ <string name="feed_auto_download_always">Siempre</string>
+ <string name="feed_auto_download_never">Nunca</string>
+ <string name="episode_cleanup_never">Nunca</string>
+ <string name="episode_cleanup_queue_removal">Cuando no en la lista</string>
+ <string name="episode_cleanup_after_listening">Despues de terminar</string>
+ <plurals name="episode_cleanup_days_after_listening">
+ <item quantity="one">1 día después de terminar</item>
+ <item quantity="other">%d días después de terminar</item>
+ </plurals>
<!--'Add Feed' Activity labels-->
<string name="feedurl_label">URL del canal</string>
+ <string name="etxtFeedurlHint">www.example.com/feed</string>
+ <string name="txtvfeedurl_label">Añadir podcast por URL</string>
+ <string name="podcastdirectories_label">Buscar podcast en directorio</string>
+ <string name="browse_gpoddernet_label">Navegar gpodder.net</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Marcar todo como leído</string>
+ <string name="mark_all_seen_label">Marcar todos como visto</string>
<string name="show_info_label">Información del programa</string>
+ <string name="remove_feed_label">Eliminar podcast</string>
<string name="share_link_label">Compartir el enlace de la web</string>
<string name="feed_delete_confirmation_msg">Confirme que quiere eliminar este canal y TODOS los episodios descargados del mismo.</string>
<!--actions on feeditems-->
@@ -75,7 +122,6 @@
<string name="download_error_malformed_url">URL malformada</string>
<string name="download_error_io_error">Error de E/S</string>
<string name="download_error_request_error">Error de petición</string>
- <string name="downloads_left">\u0020descargas restantes</string>
<string name="download_notification_title">Descargando datos del podcast</string>
<string name="download_report_content">%1$d descargas exitosas, %2$d fallidas</string>
<string name="download_log_title_unknown">Título desconocido</string>
@@ -162,7 +208,6 @@
<string name="select_all_label">Seleccionar todo</string>
<string name="deselect_all_label">Deseleccionar todo</string>
<string name="opml_export_label">Exportar a OPML</string>
- <string name="exporting_label">Exportando...</string>
<string name="export_error_label">Error en la exportación</string>
<string name="opml_export_success_sum">El archivo OPML se ha escrito en:\u0020</string>
<!--Sleep timer-->
@@ -187,8 +232,12 @@
<string name="set_to_default_folder">Elegir carpeta predeterminada</string>
<!--Online feed view-->
<!--Content descriptions for image buttons-->
+ <string name="new_episodes_count_label">Numero de nuevos episodios</string>
<!--Feed information screen-->
<!--Progress information-->
<!--AntennaPodSP-->
+ <string name="all_label">Todos</string>
+ <string name="none_label">Ningun</string>
<!--Rating dialog-->
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-es/strings.xml b/core/src/main/res/values-es/strings.xml
index 0bed13e34..bee1d5903 100644
--- a/core/src/main/res/values-es/strings.xml
+++ b/core/src/main/res/values-es/strings.xml
@@ -18,10 +18,13 @@
<string name="downloads_running_label">En curso</string>
<string name="downloads_completed_label">Completadas</string>
<string name="downloads_log_label">Registro</string>
- <string name="cancel_download_label">Cancelar descarga</string>
+ <string name="cancel_download_label">Cancelar\ndescarga</string>
<string name="playback_history_label">Historial de reproducciones</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">Iniciar sesión en gpodder.net</string>
+ <string name="free_space_label">%1$s libre</string>
+ <string name="episode_cache_full_title">Caché de episodios completa</string>
+ <string name="episode_cache_full_message">Se ha alcanzado el límite de caché de episodios. Puedes aumentar el tamaño de la caché en las Opciones.</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Publicados recientemente</string>
<string name="episode_filter_label">Mostrar solo episodios nuevos</string>
@@ -40,7 +43,7 @@
<string name="open_in_browser_label">Abrir en el navegador</string>
<string name="copy_url_label">Copiar URL</string>
<string name="share_url_label">Compartir URL</string>
- <string name="copied_url_msg">URL copiada en el portapapeles.</string>
+ <string name="copied_url_msg">URL copiado en el portapapeles</string>
<string name="go_to_position_label">Ir a esta posición</string>
<!--Playback history-->
<string name="clear_history_label">Vaciar el historial</string>
@@ -66,19 +69,19 @@
<string name="length_prefix">Duración:\u0020</string>
<string name="size_prefix">Tamaño:\u0020</string>
<string name="processing_label">Procesando</string>
- <string name="loading_label">Cargando...</string>
+ <string name="loading_label">Cargando…</string>
<string name="save_username_password_label">Guardar usuario y contraseña</string>
<string name="close_label">Cerrar</string>
<string name="retry_label">Reintentar</string>
<string name="auto_download_label">Incluir en descargas automáticas</string>
<string name="auto_download_apply_to_items_title">Aplicar a episodios anteriores</string>
<string name="auto_download_apply_to_items_message">La nueva opción <i>Auto Descarga</i> se aplicará automáticamente a episodios nuevos.\n¿También desea aplicarlo a episodios anteriores?</string>
- <string name="auto_delete_label">Auto borrar episodio\n(Ignorando los ajustes globales)</string>
+ <string name="auto_delete_label">Eliminar episodio automáticamente\n(ignorar config. global)</string>
<string name="parallel_downloads_suffix">\u0020descargas paralelas</string>
<string name="feed_auto_download_global">Global</string>
<string name="feed_auto_download_always">Siempre</string>
<string name="feed_auto_download_never">Nunca</string>
- <string name="send_label">Enviar...</string>
+ <string name="send_label">Enviar…</string>
<string name="episode_cleanup_never">Nunca</string>
<string name="episode_cleanup_queue_removal">Cuando no esté en cola</string>
<string name="episode_cleanup_after_listening">Después de acabar</string>
@@ -88,7 +91,7 @@
</plurals>
<!--'Add Feed' Activity labels-->
<string name="feedurl_label">URL del canal</string>
- <string name="etxtFeedurlHint">URL del canal o del sitio web</string>
+ <string name="etxtFeedurlHint">www.ejemplo.com/feed</string>
<string name="txtvfeedurl_label">Añadir podcast por URL</string>
<string name="podcastdirectories_label">Buscar podcast en directorio</string>
<string name="podcastdirectories_descr">Es posible buscar podcasts nuevos por nombre, categoría o popularidad en el directorio de gpodder.net.</string>
@@ -96,12 +99,12 @@
<!--Actions on feeds-->
<string name="mark_all_read_label">Marcar todos como escuchado</string>
<string name="mark_all_read_msg">Se marcaron todos los episodios como escuchados</string>
- <string name="mark_all_read_confirmation_msg">Por favor, confirme que desea marcar todos los episodios como escuchados.</string>
- <string name="mark_all_read_feed_confirmation_msg">Por favor, confirme que desea marcar todos los episodios de este feed como escuchados.</string>
+ <string name="mark_all_read_confirmation_msg">Confirme que quiere marcar todos los episodios como escuchados.</string>
+ <string name="mark_all_read_feed_confirmation_msg">Confirme que quiere marcar todos los episodios de este canal como escuchados.</string>
<string name="mark_all_seen_label">Marcar todos como vistos</string>
<string name="show_info_label">Información del programa</string>
<string name="remove_feed_label">Eliminar podcast</string>
- <string name="share_label">Compartir...</string>
+ <string name="share_label">Compartir…</string>
<string name="share_link_label">Compartir el enlace de la web</string>
<string name="share_link_with_position_label">Compartir enlace con posición</string>
<string name="share_feed_url_label">Compartir URL del canal</string>
@@ -135,8 +138,10 @@
<string name="add_to_queue_label">Añadir a la cola</string>
<string name="added_to_queue_label">Añadido a la cola</string>
<string name="remove_from_queue_label">Quitar de la cola</string>
- <string name="add_to_favorite_label">Agregar a Favoritos</string>
+ <string name="add_to_favorite_label">Añadir a Favoritos</string>
+ <string name="added_to_favorites">Añadido a Favoritos</string>
<string name="remove_from_favorite_label">Eliminar de Favoritos</string>
+ <string name="removed_from_favorites">Quitado de Favoritos</string>
<string name="visit_website_label">Visitar el sitio web</string>
<string name="support_label">Añadir a Flattr</string>
<string name="enqueue_all_new">Ponerlos todos en cola</string>
@@ -163,14 +168,17 @@
<string name="download_error_unauthorized">Error de autenticación</string>
<string name="cancel_all_downloads_label">Cancelar todas las descargas</string>
<string name="download_canceled_msg">Descarga cancelada</string>
- <string name="download_canceled_autodownload_enabled_msg">Cancelada descarga\nDeshabilitada <i>Descarga Automática</i> para este ítem</string>
+ <string name="download_canceled_autodownload_enabled_msg">Descarga cancelada\nSe desactivó <i>Descarga automática</i> en este elemento</string>
<string name="download_report_title">Descargas completadas con error(es)</string>
<string name="download_report_content_title">Informe de descarga</string>
<string name="download_error_malformed_url">URL con formato incorrecto</string>
<string name="download_error_io_error">Error de E/S</string>
<string name="download_error_request_error">Error de solicitud</string>
<string name="download_error_db_access">Error de acceso a la base de datos</string>
- <string name="downloads_left">\u0020descargas restantes</string>
+ <plurals name="downloads_left">
+ <item quantity="one">Queda %d descarga</item>
+ <item quantity="other">Quedan %d descargas</item>
+ </plurals>
<string name="downloads_processing">Procesando descargas</string>
<string name="download_notification_title">Descargando datos del podcast</string>
<string name="download_report_content">%1$d descargas exitosas, %2$d fallidas</string>
@@ -182,10 +190,10 @@
<string name="authentication_notification_title">Se necesita autenticación</string>
<string name="authentication_notification_msg">Para acceder al recurso solicitado debe proporcionar un usuario y contraseña</string>
<string name="confirm_mobile_download_dialog_title">Confirmar descarga por red móvil</string>
- <string name="confirm_mobile_download_dialog_message_not_in_queue">Las descargas sobre la red móvil están deshabilitadas en ajustes.\n\nHabilitar temporalmente o sólo agregar a la cola?\n\n<small>Esta elección será recordada por 10 minutos.</small></string>
- <string name="confirm_mobile_download_dialog_message">Las descargas sobre la red móvil están deshabilitadas en ajustes.\n\nHabilitar temporalmente?\n\n<small>Esta elección será recordada por 10 minutos.</small></string>
- <string name="confirm_mobile_download_dialog_only_add_to_queue">Sólo agregar a la cola</string>
- <string name="confirm_mobile_download_dialog_enable_temporarily">Habilitar temporalmente</string>
+ <string name="confirm_mobile_download_dialog_message_not_in_queue">Se desactivaron las descargas por red de datos móviles en la configuración.\n\nPuede elegir entre añadir el episodio a la cola o permitir las descargas temporalmente.\n\n<small>Se recordará la elección por 10 minutos.</small></string>
+ <string name="confirm_mobile_download_dialog_message">Se desactivaron las descargas por red de datos móviles en la configuración.\n\n¿Quiere permitir las descargas temporalmente?\n\n<small>Se recordará la elección por 10 minutos.</small></string>
+ <string name="confirm_mobile_download_dialog_only_add_to_queue">Añadir a la cola</string>
+ <string name="confirm_mobile_download_dialog_enable_temporarily">Permitir temporalmente</string>
<!--Mediaplayer messages-->
<string name="player_error_msg">Error</string>
<string name="player_stopped_msg">No hay medios en reproducción</string>
@@ -202,9 +210,11 @@
<!--Queue operations-->
<string name="lock_queue">Bloquear cola</string>
<string name="unlock_queue">Desbloquear cola</string>
+ <string name="queue_locked">Cola bloqueada</string>
+ <string name="queue_unlocked">Cola desbloqueada</string>
<string name="clear_queue_label">Vaciar la cola</string>
<string name="undo">Deshacer</string>
- <string name="removed_from_queue">Artículo eliminado</string>
+ <string name="removed_from_queue">Se quitó el elemento</string>
<string name="move_to_top_label">Mover al principio</string>
<string name="move_to_bottom_label">Mover al final</string>
<string name="sort">Ordenar</string>
@@ -213,7 +223,7 @@
<string name="duration">Duración</string>
<string name="ascending">Ascendente</string>
<string name="descending">Descendente</string>
- <string name="clear_queue_confirmation_msg">Por favor, confirme que desea borrar TODOS los episodios de la cola</string>
+ <string name="clear_queue_confirmation_msg">Confirme que quiere borrar TODOS los episodios de la cola</string>
<!--Flattr-->
<string name="flattr_auth_label">Identificarse en Flattr</string>
<string name="flattr_auth_explanation">Pulse el botón inferior para comenzar la autenticación. Su navegador abrirá la pantalla de identificación de Flattr y le preguntará si quiere conceder permiso a AntennaPod para valorar cosas. Tras concederlo, volverá a esta pantalla automáticamente.</string>
@@ -221,7 +231,7 @@
<string name="return_home_label">Volver a la pantalla principal</string>
<string name="flattr_auth_success">Autentificación exitosa. Ya puede valorar cosas en Flattr desde la aplicación.</string>
<string name="no_flattr_token_title">No se ha encontrado un token de Flattr</string>
- <string name="no_flattr_token_notification_msg">Tu cuenta Flatter parece no estar conectada con AntennaPod. Pulsa aquí para autenticar.</string>
+ <string name="no_flattr_token_notification_msg">Parece que su cuenta de Flattr no está conectada con AntennaPod. Toque aquí para autenticarse.</string>
<string name="no_flattr_token_msg">Su cuenta de Flattr no está conectada con AntennaPod. Puede conectarla o puede visitar la página web de cada cosa para valorarla desde allí.</string>
<string name="authenticate_now_label">Autenticarse</string>
<string name="action_forbidden_title">Acción prohibida</string>
@@ -229,10 +239,10 @@
<string name="access_revoked_title">Acceso revocado</string>
<string name="access_revoked_info">Ha revocado el token de acceso de AntennaPod a su cuenta. Para completar el proceso debe eliminar esta aplicación de la lista de aplicaciones aprobadas, en los ajustes de Flattr.</string>
<!--Flattr-->
- <string name="flattr_click_success">¡Flattr una cosa!</string>
- <string name="flattr_click_success_count">¡Flattr %d cosas!</string>
+ <string name="flattr_click_success">Ha hecho Flattr en un elemento.</string>
+ <string name="flattr_click_success_count">Ha hecho Flattr en %d elementos.</string>
<string name="flattr_click_success_queue">Flattr: %s.</string>
- <string name="flattr_click_failure_count">¡Falló Flattr de %d cosas!</string>
+ <string name="flattr_click_failure_count">No se pudo hacer Flattr en %d elementos.</string>
<string name="flattr_click_failure">No se hizo Flattr: %s.</string>
<string name="flattr_click_enqueued">Se hará Flattr de esta cosa más tarde</string>
<string name="flattring_thing">Haciendo Flattr de %s</string>
@@ -243,12 +253,13 @@
<!--Variable Speed-->
<string name="download_plugin_label">Descargar complemento</string>
<string name="no_playback_plugin_title">Complemento no instalado</string>
- <string name="no_playback_plugin_or_sonic_msg">Para que funcione la reproducción a velocidad variable, es necesaria una librería de terceros o habilitar el reproductor experimental Sonic Player [Android 4.1+].\n\nPulsa «Descargar plugin» para descargar un plugin gratuito desde el Play Store\n\nCualquier problema relacionado con este plugin no es responsabilidad de AntennaPod y deberían ser reportados al autor del plugin.</string>
+ <string name="no_playback_plugin_or_sonic_msg">Para que funciona la velocidad de reproducción variable, recomendamos habilitar el reproductor Sonic Media [Android 4.1+].\n\nPor otro lado, puedes descargar el plugin de terceros <i>Prestissimo</i> de la Play Store.\nCualquier problema con Prestissimo no es reponsabilidad de AntennaPod y no debería ser reportado al propietario del plugin.</string>
<string name="set_playback_speed_label">Velocidades de reproducción</string>
- <string name="enable_sonic">Habilitar Sonic</string>
+ <string name="enable_sonic">Activar Sonic</string>
<!--Empty list labels-->
<string name="no_items_label">Esta lista no tiene elementos.</string>
<string name="no_feeds_label">No se ha suscrito a ningún canal.</string>
+ <string name="no_chapters_label">Este episodio no tiene capítulos.</string>
<!--Preferences-->
<string name="other_pref">Otros</string>
<string name="about_pref">Acerca de</string>
@@ -256,10 +267,12 @@
<string name="services_label">Servicios</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Limpieza de episodios</string>
- <string name="pref_episode_cleanup_summary">Los episodios que no están en la cola ni son favoritos serían candidatos a eliminarse si hace falta espacio</string>
+ <string name="pref_episode_cleanup_summary">Los episodios que no estén en la cola ni en Favoritos pueden eliminarse si Descarga automática necesita espacio para episodios nuevos</string>
<string name="pref_pauseOnDisconnect_sum">Pausar la reproducción al desconectar los auriculares o el bluetooth</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Reanudar reproducción cuando se reconecten los auriculares</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Reanudar reproducción cuando se reconecte el bluetooth</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Saltar episodio con botón</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Al pulsar el botón físico de avanzar se saltará al siguiente episodio en lugar de sólo avanzar</string>
<string name="pref_followQueue_sum">Saltar al siguiente elemento de la cola al acabar la reproducción</string>
<string name="pref_auto_delete_sum">Borrar episodio cuando finalice la reproducción</string>
<string name="pref_auto_delete_title">Eliminar automáticamente</string>
@@ -275,6 +288,8 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">Deshabilitar</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Ajustar intervalo</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Ajustar hora del día</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">todos los %1$s</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">a las %1$s</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Solo descargar los contenidos por WiFi</string>
<string name="pref_followQueue_title">Reproducción continua</string>
<string name="pref_downloadMediaOnWifiOnly_title">Descarga de contenidos por WiFi</string>
@@ -344,9 +359,13 @@
<string name="pref_smart_mark_as_played_disabled">Deshabilitado</string>
<string name="pref_image_cache_size_title">Tamaño de la caché de imágenes</string>
<string name="pref_image_cache_size_sum">Tamaño de la caché en disco para imágenes.</string>
+ <string name="crash_report_title">Informe de fallo</string>
+ <string name="crash_report_sum">Enviar el último informe de fallo por e-mail</string>
+ <string name="send_email">Enviar e-mail</string>
<string name="experimental_pref">Experimental</string>
<string name="pref_sonic_title">Sonic media player</string>
- <string name="pref_sonic_message">Usar sonic media player integrado como sustitución de Prestissimo</string>
+ <string name="pref_sonic_message">Usar el reproductor Sonic Media incorporado en lugar del reproductor multimedia de Android y Prestissimo</string>
+ <string name="pref_current_value">Valor actual: %1$s</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Habilitar Flattr automático</string>
<string name="auto_flattr_after_percent">Hacer Flattr del episodio en cuanto se haya reproducido el %d por ciento</string>
@@ -373,14 +392,15 @@
<string name="opml_import_error_dir_empty">El directorio de importación está vacío.</string>
<string name="select_all_label">Seleccionar todo</string>
<string name="deselect_all_label">Deseleccionar todo</string>
- <string name="select_options_label">Seleccionar...</string>
+ <string name="select_options_label">Seleccionar…</string>
<string name="choose_file_from_filesystem">Desde el sistema de ficheros local</string>
<string name="choose_file_from_external_application">Usar aplicación externa</string>
<string name="opml_export_label">Exportar a OPML</string>
- <string name="exporting_label">Exportando...</string>
+ <string name="exporting_label">Exportando…</string>
<string name="export_error_label">Error en la exportación</string>
<string name="opml_export_success_title">Exportación a OPML exitosa</string>
<string name="opml_export_success_sum">El archivo OPML se ha escrito en:\u0020</string>
+ <string name="opml_import_ask_read_permission">Es necesario el acceso al almacenamiento externo para leer archivos OPML</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Establecer un temporizador</string>
<string name="disable_sleeptimer_label">Desactivar el temporizador</string>
@@ -438,11 +458,16 @@
<string name="selected_folder_label">Carpeta seleccionada</string>
<string name="create_folder_label">Crear carpeta</string>
<string name="choose_data_directory">Elegir carpeta de datos</string>
+ <string name="choose_data_directory_message">Por favor elige la raíz de la carpeta de datos. AntennaPod creará los subdirectorios apropiados.</string>
+ <string name="choose_data_directory_permission_rationale">Se necesita acceso a almacenamiento externo para cambiar la carpeta de datos</string>
<string name="create_folder_msg">¿Crear carpeta con nombre «%1$s»?</string>
<string name="create_folder_success">Carpeta creada</string>
<string name="create_folder_error_no_write_access">No se puede escribir a esta carpeta</string>
<string name="create_folder_error_already_exists">Ya existe la carpeta</string>
<string name="create_folder_error">No se ha podido crear la carpeta</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" no existe</string>
+ <string name="folder_not_readable_error">\"%1$s\" no se puede leer</string>
+ <string name="folder_not_writable_error">\"%1$s\" no se puede modificar</string>
<string name="folder_not_empty_dialog_title">La carpeta no está vacía</string>
<string name="folder_not_empty_dialog_msg">La carpeta elegida no está vacía. Las descargas y otros archivos se copiarán directamente en esta carpeta. ¿Continuar igualmente?</string>
<string name="set_to_default_folder">Elegir carpeta predeterminada</string>
@@ -477,12 +502,20 @@
<!--Feed information screen-->
<string name="authentication_label">Autenticación</string>
<string name="authentication_descr">Cambiar nombre y contraseña de este podcast y sus episodios</string>
+ <string name="auto_download_settings_label">Opciones de Auto Descarga</string>
+ <string name="episode_filters_label">Filtro de Episodios</string>
+ <string name="episode_filters_description">Listado de términos para decidir si un episodio debe ser incluído o excluído al auto descargar</string>
+ <string name="episode_filters_include">Incluir</string>
+ <string name="episode_filters_exclude">Excluir</string>
+ <string name="episode_filters_hint">Palabras sueltas \n\"Múltiples palabras\"</string>
+ <string name="keep_updated">Mantener actualizado</string>
<!--Progress information-->
<string name="progress_upgrading_database">Actualizando la base de datos</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Importando subscripciones de aplicaciones de uso específico...</string>
<string name="search_itunes_label">Buscar en iTunes</string>
- <string name="select_label"><b>Seleccionar...</b></string>
+ <string name="select_label"><b>Seleccionar…</b></string>
+ <string name="filter">Filtro</string>
<string name="all_label">Todo</string>
<string name="selected_all_label">Seleccionados todos los episodios</string>
<string name="none_label">Ninguno</string>
@@ -495,7 +528,11 @@
<string name="selected_downloaded_label">Seleccionados episodios descargados</string>
<string name="not_downloaded_label">No descargado</string>
<string name="selected_not_downloaded_label">Seleccionados episodios no descargados</string>
- <string name="sort_title"><b>Ordenar por...</b></string>
+ <string name="queued_label">En cola</string>
+ <string name="selected_queued_label">Seleccionados episodios en cola</string>
+ <string name="not_queued_label">No en cola</string>
+ <string name="selected_not_queued_label">Seleccionados episodios no en cola</string>
+ <string name="sort_title"><b>Ordenar por…</b></string>
<string name="sort_title_a_z">Título (A \u2192 Z)</string>
<string name="sort_title_z_a">Título (Z \u2192 A)</string>
<string name="sort_date_new_old">Fecha (Nuevo \u2192 Antiguo)</string>
@@ -503,4 +540,18 @@
<string name="sort_duration_short_long">Duración (Corto \u2192 Largo)</string>
<string name="sort_duration_long_short">Duración (Largo \u2192 Corto)</string>
<!--Rating dialog-->
+ <string name="rating_title">¿Te gusta AntennaPod?</string>
+ <string name="rating_message">Estaríamos muy agradecidos si nos dedicas un tiempo para puntuar AntennaPod</string>
+ <string name="rating_never_label">Déjame en paz</string>
+ <string name="rating_later_label">Recuérdamelo después</string>
+ <string name="rating_now_label">¡Venga, hagámoslo!</string>
+ <!--Audio controls-->
+ <string name="audio_controls">Controles de audio</string>
+ <string name="playback_speed">Velocidad de reproducción</string>
+ <string name="volume">Volumen</string>
+ <string name="left_short">I</string>
+ <string name="right_short">D</string>
+ <string name="audio_effects">Efectos de audio</string>
+ <string name="stereo_to_mono">Downmix: De estereo a mono</string>
+ <string name="sonic_only">Sólo Sonic</string>
</resources>
diff --git a/core/src/main/res/values-fr/strings.xml b/core/src/main/res/values-fr/strings.xml
index bd3d1406f..239946097 100644
--- a/core/src/main/res/values-fr/strings.xml
+++ b/core/src/main/res/values-fr/strings.xml
@@ -22,7 +22,9 @@
<string name="playback_history_label">Journal des lectures</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">Identifiants gpodder.net</string>
- <string name="free_space_label">\"%1$s libre</string>
+ <string name="free_space_label">%1$s d\'espace libre</string>
+ <string name="episode_cache_full_title">L\'emplacement pour stocker les épisodes est plein</string>
+ <string name="episode_cache_full_message">Le volume maximum d\'épisode à stocker a été atteint. Vous pouvez augmenter la taille du cache dans les paramètres.</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Publié récemment</string>
<string name="episode_filter_label">N\'afficher que les nouveaux épisodes</string>
@@ -67,7 +69,7 @@
<string name="length_prefix">Durée :\u0020</string>
<string name="size_prefix">Taille :\u0020</string>
<string name="processing_label">Traitement en cours</string>
- <string name="loading_label">En chargement...</string>
+ <string name="loading_label">Chargement...</string>
<string name="save_username_password_label">Sauvegarder votre identifiant et votre mot de passe</string>
<string name="close_label">Fermer</string>
<string name="retry_label">Réessayer</string>
@@ -79,7 +81,7 @@
<string name="feed_auto_download_global">Global</string>
<string name="feed_auto_download_always">Toujours</string>
<string name="feed_auto_download_never">Jamais</string>
- <string name="send_label">Envoyer....</string>
+ <string name="send_label">Envoyer...</string>
<string name="episode_cleanup_never">Jamais</string>
<string name="episode_cleanup_queue_removal">Quand l’épisode n\'est pas dans la liste</string>
<string name="episode_cleanup_after_listening">Après avoir terminé</string>
@@ -121,7 +123,7 @@
<string name="hide_downloaded_episodes_label">Téléchargé</string>
<string name="hide_not_downloaded_episodes_label">Non téléchargé</string>
<string name="filtered_label">Filtré</string>
- <string name="refresh_failed_msg">{fa-exclamation-circle} La dernière mise à jour a échouée</string>
+ <string name="refresh_failed_msg">{fa-exclamation-circle} La dernière mise à jour a échoué</string>
<!--actions on feeditems-->
<string name="download_label">Télécharger</string>
<string name="play_label">Lire</string>
@@ -137,7 +139,9 @@
<string name="added_to_queue_label">Ajouté à la liste</string>
<string name="remove_from_queue_label">Supprimer de la liste</string>
<string name="add_to_favorite_label">Ajouter aux Favoris</string>
+ <string name="added_to_favorites">Ajouter aux Favoris</string>
<string name="remove_from_favorite_label">Supprimer des Favoris</string>
+ <string name="removed_from_favorites">Supprimer des Favoris</string>
<string name="visit_website_label">Visiter le site</string>
<string name="support_label">Flattr ça!</string>
<string name="enqueue_all_new">Ajouter tous à la liste</string>
@@ -171,7 +175,10 @@
<string name="download_error_io_error">Erreur d\'E/S</string>
<string name="download_error_request_error">Erreur de requête</string>
<string name="download_error_db_access">Problème d\'accès à la base de données</string>
- <string name="downloads_left">\u0020téléchargements restants</string>
+ <plurals name="downloads_left">
+ <item quantity="one">%d téléchargement restant</item>
+ <item quantity="other">%d téléchargements restants</item>
+ </plurals>
<string name="downloads_processing">Traitement des téléchargements</string>
<string name="download_notification_title">Téléchargement des données du podcast</string>
<string name="download_report_content">%1$d téléchargements réussis, %2$d échoués</string>
@@ -203,6 +210,8 @@
<!--Queue operations-->
<string name="lock_queue">Bloquer la liste</string>
<string name="unlock_queue">Débloquer la liste</string>
+ <string name="queue_locked">Liste de lecture verrouillée</string>
+ <string name="queue_unlocked">Liste de lecture déverrouillée</string>
<string name="clear_queue_label">Effacer la liste</string>
<string name="undo">Annuler</string>
<string name="removed_from_queue">Élément retiré</string>
@@ -244,12 +253,13 @@
<!--Variable Speed-->
<string name="download_plugin_label">Télécharger une extension</string>
<string name="no_playback_plugin_title">Extension non installée</string>
- <string name="no_playback_plugin_or_sonic_msg">Pour pouvoir changer la vitesse de lecture il est nécessaire d\'installer une librairie tierce ou d\'activer le lecteur expérimental Sonic [Android 4.1+].\n\nSélectionnez \"Télécharger une extension\" pour télécharger une extension gratuite depuis le Play Store.\n\nLes problème rencontrés avec cette extension ne sont pas de la responsabilité d\'AntennaPod. Veillez à notifier le créateur de l\'extension pour tout problème.</string>
+ <string name="no_playback_plugin_or_sonic_msg">Pour pouvoir changer la vitesse de lecture il est recommandé d\'activer le lecteur interne Sonic [Android 4.1+].\n\nSinon vous pouvez télécharger l\'extension <i>Prestissimo</i> depuis le Play Store.\nLes problème rencontrés avec Prestissimo ne sont pas de la responsabilité d\'AntennaPod et sont à communiquer au créateur de l\'extension.</string>
<string name="set_playback_speed_label">Vitesses de lecture</string>
<string name="enable_sonic">Activer Sonic</string>
<!--Empty list labels-->
<string name="no_items_label">Cette liste est vide.</string>
<string name="no_feeds_label">Vous n\'êtes encore abonné à aucun flux.</string>
+ <string name="no_chapters_label">Cet épisode n\'a pas de chapitres.</string>
<!--Preferences-->
<string name="other_pref">Autres</string>
<string name="about_pref">À propos</string>
@@ -257,12 +267,12 @@
<string name="services_label">Services</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Nettoyage des épisodes</string>
- <string name="pref_episode_cleanup_summary">Les épisodes qui ne sont ni dans la liste ni dans les favoris peuvent être supprimés si l\'espace disque devient faible</string>
+ <string name="pref_episode_cleanup_summary">Les épisodes qui ne sont pas dans la liste de lecture et qui ne sont pas marqués comme favoris peuvent être supprimés si l\'espace est insuffisant pour le téléchargement automatique de nouveaux épisodes</string>
<string name="pref_pauseOnDisconnect_sum">Interrompre la lecture lorsque le casque ou le bluetooth sont déconnectés</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Reprendre la lecture quand les écouteurs sont reconnectés</string>
- <string name="pref_unpauseOnBluetoothReconnect_sum">Reprendre la lecture quand le bluetooth se reconnecte</string>
+ <string name="pref_unpauseOnBluetoothReconnect_sum">Reprendre la lecture quand le Bluetooth se reconnecte</string>
<string name="pref_hardwareForwardButtonSkips_title">Le bouton piste suivante saute l\'épisode</string>
- <string name="pref_hardwareForwardButtonSkips_sum">Au lieu de faire un saut avant passer à l\'épisode suivant quand un bouton physique pour passer à la piste suivante est pressé</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Passer à l\'épisode suivant au lieu de faire un saut avant quand il est pressé un bouton physique pour avancer à la piste suivante</string>
<string name="pref_followQueue_sum">Après la fin d\'un épisode, passer au suivant</string>
<string name="pref_auto_delete_sum">Supprimer l\'épisode quand la lecture est finie</string>
<string name="pref_auto_delete_title">Suppression automatique</string>
@@ -278,12 +288,14 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">Désactiver</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Définir intervalle</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Régler l\'heure</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">toutes les %1$s</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">à %1$s</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Ne télécharger les épisodes que par Wi-Fi</string>
<string name="pref_followQueue_title">Lecture continue</string>
<string name="pref_downloadMediaOnWifiOnly_title">Téléchargement en Wi-Fi</string>
<string name="pref_pauseOnHeadsetDisconnect_title">Déconnexion du casque</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Reconnexion du casque</string>
- <string name="pref_unpauseOnBluetoothReconnect_title">Connection bluetooth</string>
+ <string name="pref_unpauseOnBluetoothReconnect_title">Reconnexion Bluetooth</string>
<string name="pref_mobileUpdate_title">Mises à jour mobile</string>
<string name="pref_mobileUpdate_sum">Autoriser les mises à jour à travers la connexion de données mobile</string>
<string name="refreshing_label">Mise à jour en cours</string>
@@ -352,7 +364,8 @@
<string name="send_email">Envoyer e-mail</string>
<string name="experimental_pref">Expérimental</string>
<string name="pref_sonic_title">Lecteur multimédia Sonic</string>
- <string name="pref_sonic_message">Utiliser le lecteur multimédia interne Sonic au lieu de Prestissimo</string>
+ <string name="pref_sonic_message">Utiliser le lecteur interne Sonic au lieu du lecteur natif d\'Android et de Prestissimo</string>
+ <string name="pref_current_value">Valeur actuelle : %1$s</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Activer le paiement flattr automatique</string>
<string name="auto_flattr_after_percent">Lancer un paiement flattr pour un épisode dès que %d de l\'épisode a été joué</string>
@@ -379,14 +392,15 @@
<string name="opml_import_error_dir_empty">Le répertoire d\'importation est vide.</string>
<string name="select_all_label">Tout choisir</string>
<string name="deselect_all_label">Ne rien choisir</string>
- <string name="select_options_label">Sélectionner...</string>
+ <string name="select_options_label">Choisir...</string>
<string name="choose_file_from_filesystem">Depuis le système de fichier local</string>
<string name="choose_file_from_external_application">Utiliser une application tierce</string>
<string name="opml_export_label">Exportation OPML</string>
- <string name="exporting_label">Exportation en cours...</string>
+ <string name="exporting_label">Export en cours...</string>
<string name="export_error_label">Erreur d\'exportation</string>
<string name="opml_export_success_title">Exportation OPML réussie.</string>
<string name="opml_export_success_sum">Le fichier .opml a été écrit ici :\u0020</string>
+ <string name="opml_import_ask_read_permission">L\'accès aux stockages externes est requis pour lire le fichier OPML</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Définir le minuteur d\'arrêt automatique</string>
<string name="disable_sleeptimer_label">Désactiver le minuteur d\'arrêt automatique</string>
@@ -464,7 +478,7 @@
<!--Online feed view-->
<string name="subscribe_label">S\'abonner</string>
<string name="subscribed_label">Abonné</string>
- <string name="downloading_label">Téléchargement en cours</string>
+ <string name="downloading_label">En cours de téléchargement...</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Afficher chapitres</string>
<string name="show_shownotes_label">Afficher notes d\'épisode</string>
@@ -487,12 +501,20 @@
<!--Feed information screen-->
<string name="authentication_label">Authentification</string>
<string name="authentication_descr">Modifier votre identifiant et mot de passe pour ce podcast et tous ses épisodes</string>
+ <string name="auto_download_settings_label">Préférence de téléchargement automatique</string>
+ <string name="episode_filters_label">Filtre d\'épisode</string>
+ <string name="episode_filters_description">Liste de mots décidant si un épisode est à inclure ou exclure des téléchargements automatiques</string>
+ <string name="episode_filters_include">Inclure</string>
+ <string name="episode_filters_exclude">Exclure</string>
+ <string name="episode_filters_hint">Mots uniques \n\"Liste de mots\"</string>
+ <string name="keep_updated">Mettre à jour</string>
<!--Progress information-->
<string name="progress_upgrading_database">Mise à jour de la base de données</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Importation des abonnements à partir d\'applications à usage unique...</string>
<string name="search_itunes_label">Chercher sur iTunes</string>
- <string name="select_label"><b>Sélectionner ...</b></string>
+ <string name="select_label"><b>Sélectionner…</b></string>
+ <string name="filter">Filtrer</string>
<string name="all_label">Tout</string>
<string name="selected_all_label">Tous les épisodes ont été sélectionné</string>
<string name="none_label">Aucun</string>
@@ -505,7 +527,11 @@
<string name="selected_downloaded_label">Episodes téléchargés sélectionnés</string>
<string name="not_downloaded_label">Non téléchargés</string>
<string name="selected_not_downloaded_label">Épisodes non téléchargés sélectionnés</string>
- <string name="sort_title"><b>Trier par ...</b></string>
+ <string name="queued_label">Dans liste de lecture</string>
+ <string name="selected_queued_label">Episodes présents dans la liste de lecture sélectionnés</string>
+ <string name="not_queued_label">Hors liste de lecture</string>
+ <string name="selected_not_queued_label">Episodes absents de la liste de lecture sélectionnés</string>
+ <string name="sort_title"><b>Trier par...</b></string>
<string name="sort_title_a_z">Titre (A \u2192 Z)</string>
<string name="sort_title_z_a">Titre (Z \u2192 A)</string>
<string name="sort_date_new_old">Date (Nouveau \u2192 Ancien)</string>
@@ -517,5 +543,14 @@
<string name="rating_message">Nous vous serions reconnaissant de prendre un peu de temps pour noter AntennaPod.</string>
<string name="rating_never_label">Laissez moi tranquille</string>
<string name="rating_later_label">Rappelez le moi plus tard</string>
- <string name="rating_now_label">Okay, faisons ça !</string>
+ <string name="rating_now_label">Okay, c\'est parti !</string>
+ <!--Audio controls-->
+ <string name="audio_controls">Contrôles audio</string>
+ <string name="playback_speed">Vitesse de lecture</string>
+ <string name="volume">Volume</string>
+ <string name="left_short">G</string>
+ <string name="right_short">D</string>
+ <string name="audio_effects">Effets audio</string>
+ <string name="stereo_to_mono">Mixage : stéréo à mono</string>
+ <string name="sonic_only">Sonic seulement</string>
</resources>
diff --git a/core/src/main/res/values-hi-rIN/strings.xml b/core/src/main/res/values-hi-rIN/strings.xml
index 9fa3d716f..87aa77caf 100644
--- a/core/src/main/res/values-hi-rIN/strings.xml
+++ b/core/src/main/res/values-hi-rIN/strings.xml
@@ -41,7 +41,6 @@
<string name="length_prefix">लंबाई:\u0020</string>
<string name="size_prefix">साइज:\u0020</string>
<string name="processing_label">प्रसंस्करण</string>
- <string name="loading_label">लोड हो रहा है ...</string>
<string name="save_username_password_label">यूज़रनेम और पासवर्ड सहेजें</string>
<string name="close_label">बंद करें</string>
<string name="retry_label">पुन: प्रयास</string>
@@ -95,7 +94,6 @@
<string name="download_error_io_error">आईओ त्रुटि</string>
<string name="download_error_request_error">अनुरोध त्रुटि</string>
<string name="download_error_db_access">डेटाबेस का उपयोग त्रुटि</string>
- <string name="downloads_left">\u0020Downloads छोड़ा</string>
<string name="download_notification_title">पॉडकास्ट डेटा डाउनलोड करें</string>
<string name="download_report_content">%1$d डाउनलोड सफल रहा, %2$d में विफल रहा है</string>
<string name="download_log_title_unknown">अज्ञात शीर्षक</string>
@@ -212,7 +210,6 @@
<string name="select_all_label">सभी का चयन करें</string>
<string name="deselect_all_label">सभी का चयन रद्द करें</string>
<string name="opml_export_label">OPML निर्यात</string>
- <string name="exporting_label">निर्यात ...</string>
<string name="export_error_label">निर्यात त्रुटि</string>
<string name="opml_export_success_sum">.ompl फ़ाइल लिखा गया था:\u0020</string>
<!--Sleep timer-->
@@ -266,10 +263,10 @@
<!--Online feed view-->
<string name="subscribe_label">सदस्यता लें</string>
<string name="subscribed_label">सदस्यता ली गई</string>
- <string name="downloading_label">डाउनलोड कर रहा है ...</string>
<!--Content descriptions for image buttons-->
<!--Feed information screen-->
<!--Progress information-->
<!--AntennaPodSP-->
<!--Rating dialog-->
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-it-rIT/strings.xml b/core/src/main/res/values-it-rIT/strings.xml
index adf4bd748..d7aff71cf 100644
--- a/core/src/main/res/values-it-rIT/strings.xml
+++ b/core/src/main/res/values-it-rIT/strings.xml
@@ -63,7 +63,6 @@
<string name="length_prefix">Durata:\u0020</string>
<string name="size_prefix">Dimensione:\u0020</string>
<string name="processing_label">Elaborazione in corso</string>
- <string name="loading_label">Caricamento in corso...</string>
<string name="save_username_password_label">Salva nome utente e password</string>
<string name="close_label">Chiudi</string>
<string name="retry_label">Riprova</string>
@@ -73,7 +72,6 @@
<string name="feed_auto_download_global">Globale</string>
<string name="feed_auto_download_always">Sempre</string>
<string name="feed_auto_download_never">Mai</string>
- <string name="send_label">Invia...</string>
<string name="episode_cleanup_never">Mai</string>
<plurals name="episode_cleanup_days_after_listening">
<item quantity="one">1 giorno dopo il completamento</item>
@@ -92,7 +90,6 @@
<string name="mark_all_seen_label">Segna tutti come visti</string>
<string name="show_info_label">Informazioni</string>
<string name="remove_feed_label">Rimuovi un podcast</string>
- <string name="share_label">Condividi...</string>
<string name="share_link_label">Condividi il link al sito</string>
<string name="share_link_with_position_label">Condividi il Link con la Posizione</string>
<string name="share_feed_url_label">Condividi URL del Feed</string>
@@ -159,7 +156,6 @@
<string name="download_error_io_error">Errore IO</string>
<string name="download_error_request_error">Errore della richiesta</string>
<string name="download_error_db_access">Errore di accesso al database</string>
- <string name="downloads_left">\u0020Download rimasti</string>
<string name="downloads_processing">Elaborazione dei download in corso</string>
<string name="download_notification_title">Download podcast in corso</string>
<string name="download_report_content">%1$d download con successo, %2$d falliti</string>
@@ -323,7 +319,6 @@
<string name="choose_file_from_filesystem">Dal filesystem locale</string>
<string name="choose_file_from_external_application">Utilizza un\'applicazione esterna</string>
<string name="opml_export_label">Esportazione su OPML</string>
- <string name="exporting_label">Esportazione in corso...</string>
<string name="export_error_label">Errore di esportazione</string>
<string name="opml_export_success_title">Esportazione OPML avvenuta con successo.</string>
<string name="opml_export_success_sum">Il file .opml è stato scritto su:\u0020</string>
@@ -395,7 +390,6 @@
<!--Online feed view-->
<string name="subscribe_label">Abbonati</string>
<string name="subscribed_label">Abbonato</string>
- <string name="downloading_label">Download in corso...</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Mostra i capitoli</string>
<string name="show_shownotes_label">Mostra le note dell\'episodio</string>
@@ -422,7 +416,6 @@
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Importazione di sottoscrizioni da applicazioni monouso in corso...</string>
<string name="search_itunes_label">Cerca su iTunes</string>
- <string name="select_label"><b>Seleziona ...</b></string>
<string name="all_label">Tutti</string>
<string name="selected_all_label">Tutti gli Episodi Selezionati</string>
<string name="none_label">Nessuno</string>
@@ -436,4 +429,5 @@
<string name="sort_duration_short_long">Durata (Short \u2192 Long)</string>
<string name="sort_duration_long_short">Durata (Long \u2192 Short)</string>
<!--Rating dialog-->
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-iw-rIL/strings.xml b/core/src/main/res/values-iw-rIL/strings.xml
index 52a6a170a..6adc16fd6 100644
--- a/core/src/main/res/values-iw-rIL/strings.xml
+++ b/core/src/main/res/values-iw-rIL/strings.xml
@@ -56,7 +56,6 @@
<string name="length_prefix">אורך:\u0020</string>
<string name="size_prefix">גודל:\u0020</string>
<string name="processing_label">מעבד</string>
- <string name="loading_label">טוען...</string>
<string name="save_username_password_label">שמור שם משתמש וססמה</string>
<string name="close_label">סגור</string>
<string name="retry_label">נסה שוב</string>
@@ -81,7 +80,6 @@
<string name="mark_all_read_feed_confirmation_msg">אנא אשר שאתה רוצה לסמן את כל פרקים בהזנה זו כנקראים.</string>
<string name="show_info_label">הצג מידע</string>
<string name="remove_feed_label">הסר פודקאסט</string>
- <string name="share_label">שתף...</string>
<string name="share_link_label">שתף קישור אתר</string>
<string name="feed_delete_confirmation_msg">אשר מחיקת הזנה זו ואת כל פרקי ההזנה שהורדת.</string>
<string name="feed_remover_msg">הסר הזנה</string>
@@ -128,7 +126,6 @@
<string name="download_error_io_error">שגיאת קלט פלט</string>
<string name="download_error_request_error">שגיאת בקשה</string>
<string name="download_error_db_access">שגיאת גישה למסד הנתונים</string>
- <string name="downloads_left">הורדות נותרוu0020\</string>
<string name="downloads_processing">מעבד הורדות</string>
<string name="download_notification_title">מוריד פודקאסט</string>
<string name="download_report_content">%1$d הורדות הצליחו, %2$d ניכשלו</string>
@@ -289,7 +286,6 @@
<string name="choose_file_from_filesystem">ממערכת הקבצים המקומית</string>
<string name="choose_file_from_external_application">השתמש באפליקציה חיצונית</string>
<string name="opml_export_label">יצוא OPML</string>
- <string name="exporting_label">מייצא...</string>
<string name="export_error_label">שגיאת יצוא</string>
<string name="opml_export_success_title">יצוא OPML הצליח.</string>
<string name="opml_export_success_sum">קובץ OPML נכתב ל:\u0020</string>
@@ -345,7 +341,6 @@
<!--Online feed view-->
<string name="subscribe_label">הרשם</string>
<string name="subscribed_label">נרשם</string>
- <string name="downloading_label">מוריד...</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">הצג פרקים</string>
<string name="show_shownotes_label">הצג הערות פרק</string>
@@ -373,4 +368,5 @@
<string name="sp_apps_importing_feeds_msg">מייבא רישום מאפליקציות יעודיות...</string>
<string name="search_itunes_label">חפש בiTunes</string>
<!--Rating dialog-->
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-ja/strings.xml b/core/src/main/res/values-ja/strings.xml
index f58e90597..836af9fc0 100644
--- a/core/src/main/res/values-ja/strings.xml
+++ b/core/src/main/res/values-ja/strings.xml
@@ -22,6 +22,9 @@
<string name="playback_history_label">再生履歴</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">gpodder.net ログイン</string>
+ <string name="free_space_label">%1$s 空き</string>
+ <string name="episode_cache_full_title">エピソードキャッシュが一杯です</string>
+ <string name="episode_cache_full_message">エピソードキャッシュが制限に達しました。設定でキャッシュサイズを増やすことができます。</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">最近公開された</string>
<string name="episode_filter_label">新しいエピソードのみ表示</string>
@@ -66,7 +69,7 @@
<string name="length_prefix">長さ:\u0020</string>
<string name="size_prefix">サイズ:\u0020</string>
<string name="processing_label">処理中</string>
- <string name="loading_label">読み込み中...</string>
+ <string name="loading_label">ロード中…</string>
<string name="save_username_password_label">ユーザ名とパスワードを保存する</string>
<string name="close_label">閉じる</string>
<string name="retry_label">再試行</string>
@@ -78,7 +81,7 @@
<string name="feed_auto_download_global">全般</string>
<string name="feed_auto_download_always">常に</string>
<string name="feed_auto_download_never">しない</string>
- <string name="send_label">送信...</string>
+ <string name="send_label">送信…</string>
<string name="episode_cleanup_never">しない</string>
<string name="episode_cleanup_queue_removal">キューにない時</string>
<string name="episode_cleanup_after_listening">完了後</string>
@@ -100,7 +103,7 @@
<string name="mark_all_seen_label">参照済としてマーク</string>
<string name="show_info_label">情報を表示</string>
<string name="remove_feed_label">ポッドキャストを削除</string>
- <string name="share_label">共有...</string>
+ <string name="share_label">共有…</string>
<string name="share_link_label">Webサイトのリンクを共有</string>
<string name="share_link_with_position_label">場所とリンクを共有</string>
<string name="share_feed_url_label">フィード URLを共有</string>
@@ -135,7 +138,9 @@
<string name="added_to_queue_label">キューに追加しました</string>
<string name="remove_from_queue_label">キューから削除</string>
<string name="add_to_favorite_label">お気に入りに追加</string>
+ <string name="added_to_favorites">お気に入りに追加</string>
<string name="remove_from_favorite_label">お気に入りから削除</string>
+ <string name="removed_from_favorites">お気に入りから削除</string>
<string name="visit_website_label">Webサイトを訪問</string>
<string name="support_label">これをFlattr</string>
<string name="enqueue_all_new">すべてキューに入れる</string>
@@ -169,7 +174,9 @@
<string name="download_error_io_error">IOエラー</string>
<string name="download_error_request_error">リクエストエラー</string>
<string name="download_error_db_access">データベース アクセスエラー</string>
- <string name="downloads_left">\u0020ダウンロード残</string>
+ <plurals name="downloads_left">
+ <item quantity="other">%d ダウンロード残</item>
+ </plurals>
<string name="downloads_processing">ダウンロード処理中</string>
<string name="download_notification_title">ポッドキャストデータをダウンロード中</string>
<string name="download_report_content">%1$d ダウンロード成功, %2$d 失敗</string>
@@ -201,6 +208,8 @@
<!--Queue operations-->
<string name="lock_queue">キューをロック</string>
<string name="unlock_queue">キューのロックを解除</string>
+ <string name="queue_locked">キューをロックしました</string>
+ <string name="queue_unlocked">キューのロックを解除しました</string>
<string name="clear_queue_label">キューをクリア</string>
<string name="undo">元に戻す</string>
<string name="removed_from_queue">アイテムを削除しました</string>
@@ -242,12 +251,13 @@
<!--Variable Speed-->
<string name="download_plugin_label">プラグインをダウンロード</string>
<string name="no_playback_plugin_title">プラグイン はインストールされていません</string>
- <string name="no_playback_plugin_or_sonic_msg">再生速度の変更が機能するには、サードパーティのライブラリをインストールするか、実験的に Sonic プレーヤー [Android 4.1+] を有効にする必要があります。\n\n\'プラグインをダウンロード\' をタップして、Google Playから無料のプラグインをダウンロードしてください\n\nこのプラグインを使用して見つかったすべての問題は AntennaPodの責任ではなく、プラグインのオーナーに報告すべきです。</string>
+ <string name="no_playback_plugin_or_sonic_msg">再生速度の変更を機能させるには、内蔵の Sonic メディアプレーヤーを有効にすることを推奨します [Android 4.1+]。代わりに、Google Play からサードパーティのプラグイン <i>Prestissimo</i> をダウンロードすることができます。\nPrestissimo での問題は AntennaPod の責任ではなく、プラグインのオーナーに報告すべきです。</string>
<string name="set_playback_speed_label">再生速度</string>
<string name="enable_sonic">Sonic を有効にする</string>
<!--Empty list labels-->
<string name="no_items_label">このリストにはアイテムがありません。</string>
<string name="no_feeds_label">まだフィードを何も購読していません。</string>
+ <string name="no_chapters_label">このエピソードにチャプターはありません。</string>
<!--Preferences-->
<string name="other_pref">その他</string>
<string name="about_pref">について</string>
@@ -255,10 +265,12 @@
<string name="services_label">サービス</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">エピソード クリーンアップ</string>
- <string name="pref_episode_cleanup_summary">空き容量が必要な場合、キューに含まれていおらず、お気に入りでもないエピソードは、削除の対象になります</string>
+ <string name="pref_episode_cleanup_summary">キューに含まれておらず、お気に入りではないエピソードは、自動ダウンロードで新しいエピソードのためにスペースが必要な場合、除去の対象になります</string>
<string name="pref_pauseOnDisconnect_sum">ヘッドフォンまたはBluetoothの接続が切断された時、再生を一時停止します</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">ヘッドフォンが再接続された時に再生を再開します</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Bluetoothが再接続された時に再生を再開します</string>
+ <string name="pref_hardwareForwardButtonSkips_title">早送りボタンでスキップ</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">ハードウェアの早送りボタンを押したときに、早送りの代わりに次のエピソードにスキップします</string>
<string name="pref_followQueue_sum">再生が完了した時に次のキューのアイテムに移動します</string>
<string name="pref_auto_delete_sum">再生が完了した時にエピソードを削除します</string>
<string name="pref_auto_delete_title">自動削除</string>
@@ -274,6 +286,8 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">無効</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">間隔をセット</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">時間をセット</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">%1$s ごと</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">%1$s に</string>
<string name="pref_downloadMediaOnWifiOnly_sum">WiFi接続時のみメディアファイルをダウンロードします</string>
<string name="pref_followQueue_title">連続再生</string>
<string name="pref_downloadMediaOnWifiOnly_title">WiFiメディアダウンロード</string>
@@ -343,9 +357,13 @@
<string name="pref_smart_mark_as_played_disabled">無効</string>
<string name="pref_image_cache_size_title">画像キャッシュサイズ</string>
<string name="pref_image_cache_size_sum">画像のディスクキャッシュのサイズ。</string>
+ <string name="crash_report_title">クラッシュレポート</string>
+ <string name="crash_report_sum">メールで最新のクラッシュレポートを送信します</string>
+ <string name="send_email">メールを送信</string>
<string name="experimental_pref">実験的</string>
<string name="pref_sonic_title">Sonic メディアプレーヤー</string>
- <string name="pref_sonic_message">Prestissimo の代わりに、内蔵の Sonic メディアプレーヤーを使用します</string>
+ <string name="pref_sonic_message">Android 標準のメディアプレーヤーと Prestissimo の代わりに、内蔵のソニックメディアプレーヤーを使用します</string>
+ <string name="pref_current_value">現在の値: %1$s</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">自動Flattrを有効にする</string>
<string name="auto_flattr_after_percent">%d %再生したらエピソードをFlattr </string>
@@ -372,14 +390,15 @@
<string name="opml_import_error_dir_empty">インポートディレクトリが空です。</string>
<string name="select_all_label">すべてを選択</string>
<string name="deselect_all_label">選択解除</string>
- <string name="select_options_label">選択 ...</string>
+ <string name="select_options_label">選択…</string>
<string name="choose_file_from_filesystem">ローカル ファイルシステムから</string>
<string name="choose_file_from_external_application">外部アプリケーションを使用する</string>
<string name="opml_export_label">OPMLエクスポート</string>
- <string name="exporting_label">エクスポート中...</string>
+ <string name="exporting_label">エクスポート中…</string>
<string name="export_error_label">エクスポートエラー</string>
<string name="opml_export_success_title">OPMLをエクスポートしました。</string>
<string name="opml_export_success_sum">.opml ファイルを書き込みました:\u0020</string>
+ <string name="opml_import_ask_read_permission">OPML ファイルを読み込むために、外部ストレージへのアクセスが必要です</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">スリープタイマーをセット</string>
<string name="disable_sleeptimer_label">スリープタイマーを無効にする</string>
@@ -434,11 +453,16 @@
<string name="selected_folder_label">選択したフォルダー:</string>
<string name="create_folder_label">フォルダーを作成</string>
<string name="choose_data_directory">データ フォルダーを選択</string>
+ <string name="choose_data_directory_message">基本のデータフォルダーを選択してください。 AntennaPodは、適切なサブディレクトリを作成します。</string>
+ <string name="choose_data_directory_permission_rationale">データフォルダーを変更するために外部ストレージのアクセスが必要です</string>
<string name="create_folder_msg">名前 \"%1$s\" で新しいフォルダーを作成しますか?</string>
<string name="create_folder_success">新しいフォルダーを作成しました</string>
<string name="create_folder_error_no_write_access">このフォルダーに書き込みできません</string>
<string name="create_folder_error_already_exists">フォルダーは既に存在します</string>
<string name="create_folder_error">フォルダーを作成できません</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" は存在しません</string>
+ <string name="folder_not_readable_error">\"%1$s\" は読み込みできません</string>
+ <string name="folder_not_writable_error">\"%1$s\" は書き込みできません</string>
<string name="folder_not_empty_dialog_title">フォルダーが空ではありません</string>
<string name="folder_not_empty_dialog_msg">選択したフォルダは空ではありません。メディアのダウンロードやその他のファイルはこのフォルダに直接配置されます。続けますか?</string>
<string name="set_to_default_folder">デフォルトのフォルダーを選択</string>
@@ -450,7 +474,7 @@
<!--Online feed view-->
<string name="subscribe_label">購読</string>
<string name="subscribed_label">購読しました</string>
- <string name="downloading_label">ダウンロード中...</string>
+ <string name="downloading_label">ダウンロード中…</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">チャプターを表示</string>
<string name="show_shownotes_label">ショーノートを表示</string>
@@ -473,12 +497,20 @@
<!--Feed information screen-->
<string name="authentication_label">認証</string>
<string name="authentication_descr">このポッドキャストとそのエピソード用のあなたのユーザー名とパスワードを変更します。</string>
+ <string name="auto_download_settings_label">自動ダウンロード設定</string>
+ <string name="episode_filters_label">エピソード フィルター</string>
+ <string name="episode_filters_description">自動ダウンロードのときに、エピソードを含めるか除外する必要があるかを決定するために使用される条件のリスト</string>
+ <string name="episode_filters_include">含む</string>
+ <string name="episode_filters_exclude">含まない</string>
+ <string name="episode_filters_hint">単一の単語 \n\"複数の 単語\"</string>
+ <string name="keep_updated">更新済を保持</string>
<!--Progress information-->
<string name="progress_upgrading_database">データベースをアップグレードしています</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">単一目的のアプリから購読をインポート中…</string>
<string name="search_itunes_label">iTunes を検索</string>
- <string name="select_label"><b>選択 ...</b></string>
+ <string name="select_label"><b>選択…</b></string>
+ <string name="filter">フィルター</string>
<string name="all_label">すべて</string>
<string name="selected_all_label">すべてのエピソードを選択しました</string>
<string name="none_label">なし</string>
@@ -491,7 +523,11 @@
<string name="selected_downloaded_label">ダウンロード済のエピソードを選択しました</string>
<string name="not_downloaded_label">ダウンロードしていません</string>
<string name="selected_not_downloaded_label">ダウンロードしていないエピソードを選択しました</string>
- <string name="sort_title"><b>並び替え順 ...</b></string>
+ <string name="queued_label">キューに入れました</string>
+ <string name="selected_queued_label">キューに入ったエピソードを選択しました</string>
+ <string name="not_queued_label">キューに入っていません</string>
+ <string name="selected_not_queued_label">キューに入っていないエピソードを選択しました</string>
+ <string name="sort_title"><b>並び替え…</b></string>
<string name="sort_title_a_z">タイトル (A \u2192 Z)</string>
<string name="sort_title_z_a">タイトル (Z \u2192 A)</string>
<string name="sort_date_new_old">日付 (新 \u2192 旧)</string>
@@ -499,4 +535,18 @@
<string name="sort_duration_short_long">期間 (短 \u2192 長)</string>
<string name="sort_duration_long_short">期間 (長 \u2192 短)</string>
<!--Rating dialog-->
+ <string name="rating_title">AntennaPod は気に入りましたか?</string>
+ <string name="rating_message">AntennaPodを評価する時間をいただければ幸いです。</string>
+ <string name="rating_never_label">構わないで</string>
+ <string name="rating_later_label">後で確認する</string>
+ <string name="rating_now_label">もちろん、します!</string>
+ <!--Audio controls-->
+ <string name="audio_controls">自動コントロール</string>
+ <string name="playback_speed">再生速度</string>
+ <string name="volume">音量</string>
+ <string name="left_short">左</string>
+ <string name="right_short">右</string>
+ <string name="audio_effects">オーディオエフェクト</string>
+ <string name="stereo_to_mono">ダウンミックス: ステレオからモノラル</string>
+ <string name="sonic_only">Sonic のみ</string>
</resources>
diff --git a/core/src/main/res/values-ko/strings.xml b/core/src/main/res/values-ko/strings.xml
index 250bd445d..d0b3aae33 100644
--- a/core/src/main/res/values-ko/strings.xml
+++ b/core/src/main/res/values-ko/strings.xml
@@ -5,8 +5,11 @@
<string name="feeds_label">피드</string>
<string name="add_feed_label">팟캐스트 추가</string>
<string name="podcasts_label">팟캐스트</string>
+ <string name="episodes_label">에피소드</string>
<string name="new_episodes_label">새 에피소드</string>
<string name="all_episodes_label">모든 에피소드</string>
+ <string name="all_episodes_short_label">모두</string>
+ <string name="favorite_episodes_label">즐겨찾기</string>
<string name="new_label">신규</string>
<string name="waiting_list_label">추가 대기 목록</string>
<string name="settings_label">설정</string>
@@ -19,6 +22,9 @@
<string name="playback_history_label">재생 기록</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">gpodder.net 로그인</string>
+ <string name="free_space_label">%1$s 남음</string>
+ <string name="episode_cache_full_title">에피소드 캐시 꽉 참</string>
+ <string name="episode_cache_full_message">에피소드 캐시 한계값에 도달했습니다. 설정에서 캐시 크기를 늘릴 수 있습니다.</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">최근에 발표</string>
<string name="episode_filter_label">새 에피소드만 표시</string>
@@ -28,6 +34,7 @@
<string name="drawer_preferences">드로어 기본 설정</string>
<string name="drawer_feed_order_unplayed_episodes">카운터로 정렬</string>
<string name="drawer_feed_order_alphabetical">사전 순서로 정렬</string>
+ <string name="drawer_feed_order_last_update">배포 날짜 순서대로 정렬</string>
<string name="drawer_feed_counter_new_unplayed">새로운 에피소드와 재생하지 않은 에피소드 수</string>
<string name="drawer_feed_counter_new">새로운 에피소드 수</string>
<string name="drawer_feed_counter_unplayed">재생하지 않은 에피소드 수</string>
@@ -62,17 +69,25 @@
<string name="length_prefix">길이:\u0020</string>
<string name="size_prefix">크기:\u0020</string>
<string name="processing_label">처리 중</string>
- <string name="loading_label">읽어들이는 중...</string>
+ <string name="loading_label">읽어들이는 중…</string>
<string name="save_username_password_label">사용자 이름 및 암호 저장</string>
<string name="close_label">닫기</string>
<string name="retry_label">다시 시도</string>
<string name="auto_download_label">자동 다운로드에 포함</string>
<string name="auto_download_apply_to_items_title">예전 에피소드에 적용</string>
+ <string name="auto_download_apply_to_items_message">새로운 \'자동 다운로드\' 설정은 새 에피소드에 자동적으로 적용됩니다. 기존에 배포된 에피소드에도 적용할까요?</string>
<string name="auto_delete_label">에피소드 자동 삭제\n(전체 설정보다 우선)</string>
<string name="parallel_downloads_suffix">\u0020동시 다운로드</string>
<string name="feed_auto_download_global">전체 설정</string>
<string name="feed_auto_download_always">항상</string>
<string name="feed_auto_download_never">안 함</string>
+ <string name="send_label">보내기…</string>
+ <string name="episode_cleanup_never">안 함</string>
+ <string name="episode_cleanup_queue_removal">대기열에 없을 때</string>
+ <string name="episode_cleanup_after_listening">재생이 끝나고 나서</string>
+ <plurals name="episode_cleanup_days_after_listening">
+ <item quantity="other">재생이 끝나고 나서 %d일 뒤</item>
+ </plurals>
<!--'Add Feed' Activity labels-->
<string name="feedurl_label">피드 URL</string>
<string name="etxtFeedurlHint">피드의 URL 또는 홈페이지</string>
@@ -88,7 +103,7 @@
<string name="mark_all_seen_label">모두 봤다고 표시</string>
<string name="show_info_label">정보 표시</string>
<string name="remove_feed_label">팟캐스트 제거</string>
- <string name="share_label">공유...</string>
+ <string name="share_label">공유…</string>
<string name="share_link_label">홈페이지 링크 공유</string>
<string name="share_link_with_position_label">위치와 같이 링크 공유</string>
<string name="share_feed_url_label">피드 URL 공유</string>
@@ -122,6 +137,10 @@
<string name="add_to_queue_label">대기열에 추가</string>
<string name="added_to_queue_label">대기열에 추가함</string>
<string name="remove_from_queue_label">대기열에서 제거</string>
+ <string name="add_to_favorite_label">즐겨찾기에 추가</string>
+ <string name="added_to_favorites">즐겨찾기에 추가함</string>
+ <string name="remove_from_favorite_label">즐겨찾기에서 제거</string>
+ <string name="removed_from_favorites">즐겨찾기에서 제거함</string>
<string name="visit_website_label">홈페이지 보기</string>
<string name="support_label">Flattr하기</string>
<string name="enqueue_all_new">모두 대기열에 추가</string>
@@ -130,6 +149,7 @@
<string name="activate_auto_download">자동 다운로드 활성화</string>
<string name="deactivate_auto_download">자동 다운로드 해제</string>
<string name="reset_position">재생 위치 초기화</string>
+ <string name="removed_item">항목 제거됨</string>
<!--Download messages and labels-->
<string name="download_successful">성공</string>
<string name="download_failed">실패</string>
@@ -154,7 +174,9 @@
<string name="download_error_io_error">입출력 오류</string>
<string name="download_error_request_error">요청 오류</string>
<string name="download_error_db_access">데이터베이스 접근 오류</string>
- <string name="downloads_left">개\u0020다운로드 남음</string>
+ <plurals name="downloads_left">
+ <item quantity="other">다운로드 %d개 남음</item>
+ </plurals>
<string name="downloads_processing">다운로드 처리 중</string>
<string name="download_notification_title">팟캐스트 데이터 다운로드 중</string>
<string name="download_report_content">다운로드 %1$d개 성공, %2$d개 실패</string>
@@ -186,6 +208,8 @@
<!--Queue operations-->
<string name="lock_queue">대기열 잠그기</string>
<string name="unlock_queue">대기열 잠금 해제</string>
+ <string name="queue_locked">대기열 잠겨짐</string>
+ <string name="queue_unlocked">대기열 잠금 풀림</string>
<string name="clear_queue_label">대기열 지우기</string>
<string name="undo">실행 취소</string>
<string name="removed_from_queue">항목을 제거했습니다</string>
@@ -227,22 +251,33 @@
<!--Variable Speed-->
<string name="download_plugin_label">플러그인 다운로드</string>
<string name="no_playback_plugin_title">플러그인을 설치하지 않았습니다</string>
+ <string name="no_playback_plugin_or_sonic_msg">여러가지 속도로 재생이 동작하려면 내부의 소닉 미디어 플레이어를 활성화해야 합니다. [Android 4.1 이상]\n\n아니면, 서드파티 플러그인 <i>Prestissimo</i>를 플레이스토어에서 다운로드할 수도 있습니다.\nPrestissimo에서 발생하는 문제는 안테나팟의 책임이 아니므로 플러그인 개발자에게 문의하십시오.</string>
<string name="set_playback_speed_label">재생 속도</string>
+ <string name="enable_sonic">소닉 플레이어 사용</string>
<!--Empty list labels-->
<string name="no_items_label">이 목록에 항목이 없습니다.</string>
<string name="no_feeds_label">아직 어떤 피드도 구독하지 않았습니다.</string>
+ <string name="no_chapters_label">에피소드에 챕터가 없습니다.</string>
<!--Preferences-->
<string name="other_pref">기타</string>
<string name="about_pref">정보</string>
<string name="queue_label">대기열</string>
<string name="services_label">서비스</string>
<string name="flattr_label">Flattr</string>
+ <string name="pref_episode_cleanup_title">에피소드 정리</string>
+ <string name="pref_episode_cleanup_summary">대기열에 없고 즐겨찾기에 넣지 않은 에피소드는 자동 다운로드에서 새 에피소드에 공간이 필요할 경우 제거될 수 있습니다.</string>
+ <string name="pref_pauseOnDisconnect_sum">헤드폰이나 블루투스가 연결 해제되었을 경우 일시정지</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">헤드폰 다시 연결할 때 재생 계속</string>
+ <string name="pref_unpauseOnBluetoothReconnect_sum">블루투스가 다시 연결되면 재생 재개 </string>
+ <string name="pref_hardwareForwardButtonSkips_title">빨리감기 버튼을 넘김 버튼으로</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">빨리감기 하드웨어 버튼을 눌렀을 경우 빨리감기 대신 다음 에피소드로 넘깁니다</string>
<string name="pref_followQueue_sum">재생을 마쳤을 때 다음 대기열로 이동</string>
<string name="pref_auto_delete_sum">재생이 끝나면 에피소드 삭제</string>
<string name="pref_auto_delete_title">자동 삭제</string>
<string name="pref_smart_mark_as_played_sum">재생이 일정한 시간보다 (초 단위) 적게 남으면 에피소드를 재생한 것으로 표시</string>
<string name="pref_smart_mark_as_played_title">똑똑하게 재생한 것으로 표시</string>
+ <string name="pref_skip_keeps_episodes_sum">에피소드를 넘겼을 경우에도 유지</string>
+ <string name="pref_skip_keeps_episodes_title">넘긴 에피소드를 유지 보관합니다</string>
<string name="playback_pref">재생</string>
<string name="network_pref">네트워크</string>
<string name="pref_autoUpdateIntervallOrTime_title">업데이트 주기 또는 하루 중 시각</string>
@@ -251,11 +286,14 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">사용 안 함</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">주기 지정</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">하루 중 시각 지정</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">매 %1$s</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">%1$s에서</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Wi-Fi를 통해서만 미디어 파일 다운로드</string>
<string name="pref_followQueue_title">연속 재생</string>
<string name="pref_downloadMediaOnWifiOnly_title">Wi-Fi 미디어 다운로드</string>
<string name="pref_pauseOnHeadsetDisconnect_title">헤드폰 연결 끊김</string>
<string name="pref_unpauseOnHeadsetReconnect_title">헤드폰 재연결</string>
+ <string name="pref_unpauseOnBluetoothReconnect_title">블루투스 다시 연결</string>
<string name="pref_mobileUpdate_title">휴대전화망 업데이트</string>
<string name="pref_mobileUpdate_sum">휴대전화 데이터 연결을 통해 업데이트 허용</string>
<string name="refreshing_label">새로 고치는 중</string>
@@ -309,6 +347,8 @@
<string name="pref_expandNotify_sum">항상 알림에서 재생 버튼이 표시되도록 확장</string>
<string name="pref_persistNotify_title">재생 조작 고정</string>
<string name="pref_persistNotify_sum">재생이 일시 중지했을 때에도 알림과 잠금 화면의 조작 기능 유지</string>
+ <string name="pref_lockscreen_background_title">잠금 화면 배경 설정</string>
+ <string name="pref_lockscreen_background_sum">현재 에피소드의 이미지를 잠금 화면의 배경으로 설정합니다. 대신 이는 제3자 앱의 이미지도 표시하게 됩니다.</string>
<string name="pref_showDownloadReport_title">다운로드 보고서 보기</string>
<string name="pref_showDownloadReport_sum">다운로드가 실패하면, 실패를 자세히 표시하는 보고서를 만듭니다.</string>
<string name="pref_expand_notify_unsupport_toast">안드로이드 4.1 전 버전에서는 알림 확장을 지원하지 않습니다.</string>
@@ -317,6 +357,13 @@
<string name="pref_smart_mark_as_played_disabled">사용 안 함</string>
<string name="pref_image_cache_size_title">이미지 캐시 크기</string>
<string name="pref_image_cache_size_sum">이미지에 사용할 디스크 캐시 크기</string>
+ <string name="crash_report_title">오류 보고</string>
+ <string name="crash_report_sum">최근의 오류 보고서를 전자메일로 보내기</string>
+ <string name="send_email">전자메일 보내기</string>
+ <string name="experimental_pref">실험적 기능</string>
+ <string name="pref_sonic_title">소닉 미디어 플레이어</string>
+ <string name="pref_sonic_message">내장 소닉 미디어 플레이어를 안드로이드 고유 미디어 플레이어와 Prestissimo 대신 사용합니다.</string>
+ <string name="pref_current_value">현재 값: %1$s</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">자동 flattr 사용</string>
<string name="auto_flattr_after_percent">%d 퍼센트를 재생하면 에피소드에 flattr합니다</string>
@@ -331,6 +378,7 @@
<string name="found_in_title_label">제목에서 발견</string>
<!--OPML import and export-->
<string name="opml_import_txtv_button_lable">OPML 파일을 이용하면 팟캐스트 목록을 한 팟캐스트 프로그램에서 다른 팟캐스트 프로그램으로 옮길 수 있습니다.</string>
+ <string name="opml_import_option">옵션 %1$d</string>
<string name="opml_import_explanation_1">로컬 파일시스템의 특정 파일 경로를 선택하십시오.</string>
<string name="opml_import_explanation_2">OPML 파일을 여는데 Dropbox, Google Drive, 또는 파일 관리자 와 같은 외부 앱을 사용합니다.</string>
<string name="opml_import_explanation_3">Google Mail, Dropbox, Google Drive 및 대부분의 파일 관리자는 OPML 파일을 안테나팟<i>으로</i> <i>열 수</i> 있습니다.</string>
@@ -342,11 +390,11 @@
<string name="opml_import_error_dir_empty">가져오기 디렉터리가 비어 있습니다.</string>
<string name="select_all_label">모두 선택</string>
<string name="deselect_all_label">모두 선택 해제</string>
- <string name="select_options_label">선택...</string>
+ <string name="select_options_label">선택…</string>
<string name="choose_file_from_filesystem">로컬 파일시스템에서</string>
<string name="choose_file_from_external_application">외부 앱 사용</string>
<string name="opml_export_label">OPML 내보내기</string>
- <string name="exporting_label">내보내는 중...</string>
+ <string name="exporting_label">내보내는 중…</string>
<string name="export_error_label">내보내기 오류</string>
<string name="opml_export_success_title">OPML 내보내기가 성공했습니다.</string>
<string name="opml_export_success_sum">OPML 파일을 다음에 저장했습니다:\u0020</string>
@@ -357,6 +405,9 @@
<string name="sleep_timer_label">취침 타이머</string>
<string name="time_left_label">남은 시간:\u0020</string>
<string name="time_dialog_invalid_input">입력이 잘못되었습니다. 시간으로 숫자를 입력해야 합니다.</string>
+ <string name="timer_about_to_expire_label"><b>타이머가 만료될 때:</b></string>
+ <string name="shake_to_reset_label">흔들어서 타이머 초기화</string>
+ <string name="timer_vibration_label">진동</string>
<string name="time_seconds">초</string>
<string name="time_minutes">분</string>
<string name="time_hours">시간</string>
@@ -401,11 +452,15 @@
<string name="selected_folder_label">선택한 폴더:</string>
<string name="create_folder_label">폴더 만들기</string>
<string name="choose_data_directory">데이터 폴더 선택</string>
+ <string name="choose_data_directory_message">데이터 폴더를 선택하십시오. 안테나팟은 알아서 그 하위 디렉토리를 생성합니다.</string>
<string name="create_folder_msg">이름이 \"%1$s\"인 폴더를 만드시겠습니까?</string>
<string name="create_folder_success">새 폴더를 만들었습니다</string>
<string name="create_folder_error_no_write_access">이 폴더에 쓸 수 없습니다</string>
<string name="create_folder_error_already_exists">폴더가 이미 있습니다</string>
<string name="create_folder_error">폴더를 만들 수 없습니다</string>
+ <string name="folder_does_not_exist_error">\"%1$s\"이(가) 없습니다.</string>
+ <string name="folder_not_readable_error">\"%1$s\"에서 읽을 수 없습니다</string>
+ <string name="folder_not_writable_error">\"%1$s\"에 쓸 수 없습니다</string>
<string name="folder_not_empty_dialog_title">폴더가 비어 있지 않습니다</string>
<string name="folder_not_empty_dialog_msg">선택한 폴더가 비어 있지 않습니다. 다운로드한 미디어 파일 및 기타 파일이 이 폴더에 저장됩니다. 그래도 계속 하시겠습니까?</string>
<string name="set_to_default_folder">기본 폴더 선택</string>
@@ -417,7 +472,7 @@
<!--Online feed view-->
<string name="subscribe_label">구독</string>
<string name="subscribed_label">구독함</string>
- <string name="downloading_label">다운로드하는 중...</string>
+ <string name="downloading_label">다운로드하는 중…</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">챕터 보이기</string>
<string name="show_shownotes_label">프로그램 메모 표시</string>
@@ -440,12 +495,20 @@
<!--Feed information screen-->
<string name="authentication_label">인증</string>
<string name="authentication_descr">이 팟캐스트와 에피소드에 대한 사용자 이름과 비밀번호를 바꿉니다.</string>
+ <string name="auto_download_settings_label">자동 다운로드 설정</string>
+ <string name="episode_filters_label">에피소드 필터</string>
+ <string name="episode_filters_description">자동 다운로드를 할 때 에피소드가 포함되어야할지 제외되어야할지 결정하는 규칙의 목록</string>
+ <string name="episode_filters_include">포함</string>
+ <string name="episode_filters_exclude">제외</string>
+ <string name="episode_filters_hint">단수 단어 \n\"복수 단어\"</string>
+ <string name="keep_updated">최신 업데이트 유지</string>
<!--Progress information-->
<string name="progress_upgrading_database">데이터베이스 업그레이드 중</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">단일 용도 앱에서 구독 정보를 가져옵니다...</string>
<string name="search_itunes_label">iTunes 검색</string>
- <string name="select_label"><b>선택 ...</b></string>
+ <string name="select_label"><b>선택…</b></string>
+ <string name="filter">필터</string>
<string name="all_label">모두</string>
<string name="selected_all_label">모든 에피소드 선택</string>
<string name="none_label">없음</string>
@@ -458,7 +521,7 @@
<string name="selected_downloaded_label">다운로드한 에피소드 선택</string>
<string name="not_downloaded_label">다운로드 안 함</string>
<string name="selected_not_downloaded_label">다운로드 안 한 에피소드 선택</string>
- <string name="sort_title"><b>정렬 ...</b></string>
+ <string name="sort_title"><b>정렬…</b></string>
<string name="sort_title_a_z">제목 (A \u2192 Z)</string>
<string name="sort_title_z_a">제목 (Z \u2192 A)</string>
<string name="sort_date_new_old">시각 (최근 \u2192 과거)</string>
@@ -466,4 +529,18 @@
<string name="sort_duration_short_long">길이 (짧은 \u2192 긴)</string>
<string name="sort_duration_long_short">길이 (긴 \u2192 짧은)</string>
<!--Rating dialog-->
+ <string name="rating_title">안테나팟이 좋으신가요?</string>
+ <string name="rating_message">안테나팟을 평가하는데 시간을 잠깐 내주시면 감사하겠습니다.</string>
+ <string name="rating_never_label">안 할래요</string>
+ <string name="rating_later_label">나중에 알림</string>
+ <string name="rating_now_label">해봅시다!</string>
+ <!--Audio controls-->
+ <string name="audio_controls">오디오 조정</string>
+ <string name="playback_speed">재생 속도</string>
+ <string name="volume">볼륨</string>
+ <string name="left_short">좌</string>
+ <string name="right_short">우</string>
+ <string name="audio_effects">오디오 효과</string>
+ <string name="stereo_to_mono">다운믹스: 스테레오에서 모노로</string>
+ <string name="sonic_only">소닉 전용</string>
</resources>
diff --git a/core/src/main/res/values-nb/strings.xml b/core/src/main/res/values-nb/strings.xml
index 435d0cc7c..e3aa1ca5d 100644
--- a/core/src/main/res/values-nb/strings.xml
+++ b/core/src/main/res/values-nb/strings.xml
@@ -22,6 +22,7 @@
<string name="playback_history_label">Avspillingshistorikk</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">gpodder.net-innlogging</string>
+ <string name="free_space_label">%1$s ledig</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Nylig publisert</string>
<string name="episode_filter_label">Vis kun nye episoder</string>
@@ -66,7 +67,6 @@
<string name="length_prefix">Lengde:\u0020</string>
<string name="size_prefix">Størrelse:\u0020</string>
<string name="processing_label">Behandler</string>
- <string name="loading_label">Laster opp...</string>
<string name="save_username_password_label">Lagre brukernavn og passord</string>
<string name="close_label">Lukk</string>
<string name="retry_label">Prøv igjen</string>
@@ -78,7 +78,6 @@
<string name="feed_auto_download_global">Global</string>
<string name="feed_auto_download_always">Alltid</string>
<string name="feed_auto_download_never">Aldri</string>
- <string name="send_label">Send ...</string>
<string name="episode_cleanup_never">AldriAldri</string>
<string name="episode_cleanup_queue_removal">Når ikke i kø</string>
<string name="episode_cleanup_after_listening">Etter den er ferdig</string>
@@ -101,7 +100,6 @@
<string name="mark_all_seen_label">Marker alle som sett</string>
<string name="show_info_label">Vis informasjon</string>
<string name="remove_feed_label">Fjern podcast</string>
- <string name="share_label">Del ...</string>
<string name="share_link_label">Del lenke</string>
<string name="share_link_with_position_label">Del lenke med plassering</string>
<string name="share_feed_url_label">Del strømmens URL</string>
@@ -170,7 +168,6 @@
<string name="download_error_io_error">IO feil</string>
<string name="download_error_request_error">Forespørselfeil</string>
<string name="download_error_db_access">Tilgangsfeil for database</string>
- <string name="downloads_left">\u0020Nedlastninger igjen</string>
<string name="downloads_processing">Behandler nedlastninger</string>
<string name="download_notification_title">Laster ned data til podcast</string>
<string name="download_report_content">%1$d nedlastninger lyktes, %2$d mislyktes</string>
@@ -243,7 +240,6 @@
<!--Variable Speed-->
<string name="download_plugin_label">Last ned programtillegg</string>
<string name="no_playback_plugin_title">Programtillegg er ikke installert</string>
- <string name="no_playback_plugin_or_sonic_msg">For at variabel avspillingshastighet skal fungere må du installere et tredjepartsbibliotek eller aktivere den eksperimentelle Sonic-avspilleren [Android 4.1+].\n\nTrykk på «Last ned programtillegg» for å laste ned en gratis tilleggsmodul fra Google Play.\n\nEventuelle problemer som måtte oppstå på grunn av denne modulen er ikke AntennaPods ansvar og skal rapporteres til eieren av modulen.</string>
<string name="set_playback_speed_label">Avspillingshastigheter</string>
<string name="enable_sonic">Skru på Sonic</string>
<!--Empty list labels-->
@@ -256,8 +252,11 @@
<string name="services_label">Tjenester</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Episodeopprydding</string>
- <string name="pref_episode_cleanup_summary">Episoder som ikke er i køen og ikke er merket som favoritt vil være markert for sletting dersom lagringsplass trengs</string>
+ <string name="pref_pauseOnDisconnect_sum">Sett playback på pause når hodetelefoner eller bluetooth er frakoblet</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Gjenoppta avspilling når hodetelefoner gjeninnkoples</string>
+ <string name="pref_unpauseOnBluetoothReconnect_sum">Fortsett avspilling når bluetooth er tilkoblet igjen</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Forover-knapp hopper</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Ved pressing av hardware forover-knapp hopp til neste episode istedenfor forover-spoling</string>
<string name="pref_followQueue_sum">Hopp til neste element i køen når avspillingen er ferdig</string>
<string name="pref_auto_delete_sum">Slett episode når avspillingen er ferdig</string>
<string name="pref_auto_delete_title">Automatisk sletting</string>
@@ -278,6 +277,7 @@
<string name="pref_downloadMediaOnWifiOnly_title">WiFi media nedlastning</string>
<string name="pref_pauseOnHeadsetDisconnect_title">Frakobling av hodetelefoner</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Gjeninnkopling av hodetelefoner</string>
+ <string name="pref_unpauseOnBluetoothReconnect_title">Blutetooth tilkoblet igjen</string>
<string name="pref_mobileUpdate_title">Mobiloppdateringer</string>
<string name="pref_mobileUpdate_sum">Tillat oppdateringer over kobling via mobildata</string>
<string name="refreshing_label">Oppdaterer</string>
@@ -341,9 +341,11 @@
<string name="pref_smart_mark_as_played_disabled">Deaktivert</string>
<string name="pref_image_cache_size_title">Størrelse for bildemellomlager</string>
<string name="pref_image_cache_size_sum">Størrelsen på mellomlageret for bilder.</string>
+ <string name="crash_report_title">Kræsj-rapport</string>
+ <string name="crash_report_sum">Send den siste kræsj-rapporten via e-post</string>
+ <string name="send_email">Send e-post</string>
<string name="experimental_pref">Eksperimentell</string>
<string name="pref_sonic_title">Sonic medieavspiller</string>
- <string name="pref_sonic_message">Bruk den innebygde Sonic medieavspilleren som en erstatning for Prestissimo</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Aktiver automatisk flattring</string>
<string name="auto_flattr_after_percent">Flattre episode så snart %d prosent er avspilt</string>
@@ -370,11 +372,9 @@
<string name="opml_import_error_dir_empty">Importkatalogen er tom.</string>
<string name="select_all_label">Velg alle</string>
<string name="deselect_all_label">Opphev alle markeringene</string>
- <string name="select_options_label">Velg ...</string>
<string name="choose_file_from_filesystem">Fra lokalt filsystem</string>
<string name="choose_file_from_external_application">Bruk ekstern applikasjon</string>
<string name="opml_export_label">OPML-eksportering</string>
- <string name="exporting_label">Eksporterer...</string>
<string name="export_error_label">Eksporteringserror</string>
<string name="opml_export_success_title">OPML-import vellykket.</string>
<string name="opml_export_success_sum">.opml-filen ble skrevet til:\u0020</string>
@@ -435,11 +435,15 @@
<string name="selected_folder_label">Valgt mappe</string>
<string name="create_folder_label">Lag mappe</string>
<string name="choose_data_directory">Velg datamappe</string>
+ <string name="choose_data_directory_message">Vennligst velg basisen for datamappen din. AntennaPod vil lage de nødvendige submappene dine.</string>
<string name="create_folder_msg">Lag en ny mappe med navn \"%1$s\"?</string>
<string name="create_folder_success">Lagde en ny mappe</string>
<string name="create_folder_error_no_write_access">Kan ikke skrive til denne mappen</string>
<string name="create_folder_error_already_exists">Mappe eksisterer allerede</string>
<string name="create_folder_error">Kunne ikke lage mappe</string>
+ <string name="folder_does_not_exist_error">%1$s eksisterer ikke</string>
+ <string name="folder_not_readable_error">%1$s kan ikke leses</string>
+ <string name="folder_not_writable_error">%1$s kan ikke skrives til</string>
<string name="folder_not_empty_dialog_title">Mappen er ikke tom</string>
<string name="folder_not_empty_dialog_msg">Mappen du har valgt er ikke tom. Nedlastet media og andre filer vil bli plassert direkte i denne mappen? Vil du fortsette?</string>
<string name="set_to_default_folder">Velg standardmappe</string>
@@ -451,7 +455,6 @@
<!--Online feed view-->
<string name="subscribe_label">Abonner</string>
<string name="subscribed_label">Abonnert</string>
- <string name="downloading_label">Laster ned...</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Vis kapitler</string>
<string name="show_shownotes_label">Vis notater</string>
@@ -479,7 +482,6 @@
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Importerer abbonementer fra enkeltstående applikasjoner ...</string>
<string name="search_itunes_label">Søk på iTunes</string>
- <string name="select_label"><b>Velg ...</b></string>
<string name="all_label">Alle</string>
<string name="selected_all_label">Valgte alle episoder</string>
<string name="none_label">Ingen</string>
@@ -492,7 +494,6 @@
<string name="selected_downloaded_label">Valgte nedlastede episoder</string>
<string name="not_downloaded_label">Ikke nedlastet</string>
<string name="selected_not_downloaded_label">Valgte ikke-nedlastede episoder</string>
- <string name="sort_title"><b>Sorter på ...</b></string>
<string name="sort_title_a_z">Tittel (A \u2192 Z)</string>
<string name="sort_title_z_a">Tittel (Z \u2192 A)</string>
<string name="sort_date_new_old">Dato (Ny \u2192 Gammel)</string>
@@ -500,4 +501,10 @@
<string name="sort_duration_short_long">Lengde (Kort \u2192 Lang)</string>
<string name="sort_duration_long_short">Lengde (Lang \u2192 Kort)</string>
<!--Rating dialog-->
+ <string name="rating_title">Liker du AntennaPod?</string>
+ <string name="rating_message">Vi ville satt pris på om du tok deg tid til å vurdere AntennaPod.</string>
+ <string name="rating_never_label">La meg være i fred</string>
+ <string name="rating_later_label">Minn meg på dette senere</string>
+ <string name="rating_now_label">Naturligvis, kom igjen!</string>
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-nl/strings.xml b/core/src/main/res/values-nl/strings.xml
index b8b3d7c51..1973cd51b 100644
--- a/core/src/main/res/values-nl/strings.xml
+++ b/core/src/main/res/values-nl/strings.xml
@@ -23,6 +23,8 @@
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">gpodder.net login</string>
<string name="free_space_label">%1$s beschikbaar</string>
+ <string name="episode_cache_full_title">Afleveringen cache is vol</string>
+ <string name="episode_cache_full_message">Het maximum aantal gecachte afleveringen is bereikt. U kunt het maximum verhogen in de instellingen.</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Recent gepubliceerd</string>
<string name="episode_filter_label">Alleen nieuwe afleveringen weergeven</string>
@@ -67,7 +69,7 @@
<string name="length_prefix">Lengte:\u0020</string>
<string name="size_prefix">Grootte:\u0020</string>
<string name="processing_label">Aan het verwerken</string>
- <string name="loading_label">Laden...</string>
+ <string name="loading_label">Laden…</string>
<string name="save_username_password_label">Gebruikersnaam en wachtwoord opslaan</string>
<string name="close_label">Sluiten</string>
<string name="retry_label">Opnieuw proberen</string>
@@ -79,7 +81,7 @@
<string name="feed_auto_download_global">Standaardinstelling</string>
<string name="feed_auto_download_always">Altijd</string>
<string name="feed_auto_download_never">Nooit</string>
- <string name="send_label">Versturen...</string>
+ <string name="send_label">Versturen…</string>
<string name="episode_cleanup_never">Nooit</string>
<string name="episode_cleanup_queue_removal">Wanneer niet in de wachtrij</string>
<string name="episode_cleanup_after_listening">Wanneer aflevering volledig is afgespeeld</string>
@@ -95,14 +97,14 @@
<string name="podcastdirectories_descr">U kunt nieuwe podcasts zoeken op naam, categorie of populariteit in de gpodder.net database, of de iTunes winkel doorzoeken.</string>
<string name="browse_gpoddernet_label">gpodder.net doorbladeren</string>
<!--Actions on feeds-->
- <string name="mark_all_read_label">Alles als beluisterd markeren</string>
+ <string name="mark_all_read_label">Alles als afgespeeld markeren</string>
<string name="mark_all_read_msg">Alle afleveringen als afgespeeld markeren</string>
<string name="mark_all_read_confirmation_msg">Bevestig aub dat u alle afleveringen als afgespeeld wilt markeren.</string>
<string name="mark_all_read_feed_confirmation_msg">Bevestig aub dat u alle afleveringen van deze feed als afgespeeld wilt markeren.</string>
<string name="mark_all_seen_label">\'Nieuw\' label van alle afleveringen verwijderen.</string>
<string name="show_info_label">Toon informatie</string>
<string name="remove_feed_label">Podcast verwijderen</string>
- <string name="share_label">Delen...</string>
+ <string name="share_label">Delen…</string>
<string name="share_link_label">Link van de aflevering delen</string>
<string name="share_link_with_position_label">Link van de aflevering met tijdstip delen</string>
<string name="share_feed_url_label">URL van de feed delen</string>
@@ -137,7 +139,9 @@
<string name="added_to_queue_label">Aan wachtrij toegevoegd</string>
<string name="remove_from_queue_label">Verwijder van wachtrij</string>
<string name="add_to_favorite_label">Toevoegen aan favorieten</string>
+ <string name="added_to_favorites">Aan favorieten toegevoegd</string>
<string name="remove_from_favorite_label">Verwijderen uit favorieten</string>
+ <string name="removed_from_favorites">Verwijderd uit favorieten</string>
<string name="visit_website_label">Website bezoeken</string>
<string name="support_label">Flattr dit</string>
<string name="enqueue_all_new">Alle aan wachtrij toevoegen</string>
@@ -171,7 +175,10 @@
<string name="download_error_io_error">IO fout</string>
<string name="download_error_request_error">Fout in de aanvraag</string>
<string name="download_error_db_access">Databasetoegangsfout</string>
- <string name="downloads_left">Nog \u0020 downloads</string>
+ <plurals name="downloads_left">
+ <item quantity="one">Nog %d download</item>
+ <item quantity="other">Nog %d downloads</item>
+ </plurals>
<string name="downloads_processing">Downloads verwerken</string>
<string name="download_notification_title">Podcast gegevens aan het downloaden</string>
<string name="download_report_content">%1$d downloads geslaagd, %2$d mislukt</string>
@@ -203,6 +210,8 @@
<!--Queue operations-->
<string name="lock_queue">Wachtrij vastzetten</string>
<string name="unlock_queue">Wachtrij ontgrendelen</string>
+ <string name="queue_locked">Wachtrij vergrendeld</string>
+ <string name="queue_unlocked">Wachtrij ontgrendeld</string>
<string name="clear_queue_label">Wachtrij leeg maken</string>
<string name="undo">Ongedaan maken</string>
<string name="removed_from_queue">Item verwijderd</string>
@@ -244,12 +253,13 @@
<!--Variable Speed-->
<string name="download_plugin_label">Plugin downloaden</string>
<string name="no_playback_plugin_title">Plugin niet geïnstalleerd</string>
- <string name="no_playback_plugin_or_sonic_msg">Om variabele afspeelsnelheid te kunnen gebruiken, moet een bibliotheek van derden worden geïnstalleerd of de experimentele Sonic Player worden geactiveerd (beschikbaar voor Android 4.1 en hoger).\n\nKies \'Plugin Downloaden\' om de gratis plugin via de Play Store te installeren.\n\nProblemen bij het gebruik van deze plugin zijn niet de verantwoordelijkheid van AntennaPod en moeten gemeld worden bij de ontwikkelaar van de plugin.</string>
+ <string name="no_playback_plugin_or_sonic_msg">Om variabele afspeelsnelheid te kunnen gebruiken, raden wij u aan om de ingebouwde Sonic mediaspeler te activeren [Android 4.1+]\n\nEventueel kunt u de externe plugin <i>Prestissimo</i> downloaden van de Play Store.\nProblemen bij het gebruik van deze plugin zijn niet de verantwoordelijkheid van AntennaPod en moeten gemeld worden bij de ontwikkelaar van de plugin.</string>
<string name="set_playback_speed_label">Afspeelsnelheden</string>
<string name="enable_sonic">Sonic instellen</string>
<!--Empty list labels-->
<string name="no_items_label">Er zijn geen items in deze lijst.</string>
<string name="no_feeds_label">U bent nog tot geen enkele feed geabonneerd.</string>
+ <string name="no_chapters_label">Deze aflevering heeft geen hoofdstukken.</string>
<!--Preferences-->
<string name="other_pref">Overig</string>
<string name="about_pref">Over AntennaPod</string>
@@ -257,14 +267,16 @@
<string name="services_label">Services</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Automatisch opschonen</string>
- <string name="pref_episode_cleanup_summary">Afleveringen die niet in de wachtrij staan en niet zijn gemarkeerd zijn als favoriet, komen in aanmerking voor verwijdering bij automatisch opschonen.</string>
+ <string name="pref_episode_cleanup_summary">Afleveringen die niet in de wachtrij staan én niet als favoriet gemarkeerd zijn, mogen verwijderd worden als Automatisch Downloaden ruimte nodig heeft voor nieuwe afleveringen</string>
<string name="pref_pauseOnDisconnect_sum">Afspelen pauzeren wanneer de koptelefoon wordt losgekoppeld of de bluetooth verbinding wordt verbroken</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Afspelen hervatten wanneer de koptelefoon opnieuw wordt aangesloten</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Afspelen hervatten wanneer de bluetooth verbinding hervat wordt</string>
+ <string name="pref_hardwareForwardButtonSkips_title">\'Volgende\' knop voor overslaan</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Aflevering overslaan ipv vooruitspoelen wanneer op een fysieke \'volgende\' knop wordt gedrukt</string>
<string name="pref_followQueue_sum">Volgende item in de wachtrij afspelen als de aflevering voltooid is</string>
<string name="pref_auto_delete_sum">Afleveringen verwijderen als ze zijn afgespeeld</string>
<string name="pref_auto_delete_title">Automatisch verwijderen</string>
- <string name="pref_smart_mark_as_played_sum">Als afgespeeld markeren wanneer minder dan een bepaald aantal seconden van de afspeeltijd over is</string>
+ <string name="pref_smart_mark_as_played_sum">Afleveringen als afgespeeld markeren wanneer deze nog maar een bepaald aantal seconden duurt</string>
<string name="pref_smart_mark_as_played_title">Slimme afgespeeld markering</string>
<string name="pref_skip_keeps_episodes_sum">Afleveringen bewaren en in de wachtrij houden als u op \'overslaan\' klikt</string>
<string name="pref_skip_keeps_episodes_title">Overgeslagen afleveringen bewaren</string>
@@ -276,10 +288,12 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">Uitschakelen</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Interval instellen</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Tijdstip instellen</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">elke %1$s</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">op %1$s</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Download mediabestanden alleen via WiFi</string>
<string name="pref_followQueue_title">Continu afspelen</string>
<string name="pref_downloadMediaOnWifiOnly_title">WiFi download van media</string>
- <string name="pref_pauseOnHeadsetDisconnect_title">Loskoppeling koptelefoon</string>
+ <string name="pref_pauseOnHeadsetDisconnect_title">Pauzeren bij loskoppeling</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Aansluiten koptelefoon</string>
<string name="pref_unpauseOnBluetoothReconnect_title">Verbinden met bluetooth</string>
<string name="pref_mobileUpdate_title">Mobiele updates</string>
@@ -295,7 +309,7 @@
<string name="pref_auto_flattr_title">Automatische Flattr</string>
<string name="pref_auto_flattr_sum">Automatisch flattr\'en instellen</string>
<string name="user_interface_label">User Interface</string>
- <string name="pref_set_theme_title">Kies theme</string>
+ <string name="pref_set_theme_title">Kies kleurschema</string>
<string name="pref_nav_drawer_title">Menu aanpassen</string>
<string name="pref_nav_drawer_sum">Het uiterlijk en andere instellingen van het menu aanpassen.</string>
<string name="pref_nav_drawer_items_title">Menu-items instellen</string>
@@ -345,10 +359,13 @@
<string name="pref_smart_mark_as_played_disabled">Uitgeschakeld</string>
<string name="pref_image_cache_size_title">Grootte cachegeheugen</string>
<string name="pref_image_cache_size_sum">De groote van het cachegeheugen voor afbeeldingen aanpassen.</string>
+ <string name="crash_report_title">Crashreport</string>
+ <string name="crash_report_sum">Verstuur laatste crashreport via email</string>
<string name="send_email">Verstuur email</string>
<string name="experimental_pref">Experimentele functie</string>
<string name="pref_sonic_title">Sonic mediaspeler</string>
- <string name="pref_sonic_message">Sonic, de standaard mediaspeler van Android, gebruiken als alternatief voor Prestissimo</string>
+ <string name="pref_sonic_message">Gebruik AntennaPod\'s ingebouwde Sonic mediaspeler als een alternatief voor Prestissimo en de mediaspeler van Android.</string>
+ <string name="pref_current_value">Huidige instelling: %1$s</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Automatisch flattr\'en aanzetten</string>
<string name="auto_flattr_after_percent">Flattr een aflevering zodra %d procent is afgespeeld</string>
@@ -373,16 +390,17 @@
<string name="reading_opml_label">OPML-bestand aan het lezen</string>
<string name="opml_reader_error">Er is een fout opgetreden bij het lezen van het OPML-bestand:</string>
<string name="opml_import_error_dir_empty">De import map is leeg.</string>
- <string name="select_all_label">Selecteer alles</string>
- <string name="deselect_all_label">Deselecteer alles</string>
- <string name="select_options_label">Selecteren …</string>
+ <string name="select_all_label">Alles selecteren</string>
+ <string name="deselect_all_label">Alles deselecteren</string>
+ <string name="select_options_label">Selecteren…</string>
<string name="choose_file_from_filesystem">Via bestandsbeheer</string>
<string name="choose_file_from_external_application">Via externe app</string>
<string name="opml_export_label">OPML export</string>
- <string name="exporting_label">Aan het exporteren...</string>
+ <string name="exporting_label">Exporteren…</string>
<string name="export_error_label">Export fout</string>
<string name="opml_export_success_title">OPML bestand succesvol geëxporteerd.</string>
<string name="opml_export_success_sum"> Het OPML-bestand is in \u0020 geplaatst</string>
+ <string name="opml_import_ask_read_permission">Toegang tot externe locaties is nodig om het OPML-bestand te kunnen lezen</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Slaap timer instellen</string>
<string name="disable_sleeptimer_label">Slaap timer uitschakelen</string>
@@ -440,23 +458,28 @@
<string name="selected_folder_label">Geselecteerde map:</string>
<string name="create_folder_label">Map aanmaken</string>
<string name="choose_data_directory">Kies data map</string>
+ <string name="choose_data_directory_message">Kies de hoofdmap voor uw data. AntennaPod zal de benodigde submappen creeëren.</string>
+ <string name="choose_data_directory_permission_rationale">Toegang tot de externe opslag is nodig om de data-map aan te passen</string>
<string name="create_folder_msg">Maak een nieuwe map aan met de naam \"%1$s\"?</string>
<string name="create_folder_success">Nieuwe map aangemaakt</string>
<string name="create_folder_error_no_write_access">Kan in deze map niet schrijven</string>
<string name="create_folder_error_already_exists">Map bestaat al</string>
<string name="create_folder_error">Kon map niet aanmaken</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" bestaat niet</string>
+ <string name="folder_not_readable_error">\"%1$s\" kan niet gelezen worden</string>
+ <string name="folder_not_writable_error">in \"%1$s\" kan geen data geschreven worden</string>
<string name="folder_not_empty_dialog_title">Map is niet leeg</string>
<string name="folder_not_empty_dialog_msg">De map die je hebt gekozen is niet leeg. Media downloads en andere bestanden zullen rechtstreeks in deze map geplaatst worden. Toch doorgaan?</string>
<string name="set_to_default_folder">Kies default map</string>
- <string name="pref_pausePlaybackForFocusLoss_sum">Het afspelen onderbreken in plaats van het volume te verlagen wanneer er een andere app geluiden af wilt spelen</string>
- <string name="pref_pausePlaybackForFocusLoss_title">Pauze voor onderbrekingen</string>
+ <string name="pref_pausePlaybackForFocusLoss_sum">Het afspelen onderbreken in plaats van het volume te verlagen wanneer er een andere app geluiden af wil spelen</string>
+ <string name="pref_pausePlaybackForFocusLoss_title">Pauzeren bij onderbrekingen</string>
<string name="pref_resumeAfterCall_sum">Afspelen hervatten na beëindigen telefoongesprek</string>
<string name="pref_resumeAfterCall_title">Hervatten na gesprek</string>
<string name="pref_restart_required">AntennaPod moet opnieuw worden opgestart om deze wijziging door te voeren.</string>
<!--Online feed view-->
<string name="subscribe_label">Abonneren</string>
<string name="subscribed_label">Geabonneerd</string>
- <string name="downloading_label">Aan het downloaden</string>
+ <string name="downloading_label">Downloaden…</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Hoofdstukken tonen</string>
<string name="show_shownotes_label">Shownotes tonen</string>
@@ -479,12 +502,19 @@
<!--Feed information screen-->
<string name="authentication_label">Authenticatie</string>
<string name="authentication_descr">Gebruikersnaam en wachtwoord aanpassen voor deze podcast</string>
+ <string name="auto_download_settings_label">Instellingen voor Automatisch downloaden</string>
+ <string name="episode_filters_label">Afleveringenfilter</string>
+ <string name="episode_filters_description">Lijst van zoektermen die bepalen of een aflevering meegenomen of uitgesloten wordt bij automatisch downloaden</string>
+ <string name="episode_filters_include">Meenemen</string>
+ <string name="episode_filters_exclude">Uitsluiten</string>
+ <string name="keep_updated">Up to date houden</string>
<!--Progress information-->
<string name="progress_upgrading_database">Database upgraden</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Abonnementen aan het importeren vanuit single-purpose apps...</string>
<string name="search_itunes_label">Zoeken in iTunes</string>
- <string name="select_label"><b>Selecteren …</b></string>
+ <string name="select_label"><b>Selecteren…</b></string>
+ <string name="filter">Filter</string>
<string name="all_label">Alle</string>
<string name="selected_all_label">Alle afleveringen selecteren</string>
<string name="none_label">Geen</string>
@@ -497,7 +527,11 @@
<string name="selected_downloaded_label">Gedownloadde afleveringen geselecteerd</string>
<string name="not_downloaded_label">Niet gedownload</string>
<string name="selected_not_downloaded_label">Niet gedownloadde afleveringen geselecteerd</string>
- <string name="sort_title"><b>Sorteren op ...</b></string>
+ <string name="queued_label">In de wachtrij</string>
+ <string name="selected_queued_label">Afleveringen in de wachtrij selecteren</string>
+ <string name="not_queued_label">Niet in de wachtrij</string>
+ <string name="selected_not_queued_label">Afleveringen geselecteerd die niet in de wachtrij staan</string>
+ <string name="sort_title"><b>Sorteren op…</b></string>
<string name="sort_title_a_z">Titel (A \u2192 Z)</string>
<string name="sort_title_z_a">Titel (A \u2192 A)</string>
<string name="sort_date_new_old">Datum (nieuw \u2192 oud)</string>
@@ -510,4 +544,13 @@
<string name="rating_never_label">Nee, bedankt.</string>
<string name="rating_later_label">Herinner me later</string>
<string name="rating_now_label">Ja, doen we!</string>
+ <!--Audio controls-->
+ <string name="audio_controls">Audio-instellingen</string>
+ <string name="playback_speed">Afspeelsnelheid</string>
+ <string name="volume">Volume</string>
+ <string name="left_short">L</string>
+ <string name="right_short">R</string>
+ <string name="audio_effects">Terugmixen</string>
+ <string name="stereo_to_mono">Stereo terugmixen tot monogeluid op beide kanalen</string>
+ <string name="sonic_only">Alleen Sonic</string>
</resources>
diff --git a/core/src/main/res/values-pl-rPL/strings.xml b/core/src/main/res/values-pl-rPL/strings.xml
index c43a5647a..81d9ebec4 100644
--- a/core/src/main/res/values-pl-rPL/strings.xml
+++ b/core/src/main/res/values-pl-rPL/strings.xml
@@ -5,8 +5,11 @@
<string name="feeds_label">Kanały</string>
<string name="add_feed_label">Dodaj podcast</string>
<string name="podcasts_label">PODCASTY</string>
+ <string name="episodes_label">Odcinki</string>
<string name="new_episodes_label">Nowe odcinki</string>
<string name="all_episodes_label">Wszystkie odcinki</string>
+ <string name="all_episodes_short_label">Wszystkie</string>
+ <string name="favorite_episodes_label">Ulubione</string>
<string name="new_label">Nowy</string>
<string name="waiting_list_label">Lista oczekujących</string>
<string name="settings_label">Ustawienia</string>
@@ -25,6 +28,14 @@
<!--Main activity-->
<string name="drawer_open">Otwórz menu</string>
<string name="drawer_close">Zamknij menu</string>
+ <string name="drawer_preferences">Ustawienia panelu</string>
+ <string name="drawer_feed_order_unplayed_episodes">Sortuj wg liczby</string>
+ <string name="drawer_feed_order_alphabetical">Sortuj alfabetycznie</string>
+ <string name="drawer_feed_order_last_update">Sortuj wg daty publikacji</string>
+ <string name="drawer_feed_counter_new_unplayed">Liczba nowych i nieodtworzonych odcinków</string>
+ <string name="drawer_feed_counter_new">Liczba nowych odcinków</string>
+ <string name="drawer_feed_counter_unplayed">Liczba nieodtworzonych odcinków</string>
+ <string name="drawer_feed_counter_none">Brak</string>
<!--Webview actions-->
<string name="open_in_browser_label">Otwórz w przeglądarce</string>
<string name="copy_url_label">Kopiuj adres</string>
@@ -36,6 +47,8 @@
<!--Other-->
<string name="confirm_label">Potwierdź </string>
<string name="cancel_label">Anuluj</string>
+ <string name="yes">Tak</string>
+ <string name="no">Nie</string>
<string name="author_label">Autor</string>
<string name="language_label">Język</string>
<string name="podcast_settings_label">Ustawienia</string>
@@ -52,11 +65,25 @@
<string name="length_prefix">Długość:\u0020</string>
<string name="size_prefix">Rozmiar:\u0020</string>
<string name="processing_label">Przetwarzanie</string>
- <string name="loading_label">Ładowanie...</string>
<string name="save_username_password_label">Zapisz nazwę użytkownika i hasło</string>
<string name="close_label">Zamknij</string>
<string name="retry_label">Spróbuj ponownie</string>
<string name="auto_download_label">Dołącz do automatycznego pobierania</string>
+ <string name="auto_download_apply_to_items_title">Zastosuj do poprzednich odcinków</string>
+ <string name="auto_download_apply_to_items_message">Nowe ustawienie <i>automatycznego pobierania</i> zostanie zastosowane do nowych odcinków.\n Czy chcesz zastosować je także do odcinków opublikowanych wcześniej?</string>
+ <string name="auto_delete_label">Automatyczne usuwanie odcinków\n(nadpisz ustawienia globalne)</string>
+ <string name="parallel_downloads_suffix">\u0020równoległych pobierań</string>
+ <string name="feed_auto_download_global">Globalnie</string>
+ <string name="feed_auto_download_always">Zawsze</string>
+ <string name="feed_auto_download_never">Nigdy</string>
+ <string name="episode_cleanup_never">Nigdy</string>
+ <string name="episode_cleanup_queue_removal">Kiedy nie są w kolejce</string>
+ <string name="episode_cleanup_after_listening">Po odtworzeniu</string>
+ <plurals name="episode_cleanup_days_after_listening">
+ <item quantity="one">1 dzień po odtworzeniu</item>
+ <item quantity="few">%d dni po odtworzeniu</item>
+ <item quantity="other">%d dni po odtworzeniu</item>
+ </plurals>
<!--'Add Feed' Activity labels-->
<string name="feedurl_label">Adres kanału</string>
<string name="etxtFeedurlHint">Adres URL kanału lub strony internetowej</string>
@@ -65,14 +92,27 @@
<string name="podcastdirectories_descr">Możesz wyszukiwać nowe podcasty ze względu na nazwę, kategorię lub popularność na gpodder.net</string>
<string name="browse_gpoddernet_label">Przeglądaj gpodder.net</string>
<!--Actions on feeds-->
- <string name="mark_all_read_label">Oznacz wszystkie jako przeczytane</string>
- <string name="mark_all_read_msg">Wszystkie odcinki zaznaczone jako przeczytane</string>
+ <string name="mark_all_read_label">Oznacz wszystkie jako odtworzone</string>
+ <string name="mark_all_read_msg">Wszystkie odcinki zaznaczono jako odtworzone</string>
+ <string name="mark_all_seen_label">Oznacz wszystkie jako widziane</string>
<string name="show_info_label">Pokaż informacje</string>
<string name="remove_feed_label">Usuń podcast</string>
<string name="share_link_label">Udostępnij stronę</string>
+ <string name="share_link_with_position_label">Udostępnij link z aktualną pozycją</string>
+ <string name="share_feed_url_label">Udostępnij adres kanału</string>
+ <string name="share_item_url_label">Udostępnij adres URL odcinka</string>
+ <string name="share_item_url_with_position_label">Udostępnij adres URL odcinka z aktualną pozycją</string>
<string name="feed_delete_confirmation_msg">Potwierdź chęć usunięcia tego kanału wraz ze WSZYSTKIMI odcinkami, które zostały pobrane.</string>
<string name="feed_remover_msg">Usuwanie kanału</string>
<string name="load_complete_feed">Odśwież cały kanał</string>
+ <string name="hide_episodes_title">Ukryj odcinki</string>
+ <string name="hide_unplayed_episodes_label">Nieodtworzone</string>
+ <string name="hide_paused_episodes_label">Zatrzymane</string>
+ <string name="hide_played_episodes_label">Odtworzone</string>
+ <string name="hide_queued_episodes_label">W kolejce</string>
+ <string name="hide_not_queued_episodes_label">Nie w kolejce</string>
+ <string name="hide_downloaded_episodes_label">Pobrane</string>
+ <string name="hide_not_downloaded_episodes_label">Nie pobrane</string>
<!--actions on feeditems-->
<string name="download_label">Pobierz</string>
<string name="play_label">Odtwórz</string>
@@ -81,15 +121,22 @@
<string name="stream_label">Strumień</string>
<string name="remove_label">Usuń</string>
<string name="remove_episode_lable">Usuń odcinek</string>
- <string name="mark_read_label">Oznacz jako przeczytane</string>
- <string name="mark_unread_label">Oznacz jako nieprzeczytane</string>
+ <string name="mark_read_label">Oznacz jako odtworzone</string>
+ <string name="marked_as_read_label">Oznaczone jako odtworzone</string>
+ <string name="mark_unread_label">Oznacz jako nieodtworzone</string>
<string name="add_to_queue_label">Dodaj do kolejki</string>
+ <string name="added_to_queue_label">Dodano do Kolejki</string>
<string name="remove_from_queue_label">Usuń z kolejki</string>
+ <string name="add_to_favorite_label">Dodaj do Ulubionych</string>
+ <string name="remove_from_favorite_label">Usuń z Ulubionych</string>
<string name="visit_website_label">Odwiedź stronę</string>
<string name="support_label">Wspomóż na Flattr</string>
<string name="enqueue_all_new">Dodaj wszystko do kolejki</string>
<string name="download_all">Pobierz wszystkie</string>
<string name="skip_episode_label">Pomiń odcinek</string>
+ <string name="activate_auto_download">Włącz automatyczne pobieranie</string>
+ <string name="deactivate_auto_download">Wyłącz automatyczne pobieranie</string>
+ <string name="removed_item">Pozycja usunięta</string>
<!--Download messages and labels-->
<string name="download_successful">Operacja zakończona sukcesem</string>
<string name="download_failed">Operacja nie powiodła się</string>
@@ -108,11 +155,11 @@
<string name="cancel_all_downloads_label">Anuluj wszystkie pobierania</string>
<string name="download_canceled_msg">Pobieranie anulowane</string>
<string name="download_report_title">Pobieranie ukończone</string>
+ <string name="download_report_content_title">Raport pobierania</string>
<string name="download_error_malformed_url">Niepoprawny adres</string>
<string name="download_error_io_error">Błąd wejścia/wyjścia</string>
<string name="download_error_request_error">Błąd żądania</string>
<string name="download_error_db_access">Błąd dostępu do bazy danych</string>
- <string name="downloads_left">:\u0020pobrań pozostało</string>
<string name="downloads_processing">Przetwarzanie pobranych</string>
<string name="download_notification_title">Pobieranie danych podcastu</string>
<string name="download_report_content">%1$d pobierania poprawne, %2$d nieudane</string>
@@ -123,6 +170,11 @@
<string name="download_request_error_dialog_message_prefix">Wystąpił błąd przy próbie pobierania:\u0020</string>
<string name="authentication_notification_title">Wymagana autoryzacja</string>
<string name="authentication_notification_msg">Żądany zasób wymaga podania nazwy użytkownika oraz hasła</string>
+ <string name="confirm_mobile_download_dialog_title">Potwierdź pobieranie przez sieć komórkową</string>
+ <string name="confirm_mobile_download_dialog_message_not_in_queue">Pobieranie przez sieć komórkową jest wyłączone w ustawieniach.\n\nMożesz dodać odcinek do kolejki lub tymczasowo zezwolić na pobieranie.\n\n<small>Twój wybór zostanie zapamiętany na 10 minut.</small></string>
+ <string name="confirm_mobile_download_dialog_message">Pobieranie przez sieć komórkową jest wyłączone w ustawieniach.\n\nCzy chcesz tymczasowo zezwolić na pobieranie?\n\n<small>Twój wybór zostanie zapamiętany na 10 minut.</small></string>
+ <string name="confirm_mobile_download_dialog_only_add_to_queue">Dodaj do kolejki</string>
+ <string name="confirm_mobile_download_dialog_enable_temporarily">Zezwól tymczasowo</string>
<!--Mediaplayer messages-->
<string name="player_error_msg">Błąd!</string>
<string name="player_stopped_msg">Żadne media nie odtwarzane </string>
@@ -137,6 +189,8 @@
<string name="playbackservice_notification_title">Odtwarzenie podcastu </string>
<string name="unknown_media_key">AntennaPod - Nieznany klawisz: %1$d</string>
<!--Queue operations-->
+ <string name="lock_queue">Zablokuj Kolejkę</string>
+ <string name="unlock_queue">Odblokuj Kolejkę</string>
<string name="clear_queue_label">Wyczyść kolejkę</string>
<string name="undo">Cofnij</string>
<string name="removed_from_queue">Element usunięty</string>
@@ -148,6 +202,7 @@
<string name="duration">Według długości</string>
<string name="ascending">Rosnąco</string>
<string name="descending">Malejąco</string>
+ <string name="clear_queue_confirmation_msg">Potwierdź usunięcie WSZYSTKICH pozycji z kolejki</string>
<!--Flattr-->
<string name="flattr_auth_label">Logowanie do Flattr</string>
<string name="flattr_auth_explanation">Naciśnij przycisk poniżej by zacząć proces autoryzacji. Zostaniesz przekierowany na stronę logowania do flattr w przeglądarce i zostaniesz poproszony o przyznanie zezwolenia AntennaPod-owi na flattr-owanie. Po daniu zezwolenia powrócisz do tej strony automatycznie.</string>
@@ -187,10 +242,19 @@
<string name="queue_label">Kolejka</string>
<string name="services_label">Usługi</string>
<string name="flattr_label">Flattr</string>
+ <string name="pref_episode_cleanup_title">Usuwanie odcinków</string>
+ <string name="pref_pauseOnDisconnect_sum">Wstrzymaj odtwarzanie po rozłączeniu słuchawek lub Bluetooth</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Wznów odtwarzanie kiedy słuchawki zostaną podłączone ponownie</string>
+ <string name="pref_unpauseOnBluetoothReconnect_sum">Wznów odtwarzanie po przywróceniu połączenia Bluetooth</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Przycisk \'Do przodu\' pomija odcinek</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Przyciśnięcie fizycznego przycisku \'Do przodu\' przeskakuje do następnego odcinka zamiast przewijania</string>
<string name="pref_followQueue_sum">Przeskocz do następnego elementu kolejki po zakończeniu odtwarzania</string>
<string name="pref_auto_delete_sum">Usuń odcinek kiedy jego odtwarzanie zostanie zakończone</string>
<string name="pref_auto_delete_title">Automatyczne usuwanie</string>
+ <string name="pref_smart_mark_as_played_sum">Oznacz odcinek jako odtworzony, jeśli do końca pozostało mniej niż określona ilość czasu</string>
+ <string name="pref_smart_mark_as_played_title">Inteligentnie oznacz jako odtworzone</string>
+ <string name="pref_skip_keeps_episodes_sum">Zachowuje pominięte odcinki w kolejce</string>
+ <string name="pref_skip_keeps_episodes_title">Zachowaj pominięte odcinki</string>
<string name="playback_pref">Odtwarzanie</string>
<string name="network_pref">Sieć</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Pobieraj pliki tylko przez WiFi</string>
@@ -198,6 +262,7 @@
<string name="pref_downloadMediaOnWifiOnly_title">WiFi media pobrane</string>
<string name="pref_pauseOnHeadsetDisconnect_title">Słuchawki odłączone</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Słuchawki podłączone ponownie</string>
+ <string name="pref_unpauseOnBluetoothReconnect_title">Bluetooth podłączony ponownie</string>
<string name="pref_mobileUpdate_title">Aktualizacje mobilne</string>
<string name="pref_mobileUpdate_sum">Zezwól na aktualizacje poprzez sieć komórkową</string>
<string name="refreshing_label">Odświeżanie</string>
@@ -212,11 +277,22 @@
<string name="pref_auto_flattr_sum">Skonfiguruj automatyczne flattr-owanie</string>
<string name="user_interface_label">Interfejs użytkownika</string>
<string name="pref_set_theme_title">Wybierz motyw</string>
+ <string name="pref_nav_drawer_title">Dopasuj panel nawigacyjny</string>
+ <string name="pref_nav_drawer_sum">Dopasuj wygląd panelu nawigacyjnego.</string>
+ <string name="pref_nav_drawer_items_title">Wybierz pozycje panelu nawigacyjnego</string>
+ <string name="pref_nav_drawer_items_sum">Zmienia pozycje widoczne w panelu nawigacyjnym.</string>
+ <string name="pref_nav_drawer_feed_order_title">Ustaw kolejność subskrypcji</string>
+ <string name="pref_nav_drawer_feed_order_sum">Zmień kolejność subskrybowanych kanałów</string>
+ <string name="pref_nav_drawer_feed_counter_title">Ustaw licznik subskrypcji</string>
+ <string name="pref_nav_drawer_feed_counter_sum">Zmień informację wyświetlaną przez licznik subskrypcji</string>
<string name="pref_set_theme_sum">Zmień wygląd AntennaPod.</string>
<string name="pref_automatic_download_title">Automatyczne pobieranie</string>
<string name="pref_automatic_download_sum">Skonfiguruj automatyczne pobieranie odcinków.</string>
<string name="pref_autodl_wifi_filter_title">Włącz filtr Wi-Fi</string>
<string name="pref_autodl_wifi_filter_sum">Zezwól na automatyczne pobieranie tylko dla określonych sieci Wi-Fi.</string>
+ <string name="pref_automatic_download_on_battery_title">Pobieraj, gdy nie ładuje</string>
+ <string name="pref_automatic_download_on_battery_sum">Zezwól na automatyczne pobieranie, gdy bateria nie jest ładowana.</string>
+ <string name="pref_parallel_downloads_title">Liczba równoległych pobierań</string>
<string name="pref_episode_cache_title">Pamięć podręczna odcinków</string>
<string name="pref_theme_title_light">Jasny</string>
<string name="pref_theme_title_dark">Ciemny</string>
@@ -238,7 +314,20 @@
<string name="pref_expandNotify_sum">Zawsze rozwijaj powiadomienie żeby pokazać przyciski odtwarzacza.</string>
<string name="pref_persistNotify_title">Stałe przyciski odtwarzacza</string>
<string name="pref_persistNotify_sum">Utrzymuj powiadomienie i przyciski odtwarzania na ekranie blokady gdy odtwarzanie jest wstrzymane.</string>
+ <string name="pref_lockscreen_background_title">Ustaw tło ekranu blokady</string>
+ <string name="pref_showDownloadReport_title">Pokaż raport z pobierania</string>
+ <string name="pref_showDownloadReport_sum">Jeżeli pobieranie się nie powiedzie, pokaż raport ze szczegółami błędu.</string>
<string name="pref_expand_notify_unsupport_toast">Android starszy niż 4.1 nie wspiera rozszerzonych powiadomień.</string>
+ <string name="pref_queueAddToFront_sum">Dodaj nowe odcinki na początku kolejki.</string>
+ <string name="pref_queueAddToFront_title">Dodaj na początku</string>
+ <string name="pref_smart_mark_as_played_disabled">Wyłączone</string>
+ <string name="pref_image_cache_size_title">Pamięć podręczna obrazów</string>
+ <string name="pref_image_cache_size_sum">Rozmiar przestrzeni na dysku dla pamięci podręcznej obrazów</string>
+ <string name="crash_report_title">Raport o błędach</string>
+ <string name="crash_report_sum">Wyślij ostatni raport o błędach przez e-mail</string>
+ <string name="send_email">Wyślij e-mail</string>
+ <string name="experimental_pref">Eksperymentalne</string>
+ <string name="pref_sonic_title">Odtwarzacz mediów Sonic</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Włącz automatyczne wspieranie na flattr.</string>
<string name="auto_flattr_after_percent">Z-flattr-uj odcinki odegrane %d procentach.</string>
@@ -253,6 +342,7 @@
<string name="found_in_title_label">Znaleziono w tytułach</string>
<!--OPML import and export-->
<string name="opml_import_txtv_button_lable">Pliki OPML pozwalają na przenoszenie podcastów między aplikacjami.</string>
+ <string name="opml_import_explanation_2">Użyj zewnętrznej aplikacji takiej jak Dropbox, Google Drive lub ulubionego menedżera plików, aby otworzyć plik OPML.</string>
<string name="start_import_label">Rozpocznij import</string>
<string name="opml_import_label">Import OPML</string>
<string name="opml_directory_error">BŁĄD!</string>
@@ -261,8 +351,8 @@
<string name="opml_import_error_dir_empty">Katalog importowania jest pusty.</string>
<string name="select_all_label">Zaznacz wszystko</string>
<string name="deselect_all_label">Odznacz wszystko</string>
+ <string name="choose_file_from_external_application">Użyj zewnętrznej aplikacji</string>
<string name="opml_export_label">Eksport OPML</string>
- <string name="exporting_label">Eksportowanie...</string>
<string name="export_error_label">Błąd eksportu</string>
<string name="opml_export_success_title">Eksport OPML udany.</string>
<string name="opml_export_success_sum">Plik .opml został zapisany do:\u0020</string>
@@ -273,6 +363,27 @@
<string name="sleep_timer_label">Wyłącznik czasowy</string>
<string name="time_left_label">Pozostały czas:\u0020</string>
<string name="time_dialog_invalid_input">Błąd wpisu, czas musi być liczbą całkowitą</string>
+ <string name="timer_about_to_expire_label"><b>Kiedy odliczanie dobiega końca:</b></string>
+ <string name="shake_to_reset_label">Potrząśnij, aby zresetować odliczanie</string>
+ <string name="timer_vibration_label">Wibruj</string>
+ <string name="time_seconds">sekund</string>
+ <string name="time_minutes">minut</string>
+ <string name="time_hours">godzin</string>
+ <plurals name="time_seconds_quantified">
+ <item quantity="one">1 sekunda</item>
+ <item quantity="few">%d sekundy</item>
+ <item quantity="other">%d sekund</item>
+ </plurals>
+ <plurals name="time_minutes_quantified">
+ <item quantity="one">1 minuta</item>
+ <item quantity="few">%d minuty</item>
+ <item quantity="other">%d minut</item>
+ </plurals>
+ <plurals name="time_hours_quantified">
+ <item quantity="one">1 godzina</item>
+ <item quantity="few">%d godziny</item>
+ <item quantity="other">%d godzin</item>
+ </plurals>
<!--gpodder.net-->
<string name="gpodnet_taglist_header">KATEGORIE</string>
<string name="gpodnet_toplist_header">TOP PODCASTY</string>
@@ -306,20 +417,26 @@ https://gpodder.net/register/</string>
<string name="selected_folder_label">Wybrany folder:</string>
<string name="create_folder_label">Utwórz folder</string>
<string name="choose_data_directory">Wybierz folder danych</string>
+ <string name="choose_data_directory_message">Wybierz główny folder dla danych. AntennaPod utworzy odpowiednie podkatalogi.</string>
<string name="create_folder_msg">Utworzyć nowy folder o nazwie \"%1$s\"?</string>
<string name="create_folder_success">Utworzono nowy folder</string>
<string name="create_folder_error_no_write_access">Nie można zapisać do tego folderu</string>
<string name="create_folder_error_already_exists">Folder już istnieje</string>
<string name="create_folder_error">Nie można utworzyć folderu</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" nie istnieje</string>
+ <string name="folder_not_readable_error">\"%1$s\" nie może być odczytany</string>
+ <string name="folder_not_writable_error">\"%1$s\" nie może być zapisany</string>
<string name="folder_not_empty_dialog_title">Folder nie jest pusty</string>
<string name="folder_not_empty_dialog_msg">Wybrany folder nie jest pusty. Pobierane media i inne pliki będą umieszczane bezpośrednio w folderze, czy kontynuować?</string>
<string name="set_to_default_folder">Wybierz domyślny folder</string>
<string name="pref_pausePlaybackForFocusLoss_sum">Wstrzymaj odtwarzanie zamiast wyciszenia jeśli inna aplikacja chce odtworzyć dźwięk.</string>
<string name="pref_pausePlaybackForFocusLoss_title">Wstrzymaj przy przerwaniu</string>
+ <string name="pref_resumeAfterCall_sum">Wznów odtwarzanie po zakończeniu połączenia telefonicznego</string>
+ <string name="pref_resumeAfterCall_title">Wznów po połączeniu</string>
+ <string name="pref_restart_required">AntennaPod musi zostać uruchomiony ponownie, by zmiany odniosły skutek.</string>
<!--Online feed view-->
<string name="subscribe_label">Subskrybuj</string>
<string name="subscribed_label">Subskrybowane</string>
- <string name="downloading_label">Pobieranie...</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Pokaż rozdziały</string>
<string name="show_shownotes_label">Pokaż opis odcinka</string>
@@ -343,7 +460,33 @@ https://gpodder.net/register/</string>
<string name="authentication_label">Autoryzacja</string>
<string name="authentication_descr">Zmień swoją nazwę użytkownika oraz hasło dla tego podcastu i jego odcinków</string>
<!--Progress information-->
+ <string name="progress_upgrading_database">Aktualizacja bazy danych</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Importowanie subskrybcji z jednozadaniowych aplikacji</string>
+ <string name="search_itunes_label">Szukaj w iTunes</string>
+ <string name="all_label">Wszystkie</string>
+ <string name="selected_all_label">Zaznaczono wszystkie odcinki</string>
+ <string name="none_label">Brak</string>
+ <string name="deselected_all_label">Odznaczono wszystkie odcinki</string>
+ <string name="played_label">Odtworzone</string>
+ <string name="selected_played_label">Zaznaczono odtworzone odcinki</string>
+ <string name="unplayed_label">Nieodtworzone</string>
+ <string name="selected_unplayed_label">Zaznaczono nieodtworzone odcinki</string>
+ <string name="downloaded_label">Pobrane</string>
+ <string name="selected_downloaded_label">Zaznaczono pobrane odcinki</string>
+ <string name="not_downloaded_label">Nie pobrane</string>
+ <string name="selected_not_downloaded_label">Zaznaczono niepobrane odcinki</string>
+ <string name="sort_title_a_z">Tytuł (A \u2192 Z)</string>
+ <string name="sort_title_z_a">Tytuł (Z \u2192 A)</string>
+ <string name="sort_date_new_old">Data (Nowe \u2192 Stare)</string>
+ <string name="sort_date_old_new">Data (Stare \u2192 Nowe)</string>
+ <string name="sort_duration_short_long">Długość (Krótkie \u2192 Długie)</string>
+ <string name="sort_duration_long_short">Długość (Długie \u2192 Krótkie)</string>
<!--Rating dialog-->
+ <string name="rating_title">Podoba Ci się AntennaPod?</string>
+ <string name="rating_message">Bylibyśmy wdzięczni, jeśli poświęciłbyś chwilę aby ocenić AntennaPod.</string>
+ <string name="rating_never_label">Daj mi spokój</string>
+ <string name="rating_later_label">Przypomnij później</string>
+ <string name="rating_now_label">Pewnie, zróbmy to!</string>
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-pt-rBR/strings.xml b/core/src/main/res/values-pt-rBR/strings.xml
index c57f20177..95b279022 100644
--- a/core/src/main/res/values-pt-rBR/strings.xml
+++ b/core/src/main/res/values-pt-rBR/strings.xml
@@ -53,7 +53,6 @@
<string name="length_prefix">Duração:\u0020</string>
<string name="size_prefix">Tamanho:\u0020</string>
<string name="processing_label">Processando</string>
- <string name="loading_label">Carregando...</string>
<string name="save_username_password_label">Salvar nome do usuário e senha</string>
<string name="close_label">Fechar</string>
<string name="retry_label">Tentar novamente</string>
@@ -69,7 +68,6 @@
<string name="mark_all_seen_label">Marcar todos como lido</string>
<string name="show_info_label">Mostrar informação</string>
<string name="remove_feed_label">Remover Podcast</string>
- <string name="share_label">Compartilhar...</string>
<string name="share_link_label">Compartilhar link do site</string>
<string name="share_link_with_position_label">Compartilhar link com posição</string>
<string name="share_item_url_label">Compartilhar url do episódio</string>
@@ -124,7 +122,6 @@
<string name="download_error_io_error">Erro de IO</string>
<string name="download_error_request_error">Erro de requisição</string>
<string name="download_error_db_access">Erro no acesso ao Banco de dados</string>
- <string name="downloads_left">\u0020Downloads restantes</string>
<string name="downloads_processing">Processando downloads</string>
<string name="download_notification_title">Baixando dados do podcast</string>
<string name="download_report_content">%1$d downloads com sucesso, %2$d falharam</string>
@@ -244,9 +241,7 @@
<string name="opml_import_error_dir_empty">O diretório de importação está vazio.</string>
<string name="select_all_label">Selecionar todos</string>
<string name="deselect_all_label">Remover seleção</string>
- <string name="select_options_label">Selecionar</string>
<string name="opml_export_label">Exportar OPML</string>
- <string name="exporting_label">Exportando...</string>
<string name="export_error_label">Erro na exportação</string>
<string name="opml_export_success_sum">O arquivo .opml foi gravado em:\u0020</string>
<!--Sleep timer-->
@@ -304,7 +299,6 @@
<!--Online feed view-->
<string name="subscribe_label">Assinar</string>
<string name="subscribed_label">Assinado</string>
- <string name="downloading_label">Baixando...</string>
<!--Content descriptions for image buttons-->
<string name="show_cover_label">Mostrar imagem</string>
<string name="butAction_label">Mais ações</string>
@@ -317,4 +311,5 @@
<!--Progress information-->
<!--AntennaPodSP-->
<!--Rating dialog-->
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-pt/strings.xml b/core/src/main/res/values-pt/strings.xml
index 16c909d78..ebea5f391 100644
--- a/core/src/main/res/values-pt/strings.xml
+++ b/core/src/main/res/values-pt/strings.xml
@@ -10,19 +10,21 @@
<string name="all_episodes_label">Todos os episódios</string>
<string name="all_episodes_short_label">Todos</string>
<string name="favorite_episodes_label">Favoritos</string>
- <string name="new_label">Novo</string>
+ <string name="new_label">Novos</string>
<string name="waiting_list_label">Lista de espera</string>
<string name="settings_label">Definições</string>
<string name="add_new_feed_label">Adicionar podcast</string>
- <string name="downloads_label">Transferências</string>
+ <string name="downloads_label">Descargas</string>
<string name="downloads_running_label">Em curso</string>
- <string name="downloads_completed_label">Terminadas</string>
+ <string name="downloads_completed_label">Terminada</string>
<string name="downloads_log_label">Registo</string>
- <string name="cancel_download_label">Cancelar\ntransferência</string>
+ <string name="cancel_download_label">Cancelar\ndescarga</string>
<string name="playback_history_label">Histórico de reprodução</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">Dados gpodder.net</string>
- <string name="free_space_label">%1$s livre</string>
+ <string name="free_space_label">%1$s disponível</string>
+ <string name="episode_cache_full_title">Cache de episódios cheia</string>
+ <string name="episode_cache_full_message">Atingido o limite máximo de itens em cache. Pode aumentar o tamanho de cache nas definições.</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Publicados recentemente</string>
<string name="episode_filter_label">Mostrar apenas novos episódios</string>
@@ -46,7 +48,7 @@
<!--Playback history-->
<string name="clear_history_label">Limpar histórico</string>
<!--Other-->
- <string name="confirm_label">Confirmar</string>
+ <string name="confirm_label">Confirmação</string>
<string name="cancel_label">Cancelar</string>
<string name="yes">Sim</string>
<string name="no">Não</string>
@@ -71,11 +73,11 @@
<string name="save_username_password_label">Guardar utilizador e palavra-passe</string>
<string name="close_label">Fechar</string>
<string name="retry_label">Tentar novamente</string>
- <string name="auto_download_label">Incluir nas transferências automáticas</string>
+ <string name="auto_download_label">Incluir nas descargas automáticas</string>
<string name="auto_download_apply_to_items_title">Aplicar aos episódios anteriores</string>
- <string name="auto_download_apply_to_items_message">A definição <i>Transferência automática</i> será aplicada a todos os novos episódios.\nGostaria de também a aplicar aos episódios anteriores?</string>
- <string name="auto_delete_label">Apagar episódio automáticamente\n(altera a definição global)</string>
- <string name="parallel_downloads_suffix">\u0020transferências simultâneas</string>
+ <string name="auto_download_apply_to_items_message">A definição <i>Descarga automática</i> será aplicada a todos os novos episódios.\nGostaria de também a aplicar aos episódios anteriores?</string>
+ <string name="auto_delete_label">Apagar episódio automaticamente\n(altera a definição global)</string>
+ <string name="parallel_downloads_suffix">\u0020descargas simultâneas</string>
<string name="feed_auto_download_global">Global</string>
<string name="feed_auto_download_always">Sempre</string>
<string name="feed_auto_download_never">Nunca</string>
@@ -108,7 +110,7 @@
<string name="share_feed_url_label">Partilhar URL da fonte</string>
<string name="share_item_url_label">Partilhar URL do episódio</string>
<string name="share_item_url_with_position_label">Partilhar URL do episódio com posição</string>
- <string name="feed_delete_confirmation_msg">Por favor confirme que deseja apagar esta fonte e todos os episódios transferidos</string>
+ <string name="feed_delete_confirmation_msg">Confirma a remoção desta fonte e de todos os episódios descarregados?</string>
<string name="feed_remover_msg">Remover fonte</string>
<string name="load_complete_feed">Atualizar todas as páginas da fonte</string>
<string name="hide_episodes_title">Ocultar episódios</string>
@@ -118,12 +120,12 @@
<string name="hide_played_episodes_label">Reproduzidos</string>
<string name="hide_queued_episodes_label">Na fila</string>
<string name="hide_not_queued_episodes_label">Não na fila</string>
- <string name="hide_downloaded_episodes_label">Transferidos</string>
- <string name="hide_not_downloaded_episodes_label">Não transferidos</string>
+ <string name="hide_downloaded_episodes_label">Descarregados</string>
+ <string name="hide_not_downloaded_episodes_label">Não descarregados</string>
<string name="filtered_label">Filtrados</string>
<string name="refresh_failed_msg">{fa-exclamation-circle} Última atualização falhada</string>
<!--actions on feeditems-->
- <string name="download_label">Transferir</string>
+ <string name="download_label">Descarregar</string>
<string name="play_label">Reproduzir</string>
<string name="pause_label">Pausa</string>
<string name="stop_label">Parar</string>
@@ -137,21 +139,23 @@
<string name="added_to_queue_label">Adicionado à fila</string>
<string name="remove_from_queue_label">Remover da fila</string>
<string name="add_to_favorite_label">Adicionar aos favoritos</string>
+ <string name="added_to_favorites">Adicionado aos favoritos</string>
<string name="remove_from_favorite_label">Remover dos favoritos</string>
+ <string name="removed_from_favorites">Removido dos favoritos</string>
<string name="visit_website_label">Aceder ao sítio web</string>
<string name="support_label">Flattr</string>
<string name="enqueue_all_new">Colocar tudo na fila</string>
- <string name="download_all">Transferir tudo</string>
+ <string name="download_all">Descarregar tudo</string>
<string name="skip_episode_label">Ignorar episódio</string>
- <string name="activate_auto_download">Ativar transferência automática</string>
- <string name="deactivate_auto_download">Desativar transferência automática</string>
+ <string name="activate_auto_download">Ativar descarga automática</string>
+ <string name="deactivate_auto_download">Desativar descarga automática</string>
<string name="reset_position">Repor posição de reprodução</string>
<string name="removed_item">Item removido</string>
<!--Download messages and labels-->
<string name="download_successful">sucesso</string>
<string name="download_failed">falha</string>
- <string name="download_pending">Transferência pendente</string>
- <string name="download_running">Transferência atual</string>
+ <string name="download_pending">Descarga pendente</string>
+ <string name="download_running">Descarga atual</string>
<string name="download_error_device_not_found">Cartão SD não encontrado</string>
<string name="download_error_insufficient_space">Espaço insuficiente</string>
<string name="download_error_file_error">Erro no ficheiro</string>
@@ -162,29 +166,32 @@
<string name="download_error_connection_error">Erro de ligação</string>
<string name="download_error_unknown_host">Servidor desconhecido</string>
<string name="download_error_unauthorized">Erro de autenticação</string>
- <string name="cancel_all_downloads_label">Cancelar transferências</string>
- <string name="download_canceled_msg">Transferência cancelada</string>
- <string name="download_canceled_autodownload_enabled_msg">Transferência cancelada\n<i>Transferência automática</i> desativada para este item</string>
- <string name="download_report_title">Transferências terminadas com erros</string>
- <string name="download_report_content_title">Relatório de transferências</string>
+ <string name="cancel_all_downloads_label">Cancelar descargas</string>
+ <string name="download_canceled_msg">Descarga cancelada</string>
+ <string name="download_canceled_autodownload_enabled_msg">Descarga cancelada\n<i>Descarga automática</i> desativada para este item</string>
+ <string name="download_report_title">Descargas terminadas com erros</string>
+ <string name="download_report_content_title">Relatório de descargas</string>
<string name="download_error_malformed_url">URL inválido</string>
<string name="download_error_io_error">Erro I/O</string>
<string name="download_error_request_error">Erro de pedido</string>
<string name="download_error_db_access">Erro de acesso à base de dados</string>
- <string name="downloads_left">\u0020Transferências em falta</string>
- <string name="downloads_processing">Processamento de transferências</string>
- <string name="download_notification_title">A transferir dados do podcast</string>
- <string name="download_report_content">%1$d transferências efetuadas, %2$d falhadas</string>
+ <plurals name="downloads_left">
+ <item quantity="one">%d descarga em curso</item>
+ <item quantity="other">%d descargas em curso</item>
+ </plurals>
+ <string name="downloads_processing">Processamento de descargas</string>
+ <string name="download_notification_title">A descarregar dados do podcast</string>
+ <string name="download_report_content">%1$d descargas efetuadas, %2$d falhadas</string>
<string name="download_log_title_unknown">Título desconhecido</string>
<string name="download_type_feed">Fonte</string>
<string name="download_type_media">Ficheiro multimédia</string>
<string name="download_type_image">Imagem</string>
- <string name="download_request_error_dialog_message_prefix">Ocorreu um erro ao transferir o ficheiro:\u0020</string>
+ <string name="download_request_error_dialog_message_prefix">Ocorreu um erro ao tentar descarregar o ficheiro:\u0020</string>
<string name="authentication_notification_title">Requer autenticação</string>
<string name="authentication_notification_msg">O recurso solicitado requer um utilizador e uma palavra-passe</string>
- <string name="confirm_mobile_download_dialog_title">Confirmação de transferência</string>
- <string name="confirm_mobile_download_dialog_message_not_in_queue">A transferência através de dados móveis está desativada nas definições.\n\nAtivar temporariamente ou apenas adicionar à fila?\n\n<small>A sua decisão será memorizada durante 10 minutos.</small></string>
- <string name="confirm_mobile_download_dialog_message">A transferência através de dados móveis está desativada nas definições.\n\nAtivar temporariamente?\n\n<small>A sua decisão será memorizada durante 10 minutos.</small></string>
+ <string name="confirm_mobile_download_dialog_title">Confirmação de descarga</string>
+ <string name="confirm_mobile_download_dialog_message_not_in_queue">A descarga através de dados móveis está desativada nas definições.\n\nAtivar temporariamente ou apenas adicionar à fila?\n\n<small>A sua decisão será memorizada durante 10 minutos.</small></string>
+ <string name="confirm_mobile_download_dialog_message">A descarga através de dados móveis está desativada nas definições.\n\nAtivar temporariamente?\n\n<small>A sua decisão será memorizada durante 10 minutos.</small></string>
<string name="confirm_mobile_download_dialog_only_add_to_queue">Apenas adicionados à fila</string>
<string name="confirm_mobile_download_dialog_enable_temporarily">Ativar temporariamente</string>
<!--Mediaplayer messages-->
@@ -203,6 +210,8 @@
<!--Queue operations-->
<string name="lock_queue">Bloquear fila</string>
<string name="unlock_queue">Desbloquear fila</string>
+ <string name="queue_locked">Fila bloqueada</string>
+ <string name="queue_unlocked">Fila desbloqueada</string>
<string name="clear_queue_label">Limpar fila</string>
<string name="undo">Anular</string>
<string name="removed_from_queue">Item removido</string>
@@ -242,14 +251,15 @@
<string name="flattrd_failed_label">O AntennaPod não fez o flattr</string>
<string name="flattr_retrieving_status">A obter itens com flattr</string>
<!--Variable Speed-->
- <string name="download_plugin_label">Transferir extra</string>
+ <string name="download_plugin_label">Descarregar extra</string>
<string name="no_playback_plugin_title">Extra não instalado</string>
- <string name="no_playback_plugin_or_sonic_msg">Para que a velocidade variável de reprodução funcione, tem que instalar um biblioteca de terceiros ou ativar o reprodutor Sonic [Android 4.1+].\n\nClique em \'Transferir extra\' para a transferir no Google Play.\n\nQuaisquer erros que ocorram na utilização do extra não são da responsabilidade do AntennaPod e devem ser reportados diretamente ao seu programador.</string>
+ <string name="no_playback_plugin_or_sonic_msg">Para que a velocidade variável de reprodução funcione, recomendamos que ative o Sonic Media Player incorporado [Android 4.1+].\n\nEm alternativa, pode transferir o extra <i>Prestissimo</i>, disponível na Google Play.\nQuaisquer problemas que ocorram com o Prestissimo não são da responsabilidade dos programadores do AntennaPod e devem ser reportados ao dono do extra.</string>
<string name="set_playback_speed_label">Velocidades de reprodução</string>
<string name="enable_sonic">Ativar Sonic</string>
<!--Empty list labels-->
<string name="no_items_label">Não existem itens nesta lista</string>
<string name="no_feeds_label">Ainda não possui quaisquer fontes</string>
+ <string name="no_chapters_label">Este episódio não tem capítulos.</string>
<!--Preferences-->
<string name="other_pref">Outras</string>
<string name="about_pref">Sobre</string>
@@ -257,18 +267,18 @@
<string name="services_label">Serviços</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Limpeza de episódios</string>
- <string name="pref_episode_cleanup_summary">Os episódios que não estiverem na fila ou que não sejam favoritos são elegiveis para remoção se necessitar de espaço</string>
+ <string name="pref_episode_cleanup_summary">Os episódios que não estejam na fila e não sejam favoritos podem ser elegíveis para serem removidos se a Descarga automática necessitar de espaço para novos episódios.</string>
<string name="pref_pauseOnDisconnect_sum">Pausa na reprodução ao desligar os auscultadores ou o bluetooth</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Continuar reprodução ao ligar os auscultadores</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Continuar reprodução ao estabelecer a ligação bluetooth</string>
- <string name="pref_hardwareForwardButtonSkips_title">Botão de avançar ignora</string>
- <string name="pref_hardwareForwardButtonSkips_sum">Ao premir o botão Avançar, avança para o episódio seguinte em vez de avançar</string>
- <string name="pref_followQueue_sum">Ir para a faixa seguinte ao terminar a reprodução</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Botão para avançar</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Ao premir o botão Avançar, ir para o episódio seguinte em vez de avançar a reprodução</string>
+ <string name="pref_followQueue_sum">Ir para a episódio seguinte ao terminar a reprodução</string>
<string name="pref_auto_delete_sum">Apagar episódio ao terminar a reprodução</string>
<string name="pref_auto_delete_title">Eliminação automática</string>
- <string name="pref_smart_mark_as_played_sum">Marcar episódios como reproduzidos mesmo que restem alguns segundos de reprodução</string>
+ <string name="pref_smart_mark_as_played_sum">Marcar episódio como reproduzido mesmo que restem alguns segundos de reprodução</string>
<string name="pref_smart_mark_as_played_title">Marcar como reproduzido (inteligente)</string>
- <string name="pref_skip_keeps_episodes_sum">Manter episódio mesmo se forem ignorados</string>
+ <string name="pref_skip_keeps_episodes_sum">Manter episódios mesmo que tenham sido ignorados</string>
<string name="pref_skip_keeps_episodes_title">Manter episódios ignorados</string>
<string name="playback_pref">Reprodução</string>
<string name="network_pref">Rede</string>
@@ -278,9 +288,11 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">Desativar</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Definir intervalo</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Definir hora do dia</string>
- <string name="pref_downloadMediaOnWifiOnly_sum">Apenas transferir através de redes sem fios</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">a cada %1$s</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">às %1$s</string>
+ <string name="pref_downloadMediaOnWifiOnly_sum">Apenas descarregar através de redes sem fios</string>
<string name="pref_followQueue_title">Reprodução contínua</string>
- <string name="pref_downloadMediaOnWifiOnly_title">Transferir por Wi-Fi</string>
+ <string name="pref_downloadMediaOnWifiOnly_title">Descarregar por Wi-Fi</string>
<string name="pref_pauseOnHeadsetDisconnect_title">Auscultadores removidos</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Auscultadores inseridos</string>
<string name="pref_unpauseOnBluetoothReconnect_title">Ligação bluetooth</string>
@@ -298,7 +310,7 @@
<string name="pref_auto_flattr_sum">Configurar flattr automático</string>
<string name="user_interface_label">Interface</string>
<string name="pref_set_theme_title">Tema</string>
- <string name="pref_nav_drawer_title">Personalizar menu de navegação</string>
+ <string name="pref_nav_drawer_title">Menu de navegação</string>
<string name="pref_nav_drawer_sum">Personalizar a aparência do menu de navegação</string>
<string name="pref_nav_drawer_items_title">Alterar elementos do menu</string>
<string name="pref_nav_drawer_items_sum">Alterar os itens que aparecem no menu de navegação</string>
@@ -307,13 +319,13 @@
<string name="pref_nav_drawer_feed_counter_title">Definir contador de subscrições</string>
<string name="pref_nav_drawer_feed_counter_sum">Alterar a informação mostrada no contador de subscrições</string>
<string name="pref_set_theme_sum">Alterar a aparência do AntennaPod</string>
- <string name="pref_automatic_download_title">Transferência automática</string>
- <string name="pref_automatic_download_sum">Configure a transferência automática dos episódios</string>
+ <string name="pref_automatic_download_title">Descarga automática</string>
+ <string name="pref_automatic_download_sum">Configure a descarga automática dos episódios</string>
<string name="pref_autodl_wifi_filter_title">Ativar filtro Wi-Fi</string>
- <string name="pref_autodl_wifi_filter_sum">Apenas permitir transferências automáticas através de redes sem fios</string>
- <string name="pref_automatic_download_on_battery_title">Transferir se não estiver a carregar</string>
- <string name="pref_automatic_download_on_battery_sum">Permitir transferência automática se a bateria não estiver a ser carregada</string>
- <string name="pref_parallel_downloads_title">Transferências simultâneas</string>
+ <string name="pref_autodl_wifi_filter_sum">Apenas permitir descargas automáticas através de redes sem fios</string>
+ <string name="pref_automatic_download_on_battery_title">Descarregar se não estiver a carregar</string>
+ <string name="pref_automatic_download_on_battery_sum">Permitir descarga automática se a bateria não estiver a ser carregada</string>
+ <string name="pref_parallel_downloads_title">Descargas simultâneas</string>
<string name="pref_episode_cache_title">Cache de episódios</string>
<string name="pref_theme_title_light">Claro</string>
<string name="pref_theme_title_dark">Escuro</string>
@@ -335,15 +347,15 @@
<string name="pref_gpodnet_sethostname_use_default_host">Utilizar predefinições</string>
<string name="pref_expandNotify_title">Expansão de notificação</string>
<string name="pref_expandNotify_sum">Expandir sempre a notificação para mostrar os botões de reprodução</string>
- <string name="pref_persistNotify_title">Controlos de reprodução persistentes</string>
+ <string name="pref_persistNotify_title">Controlos de reprodução</string>
<string name="pref_persistNotify_sum">Manter controlos de notificação e ecrã de bloqueio ao colocar a reprodução em pausa</string>
<string name="pref_lockscreen_background_title">Definir fundo do ecrã de bloqueio</string>
<string name="pref_lockscreen_background_sum">Define a imagem do episódio como fundo do ecrã de bloqueio. Efeito colateral: também será mostrada em outras aplicações</string>
<string name="pref_showDownloadReport_title">Mostrar relatório de erros</string>
- <string name="pref_showDownloadReport_sum">Se a transferência falhar, gera um relatório que mostra os detalhes do erro</string>
+ <string name="pref_showDownloadReport_sum">Se a descarga falhar, gera um relatório que mostra os detalhes do erro</string>
<string name="pref_expand_notify_unsupport_toast">As versões Android anteriores à 4.1 não possuem suporte à expansão de notificações</string>
- <string name="pref_queueAddToFront_sum">Colocar novos episódios no inicio da fila</string>
- <string name="pref_queueAddToFront_title">Novos episódios no inicio</string>
+ <string name="pref_queueAddToFront_sum">Colocar novos episódios no início da fila</string>
+ <string name="pref_queueAddToFront_title">Novos episódios no início</string>
<string name="pref_smart_mark_as_played_disabled">Desativada</string>
<string name="pref_image_cache_size_title">Cache de imagens</string>
<string name="pref_image_cache_size_sum">O tamanho da cache de imagens</string>
@@ -352,7 +364,8 @@
<string name="send_email">Enviar e-mail</string>
<string name="experimental_pref">Experimental</string>
<string name="pref_sonic_title">Reprodutor Sonic</string>
- <string name="pref_sonic_message">Utilizar reprodutor multimédia Sonic como substituto de Prestissimo</string>
+ <string name="pref_sonic_message">Utilizar o Sonic Media Player como substituto do reprodutor nativo do Android e do Prestissimo</string>
+ <string name="pref_current_value">Valor atual: %1$s</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Ativar flattr automático</string>
<string name="auto_flattr_after_percent">Flattr de episódios ao atingir %d porcento de reprodução</string>
@@ -383,10 +396,11 @@
<string name="choose_file_from_filesystem">Do sistema local de ficheiros</string>
<string name="choose_file_from_external_application">Utilizar aplicação externa</string>
<string name="opml_export_label">Exportação OPML</string>
- <string name="exporting_label">Exportação...</string>
+ <string name="exporting_label">A exportar...</string>
<string name="export_error_label">Erro de exportação</string>
<string name="opml_export_success_title">Exportação efetuada</string>
<string name="opml_export_success_sum">O ficheiro .opml foi guardado em:\u0020</string>
+ <string name="opml_import_ask_read_permission">Requer acesso ao armazenamento externo para ler o ficheiro OPML</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Definir temporizador</string>
<string name="disable_sleeptimer_label">Desativar temporizador</string>
@@ -445,6 +459,7 @@
<string name="create_folder_label">Criar pasta</string>
<string name="choose_data_directory">Escolha a pasta de dados</string>
<string name="choose_data_directory_message">Escolha a base da pasta de dados. O AntennaPod irá criar as subpastas apropriadas.</string>
+ <string name="choose_data_directory_permission_rationale">Para alterar a pasta de dados, tem que ter acesso ao armazenamento externo</string>
<string name="create_folder_msg">Criar uma pasta com o nome \"%1$s\"?</string>
<string name="create_folder_success">Nova pasta criada</string>
<string name="create_folder_error_no_write_access">Não é possível guardar nesta pasta</string>
@@ -454,7 +469,7 @@
<string name="folder_not_readable_error">\"%1$s\" não permite leitura</string>
<string name="folder_not_writable_error">\"%1$s\" não permite escrita</string>
<string name="folder_not_empty_dialog_title">A pasta não está vazia</string>
- <string name="folder_not_empty_dialog_msg">A pasta escolhida não está vazia. As transferências multimédia e os ficheiros serão colocados nesta pasta. Continuar?</string>
+ <string name="folder_not_empty_dialog_msg">A pasta escolhida não está vazia. Os dados multimédia e os outros ficheiros serão colocados nesta pasta. Continuar?</string>
<string name="set_to_default_folder">Escolha a pasta pré-definida</string>
<string name="pref_pausePlaybackForFocusLoss_sum">Pausa na reprodução em vez de baixar o volume se outra aplicação quiser reproduzir sons</string>
<string name="pref_pausePlaybackForFocusLoss_title">Pausa nas interrupções</string>
@@ -464,7 +479,7 @@
<!--Online feed view-->
<string name="subscribe_label">Subscrever</string>
<string name="subscribed_label">Subscrito</string>
- <string name="downloading_label">A transferir...</string>
+ <string name="downloading_label">A descarregar...</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Mostrar capítulos</string>
<string name="show_shownotes_label">Mostrar notas</string>
@@ -476,8 +491,8 @@
<string name="navigate_upwards_label">Navegar para cima</string>
<string name="butAction_label">Mais ações</string>
<string name="status_playing_label">Episódio em reprodução</string>
- <string name="status_downloading_label">Episódio a ser transferido</string>
- <string name="status_downloaded_label">Episódio transferido</string>
+ <string name="status_downloading_label">Episódio a ser descarregado</string>
+ <string name="status_downloaded_label">Episódio descarregado</string>
<string name="status_unread_label">Novo item</string>
<string name="in_queue_label">Episódio está na fila</string>
<string name="new_episodes_count_label">Número de novos episódios</string>
@@ -487,12 +502,20 @@
<!--Feed information screen-->
<string name="authentication_label">Autenticação</string>
<string name="authentication_descr">Altere o seu nome de utilizador e palavra-passe para este podcast e seus episódios</string>
+ <string name="auto_download_settings_label">Definições de descarga automática</string>
+ <string name="episode_filters_label">Filtro de episódios</string>
+ <string name="episode_filters_description">Lista de termos utilizados para determinar se um episódio deve ser incluído ou excluído das descargas automáticas</string>
+ <string name="episode_filters_include">Incluir</string>
+ <string name="episode_filters_exclude">Excluir</string>
+ <string name="episode_filters_hint">Uma palavra\n\"Várias palavras\"</string>
+ <string name="keep_updated">Manter atualizada</string>
<!--Progress information-->
<string name="progress_upgrading_database">Atualizando base de dados</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Importar subscrições de aplicações single-purpose...</string>
<string name="search_itunes_label">Procurar no iTunes</string>
<string name="select_label"><b>Selecionar...</b></string>
+ <string name="filter">Filtro</string>
<string name="all_label">Todos</string>
<string name="selected_all_label">Marcar todos os episódios</string>
<string name="none_label">Nenhum</string>
@@ -501,11 +524,15 @@
<string name="selected_played_label">Selecionar episódios reproduzidos</string>
<string name="unplayed_label">Não reproduzidos</string>
<string name="selected_unplayed_label">Selecionar episódios não reproduzidos</string>
- <string name="downloaded_label">Transferidos</string>
- <string name="selected_downloaded_label">Selecionar episódios transferidos</string>
- <string name="not_downloaded_label">Não transferidos</string>
- <string name="selected_not_downloaded_label">Selecionar episódios não transferidos</string>
- <string name="sort_title"><b>Ordenar por...</b></string>
+ <string name="downloaded_label">Descarregados</string>
+ <string name="selected_downloaded_label">Selecionar episódios descarregados</string>
+ <string name="not_downloaded_label">Não descarregados</string>
+ <string name="selected_not_downloaded_label">Selecionar episódios não descarregados</string>
+ <string name="queued_label">Na fila</string>
+ <string name="selected_queued_label">Episódios selecionados na fila</string>
+ <string name="not_queued_label">Não na fila</string>
+ <string name="selected_not_queued_label">Episódios não selecionados na fila</string>
+ <string name="sort_title"><b>Ordenar por…</b></string>
<string name="sort_title_a_z">Título (A \u2192 Z)</string>
<string name="sort_title_z_a">Título (Z \u2192 A)</string>
<string name="sort_date_new_old">Data (Recente \u2192 Antiga)</string>
@@ -518,4 +545,13 @@
<string name="rating_never_label">Não avaliar</string>
<string name="rating_later_label">Lembrar mais tarde</string>
<string name="rating_now_label">Claro, vamos a isso!</string>
+ <!--Audio controls-->
+ <string name="audio_controls">Controlos de áudio</string>
+ <string name="playback_speed">Velocidade de reprodução</string>
+ <string name="volume">Volume</string>
+ <string name="left_short">E</string>
+ <string name="right_short">D</string>
+ <string name="audio_effects">Efeitos áudio</string>
+ <string name="stereo_to_mono">Mistura: estéreo para mono</string>
+ <string name="sonic_only">Apenas Sonic</string>
</resources>
diff --git a/core/src/main/res/values-ro-rRO/strings.xml b/core/src/main/res/values-ro-rRO/strings.xml
index 0512a989b..a112db8dd 100644
--- a/core/src/main/res/values-ro-rRO/strings.xml
+++ b/core/src/main/res/values-ro-rRO/strings.xml
@@ -39,7 +39,6 @@
<string name="length_prefix">Durată:\u0020</string>
<string name="size_prefix">Dimensiune:\u0020</string>
<string name="processing_label">Procesează</string>
- <string name="loading_label">Încărcare...</string>
<string name="save_username_password_label">Salvează numele de utilizator și parola</string>
<string name="close_label">închide</string>
<string name="retry_label">Reîncearcă</string>
@@ -83,7 +82,6 @@
<string name="download_error_malformed_url">URL malformat</string>
<string name="download_error_io_error">Eroare IO</string>
<string name="download_error_request_error">Eroare cerere</string>
- <string name="downloads_left">\u0020descărcări rămase</string>
<string name="download_notification_title">Descarcă date podcast</string>
<string name="download_report_content">%1$d descărcari cu succes, %2$d eșuate</string>
<string name="download_log_title_unknown">Titlu necunoscut</string>
@@ -186,7 +184,6 @@
<string name="select_all_label">Selectează toate</string>
<string name="deselect_all_label">Deselectează toate</string>
<string name="opml_export_label">Exportă OPML</string>
- <string name="exporting_label">Exportă...</string>
<string name="export_error_label">Eroare exportare</string>
<string name="opml_export_success_sum">Fișierul .opml a fost scris în:\u0020</string>
<!--Sleep timer-->
@@ -229,10 +226,10 @@
<!--Online feed view-->
<string name="subscribe_label">Abonează-te</string>
<string name="subscribed_label">Abonat</string>
- <string name="downloading_label">Se descarcă...</string>
<!--Content descriptions for image buttons-->
<!--Feed information screen-->
<!--Progress information-->
<!--AntennaPodSP-->
<!--Rating dialog-->
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-ru/strings.xml b/core/src/main/res/values-ru/strings.xml
index 4ad4d3561..46a9d5feb 100644
--- a/core/src/main/res/values-ru/strings.xml
+++ b/core/src/main/res/values-ru/strings.xml
@@ -66,7 +66,6 @@
<string name="length_prefix">Продолжительность:\u0020</string>
<string name="size_prefix">Размер:\u0020</string>
<string name="processing_label">Обработка</string>
- <string name="loading_label">Загрузка...</string>
<string name="save_username_password_label">Сохранить имя пользователя и пароль</string>
<string name="close_label">Закрыть</string>
<string name="retry_label">Повторить</string>
@@ -78,7 +77,6 @@
<string name="feed_auto_download_global">Общие</string>
<string name="feed_auto_download_always">Всегда</string>
<string name="feed_auto_download_never">Никогда</string>
- <string name="send_label">Отправить...</string>
<string name="episode_cleanup_never">Никогда</string>
<string name="episode_cleanup_queue_removal">Когда не в очереди</string>
<string name="episode_cleanup_after_listening">После прослушивания</string>
@@ -97,7 +95,6 @@
<string name="mark_all_seen_label">Отметить все как про</string>
<string name="show_info_label">Показать информацию</string>
<string name="remove_feed_label">Удалить подкаст</string>
- <string name="share_label">Поделиться...</string>
<string name="share_link_label">Поделиться ссылкой</string>
<string name="share_link_with_position_label">Поделиться ссылкой с отметкой времени</string>
<string name="share_feed_url_label">Поделиться ссылкой на канал</string>
@@ -165,7 +162,6 @@
<string name="download_error_io_error">Ошибка ввода-вывода</string>
<string name="download_error_request_error">Ошибка запроса</string>
<string name="download_error_db_access">Ошибка доступа к базе данных</string>
- <string name="downloads_left">Осталось\u0020загрузок</string>
<string name="downloads_processing">Производится загрузка</string>
<string name="download_notification_title">Получение данных подкаста</string>
<string name="download_report_content">%1$d загрузок завершено, %2$d не удалось</string>
@@ -238,7 +234,6 @@
<!--Variable Speed-->
<string name="download_plugin_label">Загрузить плагин</string>
<string name="no_playback_plugin_title">Плагин не установлен</string>
- <string name="no_playback_plugin_or_sonic_msg">Для изменения скорости воспроизведения нужно установить библиотеку стороннего разработчика или включить экспериментальный Sonic player [Android 4.1+].\n\nНажмите \"Загрузить плагин\", чтобы скачать бесплатный плагин из Play Store\n\nЛюбые вопросы по работе плагина находятся вне ответственности AntennaPod и должны быть направлены владельцу плагина.</string>
<string name="set_playback_speed_label">Скорость воспроизведения</string>
<string name="enable_sonic">Включить Sonic</string>
<!--Empty list labels-->
@@ -251,7 +246,6 @@
<string name="services_label">Сервисы</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Удаление выпусков</string>
- <string name="pref_episode_cleanup_summary">Выпуски, которые не стоят в очереди и не отмечены как избранные могут быть удалены для освобождения места.</string>
<string name="pref_pauseOnDisconnect_sum">Приостановить воспроизведение, когда наушники или bluetooth отключены</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Продолжать воспроизведение после подключения наушников</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Продолжать воспроизведение после подключения наушников или восстановления bluetooth-соединения</string>
@@ -339,9 +333,10 @@
<string name="pref_smart_mark_as_played_disabled">Отключено</string>
<string name="pref_image_cache_size_title">Размер кэша для изображений</string>
<string name="pref_image_cache_size_sum">Размер дискового кэша для изображений</string>
+ <string name="crash_report_title">Отчет о сбое</string>
+ <string name="send_email">Отправить Email</string>
<string name="experimental_pref">Экспериментальные настройки</string>
<string name="pref_sonic_title">Проигрыватель Sonic</string>
- <string name="pref_sonic_message">Использовать встроенный проигрыватель Sonic вместо Prestissimo.</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Включить автоматическую поддержку через Flattr</string>
<string name="auto_flattr_after_percent">Поддерживать через Flattr эпизоды, прослушанные на %d процентов</string>
@@ -368,11 +363,9 @@
<string name="opml_import_error_dir_empty">Каталог для импорта пуст.</string>
<string name="select_all_label">Отметить все</string>
<string name="deselect_all_label">Снять все отметки</string>
- <string name="select_options_label">Выбрать...</string>
<string name="choose_file_from_filesystem">Из файловой системы</string>
<string name="choose_file_from_external_application">С помощью внешнего приложения</string>
<string name="opml_export_label">Экспорт в OPML</string>
- <string name="exporting_label">Экспортируется...</string>
<string name="export_error_label">Ошибка экспорта</string>
<string name="opml_export_success_title">OPML успешно экспортирован.</string>
<string name="opml_export_success_sum">Файл OPML был записан в:\u0020</string>
@@ -389,6 +382,24 @@
<string name="time_seconds">с</string>
<string name="time_minutes">м</string>
<string name="time_hours">ч</string>
+ <plurals name="time_seconds_quantified">
+ <item quantity="one">1 секунда</item>
+ <item quantity="few">%d сек.</item>
+ <item quantity="many">%d секунд</item>
+ <item quantity="other">%d секунд</item>
+ </plurals>
+ <plurals name="time_minutes_quantified">
+ <item quantity="one">1 минута</item>
+ <item quantity="few">%d мин.</item>
+ <item quantity="many">%d минут</item>
+ <item quantity="other">%d минут</item>
+ </plurals>
+ <plurals name="time_hours_quantified">
+ <item quantity="one">1 час</item>
+ <item quantity="few">%d ч.</item>
+ <item quantity="many">%d часов</item>
+ <item quantity="other">%d часов</item>
+ </plurals>
<!--gpodder.net-->
<string name="gpodnet_taglist_header">Категории</string>
<string name="gpodnet_toplist_header">Лучшее</string>
@@ -426,6 +437,9 @@
<string name="create_folder_error_no_write_access">Запись в эту папку невозможна</string>
<string name="create_folder_error_already_exists">Папка уже существует</string>
<string name="create_folder_error">Невозможно создать папку</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" не существует</string>
+ <string name="folder_not_readable_error">\"%1$s\" недоступен для чтения</string>
+ <string name="folder_not_writable_error">\"%1$s\" недоступен для записи</string>
<string name="folder_not_empty_dialog_title">Папка не пуста</string>
<string name="folder_not_empty_dialog_msg">Выбранная папка не пуста. Загрузки и прочие файлы будут сохранены в эту папку. Продолжить?</string>
<string name="set_to_default_folder">Выберите папку по умолчанию</string>
@@ -437,7 +451,6 @@
<!--Online feed view-->
<string name="subscribe_label">Подписаться</string>
<string name="subscribed_label">Подписка оформлена</string>
- <string name="downloading_label">Загрузка...</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Показать главы</string>
<string name="show_shownotes_label">Показать примечания к выпуску</string>
@@ -465,7 +478,6 @@
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Импорт подписок из одноцелевых приложений…</string>
<string name="search_itunes_label">Поиск в iTunes</string>
- <string name="select_label"><b>Выбрать ...</b></string>
<string name="all_label">Все</string>
<string name="selected_all_label">Отмечены все выпуски</string>
<string name="none_label">Нет</string>
@@ -478,7 +490,6 @@
<string name="selected_downloaded_label">Выбраны загруженные выпуски</string>
<string name="not_downloaded_label">Не загружено</string>
<string name="selected_not_downloaded_label">Выбраны незагруженные выпуски</string>
- <string name="sort_title"><b>Сортировать по ...</b></string>
<string name="sort_title_a_z">Заголовку (А \u2192 Я)</string>
<string name="sort_title_z_a">Заголовку (Я \u2192 А)</string>
<string name="sort_date_new_old">Дате (Новое \u2192 Старое)</string>
@@ -486,4 +497,10 @@
<string name="sort_duration_short_long">Продолжительности (Короткие \u2192 Длинные)</string>
<string name="sort_duration_long_short">Продолжительности (Длинные \u2192 Короткие)</string>
<!--Rating dialog-->
+ <string name="rating_title">Нравится AntennaPod?</string>
+ <string name="rating_message">Мы будем благодарны, если вы оцените AntennaPod.</string>
+ <string name="rating_never_label">Отстань от меня</string>
+ <string name="rating_later_label">Напомни позже</string>
+ <string name="rating_now_label">Конечно, давай!</string>
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-sv-rSE/strings.xml b/core/src/main/res/values-sv-rSE/strings.xml
index a618e257f..7407b3474 100644
--- a/core/src/main/res/values-sv-rSE/strings.xml
+++ b/core/src/main/res/values-sv-rSE/strings.xml
@@ -22,7 +22,9 @@
<string name="playback_history_label">Uppspelningshistorik</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">Inloggning till gpodder.net</string>
- <string name="free_space_label">\"%1$s oanvänt</string>
+ <string name="free_space_label">%1$s kvar</string>
+ <string name="episode_cache_full_title">Episodcachen är full</string>
+ <string name="episode_cache_full_message">Episodcachens gräns har nåtts. Du kan öka cachens storlek i inställningarna.</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Nyligen publicerade</string>
<string name="episode_filter_label">Visa bara nya Episoder</string>
@@ -67,7 +69,7 @@
<string name="length_prefix">Längd:\u0020</string>
<string name="size_prefix">Storlek:\u0020</string>
<string name="processing_label">Bearbetar</string>
- <string name="loading_label">Laddar...</string>
+ <string name="loading_label">Laddar…</string>
<string name="save_username_password_label">Spara användarnamn och lösenord</string>
<string name="close_label">Stäng</string>
<string name="retry_label">Försök igen</string>
@@ -79,7 +81,7 @@
<string name="feed_auto_download_global">Global</string>
<string name="feed_auto_download_always">Alltid</string>
<string name="feed_auto_download_never">Aldrig</string>
- <string name="send_label">Skicka...</string>
+ <string name="send_label">Skicka…</string>
<string name="episode_cleanup_never">Aldrig</string>
<string name="episode_cleanup_queue_removal">Om inte köad</string>
<string name="episode_cleanup_after_listening">Efter färdigspelad</string>
@@ -102,7 +104,7 @@
<string name="mark_all_seen_label">Markera alla som sedda</string>
<string name="show_info_label">Visa information</string>
<string name="remove_feed_label">Ta bort Podcast</string>
- <string name="share_label">Dela...</string>
+ <string name="share_label">Dela…</string>
<string name="share_link_label">Dela Länk</string>
<string name="share_link_with_position_label">Dela Länk med Position</string>
<string name="share_feed_url_label">Dela Flödets URL</string>
@@ -137,7 +139,9 @@
<string name="added_to_queue_label">Lägg till i Kö</string>
<string name="remove_from_queue_label">Ta bort från Kön</string>
<string name="add_to_favorite_label">Lägg till i Favoriter</string>
+ <string name="added_to_favorites">Tillagd i Favoriter</string>
<string name="remove_from_favorite_label">Ta bort från Favoriter</string>
+ <string name="removed_from_favorites">Borrtagen ur Favoriter</string>
<string name="visit_website_label">Besök websidan</string>
<string name="support_label">Flattra det här</string>
<string name="enqueue_all_new">Lägg till alla i kön</string>
@@ -171,7 +175,10 @@
<string name="download_error_io_error">IO fel</string>
<string name="download_error_request_error">Förfrågningsfel</string>
<string name="download_error_db_access">Åtkomstfel till databasen</string>
- <string name="downloads_left">\u0020Nedladdningar kvar</string>
+ <plurals name="downloads_left">
+ <item quantity="one">%d nedladdning kvar</item>
+ <item quantity="other">%d nedladdningar kvar</item>
+ </plurals>
<string name="downloads_processing">Bearbetar nedladdningar</string>
<string name="download_notification_title">Laddar ner podcastdata</string>
<string name="download_report_content">%1$d nedladdningar lyckades, %2$d misslyckades</string>
@@ -203,6 +210,8 @@
<!--Queue operations-->
<string name="lock_queue">Lås Kön</string>
<string name="unlock_queue">Lås upp Kön</string>
+ <string name="queue_locked">Kön låst</string>
+ <string name="queue_unlocked">Kön upplåst</string>
<string name="clear_queue_label">Rensa Kön</string>
<string name="undo">Ångra</string>
<string name="removed_from_queue">Föremålet avlägsnades</string>
@@ -244,12 +253,13 @@
<!--Variable Speed-->
<string name="download_plugin_label">Ladda ner tillägg</string>
<string name="no_playback_plugin_title">Tillägg ej installerat</string>
- <string name="no_playback_plugin_or_sonic_msg">För att variabel uppspelningshastighet ska funger måste du installera ett tredjepartsbibliotek eller aktivera den experimentella spelaren Sonic [Android 4.1+].\n\nTryck på \'Ladda ner Plugin\' för att ladda ner en gratis plugin från Play Store.\n\nAntennaPod ansvarar inte för eventualla problem som upptäcks vid användning av denna plugin och de bör rapporteras till pluginens ägare.</string>
+ <string name="no_playback_plugin_or_sonic_msg">För att variabel uppspelningshastighet ska fungera rekommenderas att aktivera den inbyggda Sonic mediaspelaren [Android 4.1+].\n\nAlternativt kan du ladda ner tredjepartstillägget <i>Prestissimo</i> från Google Play.\nProblem med Prestissimo är inte AntennaPods ansvar och bör rapporteras till tilläggets ägare.</string>
<string name="set_playback_speed_label">Uppspelningshastigheter</string>
<string name="enable_sonic">Aktivera Sonic</string>
<!--Empty list labels-->
<string name="no_items_label">Det finns inget i denna lista.</string>
<string name="no_feeds_label">Du har inte prenumererat på något flöde ännu.</string>
+ <string name="no_chapters_label">Denna episod har inga kapitel.</string>
<!--Preferences-->
<string name="other_pref">Annat</string>
<string name="about_pref">Om</string>
@@ -257,12 +267,12 @@
<string name="services_label">Tjänster</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Episodupprensning</string>
- <string name="pref_episode_cleanup_summary">Episoder som inte ligger i kön och inte är favoriter ska kunna tas bort om det behövs utrymme</string>
+ <string name="pref_episode_cleanup_summary">Episoder som inte är i kön och inte är favoriter kan tas bort om Automatisk Nedladdning behöver utrymme för nya episoder</string>
<string name="pref_pauseOnDisconnect_sum">Pausa uppspelningen när hörlurar eller bluetooth kopplas ifrån.</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Fortsätt uppspelningen när hörlurarna återansluts</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Fortsätt uppspelningen när bluetooth återansluts</string>
<string name="pref_hardwareForwardButtonSkips_title">Framåt-knappen hoppar</string>
- <string name="pref_hardwareForwardButtonSkips_sum">När den fysiska framåt-knappen trycks in, hoppa till nästa episod istället för att spola framåt</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Hoppa till nästa episod istället för att snabbspola vid tryck på hårdvaruknappen</string>
<string name="pref_followQueue_sum">Hoppa till nästa i kön när uppspelningen är klar</string>
<string name="pref_auto_delete_sum">Ta bort episoden när uppspelningen är klar</string>
<string name="pref_auto_delete_title">Automatisk Borttagning</string>
@@ -278,6 +288,8 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">Avaktivera</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Sätt intervall</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Sätt Tid på Dagen</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">var %1$s</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">vid %1$s</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Hämta mediefiler endast över WiFi</string>
<string name="pref_followQueue_title">Kontinuerlig Uppspelning</string>
<string name="pref_downloadMediaOnWifiOnly_title">WiFi nedladdning</string>
@@ -352,7 +364,8 @@
<string name="send_email">Sänd e-post</string>
<string name="experimental_pref">Experimentellt</string>
<string name="pref_sonic_title">Sonic mediaspelare</string>
- <string name="pref_sonic_message">Använd inbyggda mediaspelaren Sonic som en ersättning för Prestissimo</string>
+ <string name="pref_sonic_message">Använd den inbyggda Sonic mediaspelare som ersättning för Androids egna mediaspelare och Prestissimo</string>
+ <string name="pref_current_value">Nuvarande värde: %1$s</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Aktivera automatisk Flattring</string>
<string name="auto_flattr_after_percent">Flattra episoden så snart %d procent har spelats</string>
@@ -379,14 +392,15 @@
<string name="opml_import_error_dir_empty">Katalogen är tom.</string>
<string name="select_all_label">Välj alla</string>
<string name="deselect_all_label">Avmarkera alla</string>
- <string name="select_options_label">Välj ...</string>
+ <string name="select_options_label">Välj…</string>
<string name="choose_file_from_filesystem">Från lokalt filsystem</string>
<string name="choose_file_from_external_application">Använd extern applikation</string>
<string name="opml_export_label">OPML export</string>
- <string name="exporting_label">Exporterar...</string>
+ <string name="exporting_label">Exporterar…</string>
<string name="export_error_label">Exporteringsfel</string>
<string name="opml_export_success_title">OPML Exportering lyckades.</string>
<string name="opml_export_success_sum">.opml filen skrevs till:\u0020</string>
+ <string name="opml_import_ask_read_permission">Tillgång till extern lagring krävs för att läsa OPML-filen</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Ställ in sömntimer</string>
<string name="disable_sleeptimer_label">Stäng av sömntimer</string>
@@ -445,6 +459,7 @@
<string name="create_folder_label">Skapa mapp</string>
<string name="choose_data_directory">Välj Datakatalog</string>
<string name="choose_data_directory_message">Välj rotkatalogen för din data. AntennaPod skapar de underkataloger som behövs.</string>
+ <string name="choose_data_directory_permission_rationale">Tillgång till extern lagring krävs för att byta datakatalogen</string>
<string name="create_folder_msg">Skapa ny mapp med namnet \"%1$s\"?</string>
<string name="create_folder_success">Skapade ny mapp</string>
<string name="create_folder_error_no_write_access">Kan inte skriva till den här mappen</string>
@@ -464,7 +479,7 @@
<!--Online feed view-->
<string name="subscribe_label">Prenumerera</string>
<string name="subscribed_label">Prenumererar</string>
- <string name="downloading_label">Laddar ner...</string>
+ <string name="downloading_label">Laddar ner…</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Visa kapitel</string>
<string name="show_shownotes_label">Visa shownotes</string>
@@ -487,12 +502,20 @@
<!--Feed information screen-->
<string name="authentication_label">Autentisering</string>
<string name="authentication_descr">Byt ditt användarnamn och lösenord för den här podcasten och dess episoder.</string>
+ <string name="auto_download_settings_label">Automatisk nedladdningsinställningar</string>
+ <string name="episode_filters_label">Episodfilter</string>
+ <string name="episode_filters_description">Lista av termer som används för att avgöra om en episod ska inkluderas eller exkluderas vid automatisk nedladdning</string>
+ <string name="episode_filters_include">Inkludera</string>
+ <string name="episode_filters_exclude">Exkludera</string>
+ <string name="episode_filters_hint">Enstaka ord \n\"Flera ord\"</string>
+ <string name="keep_updated">Håll uppdaterad</string>
<!--Progress information-->
<string name="progress_upgrading_database">Uppgraderar databasen</string>
<!--AntennaPodSP-->
- <string name="sp_apps_importing_feeds_msg">Importerar prenumerationer från appar gjorda för ett enda syfte...</string>
+ <string name="sp_apps_importing_feeds_msg">Importerar prenumerationer från appar gjorda för ett enda syfte…</string>
<string name="search_itunes_label">Leta i iTunes</string>
- <string name="select_label"><b>Välj ...</b></string>
+ <string name="select_label"><b>Välj…</b></string>
+ <string name="filter">Filtrera</string>
<string name="all_label">Alla</string>
<string name="selected_all_label">Välj alla Episoder</string>
<string name="none_label">Inga</string>
@@ -505,7 +528,11 @@
<string name="selected_downloaded_label">Valde nedladdade Episoder</string>
<string name="not_downloaded_label">Ej nedladdade</string>
<string name="selected_not_downloaded_label">Valde ej nedladdade Episoder</string>
- <string name="sort_title"><b>Sortera efter ...</b></string>
+ <string name="queued_label">Köad</string>
+ <string name="selected_queued_label">Valde köade Episoder</string>
+ <string name="not_queued_label">Ej köad</string>
+ <string name="selected_not_queued_label">Välj ej köade Episoder</string>
+ <string name="sort_title"><b>Sortera efter…</b></string>
<string name="sort_title_a_z">Titel (A \u2192 Ö)</string>
<string name="sort_title_z_a">Titel (Ö \u2192 A)</string>
<string name="sort_date_new_old">Datum (Ny \u2192 Gammal)</string>
@@ -518,4 +545,13 @@
<string name="rating_never_label">Lämna mig ifred</string>
<string name="rating_later_label">Påminn mig senare</string>
<string name="rating_now_label">Okej, gör det nu!</string>
+ <!--Audio controls-->
+ <string name="audio_controls">Ljudkontroller</string>
+ <string name="playback_speed">Uppspelningshastighet</string>
+ <string name="volume">Volym</string>
+ <string name="left_short">V</string>
+ <string name="right_short">H</string>
+ <string name="audio_effects">Ljudeffekter</string>
+ <string name="stereo_to_mono">Nedmixning: Stereo till mono</string>
+ <string name="sonic_only">Bara Sonic</string>
</resources>
diff --git a/core/src/main/res/values-tr/strings.xml b/core/src/main/res/values-tr/strings.xml
index 6a59248f6..6dca19d57 100644
--- a/core/src/main/res/values-tr/strings.xml
+++ b/core/src/main/res/values-tr/strings.xml
@@ -66,7 +66,6 @@
<string name="length_prefix">Uzunluk:\u0020</string>
<string name="size_prefix">Boyut:\u0020</string>
<string name="processing_label">İşleniyor</string>
- <string name="loading_label">Yükleniyor...</string>
<string name="save_username_password_label">Kullanıcı adı ve şifreyi kaydet</string>
<string name="close_label">Kapat</string>
<string name="retry_label">Yeniden dene</string>
@@ -77,7 +76,6 @@
<string name="feed_auto_download_global">Genel</string>
<string name="feed_auto_download_always">Her zaman</string>
<string name="feed_auto_download_never">Hiçbir zaman</string>
- <string name="send_label">Gönder...</string>
<string name="episode_cleanup_never">Hiçbir zaman</string>
<string name="episode_cleanup_queue_removal">Sırada değilse</string>
<string name="episode_cleanup_after_listening">Bittikten sonra</string>
@@ -100,7 +98,6 @@
<string name="mark_all_seen_label">Hepsini görüldü olarak işaretle</string>
<string name="show_info_label">Bilgiyi göster</string>
<string name="remove_feed_label">Cep yayını kaldır</string>
- <string name="share_label">Paylaş...</string>
<string name="share_link_label">Link\'i paylaş</string>
<string name="share_link_with_position_label">Link\'i Konumla birlikte paylaş</string>
<string name="share_feed_url_label">Besleme Adresini Paylaş</string>
@@ -169,7 +166,6 @@
<string name="download_error_io_error">G/Ç Hatası</string>
<string name="download_error_request_error">İstek hatası</string>
<string name="download_error_db_access">Veritabanı erişim hatası</string>
- <string name="downloads_left">\u0020Kalan indirme</string>
<string name="downloads_processing">İndirmeler işleniyor</string>
<string name="download_notification_title">Cep yayını verileri indiriliyor</string>
<string name="download_report_content">%1$d indirme başarılı, %2$d başarısız</string>
@@ -254,7 +250,6 @@
<string name="services_label">Servisler</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Bölüm Temizliği</string>
- <string name="pref_episode_cleanup_summary">Daha fazla yer gerektiğinde kuyrukta olmayan ve favorilere eklenmemiş bölümler kaldırılmak için uygundur</string>
<string name="pref_pauseOnDisconnect_sum">Kulaklıklar çıkarıldığında veya bluetooth bağlantısı kesildiğinde çalmayı duraklat</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Kulaklıklar yeniden bağlandığında çalmaya devam et</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Bluetooth yeniden bağlandığında çalmaya devam et</string>
@@ -332,6 +327,11 @@
<string name="pref_smart_mark_as_played_disabled">Devre dışı</string>
<string name="pref_image_cache_size_title">Görüntü Önbelleği Boyutu</string>
<string name="pref_image_cache_size_sum">Görüntüler için diskte tutulacak önbelleğin boyutu.</string>
+ <string name="crash_report_title">Çökme Raporu</string>
+ <string name="crash_report_sum">En son çökme raporunu e-posta ile gönder</string>
+ <string name="send_email">E-posta gönder</string>
+ <string name="experimental_pref">Deneysel</string>
+ <string name="pref_sonic_title">Sonic ortam yürütücüsü</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Otomatik Flattr\'lamayı etkinleştir</string>
<string name="auto_flattr_after_percent">Bölümün yüzde %d kısmı oynatıldığında Flattr\'la</string>
@@ -346,6 +346,7 @@
<string name="found_in_title_label">Başlıkta bulundu</string>
<!--OPML import and export-->
<string name="opml_import_txtv_button_lable">OPML dosyaları cep yayınlarını bir cihazdan diğerine aktarmanıza yarar.</string>
+ <string name="opml_import_option">Seçenek %1$d</string>
<string name="opml_import_explanation_1">Yerel dosya sisteminden belirli bir yol seçin.</string>
<string name="opml_import_explanation_2">OPML dosyasını açmak için harici uygulamalardan Dropbox, Google Drive veya kendi favori dosya yöneticinizi kullanın.</string>
<string name="opml_import_explanation_3">Google Mail, Dropbox, Google Drive gibi birçok uygulama ve çoğu dosya yöneticisi OPML dosyalarını AntennaPod <i>ile</i> <i>açabilir.</i></string>
@@ -357,11 +358,9 @@
<string name="opml_import_error_dir_empty">İça aktarma dizini boş</string>
<string name="select_all_label">Hepsini seç</string>
<string name="deselect_all_label">Tüm seçimleri geri al</string>
- <string name="select_options_label">Seç ...</string>
<string name="choose_file_from_filesystem">Yerel dosya sisteminden</string>
<string name="choose_file_from_external_application">Harici uygulama kullan</string>
<string name="opml_export_label">OPML dışa aktar</string>
- <string name="exporting_label">Dışa aktarılıyor...</string>
<string name="export_error_label">Dışa aktarma hatası</string>
<string name="opml_export_success_title">Opml dışa aktarma başarılı.</string>
<string name="opml_export_success_sum">.opml dosyasy yazıldı: \u0020</string>
@@ -372,6 +371,9 @@
<string name="sleep_timer_label">Zamanlayıcı</string>
<string name="time_left_label">Kalan süre:\u0020</string>
<string name="time_dialog_invalid_input">Geçersiz giriş, zaman bir tam sayı olmalıdır</string>
+ <string name="timer_about_to_expire_label"><b>Zamanlayıcı süresi dolduğunda:</b></string>
+ <string name="shake_to_reset_label">Zamanyacıyı sıfırlamak için salla</string>
+ <string name="timer_vibration_label">Titret</string>
<string name="time_seconds">saniye</string>
<string name="time_minutes">dakika</string>
<string name="time_hours">saat</string>
@@ -419,11 +421,15 @@
<string name="selected_folder_label">Seçilen dizin:</string>
<string name="create_folder_label">Dizin yarat</string>
<string name="choose_data_directory">Veri dizinini seç</string>
+ <string name="choose_data_directory_message">Lütfen verileriniz için ana klasörü seçin. AntennaPod gerekli alt-klasörleri oluşturacaktır.</string>
<string name="create_folder_msg">\"%1$s\" isminde yeni dizin oluştur?</string>
<string name="create_folder_success">Yeni dizin yaratıldı</string>
<string name="create_folder_error_no_write_access">Bu dizine yazılamadı</string>
<string name="create_folder_error_already_exists">Dizin zaten var</string>
<string name="create_folder_error">Dizin yaratılamadı</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" adlı klasör yok</string>
+ <string name="folder_not_readable_error">\"%1$s\" klasörü okunabilir değil</string>
+ <string name="folder_not_writable_error">\"%1$s\" klasörü yazılabilir değil</string>
<string name="folder_not_empty_dialog_title">Dizin boş değil</string>
<string name="folder_not_empty_dialog_msg">Seçtiğiniz dizin dolu. Medya indirmeleri ve diğer dosyalar doğrudan bu dizine yerleştirilecek. Devam edilsin mi?</string>
<string name="set_to_default_folder">Vaysayılan dizini seç</string>
@@ -435,7 +441,6 @@
<!--Online feed view-->
<string name="subscribe_label">Üye ol</string>
<string name="subscribed_label">Üye olundu</string>
- <string name="downloading_label">İndiriliyor...</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Kısımları göster</string>
<string name="show_shownotes_label">Notları göster</string>
@@ -463,7 +468,6 @@
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Üyelikler tek-amaçlı uygulamalardan içe aktarılıyor...</string>
<string name="search_itunes_label">iTunes\'da Arama</string>
- <string name="select_label"><b>Seç ...</b></string>
<string name="all_label">Tümü</string>
<string name="selected_all_label">Tüm Bölümler Seçildi</string>
<string name="none_label">Hiçbiri</string>
@@ -476,7 +480,6 @@
<string name="selected_downloaded_label">İndirilen Bölümler Seçildi</string>
<string name="not_downloaded_label">İndirilmeyen</string>
<string name="selected_not_downloaded_label">İndirilmeyen Bölümler Seçildi</string>
- <string name="sort_title"><b>Sırala ...</b></string>
<string name="sort_title_a_z">Başlık (A \u2192 Z)</string>
<string name="sort_title_z_a">Başlık (Z \u2192 A)</string>
<string name="sort_date_new_old">Tarih (Yeni \u2192 Eski)</string>
@@ -484,4 +487,10 @@
<string name="sort_duration_short_long">Süre (Kısa \u2192 Uzun)</string>
<string name="sort_duration_long_short">Süre (Uzun \u2192 Kısa)</string>
<!--Rating dialog-->
+ <string name="rating_title">AntennaPod\'u beğendiniz mi?</string>
+ <string name="rating_message">Eğer AntennaPod\'a oy vermek için biraz zamanını ayırırsanız memnun oluruz.</string>
+ <string name="rating_never_label">Bir daha gösterme</string>
+ <string name="rating_later_label">Daha sonra hatırlat</string>
+ <string name="rating_now_label">Evet, şimdi yapalım!</string>
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values-uk-rUA/strings.xml b/core/src/main/res/values-uk-rUA/strings.xml
index 4fcd811b0..f0970a6cd 100644
--- a/core/src/main/res/values-uk-rUA/strings.xml
+++ b/core/src/main/res/values-uk-rUA/strings.xml
@@ -22,6 +22,9 @@
<string name="playback_history_label">Що грало</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">gpodder.net логін</string>
+ <string name="free_space_label">%1$s вільно</string>
+ <string name="episode_cache_full_title">Кеш епізодів заповнений</string>
+ <string name="episode_cache_full_message">Досягнута межа розміра кеша епізодів. Розмір кеша можна збільшити в налаштуваннях.</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Щойно опубліковано</string>
<string name="episode_filter_label">Показати тількі нові епізоди</string>
@@ -66,7 +69,7 @@
<string name="length_prefix">Довжина:\u0020</string>
<string name="size_prefix">Розмір:\u0020</string>
<string name="processing_label">Обробка</string>
- <string name="loading_label">Завантаження категорій ...</string>
+ <string name="loading_label">Завантажується…</string>
<string name="save_username_password_label">Зберегти ім\'я користувача та пароль</string>
<string name="close_label">Закрити</string>
<string name="retry_label">Повторити знову</string>
@@ -78,7 +81,7 @@
<string name="feed_auto_download_global">Для всіх</string>
<string name="feed_auto_download_always">Завжди</string>
<string name="feed_auto_download_never">Ніколи</string>
- <string name="send_label">Надіслати...</string>
+ <string name="send_label">Відправити…</string>
<string name="episode_cleanup_never">Ніколи</string>
<string name="episode_cleanup_queue_removal">Якщо не в черзі</string>
<string name="episode_cleanup_after_listening">Після закінчення</string>
@@ -102,7 +105,7 @@
<string name="mark_all_seen_label">Позначити всі як переглянуті</string>
<string name="show_info_label">Інформація</string>
<string name="remove_feed_label">Видалити подкаст</string>
- <string name="share_label">Поділитись...</string>
+ <string name="share_label">Поділитися…</string>
<string name="share_link_label">Поділитися URL сайту</string>
<string name="share_link_with_position_label">Поділитись посиланням на позицію</string>
<string name="share_feed_url_label">Поділитись посиланням на канал</string>
@@ -137,7 +140,9 @@
<string name="added_to_queue_label">Додано до черги</string>
<string name="remove_from_queue_label">Видалити з черги</string>
<string name="add_to_favorite_label">Додати до улюблених</string>
+ <string name="added_to_favorites">Додано до улюблених</string>
<string name="remove_from_favorite_label">Видалити з улюблених</string>
+ <string name="removed_from_favorites">Видалено з улюблених</string>
<string name="visit_website_label">Відкрити сайт</string>
<string name="support_label">Підтримати за допомогою Flattr</string>
<string name="enqueue_all_new">Додати до черги</string>
@@ -171,7 +176,11 @@
<string name="download_error_io_error">Помилка IO</string>
<string name="download_error_request_error">Помилка запиту</string>
<string name="download_error_db_access">Помилка бази даних</string>
- <string name="downloads_left">\0020 залишилось завантажити</string>
+ <plurals name="downloads_left">
+ <item quantity="one">%d завантаження залишилось</item>
+ <item quantity="few">%d завантаження залишилось</item>
+ <item quantity="other">%d завантажень залишилось</item>
+ </plurals>
<string name="downloads_processing">Обробка завантаженого</string>
<string name="download_notification_title">Завантаження даних подкасту</string>
<string name="download_report_content">Завантажилось %1$d успішно, %2$d з помилками</string>
@@ -203,6 +212,8 @@
<!--Queue operations-->
<string name="lock_queue">Заблокувати чергу</string>
<string name="unlock_queue">Розблокувати чергу</string>
+ <string name="queue_locked">Чергу заблоковано</string>
+ <string name="queue_unlocked">Чергу разблоковано</string>
<string name="clear_queue_label">Очистити чергу</string>
<string name="undo">Скасувати</string>
<string name="removed_from_queue">Видалено</string>
@@ -244,12 +255,13 @@
<!--Variable Speed-->
<string name="download_plugin_label">Завантажити додаток</string>
<string name="no_playback_plugin_title">Додаток не встановлено</string>
- <string name="no_playback_plugin_or_sonic_msg">Для керування швидкістю програвання потрібно встановити додаток або включити експериментальний програвач Sonic [Android 4.1+].\n\nНатисніть \"Завантажити додаток\" для завантаження безкоштовного додатку з Play Store\n\nЯкщо при використанні plugin виникнуть будь які проблеми - це відповідальність автора додатка, а не автора AntennaPod.</string>
+ <string name="no_playback_plugin_or_sonic_msg">Для програвання зі змінною швидкістю, ми радимо включити вбудований програвач Sonic [Android 4.1+].\n\nАбо ви можете завантажити додаток <i>Prestissimo</i> із Play Store.\nБудь які проблеми з Prestissimo не є відповідальністю розробників AntennaPod та мають вирішуватись авторами додатка.</string>
<string name="set_playback_speed_label">Швидкість програвання</string>
<string name="enable_sonic">Включити Sonic</string>
<!--Empty list labels-->
<string name="no_items_label">Нічого в цьому списку</string>
<string name="no_feeds_label">Немає підписаних каналів </string>
+ <string name="no_chapters_label">В цьому епізоді немає розділів.</string>
<!--Preferences-->
<string name="other_pref">Інше</string>
<string name="about_pref">Про програму</string>
@@ -257,10 +269,12 @@
<string name="services_label">Сервіси</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Чищення епізодів</string>
- <string name="pref_episode_cleanup_summary">У разі нестачі пам\'яті видалять епізоди які не знаходяться ні в списку улюблених ні в черзі.</string>
+ <string name="pref_episode_cleanup_summary">Епізоди що не знаходяться в черзі та не помічені як улюблені можуть бути видалені якщо Автозавантажувач потребуватиме місце для нових епізодів.</string>
<string name="pref_pauseOnDisconnect_sum">Зупинятись коли навушники або блютуз від’єднано</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Поновити відтворення коли навушники повторно під’єднано</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Поновити відтворення коли блютуз повторно під’єднано</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Пропуск кнопкой перемотки</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">При натисканні апаратної кнопки перемотки перейти до наступного епізода замість перемотки.</string>
<string name="pref_followQueue_sum">Перейти до наступного епізода в черзі коли поточний закінчено</string>
<string name="pref_auto_delete_sum">Видалити епізод після повного відтворення</string>
<string name="pref_auto_delete_title">Автовидалення</string>
@@ -276,6 +290,8 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">Вимкнути</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Інтервал</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Встановити час щодня</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">кожні %1$s</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">на %1$s</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Завантажувати тільки через Wifi</string>
<string name="pref_followQueue_title">Грати безперервно</string>
<string name="pref_downloadMediaOnWifiOnly_title">Завантаження через Wifi</string>
@@ -345,9 +361,13 @@
<string name="pref_smart_mark_as_played_disabled">Вимкнено</string>
<string name="pref_image_cache_size_title">Розмір кеша зображень</string>
<string name="pref_image_cache_size_sum">Розмір дискового кеша для зображень.</string>
+ <string name="crash_report_title">Звіт про збій</string>
+ <string name="crash_report_sum">Надіслати е-пошту зі звітом про останній збій</string>
+ <string name="send_email">Надіслати е-пошту</string>
<string name="experimental_pref">Експериментальні</string>
<string name="pref_sonic_title">Програвач Sonic</string>
- <string name="pref_sonic_message">Використовивать вбудований програвач sonic media player замість Prestissimo</string>
+ <string name="pref_sonic_message">Застосувати вбудований програвач sonic замість програвача Android та Prestissimo</string>
+ <string name="pref_current_value">Поточне значення: %1$s</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Включити автоматичне заохочення авторів через сервіс flattr</string>
<string name="auto_flattr_after_percent">Заохотити автора через Flattr щойно %d відсотків епізода було відтворено</string>
@@ -374,14 +394,15 @@
<string name="opml_import_error_dir_empty">Директорія імпорту пуста</string>
<string name="select_all_label">Обрати все</string>
<string name="deselect_all_label">Убрати виділення</string>
- <string name="select_options_label">Обрати ...</string>
+ <string name="select_options_label">Обрати…</string>
<string name="choose_file_from_filesystem">З локальної файлової системи</string>
<string name="choose_file_from_external_application">За допомогою додатка</string>
<string name="opml_export_label">OPML экспорт</string>
- <string name="exporting_label">Експорт ...</string>
+ <string name="exporting_label">Експортується…</string>
<string name="export_error_label">Помилка експорту</string>
<string name="opml_export_success_title">OPML експорт успішний</string>
<string name="opml_export_success_sum">OPML файл записаний в:\u0020</string>
+ <string name="opml_import_ask_read_permission">Щоб прочитати файл OPML потрібен доступ до зовнішньої пам’яти</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Таймер сну</string>
<string name="disable_sleeptimer_label">Вимкнути засинання</string>
@@ -442,11 +463,16 @@
<string name="selected_folder_label">Обрати папку:</string>
<string name="create_folder_label">Нова папка</string>
<string name="choose_data_directory">Обрати папку</string>
+ <string name="choose_data_directory_message">Оберіть, будь ласка, базовий каталог для даних. AntennaPod створить відповідні підрозділи. </string>
+ <string name="choose_data_directory_permission_rationale">Для зміни папки зберігання даних потрібен доступ до зовнішнього носія</string>
<string name="create_folder_msg">Створити папку з ім\'ям \"%1$s\"?</string>
<string name="create_folder_success">Створена нова папка</string>
<string name="create_folder_error_no_write_access">Не можу записати в цю папку</string>
<string name="create_folder_error_already_exists">Папка вже існує</string>
<string name="create_folder_error">Не можу создати папку</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" не існує</string>
+ <string name="folder_not_readable_error">\"%1$s\" недоступний до читання</string>
+ <string name="folder_not_writable_error">\"%1$s\" недоступний для запису</string>
<string name="folder_not_empty_dialog_title">Папка не є пустою</string>
<string name="folder_not_empty_dialog_msg">В папці щось є. Всі завантаження зберігаються в цю папку. Все рівно продовжувати?</string>
<string name="set_to_default_folder">Обрати папку по замовчанню</string>
@@ -458,7 +484,7 @@
<!--Online feed view-->
<string name="subscribe_label">Підписатися</string>
<string name="subscribed_label">Підписано</string>
- <string name="downloading_label">Завантаження...</string>
+ <string name="downloading_label">Завантажується…</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">Показати глави</string>
<string name="show_shownotes_label">Показати нотатки</string>
@@ -481,12 +507,20 @@
<!--Feed information screen-->
<string name="authentication_label">Автентикація</string>
<string name="authentication_descr">Змінити ваші логін та пароль для подкаста та епізодів</string>
+ <string name="auto_download_settings_label">Налаштування автозавантаження</string>
+ <string name="episode_filters_label">Фільтр епізодів</string>
+ <string name="episode_filters_description">Перелік термінів що використовуються для вирішення чи завантажувати епізод автоматично</string>
+ <string name="episode_filters_include">Включити</string>
+ <string name="episode_filters_exclude">Вилучити</string>
+ <string name="episode_filters_hint">Окремі слова \n\"Слова Разом\"</string>
+ <string name="keep_updated">Підтримувати оновленим</string>
<!--Progress information-->
<string name="progress_upgrading_database">Оновлення бази даних</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Імпорт подкастів з інших програм...</string>
<string name="search_itunes_label">Пошук в iTunes</string>
- <string name="select_label"><b>Обрати ...</b></string>
+ <string name="select_label"><b>Обрати…</b></string>
+ <string name="filter">Фільтр</string>
<string name="all_label">Всі</string>
<string name="selected_all_label">Обрано всі епізоди</string>
<string name="none_label">Жодного</string>
@@ -499,7 +533,11 @@
<string name="selected_downloaded_label">Обрано завантажені епізоди</string>
<string name="not_downloaded_label">Незавантажені</string>
<string name="selected_not_downloaded_label">Обрано незавантажені епізоди</string>
- <string name="sort_title"><b>Сортувати за ...</b></string>
+ <string name="queued_label">В черзі</string>
+ <string name="selected_queued_label">Обрано епізоди що в черзі</string>
+ <string name="not_queued_label">Не в черзі</string>
+ <string name="selected_not_queued_label">Обрано епізоди що не в черзі</string>
+ <string name="sort_title"><b>Сортувати за…</b></string>
<string name="sort_title_a_z">Назва (А \u2192 Я)</string>
<string name="sort_title_z_a">Назва (Я \u2192 А)</string>
<string name="sort_date_new_old">Дата (Нові \u2192 Старі)</string>
@@ -507,4 +545,18 @@
<string name="sort_duration_short_long">Тривалість (Короткі \u2192 Довгі)</string>
<string name="sort_duration_long_short">Тривалість (Довгі \u2192 Короткі)</string>
<!--Rating dialog-->
+ <string name="rating_title">Оцінити AntennaPod?</string>
+ <string name="rating_message">Ми будемо вдячні якщо ви поставите свою оцінку AntennaPod.</string>
+ <string name="rating_never_label">Не зараз</string>
+ <string name="rating_later_label">Нагадати згодом</string>
+ <string name="rating_now_label">Звичайно, з задоволенням!</string>
+ <!--Audio controls-->
+ <string name="audio_controls">Керування звуком</string>
+ <string name="playback_speed">Швидкість програвання</string>
+ <string name="volume">Гучність</string>
+ <string name="left_short">Л</string>
+ <string name="right_short">П</string>
+ <string name="audio_effects">Аудіоефекти</string>
+ <string name="stereo_to_mono">Зробити моно із стерео</string>
+ <string name="sonic_only">Тільки Sonic</string>
</resources>
diff --git a/core/src/main/res/values-zh-rCN/strings.xml b/core/src/main/res/values-zh-rCN/strings.xml
index 310b93aec..78017b383 100644
--- a/core/src/main/res/values-zh-rCN/strings.xml
+++ b/core/src/main/res/values-zh-rCN/strings.xml
@@ -5,8 +5,11 @@
<string name="feeds_label">订阅</string>
<string name="add_feed_label">添加播客</string>
<string name="podcasts_label">播客</string>
+ <string name="episodes_label">曲目</string>
<string name="new_episodes_label">新曲目</string>
<string name="all_episodes_label">所有曲目</string>
+ <string name="all_episodes_short_label">全部</string>
+ <string name="favorite_episodes_label">收藏</string>
<string name="new_label">最新</string>
<string name="waiting_list_label">等待列表</string>
<string name="settings_label">设置</string>
@@ -28,6 +31,7 @@
<string name="drawer_preferences">侧边栏设置</string>
<string name="drawer_feed_order_unplayed_episodes">按数量排序</string>
<string name="drawer_feed_order_alphabetical">按名称排序</string>
+ <string name="drawer_feed_order_last_update">按出版日期排序</string>
<string name="drawer_feed_counter_new_unplayed">新曲目和播放曲目数</string>
<string name="drawer_feed_counter_new">新曲目数</string>
<string name="drawer_feed_counter_unplayed">未播曲目数</string>
@@ -62,7 +66,6 @@
<string name="length_prefix">长度:\u0020</string>
<string name="size_prefix">大小:\u0020</string>
<string name="processing_label">处理中</string>
- <string name="loading_label">加载中...</string>
<string name="save_username_password_label">保存用户名密码</string>
<string name="close_label">关闭</string>
<string name="retry_label">重试</string>
@@ -73,6 +76,12 @@
<string name="feed_auto_download_global">全局</string>
<string name="feed_auto_download_always"> 总是</string>
<string name="feed_auto_download_never">从不</string>
+ <string name="episode_cleanup_never">从不</string>
+ <string name="episode_cleanup_queue_removal">当不在队列中</string>
+ <string name="episode_cleanup_after_listening">结束后</string>
+ <plurals name="episode_cleanup_days_after_listening">
+ <item quantity="other">结束后 %d 天</item>
+ </plurals>
<!--'Add Feed' Activity labels-->
<string name="feedurl_label">订阅 URL</string>
<string name="etxtFeedurlHint">www.example.com/feed</string>
@@ -85,9 +94,9 @@
<string name="mark_all_read_msg">将所有曲目标记为已播放</string>
<string name="mark_all_read_confirmation_msg">请确认您要将所有曲目标为已播放</string>
<string name="mark_all_read_feed_confirmation_msg">请确认您要将该订阅下的所有曲目标为已播放</string>
+ <string name="mark_all_seen_label">所有可见</string>
<string name="show_info_label">查看信息</string>
<string name="remove_feed_label">删除播客</string>
- <string name="share_label">分享到...</string>
<string name="share_link_label">分享网站链接</string>
<string name="share_link_with_position_label">分享网站链接与位置</string>
<string name="share_feed_url_label">分享订阅地址</string>
@@ -97,6 +106,7 @@
<string name="feed_remover_msg">删除订阅</string>
<string name="load_complete_feed">刷新全部订阅</string>
<string name="hide_episodes_title">隐藏曲目</string>
+ <string name="episode_actions">启用</string>
<string name="hide_unplayed_episodes_label">未播放</string>
<string name="hide_paused_episodes_label">已暂停</string>
<string name="hide_played_episodes_label">已播放</string>
@@ -120,6 +130,8 @@
<string name="add_to_queue_label">添加到播放列表</string>
<string name="added_to_queue_label">已添加到播放列表</string>
<string name="remove_from_queue_label">从播放列表中删除</string>
+ <string name="add_to_favorite_label">加入收藏</string>
+ <string name="remove_from_favorite_label">从收藏删除</string>
<string name="visit_website_label">访问网站</string>
<string name="support_label">Flattr 他</string>
<string name="enqueue_all_new">全部添加到播放列表</string>
@@ -128,6 +140,7 @@
<string name="activate_auto_download">开启自动下载</string>
<string name="deactivate_auto_download">关闭自动下载</string>
<string name="reset_position">重置播放进度</string>
+ <string name="removed_item">已删除项</string>
<!--Download messages and labels-->
<string name="download_successful">成功</string>
<string name="download_failed">失败</string>
@@ -152,7 +165,6 @@
<string name="download_error_io_error">IO 错误</string>
<string name="download_error_request_error">请求出错</string>
<string name="download_error_db_access">数据库访问错误</string>
- <string name="downloads_left">\u0020 下载剩余</string>
<string name="downloads_processing">正在处理下载</string>
<string name="download_notification_title">下载播客数据</string>
<string name="download_report_content">%1$d 下载成功, %2$d 失败</string>
@@ -163,6 +175,7 @@
<string name="download_request_error_dialog_message_prefix">尝试下载文件:\u0020 时出错</string>
<string name="authentication_notification_title">需要认证</string>
<string name="authentication_notification_msg">您所请求的资源需要用户名和密码</string>
+ <string name="confirm_mobile_download_dialog_title">确认手机下载</string>
<!--Mediaplayer messages-->
<string name="player_error_msg">错误!</string>
<string name="player_stopped_msg">没有可播放媒体</string>
@@ -294,12 +307,14 @@
<string name="pref_gpodnet_setlogin_information_sum">改变 gpodder.net 账户登录信息.</string>
<string name="pref_playback_speed_title">播放速度</string>
<string name="pref_playback_speed_sum">自定义音频播放速度</string>
+ <string name="pref_rewind">时间倒回</string>
<string name="pref_gpodnet_sethostname_title">设置主机名</string>
<string name="pref_gpodnet_sethostname_use_default_host">使用默认主机</string>
<string name="pref_expandNotify_title">扩展通知</string>
<string name="pref_expandNotify_sum">总是扩展通知以显示播放按钮</string>
<string name="pref_persistNotify_title">保持播放控制</string>
<string name="pref_persistNotify_sum">在暂停时保持通知和锁屏界面的控制。</string>
+ <string name="pref_lockscreen_background_title">设置锁屏背景</string>
<string name="pref_showDownloadReport_title">显示下载报告</string>
<string name="pref_showDownloadReport_sum">如果下载失败,生成一份显示详细失败信息的报告。</string>
<string name="pref_expand_notify_unsupport_toast">Android 4.1 之前不支持扩展通知。</string>
@@ -308,6 +323,9 @@
<string name="pref_smart_mark_as_played_disabled">已禁用</string>
<string name="pref_image_cache_size_title">图像缓存大小</string>
<string name="pref_image_cache_size_sum">用于缓存图像的存储空间大小</string>
+ <string name="crash_report_title">崩溃报告</string>
+ <string name="crash_report_sum">通过 E-mail 发送最后崩溃报告</string>
+ <string name="send_email">发送 E-mail</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">启用自动 flattring</string>
<string name="auto_flattr_after_percent">当播放到百分之%d时Flattr改曲目</string>
@@ -322,6 +340,7 @@
<string name="found_in_title_label">标题中查找</string>
<!--OPML import and export-->
<string name="opml_import_txtv_button_lable">OPML 文件可以方便的从别的播客转移数据过来。</string>
+ <string name="opml_import_option">设置 %1$d</string>
<string name="opml_import_explanation_1">从本地文件系统选择一个特定文件地址。</string>
<string name="opml_import_explanation_2">使用外部应用程序,例如 Dropbox,Google Drive 或您喜爱的文件管理器打开 OPML 文件。</string>
<string name="opml_import_explanation_3"><i>与</i> AntennaPod 一样,许多应用例如Google Mail,Dropbox,Google Drive和大多数文件管理器均可 <i>打开</i> OPML文件。</string>
@@ -336,7 +355,6 @@
<string name="choose_file_from_filesystem">来自本地文件系统</string>
<string name="choose_file_from_external_application">使用外部应用</string>
<string name="opml_export_label">OPML 导出</string>
- <string name="exporting_label">导出中...</string>
<string name="export_error_label">导出出错</string>
<string name="opml_export_success_title">OPML 导出成功.</string>
<string name="opml_export_success_sum">.opml 文件已保存到:\u0020</string>
@@ -347,6 +365,8 @@
<string name="sleep_timer_label">休眠计时器</string>
<string name="time_left_label">计时剩余:\u0020</string>
<string name="time_dialog_invalid_input">无效的输入, 时间是一个整数</string>
+ <string name="timer_about_to_expire_label"><b>当计时器过期时:</b></string>
+ <string name="timer_vibration_label">振动</string>
<string name="time_seconds">秒</string>
<string name="time_minutes">分</string>
<string name="time_hours">小时</string>
@@ -396,6 +416,9 @@
<string name="create_folder_error_no_write_access">本文件夹不能写入</string>
<string name="create_folder_error_already_exists">文件夹已存在</string>
<string name="create_folder_error">不能创建文件夹</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" 不存在</string>
+ <string name="folder_not_readable_error">\"%1$s\" 不可读</string>
+ <string name="folder_not_writable_error">\"%1$s\" 不可写</string>
<string name="folder_not_empty_dialog_title">文件夹不能为空</string>
<string name="folder_not_empty_dialog_msg">您所选择的文件夹不能为空. 媒体下载和其他文件将被直接放在本文件夹. 确认继续吗?</string>
<string name="set_to_default_folder">选择默认文件夹</string>
@@ -407,7 +430,6 @@
<!--Online feed view-->
<string name="subscribe_label">订阅</string>
<string name="subscribed_label">已订阅</string>
- <string name="downloading_label">下载中...</string>
<!--Content descriptions for image buttons-->
<string name="show_chapters_label">显示章节</string>
<string name="show_shownotes_label">显示笔记</string>
@@ -435,7 +457,6 @@
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">正在从选定的应用中导入订阅...</string>
<string name="search_itunes_label">搜索 iTunes</string>
- <string name="select_label"><b>选择 ...</b></string>
<string name="all_label">全部</string>
<string name="selected_all_label">全选</string>
<string name="none_label">无</string>
@@ -448,7 +469,6 @@
<string name="selected_downloaded_label">选择已下载的曲目</string>
<string name="not_downloaded_label">未下载</string>
<string name="selected_not_downloaded_label">选择未下载的曲目</string>
- <string name="sort_title"><b>排序 ...</b></string>
<string name="sort_title_a_z">标题 (A \u2192 Z)</string>
<string name="sort_title_z_a">标题 (Z \u2192 A)</string>
<string name="sort_date_new_old">日期 (新 \u2192 旧)</string>
@@ -456,4 +476,9 @@
<string name="sort_duration_short_long">时长 (短 \u2192 长)</string>
<string name="sort_duration_long_short">时长 (长 \u2192 短)</string>
<!--Rating dialog-->
+ <string name="rating_title">喜欢 AntennaPod?</string>
+ <string name="rating_never_label">请勿打扰</string>
+ <string name="rating_later_label">稍后提醒</string>
+ <string name="rating_now_label">好的, 就这样!</string>
+ <!--Audio controls-->
</resources>
diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml
index 341a7e520..0de515292 100644
--- a/core/src/main/res/values/arrays.xml
+++ b/core/src/main/res/values/arrays.xml
@@ -11,8 +11,9 @@
<item>0</item>
<item>15</item>
<item>30</item>
- <item>45</item>
<item>60</item>
+ <item>120</item>
+ <item>300</item>
</string-array>
@@ -75,15 +76,15 @@
</string-array>
<string-array name="playback_speed_values">
- <item>0.5</item>
- <item>0.6</item>
- <item>0.7</item>
+ <item>0.50</item>
+ <item>0.60</item>
+ <item>0.70</item>
<item>0.75</item>
- <item>0.8</item>
+ <item>0.80</item>
<item>0.85</item>
- <item>0.9</item>
+ <item>0.90</item>
<item>0.95</item>
- <item>1.0</item>
+ <item>1.00</item>
<item>1.05</item>
<item>1.10</item>
<item>1.15</item>
@@ -174,7 +175,7 @@
<item>3</item>
</string-array>
- <string-array name="episode_hide_options">
+ <string-array name="episode_filter_options">
<item>@string/hide_unplayed_episodes_label</item>
<item>@string/hide_paused_episodes_label</item>
<item>@string/hide_played_episodes_label</item>
@@ -184,7 +185,7 @@
<item>@string/hide_not_downloaded_episodes_label</item>
</string-array>
- <string-array name="episode_hide_values">
+ <string-array name="episode_filter_values">
<item>unplayed</item>
<item>paused</item>
<item>played</item>
diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml
index de641f518..2d3379d95 100644
--- a/core/src/main/res/values/attrs.xml
+++ b/core/src/main/res/values/attrs.xml
@@ -13,7 +13,6 @@
<attr name="content_discard" format="reference"/>
<attr name="content_new" format="reference"/>
<attr name="feed" format="reference"/>
- <attr name="device_access_time" format="reference"/>
<attr name="location_web_site" format="reference"/>
<attr name="navigation_accept" format="reference"/>
<attr name="navigation_cancel" format="reference"/>
@@ -37,14 +36,26 @@
<attr name="av_pause_big" format="reference"/>
<attr name="av_ff_big" format="reference"/>
<attr name="av_rew_big" format="reference"/>
+ <attr name="av_skip_big" format="reference"/>
<attr name="ic_settings" format="reference"/>
<attr name="ic_lock_open" format="reference"/>
<attr name="ic_lock_closed" format="reference"/>
<attr name="ic_filter" format="reference"/>
+ <attr name="progressBarTheme" format="reference"/>
+ <attr name="ic_fav" format="reference"/>
+ <attr name="ic_unfav" format="reference"/>
+ <attr name="ic_sleep" format="reference"/>
+ <attr name="ic_sleep_off" format="reference"/>
+ <attr name="ic_check_box" format="reference"/>
+ <attr name="ic_check_box_outline" format="reference"/>
+ <attr name="ic_indeterminate_check_box" format="reference"/>
+ <attr name="ic_sort" format="reference"/>
+ <attr name="ic_sd_storage" format="reference"/>
+ <attr name="ic_create_new_folder" format="reference"/>
<!-- Used in itemdescription -->
<attr name="non_transparent_background" format="reference"/>
<attr name="overlay_background" format="color"/>
<attr name="nav_drawer_background" format="color"/>
-</resources> \ No newline at end of file
+</resources>
diff --git a/core/src/main/res/values/dimens.xml b/core/src/main/res/values/dimens.xml
index c46537b3e..9aafd14e3 100644
--- a/core/src/main/res/values/dimens.xml
+++ b/core/src/main/res/values/dimens.xml
@@ -3,7 +3,7 @@
<dimen name="widget_margin">8dp</dimen>
<dimen name="thumbnail_length">70dp</dimen>
- <dimen name="external_player_height">70dp</dimen>
+ <dimen name="external_player_height">56dp</dimen>
<dimen name="enc_icons_size">20dp</dimen>
<dimen name="text_size_micro">12sp</dimen>
<dimen name="text_size_small">14sp</dimen>
@@ -33,6 +33,6 @@
<dimen name="listitem_icon_leftpadding">16dp</dimen>
<dimen name="listitem_icon_rightpadding">16dp</dimen>
- <dimen name="audioplayer_playercontrols_length">64dp</dimen>
+ <dimen name="audioplayer_playercontrols_length">48dp</dimen>
-</resources> \ No newline at end of file
+</resources>
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 443a1a8a8..912a60f55 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -26,6 +26,8 @@
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">gpodder.net Login</string>
<string name="free_space_label">%1$s free</string>
+ <string name="episode_cache_full_title">Episode cache full</string>
+ <string name="episode_cache_full_message">The episode cache limit has been reached. You can increase the cache size in the Settings.</string>
<!-- New episodes fragment -->
<string name="recently_published_episodes_label">Recently published</string>
@@ -75,7 +77,7 @@
<string name="length_prefix">Length:\u0020</string>
<string name="size_prefix">Size:\u0020</string>
<string name="processing_label">Processing</string>
- <string name="loading_label">Loading...</string>
+ <string name="loading_label">Loading&#8230;</string>
<string name="save_username_password_label">Save username and password</string>
<string name="close_label">Close</string>
<string name="retry_label">Retry</string>
@@ -87,7 +89,7 @@
<string name="feed_auto_download_global">Global</string>
<string name="feed_auto_download_always">Always</string>
<string name="feed_auto_download_never">Never</string>
- <string name="send_label">Send...</string>
+ <string name="send_label">Send&#8230;</string>
<string name="episode_cleanup_never">Never</string>
<string name="episode_cleanup_queue_removal">When not in queue</string>
<string name="episode_cleanup_after_listening">After finishing</string>
@@ -112,7 +114,7 @@
<string name="mark_all_seen_label">Mark all as seen</string>
<string name="show_info_label">Show information</string>
<string name="remove_feed_label">Remove Podcast</string>
- <string name="share_label">Share...</string>
+ <string name="share_label">Share&#8230;</string>
<string name="share_link_label">Share Link</string>
<string name="share_link_with_position_label">Share Link with Position</string>
<string name="share_feed_url_label">Share Feed URL</string>
@@ -148,7 +150,9 @@
<string name="added_to_queue_label">Added to Queue</string>
<string name="remove_from_queue_label">Remove from Queue</string>
<string name="add_to_favorite_label">Add to Favorites</string>
+ <string name="added_to_favorites">Added to Favorites</string>
<string name="remove_from_favorite_label">Remove from Favorites</string>
+ <string name="removed_from_favorites">Removed from Favorites</string>
<string name="visit_website_label">Visit Website</string>
<string name="support_label">Flattr this</string>
<string name="enqueue_all_new">Enqueue all</string>
@@ -183,7 +187,10 @@
<string name="download_error_io_error">IO Error</string>
<string name="download_error_request_error">Request Error</string>
<string name="download_error_db_access">Database Access Error</string>
- <string name="downloads_left">\u0020Downloads left</string>
+ <plurals name="downloads_left">
+ <item quantity="one">%d download left</item>
+ <item quantity="other">%d downloads left</item>
+ </plurals>
<string name="downloads_processing">Processing downloads</string>
<string name="download_notification_title">Downloading podcast data</string>
<string name="download_report_content">%1$d downloads succeeded, %2$d failed</string>
@@ -217,6 +224,8 @@
<!-- Queue operations -->
<string name="lock_queue">Lock Queue</string>
<string name="unlock_queue">Unlock Queue</string>
+ <string name="queue_locked">Queue locked</string>
+ <string name="queue_unlocked">Queue unlocked</string>
<string name="clear_queue_label">Clear Queue</string>
<string name="undo">Undo</string>
<string name="removed_from_queue">Item removed</string>
@@ -261,13 +270,14 @@
<!-- Variable Speed -->
<string name="download_plugin_label">Download Plugin</string>
<string name="no_playback_plugin_title">Plugin Not Installed</string>
- <string name="no_playback_plugin_or_sonic_msg">For variable speed playback to work, you have to install a third party library or enable the experimental Sonic player [Android 4.1+].\n\nTap \'Download Plugin\' to download a free plugin from the Play Store.\n\nAny problems found using this plugin are not the responsibility of AntennaPod and should be reported to the plugin owner.</string>
+ <string name="no_playback_plugin_or_sonic_msg">For variable speed playback to work, we recommend to enable the built-in Sonic mediaplayer [Android 4.1+].\n\nAlternatively, you can download the third party plugin <i>Prestissimo</i> from the Play Store.\nAny problems with Prestissimo are not the responsibility of AntennaPod and should be reported to the plugin owner.</string>
<string name="set_playback_speed_label">Playback Speeds</string>
<string name="enable_sonic">Enable Sonic</string>
<!-- Empty list labels -->
<string name="no_items_label">There are no items in this list.</string>
<string name="no_feeds_label">You haven\'t subscribed to any feeds yet.</string>
+ <string name="no_chapters_label">This episode has no chapters.</string>
<!-- Preferences -->
<string name="other_pref">Other</string>
@@ -276,7 +286,7 @@
<string name="services_label">Services</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Episode Cleanup</string>
- <string name="pref_episode_cleanup_summary">Episodes that aren\'t in the queue and aren\'t favorites should be eligible for removal if space is needed</string>
+ <string name="pref_episode_cleanup_summary">Episodes that aren\'t in the queue and aren\'t favorites should be eligible for removal if Auto Download needs space for new episodes</string>
<string name="pref_pauseOnDisconnect_sum">Pause playback when headphones or bluetooth are disconnected</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Resume playback when the headphones are reconnected</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Resume playback when bluetooth reconnects</string>
@@ -297,6 +307,8 @@
<string name="pref_autoUpdateIntervallOrTime_Disable">Disable</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Set Interval</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Set Time of Day</string>
+ <string name="pref_autoUpdateIntervallOrTime_every">every %1$s</string>
+ <string name="pref_autoUpdateIntervallOrTime_at">at %1$s</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Download media files only over WiFi</string>
<string name="pref_followQueue_title">Continuous Playback</string>
<string name="pref_downloadMediaOnWifiOnly_title">WiFi media download</string>
@@ -371,7 +383,8 @@
<string name="send_email">Send e-mail</string>
<string name="experimental_pref">Experimental</string>
<string name="pref_sonic_title">Sonic media player</string>
- <string name="pref_sonic_message">Use built-in sonic media player as a replacement for Prestissimo</string>
+ <string name="pref_sonic_message">Use built-in sonic media player as a replacement for Android\'s native mediaplayer and Prestissimo</string>
+ <string name="pref_current_value">Current value: %1$s</string>
<!-- Auto-Flattr dialog -->
<string name="auto_flattr_enable">Enable automatic flattring</string>
@@ -400,14 +413,15 @@
<string name="opml_import_error_dir_empty">The import directory is empty.</string>
<string name="select_all_label">Select all</string>
<string name="deselect_all_label">Deselect all</string>
- <string name="select_options_label">Select ...</string>
+ <string name="select_options_label">Select&#8230;</string>
<string name="choose_file_from_filesystem">From local filesystem</string>
<string name="choose_file_from_external_application">Use external application</string>
<string name="opml_export_label">OPML export</string>
- <string name="exporting_label">Exporting...</string>
+ <string name="exporting_label">Exporting&#8230;</string>
<string name="export_error_label">Export error</string>
<string name="opml_export_success_title">OPML Export successful.</string>
<string name="opml_export_success_sum">The .opml file was written to:\u0020</string>
+ <string name="opml_import_ask_read_permission">Access to external storage is required to read the OPML file</string>
<!-- Sleep timer -->
<string name="set_sleeptimer_label">Set sleep timer</string>
@@ -471,6 +485,7 @@
<string name="create_folder_label">Create folder</string>
<string name="choose_data_directory">Choose Data Folder</string>
<string name="choose_data_directory_message">Please choose the base of your data folder. AntennaPod will create the appropriate sub-directories.</string>
+ <string name="choose_data_directory_permission_rationale">Access to external storage is required to change the data folder</string>
<string name="create_folder_msg">Create new folder with name "%1$s"?</string>
<string name="create_folder_success">Created new folder</string>
<string name="create_folder_error_no_write_access">Cannot write to this folder</string>
@@ -492,7 +507,7 @@
<!-- Online feed view -->
<string name="subscribe_label">Subscribe</string>
<string name="subscribed_label">Subscribed</string>
- <string name="downloading_label">Downloading...</string>
+ <string name="downloading_label">Downloading&#8230;</string>
<!-- Content descriptions for image buttons -->
<string name="show_chapters_label">Show chapters</string>
@@ -517,7 +532,13 @@
<!-- Feed information screen -->
<string name="authentication_label">Authentication</string>
<string name="authentication_descr">Change your username and password for this podcast and its episodes.</string>
-
+ <string name="auto_download_settings_label">Auto Download Settings</string>
+ <string name="episode_filters_label">Episode Filter</string>
+ <string name="episode_filters_description">List of terms used to decide if an episode should be included or excluded when auto downloading</string>
+ <string name="episode_filters_include">Include</string>
+ <string name="episode_filters_exclude">Exclude</string>
+ <string name="episode_filters_hint">Single words \n\"Multiple Words\"</string>
+ <string name="keep_updated">Keep Updated</string>
<!-- Progress information -->
<string name="progress_upgrading_database">Upgrading the database</string>
@@ -527,7 +548,8 @@
<string name="sp_apps_importing_feeds_msg">Importing subscriptions from single-purpose apps&#8230;</string>
<string name="search_itunes_label">Search iTunes</string>
- <string name="select_label"><b>Select ...</b></string>
+ <string name="select_label"><b>Select&#8230;</b></string>
+ <string name="filter">Filter</string>
<string name="all_label">All</string>
<string name="selected_all_label">Selected all Episodes</string>
<string name="none_label">None</string>
@@ -540,7 +562,11 @@
<string name="selected_downloaded_label">Selected downloaded Episodes</string>
<string name="not_downloaded_label">Not downloaded</string>
<string name="selected_not_downloaded_label">Selected not downloaded Episodes</string>
- <string name="sort_title"><b>Sort by ...</b></string>
+ <string name="queued_label">Queued</string>
+ <string name="selected_queued_label">Selected queued Episodes</string>
+ <string name="not_queued_label">Not queued</string>
+ <string name="selected_not_queued_label">Selected not queued Episodes</string>
+ <string name="sort_title"><b>Sort by&#8230;</b></string>
<string name="sort_title_a_z">Title (A \u2192 Z)</string>
<string name="sort_title_z_a">Title (Z \u2192 A)</string>
<string name="sort_date_new_old">Date (New \u2192 Old)</string>
@@ -555,4 +581,14 @@
<string name="rating_later_label">Remind me later</string>
<string name="rating_now_label">Sure, let\'s do this!</string>
+ <!-- Audio controls -->
+ <string name="audio_controls">Audio controls</string>
+ <string name="playback_speed">Playback Speed</string>
+ <string name="volume">Volume</string>
+ <string name="left_short">L</string>
+ <string name="right_short">R</string>
+ <string name="audio_effects">Audio Effects</string>
+ <string name="stereo_to_mono">Downmix: Stereo to mono</string>
+ <string name="sonic_only">Sonic only</string>
+
</resources>
diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml
index b9ee70dbf..c4a731a53 100644
--- a/core/src/main/res/values/styles.xml
+++ b/core/src/main/res/values/styles.xml
@@ -4,6 +4,7 @@
<style name="Theme.AntennaPod.Light" parent="Theme.AppCompat.Light">
<item name="colorPrimary">@color/primary_light</item>
<item name="colorAccent">@color/holo_blue_light</item>
+ <item name="progressBarTheme">@style/ProgressBarLight</item>
<item name="buttonStyle">@style/Widget.AntennaPod.Button</item>
<item name="alertDialogTheme">@style/AntennaPod.Dialog.Light</item>
<item name="attr/action_bar_icon_color">@color/grey600</item>
@@ -17,7 +18,6 @@
<item name="attr/av_rewind">@drawable/ic_fast_rewind_grey600_24dp</item>
<item name="attr/content_discard">@drawable/ic_delete_grey600_24dp</item>
<item name="attr/content_new">@drawable/ic_add_grey600_24dp</item>
- <item name="attr/device_access_time">@drawable/ic_timer_grey600_24dp</item>
<item name="attr/feed">@drawable/ic_feed_grey600_24dp</item>
<item name="attr/location_web_site">@drawable/ic_web_grey600_24dp</item>
<item name="attr/navigation_accept">@drawable/ic_done_grey600_24dp</item>
@@ -44,15 +44,27 @@
<item name="attr/av_pause_big">@drawable/ic_pause_grey600_36dp</item>
<item name="attr/av_ff_big">@drawable/ic_fast_forward_grey600_36dp</item>
<item name="attr/av_rew_big">@drawable/ic_fast_rewind_grey600_36dp</item>
+ <item name="attr/av_skip_big">@drawable/ic_skip_grey600_36dp</item>
+ <item name="attr/ic_fav">@drawable/ic_star_border_grey600_24dp</item>
+ <item name="attr/ic_unfav">@drawable/ic_star_grey600_24dp</item>
<item name="attr/ic_settings">@drawable/ic_settings_grey600_24dp</item>
<item name="attr/ic_lock_open">@drawable/ic_lock_open_grey600_24dp</item>
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_grey600_24dp</item>
<item name="attr/ic_filter">@drawable/ic_filter_grey600_24dp</item>
+ <item name="attr/ic_sleep">@drawable/ic_sleep_grey600_24dp</item>
+ <item name="attr/ic_sleep_off">@drawable/ic_sleep_off_grey600_24dp</item>
+ <item name="attr/ic_check_box">@drawable/ic_check_box_grey600_24dp</item>
+ <item name="attr/ic_check_box_outline">@drawable/ic_check_box_outline_blank_grey600_24dp</item>
+ <item name="attr/ic_indeterminate_check_box">@drawable/ic_indeterminate_check_box_grey600_24dp</item>
+ <item name="attr/ic_sort">@drawable/ic_sort_grey600_24dp</item>
+ <item name="attr/ic_sd_storage">@drawable/ic_sd_storage_grey600_36dp</item>
+ <item name="attr/ic_create_new_folder">@drawable/ic_create_new_folder_grey600_24dp</item>
</style>
<style name="Theme.AntennaPod.Dark" parent="Theme.AppCompat">
<item name="colorAccent">@color/holo_blue_dark</item>
<item name="buttonStyle">@style/Widget.AntennaPod.Button</item>
+ <item name="progressBarTheme">@style/ProgressBarDark</item>
<item name="alertDialogTheme">@style/AntennaPod.Dialog.Dark</item>
<item name="attr/action_bar_icon_color">@color/white</item>
<item name="attr/action_about">@drawable/ic_info_white_24dp</item>g
@@ -65,7 +77,6 @@
<item name="attr/av_rewind">@drawable/ic_fast_rewind_white_24dp</item>
<item name="attr/content_discard">@drawable/ic_delete_white_24dp</item>
<item name="attr/content_new">@drawable/ic_add_white_24dp</item>
- <item name="attr/device_access_time">@drawable/ic_timer_white_24dp</item>
<item name="attr/feed">@drawable/ic_feed_white_24dp</item>
<item name="attr/location_web_site">@drawable/ic_web_white_24dp</item>
<item name="attr/navigation_accept">@drawable/ic_done_white_24dp</item>
@@ -92,15 +103,27 @@
<item name="attr/av_pause_big">@drawable/ic_pause_white_36dp</item>
<item name="attr/av_ff_big">@drawable/ic_fast_forward_white_36dp</item>
<item name="attr/av_rew_big">@drawable/ic_fast_rewind_white_36dp</item>
+ <item name="attr/av_skip_big">@drawable/ic_skip_white_36dp</item>
+ <item name="attr/ic_fav">@drawable/ic_star_border_white_24dp</item>
+ <item name="attr/ic_unfav">@drawable/ic_star_white_24dp</item>
<item name="attr/ic_settings">@drawable/ic_settings_white_24dp</item>
<item name="attr/ic_lock_open">@drawable/ic_lock_open_white_24dp</item>
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_white_24dp</item>
<item name="attr/ic_filter">@drawable/ic_filter_white_24dp</item>
+ <item name="attr/ic_sleep">@drawable/ic_sleep_white_24dp</item>
+ <item name="attr/ic_sleep_off">@drawable/ic_sleep_off_white_24dp</item>
+ <item name="attr/ic_check_box">@drawable/ic_check_box_white_24dp</item>
+ <item name="attr/ic_check_box_outline">@drawable/ic_check_box_outline_blank_white_24dp</item>
+ <item name="attr/ic_indeterminate_check_box">@drawable/ic_indeterminate_check_box_white_24dp</item>
+ <item name="attr/ic_sort">@drawable/ic_sort_white_24dp</item>
+ <item name="attr/ic_sd_storage">@drawable/ic_sd_storage_white_36dp</item>
+ <item name="attr/ic_create_new_folder">@drawable/ic_create_new_folder_white_24dp</item>
</style>
<style name="Theme.AntennaPod.Light.NoTitle" parent="Theme.AppCompat.Light.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowActionModeOverlay">true</item>
+ <item name="progressBarTheme">@style/ProgressBarLight</item>
<item name="colorPrimary">@color/primary_light</item>
<item name="colorAccent">@color/holo_blue_light</item>
<item name="buttonStyle">@style/Widget.AntennaPod.Button</item>
@@ -115,7 +138,6 @@
<item name="attr/av_rewind">@drawable/ic_fast_rewind_grey600_24dp</item>
<item name="attr/content_discard">@drawable/ic_delete_grey600_24dp</item>
<item name="attr/content_new">@drawable/ic_add_grey600_24dp</item>
- <item name="attr/device_access_time">@drawable/ic_timer_grey600_24dp</item>
<item name="attr/feed">@drawable/ic_feed_grey600_24dp</item>
<item name="attr/location_web_site">@drawable/ic_web_grey600_24dp</item>
<item name="attr/navigation_accept">@drawable/ic_done_grey600_24dp</item>
@@ -142,15 +164,27 @@
<item name="attr/av_pause_big">@drawable/ic_pause_grey600_36dp</item>
<item name="attr/av_ff_big">@drawable/ic_fast_forward_grey600_36dp</item>
<item name="attr/av_rew_big">@drawable/ic_fast_rewind_grey600_36dp</item>
+ <item name="attr/av_skip_big">@drawable/ic_skip_grey600_36dp</item>
+ <item name="attr/ic_fav">@drawable/ic_star_border_grey600_24dp</item>
+ <item name="attr/ic_unfav">@drawable/ic_star_grey600_24dp</item>
<item name="attr/ic_settings">@drawable/ic_settings_grey600_24dp</item>
<item name="attr/ic_lock_open">@drawable/ic_lock_open_grey600_24dp</item>
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_grey600_24dp</item>
<item name="attr/ic_filter">@drawable/ic_filter_grey600_24dp</item>
+ <item name="attr/ic_sleep">@drawable/ic_sleep_grey600_24dp</item>
+ <item name="attr/ic_sleep_off">@drawable/ic_sleep_off_grey600_24dp</item>
+ <item name="attr/ic_check_box">@drawable/ic_check_box_grey600_24dp</item>
+ <item name="attr/ic_check_box_outline">@drawable/ic_check_box_outline_blank_grey600_24dp</item>
+ <item name="attr/ic_indeterminate_check_box">@drawable/ic_indeterminate_check_box_grey600_24dp</item>
+ <item name="attr/ic_sort">@drawable/ic_sort_grey600_24dp</item>
+ <item name="attr/ic_sd_storage">@drawable/ic_sd_storage_grey600_36dp</item>
+ <item name="attr/ic_create_new_folder">@drawable/ic_create_new_folder_grey600_24dp</item>
</style>
<style name="Theme.AntennaPod.Dark.NoTitle" parent="Theme.AppCompat.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowActionModeOverlay">true</item>
+ <item name="progressBarTheme">@style/ProgressBarDark</item>
<item name="colorAccent">@color/holo_blue_dark</item>
<item name="buttonStyle">@style/Widget.AntennaPod.Button</item>
<item name="alertDialogTheme">@style/AntennaPod.Dialog.Dark</item>
@@ -164,7 +198,6 @@
<item name="attr/av_rewind">@drawable/ic_fast_rewind_white_24dp</item>
<item name="attr/content_discard">@drawable/ic_delete_white_24dp</item>
<item name="attr/content_new">@drawable/ic_add_white_24dp</item>
- <item name="attr/device_access_time">@drawable/ic_timer_white_24dp</item>
<item name="attr/feed">@drawable/ic_feed_white_24dp</item>
<item name="attr/location_web_site">@drawable/ic_web_white_24dp</item>
<item name="attr/navigation_accept">@drawable/ic_done_white_24dp</item>
@@ -191,10 +224,21 @@
<item name="attr/av_pause_big">@drawable/ic_pause_white_36dp</item>
<item name="attr/av_ff_big">@drawable/ic_fast_forward_white_36dp</item>
<item name="attr/av_rew_big">@drawable/ic_fast_rewind_white_36dp</item>
+ <item name="attr/av_skip_big">@drawable/ic_skip_white_36dp</item>
+ <item name="attr/ic_fav">@drawable/ic_star_border_white_24dp</item>
+ <item name="attr/ic_unfav">@drawable/ic_star_white_24dp</item>
<item name="attr/ic_settings">@drawable/ic_settings_white_24dp</item>
<item name="attr/ic_lock_open">@drawable/ic_lock_open_white_24dp</item>
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_white_24dp</item>
<item name="attr/ic_filter">@drawable/ic_filter_white_24dp</item>
+ <item name="attr/ic_sleep">@drawable/ic_sleep_white_24dp</item>
+ <item name="attr/ic_sleep_off">@drawable/ic_sleep_off_white_24dp</item>
+ <item name="attr/ic_check_box">@drawable/ic_check_box_white_24dp</item>
+ <item name="attr/ic_check_box_outline">@drawable/ic_check_box_outline_blank_white_24dp</item>
+ <item name="attr/ic_indeterminate_check_box">@drawable/ic_indeterminate_check_box_white_24dp</item>
+ <item name="attr/ic_sort">@drawable/ic_sort_white_24dp</item>
+ <item name="attr/ic_sd_storage">@drawable/ic_sd_storage_white_36dp</item>
+ <item name="attr/ic_create_new_folder">@drawable/ic_create_new_folder_white_24dp</item>
</style>
<style name="Theme.AntennaPod.VideoPlayer" parent="@style/Theme.AntennaPod.Dark">
@@ -213,6 +257,12 @@
<item name="android:ellipsize">end</item>
</style>
+ <style name="AntennaPod.TextView.ListItemPrimaryTitle2" parent="@android:style/TextAppearance.Small">
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:ellipsize">end</item>
+ </style>
+
<style name="AntennaPod.TextView.ListItemSecondaryTitle" parent="@android:style/TextAppearance.Small">
<item name="android:textSize">14sp</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
@@ -253,4 +303,14 @@
</style>
+ <style name="ProgressBarLight">
+ <item name="android:indeterminateOnly">false</item>
+ <item name="android:progressDrawable">@drawable/progress_bar_horizontal_light</item>
+ </style>
+
+ <style name="ProgressBarDark">
+ <item name="android:indeterminateOnly">false</item>
+ <item name="android:progressDrawable">@drawable/progress_bar_horizontal_dark</item>
+ </style>
+
</resources>
diff --git a/description/ca_ES.txt b/description/ca_ES.txt
new file mode 100644
index 000000000..b4955d18a
--- /dev/null
+++ b/description/ca_ES.txt
@@ -0,0 +1,42 @@
+Easy-to-use, flexible and open-source podcast manager and player
+
+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
+
+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/description/de.txt b/description/de.txt
index e14c619f2..84f6c388b 100644
--- a/description/de.txt
+++ b/description/de.txt
@@ -20,23 +20,26 @@ ORDNE, TEILE & GENIEßE
&#8226; Unterstütze die Autoren von Inhalten mit Flattr (inklusive automatischem Flattren)
STEUER DAS SYSTEM<br>
-&#8226; Kontrolliere automatisches Herunterladen: Wähle Feeds aus, schließe mobile Netze aus, suche bestimmte WiFi-Netze aus, setze voraus, dass das Smartphone geladen wird und lege Zeitpunkt oder Intervalle fest<br>
+&#8226; Kontrolliere automatisches Herunterladen: Wähle Feeds aus, filtere Episodes durch Schlüsselwörter, schließe mobile Netze aus, suche bestimmte WiFi-Netze aus, setze voraus, dass das Smartphone geladen wird und lege Zeitpunkt oder Intervalle fest<br>
&#8226; Verwalte deinen Speicherplatz durch das Festlegen der Anzahl gespeicherter Episoden, schlaues Löschen und durch Auswahl des Speicherortes<br>
&#8226; Benutze AntennaPod in deiner Sprache (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<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-Gemeinschaft bei!</b><br>
+<b>Trete der AntennaPod-Community bei!</b>
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 und zur Beteiligung an der Entwicklung.
-https://www.github.com/AntennaPod/AntennaPod (Englisch)
+Stelle uns über Twitter Fragen oder gebe uns Feedback:
+https://twitter.com/@AntennaPod
-In unserer Google-Gruppe können Ideen und Lieblingspodcastmomente geteilt werden.
+Teile deine Idee und Lieblingspodcastmomente und äußere deine Dankbarkeit gegenüber allen Freiwilligen in unserer Google Group:
https://groups.google.com/forum/#!forum/antennapod (Englisch)
-Mit Transifex kannst du uns beim Übersetzen helfen:<br>
-https://www.transifex.com/antennapod/antennapod (Englisch)
+Helfe auf Transifex, die App in deine Muttersprache zu übersetzen:
+https://www.transifex.com/antennapod/antennapod
+
+Probiere unser Beta-Testing-Programm aus, um die neusten Funktionen als Erster zu erhalten:
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod
-Probiere unser Beta-Testing-Programm aus, um die neusten Funktionen als Erster zu erhalten:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod (Englisch) \ No newline at end of file
+Wir verwenden GitHub für Funktionswünsche (Feature Requests), Fehlerberichte und zur Beteiligung an der Entwicklung.
+https://www.github.com/AntennaPod/AntennaPod \ No newline at end of file
diff --git a/description/en.txt b/description/en.txt
index 233410c3c..74b864455 100755
--- a/description/en.txt
+++ b/description/en.txt
@@ -1,6 +1,6 @@
Easy-to-use, flexible and open-source podcast manager and player
-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 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 (episode filtering, specify times, intervals and WiFi networks) and deleting episodes (based your favorites 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.
@@ -14,29 +14,32 @@ IMPORT, ORGANIZE AND PLAY<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; Keep track of the best of the best by marking episodes as favorites<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; Take control over automated downloading: choose feeds, filter episodes based on keywords, 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 favorites 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>
+<b>Join the AntennaPod community!</b>
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
+Ask your question or give feedback via Twitter:
+https://twitter.com/@AntennaPod
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
+Share your ideas, favorite podcasting moments and gratitude to all the volunteers in our Google group:
https://groups.google.com/forum/#!forum/antennapod
-Transifex is the place to help with translations:<br>
+Help translate the app to your mother tongue on Transifex:
https://www.transifex.com/antennapod/antennapod
-Check out our Beta Testing programme to get the latest features first:<br>
+Check out our Beta Testing programme to get the latest features first:
https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod
+
+Visit GitHub to submit feature requests, bug reports and code contributions:
+https://www.github.com/AntennaPod/AntennaPod
diff --git a/description/es.txt b/description/es.txt
index 444819625..3ebde6ef6 100644
--- a/description/es.txt
+++ b/description/es.txt
@@ -1,6 +1,6 @@
Reproductor y gestor de podcast de código abierto, flexible y fácil de usar
-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 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 (episode filtering, specify times, intervals and WiFi networks) and deleting episodes (based your favorites and delay settings).<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.
@@ -20,23 +20,26 @@ RECUERDA, COMPARTE Y APRECIA
&#8226; Ayuda a los creadores de contenido con la integración Flatter, siendo posible hacer Flattr automático
CONTROLA EL SISTEMA<br>
-&#8226; Toma el control de la descarga automática: elige los feeds, excluye las redes móviles, elige redes WiFi específicas, hazlo sólo si el teléfono está cargando o a ciertas horas o intervalos<br>
-&#8226; Gestiona el almacenamiento configurando la cantidad de episodios en caché, configura borrado inteligente (basado en favoritos y el estado de reproducción) y eligiendo tu ubicación favorita<br>
+&#8226; Take control over automated downloading: choose feeds, filter episodes based on keywords, 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 favorites and play status) and selecting your preferred location<br>
&#8226; Usa AntennaPod en tu idioma (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
&#8226; Adáptate a tu entorno usando el tema claro u oscuro<br>
&#8226; Haz backup de tus suscripciones usando gPodder.net o exportando a OPML
-<b>¡Únete a la comunidad AntennaPod!</b><br>
+<b>¡Únete a la comunidad AntennaPod!</b>
AntennaPod está en continuo desarrollo por voluntarios. ¡Tú también puedes contribuir, con tu código o con tus comentarios!
-GitHub es el sitio que debes visitar para solicitar características nuevas, reportar fallos y contribuir con código<br>
-https://www.github.com/AntennaPod/AntennaPod
+Haz tu pregunta o danos tu opinión vía Twitter:
+https://twitter.com/@AntennaPod
-Nuestro Grupo de Google es el sitio para compartir tus ideas, tus momentos favoritos de podcasting y tu gratitud a los voluntarios:<br>
+Comparte tus ideas, tus momentos favoritos de podcasting y tu gratitud a los voluntarios en nuestro Grupo de Google:
https://groups.google.com/forum/#!forum/antennapod
-Transifex es el sitio para ayudar con las traducciones:<br>
+Ayuda a traducir la app a tu idioma en Transifex:
https://www.transifex.com/antennapod/antennapod
-Echa un vistazo a nuestro programa de Beta Testing para ser el primero en usar las nuevas características:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+Check out our Beta Testing programme to get the latest features first:
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod
+
+Visita GitHub para enviar sugerencias, informes de fallos y aportes de código:
+https://www.github.com/AntennaPod/AntennaPod \ No newline at end of file
diff --git a/description/fr.txt b/description/fr.txt
index 4d05a9ca7..6fc861f86 100644
--- a/description/fr.txt
+++ b/description/fr.txt
@@ -1,42 +1,45 @@
Un lecteur et gestionnaire de podcast facile à utiliser et flexible
-AntennaPod est un lecteur et gestionnaire de podcast permettant l'accès à des millions de podcast gratuits ou payants produit aussi bien par des podcasters indépendants que de gros éditeurs comme la BBC, NPR ou CNN. Ajoutez, importez et exportez leurs flux facilement à partir d'ITunes, de fichiers OPML ou simplement à partir de liens RSS. Économisez votre temps, votre batterie et votre consommation internet grâce à une automatisation puissante des téléchargements (quand, à quel rythme et à partir de quel réseau wifi) et de la suppression des épisodes (à partir d'un certains temps ou des favoris)<br>
-Encore plus important : téléchargez, streamez ou mettez dans votre liste de lecture vos épisodes et écoutez les à votre manière grâce à une vitesse de lecture réglable, au support des chapitres et une fonction de mise en veille automatique. Vous pouvez même montrer votre appréciation aux créateurs de contenu avec notre intégration de Flattr.
+AntennaPod est un lecteur et gestionnaire de podcast permettant l'accès à des millions de podcast gratuits ou payants produit aussi bien par des podcasters indépendants que de gros éditeurs comme la BBC, NPR ou CNN. Ajoutez, importez et exportez leurs flux facilement à partir d'ITunes, de fichiers OPML ou simplement à partir de liens RSS. Gagnez du temps, préservez votre batterie et consommation internet grâce à une automatisation puissante des téléchargements (filtrage des épisodes, date, fréquence, choix du réseau WiFi, etc...) et des suppressions d’épisodes écoutés (selon vos critères).<br>
+Plus important : téléchargez, streamez ou ajoutez à la liste de lecture vos épisodes et écoutez les comme vous voulez grâce au réglage de vitesse de lecture, au support des chapitres et au minuteur d'arrêt automatique. Vous pouvez même montrer votre appréciation aux créateurs de contenu avec notre intégration de Flattr.
-Programmé par des fans de podcast, AntennaPod est gratuit dans tous les sens du terme : open source, aucun cout et pas de publicité.
+Programmé par des fans de podcast, AntennaPod est gratuit dans tous les sens du terme : open source, gratuit et sans publicité.
<b>Caractéristiques complètes :</b><br>
-Importer, gérer et écouter<br>
-&#8226; Ajouter et importer à partir d'iTunes, gPodder.net, de fichiers OPML ou de liens RSS ou Atom<br>
-&#8226; Gérez la lecture de n'importe où : widget sur l'écran d'accueil, notification système, commande casque ou bluetooth<br>
-&#8226; Ecoutez à votre façon grâce à une vitesse de lecture réglable, au support des chapitres (MP3, VorbisComment et Podlove), enregistrement de la position de lecture et une mise en veille automatique puissante (secouer pour prolonger le minuteur, baisse du volume et ralentissement de la lecture)<br>
+IMPORTER, GÉRER ET ÉCOUTER<br>
+&#8226; Ajouter et importer à partir d'iTunes, gPodder.net, fichiers OPML, liens RSS ou Atom<br>
+&#8226; Gérez la lecture de n'importe où : widget sur l'écran d'accueil, notification système, commande casque ou Bluetooth<br>
+&#8226; Écoutez à votre façon grâce à une vitesse de lecture réglable, au support des chapitres (MP3, VorbisComment et Podlove), à l'enregistrement de la position de lecture et à une mise en veille automatique puissante (secouez pour prolonger le minuteur, baisser le volume et ralentir la lecture)<br>
&#8226; Accès aux flux et épisodes protégés par mot de passe<br>
-&#8226; Tirez profit des flux à plusieurs pages (www.podlove.org/paged-feeds)
+&#8226; Tirez profit des flux paginés (www.podlove.org/paged-feeds)
-GARDEZ TRACE, PARTAGEZ & APPRECIEZ<br>
+SUIVEZ, PARTAGEZ & PROFITEZ<br>
&#8226; Gardez trace des meilleurs épisodes en les marquant comme favoris<br>
-&#8226; Retrouvez un épisode à partir de l'historique de lecture ou en cherchant (les titres et les commentaires des épisodes)<br>
-&#8226; Partagez vos épisodes ou flux à travers des options de réseaux sociaux et email avancées, du service gPodder.net ou par des exports OPML<br>
+&#8226; Retrouvez un épisode à partir de l'historique de lecture ou en recherchant parmi les titres et commentaires des épisodes précédents<br>
+&#8226; Partagez vos épisodes et flux sur les réseaux sociaux, par email, sur gPodder.net ou en les exportant au format OPML<br>
&#8226; Soutenez les créateurs de contenu avec l'intégration à Flattr et la possibilité de flatter automatiquement
CONTRÔLER LE SYSTÈME<br>
-&#8226; Prenez le contrôle avec l'automatisation des téléchargements : choisissez les flux, empêchez l'utilisation du réseau mobile, sélectionnez les réseaux WIFI à utiliser, exigez que le téléphone soit en train de charger et spécifiez quand ou à quel rythme<br>
-&#8226; Gérez l'espace de stockage en paramétrant le nombre d'épisodes à garder, de leurs suppressions automatique (à partir de vos favoris et du statut de lecture) et de l'emplacement où les enregistrer<br>
+&#8226; Prenez le contrôle en automatisant vos téléchargements : choix des flux, filtrage des épisodes, restriction de la connexion mobile, sélection du réseau WIFI à utiliser, uniquement durant la recharge et spécifiez la fréquence de mise à jour vous-même<br>
+&#8226; Gérez l'espace de stockage en paramétrant le nombre d'épisodes à garder, leur suppression automatique (en fonction de vos favoris et de leur statut) et leur emplacement sur le disque<br>
&#8226; Utilisez AntennaPod dans votre langue (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adaptez à votre environnement avec un thème clair ou sombre<br>
-&#8226; Sauvegardez vos abonnements avec l'intération à gPodder.net ou des exports OPML
+&#8226; Choix d'un thème clair ou sombre selon vos préférences<br>
+&#8226; Sauvegardez vos abonnements avec l’intégration à gPodder.net et les exports OPML
-<b>Rejoignez la communauté d'AntennaPod !</b><br>
-AntennaPod est développé activement par des volontaires. Vous pouvez aussi contribuer avec du code ou des commentaires !
+<b>Rejoignez la communauté d'AntennaPod !</b>
+AntennaPod est développé activement par des volontaires. Vous pouvez aussi contribuer avec du code, des traductions ou des commentaires !
-GitHub est l'endroit où aller pour demander de nouvelles options, faire part de bug ou pour contribuer au code :<br>
-https://www.github.com/AntennaPod/AntennaPod
+Posez vos questions ou donnez votre avis sur Twitter :
+https://twitter.com/@AntennaPod
-Notre groupe Google est l'endroit où aller pour partager vos idées, moments préférés de podcast et vos remerciements aux volontaires :<br>
+Partager vos idées, podcast préférés et adressez vos remerciements à tous les bénévoles dans notre groupe Google :
https://groups.google.com/forum/#!forum/antennapod
-Transifex est le lieu où vous pouvez aider à la traduction :<br>
+Aider à traduire l'application dans votre langue sur Transifex :
https://www.transifex.com/antennapod/antennapod
-Jetez un coup d’œil à notre programme de version Beta pour bénéficier des dernières options :<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+Jetez un coup d’œil à la version Beta pour bénéficier des dernières nouveautés :
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod
+
+Allez sur GitHub pour demander de nouvelles options, faire part de bugs et pour contribuer au code :
+https://www.github.com/AntennaPod/AntennaPod \ No newline at end of file
diff --git a/description/it.txt b/description/it.txt
index b4955d18a..ba94d94ee 100644
--- a/description/it.txt
+++ b/description/it.txt
@@ -5,28 +5,28 @@ 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>
-IMPORT, ORGANIZE AND PLAY<br>
+<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; Access password-protected feeds and episodes<br>
&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-KEEP TRACK, SHARE & APPRECIATE<br>
+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
-CONTROL THE SYSTEM<br>
+CONTROLLA IL SISTEMA<br>
&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
&#8226; Adapt to your environment using the light and dark theme<br>
&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-<b>Join the AntennaPod community!</b><br>
+<b>Unisciti alla comunità di AntennaPod!</b><br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
@@ -35,7 +35,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
-Transifex is the place to help with translations:<br>
+Transifex è il luogo con cui aiutare con le traduzioni:<br>
https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
diff --git a/description/it_IT.txt b/description/it_IT.txt
index dcf36da21..5e6bc0fbe 100644
--- a/description/it_IT.txt
+++ b/description/it_IT.txt
@@ -38,5 +38,5 @@ https://groups.google.com/forum/#!forum/antennapod
Transifex è il posto dove puoi aiutare a tradurre AntennaPod:<br>
https://www.transifex.com/antennapod/antennapod
-Check out our Beta Testing programme to get the latest features first:<br>
+Dai un'occhiata al nostro programma di Beta Testing per avere accesso in anticipo alle nuove features:<br>
https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/ja.txt b/description/ja.txt
index c7b518201..8d84248ae 100644
--- a/description/ja.txt
+++ b/description/ja.txt
@@ -1,6 +1,6 @@
使いやすくて柔軟な、オープンソース ポッドキャスト マネージャー/プレイヤーです。
-AntennaPodは、独自のポッドキャスターから、BBC、NPR、CNNなどの大規模な放送まで、数百万の無料や有料ポッドキャストに瞬時にアクセスすることができる、ポッドキャストマネージャーおよびプレーヤーです。フィードは手間のかからないiTunesのPodcastのデータベース、OPMLファイルや簡単なRSSのURLを使用して追加、インポート、エクスポートします。エピソードのダウンロード (時間、間隔およびWiFiネットワークを指定) とエピソードの削除 (お気に入りと遅延設定に基づいて) をするために強力な自動コントロールで、手間、バッテリ消費、モバイルデータ使用量を節約します。<br>
+AntennaPodは、独自のポッドキャスターから、BBC、NPR、CNNなどの大規模な放送まで、数百万の無料や有料ポッドキャストに瞬時にアクセスすることができる、ポッドキャストマネージャーおよびプレーヤーです。フィードは手間のかからないiTunesのPodcastのデータベース、OPMLファイルや簡単なRSSのURLを使用して追加、インポート、エクスポートします。エピソードのダウンロード (エピソードのフィルター、時間、間隔およびWiFiネットワークを指定) とエピソードの削除 (お気に入りと遅延設定に基づいて) をする強力な自動コントロールで、手間、バッテリ消費、モバイルデータ使用量を節約します。<br>
しかし最も重要なこと: エピソードをダウンロード、ストリーム再生、またはキューに入れて、そして再生速度の調整、チャプターのサポート、スリープタイマーで好きなように楽しんでください。Flattr統合でコンテンツ作成者にあなたの愛を示すことができます。
ポッドキャスト愛好家が作成した AntennaPod はすべての意味でフリー自由です: オープンソース、コスト不要、広告はありません。
@@ -20,23 +20,26 @@ AntennaPodは、独自のポッドキャスターから、BBC、NPR、CNNなど
&#8226; 自動Flattrを含むFlattrの統合でコンテンツクリエイターをサポートします
システムのコントロール
-&#8226; 自動ダウンロードの制御: フィードを選択、モバイルネットワークを除外、特定のWiFiネットワークを選択、電話を充電する必要、時間や間隔を設定<br>
+&#8226; 自動ダウンロードの制御: フィードを選択、キーワードに基づいてエピソードをフィルター、モバイルネットワークを除外、特定のWiFiネットワークを選択、電話を充電する必要性、時間や間隔を設定<br>
&#8226; キャッシュされるエピソードの量の設定、スマート削除 (お気に入りやプレイ状況に基づいて) と、お好みの場所を選択して、ストレージを管理します<br>
&#8226; AntennaPod をあなたの言語でご利用ください (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
&#8226; ライトとダーク テーマを使用して環境に適応します<br>
&#8226; gPodder.net統合とOPMLのエクスポートで、購読をバックアップします
-<b>AntennaPod のコミュニティに参加してください!</b><br>
+<b>AntennaPod のコミュニティに参加してください!</b>
AntennaPod はボランティアによって活発に開発中です。コードやコメントで、あなたもも貢献することができます!
-GitHubは、機能のリクエスト、バグの報告、コードの貢献のための場所です:<br>
-https://www.github.com/AntennaPod/AntennaPod
+Twitterで質問や、フィードバックをしてください:
+https://twitter.com/@AntennaPod
-私たちのGoogleグループは、あなたのアイデア、お気に入りのポッドキャスティングモーメント、感謝を、すべてのボランティアと共有するための場所で:<br>
+私たちのGoogleグループで、あなたのアイデア、お気に入りのポッドキャスティングモーメント、感謝を、すべてのボランティアと共有してください:
https://groups.google.com/forum/#!forum/antennapod
-Transifexは翻訳を支援するための場所です:<br>
+Transifexであなたの母国語へのアプリの翻訳を手伝ってください:
https://www.transifex.com/antennapod/antennapod
-私たちのベータテストプログラムをチェックして、最新機能を最初に入手してください:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+私たちのベータテストプログラムをチェックして、最新機能を最初に入手してください:
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod
+
+GitHubを訪問して、機能のリクエスト、バグの報告、コードの貢献をしてください:
+https://www.github.com/AntennaPod/AntennaPod \ No newline at end of file
diff --git a/description/ko.txt b/description/ko.txt
index b4955d18a..566c0f289 100644
--- a/description/ko.txt
+++ b/description/ko.txt
@@ -1,42 +1,42 @@
-Easy-to-use, flexible and open-source podcast manager and player
-
-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>
+사용하기 쉽고 유연하고 오픈소스인 팟캐스트 관리 및 플레이어
+
+안테나팟을 사용해 소규모 독립 제작자들부터 BBC, NPR, CNN 등의 대형 언론사까지 수많은 무료 및 유료 팟캐스트에 접근할 수 있습니다. iTunes 팟캐스트 데이터베이스, OPML 파일, RSS 주소를 사용해 팟캐스트 피드를 간편하게 추가하고 내보내고 가져올 수 있습니다. 강력한 자동 다운로드 제어(특정 시간 간격 및 Wi-Fi 네트워크 지정)와 삭제 제어(즐겨찾기 및 지연 설정에 기반한)를 통해 편리하게 배터리와 모바일 데이터 사용량을 줄이세요.
+하지만 가장 중요한 기능은: 에피소드를 다운로드하거나 스트리밍하거나 대기열을 만들고, 재생 속도 조절, 챕터 지원, 취침 타이머를 통해 원하는대로 즐길 수 있다는 점입니다. 내장된 Flattr 지원을 통해 팟캐스트 제작자들에게 호응을 보낼 수도 있습니다.
+
+팟캐스트 애호가에 의해 만들어진, 안테나팟은 모든 면에서 자유롭습니다: 소스 코드가 공개되어 있고, 무료인데다가 광고도 없습니다.
+
+<b>모든 기능:</b><br>
+가져오기, 관리하기, 재생하기<br>
+&#8226; iTunes, gPodder.net, OPML 파일, RSS 및 Atom 링크를 통해 피드를 추가하거나 가져올 수 있습니다.<br>
+&#8226; 재생을 어디에서나 관리할 수 있습니다: 홈스크린 위젯, 시스템 알림, 이어폰 및 블루투스 컨트롤<br>
+&#8226; 배속 재생 지원, 챕터 지원(MP3, VorbisComment, Podlove), 마지막 재생 위치 기억, 고급 취침 타이머(흔들어서 초기화, 볼륨 낮추기, 재생 느리게 하기) 등의 기능으로 팟캐스트를 즐기세요<br>
+&#8226; 암호로 보호된 피드와 에피소드에 접근<br>
+&#8226; 페이지로 구분된 피드 활용 (www.podlove.org/paged-feeds)
+
+기록하고, 공유하고, 호응하기<br>
+&#8226; 가장 좋아하는 팟캐스트 에피소드를 즐겨찾기로 저장<br>
+&#8226; 에피소드를 재생 기록 또는 검색(제목 및 노트)으로 찾기<br>
+&#8226; 에피소드와 피드를 SNS, 이메일, gPodder.net, OPML 내보내기로 공유<br>
+&#8226; 자동으로 Flattr하기 등의 Flattr 기능으로 팟캐스트 제작자 지원
+
+시스템 컨트롤
+&#8226; 자동 다운로드를 제어하세요: 피드를 고르고, 모바일 네트워크를 제외시키고, 특정 Wi-Fi 네트워크를 선택하고, 기기가 충전중일때만 다운로드하게 하고, 시간과 간격을 정하세요<br>
+&#8226; 에피소드 캐시 용량, 똑똑한 삭제(즐겨찾기와 재생 상태에 기반), 선호하는 저장 위치 등으로 저장소를 관리하세요<br>
+&#8226; 여러가지 언어로 안테나팟을 사용하세요 (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
+&#8226; 밝음 및 어두움 테마로 환경에 맞춰 사용하세요<br>
+&#8226; gPodder.net과 OPML 내보내기 기능으로 구독한 팟캐스트를 백업하세요
+
+<b>안테나팟 커뮤니티에 참여하세요!</b><br>
+안테나팟은 지원자들에 의해 활발히 개발되고 있습니다. 당신도 제작을 돕거나 제안을 해서 참여할 수 있습니다!
+
+GitHub에서 새로운 기능 제안, 버그 보고, 그리고 코드 기여를 할 수 있습니다.:<br>
https://www.github.com/AntennaPod/AntennaPod
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
+구글 그룹에서 아이디어와 좋은 팟캐스트를 공유하고 모든 지원자들에게 감사할 수 있습니다:<br>
https://groups.google.com/forum/#!forum/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/description/nb.txt b/description/nb.txt
new file mode 100644
index 000000000..b4955d18a
--- /dev/null
+++ b/description/nb.txt
@@ -0,0 +1,42 @@
+Easy-to-use, flexible and open-source podcast manager and player
+
+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
+
+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/description/nb_NO.txt b/description/nb_NO.txt
index b4955d18a..e8edc03c1 100644
--- a/description/nb_NO.txt
+++ b/description/nb_NO.txt
@@ -1,42 +1,42 @@
-Easy-to-use, flexible and open-source podcast manager and player
-
-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>
+En podcast-behandler for Android basert på åpen kildekode.
+
+AntennaPod er en podkast-behandler og -spiller som gir deg umiddelbar tilgang til millioner av gratis og betalte podkaster, fra uavhengige podkastere til store forlagshus som BBC, NPR og CNN. Legg til, importer og eksporter deres strømmer uten problemer ved hjelp av iTunes' podkast-database, OPML-filer eller enkle RSS URLer. Spar anstrengelser, batterikapasitet og mobildata-bruk med kraftfulle automatiseringskontroller for nedlasting av episoder (spesifiser tider, intervaller og WiFi-nettverk) og sletting av episoder (basert på dine favoritter og delay-instillinger).<br>
+Men viktigst av alt: Last ned, strøm eller legg episoder i kø og nyt dem slik du ønsker med regulerbar avspillingshasitghet, kapittelstøtte og en tidtaker for automatisk avslåing. Du kan til og med vise din takknemlighet til innholdets skapere med vår Flattr-integrasjon.
+
+Laget av podkast-entusiaster er AntennaPod gratis i ordets rette forstand: åpen kildekode, ingen kostnader, ingen reklame.
+
+<br>Alle funksjoner:</b></b>
+IMPORTER, ORGANISER OG SPILL AV<br>
+&#8226; Legg til og importer strømmer fra mapper fra iTunes og gPodder.net, OPML-filer og linker fra RSS og Atom<br>
+&#8226; Behandle avspillinger fra hvor som helst: widget på startskjerm, systemnotifikasjoner og ørepropp- og bluetoothkontroller<br>
+&#8226; Nyt det å høre på din måte med regulerbar avspillingshastighet, kapittelstøtte (MP3, VorbisComment og Podlove), husket avspillingsposisjon og en avansert tidtaker for automatisk avslåing (rist for å tilbakestille, senke volumet og sakke ned avspillingen)<br>
+&#8226; Støtte for passordbeskyttede strømmer og episoder<br>
+&#8226; Støtte for &#171;paged feeds&#187; (www.podlove.org/paged-feeds)
+
+FØLG MED, DEL OG SETT PRIS PÅ<br>
+&#8226; Følg med på det beste av det beste ved å markere episoder som favoritter<br>
+&#8226; Find den ene episoden gjennom avspillingshistorien eller ved å søke (titler og shownotater)<br>
+&#8226; Del episoder og strømmer gjennom avanserte sosiale medier- og e-postinstillinger, gPodder.net-tjenester og via OPML-eksportering<br>
+&#8226; Støtt innholdsskapere med Flattr-integrasjon gjennom automatisk &#171;flattring&#187;
+
+KONTROLLER SYSTEMET<br>
+&#8226; Ta kontroll over automatisk nedlasting: velg strømmer, ekskluder mobile nettverk, velg spesifikke WiFi-nettverk, krev av telefonen er til lading og sett klokkeslett eller intervaller<br>
+&#8226; Behandle lagring ved å sette en øvre grense for «cachede» episoder, smart sletting (basert på dine favoritter og avspillingsstatus) og velg din foretrukne lokasjon<br>
+&#8226; Bruk AntennaPod i ditt språk (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
+&#8226; Tilpass appens stil ved å bruke det mørke eller lyse temaet<br>
+&#8226; Lag back-up av dine abonnement med gPodder.net-integrasjon og OPML-eksport
+
+<b>Bli med i AntennaPod-samfunnet!</b></br>
+AntennaPod er under aktiv utvikling av frivillige. Du kan også bidra, med kode eller kommentarer!
+
+GitHub er stedet å gå for å etterspørre funksjoner, feilrapportering og kodebidrag:<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>
+Vår Google Gruppe er stedet for å dele dine ideer, dine podkast-favorittøyeblikk og din takknemlighet til alle frivillige:<br>
https://groups.google.com/forum/#!forum/antennapod
-Transifex is the place to help with translations:<br>
+Transifex er stedet for å hjelpe til med oversettelser:<br>
https://www.transifex.com/antennapod/antennapod
-Check out our Beta Testing programme to get the latest features first:<br>
+Sjekk ut vårt Betatesting-program for å få de siste funksjonene først:<br>
https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/pt.txt b/description/pt.txt
index 45a3f03d9..3a24b8884 100644
--- a/description/pt.txt
+++ b/description/pt.txt
@@ -1,7 +1,7 @@
Gestor e reprodutor de podcasts simples, flexível e open souce
-O AntennaPod é um gestor de podcasts que lhe permite aceder a milhões de podcasts (gratuitos ou pagos), a partir de diversas fontes tais como as estações BBC, NPR e CNN. A adição de fontes é muito fácil através das base de dados iTunes ou gPodder, ficheiros OPML ou fontes RSS. Poupe tempo, economize energia e dados móveis através dos mecanismos de controlo de transferência de episódios (possibilidade de especificar intervalos ou horas para as transferências e redes WiFi) e de eliminação de episódios (de acordo com as suas preferências).<br>
-Mas ainda mais importante: pode transferir, emitir ou colocar episódios na lista de reprodução ao seu gosto, pode utilizar velocidades variáveis de reprodução, tem suporte a capítulos e um temporizador. Pode também mostrar o seu apreço aos disponibilizadores dos episódios através do serviço Flattr.
+O AntennaPod é um gestor e reprodutor de podcasts que lhe permite aceder a milhões de podcasts gratuitos ou pagos, a partir de fontes independentes ou de grandes editoras, tais como as estações BBC, NPR e CNN. Adicione, importe e exporte as fontes facilmente através das base de dados iTunes, ficheiros OPML ou fontes RSS. Poupe tempo, economize bateria e dados móveis através dos mecanismos de controlo de descarga de episódios (possibilidade de especificar intervalos ou horas e redes Wi-Fi) e de eliminação de episódios (de acordo com as suas preferências).<br>
+Mas ainda mais importante: pode descarregar, emitir ou colocar episódios na lista de reprodução ao seu gosto, pode utilizar velocidades variáveis de reprodução, tem suporte a capítulos e um temporizador. Pode também mostrar o seu apreço aos criadores dos episódios através do serviço Flattr.
Criado por entusiastas de podcasts, o AntennaPod é livre em todos os sentidos da palavra: open source, gratuito e sem publicidade.
@@ -9,34 +9,37 @@ Criado por entusiastas de podcasts, o AntennaPod é livre em todos os sentidos d
Importação, organização e reprodução<br>
&#8226; Adicione e importe fontes existentes nos diretórios iTunes e gPodder.net, ficheiros OPML e ligações ATOM e RSS<br>
&#8226; Gestão de podcasts através do widget, barra de notificações e controlos de auriculares ou auscultadores<br>
-&#8226; Velocidade variável de reprodução, suporte a capítulos (MP3, VorbisComment e Podlove), memorização da posição de reprodução e um temporizador avançado (agite para repor ou baixar e aumentar o volume)<br>
+&#8226; Velocidade variável de reprodução, suporte a capítulos (MP3, VorbisComment e Podlove), memorização da posição de reprodução e um temporizador avançado (agite para repor, baixar e aumentar o volume)<br>
&#8226; Acesso a fontes e episódios protegidos por palavra-passe<br>
&#8226; Possibilidade de subscrever fontes paginadas (www.podlove.org/paged-feeds)
Monitorização, partilha e suporte<br>
-&#8226; Monitorize os seus podcasts preferidos marcando-os como favoritos<br>
+&#8226; Monitorize os seus episódio preferidos marcando-os como favoritos<br>
&#8226; Localize um episódio através do histórico de reprodução ou através de uma pesquisa (títulos e notas)<br>
&#8226; Partilhe episódios e fontes nas redes sociais, por e-mail, no diretório gPodder.net ou através de ficheiros OPML<br>
&#8226; Ajude os criadores de conteúdos através do serviço Flattr
-Controlar o sistema<br>
-&#8226; Controle todas as transferÊncias automáticas: escolha as fontes, exclua redes móveis, especifique as redes WiFi, indique se o telefone deve estar a ser carregado e defina as horas ou intervalos das transferências<br>
-&#8226; Faça a gestão do armazenamento através da cache de episódios, da eliminação inteligente (de acordo com os seus favoritos e estado de reprodução) e selecionado a localização de armazenamento<br>
+Controlo do sistema<br>
+&#8226; Controle as descargas automáticas: escolha as fontes, filtre episódios com base em palavras-chave, exclua redes móveis, selecione redes Wi-Fi, indique se o dispositivo deve estar a ser carregado e defina as horas ou intervalos das descargas<br>
+&#8226; Faça a gestão do armazenamento através da cache de episódios, da eliminação inteligente (de acordo com os seus favoritos e estado de reprodução) e selecionando a localização dos dados<br>
&#8226; Utilize o AntennaPod no seu idioma (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
&#8226; Adapte-se ao seu ambiente através dos temas claro ou escuro<br>
&#8226; Salvaguarde as suas subscrições com a integração gPodder.net ou através da exportação OPML
-<b>Integre a comunidade do AntennaPod!</b><br>
+<b>Junte-se à comunidade do AntennaPod!</b>
O AntennaPod é desenvolvido por voluntários. Você também pode contribuir na programação ou reportando os erros encontrados!
-O GitHub é o local certo para os pedidos de funcionalidades, relatórios de erros e contribuições:<br>
-https://www.github.com/AntennaPod/AntennaPod
+Coloque uma questão ou dê a sua opinião através do Twitter:
+https://twitter.com/@AntennaPod
-O nosso grupo Google é o local certo para partilhar ideias e agradecer aos nossos voluntários:<br>
+Partilhe as suas ideias e os seus momentos favoritos nos podcasts com todos os voluntários do nosso grupo Google:
https://groups.google.com/forum/#!forum/antennapod
-O Transifex é o local no qual pode ajudar a traduzir a aplicação:<br>
+Ajude a traduzir a aplicação para o seu idioma no Transifex:
https://www.transifex.com/antennapod/antennapod
-Junte-se ao nosso programa de testes para obter as funcionalidades mais recentes:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+Junte-se ao nosso programa de testes para obter as funcionalidades mais recentes:
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod
+
+Visite o GitHub para submeter pedidos de funcionalidades, relatórios de erros e contribuições de programação:
+https://www.github.com/AntennaPod/AntennaPod \ No newline at end of file
diff --git a/description/uk_UA.txt b/description/uk_UA.txt
index b4c604a4f..b3aa64be5 100644
--- a/description/uk_UA.txt
+++ b/description/uk_UA.txt
@@ -20,23 +20,26 @@ AntennaPod це менеджер подкастів та плейер що да
&#8226; Підтримуйте авторів за допомогою інтегрованого сервіса Flattr з можливістю автоматичной підтримки
КЕРУЙТЕ СИСТЕМОЙ<br>
-&#8226; Керуйте автоматичним завантаженням: вибирайте канали, мобільні мережі, мережі WiFi, завантажуйте тільки під час зарядки або у встановлений час і інтервали<br>
+&#8226; Керуйте автоматичним завантаженням: вибирайте канали, мобільні мережі, мережі WiFi, фільтруйте епізоди за ключовими словами, завантажуйте тільки під час зарядки або у встановлений час і інтервали<br>
&#8226; Керуйте збереженням, встановлюйте ліміт на кеш епізодів, налагоджуйте розумне видалення (з урахуванням улюблених епізодів і статуса програвання) та вибирайте місце зберігання<br>
&#8226; Користуйтесь AntennaPod вашою мовою (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
&#8226; Пристосовуйтесь до ваших умов, користуйтесь світлой або темной темами<br>
&#8226; Зберігайте ваші підписки на gPodder.net або експортуйте в файл OPML
-<b>Долучайтесь до спільноти AntennaPod!</b><br>
+<b>Долучайтесь до спільноти AntennaPod!</b>
AntennaPod швидко розвивається волонтерами. Ви також маєте змогу допомогти, кодом або зауваженнями!
-Долучитись до проекта, повідомити про ваші побажання та про помилки можна на GitHub:<br>
-https://www.github.com/AntennaPod/AntennaPod
+Запитуйте, та спілкуйтесь за допомогую твітера:
+https://twitter.com/@AntennaPod
-В нашій групі на Google можна поділитись ідеями, улюбленими моментами з подкастінга та добрими побажаннями волонтерам:<br>
+В нашій групі на Google можна поділитись ідеями, улюбленими моментами з подкастінга та добрими побажаннями волонтерам:
https://groups.google.com/forum/#!forum/antennapod
-Допомагайте з перекладом на Transifex:<br>
+Допоможіть з перекладом на рідну мову на Transifex:
https://www.transifex.com/antennapod/antennapod
-Зверніть увагу на нашу програму для бета тестування якщо бажаєте получати найновіші версії в першу чергу:<br>
-https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+Зверніть увагу на нашу програму для бета тестування якщо бажаєте получати найновіші версії в першу чергу:
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod
+
+Долучитись до проекта, повідомити про ваші побажання та про помилки можна на GitHub:
+https://www.github.com/AntennaPod/AntennaPod \ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index b5166dad4..5ccda13e9 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index fb3375000..2cf959511 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue May 19 11:59:21 CEST 2015
+#Sat Feb 13 13:14:00 CET 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-all.zip
diff --git a/gradlew b/gradlew
index 91a7e269e..9d82f7891 100755
--- a/gradlew
+++ b/gradlew
@@ -42,11 +42,6 @@ case "`uname`" in
;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do
fi
done
SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
+cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
+cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -114,6 +109,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
diff --git a/gradlew.bat b/gradlew.bat
index 8a0b282aa..5f192121e 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -46,7 +46,7 @@ echo location of your Java installation.
goto fail
:init
-@rem Get command-line arguments, handling Windowz variants
+@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args