summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml14
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md53
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml5
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md25
-rw-r--r--.github/PULL_REQUEST_TEMPLATE/default.md1
-rw-r--r--CONTRIBUTING.md15
-rw-r--r--CONTRIBUTORS39
-rw-r--r--README.md2
-rw-r--r--app/build.gradle15
-rw-r--r--app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java27
-rw-r--r--app/src/androidTest/java/de/test/antennapod/dialogs/ShareDialogTest.java92
-rw-r--r--app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java27
-rw-r--r--app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/handler/AtomParserTest.java40
-rw-r--r--app/src/androidTest/java/de/test/antennapod/handler/FeedParserTestBase.java (renamed from app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java)65
-rw-r--r--app/src/androidTest/java/de/test/antennapod/handler/RssParserTest.java63
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java20
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java17
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java21
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java28
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java23
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java111
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.java79
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java9
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java13
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/SpeedChangeTest.java5
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/TextOnlyFeedsTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java30
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java7
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java8
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/AtomGenerator.java8
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java (renamed from app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/RSS2Generator.java)18
-rw-r--r--app/src/main/AndroidManifest.xml17
-rw-r--r--app/src/main/assets/developers.csv17
-rw-r--r--app/src/main/assets/translators.csv22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/PodcastApp.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java333
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java87
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java58
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java47
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java120
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java64
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java42
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/FeedFilterDialog.java40
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java60
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java85
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ShareDialog.java112
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/StreamingConfirmationDialog.java31
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java196
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java14
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java45
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java28
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java61
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java62
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java23
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java55
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java43
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java27
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java29
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java100
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/EpisodeItemListRecyclerView.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/ItemOffsetDecoration.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/NestedScrollableHost.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/PlaybackSpeedSeekBar.java86
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/RecursiveRadioGroup.java67
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/ShownotesWebView.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/ToolbarIconTintManager.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java4
-rw-r--r--app/src/main/play/listings/en-US/full-description.txt4
-rw-r--r--app/src/main/res/layout-sw720dp/main.xml46
-rw-r--r--app/src/main/res/layout/about.xml13
-rw-r--r--app/src/main/res/layout/addfeed.xml2
-rw-r--r--app/src/main/res/layout/all_episodes_fragment.xml3
-rw-r--r--app/src/main/res/layout/audio_controls.xml46
-rw-r--r--app/src/main/res/layout/audioplayer_fragment.xml2
-rw-r--r--app/src/main/res/layout/choose_data_folder_dialog_entry.xml1
-rw-r--r--app/src/main/res/layout/cover_fragment.xml69
-rw-r--r--app/src/main/res/layout/directory_chooser.xml122
-rw-r--r--app/src/main/res/layout/downloadlog_item.xml1
-rw-r--r--app/src/main/res/layout/empty_view_layout.xml1
-rw-r--r--app/src/main/res/layout/feed_item_list_fragment.xml1
-rw-r--r--app/src/main/res/layout/feedinfo.xml2
-rw-r--r--app/src/main/res/layout/feeditemlist_header.xml2
-rw-r--r--app/src/main/res/layout/feeditemlist_item.xml2
-rw-r--r--app/src/main/res/layout/filter_dialog.xml11
-rw-r--r--app/src/main/res/layout/filter_dialog_row.xml61
-rw-r--r--app/src/main/res/layout/fragment_subscriptions.xml16
-rw-r--r--app/src/main/res/layout/listview_activity.xml12
-rw-r--r--app/src/main/res/layout/main.xml6
-rw-r--r--app/src/main/res/layout/nav_section_item.xml22
-rw-r--r--app/src/main/res/layout/playback_speed_seek_bar.xml43
-rw-r--r--app/src/main/res/layout/queue_fragment.xml1
-rw-r--r--app/src/main/res/layout/search_fragment.xml2
-rw-r--r--app/src/main/res/layout/searchlist_item.xml55
-rw-r--r--app/src/main/res/layout/share_episode_dialog.xml40
-rw-r--r--app/src/main/res/layout/simple_list_fragment.xml4
-rw-r--r--app/src/main/res/layout/speed_select_dialog.xml45
-rw-r--r--app/src/main/res/layout/statistics_fragment.xml24
-rw-r--r--app/src/main/res/menu/directory_chooser.xml16
-rw-r--r--app/src/main/res/menu/downloads_completed.xml6
-rw-r--r--app/src/main/res/menu/downloads_log.xml16
-rw-r--r--app/src/main/res/menu/downloads_running.xml10
-rw-r--r--app/src/main/res/menu/episodes_apply_action_options.xml2
-rw-r--r--app/src/main/res/menu/feeditem_options.xml24
-rw-r--r--app/src/main/res/menu/feedlist.xml24
-rw-r--r--app/src/main/res/menu/mediaplayer.xml24
-rw-r--r--app/src/main/res/menu/subscriptions.xml5
-rw-r--r--app/src/main/res/values-sw600dp/integers.xml4
-rw-r--r--app/src/main/res/values-w1000dp/dimens.xml4
-rw-r--r--app/src/main/res/values-w300dp/dimens-fabspeeddial.xml8
-rw-r--r--app/src/main/res/values-w300dp/dimens.xml11
-rw-r--r--app/src/main/res/values/dimens.xml4
-rw-r--r--app/src/main/res/values/integers.xml5
-rw-r--r--app/src/main/res/xml/automotive_app_desc.xml2
-rw-r--r--app/src/main/res/xml/feed_settings.xml1
-rw-r--r--app/src/main/res/xml/preferences.xml2
-rw-r--r--app/src/main/res/xml/preferences_autodownload.xml1
-rw-r--r--app/src/main/res/xml/preferences_import_export.xml4
-rw-r--r--app/src/main/res/xml/preferences_playback.xml2
-rw-r--r--app/src/main/res/xml/preferences_user_interface.xml37
-rw-r--r--app/src/main/res/xml/provider_paths.xml2
-rw-r--r--app/src/main/res/xml/searchable.xml4
-rw-r--r--app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java3
-rw-r--r--artwork/screenshots/generateScreenshots.sh19
-rw-r--r--artwork/screenshots/raw/de-DE/tablet.pngbin0 -> 480806 bytes
-rw-r--r--artwork/screenshots/raw/de-DE/texts.txt1
-rw-r--r--artwork/screenshots/raw/en-US/tablet.pngbin0 -> 215587 bytes
-rw-r--r--artwork/screenshots/raw/en-US/texts.txt1
-rw-r--r--artwork/screenshots/raw/fr-FR/tablet.pngbin0 -> 476990 bytes
-rw-r--r--artwork/screenshots/raw/nl-NL/tablet.pngbin0 -> 477148 bytes
-rw-r--r--artwork/screenshots/raw/nl-NL/texts.txt1
-rw-r--r--artwork/screenshots/templates/tablet.pngbin0 -> 165190 bytes
-rw-r--r--build.gradle2
-rw-r--r--core/src/main/assets/html-export-favorites-item-template.html4
-rw-r--r--core/src/main/assets/html-export-feed-template.html7
-rw-r--r--core/src/main/assets/html-export-template.html11
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/DownloadLogEvent.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java1
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java132
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java1
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedEvent.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java30
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilterGroup.java36
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java45
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java16
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/ProviderInstallerInterceptor.java18
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/UserAgentInterceptor.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java18
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java22
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java73
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java9
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java18
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java1
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java145
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java1
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java222
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java12
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java14
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java2
-rw-r--r--core/src/main/res/color/filter_dialog_background_dark.xml5
-rw-r--r--core/src/main/res/color/filter_dialog_background_light.xml5
-rw-r--r--core/src/main/res/color/filter_dialog_button_text.xml5
-rw-r--r--core/src/main/res/color/filter_dialog_clear_dark.xml5
-rw-r--r--core/src/main/res/color/filter_dialog_clear_light.xml5
-rw-r--r--core/src/main/res/drawable/ic_av_skip_black_24dp.xml7
-rw-r--r--core/src/main/res/drawable/ic_av_skip_white_24dp.xml7
-rw-r--r--core/src/main/res/drawable/ic_filter_close.xml55
-rw-r--r--core/src/main/res/values-ca/strings.xml9
-rw-r--r--core/src/main/res/values-cs/strings.xml9
-rw-r--r--core/src/main/res/values-da/strings.xml74
-rw-r--r--core/src/main/res/values-de/strings.xml62
-rw-r--r--core/src/main/res/values-es/strings.xml56
-rw-r--r--core/src/main/res/values-et/strings.xml11
-rw-r--r--core/src/main/res/values-eu/strings.xml108
-rw-r--r--core/src/main/res/values-fa/strings.xml12
-rw-r--r--core/src/main/res/values-fi/strings.xml16
-rw-r--r--core/src/main/res/values-fr/strings.xml102
-rw-r--r--core/src/main/res/values-gl/strings.xml56
-rw-r--r--core/src/main/res/values-hi/strings.xml3
-rw-r--r--core/src/main/res/values-hu/strings.xml90
-rw-r--r--core/src/main/res/values-it/strings.xml236
-rw-r--r--core/src/main/res/values-iw/strings.xml74
-rw-r--r--core/src/main/res/values-ja/strings.xml62
-rw-r--r--core/src/main/res/values-ko/strings.xml55
-rw-r--r--core/src/main/res/values-lt/strings.xml8
-rw-r--r--core/src/main/res/values-nb/strings.xml247
-rw-r--r--core/src/main/res/values-nl/strings.xml58
-rw-r--r--core/src/main/res/values-pl/strings.xml13
-rw-r--r--core/src/main/res/values-pt-rBR/strings.xml32
-rw-r--r--core/src/main/res/values-pt/strings.xml56
-rw-r--r--core/src/main/res/values-ru/strings.xml37
-rw-r--r--core/src/main/res/values-sv/strings.xml56
-rw-r--r--core/src/main/res/values-tr/strings.xml4
-rw-r--r--core/src/main/res/values-uk/strings.xml11
-rw-r--r--core/src/main/res/values-zh-rCN/strings.xml55
-rw-r--r--core/src/main/res/values/arrays.xml34
-rw-r--r--core/src/main/res/values/attrs.xml3
-rw-r--r--core/src/main/res/values/colors.xml5
-rw-r--r--core/src/main/res/values/dimens.xml2
-rw-r--r--core/src/main/res/values/ids.xml34
-rw-r--r--core/src/main/res/values/strings.xml53
-rw-r--r--core/src/main/res/values/styles.xml9
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java15
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/feed/VolumeAdaptionSettingTest.java2
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/storage/ItemEnqueuePositionCalculatorTest.java6
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/util/FeedItemUtilTest.java3
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/util/LongLongMapTest.java8
-rw-r--r--infrastructure.md65
279 files changed, 4324 insertions, 2749 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index ccdd5aaee..093954036 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -39,6 +39,10 @@ workflows:
- run:
name: Build debug
command: ./gradlew assembleDebug -PdisablePreDex
+ - store_artifacts:
+ name: Uploading apk artifact
+ path: app/build/outputs/apk/play/debug/app-play-debug.apk
+ destination: app-play-debug.apk
- run:
name: Execute debug unit tests
command: ./gradlew :core:testPlayDebugUnitTest -PdisablePreDex
@@ -80,3 +84,13 @@ workflows:
echo "Comparing to $branchBaseCommit"
curl -s -L https://github.com/yangziwen/diff-checkstyle/releases/download/0.0.4/diff-checkstyle.jar > diff-checkstyle.jar
java -Dconfig_loc=config/checkstyle -jar diff-checkstyle.jar -c config/checkstyle/checkstyle-new-code.xml --git-dir . --base-rev $branchBaseCommit
+ - build:
+ name: Lint app
+ build-steps:
+ - run:
+ name: Lint app
+ command: ./gradlew app:lintPlayRelease
+ - store_artifacts:
+ name: Uploading lint reports
+ path: app/build/reports/lint-results-playRelease.html
+ destination: lint-results.html
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index cb7c71b63..25697186a 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -4,46 +4,24 @@ about: Create a report to help us improve existing features
---
-<!--
-DELETE ME
+# Checklist
+<!-- Place an x in the boxes to tick them: [x] -->
-Use the search function to see if someone else has already submitted the same bug report.
+- [ ] I have used the search function to see if someone else has already submitted the same bug report.
+- [ ] I will describe the problem with as much detail as possible.
+- [ ] If the bug only to occurs with a certain podcast, I will include the URL of that podcast.
-Try to describe the problem with as much detail as possible.
-
-Some bugs may only occur on certain devices or versions of Android. Please add information about your device and the version of Android that is running on it (you can look these up under `Settings → About Phone`), as well as which version of AntennaPod you are using.
-
-If the bug only seems to occur with a certain podcast, please include the URL of that podcast.
-
-If possible, add instructions on how to reproduce the bug.
-
-If possible, add a logfile to your post. This is especially useful if the bug makes the application crash. AntennaPod has an `export logs` feature for this.
-
-Usually, you can take a screenshot of your smartphone by pressing *Power* + *Volume down* for a few seconds.
-
-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 experiencing a crash, including the stacktrace will likely get it fixed sooner.
--->
-
-<!-- READ THIS: The latest version may be different depending on your device. You can find the version in AntennaPod's settings. -->
-**App version**: x.y.z (state whether from Google Play/F-Droid/Custom built APK)
+# System info
+<!-- The following information is very important to fill out because some bugs may only occur on certain devices or versions of Android. -->
+**App version**: x.y.z (Where did you download the app?)
+<!-- The latest version may be different depending on your device. You can find the version in AntennaPod's settings. -->
**Android version**: 5.x (Please mention if you are using a custom rom!)
-
**Device model**:
-
-**Expected behaviour**:
-
-
-**Current behaviour**:
-
-
-**First occurred**: (e.g. about x days/weeks ago)
-
+# Bug description
**Steps to reproduce**:
1. This
@@ -51,11 +29,18 @@ If you are experiencing a crash, including the stacktrace will likely get it fix
3. Then this
4. Etc.
+**Expected behaviour**:
+<!-- After following the steps, what did you think AntennaPod would do? -->
-**Environment**: (Settings you have changed (e.g. Auto Download). "Unusual" devices you use (e.g. Bluetooth headphones). Did you select another media player?)
+**Current behaviour**:
+<!-- What did AntennaPod do instead? Screenshots might help. Usually, you can take a screenshot of your smartphone by pressing *Power* + *Volume down* for a few seconds. -->
+**First occurred**: (e.g. about x days/weeks ago)
+
+**Environment**: (Settings you have changed (e.g. Auto Download). "Unusual" devices you use (e.g. Bluetooth headphones). Did you select another media player?)
-**Stacktrace/Logcat**:
+**Stacktrace/Logcat**:
+<!-- If you are experiencing a crash, including the stacktrace will likely get it fixed sooner. AntennaPod has an `export logs` feature for this. -->
```
[if available]
```
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000..04c65727a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: AntennaPod Forum
+ url: https://forum.antennapod.org/
+ about: Reduce developer's workload by asking other users.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 8719120cd..bb60476d6 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -4,28 +4,25 @@ about: Request a new feature
---
-<!--
-DELETE ME
+# Checklist
+<!-- Place an x in the boxes to tick them: [x] -->
-Make sure you are using the latest version of AntennaPod. Perhaps the feature you are looking for has already been implemented.
+- [ ] I have used the search function to see if someone else has already submitted the same feature request.
+- [ ] I will only create one feature request per issue.
+- [ ] I will describe the problem with as much detail as possible.
-Use the search function to see if someone else has already submitted the same feature request. If there is another request already, please upvote the first post instead of commenting something like "I also want this".
+# System info
-To make it easier for us to keep track of requests, please only make one feature request per issue.
-
-Give a brief explanation about the problem that may currently exist and how your requested feature solves this problem.
-
-Try to be as specific as possible. Please not only explain what the feature does, but also how. If your request is about (or includes) changing or extending the UI, describe what the UI would look like and how the user would interact with it.
--->
-
-<!-- READ THIS: The latest version may be different depending on your device. You can find the version in AntennaPod's settings. -->
+<!-- The latest version may be different depending on your device. You can find the version in AntennaPod's settings. -->
**App version**: x.y.z (state whether from Google Play/F-Droid/Custom built APK)
+# Feature description
**Problem you may be having, or feature you want**:
-
+<!-- Give a brief explanation about the problem that may currently exist -->
**Suggested solution**:
-
+<!-- Describe how your requested feature solves this problem. Try to be as specific as possible. Please not only explain what the feature does, but also how. -->
**Screenshots / Drawings / Technical details**:
+<!-- If your request is about (or includes) changing or extending the UI, describe what the UI would look like and how the user would interact with it. -->
diff --git a/.github/PULL_REQUEST_TEMPLATE/default.md b/.github/PULL_REQUEST_TEMPLATE/default.md
new file mode 100644
index 000000000..f9fea783a
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE/default.md
@@ -0,0 +1 @@
+<!-- Please make sure that you have read our contribution guidelines: https://github.com/AntennaPod/AntennaPod/blob/develop/CONTRIBUTING.md#submit-a-pull-request -->
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7ac62535c..a7cb59fc2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -29,12 +29,9 @@ Submit a pull request
---------------------
- If you want to work on a feature that has been requested or fix a bug that has been reported on the "issues" page, add a comment to it so that other people know that you are working on it.
- Fork the repository.
-- Almost all changes of AntennaPod are done on the `develop` branch. If a new version of AntennaPod is released, the `develop` branch is merged into `master`. As a result, the `master` branch probably doesn't contain the latest changes when you are reading this. Please make sure that you are branching from `develop`! Otherwise, there might be a lot of merge-conflicts when merging your changes into `develop` and therefore it might take longer to review your pull-request. Exceptions are changes in files like README.md, CONTRIBUTING.md, and other files that are not directly related to the source code.
-- If your pull request fixes a bug that has been reported or implements a feature that has been requested in another issue, try to mention it so that it can be closed once your pull request has been merged. If you use special keywords in the [commit comment](https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) or [pull request text](https://github.blog/2013-05-14-closing-issues-via-pull-requests/), GitHub will close the issue(s) automatically when the changes land on the master branch.
-- Although not every part of AntennaPod's source code is fully documented yet, it would be very nice if you could add documentation to your changes if it is a larger pull request.
-- If possible, add unit tests for your pull request and make sure that they pass. Information on how to add unit tests and run them can be found here: (TODO)
-
-
-Improving this file
--------------------
-If you think this file needs clarification or additional information on certain topics, feel free to improve it via pull requests or by opening an issue.
+- Almost all changes of AntennaPod are done on the `develop` branch. If a new version of AntennaPod is released, the `develop` branch is merged into `master`. As a result, the `master` branch probably doesn't contain the latest changes when you are reading this. Please make sure that you are branching from `develop`! Otherwise, there might be a lot of merge-conflicts when merging your changes into `develop` and therefore it might take longer to review your pull-request. Exceptions are urgent issues that need to be fixed in the production version.
+- If your pull request fixes a bug that has been reported or implements a feature that has been requested in another issue, try to mention it in the message, so that it can be closed once your pull request has been merged. If you use special keywords in the [commit comment](https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) or [pull request text](https://github.blog/2013-05-14-closing-issues-via-pull-requests/), GitHub will close the issue(s) automatically.
+- If possible, add unit tests for your pull request and make sure that they pass.
+- Please do not upgrade dependencies or build tools unless you have a good reason for it. Doing so can easily introduce bugs that are hard to track down.
+- If you plan to do a change that touches many files (10+), please ask beforehand. This usually causes merge conflicts for other developers.
+- Please follow our code style. You can use Checkstyle within Android Studio using our [coniguration file](https://github.com/AntennaPod/AntennaPod/blob/develop/config/checkstyle/checkstyle-new-code.xml).
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 929245f98..dabd2911e 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1,11 +1,12 @@
-danieloeh
ByteHamster
+danieloeh
mfietz
TomHennen
orionlee
domingos86
andersonvom
shortspider
+ebraminio
spacecowboy
patheticpat
brad
@@ -13,25 +14,27 @@ Cj-Malone
maxbechtold
gaul
qkolj
+tonytamsf
pachecosf
ahangarha
+hannesa2
+keunes
rharriso
xgouchet
damoasda
-keunes
sevenmaster
TheRealFalcon
-hannesa2
jas14
udif
+malockin
dirkmueller
jatinkumarg
peschmae0
+TacoTheDank
orelogo
txtd
ydinath
CedricCabessa
-tonytamsf
mchelen
johnjohndoe
dethstar
@@ -51,7 +54,9 @@ twiceyuan
JessieVela
HaBaLeS
volhol
+michaelmwhite
CameronBanga
+HrBDev
HolgerJeromin
xisberto
jmue
@@ -71,10 +76,12 @@ jhunnius
ShadowIce
raghulj
raghulrm
+mamehacker
skitt
wseemann
mr-intj
tuxayo
+schlch
alimemonzx
alanorth
alexte
@@ -109,7 +116,6 @@ selivan
sonnayasomnambula
sethoscope
shantanahardy
-mamehacker
danners
corecode
vimsick
@@ -119,25 +125,26 @@ waylife
amhokies
axq
fossterer
+jmdouglas
lightonflux
minusf
-Arabic: abdelrahman.fahem93, abdunnasir, abuzar3.khalid, desha, iDemo, mohamedagamy, msahouli, nabilMaghura, rex07
+Arabic: abdelrahman.fahem93, abdunnasir, abuzar3.khalid, desha, iDemo, mohamedagamy, msahouli, nabilMaghura, rex07, shubbar
Asturian (ast_ES): enolp
Azerbaijani: danieloeh, kotfenix
Basque: gaztainalde, pospolos, zakurranputza
Bulgarian: bozhkov, ByteHamster, solusitor
Catalan: dvd1985, exort12, javiercoll, Kintu, lambdani, marcmetallextrem, xc70
-Chinese (zh_CN): bebeauties38, cyril3, domingos86, dudeG, ErlichLiu, Felix2yu, gaohongyuan, Guaidaodl, Huck0, iconteral, jhxie, kavdx, kyleehee, linxiangyu, molisiye, owen8877, RainSlide, Sak94664, spice2wolf, stellaxuyi, tupunco, wi24rd, wongsyrone, xukeek, yangyang, yiqiok, YogaGuru
-Chinese (zh_TW): ByteHamster, Fei1Yang, gugod, ijliao, nigelinux, pggdt, Solomon, ymhuang0808
+Chinese (zh_CN): bebeauties38, cyril3, domingos86, dudeG, ErlichLiu, Felix2yu, gaohongyuan, Guaidaodl, Huck0, iconteral, jhxie, jxj2zzz79pfp9bpo, kavdx, kyleehee, linxiangyu, molisiye, owen8877, RainSlide, Sak94664, spice2wolf, stellaxuyi, tonytamsf, tupunco, wi24rd, wongsyrone, xukeek, yangyang, yiqiok, YogaGuru
+Chinese (zh_TW): ByteHamster, Fei1Yang, gugod, ijliao, nigelinux, pggdt, Solomon, tonytamsf, ymhuang0808
Czech (cs_CZ): anotheranonymoususer, elich, Hanzmeister, mcepl, petnek, svetlemodry
Danish: danieloeh, jhertel
Dutch: e2jk, glotzbach, rwv, Vistaus
English: mfietz, sterylmreep
Estonian: ByteHamster, Eraser, mahfiaz
Finnish: danieloeh, elguitar, Sahtor
-French: cactux, ChaoticMind, clombion, e2jk, edewaele, lacouture, LouFex, Matth78, mfietz, Poussinou, repat, Sioul, sterylmreep, TacoTheDank, Tilwa, vcariven, whenrow
+French: cactux, ChaoticMind, clombion, e2jk, edewaele, glotzbach, lacouture, LouFex, Matth78, mfietz, Poussinou, repat, Sioul, sterylmreep, TacoTheDank, Tilwa, vcariven, whenrow
Galician: antiparvos, pikamoku, Raichely
-German: 112358, altegedanken, barilla, benedikt.g, bitsunited, Buggi, ByteHamster, ceving, ChaoticMind, Chaquotay, csrichter, dab0015, dadosch, DerSilly, die_otto, DJaeger, elkangaroo, enz, f_grubm, fidel, finsterwalder, Foso, GNi33, hightower5, HolgerJeromin, kalei, lohmann, LostInWeb, mfietz, moasda, nilso, Quiss42, rakudave, repat, SAPlayer, schafia, Schroedingberg, sevenmaster, skyerjoe, sucaml, Teaspoon, theonlytruth, weltenwort, Wyrrrd, ypid
+German: 112358, altegedanken, barilla, benedikt.g, bitsunited, Buggi, ByteHamster, ceving, ChaoticMind, Chaquotay, csrichter, dab0015, dadosch, DerSilly, die_otto, DJaeger, elkangaroo, enz, f_grubm, fidel, finsterwalder, Foso, GNi33, hightower5, HolgerJeromin, kalei, Kenriec, lohmann, LostInWeb, mfietz, moasda, nilso, Quiss42, rakudave, repat, SAPlayer, schafia, Schroedingberg, sevenmaster, skyerjoe, sucaml, Teaspoon, theonlytruth, weltenwort, Wyrrrd, ypid
Modern Greek (1453-): antonist, danieloeh, hua2016s, jack.ath92, MSavoritias, pavlosv
Hebrew (he_IL): amir.dafnyman, E1i9, mongoose4004, pinkasey, rellieberman, Yaron, הלוי11
Hindi (hi_IN): ankitiitb1069, Isaasu, nmabhinandan, purple.coder, realChakrawarti, siddhusengar
@@ -145,25 +152,25 @@ Hungarian: glatz.balazs, hurrikan, lna91, marthynw, meskobalazs, naren93, tszaue
Icelandic: marthjod
Indonesian: dbrw, jff, levirs565, luke137, rezafaiza, silvanael16
Italian (it_IT): aalex70, allin, apanontin, Bonnee, buongiorgio, giuseppep, Guybrush88, ilmanzo, m.chinni, marco_pag, neonsoftware, niccord, nixxo, sevenmaster, theloca95
-Japanese: mamehacker, Naofumi, RACER1, sh3llc4t, TranslatorG
+Japanese: KotaKato, mamehacker, Naofumi, RACER1, sh3llc4t, TranslatorG
Kannada (kn_IN): chiraag.nataraj, thejeshgn
Korean: changwoo, libliboom, seungrye, skcha
Lithuanian: naglis
Macedonian: krisfremen
Malayalam: joice, rashivkp, rubenroy
-Norwegian Bokmål (nb_NO): corkie, Dexy2811, heraldo, kongk, plexhd1, sevenmaster, timbast
-Persian: ahangarha, F7D, sinamoghaddas
+Norwegian Bokmål (nb_NO): bablecopherye, corkie, Dexy2811, heraldo, jakobkg, kongk, sevenmaster, timbast
+Persian: ahangarha, danialbehzadi, ebraminio, F7D, hamidrezabayat76, sinamoghaddas, Twastica
Polish (pl_PL): d6210809, hiro2020, Iwangelion, kRkk, lomapur, mandlus, maniexx, Mephistofeles, shark103, tyle
Portuguese: andersonvom, domingos86, emansije, smarquespt
Portuguese (pt_BR): alexupits, alysonborges, andersonvom, arua, caioau, carlo_valente, castrors, claudiofdasilva, deandreamatias, edman, Firmino, jackmiras, Junin, lipefire, lluccia, lucasmotacr, mbaltar, rogervezaro, RubeensVinicius, SamWilliam, silvanael16
Romanian (ro_RO): corneliu.e, fuzzmz, ralienpp
-Russian (ru_RU): astra1, btimofeev, Duke_Raven, gammja, GaynullinDima, homocomputeris, IgorPolyakov, MegMasters98, mercutiy, null, overmind88, PtilopsisLeucotis, s.chebotar, shams4real, skvheadless, un_logic, Vladryyu, whereisthetea, zhenya97
-Slovak: ByteHamster, tiborepcek
+Russian (ru_RU): astra1, btimofeev, Duke_Raven, gammja, GaynullinDima, homocomputeris, IgorPolyakov, MegMasters98, mercutiy, null, overmind88, Platun0v, PtilopsisLeucotis, s.chebotar, shams4real, skvheadless, un_logic, Vladryyu, whereisthetea, zhenya97
+Slovak: ati3, ByteHamster, tiborepcek
Slovenian (sl_SI): panter23
Spanish: AleksSyntek, andersonvom, Atreyu94, coperfix, deandreamatias, domingos86, dvd1985, Fitoschido, frandavid100, hard_ware, javiercoll, Juanmuto, lambdani, LatinSuD, leogrignafini, palopezv, TacoTheDank, tres.14159, vfmatzkin, wakutiteo
Swahili (macrolanguage): kmtra
Swedish (sv_SE): albin.brantin, Bio, bpnilsson, ChaoticMind, jony08, nilso, SharpMelon, TiloWiklund, TwoD
Telugu: Isaasu, veeven
-Turkish: basarancaner, brsata, Erdy, golcuk, overbite, Slsdem
+Turkish: abcmen, basarancaner, brsata, Erdy, golcuk, overbite, Slsdem
Ukrainian (uk_UA): IndibidAbulya, older, paul_sm, sergiyr, zhenya97
Vietnamese: abnvolk, nguyenvui, ppanhh, vietnamesel10n
diff --git a/README.md b/README.md
index 7415764af..50b4f1d20 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ This is the official repository of AntennaPod, the easy-to-use, flexible and ope
## Feedback
-You can use the [AntennaPod Google Group](https://groups.google.com/forum/#!forum/antennapod) for discussions about the app.
+You can use the [AntennaPod Forum](https://forum.antennapod.org/) for discussions about the app or just podcasting in general.
Bug reports and feature requests can be submitted [here](https://github.com/AntennaPod/AntennaPod/issues) (please read the [instructions](https://github.com/AntennaPod/AntennaPod/blob/master/CONTRIBUTING.md) on how to report a bug and how to submit a feature request first!).
diff --git a/app/build.gradle b/app/build.gradle
index e8bf5ac51..4b44cf80c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -14,8 +14,8 @@ android {
// "1.2.3-SNAPSHOT" -> 1020300
// "1.2.3-RC4" -> 1020304
// "1.2.3" -> 1020395
- versionCode 2000003
- versionName "2.0.0-RC3"
+ versionCode 2000007
+ versionName "2.0.0-RC7"
multiDexEnabled false
vectorDrawables.useSupportLibrary true
@@ -98,7 +98,14 @@ android {
}
lintOptions {
- abortOnError false
+ disable 'ObsoleteLintCustomCheck', 'CheckResult', 'UnusedAttribute', 'BatteryLife', 'InflateParams',
+ 'GradleDependency', 'RestrictedApi', 'TrustAllX509TrustManager', 'ExportedReceiver', 'AllowBackup',
+ 'StaticFieldLeak', 'UseCompoundDrawables', 'NestedWeights', 'Overdraw', 'UselessParent', 'TextFields',
+ 'AlwaysShowAction', 'Autofill', 'ClickableViewAccessibility', 'ContentDescription',
+ 'KeyboardInaccessibleWidget', 'LabelFor', 'SetTextI18n', 'HardcodedText', 'RelativeOverlap',
+ 'RtlCompat', 'RtlHardcoded', 'MissingMediaBrowserServiceIntentFilter'
+ warningsAsErrors true
+ abortOnError true
}
compileOptions {
@@ -182,6 +189,7 @@ dependencies {
androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
androidTestImplementation "androidx.test:runner:$runnerVersion"
androidTestImplementation "androidx.test:rules:$rulesVersion"
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
}
if (project.hasProperty("antennaPodPlayPublisherCredentials")) {
@@ -198,7 +206,6 @@ task copyLicense(type: Copy) {
rename { String fileName ->
fileName + ".txt"
}
- outputs.upToDateWhen { false }
}
preBuild.dependsOn copyLicense
diff --git a/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java b/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java
index 41c8365fb..3c8c5d7f0 100644
--- a/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java
@@ -5,7 +5,7 @@ import android.content.Intent;
import androidx.annotation.IdRes;
import androidx.annotation.StringRes;
import androidx.preference.PreferenceManager;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.espresso.PerformException;
import androidx.test.espresso.UiController;
import androidx.test.espresso.ViewAction;
@@ -116,38 +116,39 @@ public class EspressoTestUtils {
* Clear all app databases
*/
public static void clearPreferences() {
- File root = InstrumentationRegistry.getTargetContext().getFilesDir().getParentFile();
+ File root = InstrumentationRegistry.getInstrumentation().getTargetContext().getFilesDir().getParentFile();
String[] sharedPreferencesFileNames = new File(root, "shared_prefs").list();
for (String fileName : sharedPreferencesFileNames) {
System.out.println("Cleared database: " + fileName);
- InstrumentationRegistry.getTargetContext().getSharedPreferences(
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getSharedPreferences(
fileName.replace(".xml", ""), Context.MODE_PRIVATE).edit().clear().commit();
}
- InstrumentationRegistry.getTargetContext().getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE)
+ InstrumentationRegistry.getInstrumentation().getTargetContext()
+ .getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putBoolean(MainActivity.PREF_IS_FIRST_LAUNCH, false)
.commit();
- PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getTargetContext())
+ PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getInstrumentation().getTargetContext())
.edit()
.putString(UserPreferences.PREF_UPDATE_INTERVAL, "0")
.commit();
- RatingDialog.init(InstrumentationRegistry.getTargetContext());
+ RatingDialog.init(InstrumentationRegistry.getInstrumentation().getTargetContext());
RatingDialog.saveRated();
}
public static void setLastNavFragment(String tag) {
- InstrumentationRegistry.getTargetContext().getSharedPreferences(
- NavDrawerFragment.PREF_NAME, Context.MODE_PRIVATE)
+ InstrumentationRegistry.getInstrumentation().getTargetContext()
+ .getSharedPreferences(NavDrawerFragment.PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putString(NavDrawerFragment.PREF_LAST_FRAGMENT_TAG, tag)
.commit();
}
public static void clearDatabase() {
- PodDBAdapter.init(InstrumentationRegistry.getTargetContext());
+ PodDBAdapter.init(InstrumentationRegistry.getInstrumentation().getTargetContext());
PodDBAdapter.deleteDatabase();
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -172,7 +173,7 @@ public class EspressoTestUtils {
}
public static void tryKillPlaybackService() {
- Context context = InstrumentationRegistry.getTargetContext();
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
context.stopService(new Intent(context, PlaybackService.class));
try {
// Android has no reliable way to stop a service instantly.
@@ -183,11 +184,11 @@ public class EspressoTestUtils {
} catch (ConditionTimeoutException e) {
e.printStackTrace();
}
- androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
public static void tryKillDownloadService() {
- Context context = InstrumentationRegistry.getTargetContext();
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
context.stopService(new Intent(context, DownloadService.class));
try {
// Android has no reliable way to stop a service instantly.
@@ -198,7 +199,7 @@ public class EspressoTestUtils {
} catch (ConditionTimeoutException e) {
e.printStackTrace();
}
- androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
public static Matcher<View> actionBarOverflow() {
diff --git a/app/src/androidTest/java/de/test/antennapod/dialogs/ShareDialogTest.java b/app/src/androidTest/java/de/test/antennapod/dialogs/ShareDialogTest.java
new file mode 100644
index 000000000..8c628efd5
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/dialogs/ShareDialogTest.java
@@ -0,0 +1,92 @@
+package de.test.antennapod.dialogs;
+
+import android.content.Context;
+import android.content.Intent;
+import android.view.View;
+
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+import androidx.test.espresso.intent.rule.IntentsTestRule;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.fragment.EpisodesFragment;
+import de.test.antennapod.EspressoTestUtils;
+import de.test.antennapod.ui.UITestUtils;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.action.ViewActions.scrollTo;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition;
+import static androidx.test.espresso.matcher.ViewMatchers.hasMinimumChildCount;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static de.test.antennapod.EspressoTestUtils.onDrawerItem;
+import static de.test.antennapod.EspressoTestUtils.openNavDrawer;
+import static de.test.antennapod.EspressoTestUtils.waitForView;
+import static de.test.antennapod.NthMatcher.first;
+import static org.hamcrest.CoreMatchers.allOf;
+
+/**
+ * User interface tests for share dialog.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ShareDialogTest {
+
+ @Rule
+ public IntentsTestRule<MainActivity> activityRule = new IntentsTestRule<>(MainActivity.class, false, false);
+
+ private UITestUtils uiTestUtils;
+ protected Context context;
+
+ @Before
+ public void setUp() throws Exception {
+ context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ EspressoTestUtils.clearPreferences();
+ EspressoTestUtils.clearDatabase();
+ EspressoTestUtils.setLastNavFragment(EpisodesFragment.TAG);
+ uiTestUtils = new UITestUtils(context);
+ uiTestUtils.setup();
+ uiTestUtils.addLocalFeedData(true);
+
+ activityRule.launchActivity(new Intent());
+
+ openNavDrawer();
+ onDrawerItem(withText(R.string.episodes_label)).perform(click());
+ onView(isRoot()).perform(waitForView(withText(R.string.all_episodes_short_label), 1000));
+ onView(withText(R.string.all_episodes_short_label)).perform(click());
+
+ Matcher<View> allEpisodesMatcher;
+ final List<FeedItem> episodes = DBReader.getRecentlyPublishedEpisodes(0, 10);
+ allEpisodesMatcher = Matchers.allOf(withId(android.R.id.list), isDisplayed(), hasMinimumChildCount(2));
+ onView(isRoot()).perform(waitForView(allEpisodesMatcher, 1000));
+ onView(allEpisodesMatcher).perform(actionOnItemAtPosition(0, click()));
+ onView(first(EspressoTestUtils.actionBarOverflow())).perform(click());
+ }
+
+ @Test
+ public void testShareDialogDisplayed() throws InterruptedException {
+ onView(withText(R.string.share_label_with_ellipses)).perform(click());
+ onView(allOf(isDisplayed(), withText(R.string.share_label)));
+ }
+
+ @Test
+ public void testShareDialogCancelButton() {
+ onView(withText(R.string.share_label_with_ellipses)).perform(scrollTo()).perform(click());
+ onView(withText(R.string.cancel_label)).check(matches(isDisplayed())).perform(scrollTo()).perform(click());
+ }
+
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java b/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java
index b3c79367f..6da4e60a1 100644
--- a/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java
@@ -4,7 +4,7 @@ import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.MediaType;
@@ -36,7 +36,7 @@ public class ExternalMediaTest {
}
private SharedPreferences getDefaultSharedPrefs() {
- return PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getTargetContext());
+ return PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getInstrumentation().getTargetContext());
}
@Test
diff --git a/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java b/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java
index 4b81a4f2b..fc2943205 100644
--- a/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java
@@ -6,6 +6,7 @@ import de.danoeh.antennapod.core.feed.FeedItem;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@SmallTest
@@ -17,8 +18,8 @@ public class FeedFilterTest {
FeedItem item = new FeedItem();
item.setTitle("Hello world");
- assertTrue(!filter.excludeOnly());
- assertTrue(!filter.includeOnly());
+ assertFalse(filter.excludeOnly());
+ assertFalse(filter.includeOnly());
assertEquals("", filter.getExcludeFilter());
assertEquals("", filter.getIncludeFilter());
assertTrue(filter.shouldAutoDownload(item));
@@ -34,12 +35,12 @@ public class FeedFilterTest {
FeedItem item2 = new FeedItem();
item2.setTitle("Don't include me");
- assertTrue(!filter.excludeOnly());
+ assertFalse(filter.excludeOnly());
assertTrue(filter.includeOnly());
assertEquals("", filter.getExcludeFilter());
assertEquals(includeFilter, filter.getIncludeFilter());
assertTrue(filter.shouldAutoDownload(item));
- assertTrue(!filter.shouldAutoDownload(item2));
+ assertFalse(filter.shouldAutoDownload(item2));
}
@Test
@@ -53,10 +54,10 @@ public class FeedFilterTest {
item2.setTitle("Item2");
assertTrue(filter.excludeOnly());
- assertTrue(!filter.includeOnly());
+ assertFalse(filter.includeOnly());
assertEquals(excludeFilter, filter.getExcludeFilter());
assertEquals("", filter.getIncludeFilter());
- assertTrue(!filter.shouldAutoDownload(item));
+ assertFalse(filter.shouldAutoDownload(item));
assertTrue(filter.shouldAutoDownload(item2));
}
@@ -73,12 +74,12 @@ public class FeedFilterTest {
FeedItem item3 = new FeedItem();
item3.setTitle("One two words");
- assertTrue(!filter.excludeOnly());
+ assertFalse(filter.excludeOnly());
assertTrue(filter.includeOnly());
assertEquals("", filter.getExcludeFilter());
assertEquals(includeFilter, filter.getIncludeFilter());
assertTrue(filter.shouldAutoDownload(item));
- assertTrue(!filter.shouldAutoDownload(item2));
+ assertFalse(filter.shouldAutoDownload(item2));
assertTrue(filter.shouldAutoDownload(item3));
}
@@ -96,12 +97,12 @@ public class FeedFilterTest {
item3.setTitle("One two words");
assertTrue(filter.excludeOnly());
- assertTrue(!filter.includeOnly());
+ assertFalse(filter.includeOnly());
assertEquals(excludeFilter, filter.getExcludeFilter());
assertEquals("", filter.getIncludeFilter());
- assertTrue(!filter.shouldAutoDownload(item));
+ assertFalse(filter.shouldAutoDownload(item));
assertTrue(filter.shouldAutoDownload(item2));
- assertTrue(!filter.shouldAutoDownload(item3));
+ assertFalse(filter.shouldAutoDownload(item3));
}
@Test
@@ -122,8 +123,8 @@ public class FeedFilterTest {
assertTrue(filter.hasExcludeFilter());
assertTrue(filter.hasIncludeFilter());
assertTrue(filter.shouldAutoDownload(download));
- assertTrue(!filter.shouldAutoDownload(doNotDownload));
- assertTrue(!filter.shouldAutoDownload(doNotDownload2));
+ assertFalse(filter.shouldAutoDownload(doNotDownload));
+ assertFalse(filter.shouldAutoDownload(doNotDownload2));
}
}
diff --git a/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java b/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java
index e7e8c5b09..9b3422a5d 100644
--- a/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java
@@ -4,7 +4,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetServiceException;
diff --git a/app/src/androidTest/java/de/test/antennapod/handler/AtomParserTest.java b/app/src/androidTest/java/de/test/antennapod/handler/AtomParserTest.java
new file mode 100644
index 000000000..de9f53ae2
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/handler/AtomParserTest.java
@@ -0,0 +1,40 @@
+package de.test.antennapod.handler;
+
+import androidx.test.filters.SmallTest;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.test.antennapod.util.syndication.feedgenerator.AtomGenerator;
+import org.junit.Test;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for Atom feeds in FeedHandler.
+ */
+@SmallTest
+public class AtomParserTest extends FeedParserTestBase {
+ @Test
+ public void testAtomBasic() throws Exception {
+ Feed f1 = createTestFeed(10, true);
+ Feed f2 = runFeedTest(f1, new AtomGenerator(), "UTF-8", 0);
+ feedValid(f1, f2, Feed.TYPE_ATOM1);
+ }
+
+ @Test
+ public void testLogoWithWhitespace() throws Exception {
+ String logo = "https://example.com/image.png";
+ Feed f1 = createTestFeed(0, false);
+ f1.setImageUrl(null);
+ Feed f2 = runFeedTest(f1, new AtomGenerator() {
+ @Override
+ protected void writeAdditionalAttributes(XmlSerializer xml) throws IOException {
+ xml.startTag(null, "logo");
+ xml.text(" " + logo + "\n");
+ xml.endTag(null, "logo");
+ }
+ }, "UTF-8", 0);
+ assertEquals(logo, f2.getImageUrl());
+ }
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java b/app/src/androidTest/java/de/test/antennapod/handler/FeedParserTestBase.java
index ba4a944f7..83f334633 100644
--- a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/handler/FeedParserTestBase.java
@@ -1,13 +1,19 @@
package de.test.antennapod.handler;
import android.content.Context;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import de.danoeh.antennapod.core.feed.Chapter;
+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.syndication.handler.FeedHandler;
+import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeException;
+import de.test.antennapod.util.syndication.feedgenerator.FeedGenerator;
import org.junit.After;
import org.junit.Before;
-import org.junit.Test;
import org.xml.sax.SAXException;
+import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -16,28 +22,15 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import javax.xml.parsers.ParserConfigurationException;
-
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.syndication.handler.FeedHandler;
-import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeException;
-import de.test.antennapod.util.syndication.feedgenerator.AtomGenerator;
-import de.test.antennapod.util.syndication.feedgenerator.FeedGenerator;
-import de.test.antennapod.util.syndication.feedgenerator.RSS2Generator;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
- * Tests for FeedHandler
+ * Tests for FeedHandler.
*/
-@SmallTest
-public class FeedHandlerTest {
+public abstract class FeedParserTestBase {
private static final String FEEDS_DIR = "testfeeds";
private File file = null;
@@ -45,7 +38,7 @@ public class FeedHandlerTest {
@Before
public void setUp() throws Exception {
- Context context = InstrumentationRegistry.getTargetContext();
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
File destDir = context.getExternalFilesDir(FEEDS_DIR);
assertNotNull(destDir);
@@ -68,7 +61,8 @@ public class FeedHandlerTest {
outputStream = null;
}
- private Feed runFeedTest(Feed feed, FeedGenerator g, String encoding, long flags) throws IOException, UnsupportedFeedtypeException, SAXException, ParserConfigurationException {
+ protected Feed runFeedTest(Feed feed, FeedGenerator g, String encoding, long flags)
+ throws IOException, UnsupportedFeedtypeException, SAXException, ParserConfigurationException {
g.writeFeed(feed, outputStream, encoding, flags);
FeedHandler handler = new FeedHandler();
Feed parsedFeed = new Feed(feed.getDownload_url(), feed.getLastUpdate());
@@ -78,7 +72,7 @@ public class FeedHandlerTest {
return parsedFeed;
}
- private void feedValid(Feed feed, Feed parsedFeed, String feedType) {
+ protected void feedValid(Feed feed, Feed parsedFeed, String feedType) {
assertEquals(feed.getTitle(), parsedFeed.getTitle());
if (feedType.equals(Feed.TYPE_ATOM1)) {
assertEquals(feed.getFeedIdentifier(), parsedFeed.getFeedIdentifier());
@@ -99,8 +93,9 @@ public class FeedHandlerTest {
FeedItem item = feed.getItems().get(i);
FeedItem parsedItem = parsedFeed.getItems().get(i);
- if (item.getItemIdentifier() != null)
+ if (item.getItemIdentifier() != null) {
assertEquals(item.getItemIdentifier(), parsedItem.getItemIdentifier());
+ }
assertEquals(item.getTitle(), parsedItem.getTitle());
assertEquals(item.getDescription(), parsedItem.getDescription());
assertEquals(item.getContentEncoded(), parsedItem.getContentEncoded());
@@ -137,33 +132,19 @@ public class FeedHandlerTest {
}
}
- @Test
- public void testRSS2Basic() throws IOException, UnsupportedFeedtypeException, SAXException, ParserConfigurationException {
- Feed f1 = createTestFeed(10, true);
- Feed f2 = runFeedTest(f1, new RSS2Generator(), "UTF-8", RSS2Generator.FEATURE_WRITE_GUID);
- feedValid(f1, f2, Feed.TYPE_RSS2);
- }
-
- @Test
- public void testAtomBasic() throws IOException, UnsupportedFeedtypeException, SAXException, ParserConfigurationException {
- Feed f1 = createTestFeed(10, true);
- Feed f2 = runFeedTest(f1, new AtomGenerator(), "UTF-8", 0);
- feedValid(f1, f2, Feed.TYPE_ATOM1);
- }
-
- private Feed createTestFeed(int numItems, boolean withFeedMedia) {
+ protected Feed createTestFeed(int numItems, boolean withFeedMedia) {
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", "http://example.com/picture", file.getAbsolutePath(),
- "http://example.com/feed", true);
+ "http://example.com/payment", "Daniel", "en", null, "http://example.com/feed",
+ "http://example.com/picture", file.getAbsolutePath(), "http://example.com/feed", true);
feed.setItems(new ArrayList<>());
for (int i = 0; i < numItems; i++) {
FeedItem item = new FeedItem(0, "item-" + i, "http://example.com/item-" + i,
- "http://example.com/items/" + i, new Date(i*60000), FeedItem.UNPLAYED, feed);
+ "http://example.com/items/" + i, new Date(i * 60000), FeedItem.UNPLAYED, feed);
feed.getItems().add(item);
if (withFeedMedia) {
- item.setMedia(new FeedMedia(0, item, 4711, 0, 1024*1024, "audio/mp3", null, "http://example.com/media-" + i,
- false, null, 0, 0));
+ item.setMedia(new FeedMedia(0, item, 4711, 0, 1024 * 1024, "audio/mp3", null,
+ "http://example.com/media-" + i, false, null, 0, 0));
}
}
diff --git a/app/src/androidTest/java/de/test/antennapod/handler/RssParserTest.java b/app/src/androidTest/java/de/test/antennapod/handler/RssParserTest.java
new file mode 100644
index 000000000..c2e319233
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/handler/RssParserTest.java
@@ -0,0 +1,63 @@
+package de.test.antennapod.handler;
+
+import androidx.test.filters.SmallTest;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.MediaType;
+import de.danoeh.antennapod.core.syndication.namespace.NSMedia;
+import de.test.antennapod.util.syndication.feedgenerator.Rss2Generator;
+import org.junit.Test;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for RSS feeds in FeedHandler.
+ */
+@SmallTest
+public class RssParserTest extends FeedParserTestBase {
+ @Test
+ public void testRss2Basic() throws Exception {
+ Feed f1 = createTestFeed(10, true);
+ Feed f2 = runFeedTest(f1, new Rss2Generator(), "UTF-8", Rss2Generator.FEATURE_WRITE_GUID);
+ feedValid(f1, f2, Feed.TYPE_RSS2);
+ }
+
+ @Test
+ public void testImageWithWhitespace() throws Exception {
+ String image = "https://example.com/image.png";
+ Feed f1 = createTestFeed(0, false);
+ f1.setImageUrl(null);
+ Feed f2 = runFeedTest(f1, new Rss2Generator() {
+ @Override
+ protected void writeAdditionalAttributes(XmlSerializer xml) throws IOException {
+ xml.startTag(null, "image");
+ xml.startTag(null, "url");
+ xml.text(" " + image + "\n");
+ xml.endTag(null, "url");
+ xml.endTag(null, "image");
+ }
+ }, "UTF-8", 0);
+ assertEquals(image, f2.getImageUrl());
+ }
+
+ @Test
+ public void testMediaContentMime() throws Exception {
+ Feed f1 = createTestFeed(0, false);
+ f1.setImageUrl(null);
+ Feed f2 = runFeedTest(f1, new Rss2Generator() {
+ @Override
+ protected void writeAdditionalAttributes(XmlSerializer xml) throws IOException {
+ xml.setPrefix(NSMedia.NSTAG, NSMedia.NSURI);
+ xml.startTag(null, "item");
+ xml.startTag(NSMedia.NSURI, "content");
+ xml.attribute(null, "url", "https://www.example.com/file.mp4");
+ xml.attribute(null, "medium", "video");
+ xml.endTag(NSMedia.NSURI, "content");
+ xml.endTag(null, "item");
+ }
+ }, "UTF-8", 0);
+ assertEquals(MediaType.VIDEO, f2.getItems().get(0).getMedia().getMediaType());
+ }
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java
index b75044d73..fd395f7c1 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java
@@ -5,8 +5,8 @@ import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Consumer;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import de.test.antennapod.EspressoTestUtils;
import org.awaitility.Awaitility;
@@ -81,7 +81,7 @@ public class DownloadServiceTest {
@After
public void tearDown() throws Exception {
DownloadService.setDownloaderFactory(origFactory);
- Context context = InstrumentationRegistry.getTargetContext();
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
DownloadRequester.getInstance().cancelAllDownloads(context);
context.stopService(new Intent(context, DownloadService.class));
EspressoTestUtils.tryKillDownloadService();
@@ -106,9 +106,7 @@ public class DownloadServiceTest {
// OPEN: Ideally, I'd like the download time long enough so that multiple in-progress DownloadEvents
// are generated (to simulate typical download), but it'll make download time quite long (1-2 seconds)
// to do so
- DownloadService.setDownloaderFactory(new StubDownloaderFactory(50, downloadStatus -> {
- downloadStatus.setSuccessful();
- }));
+ DownloadService.setDownloaderFactory(new StubDownloaderFactory(50, DownloadStatus::setSuccessful));
UserPreferences.setEnqueueDownloadedEpisodes(enqueueDownloaded);
withFeedItemEventListener(feedItemEventListener -> {
@@ -117,7 +115,8 @@ public class DownloadServiceTest {
assertFalse("The media in test should not yet been downloaded",
DBReader.getFeedMedia(testMedia11.getId()).isDownloaded());
- DownloadRequester.getInstance().downloadMedia(false, InstrumentationRegistry.getTargetContext(), true, testMedia11.getItem());
+ DownloadRequester.getInstance().downloadMedia(false, InstrumentationRegistry
+ .getInstrumentation().getTargetContext(), true, testMedia11.getItem());
Awaitility.await()
.atMost(5000, TimeUnit.MILLISECONDS)
.until(() -> feedItemEventListener.getEvents().size() >= numEventsExpected);
@@ -144,11 +143,10 @@ public class DownloadServiceTest {
}
private void doTestCancelDownload_UndoEnqueue(boolean itemAlreadyInQueue) throws Exception {
- Context context = InstrumentationRegistry.getTargetContext();
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
// let download take longer to ensure the test can cancel the download in time
- DownloadService.setDownloaderFactory(new StubDownloaderFactory(30000, downloadStatus -> {
- downloadStatus.setSuccessful();
- }));
+ DownloadService.setDownloaderFactory(
+ new StubDownloaderFactory(30000, DownloadStatus::setSuccessful));
UserPreferences.setEnqueueDownloadedEpisodes(true);
UserPreferences.setEnableAutodownload(false);
diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
index 301ceea6c..4ef6594e3 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
@@ -1,6 +1,6 @@
package de.test.antennapod.service.download;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import android.util.Log;
@@ -51,7 +51,7 @@ public class HttpDownloaderTest {
@Before
public void setUp() throws Exception {
UserPreferences.init(InstrumentationRegistry.getInstrumentation().getTargetContext());
- destDir = InstrumentationRegistry.getTargetContext().getExternalFilesDir(DOWNLOAD_DIR);
+ destDir = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalFilesDir(DOWNLOAD_DIR);
assertNotNull(destDir);
assertTrue(destDir.exists());
httpServer = new HTTPBin();
@@ -82,7 +82,7 @@ public class HttpDownloaderTest {
downloader.call();
DownloadStatus status = downloader.getResult();
assertNotNull(status);
- assertTrue(status.isSuccessful() == expectedResult);
+ assertEquals(expectedResult, status.isSuccessful());
assertTrue(status.isDone());
// the file should not exist if the download has failed and deleteExisting was true
assertTrue(!deleteExisting || new File(feedFile.getFile_url()).exists() == expectedResult);
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 cfce069ec..c9cbf1bb2 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
@@ -38,6 +38,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -173,7 +174,7 @@ public class PlaybackServiceMediaPlayerTest {
throw assertionError;
assertTrue(res);
- assertTrue(psmp.getPSMPInfo().playerStatus == PlayerStatus.INITIALIZED);
+ assertSame(PlayerStatus.INITIALIZED, psmp.getPSMPInfo().playerStatus);
assertFalse(psmp.isStartWhenPrepared());
callback.cancel();
psmp.shutdown();
@@ -214,7 +215,7 @@ public class PlaybackServiceMediaPlayerTest {
throw assertionError;
assertTrue(res);
- assertTrue(psmp.getPSMPInfo().playerStatus == PlayerStatus.INITIALIZED);
+ assertSame(PlayerStatus.INITIALIZED, psmp.getPSMPInfo().playerStatus);
assertTrue(psmp.isStartWhenPrepared());
callback.cancel();
psmp.shutdown();
@@ -256,7 +257,7 @@ public class PlaybackServiceMediaPlayerTest {
if (assertionError != null)
throw assertionError;
assertTrue(res);
- assertTrue(psmp.getPSMPInfo().playerStatus == PlayerStatus.PREPARED);
+ assertSame(PlayerStatus.PREPARED, psmp.getPSMPInfo().playerStatus);
callback.cancel();
psmp.shutdown();
@@ -301,7 +302,7 @@ public class PlaybackServiceMediaPlayerTest {
if (assertionError != null)
throw assertionError;
assertTrue(res);
- assertTrue(psmp.getPSMPInfo().playerStatus == PlayerStatus.PLAYING);
+ assertSame(PlayerStatus.PLAYING, psmp.getPSMPInfo().playerStatus);
callback.cancel();
psmp.shutdown();
}
@@ -339,7 +340,7 @@ public class PlaybackServiceMediaPlayerTest {
if (assertionError != null)
throw assertionError;
assertTrue(res);
- assertTrue(psmp.getPSMPInfo().playerStatus == PlayerStatus.INITIALIZED);
+ assertSame(PlayerStatus.INITIALIZED, psmp.getPSMPInfo().playerStatus);
assertFalse(psmp.isStartWhenPrepared());
callback.cancel();
psmp.shutdown();
@@ -378,7 +379,7 @@ public class PlaybackServiceMediaPlayerTest {
if (assertionError != null)
throw assertionError;
assertTrue(res);
- assertTrue(psmp.getPSMPInfo().playerStatus == PlayerStatus.INITIALIZED);
+ assertSame(PlayerStatus.INITIALIZED, psmp.getPSMPInfo().playerStatus);
assertTrue(psmp.isStartWhenPrepared());
callback.cancel();
psmp.shutdown();
@@ -420,7 +421,7 @@ public class PlaybackServiceMediaPlayerTest {
if (assertionError != null)
throw assertionError;
assertTrue(res);
- assertTrue(psmp.getPSMPInfo().playerStatus == PlayerStatus.PREPARED);
+ assertSame(PlayerStatus.PREPARED, psmp.getPSMPInfo().playerStatus);
callback.cancel();
psmp.shutdown();
}
@@ -465,7 +466,7 @@ public class PlaybackServiceMediaPlayerTest {
if (assertionError != null)
throw assertionError;
assertTrue(res);
- assertTrue(psmp.getPSMPInfo().playerStatus == PlayerStatus.PLAYING);
+ assertSame(PlayerStatus.PLAYING, psmp.getPSMPInfo().playerStatus);
callback.cancel();
psmp.shutdown();
}
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 fce78ea4f..f039c8bdf 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java
@@ -1,7 +1,7 @@
package de.test.antennapod.service.playback;
import android.content.Context;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.LargeTest;
@@ -29,6 +29,7 @@ import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.playback.Playable;
import static de.test.antennapod.util.event.FeedItemEventListener.withFeedItemEventListener;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -92,9 +93,9 @@ public class PlaybackServiceTaskManagerTest {
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
List<FeedItem> testQueue = pstm.getQueue();
assertNotNull(testQueue);
- assertTrue(queue.size() == testQueue.size());
+ assertEquals(testQueue.size(), queue.size());
for (int i = 0; i < queue.size(); i++) {
- assertTrue(queue.get(i).getId() == testQueue.get(i).getId());
+ assertEquals(testQueue.get(i).getId(), queue.get(i).getId());
}
pstm.shutdown();
}
@@ -114,9 +115,9 @@ public class PlaybackServiceTaskManagerTest {
assertNotNull(queue);
testQueue = pstm.getQueue();
assertNotNull(testQueue);
- assertTrue(queue.size() == testQueue.size());
+ assertEquals(testQueue.size(), queue.size());
for (int i = 0; i < queue.size(); i++) {
- assertTrue(queue.get(i).getId() == testQueue.get(i).getId());
+ assertEquals(testQueue.get(i).getId(), queue.get(i).getId());
}
pstm.shutdown();
}
@@ -171,7 +172,7 @@ public class PlaybackServiceTaskManagerTest {
}
@Override
- public void onSleepTimerAlmostExpired() {
+ public void onSleepTimerAlmostExpired(long timeLeft) {
}
@@ -232,7 +233,7 @@ public class PlaybackServiceTaskManagerTest {
}
@Override
- public void onSleepTimerAlmostExpired() {
+ public void onSleepTimerAlmostExpired(long timeLeft) {
}
@@ -329,7 +330,7 @@ public class PlaybackServiceTaskManagerTest {
}
@Override
- public void onSleepTimerAlmostExpired() {
+ public void onSleepTimerAlmostExpired(long timeLeft) {
}
@@ -375,7 +376,7 @@ public class PlaybackServiceTaskManagerTest {
}
@Override
- public void onSleepTimerAlmostExpired() {
+ public void onSleepTimerAlmostExpired(long timeLeft) {
}
@@ -433,7 +434,7 @@ public class PlaybackServiceTaskManagerTest {
}
@Override
- public void onSleepTimerAlmostExpired() {
+ public void onSleepTimerAlmostExpired(long timeLeft) {
}
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 88d78fd14..0e38979b2 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
@@ -10,7 +10,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.Feed;
@@ -64,7 +64,7 @@ public class DBCleanupTests {
@Before
public void setUp() throws Exception {
- context = InstrumentationRegistry.getTargetContext();
+ context = InstrumentationRegistry.getInstrumentation().getTargetContext();
destFolder = new File(context.getCacheDir(), "DDCleanupTests");
destFolder.mkdir();
cleanupDestFolder(destFolder);
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 24cc80061..b76e0d1f3 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
@@ -10,7 +10,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.Feed;
@@ -55,7 +55,7 @@ public class DBNullCleanupAlgorithmTest {
@Before
public void setUp() throws Exception {
- context = InstrumentationRegistry.getTargetContext();
+ context = InstrumentationRegistry.getInstrumentation().getTargetContext();
destFolder = context.getExternalCacheDir();
cleanupDestFolder(destFolder);
assertNotNull(destFolder);
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 b2458bac6..409100e26 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java
@@ -5,7 +5,7 @@ import java.util.Date;
import java.util.List;
import java.util.Random;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -38,7 +38,7 @@ public class DBReaderTest {
@Before
public void setUp() throws Exception {
// create new database
- PodDBAdapter.init(InstrumentationRegistry.getTargetContext());
+ PodDBAdapter.init(InstrumentationRegistry.getInstrumentation().getTargetContext());
PodDBAdapter.deleteDatabase();
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -52,7 +52,7 @@ public class DBReaderTest {
assertNotNull(savedFeeds);
assertEquals(feeds.size(), savedFeeds.size());
for (int i = 0; i < feeds.size(); i++) {
- assertTrue(savedFeeds.get(i).getId() == feeds.get(i).getId());
+ assertEquals(feeds.get(i).getId(), savedFeeds.get(i).getId());
}
}
@@ -91,7 +91,7 @@ public class DBReaderTest {
List<Feed> feeds = saveFeedlist(10, 0, false);
List<String> urls = DBReader.getFeedListDownloadUrls();
assertNotNull(urls);
- assertTrue(urls.size() == feeds.size());
+ assertEquals(feeds.size(), urls.size());
for (int i = 0; i < urls.size(); i++) {
assertEquals(urls.get(i), feeds.get(i).getDownload_url());
}
@@ -115,8 +115,8 @@ public class DBReaderTest {
for (int j = 0; j < numItems; j++) {
FeedItem item = feeds.get(i).getItems().get(j);
assertNotNull(item.getFeed());
- assertTrue(item.getFeed().getId() == feeds.get(i).getId());
- assertTrue(item.getFeedId() == item.getFeed().getId());
+ assertEquals(feeds.get(i).getId(), item.getFeed().getId());
+ assertEquals(item.getFeed().getId(), item.getFeedId());
}
}
}
@@ -130,9 +130,9 @@ public class DBReaderTest {
feed.setItems(null);
List<FeedItem> savedItems = DBReader.getFeedItemList(feed);
assertNotNull(savedItems);
- assertTrue(savedItems.size() == items.size());
+ assertEquals(items.size(), savedItems.size());
for (int i = 0; i < savedItems.size(); i++) {
- assertTrue(items.get(i).getId() == savedItems.get(i).getId());
+ assertEquals(savedItems.get(i).getId(), items.get(i).getId());
}
}
@@ -167,10 +167,10 @@ public class DBReaderTest {
List<FeedItem> queue = saveQueue(numItems);
LongList ids = DBReader.getQueueIDList();
assertNotNull(ids);
- assertTrue(queue.size() == ids.size());
+ assertEquals(ids.size(), queue.size());
for (int i = 0; i < queue.size(); i++) {
assertTrue(ids.get(i) != 0);
- assertTrue(queue.get(i).getId() == ids.get(i));
+ assertEquals(ids.get(i), queue.get(i).getId());
}
}
@@ -180,10 +180,10 @@ public class DBReaderTest {
List<FeedItem> queue = saveQueue(numItems);
List<FeedItem> savedQueue = DBReader.getQueue();
assertNotNull(savedQueue);
- assertTrue(queue.size() == savedQueue.size());
+ assertEquals(savedQueue.size(), queue.size());
for (int i = 0; i < queue.size(); i++) {
assertTrue(savedQueue.get(i).getId() != 0);
- assertTrue(queue.get(i).getId() == savedQueue.get(i).getId());
+ assertEquals(savedQueue.get(i).getId(), queue.get(i).getId());
}
}
@@ -221,7 +221,7 @@ public class DBReaderTest {
List<FeedItem> downloaded = saveDownloadedItems(numItems);
List<FeedItem> downloaded_saved = DBReader.getDownloadedItems();
assertNotNull(downloaded_saved);
- assertTrue(downloaded_saved.size() == downloaded.size());
+ assertEquals(downloaded.size(), downloaded_saved.size());
for (FeedItem item : downloaded_saved) {
assertNotNull(item.getMedia());
assertTrue(item.getMedia().isDownloaded());
@@ -264,7 +264,7 @@ public class DBReaderTest {
}
List<FeedItem> newItemsSaved = DBReader.getNewItemsList(0, Integer.MAX_VALUE);
assertNotNull(newItemsSaved);
- assertTrue(newItems.size() == newItemsSaved.size());
+ assertEquals(newItemsSaved.size(), newItems.size());
for (FeedItem feedItem : newItemsSaved) {
long savedId = feedItem.getId();
boolean found = false;
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 806d5a07a..84b8d0e09 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
@@ -2,7 +2,7 @@ package de.test.antennapod.storage;
import android.content.Context;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.After;
@@ -30,6 +30,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
@@ -46,7 +47,7 @@ public class DBTasksTest {
@Before
public void setUp() throws Exception {
- context = InstrumentationRegistry.getTargetContext();
+ context = InstrumentationRegistry.getInstrumentation().getTargetContext();
// create new database
PodDBAdapter.init(context);
@@ -69,7 +70,7 @@ public class DBTasksTest {
}
Feed newFeed = DBTasks.updateFeed(context, feed, false);
- assertTrue(newFeed == feed);
+ assertSame(feed, newFeed);
assertTrue(feed.getId() != 0);
for (FeedItem item : feed.getItems()) {
assertFalse(item.isPlayed());
@@ -124,13 +125,13 @@ public class DBTasksTest {
}
final Feed newFeed = DBTasks.updateFeed(context, feed, false);
- assertTrue(feed != newFeed);
+ assertNotSame(newFeed, feed);
updatedFeedTest(newFeed, feedID, itemIDs, NUM_ITEMS_OLD, NUM_ITEMS_NEW);
final Feed feedFromDB = DBReader.getFeed(newFeed.getId());
assertNotNull(feedFromDB);
- assertTrue(feedFromDB.getId() == newFeed.getId());
+ assertEquals(newFeed.getId(), feedFromDB.getId());
updatedFeedTest(feedFromDB, feedID, itemIDs, NUM_ITEMS_OLD, NUM_ITEMS_NEW);
}
@@ -156,7 +157,7 @@ public class DBTasksTest {
feed.setItems(list);
final Feed newFeed = DBTasks.updateFeed(context, feed, false);
- assertTrue(feed != newFeed);
+ assertNotSame(newFeed, feed);
final Feed feedFromDB = DBReader.getFeed(newFeed.getId());
final FeedItem feedItemFromDB = feedFromDB.getItems().get(0);
@@ -186,21 +187,21 @@ public class DBTasksTest {
}
private void updatedFeedTest(final Feed newFeed, long feedID, List<Long> itemIDs, final int NUM_ITEMS_OLD, final int NUM_ITEMS_NEW) {
- assertTrue(newFeed.getId() == feedID);
- assertTrue(newFeed.getItems().size() == NUM_ITEMS_NEW + NUM_ITEMS_OLD);
+ assertEquals(feedID, newFeed.getId());
+ assertEquals(NUM_ITEMS_NEW + NUM_ITEMS_OLD, newFeed.getItems().size());
Collections.reverse(newFeed.getItems());
Date lastDate = new Date(0);
for (int i = 0; i < NUM_ITEMS_OLD; i++) {
FeedItem item = newFeed.getItems().get(i);
- assertTrue(item.getFeed() == newFeed);
- assertTrue(item.getId() == itemIDs.get(i));
+ assertSame(newFeed, item.getFeed());
+ assertEquals((long) itemIDs.get(i), item.getId());
assertTrue(item.isPlayed());
assertTrue(item.getPubDate().getTime() >= lastDate.getTime());
lastDate = item.getPubDate();
}
for (int i = NUM_ITEMS_OLD; i < NUM_ITEMS_NEW + NUM_ITEMS_OLD; i++) {
FeedItem item = newFeed.getItems().get(i);
- assertTrue(item.getFeed() == newFeed);
+ assertSame(newFeed, item.getFeed());
assertTrue(item.getId() != 0);
assertFalse(item.isPlayed());
assertTrue(item.getPubDate().getTime() >= lastDate.getTime());
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 5d18619a7..f7be8a371 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
@@ -7,7 +7,7 @@ import android.preference.PreferenceManager;
import android.util.Log;
import androidx.core.util.Consumer;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import org.awaitility.Awaitility;
@@ -35,9 +35,9 @@ import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -56,7 +56,7 @@ public class DBWriterTest {
public void tearDown() throws Exception {
assertTrue(PodDBAdapter.deleteDatabase());
- final Context context = InstrumentationRegistry.getTargetContext();
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
File testDir = context.getExternalFilesDir(TEST_FOLDER);
assertNotNull(testDir);
for (File f : testDir.listFiles()) {
@@ -67,13 +67,13 @@ public class DBWriterTest {
@Before
public void setUp() throws Exception {
// create new database
- PodDBAdapter.init(InstrumentationRegistry.getTargetContext());
+ PodDBAdapter.init(InstrumentationRegistry.getInstrumentation().getTargetContext());
PodDBAdapter.deleteDatabase();
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
adapter.close();
- Context context = InstrumentationRegistry.getTargetContext();
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()).edit();
prefEdit.putBoolean(UserPreferences.PREF_DELETE_REMOVES_FROM_QUEUE, true).commit();
@@ -116,7 +116,8 @@ public class DBWriterTest {
@Test
public void testDeleteFeedMediaOfItemFileExists()
throws IOException, ExecutionException, InterruptedException, TimeoutException {
- File dest = new File(getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER), "testFile");
+ File dest = new File(InstrumentationRegistry
+ .getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER), "testFile");
assertTrue(dest.createNewFile());
@@ -137,7 +138,7 @@ public class DBWriterTest {
assertTrue(media.getId() != 0);
assertTrue(item.getId() != 0);
- DBWriter.deleteFeedMediaOfItem(getInstrumentation().getTargetContext(), media.getId())
+ DBWriter.deleteFeedMediaOfItem(InstrumentationRegistry.getInstrumentation().getTargetContext(), media.getId())
.get(TIMEOUT, TimeUnit.SECONDS);
media = DBReader.getFeedMedia(media.getId());
assertNotNull(media);
@@ -151,7 +152,8 @@ public class DBWriterTest {
throws IOException, ExecutionException, InterruptedException, TimeoutException {
assertTrue(UserPreferences.shouldDeleteRemoveFromQueue());
- File dest = new File(getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER), "testFile");
+ File dest = new File(InstrumentationRegistry
+ .getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER), "testFile");
assertTrue(dest.createNewFile());
@@ -177,7 +179,7 @@ public class DBWriterTest {
queue = DBReader.getQueue();
assertTrue(queue.size() != 0);
- DBWriter.deleteFeedMediaOfItem(getInstrumentation().getTargetContext(), media.getId());
+ DBWriter.deleteFeedMediaOfItem(InstrumentationRegistry.getInstrumentation().getTargetContext(), media.getId());
Awaitility.await().until(() -> !dest.exists());
media = DBReader.getFeedMedia(media.getId());
assertNotNull(media);
@@ -185,12 +187,12 @@ public class DBWriterTest {
assertFalse(media.isDownloaded());
assertNull(media.getFile_url());
queue = DBReader.getQueue();
- assertTrue(queue.size() == 0);
+ assertEquals(0, queue.size());
}
@Test
public void testDeleteFeed() throws ExecutionException, InterruptedException, IOException, TimeoutException {
- File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
+ File destFolder = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
@@ -221,7 +223,8 @@ public class DBWriterTest {
assertTrue(item.getMedia().getId() != 0);
}
- DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.deleteFeed(InstrumentationRegistry
+ .getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
// check if files still exist
for (File f : itemFiles) {
@@ -231,14 +234,14 @@ public class DBWriterTest {
adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor c = adapter.getFeedCursor(feed.getId());
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
for (FeedItem item : feed.getItems()) {
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
c = adapter.getSingleFeedMediaCursor(item.getMedia().getId());
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
}
adapter.close();
@@ -246,7 +249,7 @@ public class DBWriterTest {
@Test
public void testDeleteFeedNoItems() throws IOException, ExecutionException, InterruptedException, TimeoutException {
- File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
+ File destFolder = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
@@ -260,19 +263,20 @@ public class DBWriterTest {
assertTrue(feed.getId() != 0);
- DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.deleteFeed(InstrumentationRegistry
+ .getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor c = adapter.getFeedCursor(feed.getId());
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
adapter.close();
}
@Test
public void testDeleteFeedNoFeedMedia() throws IOException, ExecutionException, InterruptedException, TimeoutException {
- File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
+ File destFolder = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
@@ -297,17 +301,18 @@ public class DBWriterTest {
assertTrue(item.getId() != 0);
}
- DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.deleteFeed(InstrumentationRegistry
+ .getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor c = adapter.getFeedCursor(feed.getId());
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
for (FeedItem item : feed.getItems()) {
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
}
adapter.close();
@@ -315,7 +320,7 @@ public class DBWriterTest {
@Test
public void testDeleteFeedWithQueueItems() throws ExecutionException, InterruptedException, TimeoutException {
- File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
+ File destFolder = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
@@ -344,39 +349,39 @@ public class DBWriterTest {
}
- List<FeedItem> queue = new ArrayList<>();
- queue.addAll(feed.getItems());
+ List<FeedItem> queue = new ArrayList<>(feed.getItems());
adapter.open();
adapter.setQueue(queue);
Cursor queueCursor = adapter.getQueueIDCursor();
- assertTrue(queueCursor.getCount() == queue.size());
+ assertEquals(queue.size(), queueCursor.getCount());
queueCursor.close();
adapter.close();
- DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.deleteFeed(InstrumentationRegistry
+ .getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
adapter.open();
Cursor c = adapter.getFeedCursor(feed.getId());
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
for (FeedItem item : feed.getItems()) {
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
c = adapter.getSingleFeedMediaCursor(item.getMedia().getId());
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
}
c = adapter.getQueueCursor();
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
adapter.close();
}
@Test
public void testDeleteFeedNoDownloadedFiles() throws ExecutionException, InterruptedException, TimeoutException {
- File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
+ File destFolder = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
@@ -404,19 +409,20 @@ public class DBWriterTest {
assertTrue(item.getMedia().getId() != 0);
}
- DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.deleteFeed(InstrumentationRegistry
+ .getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor c = adapter.getFeedCursor(feed.getId());
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
for (FeedItem item : feed.getItems()) {
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
c = adapter.getSingleFeedMediaCursor(item.getMedia().getId());
- assertTrue(c.getCount() == 0);
+ assertEquals(0, c.getCount());
c.close();
}
adapter.close();
@@ -440,7 +446,8 @@ public class DBWriterTest {
adapter.close();
List<FeedItem> itemsToDelete = feed.getItems().subList(0, 2);
- DBWriter.deleteFeedItems(getInstrumentation().getTargetContext(), itemsToDelete).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.deleteFeedItems(InstrumentationRegistry.getInstrumentation()
+ .getTargetContext(), itemsToDelete).get(TIMEOUT, TimeUnit.SECONDS);
adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -500,11 +507,11 @@ public class DBWriterTest {
assertNotNull(media);
assertNotNull(media.getPlaybackCompletionDate());
- assertFalse(OLD_DATE == media.getPlaybackCompletionDate().getTime());
+ assertNotEquals(media.getPlaybackCompletionDate().getTime(), OLD_DATE);
}
private Feed queueTestSetupMultipleItems(final int numItems) throws InterruptedException, ExecutionException, TimeoutException {
- final Context context = getInstrumentation().getTargetContext();
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
UserPreferences.setEnqueueLocation(UserPreferences.EnqueueLocation.BACK);
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
@@ -533,7 +540,7 @@ public class DBWriterTest {
@Test
public void testAddQueueItemSingleItem() throws InterruptedException, ExecutionException, TimeoutException {
- final Context context = getInstrumentation().getTargetContext();
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
@@ -551,14 +558,14 @@ public class DBWriterTest {
adapter.open();
Cursor cursor = adapter.getQueueIDCursor();
assertTrue(cursor.moveToFirst());
- assertTrue(cursor.getLong(0) == item.getId());
+ assertEquals(item.getId(), cursor.getLong(0));
cursor.close();
adapter.close();
}
@Test
public void testAddQueueItemSingleItemAlreadyInQueue() throws InterruptedException, ExecutionException, TimeoutException {
- final Context context = getInstrumentation().getTargetContext();
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
@@ -576,7 +583,7 @@ public class DBWriterTest {
adapter.open();
Cursor cursor = adapter.getQueueIDCursor();
assertTrue(cursor.moveToFirst());
- assertTrue(cursor.getLong(0) == item.getId());
+ assertEquals(item.getId(), cursor.getLong(0));
cursor.close();
adapter.close();
@@ -585,8 +592,8 @@ public class DBWriterTest {
adapter.open();
cursor = adapter.getQueueIDCursor();
assertTrue(cursor.moveToFirst());
- assertTrue(cursor.getLong(0) == item.getId());
- assertTrue(cursor.getCount() == 1);
+ assertEquals(item.getId(), cursor.getLong(0));
+ assertEquals(1, cursor.getCount());
cursor.close();
adapter.close();
}
@@ -600,7 +607,7 @@ public class DBWriterTest {
adapter.open();
Cursor cursor = adapter.getQueueIDCursor();
assertTrue(cursor.moveToFirst());
- assertTrue(cursor.getCount() == NUM_ITEMS);
+ assertEquals(NUM_ITEMS, cursor.getCount());
List<Long> expectedIds = FeedItemUtil.getIdList(feed.getItems());
List<Long> actualIds = new ArrayList<>();
for (int i = 0; i < NUM_ITEMS; i++) {
@@ -630,7 +637,7 @@ public class DBWriterTest {
@Test
public void testRemoveQueueItem() throws InterruptedException, ExecutionException, TimeoutException {
final int NUM_ITEMS = 10;
- final Context context = getInstrumentation().getTargetContext();
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
Feed feed = createTestFeed(NUM_ITEMS);
for (int removeIndex = 0; removeIndex < NUM_ITEMS; removeIndex++) {
@@ -644,7 +651,7 @@ public class DBWriterTest {
adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor queue = adapter.getQueueIDCursor();
- assertTrue(queue.getCount() == NUM_ITEMS - 1);
+ assertEquals(NUM_ITEMS - 1, queue.getCount());
for (int i = 0; i < queue.getCount(); i++) {
assertTrue(queue.moveToPosition(i));
final long queueID = queue.getLong(0);
@@ -666,7 +673,7 @@ public class DBWriterTest {
//
final int NUM_ITEMS = 5;
final int NUM_IN_QUEUE = NUM_ITEMS - 1; // the last one not in queue for boundary condition
- final Context context = getInstrumentation().getTargetContext();
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
Feed feed = createTestFeed(NUM_ITEMS);
List<FeedItem> itemsToAdd = feed.getItems().subList(0, NUM_IN_QUEUE);
@@ -733,11 +740,11 @@ public class DBWriterTest {
adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor queue = adapter.getQueueIDCursor();
- assertTrue(queue.getCount() == NUM_ITEMS);
+ assertEquals(NUM_ITEMS, queue.getCount());
assertTrue(queue.moveToPosition(from));
- assertFalse(queue.getLong(0) == fromID);
+ assertNotEquals(fromID, queue.getLong(0));
assertTrue(queue.moveToPosition(to));
- assertTrue(queue.getLong(0) == fromID);
+ assertEquals(fromID, queue.getLong(0));
queue.close();
adapter.close();
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.java b/app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.java
new file mode 100644
index 000000000..8bd4f1be6
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.java
@@ -0,0 +1,79 @@
+package de.test.antennapod.ui;
+
+import android.content.Intent;
+import androidx.test.espresso.intent.rule.IntentsTestRule;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.test.antennapod.EspressoTestUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static de.test.antennapod.EspressoTestUtils.clickPreference;
+import static de.test.antennapod.EspressoTestUtils.waitForView;
+import static org.hamcrest.Matchers.allOf;
+
+@RunWith(AndroidJUnit4.class)
+public class FeedSettingsTest {
+ private UITestUtils uiTestUtils;
+ private Feed feed;
+
+ @Rule
+ public IntentsTestRule<MainActivity> activityRule = new IntentsTestRule<>(MainActivity.class, false, false);
+
+ @Before
+ public void setUp() throws Exception {
+ uiTestUtils = new UITestUtils(InstrumentationRegistry.getInstrumentation().getTargetContext());
+ uiTestUtils.setup();
+
+ EspressoTestUtils.clearPreferences();
+ EspressoTestUtils.clearDatabase();
+
+ uiTestUtils.addLocalFeedData(false);
+ feed = uiTestUtils.hostedFeeds.get(0);
+ Intent intent = new Intent(InstrumentationRegistry.getInstrumentation().getTargetContext(), MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_FEED_ID, feed.getId());
+ activityRule.launchActivity(intent);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ uiTestUtils.tearDown();
+ }
+
+ @Test
+ public void testClickFeedSettings() {
+ onView(isRoot()).perform(waitForView(allOf(isDescendantOfA(withId(R.id.appBar)),
+ withText(feed.getTitle()), isDisplayed()), 1000));
+ onView(withId(R.id.butShowSettings)).perform(click());
+
+ clickPreference(R.string.keep_updated);
+
+ clickPreference(R.string.authentication_label);
+ onView(withText(R.string.cancel_label)).perform(click());
+
+ clickPreference(R.string.playback_speed);
+ onView(withText(R.string.cancel_label)).perform(click());
+
+ clickPreference(R.string.pref_feed_skip);
+ onView(withText(R.string.cancel_label)).perform(click());
+
+ clickPreference(R.string.auto_delete_label);
+ onView(withText(R.string.cancel_label)).perform(click());
+
+ clickPreference(R.string.feed_volume_reduction);
+ onView(withText(R.string.cancel_label)).perform(click());
+ }
+}
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 47988d23f..c7520a2e6 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
@@ -2,10 +2,10 @@ package de.test.antennapod.ui;
import android.app.Activity;
import android.content.Intent;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.espresso.Espresso;
import androidx.test.espresso.intent.rule.IntentsTestRule;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.robotium.solo.Solo;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
@@ -20,7 +20,6 @@ import org.junit.runner.RunWith;
import java.io.IOException;
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.replaceText;
@@ -55,10 +54,10 @@ public class MainActivityTest {
mActivityRule.launchActivity(new Intent());
- uiTestUtils = new UITestUtils(InstrumentationRegistry.getTargetContext());
+ uiTestUtils = new UITestUtils(InstrumentationRegistry.getInstrumentation().getTargetContext());
uiTestUtils.setup();
- solo = new Solo(getInstrumentation(), mActivityRule.getActivity());
+ solo = new Solo(InstrumentationRegistry.getInstrumentation(), mActivityRule.getActivity());
}
@After
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java b/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
index bf4dae882..ade5ea298 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
@@ -1,10 +1,10 @@
package de.test.antennapod.ui;
import android.content.Intent;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.espresso.contrib.DrawerActions;
import androidx.test.espresso.intent.rule.IntentsTestRule;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
@@ -59,7 +59,7 @@ public class NavigationDrawerTest {
@Before
public void setUp() throws IOException {
- uiTestUtils = new UITestUtils(InstrumentationRegistry.getTargetContext());
+ uiTestUtils = new UITestUtils(InstrumentationRegistry.getInstrumentation().getTargetContext());
uiTestUtils.setup();
EspressoTestUtils.clearPreferences();
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 6741cbc86..ddce8b1e3 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
@@ -7,7 +7,6 @@ import android.preference.PreferenceManager;
import androidx.annotation.StringRes;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
-import com.google.android.material.snackbar.Snackbar;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -31,7 +30,6 @@ import java.util.concurrent.TimeUnit;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.replaceText;
-import static androidx.test.espresso.action.ViewActions.scrollTo;
import static androidx.test.espresso.action.ViewActions.swipeDown;
import static androidx.test.espresso.action.ViewActions.swipeUp;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
@@ -46,7 +44,6 @@ import static de.test.antennapod.EspressoTestUtils.clickPreference;
import static de.test.antennapod.EspressoTestUtils.waitForView;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static junit.framework.TestCase.assertTrue;
-import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.not;
@@ -235,12 +232,10 @@ public class PreferencesTest {
@Test
public void testPlaybackSpeeds() {
clickPreference(R.string.playback_pref);
- clickPreference(R.string.media_player);
- onView(withText(R.string.media_player_exoplayer)).perform(click());
- clickPreference(R.string.pref_playback_speed_title);
- onView(isRoot()).perform(waitForView(withText("0.50"), 1000));
- onView(withText("0.50")).check(matches(isDisplayed()));
- onView(withText(R.string.cancel_label)).perform(click());
+ clickPreference(R.string.playback_speed);
+ onView(isRoot()).perform(waitForView(withText("0.75"), 1000));
+ onView(withText("0.75")).check(matches(isDisplayed()));
+ onView(withText(R.string.close_label)).perform(click());
}
@Test
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java b/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java
index b5c7dd0d1..634904f71 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java
@@ -4,7 +4,7 @@ import android.content.Intent;
import android.view.View;
import androidx.test.espresso.Espresso;
import androidx.test.espresso.intent.rule.IntentsTestRule;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.fragment.QueueFragment;
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/SpeedChangeTest.java b/app/src/androidTest/java/de/test/antennapod/ui/SpeedChangeTest.java
index 6c26078c1..ac5887069 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/SpeedChangeTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/SpeedChangeTest.java
@@ -5,7 +5,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import androidx.test.rule.ActivityTestRule;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -25,6 +25,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -70,7 +71,7 @@ public class SpeedChangeTest {
List<FeedItem> queue = DBReader.getQueue();
PlaybackPreferences.writeMediaPlaying(queue.get(0).getMedia(), PlayerStatus.PAUSED, false);
availableSpeeds = new String[] {"1.00", "2.00", "3.00"};
- UserPreferences.setPlaybackSpeedArray(availableSpeeds);
+ UserPreferences.setPlaybackSpeedArray(Arrays.asList(1.0f, 2.0f, 3.0f));
EspressoTestUtils.tryKillPlaybackService();
activityRule.launchActivity(new Intent().putExtra(MainActivity.EXTRA_OPEN_PLAYER, true));
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/TextOnlyFeedsTest.java b/app/src/androidTest/java/de/test/antennapod/ui/TextOnlyFeedsTest.java
index 782bb09d8..488c87052 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/TextOnlyFeedsTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/TextOnlyFeedsTest.java
@@ -3,7 +3,7 @@ package de.test.antennapod.ui;
import android.content.Intent;
import androidx.test.espresso.intent.rule.IntentsTestRule;
import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.Feed;
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 1dddca6b5..b989b519e 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
@@ -9,7 +9,7 @@ import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.test.antennapod.util.service.download.HTTPBin;
-import de.test.antennapod.util.syndication.feedgenerator.RSS2Generator;
+import de.test.antennapod.util.syndication.feedgenerator.Rss2Generator;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@@ -78,7 +78,7 @@ public class UITestUtils {
private String hostFeed(Feed feed) throws IOException {
File feedFile = new File(hostedFeedDir, feed.getTitle());
FileOutputStream out = new FileOutputStream(feedFile);
- RSS2Generator generator = new RSS2Generator();
+ Rss2Generator generator = new Rss2Generator();
generator.writeFeed(feed, out, "UTF-8", 0);
out.close();
int id = server.serveFile(feedFile);
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 a183b648e..60516454f 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java
@@ -5,7 +5,7 @@ import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.filters.MediumTest;
import de.danoeh.antennapod.core.feed.Feed;
@@ -29,7 +29,7 @@ public class UITestUtilsTest {
@Before
public void setUp() throws Exception {
- uiTestUtils = new UITestUtils(InstrumentationRegistry.getTargetContext());
+ uiTestUtils = new UITestUtils(InstrumentationRegistry.getInstrumentation().getTargetContext());
uiTestUtils.setup();
}
diff --git a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java b/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
index 6f8042d61..93e5bcb74 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
@@ -21,32 +21,28 @@ import static org.junit.Assert.assertTrue;
@SmallTest
public class FilenameGeneratorTest {
- private static final String VALID1 = "abc abc";
- private static final String INVALID1 = "ab/c: <abc";
- private static final String INVALID2 = "abc abc ";
-
public FilenameGeneratorTest() {
super();
}
@Test
public void testGenerateFileName() throws IOException {
- String result = FileNameGenerator.generateFileName(VALID1);
- assertEquals(result, VALID1);
+ String result = FileNameGenerator.generateFileName("abc abc");
+ assertEquals(result, "abc abc");
createFiles(result);
}
@Test
public void testGenerateFileName1() throws IOException {
- String result = FileNameGenerator.generateFileName(INVALID1);
- assertEquals(result, VALID1);
+ String result = FileNameGenerator.generateFileName("ab/c: <abc");
+ assertEquals(result, "abc abc");
createFiles(result);
}
@Test
public void testGenerateFileName2() throws IOException {
- String result = FileNameGenerator.generateFileName(INVALID2);
- assertEquals(result, VALID1);
+ String result = FileNameGenerator.generateFileName("abc abc ");
+ assertEquals(result, "abc abc");
createFiles(result);
}
@@ -63,6 +59,12 @@ public class FilenameGeneratorTest {
}
@Test
+ public void testFeedTitleContainsAccents() {
+ String result = FileNameGenerator.generateFileName("Äàáâãå");
+ assertEquals("Aaaaaa", result);
+ }
+
+ @Test
public void testInvalidInput() {
String result = FileNameGenerator.generateFileName("???");
assertFalse(TextUtils.isEmpty(result));
@@ -97,14 +99,6 @@ public class FilenameGeneratorTest {
assertTrue(testFile.exists());
testFile.delete();
assertTrue(testFile.createNewFile());
-
- }
-
- @After
- public void tearDown() {
- Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
- File f = new File(context.getExternalCacheDir(), VALID1);
- f.delete();
}
}
diff --git a/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java b/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java
index 4893d7d82..7f26ff612 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java
@@ -57,6 +57,13 @@ public class URLCheckerTest {
}
@Test
+ public void testItpcProtocolWithScheme() {
+ final String in = "itpc://https://example.com";
+ final String out = URLChecker.prepareURL(in);
+ assertEquals("https://example.com", out);
+ }
+
+ @Test
public void testWhiteSpaceUrlShouldNotAppend() {
final String in = "\n http://example.com \t";
final String out = URLChecker.prepareURL(in);
diff --git a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
index 59b9ceaca..ed37b7daa 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
@@ -2,7 +2,7 @@ package de.test.antennapod.util.playback;
import android.content.Context;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@@ -35,7 +35,7 @@ public class TimelineTest {
@Before
public void setUp() {
- context = InstrumentationRegistry.getTargetContext();
+ context = InstrumentationRegistry.getInstrumentation().getTargetContext();
}
private Playable newTestPlayable(List<Chapter> chapters, String shownotes, int duration) {
diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java
index 2dda77524..b213a5efa 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java
@@ -1,11 +1,12 @@
package de.test.antennapod.util.syndication;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileOutputStream;
+import java.nio.charset.Charset;
import java.util.Map;
import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer;
@@ -29,7 +30,8 @@ public class FeedDiscovererTest {
@Before
public void setUp() throws Exception {
fd = new FeedDiscoverer();
- testDir = new File(InstrumentationRegistry.getTargetContext().getFilesDir(), "FeedDiscovererTest");
+ testDir = new File(InstrumentationRegistry
+ .getInstrumentation().getTargetContext().getFilesDir(), "FeedDiscovererTest");
testDir.mkdir();
assertTrue(testDir.exists());
}
@@ -67,7 +69,7 @@ public class FeedDiscovererTest {
} else {
File testFile = new File(testDir, "feed");
FileOutputStream out = new FileOutputStream(testFile);
- IOUtils.write(html, out);
+ IOUtils.write(html, out, Charset.forName("UTF-8"));
out.close();
res = fd.findLinks(testFile, base);
}
diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/AtomGenerator.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/AtomGenerator.java
index 8d2408b45..c80e3bbb1 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/AtomGenerator.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/AtomGenerator.java
@@ -15,7 +15,7 @@ import de.danoeh.antennapod.core.util.DateUtils;
/**
* Creates Atom feeds. See FeedGenerator for more information.
*/
-public class AtomGenerator implements FeedGenerator{
+public class AtomGenerator implements FeedGenerator {
private static final String NS_ATOM = "http://www.w3.org/2005/Atom";
@@ -119,7 +119,13 @@ public class AtomGenerator implements FeedGenerator{
}
}
+ writeAdditionalAttributes(xml);
+
xml.endTag(null, "feed");
xml.endDocument();
}
+
+ protected void writeAdditionalAttributes(XmlSerializer xml) throws IOException {
+
+ }
}
diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/RSS2Generator.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java
index 5f8b4d18c..a9a6f91e7 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/RSS2Generator.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java
@@ -14,15 +14,19 @@ import de.danoeh.antennapod.core.util.DateUtils;
/**
* Creates RSS 2.0 feeds. See FeedGenerator for more information.
*/
-public class RSS2Generator implements FeedGenerator{
+public class Rss2Generator implements FeedGenerator {
public static final long FEATURE_WRITE_GUID = 1;
@Override
public void writeFeed(Feed feed, OutputStream outputStream, String encoding, long flags) throws IOException {
- if (feed == null) throw new IllegalArgumentException("feed = null");
- if (outputStream == null) throw new IllegalArgumentException("outputStream = null");
- if (encoding == null) throw new IllegalArgumentException("encoding = null");
+ if (feed == null) {
+ throw new IllegalArgumentException("feed = null");
+ } else if (outputStream == null) {
+ throw new IllegalArgumentException("outputStream = null");
+ } else if (encoding == null) {
+ throw new IllegalArgumentException("encoding = null");
+ }
XmlSerializer xml = Xml.newSerializer();
xml.setOutput(outputStream, encoding);
@@ -111,9 +115,15 @@ public class RSS2Generator implements FeedGenerator{
}
}
+ writeAdditionalAttributes(xml);
+
xml.endTag(null, "channel");
xml.endTag(null, "rss");
xml.endDocument();
}
+
+ protected void writeAdditionalAttributes(XmlSerializer xml) throws IOException {
+
+ }
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f0572d0ba..e7829ebc5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -36,7 +36,8 @@
android:theme="@style/Theme.AntennaPod.Splash"
android:usesCleartextTraffic="true"
android:supportsRtl="true"
- android:logo="@mipmap/ic_launcher">
+ android:logo="@mipmap/ic_launcher"
+ android:resizeableActivity="true">
<meta-data android:name="android.webkit.WebView.MetricsOptOut"
@@ -50,6 +51,11 @@
android:name="com.google.android.backup.api_key"
android:value="AEdPqrEAAAAI3a05VToCTlqBymJrbFGaKQMvF-bBAuLsOdavBA"/>
+ <!-- Version < 3.0. DeX Mode and Screen Mirroring support -->
+ <meta-data android:name="com.samsung.android.keepalive.density" android:value="true"/>
+ <!-- Version >= 3.0. DeX Dual Mode support -->
+ <meta-data android:name="com.samsung.android.multidisplay.keep_process_alive" android:value="true"/>
+
<activity
android:name=".activity.SplashActivity"
android:label="@string/app_name"
@@ -73,7 +79,7 @@
<activity
android:name=".activity.MainActivity"
- android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
+ android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|density|uiMode|keyboard|navigation"
android:windowSoftInputMode="stateHidden"
android:launchMode="singleTask"
android:label="@string/app_name">
@@ -192,13 +198,6 @@
<data android:mimeType="video/*"/>
</intent-filter>
</activity>
- <activity
- android:name=".activity.DirectoryChooserActivity"
- android:label="@string/choose_data_directory">
- <meta-data
- android:name="android.support.PARENT_ACTIVITY"
- android:value="de.danoeh.antennapod.activity.PreferenceActivity"/>
- </activity>
<activity
android:name=".activity.OnlineFeedViewActivity"
diff --git a/app/src/main/assets/developers.csv b/app/src/main/assets/developers.csv
index 5caa35647..ab8169eef 100644
--- a/app/src/main/assets/developers.csv
+++ b/app/src/main/assets/developers.csv
@@ -1,11 +1,12 @@
-danieloeh;968613;Original creator of AntennaPod (retired)
ByteHamster;5811634;Maintainer
+danieloeh;968613;Original creator of AntennaPod (retired)
mfietz;6860662;Maintainer
TomHennen;5216560;Maintainer (retired)
orionlee;250644;Contributor
domingos86;9538859;Contributor
andersonvom;69922;Contributor
shortspider;5712543;Contributor
+ebraminio;833473;Contributor
spacecowboy;223655;Contributor
patheticpat;16046;Contributor
brad;1614;Contributor
@@ -13,25 +14,27 @@ Cj-Malone;10121513;Contributor
maxbechtold;9162198;Contributor
gaul;848247;Contributor
qkolj;6667105;Contributor
+tonytamsf;149837;Contributor
pachecosf;46357909;Contributor
ahangarha;11241315;Contributor
+hannesa2;3314607;Contributor
+keunes;11229646;Contributor
rharriso;570910;Contributor
xgouchet;818706;Contributor
damoasda;46045854;Contributor
-keunes;11229646;Contributor
sevenmaster;12869538;Contributor
TheRealFalcon;153674;Contributor
-hannesa2;3314607;Contributor
jas14;569991;Contributor
udif;809640;Contributor
+malockin;12814657;Contributor
dirkmueller;1029152;Contributor
jatinkumarg;20503830;Contributor
peschmae0;4450993;Contributor
+TacoTheDank;32376686;Contributor
orelogo;15976578;Contributor
txtd;7108931;Contributor
ydinath;4193331;Contributor
CedricCabessa;365097;Contributor
-tonytamsf;149837;Contributor
mchelen;30691;Contributor
johnjohndoe;144518;Contributor
dethstar;1239177;Contributor
@@ -51,7 +54,9 @@ twiceyuan;2619800;Contributor
JessieVela;33134794;Contributor
HaBaLeS;730902;Contributor
volhol;11587858;Contributor
+michaelmwhite;28901334;Contributor
CameronBanga;611354;Contributor
+HrBDev;25826502;Contributor
HolgerJeromin;2410353;Contributor
xisberto;1914956;Contributor
jmue;898577;Contributor
@@ -71,10 +76,12 @@ jhunnius;9149031;Contributor
ShadowIce;59123;Contributor
raghulj;57007;Contributor
raghulrm;5362986;Contributor
+mamehacker;16738348;Contributor
skitt;2128935;Contributor
wseemann;2296196;Contributor
mr-intj;6268767;Contributor
tuxayo;2678215;Contributor
+schlch;56929215;Contributor
alimemonzx;44647595;Contributor
alanorth;191754;Contributor
alexte;7724992;Contributor
@@ -109,7 +116,6 @@ selivan;1208989;Contributor
sonnayasomnambula;7716779;Contributor
sethoscope;534043;Contributor
shantanahardy;26757164;Contributor
-mamehacker;16738348;Contributor
danners;116551;Contributor
corecode;177979;Contributor
vimsick;20211590;Contributor
@@ -119,5 +125,6 @@ waylife;3348620;Contributor
amhokies;3124968;Contributor
axq;5077221;Contributor
fossterer;4236021;Contributor
+jmdouglas;10855634;Contributor
lightonflux;1377943;Contributor
minusf;3632883;Contributor
diff --git a/app/src/main/assets/translators.csv b/app/src/main/assets/translators.csv
index d035c2afd..90b98f8db 100644
--- a/app/src/main/assets/translators.csv
+++ b/app/src/main/assets/translators.csv
@@ -1,20 +1,20 @@
-Arabic;abdelrahman.fahem93, abdunnasir, abuzar3.khalid, desha, iDemo, mohamedagamy, msahouli, nabilMaghura, rex07
+Arabic;abdelrahman.fahem93, abdunnasir, abuzar3.khalid, desha, iDemo, mohamedagamy, msahouli, nabilMaghura, rex07, shubbar
Asturian (ast_ES);enolp
Azerbaijani;danieloeh, kotfenix
Basque;gaztainalde, pospolos, zakurranputza
Bulgarian;bozhkov, ByteHamster, solusitor
Catalan;dvd1985, exort12, javiercoll, Kintu, lambdani, marcmetallextrem, xc70
-Chinese (zh_CN);bebeauties38, cyril3, domingos86, dudeG, ErlichLiu, Felix2yu, gaohongyuan, Guaidaodl, Huck0, iconteral, jhxie, kavdx, kyleehee, linxiangyu, molisiye, owen8877, RainSlide, Sak94664, spice2wolf, stellaxuyi, tupunco, wi24rd, wongsyrone, xukeek, yangyang, yiqiok, YogaGuru
-Chinese (zh_TW);ByteHamster, Fei1Yang, gugod, ijliao, nigelinux, pggdt, Solomon, ymhuang0808
+Chinese (zh_CN);bebeauties38, cyril3, domingos86, dudeG, ErlichLiu, Felix2yu, gaohongyuan, Guaidaodl, Huck0, iconteral, jhxie, jxj2zzz79pfp9bpo, kavdx, kyleehee, linxiangyu, molisiye, owen8877, RainSlide, Sak94664, spice2wolf, stellaxuyi, tonytamsf, tupunco, wi24rd, wongsyrone, xukeek, yangyang, yiqiok, YogaGuru
+Chinese (zh_TW);ByteHamster, Fei1Yang, gugod, ijliao, nigelinux, pggdt, Solomon, tonytamsf, ymhuang0808
Czech (cs_CZ);anotheranonymoususer, elich, Hanzmeister, mcepl, petnek, svetlemodry
Danish;danieloeh, jhertel
Dutch;e2jk, glotzbach, rwv, Vistaus
English;mfietz, sterylmreep
Estonian;ByteHamster, Eraser, mahfiaz
Finnish;danieloeh, elguitar, Sahtor
-French;cactux, ChaoticMind, clombion, e2jk, edewaele, lacouture, LouFex, Matth78, mfietz, Poussinou, repat, Sioul, sterylmreep, TacoTheDank, Tilwa, vcariven, whenrow
+French;cactux, ChaoticMind, clombion, e2jk, edewaele, glotzbach, lacouture, LouFex, Matth78, mfietz, Poussinou, repat, Sioul, sterylmreep, TacoTheDank, Tilwa, vcariven, whenrow
Galician;antiparvos, pikamoku, Raichely
-German;112358, altegedanken, barilla, benedikt.g, bitsunited, Buggi, ByteHamster, ceving, ChaoticMind, Chaquotay, csrichter, dab0015, dadosch, DerSilly, die_otto, DJaeger, elkangaroo, enz, f_grubm, fidel, finsterwalder, Foso, GNi33, hightower5, HolgerJeromin, kalei, lohmann, LostInWeb, mfietz, moasda, nilso, Quiss42, rakudave, repat, SAPlayer, schafia, Schroedingberg, sevenmaster, skyerjoe, sucaml, Teaspoon, theonlytruth, weltenwort, Wyrrrd, ypid
+German;112358, altegedanken, barilla, benedikt.g, bitsunited, Buggi, ByteHamster, ceving, ChaoticMind, Chaquotay, csrichter, dab0015, dadosch, DerSilly, die_otto, DJaeger, elkangaroo, enz, f_grubm, fidel, finsterwalder, Foso, GNi33, hightower5, HolgerJeromin, kalei, Kenriec, lohmann, LostInWeb, mfietz, moasda, nilso, Quiss42, rakudave, repat, SAPlayer, schafia, Schroedingberg, sevenmaster, skyerjoe, sucaml, Teaspoon, theonlytruth, weltenwort, Wyrrrd, ypid
Modern Greek (1453-);antonist, danieloeh, hua2016s, jack.ath92, MSavoritias, pavlosv
Hebrew (he_IL);amir.dafnyman, E1i9, mongoose4004, pinkasey, rellieberman, Yaron, הלוי11
Hindi (hi_IN);ankitiitb1069, Isaasu, nmabhinandan, purple.coder, realChakrawarti, siddhusengar
@@ -22,25 +22,25 @@ Hungarian;glatz.balazs, hurrikan, lna91, marthynw, meskobalazs, naren93, tszauer
Icelandic;marthjod
Indonesian;dbrw, jff, levirs565, luke137, rezafaiza, silvanael16
Italian (it_IT);aalex70, allin, apanontin, Bonnee, buongiorgio, giuseppep, Guybrush88, ilmanzo, m.chinni, marco_pag, neonsoftware, niccord, nixxo, sevenmaster, theloca95
-Japanese;mamehacker, Naofumi, RACER1, sh3llc4t, TranslatorG
+Japanese;KotaKato, mamehacker, Naofumi, RACER1, sh3llc4t, TranslatorG
Kannada (kn_IN);chiraag.nataraj, thejeshgn
Korean;changwoo, libliboom, seungrye, skcha
Lithuanian;naglis
Macedonian;krisfremen
Malayalam;joice, rashivkp, rubenroy
-Norwegian Bokmål (nb_NO);corkie, Dexy2811, heraldo, kongk, plexhd1, sevenmaster, timbast
-Persian;ahangarha, F7D, sinamoghaddas
+Norwegian Bokmål (nb_NO);bablecopherye, corkie, Dexy2811, heraldo, jakobkg, kongk, sevenmaster, timbast
+Persian;ahangarha, danialbehzadi, ebraminio, F7D, hamidrezabayat76, sinamoghaddas, Twastica
Polish (pl_PL);d6210809, hiro2020, Iwangelion, kRkk, lomapur, mandlus, maniexx, Mephistofeles, shark103, tyle
Portuguese;andersonvom, domingos86, emansije, smarquespt
Portuguese (pt_BR);alexupits, alysonborges, andersonvom, arua, caioau, carlo_valente, castrors, claudiofdasilva, deandreamatias, edman, Firmino, jackmiras, Junin, lipefire, lluccia, lucasmotacr, mbaltar, rogervezaro, RubeensVinicius, SamWilliam, silvanael16
Romanian (ro_RO);corneliu.e, fuzzmz, ralienpp
-Russian (ru_RU);astra1, btimofeev, Duke_Raven, gammja, GaynullinDima, homocomputeris, IgorPolyakov, MegMasters98, mercutiy, null, overmind88, PtilopsisLeucotis, s.chebotar, shams4real, skvheadless, un_logic, Vladryyu, whereisthetea, zhenya97
-Slovak;ByteHamster, tiborepcek
+Russian (ru_RU);astra1, btimofeev, Duke_Raven, gammja, GaynullinDima, homocomputeris, IgorPolyakov, MegMasters98, mercutiy, null, overmind88, Platun0v, PtilopsisLeucotis, s.chebotar, shams4real, skvheadless, un_logic, Vladryyu, whereisthetea, zhenya97
+Slovak;ati3, ByteHamster, tiborepcek
Slovenian (sl_SI);panter23
Spanish;AleksSyntek, andersonvom, Atreyu94, coperfix, deandreamatias, domingos86, dvd1985, Fitoschido, frandavid100, hard_ware, javiercoll, Juanmuto, lambdani, LatinSuD, leogrignafini, palopezv, TacoTheDank, tres.14159, vfmatzkin, wakutiteo
Swahili (macrolanguage);kmtra
Swedish (sv_SE);albin.brantin, Bio, bpnilsson, ChaoticMind, jony08, nilso, SharpMelon, TiloWiklund, TwoD
Telugu;Isaasu, veeven
-Turkish;basarancaner, brsata, Erdy, golcuk, overbite, Slsdem
+Turkish;abcmen, basarancaner, brsata, Erdy, golcuk, overbite, Slsdem
Ukrainian (uk_UA);IndibidAbulya, older, paul_sm, sergiyr, zhenya97
Vietnamese;abnvolk, nguyenvui, ppanhh, vietnamesel10n
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
index 4e6b8fa29..ed3f4e8f1 100644
--- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
+++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
@@ -1,12 +1,15 @@
package de.danoeh.antennapod;
import android.app.Application;
+import android.content.ComponentName;
+import android.content.Intent;
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.activity.SplashActivity;
import de.danoeh.antennapod.core.ApCoreEventBusIndex;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.spa.SPAUtil;
@@ -63,4 +66,12 @@ public class PodcastApp extends Application {
.installDefaultEventBus();
}
+ public static void forceRestart() {
+ Intent intent = new Intent(getInstance(), SplashActivity.class);
+ ComponentName cn = intent.getComponent();
+ Intent mainIntent = Intent.makeRestartActivityTask(cn);
+ getInstance().startActivity(mainIntent);
+ Runtime.getRuntime().exit(0);
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java
index 48264bb26..b1a0ba2a2 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java
@@ -42,9 +42,8 @@ public class BugReportActivity extends AppCompatActivity {
}
crashDetailsTextView.setText(crashDetailsText);
- findViewById(R.id.btn_open_bug_tracker).setOnClickListener(v -> {
- IntentUtils.openInBrowser(BugReportActivity.this, "https://github.com/AntennaPod/AntennaPod/issues");
- });
+ findViewById(R.id.btn_open_bug_tracker).setOnClickListener(v -> IntentUtils.openInBrowser(
+ BugReportActivity.this, "https://github.com/AntennaPod/AntennaPod/issues"));
findViewById(R.id.btn_copy_log).setOnClickListener(v -> {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
deleted file mode 100644
index 49ce954bc..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
+++ /dev/null
@@ -1,333 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.FileObserver;
-import androidx.core.app.NavUtils;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.ImageButton;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-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 AppCompatActivity {
-
- private static final String TAG = "DirectoryChooserActivit";
-
- private static final String CREATE_DIRECTORY_NAME = "AntennaPod";
-
- public static final String RESULT_SELECTED_DIR = "selected_dir";
- public static final int RESULT_CODE_DIR_SELECTED = 1;
-
- private Button butConfirm;
- private Button butCancel;
- private ImageButton butNavUp;
- private TextView txtvSelectedFolder;
- private ListView listDirectories;
-
- private ArrayAdapter<String> listDirectoriesAdapter;
- private ArrayList<String> filenames;
- /** The directory that is currently being shown. */
- private File selectedDir;
- private File[] filesInDir;
-
- private FileObserver fileObserver;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- setContentView(R.layout.directory_chooser);
- butConfirm = findViewById(R.id.butConfirm);
- butCancel = findViewById(R.id.butCancel);
- butNavUp = findViewById(R.id.butNavUp);
- txtvSelectedFolder = findViewById(R.id.txtvSelectedFolder);
- listDirectories = findViewById(R.id.directory_list);
-
- butConfirm.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- if (isValidFile(selectedDir)) {
- if (selectedDir.list().length == 0) {
- returnSelectedFolder();
- } else {
- showNonEmptyDirectoryWarning();
- }
- }
- }
-
- private void showNonEmptyDirectoryWarning() {
- AlertDialog.Builder adb = new AlertDialog.Builder(
- DirectoryChooserActivity.this);
- adb.setTitle(R.string.folder_not_empty_dialog_title);
- adb.setMessage(R.string.folder_not_empty_dialog_msg);
- adb.setNegativeButton(R.string.cancel_label,
- (dialog, which) -> dialog.dismiss());
- adb.setPositiveButton(R.string.confirm_label,
- (dialog, which) -> {
- dialog.dismiss();
- returnSelectedFolder();
- });
- adb.create().show();
- }
- });
-
- butCancel.setOnClickListener(v -> {
- setResult(Activity.RESULT_CANCELED);
- finish();
- });
-
- listDirectories.setOnItemClickListener((adapter, view, position, id) -> {
- Log.d(TAG, "Selected index: " + position);
- if (filesInDir != null && position >= 0
- && position < filesInDir.length) {
- changeDirectory(filesInDir[position]);
- }
- });
-
- butNavUp.setOnClickListener(v -> {
- File parent = null;
- if (selectedDir != null
- && (parent = selectedDir.getParentFile()) != null) {
- changeDirectory(parent);
- }
- });
-
- filenames = new ArrayList<>();
- listDirectoriesAdapter = new ArrayAdapter<>(this,
- android.R.layout.simple_list_item_1, filenames);
- listDirectories.setAdapter(listDirectoriesAdapter);
- changeDirectory(Environment.getExternalStorageDirectory());
- }
-
- /**
- * Finishes the activity and returns the selected folder as a result. The
- * selected folder can also be null.
- */
- private void returnSelectedFolder() {
- if (selectedDir != null && BuildConfig.DEBUG)
- Log.d(TAG, "Returning " + selectedDir.getAbsolutePath()
- + " as result");
- Intent resultData = new Intent();
- if (selectedDir != null) {
- resultData.putExtra(RESULT_SELECTED_DIR,
- selectedDir.getAbsolutePath());
- }
- setResult(Activity.RESULT_OK, resultData);
- finish();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- if (fileObserver != null) {
- fileObserver.stopWatching();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (fileObserver != null) {
- fileObserver.startWatching();
- }
- }
-
- @Override
- public void onStop() {
- super.onStop();
- listDirectoriesAdapter = null;
- fileObserver = null;
- }
-
- /**
- * Change the directory that is currently being displayed.
- *
- * @param dir
- * The file the activity should switch to. This File must be
- * non-null and a directory, otherwise the displayed directory
- * will not be changed
- */
- private void changeDirectory(File dir) {
- if (dir != null && dir.isDirectory()) {
- File[] contents = dir.listFiles();
- if (contents != null) {
- int numDirectories = 0;
- for (File f : contents) {
- if (f.isDirectory()) {
- numDirectories++;
- }
- }
- filesInDir = new File[numDirectories];
- filenames.clear();
- for (int i = 0, counter = 0; i < numDirectories; counter++) {
- if (contents[counter].isDirectory()) {
- filesInDir[i] = contents[counter];
- filenames.add(contents[counter].getName());
- i++;
- }
- }
- Arrays.sort(filesInDir);
- Collections.sort(filenames);
- selectedDir = dir;
- txtvSelectedFolder.setText(dir.getAbsolutePath());
- listDirectoriesAdapter.notifyDataSetChanged();
- fileObserver = createFileObserver(dir.getAbsolutePath());
- fileObserver.startWatching();
- Log.d(TAG, "Changed directory to " + dir.getAbsolutePath());
- } else {
- Log.d(TAG, "Could not change folder: contents of dir were null");
- }
- } else {
- if (dir == null) {
- Log.d(TAG, "Could not change folder: dir was null");
- } else {
- Log.d(TAG, "Could not change folder: dir is no directory");
- }
- }
- refreshButtonState();
- }
-
- /**
- * Changes the state of the buttons depending on the currently selected file
- * or folder.
- */
- private void refreshButtonState() {
- if (selectedDir != null) {
- butConfirm.setEnabled(isValidFile(selectedDir));
- supportInvalidateOptionsMenu();
- }
- }
-
- /** Refresh the contents of the directory that is currently shown. */
- private void refreshDirectory() {
- if (selectedDir != null) {
- changeDirectory(selectedDir);
- }
- }
-
- /** Sets up a FileObserver to watch the current directory. */
- private FileObserver createFileObserver(String path) {
- return new FileObserver(path, FileObserver.CREATE | FileObserver.DELETE
- | FileObserver.MOVED_FROM | FileObserver.MOVED_TO) {
-
- @Override
- public void onEvent(int event, String path) {
- Log.d(TAG, "FileObserver received event " + event);
- runOnUiThread(DirectoryChooserActivity.this::refreshDirectory);
- }
- };
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.new_folder_item).setVisible(isValidFile(selectedDir));
- return true;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.directory_chooser, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- return true;
- case R.id.new_folder_item:
- openNewFolderDialog();
- return true;
- case R.id.set_to_default_folder_item:
- selectedDir = null;
- returnSelectedFolder();
- return true;
- default:
- return false;
- }
- }
-
- /**
- * Shows a confirmation dialog that asks the user if he wants to create a
- * new folder.
- */
- private void openNewFolderDialog() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.create_folder_label);
- builder.setMessage(String.format(getString(R.string.create_folder_msg),
- CREATE_DIRECTORY_NAME));
- builder.setNegativeButton(R.string.cancel_label,
- (dialog, which) -> dialog.dismiss());
- builder.setPositiveButton(R.string.confirm_label,
- (dialog, which) -> {
- dialog.dismiss();
- int msg = createFolder();
- Toast t = Toast.makeText(DirectoryChooserActivity.this,
- msg, Toast.LENGTH_SHORT);
- t.show();
- });
- builder.create().show();
- }
-
- /**
- * Creates a new folder in the current directory with the name
- * CREATE_DIRECTORY_NAME.
- */
- private int createFolder() {
- if (selectedDir == null) {
- return R.string.create_folder_error;
- } else if (selectedDir.canWrite()) {
- File newDir = new File(selectedDir, CREATE_DIRECTORY_NAME);
- if (!newDir.exists()) {
- boolean result = newDir.mkdir();
- if (result) {
- return R.string.create_folder_success;
- } else {
- return R.string.create_folder_error;
- }
- } else {
- return R.string.create_folder_error_already_exists;
- }
- } else {
- return R.string.create_folder_error_no_write_access;
- }
- }
-
- /** Returns true if the selected file or directory would be valid selection. */
- 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/DownloadAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
index 810005d2d..1d3d9bf11 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
@@ -3,6 +3,8 @@ package de.danoeh.antennapod.activity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
+
+import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.Button;
@@ -86,7 +88,7 @@ public class DownloadAuthenticationActivity extends AppCompatActivity {
}
@Override
- protected void onSaveInstanceState(Bundle outState) {
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("username", etxtUsername.getText().toString());
outState.putString("password", etxtPassword.getText().toString());
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 655049b2c..f772cb084 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -5,10 +5,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -31,6 +34,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.event.MessageEvent;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.StorageUtils;
+import de.danoeh.antennapod.core.util.ThemeUtils;
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.dialog.RatingDialog;
import de.danoeh.antennapod.fragment.AddFeedFragment;
@@ -68,9 +72,9 @@ public class MainActivity extends CastEnabledActivity {
public static final String EXTRA_OPEN_PLAYER = "open_player";
public static final String EXTRA_REFRESH_ON_START = "refresh_on_start";
- private DrawerLayout drawerLayout;
+ private @Nullable DrawerLayout drawerLayout;
+ private @Nullable ActionBarDrawerToggle drawerToggle;
private View navDrawer;
- private ActionBarDrawerToggle drawerToggle;
private LockableBottomSheetBehavior sheetBehavior;
private long lastBackButtonPressTime = 0;
private RecyclerView.RecycledViewPool recycledViewPool = new RecyclerView.RecycledViewPool();
@@ -91,14 +95,21 @@ public class MainActivity extends CastEnabledActivity {
super.onCreate(savedInstanceState);
StorageUtils.checkStorageAvailability(this);
setContentView(R.layout.main);
- recycledViewPool.setMaxRecycledViews(R.id.episode_item_view_holder, 25);
+ recycledViewPool.setMaxRecycledViews(R.id.view_type_episode_item, 25);
drawerLayout = findViewById(R.id.drawer_layout);
navDrawer = findViewById(R.id.navDrawerFragment);
+ setNavDrawerSize();
final FragmentManager fm = getSupportFragmentManager();
- fm.addOnBackStackChangedListener(() ->
- drawerToggle.setDrawerIndicatorEnabled(fm.getBackStackEntryCount() == 0));
+ fm.addOnBackStackChangedListener(() -> {
+ boolean showArrow = fm.getBackStackEntryCount() != 0;
+ if (drawerToggle != null) { // Tablet layout does not have a drawer
+ drawerToggle.setDrawerIndicatorEnabled(!showArrow);
+ } else if (getActionBar() != null) {
+ getActionBar().setDisplayHomeAsUpEnabled(showArrow);
+ }
+ });
if (fm.findFragmentByTag(MAIN_FRAGMENT_TAG) == null) {
String lastFragment = NavDrawerFragment.getLastNavFragment(this);
@@ -151,12 +162,18 @@ public class MainActivity extends CastEnabledActivity {
@Override
public void setSupportActionBar(@Nullable Toolbar toolbar) {
- drawerLayout.removeDrawerListener(drawerToggle);
- drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar,
- R.string.drawer_open, R.string.drawer_close);
- drawerLayout.addDrawerListener(drawerToggle);
- drawerToggle.syncState();
- drawerToggle.setDrawerIndicatorEnabled(getSupportFragmentManager().getBackStackEntryCount() == 0);
+ if (drawerLayout != null) { // Tablet layout does not have a drawer
+ drawerLayout.removeDrawerListener(drawerToggle);
+ drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar,
+ R.string.drawer_open, R.string.drawer_close);
+ drawerLayout.addDrawerListener(drawerToggle);
+ drawerToggle.syncState();
+ drawerToggle.setDrawerIndicatorEnabled(getSupportFragmentManager().getBackStackEntryCount() == 0);
+ } else if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
+ toolbar.setNavigationIcon(null);
+ } else {
+ toolbar.setNavigationIcon(ThemeUtils.getDrawableFromAttr(this, R.attr.homeAsUpIndicator));
+ }
super.setSupportActionBar(toolbar);
}
@@ -164,7 +181,11 @@ public class MainActivity extends CastEnabledActivity {
SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
if (prefs.getBoolean(PREF_IS_FIRST_LAUNCH, true)) {
loadFragment(AddFeedFragment.TAG, null);
- new Handler().postDelayed(() -> drawerLayout.openDrawer(navDrawer), 1500);
+ new Handler().postDelayed(() -> {
+ if (drawerLayout != null) { // Tablet layout does not have a drawer
+ drawerLayout.openDrawer(navDrawer);
+ }
+ }, 1500);
// for backward compatibility, we only change defaults for fresh installs
UserPreferences.setUpdateInterval(12);
@@ -258,7 +279,10 @@ public class MainActivity extends CastEnabledActivity {
// not commit anything in an AsyncTask, but that's a bigger
// change than we want now.
t.commitAllowingStateLoss();
- drawerLayout.closeDrawer(navDrawer);
+
+ if (drawerLayout != null) { // Tablet layout does not have a drawer
+ drawerLayout.closeDrawer(navDrawer);
+ }
}
public void loadChildFragment(Fragment fragment, TransitionEffect transition) {
@@ -292,13 +316,35 @@ public class MainActivity extends CastEnabledActivity {
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
- drawerToggle.syncState();
+ if (drawerToggle != null) { // Tablet layout does not have a drawer
+ drawerToggle.syncState();
+ }
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- drawerToggle.onConfigurationChanged(newConfig);
+ if (drawerToggle != null) { // Tablet layout does not have a drawer
+ drawerToggle.onConfigurationChanged(newConfig);
+ }
+ setNavDrawerSize();
+ }
+
+ private void setNavDrawerSize() {
+ if (drawerToggle == null) { // Tablet layout does not have a drawer
+ return;
+ }
+ float screenPercent = getResources().getInteger(R.integer.nav_drawer_screen_size_percent) * 0.01f;
+ int width = (int) (getScreenWidth() * screenPercent);
+ int maxWidth = (int) getResources().getDimension(R.dimen.nav_drawer_max_screen_size);
+
+ navDrawer.getLayoutParams().width = Math.min(width, maxWidth);
+ }
+
+ private int getScreenWidth() {
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+ return displayMetrics.widthPixels;
}
@Override
@@ -317,9 +363,8 @@ public class MainActivity extends CastEnabledActivity {
RatingDialog.init(this);
if (lastTheme != UserPreferences.getNoTitleTheme()) {
- // Nav drawer is empty for half a second after recreating. Don't confuse users with that.
- drawerLayout.closeDrawer(navDrawer);
- recreate();
+ finish();
+ startActivity(new Intent(this, MainActivity.class));
}
}
@@ -352,7 +397,7 @@ public class MainActivity extends CastEnabledActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if (drawerToggle.onOptionsItemSelected(item)) {
+ if (drawerToggle != null && drawerToggle.onOptionsItemSelected(item)) { // Tablet layout does not have a drawer
return true;
} else if (item.getItemId() == android.R.id.home) {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
@@ -375,7 +420,9 @@ public class MainActivity extends CastEnabledActivity {
} else {
switch (UserPreferences.getBackButtonBehavior()) {
case OPEN_DRAWER:
- drawerLayout.openDrawer(navDrawer);
+ if (drawerLayout != null) { // Tablet layout does not have drawer
+ drawerLayout.openDrawer(navDrawer);
+ }
break;
case SHOW_PROMPT:
new AlertDialog.Builder(this)
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 34c7e3aba..b03d1e5cd 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -18,16 +18,23 @@ import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
+
+import com.bumptech.glide.Glide;
+
+import org.apache.commons.lang3.StringUtils;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.text.NumberFormat;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
-import androidx.arch.core.util.Function;
+import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
-import androidx.core.util.Consumer;
-import androidx.core.util.Supplier;
-import com.bumptech.glide.Glide;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -39,7 +46,6 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
-import de.danoeh.antennapod.core.util.Flavors;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
@@ -51,18 +57,13 @@ import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
import de.danoeh.antennapod.dialog.PlaybackControlsDialog;
+import de.danoeh.antennapod.dialog.ShareDialog;
import de.danoeh.antennapod.dialog.SkipPreferenceDialog;
import de.danoeh.antennapod.dialog.SleepTimerDialog;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import org.apache.commons.lang3.StringUtils;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
-import java.text.NumberFormat;
/**
@@ -304,7 +305,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
return false;
}
Playable media = controller.getMedia();
- boolean isFeedMedia = media != null && (media instanceof FeedMedia);
+ boolean isFeedMedia = (media instanceof FeedMedia);
menu.findItem(R.id.open_feed_item).setVisible(isFeedMedia); // FeedMedia implies it belongs to a Feed
@@ -313,13 +314,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
boolean isItemAndHasLink = isFeedMedia &&
ShareUtils.hasLinkToShare(((FeedMedia) media).getItem());
- menu.findItem(R.id.share_link_item).setVisible(isItemAndHasLink);
- menu.findItem(R.id.share_link_with_position_item).setVisible(isItemAndHasLink);
boolean isItemHasDownloadLink = isFeedMedia && ((FeedMedia) media).getDownload_url() != null;
- menu.findItem(R.id.share_download_url_item).setVisible(isItemHasDownloadLink);
- menu.findItem(R.id.share_download_url_with_position_item).setVisible(isItemHasDownloadLink);
- menu.findItem(R.id.share_file).setVisible(isFeedMedia && ((FeedMedia) media).fileExists());
menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink);
@@ -380,8 +376,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
new SleepTimerDialog().show(getSupportFragmentManager(), "SleepTimerDialog");
break;
case R.id.audio_controls:
- boolean isPlayingVideo = controller.getMedia().getMediaType() == MediaType.VIDEO;
- PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance(isPlayingVideo);
+ PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance();
dialog.show(getSupportFragmentManager(), "playback_controls");
break;
case R.id.open_feed_item:
@@ -393,29 +388,10 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
case R.id.visit_website_item:
IntentUtils.openInBrowser(MediaplayerActivity.this, getWebsiteLinkWithFallback(media));
break;
- case R.id.share_link_item:
- if (feedItem != null) {
- ShareUtils.shareFeedItemLink(this, feedItem);
- }
- break;
- case R.id.share_download_url_item:
- if (feedItem != null) {
- ShareUtils.shareFeedItemDownloadLink(this, feedItem);
- }
- break;
- case R.id.share_link_with_position_item:
+ case R.id.share_item:
if (feedItem != null) {
- ShareUtils.shareFeedItemLink(this, feedItem, true);
- }
- break;
- case R.id.share_download_url_with_position_item:
- if (feedItem != null) {
- ShareUtils.shareFeedItemDownloadLink(this, feedItem, true);
- }
- break;
- case R.id.share_file:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemFile(this, ((FeedMedia) media));
+ ShareDialog shareDialog = ShareDialog.newInstance(feedItem);
+ shareDialog.show(getSupportFragmentManager(), "ShareEpisodeDialog");
}
break;
default:
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 0f7bab273..f6623d5dc 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -227,15 +227,14 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- Intent destIntent = new Intent(this, MainActivity.class);
- if (NavUtils.shouldUpRecreateTask(this, destIntent)) {
- startActivity(destIntent);
- } else {
- NavUtils.navigateUpFromSameTask(this);
- }
- return true;
+ if (item.getItemId() == android.R.id.home) {
+ Intent destIntent = new Intent(this, MainActivity.class);
+ if (NavUtils.shouldUpRecreateTask(this, destIntent)) {
+ startActivity(destIntent);
+ } else {
+ NavUtils.navigateUpFromSameTask(this);
+ }
+ return true;
}
return super.onOptionsItemSelected(item);
}
@@ -266,16 +265,15 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
true, null, true);
download = Observable.fromCallable(() -> {
- feeds = DBReader.getFeedList();
- ClientConfig.installSslProvider(this);
- downloader = new HttpDownloader(request);
- downloader.call();
- return downloader.getResult();
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(this::checkDownloadResult,
- error -> Log.e(TAG, Log.getStackTraceString(error)));
+ feeds = DBReader.getFeedList();
+ downloader = new HttpDownloader(request);
+ downloader.call();
+ return downloader.getResult();
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::checkDownloadResult,
+ error -> Log.e(TAG, Log.getStackTraceString(error)));
}
private void checkDownloadResult(@NonNull DownloadStatus status) {
@@ -562,13 +560,11 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.error_label);
if (errorMsg != null) {
- builder.setMessage(getString(R.string.error_msg_prefix) + errorMsg);
+ builder.setMessage(errorMsg);
} else {
- builder.setMessage(R.string.error_msg_prefix);
+ builder.setMessage(R.string.download_error_error_unknown);
}
- builder.setPositiveButton(android.R.string.ok,
- (dialog, which) -> dialog.cancel()
- );
+ builder.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.cancel());
builder.setOnDismissListener(dialog -> {
setResult(RESULT_ERROR);
finish();
@@ -609,9 +605,8 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
final List<String> titles = new ArrayList<>();
- final List<String> urls = new ArrayList<>();
- urls.addAll(urlsMap.keySet());
+ final List<String> urls = new ArrayList<>(urlsMap.keySet());
for (String url : urls) {
titles.add(urlsMap.get(url));
}
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 d1cd50608..4947f478a 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
@@ -1,38 +1,25 @@
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 androidx.core.app.ActivityCompat;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Button;
-
-import java.io.File;
-
+import androidx.appcompat.app.AppCompatActivity;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
-/** Is show if there is now external storage available. */
+/**
+ * Is show if there is now external storage available.
+ */
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());
@@ -41,51 +28,11 @@ public class StorageErrorActivity extends AppCompatActivity {
setContentView(R.layout.storage_error);
Button btnChooseDataFolder = findViewById(R.id.btnChooseDataFolder);
- btnChooseDataFolder.setOnClickListener(v -> {
- if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
- Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
- 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 AlertDialog.Builder(this)
- .setMessage(R.string.choose_data_directory_permission_rationale)
- .setPositiveButton(android.R.string.ok, (dialog, which) -> requestPermission())
- .setNegativeButton(android.R.string.cancel, (dialog, which) -> finish())
- .show();
- }
+ btnChooseDataFolder.setOnClickListener(v ->
+ ChooseDataFolderDialog.showDialog(this, path -> {
+ UserPreferences.setDataFolder(path);
+ leaveErrorState();
+ }));
}
@Override
@@ -108,55 +55,6 @@ public class StorageErrorActivity extends AppCompatActivity {
}
}
- // see PreferenceController.showChooseDataFolderDialog()
- private void showChooseDataFolderDialog() {
- ChooseDataFolderDialog.showDialog(
- this, new ChooseDataFolderDialog.RunnableWithString() {
- @Override
- public void run(final String folder) {
- UserPreferences.setDataFolder(folder);
- leaveErrorState();
- }
- });
- }
-
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, 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);
- }
- if (path == null) {
- return;
- }
- 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();
- }
- }
- }
-
private void leaveErrorState() {
finish();
startActivity(new Intent(this, MainActivity.class));
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
index 337880317..cfd6ec702 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
@@ -88,10 +88,9 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ return true;
}
return super.onOptionsItemSelected(item);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
index 64560df56..bcad1b5a4 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.adapter;
-import android.app.Dialog;
import android.content.Context;
import android.text.format.Formatter;
import android.view.LayoutInflater;
@@ -9,29 +8,25 @@ import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.TextView;
-
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
+import androidx.core.util.Consumer;
import androidx.recyclerview.widget.RecyclerView;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.StorageUtils;
-import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.ViewHolder> {
- private final ChooseDataFolderDialog.RunnableWithString selectionHandler;
+ private final Consumer<String> selectionHandler;
private final String currentPath;
private final List<StoragePath> entries;
private final String freeSpaceString;
- private Dialog dialog;
- public DataFolderAdapter(Context context, ChooseDataFolderDialog.RunnableWithString selectionHandler) {
+ public DataFolderAdapter(Context context, @NonNull Consumer<String> selectionHandler) {
this.entries = getStorageEntries(context);
this.currentPath = getCurrentPath();
this.selectionHandler = selectionHandler;
@@ -56,8 +51,10 @@ public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.Vi
holder.path.setText(storagePath.getShortPath());
holder.size.setText(String.format(freeSpaceString, freeSpace, totalSpace));
holder.progressBar.setProgress(storagePath.getUsagePercentage());
- holder.root.setOnClickListener((View v) -> selectAndDismiss(storagePath));
- holder.radioButton.setOnClickListener((View v) -> selectAndDismiss(storagePath));
+ View.OnClickListener selectListener = v -> selectionHandler.accept(storagePath.getFullPath());
+ holder.root.setOnClickListener(selectListener);
+ holder.radioButton.setOnClickListener(selectListener);
+
if (storagePath.getFullPath().equals(currentPath)) {
holder.radioButton.toggle();
}
@@ -65,20 +62,14 @@ public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.Vi
@Override
public int getItemCount() {
- if (currentPath == null) {
- return 0;
- } else {
- return entries.size();
- }
- }
-
- public void setDialog(Dialog dialog) {
- this.dialog = dialog;
+ return entries.size();
}
private String getCurrentPath() {
File dataFolder = UserPreferences.getDataFolder(null);
- if (dataFolder != null) return dataFolder.getAbsolutePath();
+ if (dataFolder != null) {
+ return dataFolder.getAbsolutePath();
+ }
return null;
}
@@ -86,28 +77,27 @@ public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.Vi
File[] mediaDirs = ContextCompat.getExternalFilesDirs(context, null);
final List<StoragePath> entries = new ArrayList<>(mediaDirs.length);
for (File dir : mediaDirs) {
- if (isNotWritable(dir)) continue;
-
+ if (!isWritable(dir)) {
+ continue;
+ }
entries.add(new StoragePath(dir.getAbsolutePath()));
}
+ if (entries.isEmpty() && isWritable(context.getFilesDir())) {
+ entries.add(new StoragePath(context.getFilesDir().getAbsolutePath()));
+ }
return entries;
}
- private boolean isNotWritable(File dir) {
- return dir == null || !dir.exists() || !dir.canRead() || !dir.canWrite();
- }
-
- private void selectAndDismiss(StoragePath storagePath) {
- selectionHandler.run(storagePath.getFullPath());
- dialog.dismiss();
+ private boolean isWritable(File dir) {
+ return dir != null && dir.exists() && dir.canRead() && dir.canWrite();
}
static class ViewHolder extends RecyclerView.ViewHolder {
- private View root;
- private TextView path;
- private TextView size;
- private RadioButton radioButton;
- private ProgressBar progressBar;
+ private final View root;
+ private final TextView path;
+ private final TextView size;
+ private final RadioButton radioButton;
+ private final ProgressBar progressBar;
ViewHolder(View itemView) {
super(itemView);
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java
index d391f1c54..8efc89c9a 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java
@@ -44,7 +44,7 @@ public class EpisodeItemListAdapter extends RecyclerView.Adapter<EpisodeItemView
@Override
public final int getItemViewType(int position) {
- return R.id.episode_item_view_holder;
+ return R.id.view_type_episode_item;
}
@NonNull
@@ -86,6 +86,19 @@ public class EpisodeItemListAdapter extends RecyclerView.Adapter<EpisodeItemView
protected void afterBindViewHolder(EpisodeItemViewHolder holder, int pos) {
}
+ @Override
+ public void onViewRecycled(@NonNull EpisodeItemViewHolder holder) {
+ super.onViewRecycled(holder);
+ // Set all listeners to null. This is required to prevent leaking fragments that have set a listener.
+ // Activity -> recycledViewPool -> EpisodeItemViewHolder -> Listener -> Fragment (can not be garbage collected)
+ holder.itemView.setOnClickListener(null);
+ holder.secondaryActionButton.setOnClickListener(null);
+ holder.dragHandle.setOnTouchListener(null);
+ holder.coverHolder.setOnTouchListener(null);
+ holder.container.setOnCreateContextMenuListener(null);
+ holder.container.setOnLongClickListener(null);
+ }
+
/**
* {@link #notifyItemChanged(int)} is final, so we can not override.
* Calling {@link #notifyItemChanged(int)} may bind the item to a new ViewHolder and execute a transition.
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 690bb9e3d..6bfd34d5c 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
@@ -7,6 +7,10 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
@@ -32,8 +36,9 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> {
super(context, resource, objects);
}
+ @NonNull
@Override
- public View getView(int position, View convertView, ViewGroup parent) {
+ public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Holder holder;
FeedItem item = getItem(position);
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 e66032e11..eea977c2e 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -61,7 +61,7 @@ public class NavListAdapter extends BaseAdapter
private final ItemAccess itemAccess;
private final WeakReference<Activity> activity;
- private boolean showSubscriptionList = true;
+ public boolean showSubscriptionList = true;
public NavListAdapter(ItemAccess itemAccess, Activity context) {
this.itemAccess = itemAccess;
@@ -194,7 +194,7 @@ public class NavListAdapter extends BaseAdapter
@Override
public View getView(int position, View convertView, ViewGroup parent) {
int viewType = getItemViewType(position);
- View v = null;
+ View v;
if (viewType == VIEW_TYPE_NAV) {
v = getNavView((String) getItem(position), position, convertView, parent);
} else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
@@ -296,9 +296,17 @@ public class NavListAdapter extends BaseAdapter
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.nav_section_item, parent, false);
+ TextView feedsFilteredMsg = convertView.findViewById(R.id.nav_feeds_filtered_message);
- convertView.setEnabled(false);
- convertView.setOnClickListener(null);
+ if (UserPreferences.getFeedFilter() != UserPreferences.FEED_FILTER_NONE && showSubscriptionList) {
+ convertView.setEnabled(true);
+ feedsFilteredMsg.setText("{md-info-outline} " + context.getString(R.string.subscriptions_are_filtered));
+ Iconify.addIcons(feedsFilteredMsg);
+ feedsFilteredMsg.setVisibility(View.VISIBLE);
+ } else {
+ convertView.setEnabled(false);
+ feedsFilteredMsg.setVisibility(View.GONE);
+ }
return convertView;
}
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 428a968c6..7ce086694 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
@@ -20,16 +20,17 @@ public class QueueRecyclerAdapter extends EpisodeItemListAdapter {
private static final String TAG = "QueueRecyclerAdapter";
private final ItemTouchHelper itemTouchHelper;
- private boolean locked;
+ private boolean dragDropEnabled;
+
public QueueRecyclerAdapter(MainActivity mainActivity, ItemTouchHelper itemTouchHelper) {
super(mainActivity);
this.itemTouchHelper = itemTouchHelper;
- locked = UserPreferences.isQueueLocked();
+ dragDropEnabled = ! (UserPreferences.isQueueKeepSorted() || UserPreferences.isQueueLocked());
}
- public void setLocked(boolean locked) {
- this.locked = locked;
+ public void updateDragDropEnabled() {
+ dragDropEnabled = ! (UserPreferences.isQueueKeepSorted() || UserPreferences.isQueueLocked());
notifyDataSetChanged();
}
@@ -37,14 +38,14 @@ public class QueueRecyclerAdapter extends EpisodeItemListAdapter {
@SuppressLint("ClickableViewAccessibility")
protected void afterBindViewHolder(EpisodeItemViewHolder holder, int pos) {
View.OnTouchListener startDragTouchListener = (v1, event) -> {
- if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "startDrag()");
itemTouchHelper.startDrag(holder);
}
return false;
};
- if (locked) {
+ if (!dragDropEnabled) {
holder.dragHandle.setVisibility(View.GONE);
holder.dragHandle.setOnTouchListener(null);
holder.coverHolder.setOnTouchListener(null);
diff --git a/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java
index b810b390a..71442f50b 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java
@@ -5,11 +5,10 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.DownloadAuthenticationActivity;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.core.DownloadServiceCallbacks;
-import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.service.download.DownloadRequest;
import de.danoeh.antennapod.fragment.DownloadsFragment;
import de.danoeh.antennapod.fragment.QueueFragment;
@@ -24,7 +23,8 @@ public class DownloadServiceCallbacksImpl implements DownloadServiceCallbacks {
Bundle args = new Bundle();
args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_RUNNING);
intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
- return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getActivity(context,
+ R.id.pending_intent_download_service_notification, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
@Override
@@ -32,7 +32,8 @@ public class DownloadServiceCallbacksImpl implements DownloadServiceCallbacks {
final Intent activityIntent = new Intent(context.getApplicationContext(), DownloadAuthenticationActivity.class);
activityIntent.putExtra(DownloadAuthenticationActivity.ARG_DOWNLOAD_REQUEST, request);
activityIntent.putExtra(DownloadAuthenticationActivity.ARG_SEND_TO_DOWNLOAD_REQUESTER_BOOL, true);
- return PendingIntent.getActivity(context.getApplicationContext(), 0, activityIntent, PendingIntent.FLAG_ONE_SHOT);
+ return PendingIntent.getActivity(context.getApplicationContext(),
+ R.id.pending_intent_download_service_auth, activityIntent, PendingIntent.FLAG_ONE_SHOT);
}
@Override
@@ -42,14 +43,16 @@ public class DownloadServiceCallbacksImpl implements DownloadServiceCallbacks {
Bundle args = new Bundle();
args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_LOG);
intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
- return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getActivity(context, R.id.pending_intent_download_service_report,
+ intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
@Override
public PendingIntent getAutoDownloadReportNotificationContentIntent(Context context) {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(MainActivity.EXTRA_FRAGMENT_TAG, QueueFragment.TAG);
- return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getActivity(context, R.id.pending_intent_download_service_autodownload_report,
+ intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
index ec285a8f6..2c375f5cd 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
@@ -4,6 +4,7 @@ import android.content.Context;
import android.view.View;
import androidx.appcompat.app.AlertDialog;
+import androidx.core.util.Consumer;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import de.danoeh.antennapod.R;
@@ -11,29 +12,7 @@ import de.danoeh.antennapod.adapter.DataFolderAdapter;
public class ChooseDataFolderDialog {
- public abstract static class RunnableWithString implements Runnable {
- public RunnableWithString() {
- super();
- }
- public abstract void run(final String arg);
- @Override public void run() {
- throw new IllegalArgumentException("Expect one String parameter.");
- }
- }
-
- private ChooseDataFolderDialog() {}
-
- public static void showDialog(final Context context, RunnableWithString handlerFunc) {
- DataFolderAdapter adapter = new DataFolderAdapter(context, handlerFunc);
-
- if (adapter.getItemCount() == 0) {
- new AlertDialog.Builder(context)
- .setTitle(R.string.error_label)
- .setMessage(R.string.external_storage_error_msg)
- .setPositiveButton(android.R.string.ok, null)
- .show();
- return;
- }
+ public static void showDialog(final Context context, Consumer<String> handlerFunc) {
View content = View.inflate(context, R.layout.choose_data_folder_dialog, null);
AlertDialog dialog = new AlertDialog.Builder(context)
@@ -43,9 +22,22 @@ public class ChooseDataFolderDialog {
.setNegativeButton(R.string.cancel_label, null)
.create();
((RecyclerView) content.findViewById(R.id.recyclerView)).setLayoutManager(new LinearLayoutManager(context));
+
+ DataFolderAdapter adapter = new DataFolderAdapter(context, path -> {
+ dialog.dismiss();
+ handlerFunc.accept(path);
+ });
((RecyclerView) content.findViewById(R.id.recyclerView)).setAdapter(adapter);
- adapter.setDialog(dialog);
- dialog.show();
+
+ if (adapter.getItemCount() > 0) {
+ dialog.show();
+ } else {
+ new AlertDialog.Builder(context)
+ .setTitle(R.string.error_label)
+ .setMessage(R.string.external_storage_error_msg)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
}
} \ No newline at end of file
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 8ae3f6079..f2524c40c 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -216,7 +216,7 @@ public class EpisodesApplyActionFragment extends Fragment {
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.episodes_apply_action_options, menu);
@@ -232,7 +232,7 @@ public class EpisodesApplyActionFragment extends Fragment {
}
@Override
- public void onPrepareOptionsMenu(Menu menu) {
+ public void onPrepareOptionsMenu(@NonNull Menu menu) {
// Prepare icon for select toggle button
int[] icon = new int[1];
@@ -409,7 +409,7 @@ public class EpisodesApplyActionFragment extends Fragment {
boolean checked = checkedIds.contains(episode.getId());
mListView.setItemChecked(i, checked);
}
- ActivityCompat.invalidateOptionsMenu(EpisodesApplyActionFragment.this.getActivity());
+ getActivity().invalidateOptionsMenu();
toolbar.setTitle(getResources().getQuantityString(R.plurals.num_selected_label,
checkedIds.size(), checkedIds.size()));
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/FeedFilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FeedFilterDialog.java
new file mode 100644
index 000000000..7d1fe4026
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/FeedFilterDialog.java
@@ -0,0 +1,40 @@
+package de.danoeh.antennapod.dialog;
+
+import android.content.Context;
+
+import androidx.appcompat.app.AlertDialog;
+
+import org.greenrobot.eventbus.EventBus;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+
+public class FeedFilterDialog {
+ public static void showDialog(Context context) {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ dialog.setTitle(context.getString(R.string.pref_filter_feed_title));
+ dialog.setNegativeButton(android.R.string.cancel, (d, listener) -> d.dismiss());
+
+ int selectedIndexTemp = 0;
+ int selected = UserPreferences.getFeedFilter();
+ String[] entryValues = context.getResources().getStringArray(R.array.nav_drawer_feed_filter_values);
+ for (int i = 0; i < entryValues.length; i++) {
+ if (Integer.parseInt(entryValues[i]) == selected) {
+ selectedIndexTemp = i;
+ }
+ }
+
+ final int selectedIndex = selectedIndexTemp;
+ String[] items = context.getResources().getStringArray(R.array.nav_drawer_feed_filter_options);
+ dialog.setSingleChoiceItems(items, selectedIndex, (d, which) -> {
+ if (selectedIndex != which) {
+ UserPreferences.setFeedFilter(entryValues[which]);
+ //Update subscriptions
+ EventBus.getDefault().post(new UnreadItemsUpdateEvent());
+ }
+ d.dismiss();
+ });
+ dialog.show();
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java
index d2912f90f..82010637f 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java
@@ -1,8 +1,12 @@
package de.danoeh.antennapod.dialog;
import android.content.Context;
-import androidx.appcompat.app.AlertDialog;
import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+
+import androidx.appcompat.app.AlertDialog;
import java.util.Arrays;
import java.util.HashSet;
@@ -10,6 +14,8 @@ import java.util.Set;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItemFilter;
+import de.danoeh.antennapod.core.feed.FeedItemFilterGroup;
+import de.danoeh.antennapod.view.RecursiveRadioGroup;
public abstract class FilterDialog {
@@ -22,36 +28,46 @@ public abstract class FilterDialog {
}
public void openDialog() {
- 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 Set<String> filterValues = new HashSet<>(Arrays.asList(filter.getValues()));
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.filter);
- // make sure we have no empty strings in the filter list
- for (String filterValue : filterValues) {
- if (TextUtils.isEmpty(filterValue)) {
- filterValues.remove(filterValue);
- }
+ LayoutInflater inflater = LayoutInflater.from(this.context);
+ LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.filter_dialog, null, false);
+ builder.setView(layout);
+
+ for (FeedItemFilterGroup item : FeedItemFilterGroup.values()) {
+ RecursiveRadioGroup row = (RecursiveRadioGroup) inflater.inflate(R.layout.filter_dialog_row, null);
+ RadioButton filter1 = row.findViewById(R.id.filter_dialog_radioButton1);
+ RadioButton filter2 = row.findViewById(R.id.filter_dialog_radioButton2);
+ filter1.setText(item.values[0].displayName);
+ filter1.setTag(item.values[0].filterId);
+ filter2.setText(item.values[1].displayName);
+ filter2.setTag(item.values[1].filterId);
+ layout.addView(row);
}
- for (int i = 0; i < values.length; i++) {
- String value = values[i];
- if (filterValues.contains(value)) {
- checkedItems[i] = true;
+ for (String filterId : filterValues) {
+ if (!TextUtils.isEmpty(filterId)) {
+ ((RadioButton) layout.findViewWithTag(filterId)).setChecked(true);
}
}
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.filter);
- builder.setMultiChoiceItems(items, checkedItems, (dialog, which, isChecked) -> {
- if (isChecked) {
- filterValues.add(values[which]);
- } else {
- filterValues.remove(values[which]);
- }
- });
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
+ filterValues.clear();
+ for (int i = 0; i < layout.getChildCount(); i++) {
+ if (!(layout.getChildAt(i) instanceof RecursiveRadioGroup)) {
+ continue;
+ }
+ RecursiveRadioGroup group = (RecursiveRadioGroup) layout.getChildAt(i);
+ if (group.getCheckedButton() != null) {
+ String tag = (String) group.getCheckedButton().getTag();
+ if (tag != null) { // Clear buttons use no tag
+ filterValues.add((String) group.getCheckedButton().getTag());
+ }
+ }
+ }
updateFilter(filterValues);
});
builder.setNegativeButton(R.string.cancel_label, null);
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
index d1ffdc148..e45533826 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
@@ -11,27 +11,21 @@ import android.widget.Button;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.TextView;
-import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.Converter;
-import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.view.PlaybackSpeedSeekBar;
import java.util.List;
import java.util.Locale;
public class PlaybackControlsDialog extends DialogFragment {
- private static final String ARGUMENT_IS_PLAYING_VIDEO = "isPlayingVideo";
-
private PlaybackController controller;
private AlertDialog dialog;
- private boolean isPlayingVideo;
- public static PlaybackControlsDialog newInstance(boolean isPlayingVideo) {
+ public static PlaybackControlsDialog newInstance() {
Bundle arguments = new Bundle();
- arguments.putBoolean(ARGUMENT_IS_PLAYING_VIDEO, isPlayingVideo);
PlaybackControlsDialog dialog = new PlaybackControlsDialog();
dialog.setArguments(arguments);
return dialog;
@@ -65,8 +59,6 @@ public class PlaybackControlsDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- isPlayingVideo = getArguments() != null && getArguments().getBoolean(ARGUMENT_IS_PLAYING_VIDEO);
-
dialog = new AlertDialog.Builder(getContext())
.setTitle(R.string.audio_controls)
.setView(R.layout.audio_controls)
@@ -79,68 +71,18 @@ public class PlaybackControlsDialog extends DialogFragment {
}
private void setupUi() {
- final SeekBar barPlaybackSpeed = dialog.findViewById(R.id.playback_speed);
- final TextView butDecSpeed = dialog.findViewById(R.id.butDecSpeed);
- butDecSpeed.setOnClickListener(v -> {
- if (controller != null && controller.canSetPlaybackSpeed()) {
- barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 2);
- } else {
- VariableSpeedDialog.showGetPluginDialog(getContext());
- }
- });
- final TextView butIncSpeed = dialog.findViewById(R.id.butIncSpeed);
- butIncSpeed.setOnClickListener(v -> {
- if (controller != null && controller.canSetPlaybackSpeed()) {
- barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 2);
- } else {
- VariableSpeedDialog.showGetPluginDialog(getContext());
- }
- });
-
final TextView txtvPlaybackSpeed = dialog.findViewById(R.id.txtvPlaybackSpeed);
- float currentSpeed = getCurrentSpeed();
- txtvPlaybackSpeed.setText(String.format(Locale.getDefault(), "%.2fx", currentSpeed));
- barPlaybackSpeed.setOnSeekBarChangeListener(new SeekBar.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);
-
- PlaybackPreferences.setCurrentlyPlayingTemporaryPlaybackSpeed(playbackSpeed);
- if (isPlayingVideo) {
- UserPreferences.setVideoPlaybackSpeed(playbackSpeed);
- } else {
- UserPreferences.setPlaybackSpeed(playbackSpeed);
- }
-
- String speedStr = String.format(Locale.getDefault(), "%.2fx", playbackSpeed);
- txtvPlaybackSpeed.setText(speedStr);
- } else if (fromUser) {
- float speed = getCurrentSpeed();
- barPlaybackSpeed.post(() -> barPlaybackSpeed.setProgress(Math.round((20 * speed) - 10)));
- }
- }
+ PlaybackSpeedSeekBar speedSeekBar = dialog.findViewById(R.id.speed_seek_bar);
+ speedSeekBar.setController(controller);
+ speedSeekBar.setProgressChangedListener(speed
+ -> txtvPlaybackSpeed.setText(String.format(Locale.getDefault(), "%.2fx", speed)));
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- if (controller != null && !controller.canSetPlaybackSpeed()) {
- VariableSpeedDialog.showGetPluginDialog(getContext());
- }
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- barPlaybackSpeed.setProgress(Math.round((20 * currentSpeed) - 10));
-
- final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
+ final SeekBar barLeftVolume = dialog.findViewById(R.id.volume_left);
barLeftVolume.setProgress(UserPreferences.getLeftVolumePercentage());
- final SeekBar barRightVolume = (SeekBar) dialog.findViewById(R.id.volume_right);
+ final SeekBar barRightVolume = dialog.findViewById(R.id.volume_right);
barRightVolume.setProgress(UserPreferences.getRightVolumePercentage());
- final CheckBox stereoToMono = (CheckBox) dialog.findViewById(R.id.stereo_to_mono);
+ final CheckBox stereoToMono = dialog.findViewById(R.id.stereo_to_mono);
stereoToMono.setChecked(UserPreferences.stereoToMono());
if (controller != null && !controller.canDownmix()) {
stereoToMono.setEnabled(false);
@@ -220,13 +162,4 @@ public class PlaybackControlsDialog extends DialogFragment {
new Handler().postDelayed(this::setupAudioTracks, 500);
});
}
-
- private float getCurrentSpeed() {
- Playable media = null;
- if (controller != null) {
- media = controller.getMedia();
- }
-
- return PlaybackSpeedUtils.getCurrentPlaybackSpeed(media);
- }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
index 0c25e3e9f..d0fb91692 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
@@ -23,6 +23,7 @@ import java.net.Proxy;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.R;
@@ -63,6 +64,8 @@ public class ProxyDialog {
public Dialog show() {
View content = View.inflate(context, R.layout.proxy_settings, null);
+ spType = content.findViewById(R.id.spType);
+
dialog = new AlertDialog.Builder(context)
.setTitle(R.string.pref_proxy_title)
.setView(content)
@@ -76,7 +79,7 @@ public class ProxyDialog {
test();
return;
}
- String type = (String) ((Spinner) content.findViewById(R.id.spType)).getSelectedItem();
+ String type = (String) spType.getSelectedItem();
ProxyConfig proxy;
if (Proxy.Type.valueOf(type) == Proxy.Type.DIRECT) {
proxy = ProxyConfig.direct();
@@ -106,7 +109,6 @@ public class ProxyDialog {
dialog.dismiss();
});
- spType = content.findViewById(R.id.spType);
List<String> types = new ArrayList<>();
types.add(Proxy.Type.DIRECT.name());
types.add(Proxy.Type.HTTP.name());
@@ -227,12 +229,11 @@ public class ProxyDialog {
if(required) {
testSuccessful = false;
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.proxy_test_label);
- dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
} else {
testSuccessful = true;
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(android.R.string.ok);
- dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
}
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
}
private void test() {
@@ -261,7 +262,7 @@ public class ProxyDialog {
portValue = Integer.parseInt(port);
}
SocketAddress address = InetSocketAddress.createUnresolved(host, portValue);
- Proxy.Type proxyType = Proxy.Type.valueOf(type.toUpperCase());
+ Proxy.Type proxyType = Proxy.Type.valueOf(type.toUpperCase(Locale.US));
Proxy proxy = new Proxy(proxyType, address);
OkHttpClient.Builder builder = AntennapodHttpClient.newBuilder()
.connectTimeout(10, TimeUnit.SECONDS)
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ShareDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ShareDialog.java
new file mode 100644
index 000000000..8104d3539
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ShareDialog.java
@@ -0,0 +1,112 @@
+package de.danoeh.antennapod.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.util.ShareUtils;
+
+public class ShareDialog extends DialogFragment {
+
+ private static final String ARGUMENT_FEED_ITEM = "feedItem";
+
+ private static final String TAG = "ShareDialog";
+ private Context ctx;
+ private FeedItem item;
+
+ private static final String PREF_SHARE_DIALOG_OPTION = "prefShareDialogOption";
+ private static final String PREF_SHARE_EPISODE_START_AT = "prefShareEpisodeStartAt";
+
+ private RadioGroup radioGroup;
+ private RadioButton radioEpisodeWebsite;
+ private RadioButton radioMediaFile;
+ private CheckBox checkBoxStartAt;
+ private SharedPreferences prefs;
+
+ public ShareDialog() {
+ // Empty constructor required for DialogFragment
+ }
+
+ public static ShareDialog newInstance(FeedItem item) {
+ Bundle arguments = new Bundle();
+ arguments.putSerializable(ARGUMENT_FEED_ITEM, item);
+ ShareDialog dialog = new ShareDialog();
+ dialog.setArguments(arguments);
+ return dialog;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ if (getArguments() != null) {
+ ctx = getActivity();
+ item = (FeedItem) getArguments().getSerializable(ARGUMENT_FEED_ITEM);
+ prefs = getActivity().getSharedPreferences("ShareDialog", Context.MODE_PRIVATE);
+ }
+
+ View content = View.inflate(ctx, R.layout.share_episode_dialog, null);
+ AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
+ builder.setTitle(R.string.share_label);
+ builder.setView(content);
+
+ radioGroup = content.findViewById(R.id.share_dialog_radio_group);
+ radioEpisodeWebsite = content.findViewById(R.id.share_episode_website_radio);
+ radioMediaFile = content.findViewById(R.id.share_media_file_radio);
+ checkBoxStartAt = content.findViewById(R.id.share_start_at_timer_dialog);
+
+ setupOptions();
+
+ builder.setPositiveButton(R.string.share_label, (dialog, id) -> {
+ boolean includePlaybackPosition = checkBoxStartAt.isChecked();
+ if (radioEpisodeWebsite.isChecked()) {
+ ShareUtils.shareFeedItemLink(ctx, item, includePlaybackPosition);
+ prefs.edit().putString(PREF_SHARE_DIALOG_OPTION, "website").apply();
+ } else {
+ ShareUtils.shareFeedItemDownloadLink(ctx, item, includePlaybackPosition);
+ prefs.edit().putString(PREF_SHARE_DIALOG_OPTION, "media").apply();
+ }
+ prefs.edit().putBoolean(PREF_SHARE_EPISODE_START_AT, includePlaybackPosition).apply();
+ }).setNegativeButton(R.string.cancel_label, (dialog, id) -> dialog.dismiss());
+
+ return builder.create();
+ }
+
+ private void setupOptions() {
+ final boolean hasMedia = item.getMedia() != null;
+
+ if (!ShareUtils.hasLinkToShare(item)) {
+ radioEpisodeWebsite.setVisibility(View.GONE);
+ radioMediaFile.setChecked(true);
+ }
+
+ if (!hasMedia || item.getMedia().getDownload_url() == null) {
+ radioMediaFile.setVisibility(View.GONE);
+ radioEpisodeWebsite.setChecked(true);
+ }
+
+ if (radioEpisodeWebsite.getVisibility() == View.VISIBLE && radioMediaFile.getVisibility() == View.VISIBLE) {
+ String option = prefs.getString(PREF_SHARE_DIALOG_OPTION, "website");
+ if (option.equals("website")) {
+ radioEpisodeWebsite.setChecked(true);
+ radioMediaFile.setChecked(false);
+ } else {
+ radioEpisodeWebsite.setChecked(false);
+ radioMediaFile.setChecked(true);
+ }
+ }
+
+ boolean switchIsChecked = prefs.getBoolean(PREF_SHARE_EPISODE_START_AT, false);
+ checkBoxStartAt.setChecked(switchIsChecked);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/StreamingConfirmationDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/StreamingConfirmationDialog.java
index 81e86e217..46095604c 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/StreamingConfirmationDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/StreamingConfirmationDialog.java
@@ -1,8 +1,6 @@
package de.danoeh.antennapod.dialog;
import android.content.Context;
-import android.view.View;
-import android.widget.CheckBox;
import androidx.appcompat.app.AlertDialog;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -19,25 +17,24 @@ public class StreamingConfirmationDialog {
}
public void show() {
- View view = View.inflate(context, R.layout.checkbox_do_not_show_again, null);
- CheckBox checkDoNotShowAgain = view.findViewById(R.id.checkbox_do_not_show_again);
-
new AlertDialog.Builder(context)
.setTitle(R.string.stream_label)
.setMessage(R.string.confirm_mobile_streaming_notification_message)
- .setView(view)
- .setPositiveButton(R.string.stream_label, (dialog, which) -> {
- if (checkDoNotShowAgain.isChecked()) {
- UserPreferences.setAllowMobileStreaming(true);
- }
- new PlaybackServiceStarter(context, playable)
- .callEvenIfRunning(true)
- .startWhenPrepared(true)
- .shouldStream(true)
- .shouldStreamThisTime(true)
- .start();
+ .setPositiveButton(R.string.stream_label, (dialog, which) -> stream())
+ .setNegativeButton(R.string.confirm_mobile_streaming_button_always, (dialog, which) -> {
+ UserPreferences.setAllowMobileStreaming(true);
+ stream();
})
- .setNegativeButton(R.string.cancel_label, null)
+ .setNeutralButton(R.string.cancel_label, null)
.show();
}
+
+ private void stream() {
+ new PlaybackServiceStarter(context, playable)
+ .callEvenIfRunning(true)
+ .startWhenPrepared(true)
+ .shouldStream(true)
+ .shouldStreamThisTime(true)
+ .start();
+ }
}
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 3a6ba183f..ef8ed335d 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
@@ -1,97 +1,171 @@
package de.danoeh.antennapod.dialog;
+import android.app.Dialog;
import android.content.Context;
-import android.os.Build;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import com.google.android.material.chip.Chip;
+import com.google.android.material.snackbar.Snackbar;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.view.ItemOffsetDecoration;
+import de.danoeh.antennapod.view.PlaybackSpeedSeekBar;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Locale;
-public class VariableSpeedDialog {
+public class VariableSpeedDialog extends DialogFragment {
+ private SpeedSelectionAdapter adapter;
+ private final DecimalFormat speedFormat;
+ private PlaybackController controller;
+ private final List<Float> selectedSpeeds;
+ private PlaybackSpeedSeekBar speedSeekBar;
+ private Chip addCurrentSpeedChip;
- private VariableSpeedDialog() {
- }
-
- public static void showDialog(final Context context) {
- if (UserPreferences.useSonic()
- || UserPreferences.useExoplayer()
- || Build.VERSION.SDK_INT >= 23) {
- showSpeedSelectorDialog(context);
- } else {
- showGetPluginDialog(context, true);
- }
+ public VariableSpeedDialog() {
+ DecimalFormatSymbols format = new DecimalFormatSymbols(Locale.US);
+ format.setDecimalSeparator('.');
+ speedFormat = new DecimalFormat("0.00", format);
+ selectedSpeeds = new ArrayList<>(UserPreferences.getPlaybackSpeedArray());
}
public static void showGetPluginDialog(final Context context) {
- showGetPluginDialog(context, false);
- }
-
- private static void showGetPluginDialog(final Context context, boolean showSpeedSelector) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.no_playback_plugin_title);
builder.setMessage(R.string.no_playback_plugin_or_sonic_msg);
builder.setPositiveButton(R.string.enable_sonic, (dialog, which) -> {
UserPreferences.enableSonic();
- if (showSpeedSelector) {
- showSpeedSelectorDialog(context);
- }
});
builder.setNeutralButton(R.string.close_label, null);
builder.show();
}
- private static void showSpeedSelectorDialog(final Context context) {
- DecimalFormatSymbols format = new DecimalFormatSymbols(Locale.US);
- format.setDecimalSeparator('.');
- DecimalFormat speedFormat = new DecimalFormat("0.00", format);
-
- 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 = new ArrayList<>();
- float[] selectedSpeeds = UserPreferences.getPlaybackSpeedArray();
- for (float speed : selectedSpeeds) {
- selectedSpeedList.add(speedFormat.format(speed));
+ @Override
+ public void onStart() {
+ super.onStart();
+ controller = new PlaybackController(getActivity()) {
+ @Override
+ public void setupGUI() {
+ updateSpeed();
+ }
+
+ @Override
+ public void onPlaybackSpeedChange() {
+ updateSpeed();
+ }
+ };
+ controller.init();
+ speedSeekBar.setController(controller);
+ }
+
+ private void updateSpeed() {
+ speedSeekBar.updateSpeed();
+ addCurrentSpeedChip.setText(speedFormat.format(controller.getCurrentPlaybackSpeedMultiplier()));
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ controller.release();
+ controller = null;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setPositiveButton(R.string.close_label, null);
+
+ View root = View.inflate(getContext(), R.layout.speed_select_dialog, null);
+ speedSeekBar = root.findViewById(R.id.speed_seek_bar);
+ RecyclerView selectedSpeedsGrid = root.findViewById(R.id.selected_speeds_grid);
+ selectedSpeedsGrid.setLayoutManager(new GridLayoutManager(getContext(), 3));
+ selectedSpeedsGrid.addItemDecoration(new ItemOffsetDecoration(getContext(), 4));
+ adapter = new SpeedSelectionAdapter();
+ adapter.setHasStableIds(true);
+ selectedSpeedsGrid.setAdapter(adapter);
+
+ addCurrentSpeedChip = root.findViewById(R.id.add_current_speed_chip);
+ addCurrentSpeedChip.setCloseIconVisible(true);
+ addCurrentSpeedChip.setCloseIconResource(R.drawable.ic_add_black);
+ addCurrentSpeedChip.setOnCloseIconClickListener(v -> addCurrentSpeed());
+ addCurrentSpeedChip.setOnClickListener(v -> addCurrentSpeed());
+
+ builder.setView(root);
+ return builder.create();
+ }
+
+ private void addCurrentSpeed() {
+ float newSpeed = controller.getCurrentPlaybackSpeedMultiplier();
+ if (selectedSpeeds.contains(newSpeed)) {
+ Snackbar.make(addCurrentSpeedChip,
+ getString(R.string.preset_already_exists, newSpeed), Snackbar.LENGTH_LONG).show();
+ } else {
+ selectedSpeeds.add(newSpeed);
+ Collections.sort(selectedSpeeds);
+ UserPreferences.setPlaybackSpeedArray(selectedSpeeds);
+ adapter.notifyDataSetChanged();
}
+ }
- for (int i = 0; i < speedValues.length; i++) {
- speedChecked[i] = selectedSpeedList.contains(speedValues[i]);
+ public class SpeedSelectionAdapter extends RecyclerView.Adapter<SpeedSelectionAdapter.ViewHolder> {
+
+ @Override
+ @NonNull
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ Chip chip = new Chip(getContext());
+ chip.setCloseIconVisible(true);
+ chip.setCloseIconResource(R.drawable.ic_delete_black);
+ return new ViewHolder(chip);
}
- 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 (boolean checked : speedChecked) {
- if (checked) {
- choiceCount++;
- }
- }
- String[] newSpeedValues = new String[choiceCount];
- int newSpeedIndex = 0;
- for (int i = 0; i < speedChecked.length; i++) {
- if (speedChecked[i]) {
- newSpeedValues[newSpeedIndex++] = speedValues[i];
- }
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ float speed = selectedSpeeds.get(position);
+
+ holder.chip.setText(speedFormat.format(speed));
+ holder.chip.setOnCloseIconClickListener(v -> {
+ selectedSpeeds.remove(speed);
+ UserPreferences.setPlaybackSpeedArray(selectedSpeeds);
+ notifyDataSetChanged();
+ });
+ holder.chip.setOnClickListener(v -> {
+ if (controller != null) {
+ controller.setPlaybackSpeed(speed);
+ notifyDataSetChanged();
}
+ });
+ }
- UserPreferences.setPlaybackSpeedArray(newSpeedValues);
+ @Override
+ public int getItemCount() {
+ return selectedSpeeds.size();
+ }
- });
- builder.create().show();
- }
+ @Override
+ public long getItemId(int position) {
+ return selectedSpeeds.get(position).hashCode();
+ }
+
+ public class ViewHolder extends RecyclerView.ViewHolder {
+ Chip chip;
+ ViewHolder(Chip itemView) {
+ super(itemView);
+ chip = itemView;
+ }
+ }
+ }
}
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 cc261c708..290bf1845 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -12,11 +12,15 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.documentfile.provider.DocumentFile;
import androidx.fragment.app.Fragment;
import com.google.android.material.snackbar.Snackbar;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
@@ -44,7 +48,10 @@ public class AddFeedFragment extends Fragment {
private MainActivity activity;
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ @Nullable
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.addfeed, container, false);
activity = (MainActivity) getActivity();
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 05f38000c..4a1c12e0a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
@@ -45,20 +45,18 @@ public class AllEpisodesFragment extends EpisodesListFragment {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!super.onOptionsItemSelected(item)) {
- switch (item.getItemId()) {
- case R.id.filter_items:
- showFilterDialog();
- return true;
- default:
- return false;
+ if (item.getItemId() == R.id.filter_items) {
+ showFilterDialog();
+ return true;
}
+ return false;
} else {
return true;
}
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.findItem(R.id.filter_items).setVisible(true);
menu.findItem(R.id.mark_all_read_item).setVisible(true);
@@ -69,7 +67,7 @@ public class AllEpisodesFragment extends EpisodesListFragment {
super.onFragmentLoaded(episodes);
if (feedItemFilter.getValues().length > 0) {
- txtvInformation.setText("{fa-info-circle} " + this.getString(R.string.filtered_label));
+ txtvInformation.setText("{md-info-outline} " + this.getString(R.string.filtered_label));
Iconify.addIcons(txtvInformation);
txtvInformation.setVisibility(View.VISIBLE);
} else {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
index 5ca8b666a..7eb749681 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
@@ -13,7 +13,6 @@ import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
@@ -21,17 +20,8 @@ import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
-
import com.google.android.material.bottomsheet.BottomSheetBehavior;
-
import com.google.android.material.snackbar.Snackbar;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.CastEnabledActivity;
import de.danoeh.antennapod.activity.MainActivity;
@@ -40,7 +30,6 @@ import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
-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.util.Converter;
@@ -60,6 +49,13 @@ import io.reactivex.Maybe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.List;
/**
* Shows the audio player.
@@ -96,7 +92,9 @@ public class AudioPlayerFragment extends Fragment implements
private boolean showTimeLeft;
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.audioplayer_fragment, container, false);
toolbar = root.findViewById(R.id.toolbar);
@@ -206,30 +204,29 @@ public class AudioPlayerFragment extends Fragment implements
VariableSpeedDialog.showGetPluginDialog(getContext());
return;
}
- float[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
+ List<Float> availableSpeeds = UserPreferences.getPlaybackSpeedArray();
float currentSpeed = controller.getCurrentPlaybackSpeedMultiplier();
int newSpeedIndex = 0;
- while (newSpeedIndex < availableSpeeds.length && availableSpeeds[newSpeedIndex] < currentSpeed + EPSILON) {
+ while (newSpeedIndex < availableSpeeds.size()
+ && availableSpeeds.get(newSpeedIndex) < currentSpeed + EPSILON) {
newSpeedIndex++;
}
float newSpeed;
- if (availableSpeeds.length == 0) {
+ if (availableSpeeds.size() == 0) {
newSpeed = 1.0f;
- } else if (newSpeedIndex == availableSpeeds.length) {
- newSpeed = availableSpeeds[0];
+ } else if (newSpeedIndex == availableSpeeds.size()) {
+ newSpeed = availableSpeeds.get(0);
} else {
- newSpeed = availableSpeeds[newSpeedIndex];
+ newSpeed = availableSpeeds.get(newSpeedIndex);
}
- PlaybackPreferences.setCurrentlyPlayingTemporaryPlaybackSpeed(newSpeed);
- UserPreferences.setPlaybackSpeed(newSpeed);
controller.setPlaybackSpeed(newSpeed);
loadMediaInfo();
});
butPlaybackSpeed.setOnLongClickListener(v -> {
- VariableSpeedDialog.showDialog(getContext());
+ new VariableSpeedDialog().show(getChildFragmentManager(), null);
return true;
});
butPlaybackSpeed.setVisibility(View.VISIBLE);
@@ -491,11 +488,11 @@ public class AudioPlayerFragment extends Fragment implements
switch (item.getItemId()) {
case R.id.disable_sleeptimer_item: // Fall-through
case R.id.set_sleeptimer_item:
- new SleepTimerDialog().show(getFragmentManager(), "SleepTimerDialog");
+ new SleepTimerDialog().show(getChildFragmentManager(), "SleepTimerDialog");
return true;
case R.id.audio_controls:
- PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance(false);
- dialog.show(getFragmentManager(), "playback_controls");
+ PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance();
+ dialog.show(getChildFragmentManager(), "playback_controls");
return true;
case R.id.open_feed_item:
if (feedItem != null) {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
index e57869e6e..6f95d71da 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
@@ -45,7 +45,6 @@ public class ChaptersFragment extends Fragment {
RecyclerView recyclerView = root.findViewById(R.id.recyclerView);
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
- recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());
adapter = new ChaptersListAdapter(getActivity(), pos -> {
@@ -93,17 +92,12 @@ public class ChaptersFragment extends Fragment {
}
@Override
- public void onDestroyView() {
- super.onDestroyView();
+ public void onStop() {
+ super.onStop();
if (disposable != null) {
disposable.dispose();
}
- }
-
- @Override
- public void onStop() {
- super.onStop();
controller.release();
controller = null;
EventBus.getDefault().unregister(this);
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 6629d74e2..55a5d744e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -17,16 +17,21 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
import de.danoeh.antennapod.adapter.actionbutton.DeleteActionButton;
+import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloadLogEvent;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.event.PlayerStatusEvent;
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.FeedItemUtil;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.view.EmptyViewHandler;
import de.danoeh.antennapod.view.EpisodeItemListRecyclerView;
import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder;
@@ -58,6 +63,8 @@ public class CompletedDownloadsFragment extends Fragment {
private Disposable disposable;
private EmptyViewHandler emptyView;
+ private boolean isUpdatingFeeds = false;
+
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
@@ -104,10 +111,11 @@ public class CompletedDownloadsFragment extends Fragment {
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.downloads_completed, menu);
menu.findItem(R.id.episode_actions).setVisible(items.size() > 0);
+ isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
@Override
@@ -116,10 +124,24 @@ public class CompletedDownloadsFragment extends Fragment {
((MainActivity) requireActivity())
.loadChildFragment(EpisodesApplyActionFragment.newInstance(items, ACTION_DELETE | ACTION_ADD_TO_QUEUE));
return true;
+ } else if (item.getItemId() == R.id.refresh_item) {
+ AutoUpdateManager.runImmediate(requireContext());
+ return true;
}
return false;
}
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(DownloadEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
+ getActivity().invalidateOptionsMenu();
+ }
+ }
+
+ private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker =
+ () -> DownloadService.isRunning && DownloadRequester.getInstance().isDownloadingFeeds();
+
@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
FeedItem selectedItem = adapter.getSelectedItem();
@@ -181,12 +203,12 @@ public class CompletedDownloadsFragment extends Fragment {
loadItems();
}
- @Subscribe
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onDownloadLogChanged(DownloadLogEvent event) {
loadItems();
}
- @Subscribe
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
loadItems();
}
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 7593188b7..79f378249 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -1,16 +1,23 @@
package de.danoeh.antennapod.fragment;
+import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.TextView;
+
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
+
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.FitCenter;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
@@ -60,6 +67,11 @@ public class CoverFragment extends Fragment {
return root;
}
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ configureForOrientation(getResources().getConfiguration());
+ }
+
private void loadMediaInfo() {
if (disposable != null) {
disposable.dispose();
@@ -71,13 +83,12 @@ public class CoverFragment extends Fragment {
} else {
emitter.onComplete();
}
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(media -> {
- this.media = media;
- displayMediaInfo(media);
- }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }).subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(media -> {
+ this.media = media;
+ displayMediaInfo(media);
+ }, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
private void displayMediaInfo(@NonNull Playable media) {
@@ -117,6 +128,10 @@ public class CoverFragment extends Fragment {
@Override
public void onStop() {
super.onStop();
+
+ if (disposable != null) {
+ disposable.dispose();
+ }
controller.release();
controller = null;
EventBus.getDefault().unregister(this);
@@ -160,11 +175,35 @@ public class CoverFragment extends Fragment {
}
@Override
- public void onDestroyView() {
- super.onDestroyView();
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
- if (disposable != null) {
- disposable.dispose();
+ configureForOrientation(newConfig);
+ }
+
+ public float convertDpToPixel(float dp) {
+ Context context = this.getActivity().getApplicationContext();
+ return dp * ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
+ }
+
+ private void configureForOrientation(Configuration newConfig) {
+ LinearLayout mainContainer = getView().findViewById(R.id.cover_fragment);
+ ViewGroup.LayoutParams params = imgvCover.getLayoutParams();
+
+ if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
+ mainContainer.setOrientation(LinearLayout.VERTICAL);
+ if (newConfig.screenWidthDp > 0) {
+ params.width = (int) (convertDpToPixel(newConfig.screenWidthDp) * .80);
+ params.height = params.width;
+ imgvCover.setLayoutParams(params);
+ }
+ } else {
+ mainContainer.setOrientation(LinearLayout.HORIZONTAL);
+ if (newConfig.screenHeightDp > 0) {
+ params.height = (int) (convertDpToPixel(newConfig.screenHeightDp) * .40);
+ params.width = params.height;
+ imgvCover.setLayoutParams(params);
+ }
}
}
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 312e3cb62..055d88285 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -1,11 +1,16 @@
package de.danoeh.antennapod.fragment;
import android.app.Dialog;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.ListFragment;
-import androidx.core.view.MenuItemCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -17,14 +22,21 @@ import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
+import com.google.android.material.snackbar.Snackbar;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DownloadLogAdapter;
+import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloadLogEvent;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
@@ -32,6 +44,7 @@ import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
/**
* Shows the download log
@@ -44,6 +57,8 @@ public class DownloadLogFragment extends ListFragment {
private DownloadLogAdapter adapter;
private Disposable disposable;
+ private boolean isUpdatingFeeds = false;
+
@Override
public void onStart() {
super.onStart();
@@ -65,7 +80,7 @@ public class DownloadLogFragment extends ListFragment {
}
@Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// add padding
final ListView lv = getListView();
@@ -93,11 +108,11 @@ public class DownloadLogFragment extends ListFragment {
private void onFragmentLoaded() {
setListShown(true);
adapter.notifyDataSetChanged();
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
}
@Override
- public void onListItemClick(ListView l, View v, int position, long id) {
+ public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) {
super.onListItemClick(l, v, position, id);
DownloadStatus status = adapter.getItem(position);
@@ -119,10 +134,17 @@ public class DownloadLogFragment extends ListFragment {
message = status.getReasonDetailed();
}
+ String messageFull = getString(R.string.download_error_details_message, message, url);
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(R.string.download_error_details);
- builder.setMessage(getString(R.string.download_error_details_message, message, url));
+ builder.setMessage(messageFull);
builder.setPositiveButton(android.R.string.ok, null);
+ builder.setNeutralButton(R.string.copy_to_clipboard, (dialog, which) -> {
+ ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText(getString(R.string.download_error_details), messageFull);
+ clipboard.setPrimaryClip(clip);
+ ((MainActivity) getActivity()).showSnackbarAbovePlayer(R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT);
+ });
Dialog dialog = builder.show();
((TextView) dialog.findViewById(android.R.id.message)).setTextIsSelectable(true);
}
@@ -150,20 +172,14 @@ public class DownloadLogFragment extends ListFragment {
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if (!isAdded()) {
- return;
- }
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
- MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
- MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
- TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.ic_delete});
- clearHistory.setIcon(drawables.getDrawable(0));
- drawables.recycle();
+ inflater.inflate(R.menu.downloads_log, menu);
+ isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
@Override
- public void onPrepareOptionsMenu(Menu menu) {
+ public void onPrepareOptionsMenu(@NonNull Menu menu) {
super.onPrepareOptionsMenu(menu);
MenuItem menuItem = menu.findItem(R.id.clear_history_item);
if (menuItem != null) {
@@ -172,12 +188,15 @@ public class DownloadLogFragment extends ListFragment {
}
@Override
- public boolean onOptionsItemSelected(MenuItem item) {
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (!super.onOptionsItemSelected(item)) {
switch (item.getItemId()) {
case R.id.clear_history_item:
DBWriter.clearDownloadLog();
return true;
+ case R.id.refresh_item:
+ AutoUpdateManager.runImmediate(requireContext());
+ return true;
default:
return false;
}
@@ -186,6 +205,17 @@ public class DownloadLogFragment extends ListFragment {
}
}
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(DownloadEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
+ getActivity().invalidateOptionsMenu();
+ }
+ }
+
+ private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker =
+ () -> DownloadService.isRunning && DownloadRequester.getInstance().isDownloadingFeeds();
+
private void loadItems() {
if (disposable != null) {
disposable.dispose();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
index cf0c6db90..c173bf8ee 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
@@ -8,6 +8,7 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
@@ -39,7 +40,9 @@ public class DownloadsFragment extends Fragment {
private TabLayout tabLayout;
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.pager_fragment, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar);
@@ -76,7 +79,7 @@ public class DownloadsFragment extends Fragment {
}
@Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (getArguments() != null) {
int tab = getArguments().getInt(ARG_SELECTED_TAB);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
index 29b6a1b16..44f6c8827 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
@@ -120,7 +120,7 @@ public abstract class EpisodesListFragment extends Fragment {
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
if (!isAdded()) {
return;
}
@@ -131,7 +131,7 @@ public abstract class EpisodesListFragment extends Fragment {
}
@Override
- public boolean onOptionsItemSelected(MenuItem item) {
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (!super.onOptionsItemSelected(item)) {
switch (item.getItemId()) {
case R.id.refresh_item:
@@ -176,7 +176,7 @@ public abstract class EpisodesListFragment extends Fragment {
}
@Override
- public boolean onContextItemSelected(MenuItem item) {
+ public boolean onContextItemSelected(@NonNull MenuItem item) {
Log.d(TAG, "onContextItemSelected() called with: " + "item = [" + item + "]");
if (!getUserVisibleHint()) {
return false;
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 02f1de0d4..94c9bd056 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -77,7 +77,6 @@ public class ExternalPlayerFragment extends Fragment {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- controller = setupPlaybackController();
butPlay.setOnClickListener(v -> {
if (controller != null) {
controller.playPause();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
index 4f8b4f00c..d50be88c5 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
@@ -53,12 +53,14 @@ public class FavoriteEpisodesFragment extends EpisodesListFragment {
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT) {
@Override
- public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
+ public boolean onMove(@NonNull RecyclerView recyclerView,
+ @NonNull RecyclerView.ViewHolder viewHolder,
+ @NonNull RecyclerView.ViewHolder target) {
return false;
}
@Override
- public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
+ public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int swipeDir) {
EpisodeItemViewHolder holder = (EpisodeItemViewHolder) viewHolder;
Log.d(TAG, String.format("remove(%s)", holder.getFeedItem().getId()));
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java
index c58e6c15f..ae03b5032 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.fragment;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
import android.graphics.LightingColorFilter;
import android.net.Uri;
import android.os.Bundle;
@@ -47,9 +48,6 @@ import io.reactivex.MaybeOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import org.apache.commons.lang3.StringUtils;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
/**
* Displays information about a feed.
@@ -71,6 +69,8 @@ public class FeedInfoFragment extends Fragment {
private TextView txtvUrl;
private TextView txtvAuthorHeader;
private ImageView imgvBackground;
+ private View infoContainer;
+ private View header;
private Menu optionsMenu;
private ToolbarIconTintManager iconTintManager;
@@ -124,6 +124,8 @@ public class FeedInfoFragment extends Fragment {
txtvTitle = root.findViewById(R.id.txtvTitle);
txtvAuthorHeader = root.findViewById(R.id.txtvAuthor);
imgvBackground = root.findViewById(R.id.imgvBackground);
+ header = root.findViewById(R.id.headerContainer);
+ infoContainer = root.findViewById(R.id.infoContainer);
root.findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
root.findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
// https://github.com/bumptech/glide/issues/529
@@ -159,6 +161,15 @@ public class FeedInfoFragment extends Fragment {
}, error -> Log.d(TAG, Log.getStackTraceString(error)), () -> { });
}
+ @Override
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ int horizontalSpacing = (int) getResources().getDimension(R.dimen.additional_horizontal_spacing);
+ header.setPadding(horizontalSpacing, header.getPaddingTop(), horizontalSpacing, header.getPaddingBottom());
+ infoContainer.setPadding(horizontalSpacing, infoContainer.getPaddingTop(),
+ horizontalSpacing, infoContainer.getPaddingBottom());
+ }
+
private void showFeed() {
Log.d(TAG, "Language is " + feed.getLanguage());
Log.d(TAG, "Author is " + feed.getAuthor());
@@ -216,7 +227,7 @@ public class FeedInfoFragment extends Fragment {
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.feedinfo, menu);
optionsMenu = menu;
@@ -224,7 +235,7 @@ public class FeedInfoFragment extends Fragment {
}
@Override
- public void onPrepareOptionsMenu(Menu menu) {
+ public void onPrepareOptionsMenu(@NonNull Menu menu) {
super.onPrepareOptionsMenu(menu);
menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null);
menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null
@@ -232,7 +243,7 @@ public class FeedInfoFragment extends Fragment {
}
@Override
- public boolean onOptionsItemSelected(MenuItem item) {
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (feed == null) {
((MainActivity) getActivity()).showSnackbarAbovePlayer(
R.string.please_wait_for_data, Toast.LENGTH_LONG);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
index 284b775ea..7b66a189f 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
@@ -2,6 +2,8 @@ package de.danoeh.antennapod.fragment;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.res.Configuration;
+import android.content.Intent;
import android.graphics.LightingColorFilter;
import android.os.Bundle;
import android.util.Log;
@@ -52,6 +54,7 @@ import de.danoeh.antennapod.core.glide.FastBlurTransformation;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.FeedItemPermutors;
@@ -60,6 +63,7 @@ import de.danoeh.antennapod.core.util.Optional;
import de.danoeh.antennapod.core.util.ThemeUtils;
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
+import de.danoeh.antennapod.dialog.FilterDialog;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
@@ -77,6 +81,7 @@ import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
+import java.util.Set;
/**
* Displays a list of FeedItems.
@@ -98,6 +103,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
private TextView txtvAuthor;
private ImageButton butShowInfo;
private ImageButton butShowSettings;
+ private View header;
private Menu optionsMenu;
private ToolbarIconTintManager iconTintManager;
@@ -155,6 +161,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
butShowSettings = root.findViewById(R.id.butShowSettings);
txtvInformation = root.findViewById(R.id.txtvInformation);
txtvFailure = root.findViewById(R.id.txtvFailure);
+ header = root.findViewById(R.id.headerContainer);
AppBarLayout appBar = root.findViewById(R.id.appBar);
CollapsingToolbarLayout collapsingToolbar = root.findViewById(R.id.collapsing_toolbar);
@@ -221,7 +228,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
};
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
if (!isAdded()) {
return;
}
@@ -239,14 +246,21 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
}
@Override
- public void onPrepareOptionsMenu(Menu menu) {
+ public void onPrepareOptionsMenu(@NonNull Menu menu) {
if (feed != null) {
FeedMenuHandler.onPrepareOptionsMenu(menu, feed);
}
}
@Override
- public boolean onOptionsItemSelected(MenuItem item) {
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ int horizontalSpacing = (int) getResources().getDimension(R.dimen.additional_horizontal_spacing);
+ header.setPadding(horizontalSpacing, header.getPaddingTop(), horizontalSpacing, header.getPaddingBottom());
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (!super.onOptionsItemSelected(item)) {
if (feed == null) {
((MainActivity) getActivity()).showSnackbarAbovePlayer(
@@ -366,7 +380,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
if (event.hasChangedFeedUpdateStatus(isUpdatingFeed)) {
updateSyncProgressBarVisibility();
}
- if (adapter != null && update.mediaIds.length > 0) {
+ if (adapter != null && update.mediaIds.length > 0 && feed != null) {
for (long mediaId : update.mediaIds) {
int pos = FeedItemUtil.indexOfItemWithMediaId(feed.getItems(), mediaId);
if (pos >= 0) {
@@ -406,14 +420,14 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
@Subscribe(threadMode = ThreadMode.MAIN)
public void onFeedListChanged(FeedListUpdateEvent event) {
- if (event.contains(feed)) {
+ if (feed != null && event.contains(feed)) {
updateUi();
}
}
private void updateSyncProgressBarVisibility() {
if (isUpdatingFeed != updateRefreshMenuItemChecker.isRefreshing()) {
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
}
if (!DownloadRequester.getInstance().isDownloadingFeeds()) {
nextPageLoader.getRoot().setVisibility(View.GONE);
@@ -433,9 +447,11 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
}
recyclerView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
- adapter.updateItems(feed.getItems());
+ if (feed != null) {
+ adapter.updateItems(feed.getItems());
+ }
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
updateSyncProgressBarVisibility();
}
@@ -460,8 +476,19 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) txtvInformation.getLayoutParams();
p.addRule(RelativeLayout.BELOW, R.id.txtvFailure);
}
- txtvInformation.setText("{fa-info-circle} " + this.getString(R.string.filtered_label));
+ txtvInformation.setText("{md-info-outline} " + this.getString(R.string.filtered_label));
Iconify.addIcons(txtvInformation);
+ txtvInformation.setOnClickListener((l) -> {
+ FilterDialog filterDialog = new FilterDialog(requireContext(), feed.getItemFilter()) {
+ @Override
+ protected void updateFilter(Set<String> filterValues) {
+ feed.setItemFilter(filterValues.toArray(new String[0]));
+ DBWriter.setFeedItemsFilter(feed.getId(), filterValues);
+ }
+ };
+
+ filterDialog.openDialog();
+ });
txtvInformation.setVisibility(View.VISIBLE);
} else {
txtvInformation.setVisibility(View.GONE);
@@ -488,6 +515,14 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.SLIDE);
}
});
+ txtvFailure.setOnClickListener(v -> {
+ Intent intent = new Intent(getContext(), MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_FRAGMENT_TAG, DownloadsFragment.TAG);
+ Bundle args = new Bundle();
+ args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_LOG);
+ intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
+ startActivity(intent);
+ });
headerCreated = true;
}
@@ -561,4 +596,4 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
holder.coverHolder.setVisibility(View.GONE);
}
}
-}
+} \ No newline at end of file
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
index 8251e8716..209e5d0e1 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
@@ -66,7 +66,7 @@ public class FeedSettingsFragment extends Fragment {
Toolbar toolbar = root.findViewById(R.id.toolbar);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
- getFragmentManager().beginTransaction()
+ getParentFragmentManager().beginTransaction()
.replace(R.id.settings_fragment_container,
FeedSettingsPreferenceFragment.newInstance(feedId), "settings_fragment")
.commitAllowingStateLoss();
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 3ae4cc648..ed8697adb 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -66,9 +66,6 @@ public class ItemDescriptionFragment extends Fragment {
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Fragment destroyed");
- if (webViewLoader != null) {
- webViewLoader.dispose();
- }
if (webvDescription != null) {
webvDescription.removeAllViews();
webvDescription.destroy();
@@ -97,7 +94,7 @@ public class ItemDescriptionFragment extends Fragment {
@Nullable
private String loadData() {
- if (controller != null && controller.getMedia() == null) {
+ if (controller == null || controller.getMedia() == null) {
return null;
}
Timeline timeline = new Timeline(getActivity(), controller.getMedia());
@@ -168,6 +165,10 @@ public class ItemDescriptionFragment extends Fragment {
@Override
public void onStop() {
super.onStop();
+
+ if (webViewLoader != null) {
+ webViewLoader.dispose();
+ }
controller.release();
controller = null;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
index 814dbc74e..669dbdac2 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -146,9 +146,7 @@ public class ItemFragment extends Fragment {
}
txtvDuration = layout.findViewById(R.id.txtvDuration);
txtvPublished = layout.findViewById(R.id.txtvPublished);
- if (Build.VERSION.SDK_INT >= 14) { // ellipsize is causing problems on old versions, see #448
- txtvTitle.setEllipsize(TextUtils.TruncateAt.END);
- }
+ txtvTitle.setEllipsize(TextUtils.TruncateAt.END);
webvDescription = layout.findViewById(R.id.webvDescription);
webvDescription.setTimecodeSelectedListener(time -> {
if (controller != null && item.getMedia() != null && controller.getMedia() != null
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java
index c198ce258..3b1171df4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java
@@ -140,13 +140,11 @@ public class ItemPagerFragment extends Fragment {
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
- switch (menuItem.getItemId()) {
- case R.id.open_podcast:
- openPodcast();
- return true;
- default:
- return FeedItemMenuHandler.onMenuItemClicked(this, menuItem.getItemId(), item);
+ if (menuItem.getItemId() == R.id.open_podcast) {
+ openPodcast();
+ return true;
}
+ return FeedItemMenuHandler.onMenuItemClicked(this, menuItem.getItemId(), item);
}
@Subscribe(threadMode = ThreadMode.MAIN)
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java
index ceae7f847..8746793be 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java
@@ -19,6 +19,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
@@ -36,6 +37,7 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
+import de.danoeh.antennapod.dialog.FeedFilterDialog;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
@@ -85,9 +87,8 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
registerForContextMenu(navList);
updateSelection();
- root.findViewById(R.id.nav_settings).setOnClickListener(v -> {
- startActivity(new Intent(getActivity(), PreferenceActivity.class));
- });
+ root.findViewById(R.id.nav_settings).setOnClickListener(v ->
+ startActivity(new Intent(getActivity(), PreferenceActivity.class)));
getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(this);
return root;
@@ -373,6 +374,7 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
String tag = navAdapter.getTags().get(position);
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).loadFragment(tag, null);
+ ((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED);
} else {
showMainActivity(tag);
}
@@ -381,12 +383,16 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
long feedId = navDrawerData.feeds.get(pos).getId();
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).loadFeedFragmentById(feedId, null);
+ ((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED);
} else {
Intent intent = new Intent(getActivity(), MainActivity.class);
intent.putExtra(MainActivity.EXTRA_FEED_ID, feedId);
startActivity(intent);
}
}
+ } else if (UserPreferences.getFeedFilter() != UserPreferences.FEED_FILTER_NONE
+ && navAdapter.showSubscriptionList) {
+ FeedFilterDialog.showDialog(requireContext());
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java
index d9c31f993..8ecb692a5 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java
@@ -126,7 +126,7 @@ public class OnlineSearchFragment extends Fragment {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.online_search, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
- final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
+ final SearchView sv = (SearchView) searchItem.getActionView();
sv.setQueryHint(getString(R.string.search_podcast_hint));
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
index dabff7269..db4bda1f5 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -153,7 +153,7 @@ public class PlaybackHistoryFragment extends Fragment {
}
super.onCreateOptionsMenu(menu, inflater);
MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
- MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ clearHistory.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.ic_delete});
clearHistory.setIcon(drawables.getDrawable(0));
drawables.recycle();
@@ -171,13 +171,11 @@ public class PlaybackHistoryFragment extends Fragment {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!super.onOptionsItemSelected(item)) {
- switch (item.getItemId()) {
- case R.id.clear_history_item:
- DBWriter.clearPlaybackHistory();
- return true;
- default:
- return false;
+ if (item.getItemId() == R.id.clear_history_item) {
+ DBWriter.clearPlaybackHistory();
+ return true;
}
+ return false;
} else {
return true;
}
@@ -196,18 +194,18 @@ public class PlaybackHistoryFragment extends Fragment {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onHistoryUpdated(PlaybackHistoryEvent event) {
loadItems();
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onPlayerStatusChanged(PlayerStatusEvent event) {
loadItems();
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
}
private void onFragmentLoaded() {
adapter.notifyDataSetChanged();
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
}
private void loadItems() {
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 49c53627f..da156f904 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -16,7 +16,6 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
@@ -136,6 +135,7 @@ public class QueueFragment extends Fragment {
recyclerAdapter.notifyItemInserted(event.position);
break;
case SET_QUEUE:
+ case SORTED: //Deliberate fall-through
queue = event.items;
recyclerAdapter.notifyDataSetChanged();
break;
@@ -149,10 +149,6 @@ public class QueueFragment extends Fragment {
queue.clear();
recyclerAdapter.notifyDataSetChanged();
break;
- case SORTED:
- queue = event.items;
- recyclerAdapter.notifyDataSetChanged();
- break;
case MOVED:
return;
}
@@ -216,7 +212,7 @@ public class QueueFragment extends Fragment {
public void onPlayerStatusChanged(PlayerStatusEvent event) {
loadItems(false);
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
}
}
@@ -225,7 +221,7 @@ public class QueueFragment extends Fragment {
// Sent when playback position is reset
loadItems(false);
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
}
}
@@ -340,10 +336,10 @@ public class QueueFragment extends Fragment {
SortOrder sortOrder = UserPreferences.getQueueKeepSortedOrder();
DBWriter.reorderQueue(sortOrder, true);
if (recyclerAdapter != null) {
- recyclerAdapter.setLocked(true);
+ recyclerAdapter.updateDragDropEnabled();
}
} else if (recyclerAdapter != null) {
- recyclerAdapter.setLocked(UserPreferences.isQueueLocked());
+ recyclerAdapter.updateDragDropEnabled();
}
getActivity().invalidateOptionsMenu();
return true;
@@ -384,9 +380,9 @@ public class QueueFragment extends Fragment {
private void setQueueLocked(boolean locked) {
UserPreferences.setQueueLocked(locked);
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
if (recyclerAdapter != null) {
- recyclerAdapter.setLocked(locked);
+ recyclerAdapter.updateDragDropEnabled();
}
if (locked) {
((MainActivity) getActivity()).showSnackbarAbovePlayer(R.string.queue_locked, Snackbar.LENGTH_SHORT);
@@ -572,7 +568,7 @@ public class QueueFragment extends Fragment {
// we need to refresh the options menu because it sometimes
// needs data that may have just been loaded.
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
refreshInfoBar();
}
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 ddcf09992..ca9fba694 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
@@ -1,8 +1,13 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
+
+import androidx.annotation.NonNull;
import androidx.fragment.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 android.widget.Toast;
@@ -21,10 +26,13 @@ import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadRequest;
+import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.view.EmptyViewHandler;
import org.greenrobot.eventbus.ThreadMode;
@@ -38,6 +46,8 @@ public class RunningDownloadsFragment extends ListFragment {
private DownloadlistAdapter adapter;
private List<Downloader> downloaderList = new ArrayList<>();
+ private boolean isUpdatingFeeds = false;
+
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@@ -66,6 +76,12 @@ public class RunningDownloadsFragment extends ListFragment {
}
@Override
+ public void onResume() {
+ super.onResume();
+ setHasOptionsMenu(true);
+ }
+
+ @Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
@@ -77,6 +93,33 @@ public class RunningDownloadsFragment extends ListFragment {
setListAdapter(null);
}
+ @Override
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.downloads_running, menu);
+ isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.refresh_item) {
+ AutoUpdateManager.runImmediate(requireContext());
+ return true;
+ }
+ return false;
+ }
+
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(DownloadEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
+ getActivity().invalidateOptionsMenu();
+ }
+ }
+
+ private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker =
+ () -> DownloadService.isRunning && DownloadRequester.getInstance().isDownloadingFeeds();
+
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(DownloadEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
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 1ebf382fe..0c03d407e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -124,7 +124,6 @@ public class SearchFragment extends Fragment {
LinearLayoutManager layoutManagerFeeds = new LinearLayoutManager(getActivity());
layoutManagerFeeds.setOrientation(RecyclerView.HORIZONTAL);
recyclerViewFeeds.setLayoutManager(layoutManagerFeeds);
- recyclerViewFeeds.setHasFixedSize(true);
adapterFeeds = new FeedSearchResultAdapter((MainActivity) getActivity());
recyclerViewFeeds.setAdapter(adapterFeeds);
@@ -174,7 +173,7 @@ public class SearchFragment extends Fragment {
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
- getFragmentManager().popBackStack();
+ getParentFragmentManager().popBackStack();
return true;
}
});
@@ -190,7 +189,7 @@ public class SearchFragment extends Fragment {
return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
}
- @Subscribe
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
search();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
index 1e248af07..7d6a3dc40 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
@@ -19,8 +19,10 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridView;
+import android.widget.TextView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.joanzapata.iconify.Iconify;
import java.util.concurrent.Callable;
@@ -34,6 +36,7 @@ import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -42,6 +45,7 @@ import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.dialog.FeedFilterDialog;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.view.EmptyViewHandler;
@@ -68,6 +72,7 @@ public class SubscriptionFragment extends Fragment {
private FloatingActionButton subscriptionAddButton;
private ProgressBar progressBar;
private EmptyViewHandler emptyView;
+ private TextView feedsFilteredMsg;
private int mPosition = -1;
private boolean isUpdatingFeeds = false;
@@ -90,10 +95,13 @@ public class SubscriptionFragment extends Fragment {
View root = inflater.inflate(R.layout.fragment_subscriptions, container, false);
((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar));
subscriptionGridLayout = root.findViewById(R.id.subscriptions_grid);
- subscriptionGridLayout.setNumColumns(prefs.getInt(PREF_NUM_COLUMNS, 3));
+ subscriptionGridLayout.setNumColumns(prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns()));
registerForContextMenu(subscriptionGridLayout);
subscriptionAddButton = root.findViewById(R.id.subscriptions_add);
progressBar = root.findViewById(R.id.progLoading);
+
+ feedsFilteredMsg = root.findViewById(R.id.feeds_filtered_message);
+ feedsFilteredMsg.setOnClickListener((l) -> FeedFilterDialog.showDialog(requireContext()));
return root;
}
@@ -102,7 +110,7 @@ public class SubscriptionFragment extends Fragment {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.subscriptions, menu);
- int columns = prefs.getInt(PREF_NUM_COLUMNS, 3);
+ int columns = prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns());
menu.findItem(R.id.subscription_num_columns_2).setChecked(columns == 2);
menu.findItem(R.id.subscription_num_columns_3).setChecked(columns == 3);
menu.findItem(R.id.subscription_num_columns_4).setChecked(columns == 4);
@@ -120,6 +128,9 @@ public class SubscriptionFragment extends Fragment {
case R.id.refresh_item:
AutoUpdateManager.runImmediate(requireContext());
return true;
+ case R.id.subscriptions_filter:
+ FeedFilterDialog.showDialog(requireContext());
+ return true;
case R.id.subscription_num_columns_2:
setColumnNumber(2);
return true;
@@ -198,6 +209,18 @@ public class SubscriptionFragment extends Fragment {
emptyView.updateVisibility();
progressBar.setVisibility(View.GONE);
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
+
+ if (UserPreferences.getFeedFilter() != UserPreferences.FEED_FILTER_NONE) {
+ feedsFilteredMsg.setText("{md-info-outline} " + getString(R.string.subscriptions_are_filtered));
+ Iconify.addIcons(feedsFilteredMsg);
+ feedsFilteredMsg.setVisibility(View.VISIBLE);
+ } else {
+ feedsFilteredMsg.setVisibility(View.GONE);
+ }
+ }
+
+ private int getDefaultNumOfColumns() {
+ return getResources().getInteger(R.integer.subscriptions_default_num_of_columns);
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
index e1c85a2d3..d5cac07f1 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
@@ -56,9 +56,9 @@ public abstract class PodcastListFragment extends Fragment {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.gpodder_podcasts, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
- final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
+ final SearchView sv = (SearchView) searchItem.getActionView();
sv.setQueryHint(getString(R.string.gpodnet_search_hint));
- sv.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
sv.clearFocus();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
index 80f1a6ae0..72a752bf1 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
@@ -48,7 +48,7 @@ public class SearchListFragment extends PodcastListFragment {
super.onCreateOptionsMenu(menu, inflater);
// parent already inflated menu
MenuItem searchItem = menu.findItem(R.id.action_search);
- final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
+ final SearchView sv = (SearchView) searchItem.getActionView();
sv.setQueryHint(getString(R.string.gpodnet_search_hint));
sv.setQuery(query, false);
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
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 a7a0781ce..53a31b68d 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
@@ -38,7 +38,7 @@ public class TagListFragment extends ListFragment {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.gpodder_podcasts, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
- final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
+ final SearchView sv = (SearchView) searchItem.getActionView();
sv.setQueryHint(getString(R.string.gpodnet_search_hint));
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java
index 0fa7bd4bb..eb57972a1 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java
@@ -28,12 +28,12 @@ public class AboutFragment extends PreferenceFragmentCompat {
return true;
});
findPreference("about_developers").setOnPreferenceClickListener((preference) -> {
- getFragmentManager().beginTransaction().replace(R.id.content, new AboutDevelopersFragment())
+ getParentFragmentManager().beginTransaction().replace(R.id.content, new AboutDevelopersFragment())
.addToBackStack(getString(R.string.developers)).commit();
return true;
});
findPreference("about_translators").setOnPreferenceClickListener((preference) -> {
- getFragmentManager().beginTransaction().replace(R.id.content, new AboutTranslatorsFragment())
+ getParentFragmentManager().beginTransaction().replace(R.id.content, new AboutTranslatorsFragment())
.addToBackStack(getString(R.string.translators)).commit();
return true;
});
@@ -42,7 +42,7 @@ public class AboutFragment extends PreferenceFragmentCompat {
return true;
});
findPreference("about_licenses").setOnPreferenceClickListener((preference) -> {
- getFragmentManager().beginTransaction().replace(R.id.content, new AboutLicensesFragment())
+ getParentFragmentManager().beginTransaction().replace(R.id.content, new AboutLicensesFragment())
.addToBackStack(getString(R.string.translators)).commit();
return true;
});
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
index 6b15e4301..064c4b3bc 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.fragment.preferences;
+import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
@@ -85,6 +86,7 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat {
return val == null ? "" : val;
}
+ @SuppressLint("MissingPermission") // getConfiguredNetworks needs location permission starting with API 29
private void buildAutodownloadSelectedNetworksPreference() {
if (Build.VERSION.SDK_INT >= 29) {
return;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
index 8f8b4675d..546e12e65 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
@@ -3,9 +3,11 @@ package de.danoeh.antennapod.fragment.preferences;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
+import androidx.core.text.HtmlCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
-import android.text.Html;
+
+import android.text.Spanned;
import android.text.format.DateUtils;
import android.widget.Toast;
import com.google.android.material.snackbar.Snackbar;
@@ -115,7 +117,8 @@ public class GpodderPreferencesFragment extends PreferenceFragmentCompat {
String format = getActivity().getString(R.string.pref_gpodnet_login_status);
String summary = String.format(format, GpodnetPreferences.getUsername(),
GpodnetPreferences.getDeviceID());
- findPreference(PREF_GPODNET_LOGOUT).setSummary(Html.fromHtml(summary));
+ Spanned formattedSummary = HtmlCompat.fromHtml(summary, HtmlCompat.FROM_HTML_MODE_LEGACY);
+ findPreference(PREF_GPODNET_LOGOUT).setSummary(formattedSummary);
updateLastGpodnetSyncReport(SyncService.isLastSyncSuccessful(getContext()),
SyncService.getLastSyncAttempt(getContext()));
} else {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
index 5275f5f7e..5eb4a3aea 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
@@ -3,9 +3,7 @@ package de.danoeh.antennapod.fragment.preferences;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -18,13 +16,14 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.content.FileProvider;
import androidx.preference.PreferenceFragmentCompat;
import com.google.android.material.snackbar.Snackbar;
+import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OpmlImportActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.activity.SplashActivity;
import de.danoeh.antennapod.asynctask.DocumentFileExportWorker;
import de.danoeh.antennapod.asynctask.ExportWorker;
import de.danoeh.antennapod.core.export.ExportWriter;
+import de.danoeh.antennapod.core.export.favorites.FavoritesWriter;
import de.danoeh.antennapod.core.export.html.HtmlWriter;
import de.danoeh.antennapod.core.export.opml.OpmlWriter;
import de.danoeh.antennapod.core.storage.DatabaseExporter;
@@ -39,6 +38,7 @@ import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
+import java.util.Locale;
public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
private static final String TAG = "ImportExPrefFragment";
@@ -47,15 +47,18 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
private static final String PREF_HTML_EXPORT = "prefHtmlExport";
private static final String PREF_DATABASE_IMPORT = "prefDatabaseImport";
private static final String PREF_DATABASE_EXPORT = "prefDatabaseExport";
+ private static final String PREF_FAVORITE_EXPORT = "prefFavoritesExport";
private static final String DEFAULT_OPML_OUTPUT_NAME = "antennapod-feeds-%s.opml";
private static final String CONTENT_TYPE_OPML = "text/x-opml";
private static final String DEFAULT_HTML_OUTPUT_NAME = "antennapod-feeds-%s.html";
private static final String CONTENT_TYPE_HTML = "text/html";
+ private static final String DEFAULT_FAVORITES_OUTPUT_NAME = "antennapod-favorites-%s.html";
private static final int REQUEST_CODE_CHOOSE_OPML_EXPORT_PATH = 1;
private static final int REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH = 2;
private static final int REQUEST_CODE_CHOOSE_HTML_EXPORT_PATH = 3;
private static final int REQUEST_CODE_RESTORE_DATABASE = 4;
private static final int REQUEST_CODE_BACKUP_DATABASE = 5;
+ private static final int REQUEST_CODE_CHOOSE_FAVORITES_EXPORT_PATH = 6;
private static final String DATABASE_EXPORT_FILENAME = "AntennaPodBackup-%s.db";
private Disposable disposable;
private ProgressDialog progressDialog;
@@ -84,9 +87,7 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
}
private String dateStampFilename(String fname) {
- return String.format(fname,
- new SimpleDateFormat("yyyy-MM-dd")
- .format(new Date()));
+ return String.format(fname, new SimpleDateFormat("yyyy-MM-dd", Locale.US).format(new Date()));
}
private void setupStorageScreen() {
@@ -125,6 +126,12 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
exportDatabase();
return true;
});
+ findPreference(PREF_FAVORITE_EXPORT).setOnPreferenceClickListener(
+ preference -> {
+ openExportPathPicker(CONTENT_TYPE_HTML, dateStampFilename(DEFAULT_FAVORITES_OUTPUT_NAME),
+ REQUEST_CODE_CHOOSE_FAVORITES_EXPORT_PATH, new FavoritesWriter());
+ return true;
+ });
}
private void exportWithWriter(ExportWriter exportWriter, final Uri uri) {
@@ -203,13 +210,7 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
AlertDialog.Builder d = new AlertDialog.Builder(getContext());
d.setMessage(R.string.import_ok);
d.setCancelable(false);
- d.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
- Intent intent = new Intent(getContext(), SplashActivity.class);
- ComponentName cn = intent.getComponent();
- Intent mainIntent = Intent.makeRestartActivityTask(cn);
- startActivity(mainIntent);
- Runtime.getRuntime().exit(0);
- });
+ d.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> PodcastApp.forceRestart());
d.show();
}
@@ -257,6 +258,8 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
exportWithWriter(new OpmlWriter(), uri);
} else if (requestCode == REQUEST_CODE_CHOOSE_HTML_EXPORT_PATH) {
exportWithWriter(new HtmlWriter(), uri);
+ } else if (requestCode == REQUEST_CODE_CHOOSE_FAVORITES_EXPORT_PATH) {
+ exportWithWriter(new FavoritesWriter(), uri);
} else if (requestCode == REQUEST_CODE_RESTORE_DATABASE) {
progressDialog.show();
disposable = Completable.fromAction(() -> DatabaseExporter.importBackup(uri, getContext()))
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
index d9dd7c47d..0409ce11b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
@@ -20,7 +20,7 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
private static final String PREF_SCREEN_GPODDER = "prefScreenGpodder";
private static final String PREF_SCREEN_STORAGE = "prefScreenStorage";
private static final String PREF_FAQ = "prefFaq";
- private static final String PREF_VIEW_MAILING_LIST = "prefViewMailingList";
+ private static final String PREF_VIEW_FORUM = "prefViewForum";
private static final String PREF_SEND_BUG_REPORT = "prefSendBugReport";
private static final String STATISTICS = "statistics";
private static final String PREF_ABOUT = "prefAbout";
@@ -62,14 +62,14 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
findPreference(PREF_ABOUT).setOnPreferenceClickListener(
preference -> {
- getFragmentManager().beginTransaction().replace(R.id.content, new AboutFragment())
+ getParentFragmentManager().beginTransaction().replace(R.id.content, new AboutFragment())
.addToBackStack(getString(R.string.about_pref)).commit();
return true;
}
);
findPreference(STATISTICS).setOnPreferenceClickListener(
preference -> {
- getFragmentManager().beginTransaction().replace(R.id.content, new StatisticsFragment())
+ getParentFragmentManager().beginTransaction().replace(R.id.content, new StatisticsFragment())
.addToBackStack(getString(R.string.statistics_label)).commit();
return true;
}
@@ -78,8 +78,8 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
IntentUtils.openInBrowser(getContext(), "https://antennapod.org/faq.html");
return true;
});
- findPreference(PREF_VIEW_MAILING_LIST).setOnPreferenceClickListener(preference -> {
- IntentUtils.openInBrowser(getContext(), "https://groups.google.com/forum/#!forum/antennapod");
+ findPreference(PREF_VIEW_FORUM).setOnPreferenceClickListener(preference -> {
+ IntentUtils.openInBrowser(getContext(), "https://forum.antennapod.org/");
return true;
});
findPreference(PREF_SEND_BUG_REPORT).setOnPreferenceClickListener(preference -> {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
index 741080cf1..f07e59afe 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
@@ -45,7 +45,7 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
final Activity activity = getActivity();
findPreference(PREF_PLAYBACK_SPEED_LAUNCHER).setOnPreferenceClickListener(preference -> {
- VariableSpeedDialog.showDialog(activity);
+ new VariableSpeedDialog().show(getChildFragmentManager(), null);
return true;
});
findPreference(PREF_PLAYBACK_REWIND_DELTA_LAUNCHER).setOnPreferenceClickListener(preference -> {
@@ -116,7 +116,7 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
if(x == 0) {
entries[x] = res.getString(R.string.pref_smart_mark_as_played_disabled);
} else {
- Integer v = Integer.parseInt(values[x]);
+ int v = Integer.parseInt(values[x]);
if(v < 60) {
entries[x] = res.getQuantityString(R.plurals.time_seconds_quantified, v, v);
} else {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
index 8a0742b7f..42b0cb96f 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
@@ -1,18 +1,9 @@
package de.danoeh.antennapod.fragment.preferences;
-import android.Manifest;
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Build;
import android.os.Bundle;
-import android.util.Log;
import androidx.appcompat.app.AlertDialog;
-import androidx.core.app.ActivityCompat;
import androidx.preference.PreferenceFragmentCompat;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.DirectoryChooserActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
@@ -23,10 +14,6 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
private static final String TAG = "StoragePrefFragment";
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
private static final String PREF_IMPORT_EXPORT = "prefImportExport";
- 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;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@@ -47,36 +34,12 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
}
private void setupStorageScreen() {
- final Activity activity = getActivity();
findPreference(PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
preference -> {
- if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT
- && Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
- showChooseDataFolderDialog();
- } else {
- int readPermission = ActivityCompat.checkSelfPermission(
- activity, Manifest.permission.READ_EXTERNAL_STORAGE);
- int writePermission = ActivityCompat.checkSelfPermission(
- activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
- if (readPermission == PackageManager.PERMISSION_GRANTED
- && writePermission == PackageManager.PERMISSION_GRANTED) {
- openDirectoryChooser();
- } else {
- requestPermission();
- }
- }
- return true;
- }
- );
- findPreference(PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
- preference -> {
- if (Build.VERSION.SDK_INT >= 19) {
- showChooseDataFolderDialog();
- } else {
- Intent intent = new Intent(activity, DirectoryChooserActivity.class);
- activity.startActivityForResult(intent,
- DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
- }
+ ChooseDataFolderDialog.showDialog(getContext(), path -> {
+ UserPreferences.setDataFolder(path);
+ setDataFolderText();
+ });
return true;
}
);
@@ -104,65 +67,10 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
);
}
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (resultCode == Activity.RESULT_OK && requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
- String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
-
- File path;
- if (dir != null) {
- path = new File(dir);
- } else {
- path = getActivity().getExternalFilesDir(null);
- }
- String message = null;
- final Context context = getActivity().getApplicationContext();
- if (!path.exists()) {
- message = String.format(context.getString(R.string.folder_does_not_exist_error), dir);
- } else if (!path.canRead()) {
- message = String.format(context.getString(R.string.folder_not_readable_error), dir);
- } else if (!path.canWrite()) {
- message = String.format(context.getString(R.string.folder_not_writable_error), dir);
- }
-
- if (message == null) {
- Log.d(TAG, "Setting data folder: " + dir);
- UserPreferences.setDataFolder(dir);
- setDataFolderText();
- } else {
- AlertDialog.Builder ab = new AlertDialog.Builder(getActivity());
- ab.setMessage(message);
- ab.setPositiveButton(android.R.string.ok, null);
- ab.show();
- }
- }
- }
-
private void setDataFolderText() {
File f = UserPreferences.getDataFolder(null);
if (f != null) {
findPreference(PREF_CHOOSE_DATA_DIR).setSummary(f.getAbsolutePath());
}
}
-
- private void requestPermission() {
- ActivityCompat.requestPermissions(getActivity(), EXTERNAL_STORAGE_PERMISSIONS,
- PERMISSION_REQUEST_EXTERNAL_STORAGE);
- }
-
- private void openDirectoryChooser() {
- Activity activity = getActivity();
- Intent intent = new Intent(activity, DirectoryChooserActivity.class);
- activity.startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
- }
-
- private void showChooseDataFolderDialog() {
- ChooseDataFolderDialog.showDialog(
- getActivity(), new ChooseDataFolderDialog.RunnableWithString() {
- @Override
- public void run(final String folder) {
- UserPreferences.setDataFolder(folder);
- setDataFolderText();
- }
- });
- }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
index a44623f48..4596fc90e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
@@ -12,6 +12,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.dialog.FeedFilterDialog;
import de.danoeh.antennapod.fragment.NavDrawerFragment;
import org.apache.commons.lang3.ArrayUtils;
@@ -75,6 +76,12 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat {
return true;
});
+ findPreference(UserPreferences.PREF_FILTER_FEED)
+ .setOnPreferenceClickListener((preference -> {
+ FeedFilterDialog.showDialog(requireContext());
+ return true;
+ }));
+
if (Build.VERSION.SDK_INT >= 26) {
findPreference(UserPreferences.PREF_EXPANDED_NOTIFICATION).setVisible(false);
}
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 5860a2c5e..06b1c55bc 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
@@ -2,13 +2,14 @@ package de.danoeh.antennapod.menuhandler;
import android.content.Context;
import android.os.Handler;
-import androidx.annotation.NonNull;
-import com.google.android.material.snackbar.Snackbar;
-import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
+import com.google.android.material.snackbar.Snackbar;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -23,6 +24,7 @@ import de.danoeh.antennapod.core.sync.model.EpisodeAction;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
+import de.danoeh.antennapod.dialog.ShareDialog;
/**
* Handles interactions with the FeedItemMenu.
@@ -61,23 +63,12 @@ public class FeedItemMenuHandler {
}
if (!ShareUtils.hasLinkToShare(selectedItem)) {
setItemVisibility(menu, R.id.visit_website_item, false);
- setItemVisibility(menu, R.id.share_link_item, false);
- setItemVisibility(menu, R.id.share_link_with_position_item, false);
- }
- if (!hasMedia || selectedItem.getMedia().getDownload_url() == null) {
- setItemVisibility(menu, R.id.share_download_url_item, false);
- setItemVisibility(menu, R.id.share_download_url_with_position_item, false);
- }
- if (!hasMedia || selectedItem.getMedia().getPosition() <= 0) {
- setItemVisibility(menu, R.id.share_download_url_with_position_item, false);
- setItemVisibility(menu, R.id.share_link_with_position_item, false);
}
if (selectedItem.getFeed().isLocalFeed()) {
setItemVisibility(menu, R.id.visit_website_item, false);
}
boolean fileDownloaded = hasMedia && selectedItem.getMedia().fileExists();
- setItemVisibility(menu, R.id.share_file, fileDownloaded);
setItemVisibility(menu, R.id.remove_new_flag_item, selectedItem.isNew());
if (selectedItem.isPlayed()) {
@@ -246,20 +237,9 @@ public class FeedItemMenuHandler {
case R.id.visit_website_item:
IntentUtils.openInBrowser(context, FeedItemUtil.getLinkWithFallback(selectedItem));
break;
- case R.id.share_link_item:
- ShareUtils.shareFeedItemLink(context, selectedItem);
- break;
- case R.id.share_download_url_item:
- ShareUtils.shareFeedItemDownloadLink(context, selectedItem);
- break;
- case R.id.share_link_with_position_item:
- ShareUtils.shareFeedItemLink(context, selectedItem, true);
- break;
- case R.id.share_download_url_with_position_item:
- ShareUtils.shareFeedItemDownloadLink(context, selectedItem, true);
- break;
- case R.id.share_file:
- ShareUtils.shareFeedItemFile(context, selectedItem.getMedia());
+ case R.id.share_item:
+ ShareDialog shareDialog = ShareDialog.newInstance(selectedItem);
+ shareDialog.show((fragment.getActivity().getSupportFragmentManager()), "ShareEpisodeDialog");
break;
default:
Log.d(TAG, "Unknown menuItemId: " + menuItemId);
diff --git a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemListRecyclerView.java b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemListRecyclerView.java
index 58d562616..83d90f98b 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemListRecyclerView.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemListRecyclerView.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.view;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.util.AttributeSet;
import android.view.View;
import androidx.appcompat.view.ContextThemeWrapper;
@@ -39,6 +40,14 @@ public class EpisodeItemListRecyclerView extends RecyclerView {
setLayoutManager(layoutManager);
setHasFixedSize(true);
addItemDecoration(new HorizontalDividerItemDecoration.Builder(getContext()).build());
+ setClipToPadding(false);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ int horizontalSpacing = (int) getResources().getDimension(R.dimen.additional_horizontal_spacing);
+ setPadding(horizontalSpacing, getPaddingTop(), horizontalSpacing, getPaddingBottom());
}
public void saveScrollPosition(String tag) {
diff --git a/app/src/main/java/de/danoeh/antennapod/view/ItemOffsetDecoration.java b/app/src/main/java/de/danoeh/antennapod/view/ItemOffsetDecoration.java
new file mode 100644
index 000000000..4a1267d81
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/view/ItemOffsetDecoration.java
@@ -0,0 +1,24 @@
+package de.danoeh.antennapod.view;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.View;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * Source: https://stackoverflow.com/a/30794046
+ */
+public class ItemOffsetDecoration extends RecyclerView.ItemDecoration {
+ private final int itemOffset;
+
+ public ItemOffsetDecoration(@NonNull Context context, int itemOffsetDp) {
+ itemOffset = (int) (itemOffsetDp * context.getResources().getDisplayMetrics().density);
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+ super.getItemOffsets(outRect, view, parent, state);
+ outRect.set(itemOffset, itemOffset, itemOffset, itemOffset);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/NestedScrollableHost.java b/app/src/main/java/de/danoeh/antennapod/view/NestedScrollableHost.java
index a4daa9109..0e1846f1c 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/NestedScrollableHost.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/NestedScrollableHost.java
@@ -54,7 +54,7 @@ class NestedScrollableHost extends FrameLayout {
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
- private int touchSlop = 0;
+ private int touchSlop;
private float initialX = 0f;
private float initialY = 0f;
diff --git a/app/src/main/java/de/danoeh/antennapod/view/PlaybackSpeedSeekBar.java b/app/src/main/java/de/danoeh/antennapod/view/PlaybackSpeedSeekBar.java
new file mode 100644
index 000000000..47797e4a4
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/view/PlaybackSpeedSeekBar.java
@@ -0,0 +1,86 @@
+package de.danoeh.antennapod.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.SeekBar;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.util.Consumer;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.dialog.VariableSpeedDialog;
+
+public class PlaybackSpeedSeekBar extends FrameLayout {
+ private SeekBar seekBar;
+ private PlaybackController controller;
+ private Consumer<Float> progressChangedListener;
+
+ public PlaybackSpeedSeekBar(@NonNull Context context) {
+ super(context);
+ setup();
+ }
+
+ public PlaybackSpeedSeekBar(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ setup();
+ }
+
+ public PlaybackSpeedSeekBar(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setup();
+ }
+
+ private void setup() {
+ View.inflate(getContext(), R.layout.playback_speed_seek_bar, this);
+ seekBar = findViewById(R.id.playback_speed);
+ findViewById(R.id.butDecSpeed).setOnClickListener(v -> seekBar.setProgress(seekBar.getProgress() - 2));
+ findViewById(R.id.butIncSpeed).setOnClickListener(v -> seekBar.setProgress(seekBar.getProgress() + 2));
+
+ seekBar.setOnSeekBarChangeListener(new SeekBar.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);
+
+ if (progressChangedListener != null) {
+ progressChangedListener.accept(playbackSpeed);
+ }
+ } else if (fromUser) {
+ seekBar.post(() -> updateSpeed());
+ }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ if (controller != null && !controller.canSetPlaybackSpeed()) {
+ VariableSpeedDialog.showGetPluginDialog(getContext());
+ }
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ }
+
+ public void updateSpeed() {
+ if (controller != null) {
+ seekBar.setProgress(Math.round((20 * controller.getCurrentPlaybackSpeedMultiplier()) - 10));
+ }
+ }
+
+ public void setController(PlaybackController controller) {
+ this.controller = controller;
+ updateSpeed();
+ if (progressChangedListener != null && controller != null) {
+ progressChangedListener.accept(controller.getCurrentPlaybackSpeedMultiplier());
+ }
+ }
+
+ public void setProgressChangedListener(Consumer<Float> progressChangedListener) {
+ this.progressChangedListener = progressChangedListener;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/RecursiveRadioGroup.java b/app/src/main/java/de/danoeh/antennapod/view/RecursiveRadioGroup.java
new file mode 100644
index 000000000..ee5e7c51d
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/view/RecursiveRadioGroup.java
@@ -0,0 +1,67 @@
+package de.danoeh.antennapod.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import java.util.ArrayList;
+
+/**
+ * An alternative to {@link android.widget.RadioGroup} that allows to nest children.
+ * Basend on https://stackoverflow.com/a/14309274.
+ */
+public class RecursiveRadioGroup extends LinearLayout {
+ private final ArrayList<RadioButton> radioButtons = new ArrayList<>();
+ private RadioButton checkedButton = null;
+
+ public RecursiveRadioGroup(Context context) {
+ super(context);
+ }
+
+ public RecursiveRadioGroup(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public RecursiveRadioGroup(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ super.addView(child, index, params);
+ parseChild(child);
+ }
+
+ public void parseChild(final View child) {
+ if (child instanceof RadioButton) {
+ RadioButton button = (RadioButton) child;
+ radioButtons.add(button);
+ button.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ if (!isChecked) {
+ return;
+ }
+ checkedButton = (RadioButton) buttonView;
+
+ for (RadioButton view : radioButtons) {
+ if (view != buttonView) {
+ view.setChecked(false);
+ }
+ }
+ });
+ } else if (child instanceof ViewGroup) {
+ parseChildren((ViewGroup) child);
+ }
+ }
+
+ public void parseChildren(final ViewGroup child) {
+ for (int i = 0; i < child.getChildCount(); i++) {
+ parseChild(child.getChildAt(i));
+ }
+ }
+
+ public RadioButton getCheckedButton() {
+ return checkedButton;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/ShownotesWebView.java b/app/src/main/java/de/danoeh/antennapod/view/ShownotesWebView.java
index 99c8900ba..9355c0c15 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/ShownotesWebView.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/ShownotesWebView.java
@@ -68,7 +68,7 @@ public class ShownotesWebView extends WebView implements View.OnLongClickListene
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Timeline.isTimecodeLink(url) && timecodeSelectedListener != null) {
- timecodeSelectedListener.accept(Timeline.getTimecodeLinkTime(selectedUrl));
+ timecodeSelectedListener.accept(Timeline.getTimecodeLinkTime(url));
} else {
IntentUtils.openInBrowser(getContext(), url);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/ToolbarIconTintManager.java b/app/src/main/java/de/danoeh/antennapod/view/ToolbarIconTintManager.java
index dcf8ff20d..163100fff 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/ToolbarIconTintManager.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/ToolbarIconTintManager.java
@@ -33,11 +33,15 @@ public abstract class ToolbarIconTintManager implements AppBarLayout.OnOffsetCha
public void updateTint() {
if (isTinted) {
doTint(new ContextThemeWrapper(context, R.style.Theme_AntennaPod_Dark));
- toolbar.getNavigationIcon().setColorFilter(0xffffffff, PorterDuff.Mode.SRC_ATOP);
+ if (toolbar.getNavigationIcon() != null) { // Tablets do not show a navigation icon
+ toolbar.getNavigationIcon().setColorFilter(0xffffffff, PorterDuff.Mode.SRC_ATOP);
+ }
toolbar.getOverflowIcon().setColorFilter(0xffffffff, PorterDuff.Mode.SRC_ATOP);
} else {
doTint(context);
- toolbar.getNavigationIcon().clearColorFilter();
+ if (toolbar.getNavigationIcon() != null) { // Tablets do not show a navigation icon
+ toolbar.getNavigationIcon().clearColorFilter();
+ }
toolbar.getOverflowIcon().clearColorFilter();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
index b7e1728b5..902e5094b 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
@@ -39,7 +39,7 @@ import de.danoeh.antennapod.view.CircularProgressBar;
public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
private static final String TAG = "EpisodeItemViewHolder";
- private final View container;
+ public final View container;
public final ImageView dragHandle;
private final TextView placeholder;
private final ImageView cover;
@@ -102,7 +102,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
isNew.setVisibility(item.isNew() ? View.VISIBLE : View.GONE);
isFavorite.setVisibility(item.isTagged(FeedItem.TAG_FAVORITE) ? View.VISIBLE : View.GONE);
isInQueue.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.GONE);
- itemView.setAlpha(item.isPlayed() ? 0.6f : 1.0f);
+ itemView.setAlpha(item.isPlayed() ? 0.5f : 1.0f);
ItemActionButton actionButton = ItemActionButton.forItem(item, true, true);
actionButton.configure(secondaryActionButton, secondaryActionIcon, activity);
diff --git a/app/src/main/play/listings/en-US/full-description.txt b/app/src/main/play/listings/en-US/full-description.txt
index e0042e07f..568dd57bf 100644
--- a/app/src/main/play/listings/en-US/full-description.txt
+++ b/app/src/main/play/listings/en-US/full-description.txt
@@ -24,8 +24,8 @@ Made by podcast-enthusiasts, AntennaPod is free in all senses of the word: open
<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:
-https://www.github.com/AntennaPod/AntennaPod
+Our friendly forum members are happy to help with every question you have. You are invited to discuss features and podcasting in general, too.
+https://forum.antennapod.org/
Transifex is the place to help with translations:
https://www.transifex.com/antennapod/antennapod
diff --git a/app/src/main/res/layout-sw720dp/main.xml b/app/src/main/res/layout-sw720dp/main.xml
new file mode 100644
index 000000000..79b7213e0
--- /dev/null
+++ b/app/src/main/res/layout-sw720dp/main.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ 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:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <FrameLayout
+ android:id="@+id/navDrawerFragment"
+ android:layout_width="300dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:orientation="vertical" />
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/listDivider" />
+
+ <androidx.coordinatorlayout.widget.CoordinatorLayout
+ android:id="@+id/overview_coordinator_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <FrameLayout
+ android:id="@+id/main_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentTop="true"
+ android:foreground="?android:windowContentOverlay"
+ tools:background="@android:color/holo_red_dark" />
+
+ <FrameLayout
+ android:elevation="8dp"
+ android:id="@+id/audioplayerFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?android:attr/windowBackground"
+ android:visibility="gone"
+ app:layout_behavior="de.danoeh.antennapod.view.LockableBottomSheetBehavior" />
+
+ </androidx.coordinatorlayout.widget.CoordinatorLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/about.xml b/app/src/main/res/layout/about.xml
deleted file mode 100644
index 42f5e1245..000000000
--- a/app/src/main/res/layout/about.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/webViewContainer"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <WebView
- android:id="@+id/webViewAbout"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/addfeed.xml b/app/src/main/res/layout/addfeed.xml
index 7430579b4..297c5d812 100644
--- a/app/src/main/res/layout/addfeed.xml
+++ b/app/src/main/res/layout/addfeed.xml
@@ -71,7 +71,7 @@
android:focusableInTouchMode="true"
android:padding="16dp">
- <fragment
+ <androidx.fragment.app.FragmentContainerView
android:id="@+id/quickFeedDiscovery"
android:name="de.danoeh.antennapod.fragment.QuickFeedDiscoveryFragment"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/all_episodes_fragment.xml b/app/src/main/res/layout/all_episodes_fragment.xml
index 73f061a0f..353e4f1d0 100644
--- a/app/src/main/res/layout/all_episodes_fragment.xml
+++ b/app/src/main/res/layout/all_episodes_fragment.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
@@ -24,9 +23,9 @@
android:layout_below="@+id/txtvInformation"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
- android:clipToPadding="false"
android:paddingTop="@dimen/list_vertical_padding"
android:paddingBottom="@dimen/list_vertical_padding"
+ android:paddingHorizontal="@dimen/additional_horizontal_spacing"
android:layout_above="@id/loadingMore"
tools:itemCount="13"
tools:listitem="@layout/feeditemlist_item" />
diff --git a/app/src/main/res/layout/audio_controls.xml b/app/src/main/res/layout/audio_controls.xml
index aa1bdf236..2c9665aad 100644
--- a/app/src/main/res/layout/audio_controls.xml
+++ b/app/src/main/res/layout/audio_controls.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -38,47 +39,10 @@
</LinearLayout>
- <LinearLayout
+ <de.danoeh.antennapod.view.PlaybackSpeedSeekBar
+ android:id="@+id/speed_seek_bar"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center_vertical">
-
- <TextView
- android:id="@+id/butDecSpeed"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:gravity="center"
- android:text="-"
- android:clickable="true"
- android:focusable="true"
- android:textStyle="bold"
- android:textSize="24sp"
- android:textColor="?attr/colorSecondary"
- android:contentDescription="@string/decrease_speed"
- android:background="?attr/selectableItemBackgroundBorderless"/>
-
- <SeekBar
- android:id="@+id/playback_speed"
- android:layout_width="0dp"
- android:layout_height="32dp"
- android:max="70"
- android:layout_weight="1" />
-
- <TextView
- android:id="@+id/butIncSpeed"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:gravity="center"
- android:text="+"
- android:clickable="true"
- android:focusable="true"
- android:textStyle="bold"
- android:textSize="24sp"
- android:textColor="?attr/colorSecondary"
- android:contentDescription="@string/increase_speed"
- android:background="?attr/selectableItemBackgroundBorderless" />
- </LinearLayout>
+ android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
diff --git a/app/src/main/res/layout/audioplayer_fragment.xml b/app/src/main/res/layout/audioplayer_fragment.xml
index 5b4e26b69..1c2866a1b 100644
--- a/app/src/main/res/layout/audioplayer_fragment.xml
+++ b/app/src/main/res/layout/audioplayer_fragment.xml
@@ -184,7 +184,7 @@
android:layout_toStartOf="@id/butRev"
android:layout_centerVertical="true"
android:background="?attr/selectableItemBackgroundBorderless"
- android:contentDescription="@string/set_playback_speed_label"
+ android:contentDescription="@string/playback_speed"
tools:srcCompat="@drawable/ic_playback_speed_white"/>
<TextView
diff --git a/app/src/main/res/layout/choose_data_folder_dialog_entry.xml b/app/src/main/res/layout/choose_data_folder_dialog_entry.xml
index ae59c0614..addc63f4d 100644
--- a/app/src/main/res/layout/choose_data_folder_dialog_entry.xml
+++ b/app/src/main/res/layout/choose_data_folder_dialog_entry.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/cover_fragment.xml b/app/src/main/res/layout/cover_fragment.xml
index 28321e760..443f19835 100644
--- a/app/src/main/res/layout/cover_fragment.xml
+++ b/app/src/main/res/layout/cover_fragment.xml
@@ -1,49 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:squareImageView="http://schemas.android.com/apk/de.danoeh.antennapod"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
+ android:orientation="horizontal"
+ android:id="@+id/cover_fragment"
android:padding="8dp"
android:gravity="center">
<de.danoeh.antennapod.view.SquareImageView
android:id="@+id/imgvCover"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:scaleType="fitCenter"
- android:layout_marginLeft="32dp"
- android:layout_marginRight="32dp"
- android:transitionName="coverTransition"
- tools:src="@android:drawable/sym_def_app_icon"
+ android:layout_width="200dp"
+ android:layout_height="200dp"
+ android:layout_gravity="center"
+ android:layout_marginLeft="64dp"
+ android:layout_marginRight="64dp"
+ android:layout_weight="0"
android:foreground="?attr/selectableItemBackgroundBorderless"
android:importantForAccessibility="no"
- squareImageView:direction="minimum" />
+ android:scaleType="fitCenter"
+ squareImageView:direction="height"
+ tools:src="@android:drawable/sym_def_app_icon" />
- <TextView
- android:id="@+id/txtvPodcastTitle"
+ <LinearLayout
+ android:id="@+id/cover_fragment_text_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:ellipsize="end"
- android:gravity="center"
- android:maxLines="2"
+ android:orientation="vertical"
android:layout_marginTop="16dp"
- android:textColor="?android:attr/textColorSecondary"
- android:textIsSelectable="true"
- tools:text="Podcast" />
+ android:layout_marginBottom="8dp">
- <TextView
- android:id="@+id/txtvEpisodeTitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:gravity="center"
- android:maxLines="2"
- android:textColor="?android:attr/textColorPrimary"
- android:textIsSelectable="true"
- android:layout_marginBottom="8dp"
- tools:text="Episode" />
+ <TextView
+ android:id="@+id/txtvPodcastTitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:gravity="center"
+ android:maxLines="2"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textIsSelectable="true"
+ tools:text="Podcast" />
+
+ <TextView
+ android:id="@+id/txtvEpisodeTitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:gravity="center"
+ android:maxLines="2"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textIsSelectable="true"
+ tools:text="Episode" />
+ </LinearLayout>
</LinearLayout>
diff --git a/app/src/main/res/layout/directory_chooser.xml b/app/src/main/res/layout/directory_chooser.xml
deleted file mode 100644
index fbe5a3d19..000000000
--- a/app/src/main/res/layout/directory_chooser.xml
+++ /dev/null
@@ -1,122 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:background="@android:color/darker_gray">
-
- <RelativeLayout
- android:id="@+id/footer"
- android:layout_width="fill_parent"
- android:layout_height="48dp"
- android:layout_alignParentBottom="true" >
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:layout_alignParentTop="true"
- android:background="?android:attr/dividerVertical" />
-
- <View
- android:id="@+id/horizontal_divider"
- android:layout_width="1dip"
- android:layout_height="fill_parent"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="4dp"
- android:background="?android:attr/dividerVertical" />
-
- <Button
- android:id="@+id/butCancel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentTop="true"
- android:layout_toLeftOf="@id/horizontal_divider"
- android:layout_toStartOf="@id/horizontal_divider"
- android:background="?android:attr/selectableItemBackground"
- android:text="@string/cancel_label" />
-
- <Button
- android:id="@+id/butConfirm"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:layout_alignParentTop="true"
- android:layout_toRightOf="@id/horizontal_divider"
- android:layout_toEndOf="@id/horizontal_divider"
- android:background="?android:attr/selectableItemBackground"
- android:text="@string/confirm_label" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/directory_info"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true" >
-
- <ImageButton
- android:id="@+id/butNavUp"
- android:contentDescription="@string/navigate_upwards_label"
- android:layout_width="60dp"
- android:layout_height="60dp"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentTop="true"
- android:background="?attr/selectableItemBackground"
- android:src="?attr/navigation_up"
- tools:src="@drawable/navigation_up"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvSelectedFolderLabel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="8dp"
- android:layout_toRightOf="@id/butNavUp"
- android:layout_toEndOf="@id/butNavUp"
- android:text="@string/selected_folder_label"
- android:textStyle="bold"
- tools:background="@android:color/holo_green_dark">
- </TextView>
-
- <TextView
- android:id="@+id/txtvSelectedFolder"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:layout_below="@id/txtvSelectedFolderLabel"
- android:layout_margin="8dp"
- android:layout_toRightOf="@id/butNavUp"
- android:layout_toEndOf="@id/butNavUp"
- android:ellipsize="start"
- android:scrollHorizontally="true"
- android:singleLine="true"
- tools:text="/path/to/selected/folder"
- tools:background="@android:color/holo_green_dark"/>
-
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_below="@id/butNavUp"
- android:background="?android:attr/dividerHorizontal" />
- </RelativeLayout>
-
- <ListView
- android:id="@+id/directory_list"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_above="@id/footer"
- android:layout_below="@id/directory_info" />
-
-</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/downloadlog_item.xml b/app/src/main/res/layout/downloadlog_item.xml
index dd8328c8c..5cde763a0 100644
--- a/app/src/main/res/layout/downloadlog_item.xml
+++ b/app/src/main/res/layout/downloadlog_item.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
- xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
diff --git a/app/src/main/res/layout/empty_view_layout.xml b/app/src/main/res/layout/empty_view_layout.xml
index 768f74c41..da2040d93 100644
--- a/app/src/main/res/layout/empty_view_layout.xml
+++ b/app/src/main/res/layout/empty_view_layout.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
diff --git a/app/src/main/res/layout/feed_item_list_fragment.xml b/app/src/main/res/layout/feed_item_list_fragment.xml
index d6c7409a8..b995ff28f 100644
--- a/app/src/main/res/layout/feed_item_list_fragment.xml
+++ b/app/src/main/res/layout/feed_item_list_fragment.xml
@@ -52,6 +52,7 @@
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingHorizontal="@dimen/additional_horizontal_spacing"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<ProgressBar
diff --git a/app/src/main/res/layout/feedinfo.xml b/app/src/main/res/layout/feedinfo.xml
index fa6aac251..dd349c15c 100644
--- a/app/src/main/res/layout/feedinfo.xml
+++ b/app/src/main/res/layout/feedinfo.xml
@@ -62,6 +62,8 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:id="@+id/infoContainer"
+ android:paddingHorizontal="@dimen/additional_horizontal_spacing"
android:orientation="vertical">
<TextView
diff --git a/app/src/main/res/layout/feeditemlist_header.xml b/app/src/main/res/layout/feeditemlist_header.xml
index e74aeac0a..a8845ec27 100644
--- a/app/src/main/res/layout/feeditemlist_header.xml
+++ b/app/src/main/res/layout/feeditemlist_header.xml
@@ -5,6 +5,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:id="@+id/headerContainer"
+ android:paddingHorizontal="@dimen/additional_horizontal_spacing"
android:orientation="vertical">
<LinearLayout
diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml
index 90062bbf6..c2bcced6f 100644
--- a/app/src/main/res/layout/feeditemlist_item.xml
+++ b/app/src/main/res/layout/feeditemlist_item.xml
@@ -91,7 +91,7 @@
android:gravity="center_vertical">
<TextView
- android:text="@string/new_episodes_label"
+ android:text="@string/new_label"
style="@style/AntennaPod.TextView.UnreadIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/filter_dialog.xml b/app/src/main/res/layout/filter_dialog.xml
new file mode 100644
index 000000000..39e9258d9
--- /dev/null
+++ b/app/src/main/res/layout/filter_dialog.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingLeft="24dp"
+ android:paddingTop="24dp"
+ android:paddingRight="24dp"
+ android:paddingBottom="8dp">
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/filter_dialog_row.xml b/app/src/main/res/layout/filter_dialog_row.xml
new file mode 100644
index 000000000..0863997b3
--- /dev/null
+++ b/app/src/main/res/layout/filter_dialog_row.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<de.danoeh.antennapod.view.RecursiveRadioGroup
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingBottom="8dp"
+ android:orientation="horizontal">
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:clipChildren="true"
+ app:cardCornerRadius="32dp"
+ app:cardElevation="0dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <RadioButton
+ android:id="@+id/filter_dialog_radioButton1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="2dp"
+ android:layout_marginRight="2dp"
+ android:layout_weight="1"
+ android:background="?attr/filter_dialog_button_background"
+ android:button="@android:color/transparent"
+ android:foreground="?android:attr/selectableItemBackground"
+ android:checked="false"
+ android:gravity="center"
+ android:textColor="@color/filter_dialog_button_text" />
+
+ <RadioButton
+ android:id="@+id/filter_dialog_radioButton2"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?attr/filter_dialog_button_background"
+ android:button="@android:color/transparent"
+ android:foreground="?android:attr/selectableItemBackground"
+ android:checked="false"
+ android:gravity="center"
+ android:textColor="@color/filter_dialog_button_text" />
+ </LinearLayout>
+ </androidx.cardview.widget.CardView>
+
+ <RadioButton
+ android:id="@+id/filter_dialog_clear"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:background="@drawable/ic_filter_close"
+ android:button="@android:color/transparent"
+ android:foreground="?android:attr/selectableItemBackground"
+ android:layout_gravity="center_vertical"
+ android:checked="true" />
+
+</de.danoeh.antennapod.view.RecursiveRadioGroup>
diff --git a/app/src/main/res/layout/fragment_subscriptions.xml b/app/src/main/res/layout/fragment_subscriptions.xml
index f37a6febd..a1a5a26f2 100644
--- a/app/src/main/res/layout/fragment_subscriptions.xml
+++ b/app/src/main/res/layout/fragment_subscriptions.xml
@@ -14,8 +14,22 @@
app:title="@string/subscriptions_label"
android:id="@+id/toolbar"/>
- <GridView
+ <TextView
+ android:id="@+id/feeds_filtered_message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:layout_below="@id/toolbar"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="start"
+ android:paddingStart="8dp"
+ android:paddingTop="4dp"
+ android:paddingEnd="8dp"
+ android:paddingBottom="8dp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_small" />
+
+ <GridView
+ android:layout_below="@id/feeds_filtered_message"
android:id="@+id/subscriptions_grid"
android:layout_width="match_parent"
android:numColumns="3"
diff --git a/app/src/main/res/layout/listview_activity.xml b/app/src/main/res/layout/listview_activity.xml
deleted file mode 100644
index b276f506c..000000000
--- a/app/src/main/res/layout/listview_activity.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?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="match_parent">
- <ListView
- android:id="@+id/listview"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
-
-</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml
index 6da514b4a..48195a176 100644
--- a/app/src/main/res/layout/main.xml
+++ b/app/src/main/res/layout/main.xml
@@ -5,7 +5,9 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ tools:ignore="InconsistentLayout">
+ <!-- InconsistentLayout: Tablet layout does not have a drawer -->
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/overview_coordinator_layout"
@@ -35,8 +37,6 @@
android:id="@+id/navDrawerFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginEnd="24dp"
- android:layout_marginRight="24dp"
android:layout_gravity="start"
android:orientation="vertical" />
diff --git a/app/src/main/res/layout/nav_section_item.xml b/app/src/main/res/layout/nav_section_item.xml
index 45d0dff59..fb3021556 100644
--- a/app/src/main/res/layout/nav_section_item.xml
+++ b/app/src/main/res/layout/nav_section_item.xml
@@ -1,16 +1,28 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="16dp"
+ android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:orientation="vertical"
- android:importantForAccessibility="no">
+ android:importantForAccessibility="no"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
- android:layout_centerVertical="true"
android:background="?android:attr/listDivider"
tools:background="@android:color/holo_red_dark"/>
-</RelativeLayout>
+
+ <TextView
+ android:id="@+id/nav_feeds_filtered_message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="start"
+ android:paddingStart="@dimen/listitem_icon_leftpadding"
+ android:paddingTop="4dp"
+ android:paddingEnd="@dimen/listitem_icon_leftpadding"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_small" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/playback_speed_seek_bar.xml b/app/src/main/res/layout/playback_speed_seek_bar.xml
new file mode 100644
index 000000000..0d3985f5a
--- /dev/null
+++ b/app/src/main/res/layout/playback_speed_seek_bar.xml
@@ -0,0 +1,43 @@
+<?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="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
+
+ <TextView
+ android:id="@+id/butDecSpeed"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:gravity="center"
+ android:text="-"
+ android:clickable="true"
+ android:focusable="true"
+ android:textStyle="bold"
+ android:textSize="24sp"
+ android:textColor="?attr/colorSecondary"
+ android:contentDescription="@string/decrease_speed"
+ android:background="?attr/selectableItemBackgroundBorderless"/>
+
+ <SeekBar
+ android:id="@+id/playback_speed"
+ android:layout_width="0dp"
+ android:layout_height="32dp"
+ android:max="70"
+ android:layout_weight="1" />
+
+ <TextView
+ android:id="@+id/butIncSpeed"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:gravity="center"
+ android:text="+"
+ android:clickable="true"
+ android:focusable="true"
+ android:textStyle="bold"
+ android:textSize="24sp"
+ android:textColor="?attr/colorSecondary"
+ android:contentDescription="@string/increase_speed"
+ android:background="?attr/selectableItemBackgroundBorderless" />
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/queue_fragment.xml b/app/src/main/res/layout/queue_fragment.xml
index 94f929d30..6a1851648 100644
--- a/app/src/main/res/layout/queue_fragment.xml
+++ b/app/src/main/res/layout/queue_fragment.xml
@@ -36,6 +36,7 @@
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingHorizontal="@dimen/additional_horizontal_spacing"
android:layout_below="@id/divider" />
<ProgressBar
diff --git a/app/src/main/res/layout/search_fragment.xml b/app/src/main/res/layout/search_fragment.xml
index 19cd87409..0bc663db1 100644
--- a/app/src/main/res/layout/search_fragment.xml
+++ b/app/src/main/res/layout/search_fragment.xml
@@ -36,7 +36,7 @@
android:layout_below="@id/recyclerViewFeeds"
android:layout_marginTop="-4dp"
android:paddingTop="12dp"
- android:clipToPadding="false"
+ android:paddingHorizontal="@dimen/additional_horizontal_spacing"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
diff --git a/app/src/main/res/layout/searchlist_item.xml b/app/src/main/res/layout/searchlist_item.xml
deleted file mode 100644
index 608bfc3bc..000000000
--- a/app/src/main/res/layout/searchlist_item.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- tools:background="@android:color/darker_gray"
- android:paddingTop="@dimen/listitem_threeline_verticalpadding"
- android:paddingBottom="@dimen/listitem_threeline_verticalpadding">
-
- <ImageView
- android:id="@+id/imgvFeedimage"
- android:layout_width="@dimen/thumbnail_length_itemlist"
- android:layout_height="@dimen/thumbnail_length_itemlist"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_centerVertical="true"
- android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
- android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
- android:importantForAccessibility="no"
- android:scaleType="centerCrop"
- tools:src="@drawable/ic_antenna"
- tools:background="@android:color/holo_green_dark"/>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginLeft="@dimen/listitem_iconwithtext_textleftpadding"
- android:layout_marginStart="@dimen/listitem_iconwithtext_textleftpadding"
- android:layout_marginRight="@dimen/listitem_threeline_verticalpadding"
- android:layout_marginEnd="@dimen/listitem_threeline_verticalpadding"
- android:layout_toRightOf="@id/imgvFeedimage"
- android:layout_toEndOf="@id/imgvFeedimage"
- android:orientation="vertical"
- tools:background="@android:color/holo_red_dark">
-
- <TextView
- android:id="@+id/txtvTitle"
- style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- tools:text="Search item title"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvSubtitle"
- style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:lines="1"
- tools:text="Search item subtitle"
- tools:background="@android:color/holo_blue_light"/>
- </LinearLayout>
-
-</RelativeLayout>
diff --git a/app/src/main/res/layout/share_episode_dialog.xml b/app/src/main/res/layout/share_episode_dialog.xml
new file mode 100644
index 000000000..8cf955d4c
--- /dev/null
+++ b/app/src/main/res/layout/share_episode_dialog.xml
@@ -0,0 +1,40 @@
+<?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="match_parent"
+ android:gravity="center"
+ android:padding="16dp">
+
+ <RadioGroup
+ android:id="@+id/share_dialog_radio_group"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:orientation="vertical">
+
+ <RadioButton android:id="@+id/share_episode_website_radio"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/share_dialog_episode_website_label"
+ android:checked="true"
+ />
+ <RadioButton android:id="@+id/share_media_file_radio"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/share_dialog_media_file_label"
+ />
+ </RadioGroup>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/share_dialog_include_label"/>
+
+ <CheckBox
+ android:id="@+id/share_start_at_timer_dialog"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/share_playback_position_dialog_label" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/simple_list_fragment.xml b/app/src/main/res/layout/simple_list_fragment.xml
index 368029932..989566499 100644
--- a/app/src/main/res/layout/simple_list_fragment.xml
+++ b/app/src/main/res/layout/simple_list_fragment.xml
@@ -14,9 +14,9 @@
<de.danoeh.antennapod.view.EpisodeItemListRecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingHorizontal="@dimen/additional_horizontal_spacing"
android:layout_below="@id/toolbar"
- android:id="@+id/recyclerView"
- android:clipToPadding="false"/>
+ android:id="@+id/recyclerView"/>
<ProgressBar
android:id="@+id/progLoading"
diff --git a/app/src/main/res/layout/speed_select_dialog.xml b/app/src/main/res/layout/speed_select_dialog.xml
new file mode 100644
index 000000000..e4d78c3fa
--- /dev/null
+++ b/app/src/main/res/layout/speed_select_dialog.xml
@@ -0,0 +1,45 @@
+<?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:padding="16dp"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:text="@string/playback_speed"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"/>
+
+ <com.google.android.material.chip.Chip
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/add_current_speed_chip"/>
+ </LinearLayout>
+
+ <de.danoeh.antennapod.view.PlaybackSpeedSeekBar
+ android:id="@+id/speed_seek_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="8dp">
+ </de.danoeh.antennapod.view.PlaybackSpeedSeekBar>
+
+ <TextView
+ android:text="@string/speed_presets"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ android:layout_marginBottom="8dp"/>
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/selected_speeds_grid"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/statistics_fragment.xml b/app/src/main/res/layout/statistics_fragment.xml
deleted file mode 100644
index e44c7ca81..000000000
--- a/app/src/main/res/layout/statistics_fragment.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
-
- <com.google.android.material.tabs.TabLayout
- android:id="@+id/sliding_tabs"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/windowBackground"
- app:tabBackground="?attr/selectableItemBackground"
- app:tabGravity="fill"
- app:tabMode="fixed" />
-
- <androidx.viewpager2.widget.ViewPager2
- android:id="@+id/viewpager"
- android:layout_width="match_parent"
- android:layout_height="0px"
- android:layout_weight="1" />
-</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/menu/directory_chooser.xml b/app/src/main/res/menu/directory_chooser.xml
deleted file mode 100644
index e6150ac20..000000000
--- a/app/src/main/res/menu/directory_chooser.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
-
- <item
- android:id="@+id/new_folder_item"
- android:title="@string/create_folder_label"
- app:icon="?attr/content_new"
- app:showAsAction="ifRoom|withText" />
- <item
- android:id="@+id/set_to_default_folder_item"
- android:title="@string/set_to_default_folder"
- app:showAsAction="collapseActionView" />
-
-</menu>
diff --git a/app/src/main/res/menu/downloads_completed.xml b/app/src/main/res/menu/downloads_completed.xml
index 8badc4927..e07af520f 100644
--- a/app/src/main/res/menu/downloads_completed.xml
+++ b/app/src/main/res/menu/downloads_completed.xml
@@ -7,4 +7,10 @@
android:title="@string/multi_select"
android:icon="?attr/checkbox_multiple"
app:showAsAction="ifRoom" />
+ <item
+ android:id="@+id/refresh_item"
+ android:title="@string/refresh_label"
+ android:menuCategory="container"
+ app:showAsAction="ifRoom"
+ android:icon="?attr/navigation_refresh"/>
</menu>
diff --git a/app/src/main/res/menu/downloads_log.xml b/app/src/main/res/menu/downloads_log.xml
new file mode 100644
index 000000000..d37d9bf3f
--- /dev/null
+++ b/app/src/main/res/menu/downloads_log.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item
+ android:id="@+id/clear_history_item"
+ android:menuCategory="container"
+ android:title="@string/clear_history_label"
+ android:icon="?attr/ic_delete"
+ app:showAsAction="ifRoom" />
+ <item
+ android:id="@+id/refresh_item"
+ android:title="@string/refresh_label"
+ android:menuCategory="container"
+ app:showAsAction="ifRoom"
+ android:icon="?attr/navigation_refresh"/>
+</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/downloads_running.xml b/app/src/main/res/menu/downloads_running.xml
new file mode 100644
index 000000000..a2240d4aa
--- /dev/null
+++ b/app/src/main/res/menu/downloads_running.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item
+ android:id="@+id/refresh_item"
+ android:title="@string/refresh_label"
+ android:menuCategory="container"
+ app:showAsAction="ifRoom"
+ android:icon="?attr/navigation_refresh"/>
+</menu> \ No newline at end of file
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 c3f117386..181300fc5 100644
--- a/app/src/main/res/menu/episodes_apply_action_options.xml
+++ b/app/src/main/res/menu/episodes_apply_action_options.xml
@@ -33,7 +33,7 @@
<item android:id="@+id/check_all"
android:title="@string/all_label"/>
<item android:id="@+id/check_none"
- android:title="@string/none_label"/>
+ android:title="@string/select_none_label"/>
<item android:id="@+id/check_played"
android:title="@string/played_label"/>
<item android:id="@+id/check_unplayed"
diff --git a/app/src/main/res/menu/feeditem_options.xml b/app/src/main/res/menu/feeditem_options.xml
index e415ff85a..c29229e37 100644
--- a/app/src/main/res/menu/feeditem_options.xml
+++ b/app/src/main/res/menu/feeditem_options.xml
@@ -71,29 +71,7 @@
<item
android:id="@+id/share_item"
android:menuCategory="container"
- android:title="@string/share_label">
- <menu>
- <item
- android:id="@+id/share_link_item"
- android:menuCategory="container"
- android:title="@string/share_link_label" />
- <item
- android:id="@+id/share_link_with_position_item"
- android:menuCategory="container"
- android:title="@string/share_link_with_position_label" />
- <item
- android:id="@+id/share_download_url_item"
- android:menuCategory="container"
- android:title="@string/share_item_url_label" />
- <item
- android:id="@+id/share_download_url_with_position_item"
- android:menuCategory="container"
- android:title="@string/share_item_url_with_position_label" />
- <item
- android:id="@+id/share_file"
- android:menuCategory="container"
- android:title="@string/share_file_label" />
- </menu>
+ android:title="@string/share_label_with_ellipses">
</item>
<item
diff --git a/app/src/main/res/menu/feedlist.xml b/app/src/main/res/menu/feedlist.xml
index 939a51ab2..3614cfffa 100644
--- a/app/src/main/res/menu/feedlist.xml
+++ b/app/src/main/res/menu/feedlist.xml
@@ -52,19 +52,25 @@
android:title="@string/visit_website_label"
android:visible="true">
</item>
+
<item
- android:id="@+id/share_link_item"
- android:menuCategory="container"
- custom:showAsAction="collapseActionView"
- android:title="@string/share_website_url_label">
- </item>
- <item
- android:id="@+id/share_download_url_item"
+ android:id="@+id/share_item"
android:menuCategory="container"
- custom:showAsAction="collapseActionView"
- android:title="@string/share_feed_url_label">
+ custom:showAsAction="never"
+ android:title="@string/share_label_with_ellipses">
+ <menu>
+ <item
+ android:id="@+id/share_link_item"
+ android:title="@string/share_website_url_label">
+ </item>
+ <item
+ android:id="@+id/share_download_url_item"
+ android:title="@string/share_feed_url_label">
+ </item>
+ </menu>
</item>
+
<item
android:id="@+id/rename_item"
android:menuCategory="container"
diff --git a/app/src/main/res/menu/mediaplayer.xml b/app/src/main/res/menu/mediaplayer.xml
index a61616ce9..8afdba369 100644
--- a/app/src/main/res/menu/mediaplayer.xml
+++ b/app/src/main/res/menu/mediaplayer.xml
@@ -62,28 +62,6 @@
android:id="@+id/share_item"
android:menuCategory="container"
custom:showAsAction="never"
- android:title="@string/share_label">
- <menu>
- <item
- android:id="@+id/share_link_item"
- android:menuCategory="container"
- android:title="@string/share_link_label" />
- <item
- android:id="@+id/share_link_with_position_item"
- android:menuCategory="container"
- android:title="@string/share_link_with_position_label" />
- <item
- android:id="@+id/share_download_url_item"
- android:menuCategory="container"
- android:title="@string/share_item_url_label" />
- <item
- android:id="@+id/share_download_url_with_position_item"
- android:menuCategory="container"
- android:title="@string/share_item_url_with_position_label" />
- <item
- android:id="@+id/share_file"
- android:menuCategory="container"
- android:title="@string/share_file_label" />
- </menu>
+ android:title="@string/share_label_with_ellipses">
</item>
</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/subscriptions.xml b/app/src/main/res/menu/subscriptions.xml
index 1780592d5..8009061e5 100644
--- a/app/src/main/res/menu/subscriptions.xml
+++ b/app/src/main/res/menu/subscriptions.xml
@@ -9,6 +9,11 @@
custom:showAsAction="always"
android:icon="?attr/navigation_refresh"/>
+
+ <item
+ android:id="@+id/subscriptions_filter"
+ android:title="@string/filter"
+ custom:showAsAction="never" />
<item
android:id="@+id/subscription_num_columns"
android:title="@string/subscription_num_columns"
diff --git a/app/src/main/res/values-sw600dp/integers.xml b/app/src/main/res/values-sw600dp/integers.xml
new file mode 100644
index 000000000..fb43e5de6
--- /dev/null
+++ b/app/src/main/res/values-sw600dp/integers.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="subscriptions_default_num_of_columns">5</integer>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values-w1000dp/dimens.xml b/app/src/main/res/values-w1000dp/dimens.xml
new file mode 100644
index 000000000..59ddcb5c0
--- /dev/null
+++ b/app/src/main/res/values-w1000dp/dimens.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="additional_horizontal_spacing">56dp</dimen>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values-w300dp/dimens-fabspeeddial.xml b/app/src/main/res/values-w300dp/dimens-fabspeeddial.xml
deleted file mode 100644
index 1b90da786..000000000
--- a/app/src/main/res/values-w300dp/dimens-fabspeeddial.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:tools="http://schemas.android.com/tools">
- <!-- increase FAB speed dial label's max width if the screen is wide enough
- (300dp ~ 1.875 inch, devices with 3.5-inch screens have a width of ~ 1.9in
- so the setup is applicable for most phones)
- -->
- <dimen name="sd_label_max_width" tools:ignore="MissingDefaultResource">240dp</dimen>
-</resources>
diff --git a/app/src/main/res/values-w300dp/dimens.xml b/app/src/main/res/values-w300dp/dimens.xml
new file mode 100644
index 000000000..8adaf4c2d
--- /dev/null
+++ b/app/src/main/res/values-w300dp/dimens.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <dimen name="additional_horizontal_spacing">0dp</dimen>
+ <!--
+ Overwrites FAB library.
+ Increase FAB speed dial label's max width if the screen is wide enough
+ (300dp ~ 1.875 inch, devices with 3.5-inch screens have a width of ~ 1.9in
+ so the setup is applicable for most phones)
+ -->
+ <dimen name="sd_label_max_width" tools:ignore="MissingDefaultResource, UnusedResources">240dp</dimen>
+</resources>
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..f5f6aa0a8
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="additional_horizontal_spacing">0dp</dimen>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml
new file mode 100644
index 000000000..a7a7ead7b
--- /dev/null
+++ b/app/src/main/res/values/integers.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="subscriptions_default_num_of_columns">3</integer>
+ <integer name="nav_drawer_screen_size_percent">80</integer>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/xml/automotive_app_desc.xml b/app/src/main/res/xml/automotive_app_desc.xml
index 8f0a7c59c..0a6a3c9fb 100644
--- a/app/src/main/res/xml/automotive_app_desc.xml
+++ b/app/src/main/res/xml/automotive_app_desc.xml
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
-<automotiveApp xmlns:android="http://schemas.android.com/apk/res/android">
+<automotiveApp>
<uses name="media"/>
</automotiveApp> \ No newline at end of file
diff --git a/app/src/main/res/xml/feed_settings.xml b/app/src/main/res/xml/feed_settings.xml
index f85c9ef3c..9f8392f44 100644
--- a/app/src/main/res/xml/feed_settings.xml
+++ b/app/src/main/res/xml/feed_settings.xml
@@ -23,6 +23,7 @@
<Preference
android:key="feedAutoSkip"
+ android:icon="?attr/ic_settings_skip"
android:summary="@string/pref_feed_skip_sum"
android:title="@string/pref_feed_skip" />
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 2141c811c..b69f27473 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -50,7 +50,7 @@
android:title="@string/pref_faq"
android:icon="?attr/ic_questionmark" />
<Preference
- android:key="prefViewMailingList"
+ android:key="prefViewForum"
android:title="@string/visit_user_forum"
android:icon="?attr/ic_chat" />
<Preference
diff --git a/app/src/main/res/xml/preferences_autodownload.xml b/app/src/main/res/xml/preferences_autodownload.xml
index 333224aa0..9a2c859cd 100644
--- a/app/src/main/res/xml/preferences_autodownload.xml
+++ b/app/src/main/res/xml/preferences_autodownload.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:search="http://schemas.android.com/apk/com.bytehamster.lib.preferencesearch">
<de.danoeh.antennapod.preferences.MasterSwitchPreference
diff --git a/app/src/main/res/xml/preferences_import_export.xml b/app/src/main/res/xml/preferences_import_export.xml
index 12e27236d..383bff117 100644
--- a/app/src/main/res/xml/preferences_import_export.xml
+++ b/app/src/main/res/xml/preferences_import_export.xml
@@ -32,5 +32,9 @@
android:key="prefHtmlExport"
android:title="@string/html_export_label"
android:summary="@string/html_export_summary"/>
+ <Preference
+ android:key="prefFavoritesExport"
+ android:title="@string/favorites_export_label"
+ android:summary="@string/favorites_export_summary"/>
</PreferenceCategory>
</PreferenceScreen>
diff --git a/app/src/main/res/xml/preferences_playback.xml b/app/src/main/res/xml/preferences_playback.xml
index 32bf383d7..f8afa08ed 100644
--- a/app/src/main/res/xml/preferences_playback.xml
+++ b/app/src/main/res/xml/preferences_playback.xml
@@ -67,7 +67,7 @@
<Preference
android:key="prefPlaybackSpeedLauncher"
android:summary="@string/pref_playback_speed_sum"
- android:title="@string/pref_playback_speed_title"/>
+ android:title="@string/playback_speed"/>
<SwitchPreference
android:defaultValue="false"
android:key="prefPlaybackTimeRespectsSpeed"
diff --git a/app/src/main/res/xml/preferences_user_interface.xml b/app/src/main/res/xml/preferences_user_interface.xml
index a2fc970e0..adcbf5569 100644
--- a/app/src/main/res/xml/preferences_user_interface.xml
+++ b/app/src/main/res/xml/preferences_user_interface.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/appearance">
<ListPreference
@@ -15,20 +14,6 @@
android:key="prefHiddenDrawerItems"
android:summary="@string/pref_nav_drawer_items_sum"
android:title="@string/pref_nav_drawer_items_title"/>
- <ListPreference
- android:entryValues="@array/nav_drawer_feed_order_values"
- android:entries="@array/nav_drawer_feed_order_options"
- android:title="@string/pref_nav_drawer_feed_order_title"
- android:key="prefDrawerFeedOrder"
- android:summary="@string/pref_nav_drawer_feed_order_sum"
- android:defaultValue="0"/>
- <ListPreference
- android:entryValues="@array/nav_drawer_feed_counter_values"
- android:entries="@array/nav_drawer_feed_counter_options"
- android:title="@string/pref_nav_drawer_feed_counter_title"
- android:key="prefDrawerFeedIndicator"
- android:summary="@string/pref_nav_drawer_feed_counter_sum"
- android:defaultValue="1"/>
<SwitchPreference
android:title="@string/pref_episode_cover_title"
android:key="prefEpisodeCover"
@@ -36,6 +21,26 @@
android:defaultValue="true"
android:enabled="true"/>
</PreferenceCategory>
+ <PreferenceCategory android:title="@string/subscriptions_label">
+ <ListPreference
+ android:entryValues="@array/nav_drawer_feed_order_values"
+ android:entries="@array/nav_drawer_feed_order_options"
+ android:title="@string/pref_nav_drawer_feed_order_title"
+ android:key="prefDrawerFeedOrder"
+ android:summary="@string/pref_nav_drawer_feed_order_sum"
+ android:defaultValue="0"/>
+ <ListPreference
+ android:entryValues="@array/nav_drawer_feed_counter_values"
+ android:entries="@array/nav_drawer_feed_counter_options"
+ android:title="@string/pref_nav_drawer_feed_counter_title"
+ android:key="prefDrawerFeedIndicator"
+ android:summary="@string/pref_nav_drawer_feed_counter_sum"
+ android:defaultValue="1"/>
+ <Preference
+ android:title="@string/pref_filter_feed_title"
+ android:key="prefFeedFilter"
+ android:summary="@string/pref_filter_feed_sum" />
+ </PreferenceCategory>
<PreferenceCategory android:title="@string/external_elements">
<SwitchPreference
android:defaultValue="false"
diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml
index c4ed430be..a16b679e3 100644
--- a/app/src/main/res/xml/provider_paths.xml
+++ b/app/src/main/res/xml/provider_paths.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<paths xmlns:android="http://schemas.android.com/apk/res/android">
+<paths>
<external-path name="external_storage" path="."/>
<root-path name="external_files" path="/storage/" />
</paths>
diff --git a/app/src/main/res/xml/searchable.xml b/app/src/main/res/xml/searchable.xml
deleted file mode 100644
index 0861ecdae..000000000
--- a/app/src/main/res/xml/searchable.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<searchable xmlns:android="http://schemas.android.com/apk/res/android"
- android:hint="@string/search_label"
- android:label="@string/app_name"/> \ No newline at end of file
diff --git a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
index 810074bbe..b51fb40b0 100644
--- a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
+++ b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java
@@ -7,6 +7,7 @@ import androidx.appcompat.app.AlertDialog;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
+import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.fragment.preferences.PlaybackPreferencesFragment;
@@ -40,7 +41,7 @@ public class PreferenceControllerFlavorHelper {
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
dialog.setTitle(android.R.string.dialog_alert_title);
dialog.setMessage(R.string.pref_restart_required);
- dialog.setPositiveButton(android.R.string.ok, null);
+ dialog.setPositiveButton(android.R.string.ok, (dialog1, which) -> PodcastApp.forceRestart());
dialog.setCancelable(false);
dialog.show();
}
diff --git a/artwork/screenshots/generateScreenshots.sh b/artwork/screenshots/generateScreenshots.sh
index 7ffc4be65..5b1d7f7e8 100644
--- a/artwork/screenshots/generateScreenshots.sh
+++ b/artwork/screenshots/generateScreenshots.sh
@@ -6,6 +6,12 @@ function generateText() {
-annotate 0 "$1" /tmp/text.png
}
+function generateTabletText() {
+ echo "$1"
+ convert -size 1730x350 xc:none -gravity Center -pointsize 80 -fill white -font Lato-Regular \
+ -annotate 0 "$1" /tmp/text.png
+}
+
function simplePhone() {
generateText "$1"
convert templates/phone.png \
@@ -14,6 +20,15 @@ function simplePhone() {
$3
}
+function simpleTablet() {
+ generateTabletText "$1"
+ convert $2 -resize 1280 "/tmp/resized-image.png"
+ convert templates/tablet.png \
+ /tmp/resized-image.png -geometry +227+459 -composite \
+ /tmp/text.png -geometry +0+0 -composite \
+ $3
+}
+
function addLayer() {
convert $2 $1 -composite $2
}
@@ -27,6 +42,7 @@ function generateScreenshots() {
text3=`cat raw/$language/texts.txt | head -4 | tail -1`
text4=`cat raw/$language/texts.txt | head -5 | tail -1`
text5=`cat raw/$language/texts.txt | head -6 | tail -1`
+ text6=`cat raw/$language/texts.txt | head -7 | tail -1`
simplePhone "$text0" raw/$language/00.png output/$language/00.png
simplePhone "$text1" raw/$language/01.png output/$language/01.png
@@ -42,7 +58,8 @@ function generateScreenshots() {
simplePhone "$text4" raw/$language/04.png output/$language/04.png
simplePhone "$text5" raw/$language/05.png output/$language/05.png
addLayer templates/suggestions.png output/$language/05.png
- mogrify -resize 1120 "output/$language/*.png"
+ simpleTablet "$text6" raw/$language/tablet.png output/$language/tablet.png
+ mogrify -resize 1120 "output/$language/0*.png"
}
mkdir output 2>/dev/null
diff --git a/artwork/screenshots/raw/de-DE/tablet.png b/artwork/screenshots/raw/de-DE/tablet.png
new file mode 100644
index 000000000..592238234
--- /dev/null
+++ b/artwork/screenshots/raw/de-DE/tablet.png
Binary files differ
diff --git a/artwork/screenshots/raw/de-DE/texts.txt b/artwork/screenshots/raw/de-DE/texts.txt
index a0ea2c731..7c85b8df2 100644
--- a/artwork/screenshots/raw/de-DE/texts.txt
+++ b/artwork/screenshots/raw/de-DE/texts.txt
@@ -4,3 +4,4 @@ Spare Zeit mit\nautomatischen Downloads
Wähle dein\nLieblings-Theme
Passe AntennaPod\nan deine Wünsche an
Entdecke tausende\nneuer Podcasts
+Genieße deine Podcasts. Überall. Jederzeit.
diff --git a/artwork/screenshots/raw/en-US/tablet.png b/artwork/screenshots/raw/en-US/tablet.png
new file mode 100644
index 000000000..6593bd625
--- /dev/null
+++ b/artwork/screenshots/raw/en-US/tablet.png
Binary files differ
diff --git a/artwork/screenshots/raw/en-US/texts.txt b/artwork/screenshots/raw/en-US/texts.txt
index f1ef1c960..e946bb27c 100644
--- a/artwork/screenshots/raw/en-US/texts.txt
+++ b/artwork/screenshots/raw/en-US/texts.txt
@@ -4,3 +4,4 @@ Save time with\nautomatic downloads
Select the theme\nthat fits best to you
Adapt AntennaPod\nto your needs
Discover thousands\nof great podcasts
+Enjoy your podcasts. Anywhere. Anytime.
diff --git a/artwork/screenshots/raw/fr-FR/tablet.png b/artwork/screenshots/raw/fr-FR/tablet.png
new file mode 100644
index 000000000..a86766ba3
--- /dev/null
+++ b/artwork/screenshots/raw/fr-FR/tablet.png
Binary files differ
diff --git a/artwork/screenshots/raw/nl-NL/tablet.png b/artwork/screenshots/raw/nl-NL/tablet.png
new file mode 100644
index 000000000..54463f161
--- /dev/null
+++ b/artwork/screenshots/raw/nl-NL/tablet.png
Binary files differ
diff --git a/artwork/screenshots/raw/nl-NL/texts.txt b/artwork/screenshots/raw/nl-NL/texts.txt
index ebd140cf4..9f3651ca6 100644
--- a/artwork/screenshots/raw/nl-NL/texts.txt
+++ b/artwork/screenshots/raw/nl-NL/texts.txt
@@ -4,3 +4,4 @@ Bespaar tijd met\nautomatische downloads
Selecteer het thema\ndat het best bij je past
Pas AntennaPod aan\naan jouw wensen
Ontdek honderden\ninteressante podcasts
+Enjoy your podcasts. Anywhere. Anytime.
diff --git a/artwork/screenshots/templates/tablet.png b/artwork/screenshots/templates/tablet.png
new file mode 100644
index 000000000..0a757ab1d
--- /dev/null
+++ b/artwork/screenshots/templates/tablet.png
Binary files differ
diff --git a/build.gradle b/build.gradle
index 9774fc3c8..0a5695377 100644
--- a/build.gradle
+++ b/build.gradle
@@ -65,7 +65,7 @@ project.ext {
rxAndroidVersion = "2.1.1"
rxJavaVersion = "2.2.2"
iconifyVersion = "2.2.2"
- audioPlayerVersion = "v1.0.17"
+ audioPlayerVersion = "v2.0.0"
// Google Play build
wearableSupportVersion = "2.6.0"
diff --git a/core/src/main/assets/html-export-favorites-item-template.html b/core/src/main/assets/html-export-favorites-item-template.html
new file mode 100644
index 000000000..83f06a458
--- /dev/null
+++ b/core/src/main/assets/html-export-favorites-item-template.html
@@ -0,0 +1,4 @@
+<li><span>
+ {FAV_TITLE}<br>
+ <a href="{FAV_WEBSITE}">Website</a> • <a href="{FAV_MEDIA}">Media</a>
+</span></li>
diff --git a/core/src/main/assets/html-export-feed-template.html b/core/src/main/assets/html-export-feed-template.html
new file mode 100644
index 000000000..0646d5953
--- /dev/null
+++ b/core/src/main/assets/html-export-feed-template.html
@@ -0,0 +1,7 @@
+<img src="{FEED_IMG}" />
+<p>
+ {FEED_TITLE}
+ <span>
+ <a href="{FEED_LINK}">Website</a> • <a href="{FEED_WEBSITE}">Feed</a>
+ </span>
+</p> \ No newline at end of file
diff --git a/core/src/main/assets/html-export-template.html b/core/src/main/assets/html-export-template.html
index ddab27a43..19d63f6ca 100644
--- a/core/src/main/assets/html-export-template.html
+++ b/core/src/main/assets/html-export-template.html
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8' standalone='no' ?>
<html>
<head>
- <title>AntennaPod Subscriptions</title>
+ <title>AntennaPod {TITLE}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
@@ -72,11 +72,18 @@
margin-top: 10px;
clear:left;
}
+ ul > li > span {
+ width: 100%;
+ border-top: 1px solid #eee8e8;
+ padding: 5px;
+ box-shadow: none;
+ text-align: left;
+ }
</style>
</head>
<body>
<img src="https://antennapod.org/assets/img/antennapod-logo.png" />
- <h1>AntennaPod Subscriptions</h1>
+ <h1>AntennaPod {TITLE}</h1>
<ul>
{FEEDS}
</ul>
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java
index 24a71ec96..efd53ab9d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.core.event;
+import androidx.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.List;
@@ -19,6 +21,7 @@ public class DownloadEvent {
return new DownloadEvent(update);
}
+ @NonNull
@Override
public String toString() {
return "DownloadEvent{" +
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadLogEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadLogEvent.java
index 7428c5b00..5ab5decf9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadLogEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadLogEvent.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.core.event;
+import androidx.annotation.NonNull;
+
public class DownloadLogEvent {
private DownloadLogEvent() {
@@ -9,6 +11,7 @@ public class DownloadLogEvent {
return new DownloadLogEvent();
}
+ @NonNull
@Override
public String toString() {
return "DownloadLogEvent";
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
index f549940b7..10992408d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
@@ -46,6 +46,7 @@ public class DownloaderUpdate {
this.mediaIds = mediaIds1.toArray();
}
+ @NonNull
@Override
public String toString() {
return "DownloaderUpdate{" +
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java
index 578007561..d3be8fac0 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.core.event;
+import androidx.annotation.NonNull;
+
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@@ -27,6 +29,7 @@ public class FavoritesEvent {
return new FavoritesEvent(Action.REMOVED, item);
}
+ @NonNull
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
index 4b14a72d2..02559b2f5 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
@@ -21,7 +21,7 @@ public class FeedItemEvent {
private final Action action;
@NonNull public final List<FeedItem> items;
- private FeedItemEvent(Action action, List<FeedItem> items) {
+ private FeedItemEvent(@NonNull Action action, @NonNull List<FeedItem> items) {
this.action = action;
this.items = items;
}
@@ -42,6 +42,7 @@ public class FeedItemEvent {
return updated(Arrays.asList(items));
}
+ @NonNull
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java b/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java
new file mode 100644
index 000000000..60c38a391
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java
@@ -0,0 +1,132 @@
+package de.danoeh.antennapod.core.export.favorites;
+
+import android.content.Context;
+import android.util.Log;
+
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import de.danoeh.antennapod.core.export.ExportWriter;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.storage.DBReader;
+
+/** Writes saved favorites to file. */
+public class FavoritesWriter implements ExportWriter {
+ private static final String TAG = "FavoritesWriter";
+
+ private static final int PAGE_LIMIT = 100;
+
+ private static final String FAVORITE_TEMPLATE = "html-export-favorites-item-template.html";
+ private static final String FEED_TEMPLATE = "html-export-feed-template.html";
+ private static final String UTF_8 = "UTF-8";
+
+ @Override
+ public void writeDocument(List<Feed> feeds, Writer writer, Context context)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ Log.d(TAG, "Starting to write document");
+
+ InputStream templateStream = context.getAssets().open("html-export-template.html");
+ String template = IOUtils.toString(templateStream, UTF_8);
+ template = template.replaceAll("\\{TITLE\\}", "Favorites");
+ String[] templateParts = template.split("\\{FEEDS\\}");
+
+ InputStream favTemplateStream = context.getAssets().open(FAVORITE_TEMPLATE);
+ String favTemplate = IOUtils.toString(favTemplateStream, UTF_8);
+
+ InputStream feedTemplateStream = context.getAssets().open(FEED_TEMPLATE);
+ String feedTemplate = IOUtils.toString(feedTemplateStream, UTF_8);
+
+ Map<Long, List<FeedItem>> favoriteByFeed = getFeedMap(getFavorites());
+
+ writer.append(templateParts[0]);
+
+ for (Long feedId : favoriteByFeed.keySet()) {
+ List<FeedItem> favorites = favoriteByFeed.get(feedId);
+ writer.append("<li><div>\n");
+ writeFeed(writer, favorites.get(0).getFeed(), feedTemplate);
+
+ writer.append("<ul>\n");
+ for (FeedItem item : favorites) {
+ writeFavoriteItem(writer, item, favTemplate);
+ }
+ writer.append("</ul></div></li>\n");
+ }
+
+ writer.append(templateParts[1]);
+
+ Log.d(TAG, "Finished writing document");
+ }
+
+ private List<FeedItem> getFavorites() {
+ int page = 0;
+
+ List<FeedItem> favoritesList = new ArrayList<>();
+ List<FeedItem> favoritesPage;
+ do {
+ favoritesPage = DBReader.getFavoriteItemsList(page * PAGE_LIMIT, PAGE_LIMIT);
+ favoritesList.addAll(favoritesPage);
+ ++page;
+ } while (!favoritesPage.isEmpty() && favoritesPage.size() == PAGE_LIMIT);
+
+ // sort in descending order
+ Collections.sort(favoritesList, (lhs, rhs) -> rhs.getPubDate().compareTo(lhs.getPubDate()));
+
+ return favoritesList;
+ }
+
+ /**
+ * Group favorite episodes by feed, sorting them by publishing date in descending order.
+ *
+ * @param favoritesList {@code List} of all favorite episodes.
+ * @return A {@code Map} favorite episodes, keyed by feed ID.
+ */
+ private Map<Long, List<FeedItem>> getFeedMap(List<FeedItem> favoritesList) {
+ Map<Long, List<FeedItem>> feedMap = new TreeMap<>();
+
+ for (FeedItem item : favoritesList) {
+ List<FeedItem> feedEpisodes = feedMap.get(item.getFeedId());
+
+ if (feedEpisodes == null) {
+ feedEpisodes = new ArrayList<>();
+ feedMap.put(item.getFeedId(), feedEpisodes);
+ }
+
+ feedEpisodes.add(item);
+ }
+
+ return feedMap;
+ }
+
+ private void writeFeed(Writer writer, Feed feed, String feedTemplate) throws IOException {
+ String feedInfo = feedTemplate
+ .replace("{FEED_IMG}", feed.getImageUrl())
+ .replace("{FEED_TITLE}", feed.getTitle())
+ .replace("{FEED_LINK}", feed.getLink())
+ .replace("{FEED_WEBSITE}", feed.getDownload_url());
+
+ writer.append(feedInfo);
+ }
+
+ private void writeFavoriteItem(Writer writer, FeedItem item, String favoriteTemplate) throws IOException {
+ String favItem = favoriteTemplate
+ .replace("{FAV_TITLE}", item.getTitle().trim())
+ .replace("{FAV_WEBSITE}", item.getLink())
+ .replace("{FAV_MEDIA}", item.getMedia().getDownload_url());
+
+ writer.append(favItem);
+ }
+
+ @Override
+ public String fileExtension() {
+ return "html";
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java b/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java
index 93b66daed..3f34343ee 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java
@@ -25,6 +25,7 @@ public class HtmlWriter implements ExportWriter {
InputStream templateStream = context.getAssets().open("html-export-template.html");
String template = IOUtils.toString(templateStream, "UTF-8");
+ template = template.replaceAll("\\{TITLE\\}", "Subscriptions");
String[] templateParts = template.split("\\{FEEDS\\}");
writer.append(templateParts[0]);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java
index 2610d253f..3edecd35c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java
@@ -50,7 +50,7 @@ public abstract class FeedComponent {
@Override
public boolean equals(Object o) {
if (this == o) return true;
- if (o == null || !(o instanceof FeedComponent)) return false;
+ if (!(o instanceof FeedComponent)) return false;
FeedComponent that = (FeedComponent) o;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedEvent.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedEvent.java
index 15cdf92dc..044554451 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedEvent.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.core.feed;
+import androidx.annotation.NonNull;
+
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@@ -18,6 +20,7 @@ public class FeedEvent {
this.feedId = feedId;
}
+ @NonNull
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
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 892592a4b..131cbe563 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
@@ -1,12 +1,15 @@
package de.danoeh.antennapod.core.feed;
import android.database.Cursor;
+
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
+import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
@@ -24,7 +27,7 @@ import de.danoeh.antennapod.core.util.ShownotesProvider;
*
* @author daniel
*/
-public class FeedItem extends FeedComponent implements ShownotesProvider, ImageResource {
+public class FeedItem extends FeedComponent implements ShownotesProvider, ImageResource, Serializable {
/** tag that indicates this item is in the queue */
public static final String TAG_QUEUE = "Queue";
@@ -481,6 +484,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, ImageR
*/
public void removeTag(String tag) { tags.remove(tag); }
+ @NonNull
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
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 719383d23..d34e23506 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
@@ -1,8 +1,10 @@
package de.danoeh.antennapod.core.feed;
import android.text.TextUtils;
+import android.util.Log;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -11,17 +13,21 @@ import de.danoeh.antennapod.core.util.LongList;
import static de.danoeh.antennapod.core.feed.FeedItem.TAG_FAVORITE;
public class FeedItemFilter {
+
private final String[] mProperties;
private boolean showPlayed = false;
private boolean showUnplayed = false;
private boolean showPaused = false;
+ private boolean showNotPaused = false;
private boolean showQueued = false;
private boolean showNotQueued = false;
private boolean showDownloaded = false;
private boolean showNotDownloaded = false;
private boolean showHasMedia = false;
+ private boolean showNoMedia = false;
private boolean showIsFavorite = false;
+ private boolean showNotFavorite = false;
public FeedItemFilter(String properties) {
this(TextUtils.split(properties, ","));
@@ -29,15 +35,18 @@ public class FeedItemFilter {
public FeedItemFilter(String[] properties) {
this.mProperties = properties;
- for(String property : properties) {
+ for (String property : properties) {
// see R.arrays.feed_filter_values
- switch(property) {
+ switch (property) {
case "unplayed":
showUnplayed = true;
break;
case "paused":
showPaused = true;
break;
+ case "not_paused":
+ showNotPaused = true;
+ break;
case "played":
showPlayed = true;
break;
@@ -56,9 +65,17 @@ public class FeedItemFilter {
case "has_media":
showHasMedia = true;
break;
+ case "no_media":
+ showNoMedia = true;
+ break;
case "is_favorite":
showIsFavorite = true;
break;
+ case "not_favorite":
+ showNotFavorite = true;
+ break;
+ default:
+ break;
}
}
}
@@ -77,12 +94,15 @@ public class FeedItemFilter {
if (showQueued && showNotQueued) return result;
if (showDownloaded && showNotDownloaded) return result;
- final LongList queuedIds = DBReader.getQueueIDList();
- for(FeedItem item : items) {
+ final LongList queuedIds = DBReader.getQueueIDList();
+ for (FeedItem item : items) {
// 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;
+ if (showNotPaused && item.getState() == FeedItem.State.IN_PROGRESS) continue;
boolean queued = queuedIds.contains(item.getId());
if (showQueued && !queued) continue;
@@ -93,8 +113,10 @@ public class FeedItemFilter {
if (showNotDownloaded && downloaded) continue;
if (showHasMedia && !item.hasMedia()) continue;
+ if (showNoMedia && item.hasMedia()) continue;
if (showIsFavorite && !item.isTagged(TAG_FAVORITE)) continue;
+ if (showNotFavorite && item.isTagged(TAG_FAVORITE)) continue;
// If the item reaches here, it meets all criteria
result.add(item);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilterGroup.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilterGroup.java
new file mode 100644
index 000000000..fcbe2e4ab
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilterGroup.java
@@ -0,0 +1,36 @@
+package de.danoeh.antennapod.core.feed;
+
+import de.danoeh.antennapod.core.R;
+
+public enum FeedItemFilterGroup {
+ PLAYED(new ItemProperties(R.string.hide_played_episodes_label, "played"),
+ new ItemProperties(R.string.not_played, "unplayed")),
+ PAUSED(new ItemProperties(R.string.hide_paused_episodes_label, "paused"),
+ new ItemProperties(R.string.not_paused, "not_paused")),
+ FAVORITE(new ItemProperties(R.string.hide_is_favorite_label, "is_favorite"),
+ new ItemProperties(R.string.not_favorite, "not_favorite")),
+ MEDIA(new ItemProperties(R.string.has_media, "has_media"),
+ new ItemProperties(R.string.no_media, "no_media")),
+ QUEUED(new ItemProperties(R.string.queued_label, "queued"),
+ new ItemProperties(R.string.not_queued_label, "not_queued")),
+ DOWNLOADED(new ItemProperties(R.string.hide_downloaded_episodes_label, "downloaded"),
+ new ItemProperties(R.string.hide_not_downloaded_episodes_label, "not_downloaded"));
+
+ public final ItemProperties[] values;
+
+ FeedItemFilterGroup(ItemProperties... values) {
+ this.values = values;
+ }
+
+ public static class ItemProperties {
+
+ public final int displayName;
+ public final String filterId;
+
+ public ItemProperties(int displayName, String filterId) {
+ this.displayName = displayName;
+ this.filterId = filterId;
+ }
+
+ }
+}
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 083e8c500..92e45376a 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
@@ -482,7 +482,7 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public void onPlaybackStart() {
- startPosition = (position > 0) ? position : 0;
+ startPosition = Math.max(position, 0);
playedDurationWhenStarted = played_duration;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java
index 36da11eca..35a9d987b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java
@@ -28,8 +28,9 @@ import org.apache.commons.io.IOUtils;
public final class ChapterImageModelLoader implements ModelLoader<EmbeddedChapterImage, ByteBuffer> {
public static class Factory implements ModelLoaderFactory<EmbeddedChapterImage, ByteBuffer> {
+ @NonNull
@Override
- public ModelLoader<EmbeddedChapterImage, ByteBuffer> build(MultiModelLoaderFactory unused) {
+ public ModelLoader<EmbeddedChapterImage, ByteBuffer> build(@NonNull MultiModelLoaderFactory unused) {
return new ChapterImageModelLoader();
}
@@ -41,12 +42,15 @@ public final class ChapterImageModelLoader implements ModelLoader<EmbeddedChapte
@Nullable
@Override
- public LoadData<ByteBuffer> buildLoadData(EmbeddedChapterImage model, int width, int height, Options options) {
+ public LoadData<ByteBuffer> buildLoadData(@NonNull EmbeddedChapterImage model,
+ int width,
+ int height,
+ @NonNull Options options) {
return new LoadData<>(new ObjectKey(model), new EmbeddedImageFetcher(model));
}
@Override
- public boolean handles(EmbeddedChapterImage model) {
+ public boolean handles(@NonNull EmbeddedChapterImage model) {
return true;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
index d0301db2f..1f8ae5ad9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
@@ -21,7 +21,10 @@ public class FastBlurTransformation extends BitmapTransformation {
}
@Override
- protected Bitmap transform(BitmapPool pool, Bitmap source, int outWidth, int outHeight) {
+ protected Bitmap transform(@NonNull BitmapPool pool,
+ @NonNull Bitmap source,
+ int outWidth,
+ int outHeight) {
int targetWidth = outWidth / 3;
int targetHeight = (int) (1.0 * outHeight * targetWidth / outWidth);
Bitmap resized = ThumbnailUtils.extractThumbnail(source, targetWidth, targetHeight);
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 876251563..3488d125e 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
@@ -19,10 +19,14 @@ import org.json.JSONException;
import java.io.File;
import java.io.IOException;
import java.net.Proxy;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -64,6 +68,7 @@ public class UserPreferences {
private static final String PREF_SHOW_AUTO_DOWNLOAD_REPORT = "prefShowAutoDownloadReport";
public static final String PREF_BACK_BUTTON_BEHAVIOR = "prefBackButtonBehavior";
private static final String PREF_BACK_BUTTON_GO_TO_PAGE = "prefBackButtonGoToPage";
+ public static final String PREF_FILTER_FEED = "prefFeedFilter";
public static final String PREF_QUEUE_KEEP_SORTED = "prefQueueKeepSorted";
public static final String PREF_QUEUE_KEEP_SORTED_ORDER = "prefQueueKeepSortedOrder";
@@ -146,6 +151,8 @@ public class UserPreferences {
public static final int FEED_COUNTER_SHOW_UNPLAYED = 2;
public static final int FEED_COUNTER_SHOW_NONE = 3;
public static final int FEED_COUNTER_SHOW_DOWNLOADED = 4;
+ public static final int FEED_FILTER_NONE = 0;
+ public static final int FEED_FILTER_COUNTER_ZERO = 1;
private static Context context;
private static SharedPreferences prefs;
@@ -414,7 +421,7 @@ public class UserPreferences {
return prefs.getBoolean(PREF_PLAYBACK_SKIP_SILENCE, false);
}
- public static float[] getPlaybackSpeedArray() {
+ public static List<Float> getPlaybackSpeedArray() {
return readPlaybackSpeedArray(prefs.getString(PREF_PLAYBACK_SPEED_ARRAY, null));
}
@@ -628,8 +635,7 @@ public class UserPreferences {
}
public static boolean isQueueLocked() {
- return prefs.getBoolean(PREF_QUEUE_LOCKED, false)
- || isQueueKeepSorted();
+ return prefs.getBoolean(PREF_QUEUE_LOCKED, false);
}
public static void setFastForwardSecs(int secs) {
@@ -662,10 +668,13 @@ public class UserPreferences {
.apply();
}
- public static void setPlaybackSpeedArray(String[] speeds) {
+ public static void setPlaybackSpeedArray(List<Float> speeds) {
+ DecimalFormatSymbols format = new DecimalFormatSymbols(Locale.US);
+ format.setDecimalSeparator('.');
+ DecimalFormat speedFormat = new DecimalFormat("0.00", format);
JSONArray jsonArray = new JSONArray();
- for (String speed : speeds) {
- jsonArray.put(speed);
+ for (float speed : speeds) {
+ jsonArray.put(speedFormat.format(speed));
}
prefs.edit()
.putString(PREF_PLAYBACK_SPEED_ARRAY, jsonArray.toString())
@@ -775,13 +784,13 @@ public class UserPreferences {
}
}
- private static float[] readPlaybackSpeedArray(String valueFromPrefs) {
+ private static List<Float> readPlaybackSpeedArray(String valueFromPrefs) {
if (valueFromPrefs != null) {
try {
JSONArray jsonArray = new JSONArray(valueFromPrefs);
- float[] selectedSpeeds = new float[jsonArray.length()];
+ List<Float> selectedSpeeds = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++) {
- selectedSpeeds[i] = (float) jsonArray.getDouble(i);
+ selectedSpeeds.add((float) jsonArray.getDouble(i));
}
return selectedSpeeds;
} catch (JSONException e) {
@@ -790,7 +799,7 @@ public class UserPreferences {
}
}
// If this preference hasn't been set yet, return the default options
- return new float[] { 0.75f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f };
+ return Arrays.asList(0.75f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f);
}
public static String getMediaPlayer() {
@@ -826,8 +835,8 @@ public class UserPreferences {
public static VideoBackgroundBehavior getVideoBackgroundBehavior() {
switch (prefs.getString(PREF_VIDEO_BEHAVIOR, "pip")) {
case "stop": return VideoBackgroundBehavior.STOP;
- case "pip": return VideoBackgroundBehavior.PICTURE_IN_PICTURE;
case "continue": return VideoBackgroundBehavior.CONTINUE_PLAYING;
+ case "pip": //Deliberate fall-through
default: return VideoBackgroundBehavior.PICTURE_IN_PICTURE;
}
}
@@ -977,11 +986,11 @@ public class UserPreferences {
public static BackButtonBehavior getBackButtonBehavior() {
switch (prefs.getString(PREF_BACK_BUTTON_BEHAVIOR, "default")) {
- case "default": return BackButtonBehavior.DEFAULT;
case "drawer": return BackButtonBehavior.OPEN_DRAWER;
case "doubletap": return BackButtonBehavior.DOUBLE_TAP;
case "prompt": return BackButtonBehavior.SHOW_PROMPT;
case "page": return BackButtonBehavior.GO_TO_PAGE;
+ case "default": // Deliberate fall-through
default: return BackButtonBehavior.DEFAULT;
}
}
@@ -1052,4 +1061,16 @@ public class UserPreferences {
.putString(PREF_QUEUE_KEEP_SORTED_ORDER, sortOrder.name())
.apply();
}
+
+ public static int getFeedFilter() {
+ String value = prefs.getString(PREF_FILTER_FEED, "" + FEED_FILTER_NONE);
+ return Integer.parseInt(value);
+ }
+
+ public static void setFeedFilter(String value) {
+ prefs.edit()
+ .putString(PREF_FILTER_FEED, value)
+ .commit();
+ }
+
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
index 4562f1393..7585e9d33 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
@@ -103,12 +103,8 @@ public class PlayerWidgetJobService extends SafeJobIntentService {
AppWidgetManager manager = AppWidgetManager.getInstance(this);
int[] widgetIds = manager.getAppWidgetIds(playerWidget);
RemoteViews views = new RemoteViews(getPackageName(), R.layout.player_widget);
- PendingIntent startMediaplayer = PendingIntent.getActivity(this, 0,
- PlaybackService.getPlayerActivityIntent(this), 0);
-
- final PendingIntent startAppPending = PendingIntent.getActivity(this, 0,
- PlaybackService.getPlayerActivityIntent(this),
- PendingIntent.FLAG_UPDATE_CURRENT);
+ final PendingIntent startMediaPlayer = PendingIntent.getActivity(this, R.id.pending_intent_player_activity,
+ PlaybackService.getPlayerActivityIntent(this), PendingIntent.FLAG_UPDATE_CURRENT);
boolean nothingPlaying = false;
Playable media;
@@ -122,10 +118,10 @@ public class PlayerWidgetJobService extends SafeJobIntentService {
}
if (media != null) {
- views.setOnClickPendingIntent(R.id.layout_left, startMediaplayer);
+ views.setOnClickPendingIntent(R.id.layout_left, startMediaPlayer);
try {
- Bitmap icon = null;
+ Bitmap icon;
int iconSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
icon = Glide.with(PlayerWidgetJobService.this)
.asBitmap()
@@ -170,8 +166,8 @@ public class PlayerWidgetJobService extends SafeJobIntentService {
if (nothingPlaying) {
// start the app if they click anything
- views.setOnClickPendingIntent(R.id.layout_left, startAppPending);
- views.setOnClickPendingIntent(R.id.butPlay, startAppPending);
+ views.setOnClickPendingIntent(R.id.layout_left, startMediaPlayer);
+ views.setOnClickPendingIntent(R.id.butPlay, startMediaPlayer);
views.setViewVisibility(R.id.txtvProgress, View.GONE);
views.setViewVisibility(R.id.txtvTitle, View.GONE);
views.setViewVisibility(R.id.txtNoPlaying, View.VISIBLE);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/ProviderInstallerInterceptor.java b/core/src/main/java/de/danoeh/antennapod/core/service/ProviderInstallerInterceptor.java
new file mode 100644
index 000000000..4fa1fc3d7
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/ProviderInstallerInterceptor.java
@@ -0,0 +1,18 @@
+package de.danoeh.antennapod.core.service;
+
+import androidx.annotation.NonNull;
+import okhttp3.Interceptor;
+import okhttp3.Response;
+
+import java.io.IOException;
+
+public class ProviderInstallerInterceptor implements Interceptor {
+ public static Runnable installer = () -> { };
+
+ @Override
+ @NonNull
+ public Response intercept(Chain chain) throws IOException {
+ installer.run();
+ return chain.proceed(chain.request());
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/UserAgentInterceptor.java b/core/src/main/java/de/danoeh/antennapod/core/service/UserAgentInterceptor.java
index 5fcf8317d..3676347f7 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/UserAgentInterceptor.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/UserAgentInterceptor.java
@@ -7,10 +7,6 @@ import okhttp3.Response;
import java.io.IOException;
public class UserAgentInterceptor implements Interceptor {
-
- public UserAgentInterceptor() {
- }
-
@Override
public Response intercept(Chain chain) throws IOException {
return chain.proceed(chain.request().newBuilder()
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 e0c23bdac..9d0b3c5ad 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
@@ -32,6 +32,7 @@ import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.ProviderInstallerInterceptor;
import de.danoeh.antennapod.core.service.UserAgentInterceptor;
import de.danoeh.antennapod.core.storage.DBWriter;
import okhttp3.Cache;
@@ -116,6 +117,7 @@ public class AntennapodHttpClient {
}
return response;
});
+ builder.interceptors().add(new ProviderInstallerInterceptor());
builder.interceptors().add(new BasicAuthorizationInterceptor());
builder.networkInterceptors().add(new UserAgentInterceptor());
@@ -154,8 +156,8 @@ public class AntennapodHttpClient {
// workaround for Android 4.x for certain web sites.
// see: https://github.com/square/okhttp/issues/4053#issuecomment-402579554
- List<CipherSuite> cipherSuites = new ArrayList<>();
- cipherSuites.addAll(ConnectionSpec.MODERN_TLS.cipherSuites());
+ List<CipherSuite> cipherSuites = new ArrayList<>(
+ ConnectionSpec.MODERN_TLS.cipherSuites());
cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
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 78c4d3f48..3f503c6b4 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
@@ -115,7 +115,7 @@ public class DownloadRequest implements Parcelable {
@Override
public boolean equals(Object o) {
if (this == o) return true;
- if (o == null || !(o instanceof DownloadRequest)) return false;
+ if (!(o instanceof DownloadRequest)) return false;
DownloadRequest that = (DownloadRequest) o;
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 28523ef0a..e44aa716a 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
@@ -17,6 +17,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.sync.SyncService;
import org.apache.commons.io.FileUtils;
import org.greenrobot.eventbus.EventBus;
@@ -87,8 +88,6 @@ public class DownloadService extends Service {
public static final String EXTRA_CLEANUP_MEDIA = "cleanupMedia";
- public static final int NOTIFICATION_ID = 2;
-
/**
* Contains all completed downloads that have not been included in the report yet.
*/
@@ -165,7 +164,7 @@ public class DownloadService extends Service {
if (intent != null && intent.getParcelableArrayListExtra(EXTRA_REQUESTS) != null) {
Notification notification = notificationManager.updateNotifications(
requester.getNumberOfDownloads(), downloads);
- startForeground(NOTIFICATION_ID, notification);
+ startForeground(R.id.notification_downloading, notification);
syncExecutor.execute(() -> onDownloadQueued(intent));
} else if (numberOfDownloads.get() == 0) {
stopSelf();
@@ -191,7 +190,7 @@ public class DownloadService extends Service {
Notification notification = notificationManager.updateNotifications(
requester.getNumberOfDownloads(), downloads);
- startForeground(NOTIFICATION_ID, notification);
+ startForeground(R.id.notification_downloading, notification);
}
@Override
@@ -229,7 +228,7 @@ public class DownloadService extends Service {
stopForeground(true);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- nm.cancel(NOTIFICATION_ID);
+ nm.cancel(R.id.notification_downloading);
// if this was the initial gpodder sync, i.e. we just synced the feeds successfully,
// it is now time to sync the episode actions
@@ -480,12 +479,9 @@ public class DownloadService extends Service {
}
handler.post(() -> {
downloads.add(downloader);
+ downloadExecutor.submit(downloader);
postDownloaders();
});
- // Needs to be done after postDownloaders() because otherwise,
- // it might take long before the progress bar circle starts spinning
- ClientConfig.installSslProvider(this);
- handler.post(() -> downloadExecutor.submit(downloader));
}
handler.post(this::queryDownloads);
}
@@ -566,7 +562,7 @@ public class DownloadService extends Service {
setupNotificationUpdater();
Notification notification = notificationManager.updateNotifications(
requester.getNumberOfDownloads(), downloads);
- startForeground(NOTIFICATION_ID, notification);
+ startForeground(R.id.notification_downloading, notification);
}
}
@@ -642,7 +638,7 @@ public class DownloadService extends Service {
Notification n = notificationManager.updateNotifications(requester.getNumberOfDownloads(), downloads);
if (n != null) {
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- nm.notify(NOTIFICATION_ID, n);
+ nm.notify(R.id.notification_downloading, n);
}
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java
index f487193f3..64666d25d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java
@@ -17,8 +17,6 @@ import java.util.List;
public class DownloadServiceNotification {
private static final String TAG = "DownloadSvcNotification";
- private static final int REPORT_ID = 3;
- private static final int AUTO_REPORT_ID = 4;
private final Context context;
private NotificationCompat.Builder notificationCompatBuilder;
@@ -147,14 +145,14 @@ public class DownloadServiceNotification {
titleId = R.string.auto_download_report_title;
iconId = R.drawable.ic_notification_auto_download_complete;
intent = ClientConfig.downloadServiceCallbacks.getAutoDownloadReportNotificationContentIntent(context);
- id = AUTO_REPORT_ID;
+ id = R.id.notification_auto_download_report;
content = createAutoDownloadNotificationContent(reportQueue);
} else {
channelId = NotificationUtils.CHANNEL_ID_ERROR;
titleId = R.string.download_report_title;
iconId = R.drawable.ic_notification_sync_error;
intent = ClientConfig.downloadServiceCallbacks.getReportNotificationContentIntent(context);
- id = REPORT_ID;
+ id = R.id.notification_download_report;
content = String.format(context.getString(R.string.download_report_content), successfulDownloads, failedDownloads);
}
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 54b8d321a..61608992b 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
@@ -65,11 +65,12 @@ public class HttpDownloader extends Downloader {
final URI uri = URIUtil.getURIFromRequestUrl(request.getSource());
Request.Builder httpReq = new Request.Builder().url(uri.toURL());
httpReq.tag(request);
+ httpReq.cacheControl(new CacheControl.Builder().noStore().build());
+
if (request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
// set header explicitly so that okhttp doesn't do transparent gzip
Log.d(TAG, "addHeader(\"Accept-Encoding\", \"identity\")");
httpReq.addHeader("Accept-Encoding", "identity");
- httpReq.cacheControl(new CacheControl.Builder().noStore().build());
}
if (!TextUtils.isEmpty(request.getLastModified())) {
@@ -189,7 +190,7 @@ public class HttpDownloader extends Downloader {
}
byte[] buffer = new byte[BUFFER_SIZE];
- int count = 0;
+ int count;
request.setStatusMsg(R.string.download_running);
Log.d(TAG, "Getting size of download");
request.setSize(responseBody.contentLength() + request.getSoFar());
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java
index 05e602db8..c50162788 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java
@@ -49,10 +49,7 @@ public class FeedParserTask implements Callable<FeedHandlerResult> {
try {
result = feedHandler.parseFeed(feed);
Log.d(TAG, feed.getTitle() + " parsed");
- if (!checkFeedData(feed)) {
- throw new InvalidFeedException();
- }
-
+ checkFeedData(feed);
} catch (SAXException | IOException | ParserConfigurationException e) {
successful = false;
e.printStackTrace();
@@ -95,23 +92,17 @@ public class FeedParserTask implements Callable<FeedHandlerResult> {
/**
* Checks if the feed was parsed correctly.
*/
- private boolean checkFeedData(Feed feed) {
+ private void checkFeedData(Feed feed) throws InvalidFeedException {
if (feed.getTitle() == null) {
- Log.e(TAG, "Feed has no title.");
- return false;
- }
- if (!hasValidFeedItems(feed)) {
- Log.e(TAG, "Feed has invalid items");
- return false;
+ throw new InvalidFeedException("Feed has no title");
}
- return true;
+ checkFeedItems(feed);
}
- private boolean hasValidFeedItems(Feed feed) {
+ private void checkFeedItems(Feed feed) throws InvalidFeedException {
for (FeedItem item : feed.getItems()) {
if (item.getTitle() == null) {
- Log.e(TAG, "Item has no title");
- return false;
+ throw new InvalidFeedException("Item has no title: " + item);
}
if (item.getPubDate() == null) {
Log.e(TAG, "Item has no pubDate. Using current time as pubDate");
@@ -121,7 +112,6 @@ public class FeedParserTask implements Callable<FeedHandlerResult> {
item.setPubDate(new Date());
}
}
- return true;
}
public DownloadStatus getDownloadStatus() {
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 33a2a72ff..111e2d37c 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
@@ -79,6 +79,7 @@ import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
import io.reactivex.Observable;
+import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import org.greenrobot.eventbus.EventBus;
@@ -204,9 +205,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
*/
private static volatile boolean isCasting = false;
- private static final int NOTIFICATION_ID = 1;
- private static final int NOTIFICATION_ID_STREAMING = 2;
-
private PlaybackServiceMediaPlayer mediaPlayer;
private PlaybackServiceTaskManager taskManager;
private PlaybackServiceFlavorHelper flavorHelper;
@@ -271,7 +269,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
stateManager = new PlaybackServiceStateManager(this);
notificationBuilder = new PlaybackServiceNotificationBuilder(this);
- stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build());
registerReceiver(autoStateUpdated, new IntentFilter("com.google.android.gms.car.media.STATUS"));
registerReceiver(headsetDisconnected, new IntentFilter(Intent.ACTION_HEADSET_PLUG));
@@ -307,18 +304,16 @@ public class PlaybackService extends MediaBrowserServiceCompat {
npe.printStackTrace();
}
- List<MediaSessionCompat.QueueItem> queueItems = new ArrayList<>();
- try {
+ Single.<List<MediaSessionCompat.QueueItem>>create(emitter -> {
+ List<MediaSessionCompat.QueueItem> queueItems = new ArrayList<>();
for (FeedItem feedItem : taskManager.getQueue()) {
if (feedItem.getMedia() != null) {
MediaDescriptionCompat mediaDescription = feedItem.getMedia().getMediaItem().getDescription();
queueItems.add(new MediaSessionCompat.QueueItem(mediaDescription, feedItem.getId()));
}
}
- mediaSession.setQueue(queueItems);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ emitter.onSuccess(queueItems);
+ }).subscribe(queueItems -> mediaSession.setQueue(queueItems), Throwable::printStackTrace);
flavorHelper.initializeMediaPlayer(PlaybackService.this);
mediaSession.setActive(true);
@@ -334,7 +329,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
if (notificationBuilder.getPlayerStatus() == PlayerStatus.PLAYING) {
notificationBuilder.setPlayerStatus(PlayerStatus.STOPPED);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
- notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ notificationManager.notify(R.id.notification_playing, notificationBuilder.build());
}
stateManager.stopForeground(!UserPreferences.isPersistNotify());
isRunning = false;
@@ -424,7 +419,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
e.printStackTrace();
}
} else if (parentId.startsWith("FeedId:")) {
- Long feedId = Long.parseLong(parentId.split(":")[1]);
+ long feedId = Long.parseLong(parentId.split(":")[1]);
List<FeedItem> feedItems = DBReader.getFeedItemList(DBReader.getFeed(feedId));
for (FeedItem feedItem : feedItems) {
if (feedItem.getMedia() != null && feedItem.getMedia().getMediaItem() != null) {
@@ -450,9 +445,9 @@ public class PlaybackService extends MediaBrowserServiceCompat {
super.onStartCommand(intent, flags, startId);
Log.d(TAG, "OnStartCommand called");
- stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build());
+ stateManager.startForeground(R.id.notification_playing, notificationBuilder.build());
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
- notificationManager.cancel(NOTIFICATION_ID_STREAMING);
+ notificationManager.cancel(R.id.notification_streaming_confirmation);
final int keycode = intent.getIntExtra(MediaButtonReceiver.EXTRA_KEYCODE, -1);
final boolean castDisconnect = intent.getBooleanExtra(EXTRA_CAST_DISCONNECT, false);
@@ -542,9 +537,11 @@ public class PlaybackService extends MediaBrowserServiceCompat {
intentAllowThisTime.putExtra(EXTRA_ALLOW_STREAM_THIS_TIME, true);
PendingIntent pendingIntentAllowThisTime;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
- pendingIntentAllowThisTime = PendingIntent.getForegroundService(this, 0, intentAllowThisTime, PendingIntent.FLAG_UPDATE_CURRENT);
+ pendingIntentAllowThisTime = PendingIntent.getForegroundService(this,
+ R.id.pending_intent_allow_stream_this_time, intentAllowThisTime, PendingIntent.FLAG_UPDATE_CURRENT);
} else {
- pendingIntentAllowThisTime = PendingIntent.getService(this, 0, intentAllowThisTime, PendingIntent.FLAG_UPDATE_CURRENT);
+ pendingIntentAllowThisTime = PendingIntent.getService(this,
+ R.id.pending_intent_allow_stream_this_time, intentAllowThisTime, PendingIntent.FLAG_UPDATE_CURRENT);
}
Intent intentAlwaysAllow = new Intent(intentAllowThisTime);
@@ -552,12 +549,15 @@ public class PlaybackService extends MediaBrowserServiceCompat {
intentAlwaysAllow.putExtra(EXTRA_ALLOW_STREAM_ALWAYS, true);
PendingIntent pendingIntentAlwaysAllow;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
- pendingIntentAlwaysAllow = PendingIntent.getForegroundService(this, 0, intentAlwaysAllow, PendingIntent.FLAG_UPDATE_CURRENT);
+ pendingIntentAlwaysAllow = PendingIntent.getForegroundService(this,
+ R.id.pending_intent_allow_stream_always, intentAlwaysAllow, PendingIntent.FLAG_UPDATE_CURRENT);
} else {
- pendingIntentAlwaysAllow = PendingIntent.getService(this, 0, intentAlwaysAllow, PendingIntent.FLAG_UPDATE_CURRENT);
+ pendingIntentAlwaysAllow = PendingIntent.getService(this,
+ R.id.pending_intent_allow_stream_always, intentAlwaysAllow, PendingIntent.FLAG_UPDATE_CURRENT);
}
- NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationUtils.CHANNEL_ID_USER_ACTION)
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(this,
+ NotificationUtils.CHANNEL_ID_USER_ACTION)
.setSmallIcon(R.drawable.ic_stream_white)
.setContentTitle(getString(R.string.confirm_mobile_streaming_notification_title))
.setContentText(getString(R.string.confirm_mobile_streaming_notification_message))
@@ -573,7 +573,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
pendingIntentAlwaysAllow)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
- notificationManager.notify(NOTIFICATION_ID_STREAMING, builder.build());
+ notificationManager.notify(R.id.notification_streaming_confirmation, builder.build());
}
/**
@@ -711,9 +711,12 @@ public class PlaybackService extends MediaBrowserServiceCompat {
}
@Override
- public void onSleepTimerAlmostExpired() {
- float leftVolume = 0.1f * UserPreferences.getLeftVolume();
- float rightVolume = 0.1f * UserPreferences.getRightVolume();
+ public void onSleepTimerAlmostExpired(long timeLeft) {
+ final float[] multiplicators = {0.1f, 0.2f, 0.3f, 0.3f, 0.3f, 0.4f, 0.4f, 0.4f, 0.6f, 0.8f};
+ float multiplicator = multiplicators[Math.max(0, (int) timeLeft / 1000)];
+ Log.d(TAG, "onSleepTimerAlmostExpired: " + multiplicator);
+ float leftVolume = multiplicator * UserPreferences.getLeftVolume();
+ float rightVolume = multiplicator * UserPreferences.getRightVolume();
mediaPlayer.setVolume(leftVolume, rightVolume);
}
@@ -1140,13 +1143,11 @@ public class PlaybackService extends MediaBrowserServiceCompat {
case INITIALIZING:
state = PlaybackStateCompat.STATE_CONNECTING;
break;
- case INITIALIZED:
- case INDETERMINATE:
- state = PlaybackStateCompat.STATE_NONE;
- break;
case ERROR:
state = PlaybackStateCompat.STATE_ERROR;
break;
+ case INITIALIZED: // Deliberate fall-through
+ case INDETERMINATE:
default:
state = PlaybackStateCompat.STATE_NONE;
break;
@@ -1158,7 +1159,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
long capabilities = PlaybackStateCompat.ACTION_PLAY_PAUSE
| PlaybackStateCompat.ACTION_REWIND
| PlaybackStateCompat.ACTION_FAST_FORWARD
- | PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
+ | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
+ | PlaybackStateCompat.ACTION_SEEK_TO;
if (useSkipToPreviousForRewindInLockscreen()) {
// Workaround to fool Android so that Lockscreen will expose a skip-to-previous button,
@@ -1238,9 +1240,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
}
}
if (!Thread.currentThread().isInterrupted() && stateManager.hasReceivedValidStartCommand()) {
- mediaSession.setSessionActivity(PendingIntent.getActivity(this, 0,
- PlaybackService.getPlayerActivityIntent(this),
- PendingIntent.FLAG_UPDATE_CURRENT));
+ mediaSession.setSessionActivity(PendingIntent.getActivity(this, R.id.pending_intent_player_activity,
+ PlaybackService.getPlayerActivityIntent(this), PendingIntent.FLAG_UPDATE_CURRENT));
try {
mediaSession.setMetadata(builder.build());
} catch (OutOfMemoryError e) {
@@ -1289,7 +1290,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
notificationBuilder.updatePosition(getCurrentPosition(), getCurrentPlaybackSpeed());
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
- notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ notificationManager.notify(R.id.notification_playing, notificationBuilder.build());
startForegroundIfPlaying(playerStatus);
if (!notificationBuilder.isIconCached()) {
@@ -1297,7 +1298,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
Log.d(TAG, "Loading notification icon");
notificationBuilder.loadIcon();
if (!Thread.currentThread().isInterrupted()) {
- notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ notificationManager.notify(R.id.notification_playing, notificationBuilder.build());
}
});
notificationSetupThread.start();
@@ -1309,12 +1310,12 @@ public class PlaybackService extends MediaBrowserServiceCompat {
if (stateManager.hasReceivedValidStartCommand()) {
if (isCasting || status == PlayerStatus.PLAYING || status == PlayerStatus.PREPARING
|| status == PlayerStatus.SEEKING) {
- stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build());
+ stateManager.startForeground(R.id.notification_playing, notificationBuilder.build());
Log.d(TAG, "foreground");
} else {
stateManager.stopForeground(false);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
- notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ notificationManager.notify(R.id.notification_playing, notificationBuilder.build());
}
}
}
@@ -1717,7 +1718,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
notificationBuilder.updatePosition(getCurrentPosition(), getCurrentPlaybackSpeed());
NotificationManager notificationManager = (NotificationManager)
getSystemService(NOTIFICATION_SERVICE);
- notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ notificationManager.notify(R.id.notification_playing, notificationBuilder.build());
}
skipEndingIfNecessary();
});
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
index 174b43846..3239f3378 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
@@ -131,7 +131,7 @@ public class PlaybackServiceNotificationBuilder {
}
} else {
notification.setContentTitle(context.getString(R.string.app_name));
- notification.setContentText("Service is running");
+ notification.setContentText("Loading. If this does not go away, play any episode and contact us.");
}
notification.setContentIntent(getPlayerActivityPendingIntent());
@@ -146,8 +146,8 @@ public class PlaybackServiceNotificationBuilder {
}
private PendingIntent getPlayerActivityPendingIntent() {
- return PendingIntent.getActivity(context, 0, PlaybackService.getPlayerActivityIntent(context),
- PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getActivity(context, R.id.pending_intent_player_activity,
+ PlaybackService.getPlayerActivityIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
}
private void addActions(NotificationCompat.Builder notification, MediaSessionCompat.Token mediaSessionToken,
@@ -183,15 +183,14 @@ public class PlaybackServiceNotificationBuilder {
notification.addAction(R.drawable.ic_notification_pause, //pause action
context.getString(R.string.pause_label),
pauseButtonPendingIntent);
- compactActionList.add(numActions++);
} else {
PendingIntent playButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_PLAY, numActions);
notification.addAction(R.drawable.ic_notification_play, //play action
context.getString(R.string.play_label),
playButtonPendingIntent);
- compactActionList.add(numActions++);
}
+ compactActionList.add(numActions++);
// ff follows play, then we have skip (if it's present)
PendingIntent ffButtonPendingIntent = getPendingIntentForMediaAction(
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 e71c1dfa7..55212cd46 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
@@ -316,7 +316,8 @@ public class PlaybackServiceTaskManager {
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
- .subscribe(() -> callback.onChapterLoaded(media));
+ .subscribe(() -> callback.onChapterLoaded(media),
+ throwable -> Log.d(TAG, "Error loading chapters: " + Log.getStackTraceString(throwable)));
}
}
@@ -359,7 +360,8 @@ public class PlaybackServiceTaskManager {
class SleepTimer implements Runnable {
private static final String TAG = "SleepTimer";
private static final long UPDATE_INTERVAL = 1000L;
- private static final long NOTIFICATION_THRESHOLD = 10000;
+ public static final long NOTIFICATION_THRESHOLD = 10000;
+ private boolean hasVibrated = false;
private final long waitingTime;
private long timeLeft;
private ShakeListener shakeListener;
@@ -389,7 +391,6 @@ public class PlaybackServiceTaskManager {
@Override
public void run() {
Log.d(TAG, "Starting");
- boolean notifiedAlmostExpired = false;
long lastTick = System.currentTimeMillis();
while (timeLeft > 0) {
try {
@@ -404,19 +405,19 @@ public class PlaybackServiceTaskManager {
timeLeft -= now - lastTick;
lastTick = now;
- if (timeLeft < NOTIFICATION_THRESHOLD && !notifiedAlmostExpired) {
+ if (timeLeft < NOTIFICATION_THRESHOLD) {
Log.d(TAG, "Sleep timer is about to expire");
- if (SleepTimerPreferences.vibrate()) {
+ if (SleepTimerPreferences.vibrate() && !hasVibrated) {
Vibrator v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
if (v != null) {
v.vibrate(500);
+ hasVibrated = true;
}
}
if (shakeListener == null && SleepTimerPreferences.shakeToReset()) {
shakeListener = new ShakeListener(context, this);
}
- postCallback(callback::onSleepTimerAlmostExpired);
- notifiedAlmostExpired = true;
+ postCallback(() -> callback.onSleepTimerAlmostExpired(timeLeft));
}
if (timeLeft <= 0) {
Log.d(TAG, "Sleep timer expired");
@@ -424,6 +425,7 @@ public class PlaybackServiceTaskManager {
shakeListener.pause();
shakeListener = null;
}
+ hasVibrated = false;
if (!Thread.currentThread().isInterrupted()) {
postCallback(callback::onSleepTimerExpired);
} else {
@@ -460,7 +462,7 @@ public class PlaybackServiceTaskManager {
public interface PSTMCallback {
void positionSaverTick();
- void onSleepTimerAlmostExpired();
+ void onSleepTimerAlmostExpired(long timeLeft);
void onSleepTimerExpired();
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 b0b6e164d..b967577af 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
@@ -58,7 +58,6 @@ class ShakeListener implements SensorEventListener
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
- return;
}
} \ No newline at end of file
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 c30f46315..0de67b306 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
@@ -72,19 +72,13 @@ public final class DBReader {
@NonNull
private static List<Feed> getFeedList(PodDBAdapter adapter) {
- Cursor cursor = null;
- try {
- cursor = adapter.getAllFeedsCursor();
+ try (Cursor cursor = adapter.getAllFeedsCursor()) {
List<Feed> feeds = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
Feed feed = extractFeedFromCursorRow(cursor);
feeds.add(feed);
}
return feeds;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
}
}
@@ -96,18 +90,13 @@ public final class DBReader {
public static List<String> getFeedListDownloadUrls() {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Cursor cursor = null;
- try {
- cursor = adapter.getFeedCursorDownloadUrls();
+ try (Cursor cursor = adapter.getFeedCursorDownloadUrls()) {
List<String> result = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
result.add(cursor.getString(1));
}
return result;
} finally {
- if (cursor != null) {
- cursor.close();
- }
adapter.close();
}
}
@@ -172,9 +161,7 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Cursor cursor = null;
- try {
- cursor = adapter.getAllItemsOfFeedCursor(feed);
+ try (Cursor cursor = adapter.getAllItemsOfFeedCursor(feed)) {
List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
Collections.sort(items, new FeedItemPubdateComparator());
for (FeedItem item : items) {
@@ -182,9 +169,6 @@ public final class DBReader {
}
return items;
} finally {
- if (cursor != null) {
- cursor.close();
- }
adapter.close();
}
}
@@ -226,16 +210,10 @@ public final class DBReader {
@NonNull
static List<FeedItem> getQueue(PodDBAdapter adapter) {
Log.d(TAG, "getQueue()");
- Cursor cursor = null;
- try {
- cursor = adapter.getQueueCursor();
+ try (Cursor cursor = adapter.getQueueCursor()) {
List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
loadAdditionalFeedItemListData(items);
return items;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
}
}
@@ -257,18 +235,12 @@ public final class DBReader {
}
private static LongList getQueueIDList(PodDBAdapter adapter) {
- Cursor cursor = null;
- try {
- cursor = adapter.getQueueIDCursor();
+ try (Cursor cursor = adapter.getQueueIDCursor()) {
LongList queueIds = new LongList(cursor.getCount());
while (cursor.moveToNext()) {
queueIds.add(cursor.getLong(0));
}
return queueIds;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
}
}
@@ -302,17 +274,12 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Cursor cursor = null;
- try {
- cursor = adapter.getDownloadedItemsCursor();
+ try (Cursor cursor = adapter.getDownloadedItemsCursor()) {
List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
loadAdditionalFeedItemListData(items);
Collections.sort(items, new FeedItemPubdateComparator());
return items;
} finally {
- if (cursor != null) {
- cursor.close();
- }
adapter.close();
}
}
@@ -328,16 +295,11 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Cursor cursor = null;
- try {
- cursor = adapter.getPlayedItemsCursor();
+ try (Cursor cursor = adapter.getPlayedItemsCursor()) {
List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
loadAdditionalFeedItemListData(items);
return items;
} finally {
- if (cursor != null) {
- cursor.close();
- }
adapter.close();
}
}
@@ -355,16 +317,11 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Cursor cursor = null;
- try {
- cursor = adapter.getNewItemsCursor(offset, limit);
+ try (Cursor cursor = adapter.getNewItemsCursor(offset, limit)) {
List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
loadAdditionalFeedItemListData(items);
return items;
} finally {
- if (cursor != null) {
- cursor.close();
- }
adapter.close();
}
}
@@ -381,16 +338,11 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Cursor cursor = null;
- try {
- cursor = adapter.getFavoritesCursor(offset, limit);
+ try (Cursor cursor = adapter.getFavoritesCursor(offset, limit)) {
List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
loadAdditionalFeedItemListData(items);
return items;
} finally {
- if (cursor != null) {
- cursor.close();
- }
adapter.close();
}
}
@@ -400,18 +352,13 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Cursor cursor = null;
- try {
- cursor = adapter.getFavoritesCursor(0, Integer.MAX_VALUE);
+ try (Cursor cursor = adapter.getFavoritesCursor(0, Integer.MAX_VALUE)) {
LongList favoriteIDs = new LongList(cursor.getCount());
while (cursor.moveToNext()) {
favoriteIDs.add(cursor.getLong(0));
}
return favoriteIDs;
} finally {
- if (cursor != null) {
- cursor.close();
- }
adapter.close();
}
}
@@ -428,16 +375,11 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Cursor cursor = null;
- try {
- cursor = adapter.getRecentlyPublishedItemsCursor(offset, limit);
+ try (Cursor cursor = adapter.getRecentlyPublishedItemsCursor(offset, limit)) {
List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
loadAdditionalFeedItemListData(items);
return items;
} finally {
- if (cursor != null) {
- cursor.close();
- }
adapter.close();
}
}
@@ -492,9 +434,7 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Cursor cursor = null;
- try {
- cursor = adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE);
+ try (Cursor cursor = adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE)) {
List<DownloadStatus> downloadLog = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
downloadLog.add(DownloadStatus.fromCursor(cursor));
@@ -502,9 +442,6 @@ public final class DBReader {
Collections.sort(downloadLog, new DownloadStatusComparator());
return downloadLog;
} finally {
- if (cursor != null) {
- cursor.close();
- }
adapter.close();
}
}
@@ -521,9 +458,7 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Cursor cursor = null;
- try {
- cursor = adapter.getDownloadLog(Feed.FEEDFILETYPE_FEED, feedId);
+ try (Cursor cursor = adapter.getDownloadLog(Feed.FEEDFILETYPE_FEED, feedId)) {
List<DownloadStatus> downloadLog = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
downloadLog.add(DownloadStatus.fromCursor(cursor));
@@ -531,9 +466,6 @@ public final class DBReader {
Collections.sort(downloadLog, new DownloadStatusComparator());
return downloadLog;
} finally {
- if (cursor != null) {
- cursor.close();
- }
adapter.close();
}
}
@@ -560,9 +492,7 @@ public final class DBReader {
@Nullable
static Feed getFeed(final long feedId, PodDBAdapter adapter) {
Feed feed = null;
- Cursor cursor = null;
- try {
- cursor = adapter.getFeedCursor(feedId);
+ try (Cursor cursor = adapter.getFeedCursor(feedId)) {
if (cursor.moveToNext()) {
feed = extractFeedFromCursorRow(cursor);
feed.setItems(getFeedItemList(feed));
@@ -570,10 +500,6 @@ public final class DBReader {
Log.e(TAG, "getFeed could not find feed with id " + feedId);
}
return feed;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
}
}
@@ -582,9 +508,7 @@ public final class DBReader {
Log.d(TAG, "Loading feeditem with id " + itemId);
FeedItem item = null;
- Cursor cursor = null;
- try {
- cursor = adapter.getFeedItemCursor(Long.toString(itemId));
+ try (Cursor cursor = adapter.getFeedItemCursor(Long.toString(itemId))) {
if (cursor.moveToNext()) {
List<FeedItem> list = extractItemlistFromCursor(adapter, cursor);
if (!list.isEmpty()) {
@@ -593,10 +517,6 @@ public final class DBReader {
}
}
return item;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
}
}
@@ -631,9 +551,7 @@ public final class DBReader {
@Nullable
private static FeedItem getFeedItemByUrl(final String podcastUrl, final String episodeUrl, PodDBAdapter adapter) {
Log.d(TAG, "Loading feeditem with podcast url " + podcastUrl + " and episode url " + episodeUrl);
- Cursor cursor = null;
- try {
- cursor = adapter.getFeedItemCursor(podcastUrl, episodeUrl);
+ try (Cursor cursor = adapter.getFeedItemCursor(podcastUrl, episodeUrl)) {
if (!cursor.moveToNext()) {
return null;
}
@@ -642,10 +560,6 @@ public final class DBReader {
return list.get(0);
}
return null;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
}
}
@@ -668,10 +582,8 @@ public final class DBReader {
}
private static String getImageAuthentication(final String imageUrl, PodDBAdapter adapter) {
- String credentials = null;
- Cursor cursor = null;
- try {
- cursor = adapter.getImageAuthenticationCursor(imageUrl);
+ String credentials;
+ try (Cursor cursor = adapter.getImageAuthenticationCursor(imageUrl)) {
if (cursor.moveToFirst()) {
String username = cursor.getString(0);
String password = cursor.getString(1);
@@ -683,10 +595,6 @@ public final class DBReader {
} else {
credentials = "";
}
- } finally {
- if (cursor != null) {
- cursor.close();
- }
}
return credentials;
}
@@ -720,9 +628,7 @@ public final class DBReader {
Log.d(TAG, "loadDescriptionOfFeedItem() called with: " + "item = [" + item + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- Cursor cursor = null;
- try {
- cursor = adapter.getDescriptionOfItem(item);
+ try (Cursor cursor = adapter.getDescriptionOfItem(item)) {
if (cursor.moveToFirst()) {
int indexDescription = cursor.getColumnIndex(PodDBAdapter.KEY_DESCRIPTION);
String description = cursor.getString(indexDescription);
@@ -732,9 +638,6 @@ public final class DBReader {
item.setContentEncoded(contentEncoded);
}
} finally {
- if (cursor != null) {
- cursor.close();
- }
adapter.close();
}
}
@@ -898,6 +801,16 @@ public final class DBReader {
}
final LongIntMap feedCounters = adapter.getFeedCounters(feedIds);
+ int feedFilter = UserPreferences.getFeedFilter();
+ if (feedFilter == UserPreferences.FEED_FILTER_COUNTER_ZERO) {
+ for (int i = feeds.size() - 1; i >= 0; i--) {
+ if (feedCounters.get(feeds.get(i).getId()) <= 0) {
+ feedCounters.delete(feeds.get(i).getId());
+ feeds.remove(i);
+ }
+ }
+ }
+
Comparator<Feed> comparator;
int feedOrder = UserPreferences.getFeedOrder();
if (feedOrder == UserPreferences.FEED_ORDER_COUNTER) {
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 6f9e6b056..e3121caa2 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
@@ -274,7 +274,7 @@ public class DownloadRequester implements DownloadStateProvider {
}
File dest;
- if (feedmedia.getFile_url() != null) {
+ if (feedmedia.getFile_url() != null && new File(feedmedia.getFile_url()).exists()) {
dest = new File(feedmedia.getFile_url());
} else {
dest = new File(getMediafilePath(feedmedia), getMediafilename(feedmedia));
@@ -340,7 +340,7 @@ public class DownloadRequester implements DownloadStateProvider {
/**
* Checks if feedfile is in the downloads list
*/
- public synchronized boolean isDownloadingFile(FeedFile item) {
+ public synchronized boolean isDownloadingFile(@NonNull FeedFile item) {
return item.getDownload_url() != null && downloads.containsKey(item.getDownload_url());
}
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 a2247a3db..142763d75 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
@@ -1236,7 +1236,7 @@ public class PodDBAdapter {
public Cursor searchItems(long feedID, String searchQuery) {
String preparedQuery = prepareSearchQuery(searchQuery);
- String queryFeedId = "";
+ String queryFeedId;
if (feedID != 0) {
// search items in specific feed
queryFeedId = KEY_FEED + " = " + feedID;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java
index 6985e4421..4c89ebc19 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java
@@ -488,8 +488,8 @@ public class SyncService extends Worker {
Intent intent = getApplicationContext().getPackageManager().getLaunchIntentForPackage(
getApplicationContext().getPackageName());
- PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
+ R.id.pending_intent_sync_error, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(getApplicationContext(),
NotificationUtils.CHANNEL_ID_ERROR)
.setContentTitle(getApplicationContext().getString(R.string.gpodnetsync_error_title))
diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java
index eae7a08af..62c8ce5f3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java
@@ -21,7 +21,6 @@ import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
-import org.apache.commons.io.Charsets;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -34,6 +33,7 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
@@ -505,7 +505,7 @@ public class GpodnetService implements ISyncService {
RequestBody requestBody = RequestBody.create(TEXT, "");
Request request = new Request.Builder().url(url).post(requestBody).build();
try {
- String credential = Credentials.basic(username, password, Charsets.UTF_8);
+ String credential = Credentials.basic(username, password, Charset.forName("UTF-8"));
Request authRequest = request.newBuilder().header("Authorization", credential).build();
Response response = httpClient.newCall(authRequest).execute();
checkStatusCode(response);
@@ -519,8 +519,8 @@ public class GpodnetService implements ISyncService {
private String executeRequest(@NonNull Request.Builder requestB) throws GpodnetServiceException {
Request request = requestB.build();
- String responseString = null;
- Response response = null;
+ String responseString;
+ Response response;
ResponseBody body = null;
try {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java b/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java
index 6154ccc84..798be8d96 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.core.sync.model;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.core.util.ObjectsCompat;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.util.DateUtils;
@@ -179,6 +180,7 @@ public class EpisodeAction {
return obj;
}
+ @NonNull
@Override
public String toString() {
return "EpisodeAction{"
diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java b/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java
index 77942ffa0..90af585af 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java
@@ -23,6 +23,7 @@ public class EpisodeActionChanges {
return this.timestamp;
}
+ @NonNull
@Override
public String toString() {
return "EpisodeActionGetResponse{"
diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java
index c9f9f19c8..11588967a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java
@@ -36,6 +36,9 @@ public class UnsupportedFeedtypeException extends Exception {
if (message != null) {
return message;
} else if (type == TypeGetter.Type.INVALID) {
+ if ("html".equals(rootElement)) {
+ return "The server returned a website, not a podcast feed";
+ }
return "Invalid type";
} else {
return "Type " + type + " not supported";
diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java
index 638383223..30b01f0bc 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java
@@ -14,114 +14,118 @@ import de.danoeh.antennapod.core.syndication.util.SyndTypeUtils;
/** Processes tags from the http://search.yahoo.com/mrss/ namespace. */
public class NSMedia extends Namespace {
- private static final String TAG = "NSMedia";
-
- public static final String NSTAG = "media";
- public static final String NSURI = "http://search.yahoo.com/mrss/";
-
- private static final String CONTENT = "content";
- private static final String DOWNLOAD_URL = "url";
- private static final String SIZE = "fileSize";
- private static final String MIME_TYPE = "type";
- private static final String DURATION = "duration";
- private static final String DEFAULT = "isDefault";
- private static final String MEDIUM = "medium";
-
- private static final String MEDIUM_IMAGE = "image";
- private static final String MEDIUM_AUDIO = "audio";
- private static final String MEDIUM_VIDEO = "video";
-
- private static final String IMAGE = "thumbnail";
- private static final String IMAGE_URL = "url";
-
- private static final String DESCRIPTION = "description";
- private static final String DESCRIPTION_TYPE = "type";
-
- @Override
- public SyndElement handleElementStart(String localName, HandlerState state,
- Attributes attributes) {
- if (CONTENT.equals(localName)) {
- String url = attributes.getValue(DOWNLOAD_URL);
- String type = attributes.getValue(MIME_TYPE);
- String defaultStr = attributes.getValue(DEFAULT);
- String medium = attributes.getValue(MEDIUM);
- boolean validTypeMedia = false;
- boolean validTypeImage = false;
-
- boolean isDefault = "true".equals(defaultStr);
-
- if (MEDIUM_AUDIO.equals(medium) || MEDIUM_VIDEO.equals(medium)) {
- validTypeMedia = true;
- } else if (MEDIUM_IMAGE.equals(medium)) {
- validTypeImage = true;
- } else {
- if (type == null) {
- type = SyndTypeUtils.getMimeTypeFromUrl(url);
- }
-
- if (SyndTypeUtils.enclosureTypeValid(type)) {
- validTypeMedia = true;
- } else if (SyndTypeUtils.imageTypeValid(type)) {
- validTypeImage = true;
- }
- }
-
- if (state.getCurrentItem() != null &&
- (state.getCurrentItem().getMedia() == null || isDefault) &&
- url != null && validTypeMedia) {
- long size = 0;
- String sizeStr = attributes.getValue(SIZE);
- try {
- size = Long.parseLong(sizeStr);
- } catch (NumberFormatException e) {
- Log.e(TAG, "Size \"" + sizeStr + "\" could not be parsed.");
- }
-
- int durationMs = 0;
- String durationStr = attributes.getValue(DURATION);
- if (!TextUtils.isEmpty(durationStr)) {
- try {
- long duration = Long.parseLong(durationStr);
- durationMs = (int) TimeUnit.MILLISECONDS.convert(duration, TimeUnit.SECONDS);
- } catch (NumberFormatException e) {
- Log.e(TAG, "Duration \"" + durationStr + "\" could not be parsed");
- }
- }
- FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, type);
- if (durationMs > 0) {
- media.setDuration(durationMs);
- }
- state.getCurrentItem().setMedia(media);
- } else if (state.getCurrentItem() != null && url != null && validTypeImage) {
- state.getCurrentItem().setImageUrl(url);
- }
- } else if (IMAGE.equals(localName)) {
- String url = attributes.getValue(IMAGE_URL);
- if (url != null) {
- if (state.getCurrentItem() != null) {
- state.getCurrentItem().setImageUrl(url);
- } else {
- if (state.getFeed().getImageUrl() == null) {
- state.getFeed().setImageUrl(url);
- }
- }
- }
- } else if (DESCRIPTION.equals(localName)) {
- String type = attributes.getValue(DESCRIPTION_TYPE);
- return new AtomText(localName, this, type);
- }
- return new SyndElement(localName, this);
- }
-
- @Override
- public void handleElementEnd(String localName, HandlerState state) {
- if (DESCRIPTION.equals(localName)) {
- String content = state.getContentBuf().toString();
- if (state.getCurrentItem() != null && content != null &&
- state.getCurrentItem().getDescription() == null) {
- state.getCurrentItem().setDescription(content);
- }
- }
- }
+ private static final String TAG = "NSMedia";
+
+ public static final String NSTAG = "media";
+ public static final String NSURI = "http://search.yahoo.com/mrss/";
+
+ private static final String CONTENT = "content";
+ private static final String DOWNLOAD_URL = "url";
+ private static final String SIZE = "fileSize";
+ private static final String MIME_TYPE = "type";
+ private static final String DURATION = "duration";
+ private static final String DEFAULT = "isDefault";
+ private static final String MEDIUM = "medium";
+
+ private static final String MEDIUM_IMAGE = "image";
+ private static final String MEDIUM_AUDIO = "audio";
+ private static final String MEDIUM_VIDEO = "video";
+
+ private static final String IMAGE = "thumbnail";
+ private static final String IMAGE_URL = "url";
+
+ private static final String DESCRIPTION = "description";
+ private static final String DESCRIPTION_TYPE = "type";
+
+ @Override
+ public SyndElement handleElementStart(String localName, HandlerState state,
+ Attributes attributes) {
+ if (CONTENT.equals(localName)) {
+ String url = attributes.getValue(DOWNLOAD_URL);
+ String type = attributes.getValue(MIME_TYPE);
+ String defaultStr = attributes.getValue(DEFAULT);
+ String medium = attributes.getValue(MEDIUM);
+ boolean validTypeMedia = false;
+ boolean validTypeImage = false;
+
+ boolean isDefault = "true".equals(defaultStr);
+
+ if (MEDIUM_AUDIO.equals(medium)) {
+ validTypeMedia = true;
+ type = "audio/*";
+ } else if (MEDIUM_VIDEO.equals(medium)) {
+ validTypeMedia = true;
+ type = "video/*";
+ } else if (MEDIUM_IMAGE.equals(medium)) {
+ validTypeImage = true;
+ type = "image/*";
+ } else {
+ if (type == null) {
+ type = SyndTypeUtils.getMimeTypeFromUrl(url);
+ }
+
+ if (SyndTypeUtils.enclosureTypeValid(type)) {
+ validTypeMedia = true;
+ } else if (SyndTypeUtils.imageTypeValid(type)) {
+ validTypeImage = true;
+ }
+ }
+
+ if (state.getCurrentItem() != null && (state.getCurrentItem().getMedia() == null || isDefault)
+ && url != null && validTypeMedia) {
+ long size = 0;
+ String sizeStr = attributes.getValue(SIZE);
+ try {
+ size = Long.parseLong(sizeStr);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Size \"" + sizeStr + "\" could not be parsed.");
+ }
+
+ int durationMs = 0;
+ String durationStr = attributes.getValue(DURATION);
+ if (!TextUtils.isEmpty(durationStr)) {
+ try {
+ long duration = Long.parseLong(durationStr);
+ durationMs = (int) TimeUnit.MILLISECONDS.convert(duration, TimeUnit.SECONDS);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Duration \"" + durationStr + "\" could not be parsed");
+ }
+ }
+ FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, type);
+ if (durationMs > 0) {
+ media.setDuration(durationMs);
+ }
+ state.getCurrentItem().setMedia(media);
+ } else if (state.getCurrentItem() != null && url != null && validTypeImage) {
+ state.getCurrentItem().setImageUrl(url);
+ }
+ } else if (IMAGE.equals(localName)) {
+ String url = attributes.getValue(IMAGE_URL);
+ if (url != null) {
+ if (state.getCurrentItem() != null) {
+ state.getCurrentItem().setImageUrl(url);
+ } else {
+ if (state.getFeed().getImageUrl() == null) {
+ state.getFeed().setImageUrl(url);
+ }
+ }
+ }
+ } else if (DESCRIPTION.equals(localName)) {
+ String type = attributes.getValue(DESCRIPTION_TYPE);
+ return new AtomText(localName, this, type);
+ }
+ return new SyndElement(localName, this);
+ }
+
+ @Override
+ public void handleElementEnd(String localName, HandlerState state) {
+ if (DESCRIPTION.equals(localName)) {
+ String content = state.getContentBuf().toString();
+ if (state.getCurrentItem() != null && content != null
+ && state.getCurrentItem().getDescription() == null) {
+ state.getCurrentItem().setDescription(content);
+ }
+ }
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java
index e85d5fae1..0c0561279 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.syndication.namespace.atom;
-import android.os.Build;
-import android.text.Html;
+import androidx.core.text.HtmlCompat;
+
import de.danoeh.antennapod.core.syndication.namespace.Namespace;
import de.danoeh.antennapod.core.syndication.namespace.SyndElement;
@@ -24,11 +24,7 @@ public class AtomText extends SyndElement {
if (type == null) {
return content;
} else if (type.equals(TYPE_HTML)) {
- if (Build.VERSION.SDK_INT >= 24) {
- return Html.fromHtml(content, Html.FROM_HTML_MODE_LEGACY).toString();
- } else {
- return Html.fromHtml(content).toString();
- }
+ return HtmlCompat.fromHtml(content, HtmlCompat.FROM_HTML_MODE_LEGACY).toString();
} else if (type.equals(TYPE_XHTML)) {
return content;
} else { // Handle as text by default
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 7aa5a90e7..7e4350fd4 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
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.core.syndication.namespace.atom;
import android.text.TextUtils;
import android.util.Log;
+import de.danoeh.antennapod.core.syndication.util.SyndStringUtils;
import org.xml.sax.Attributes;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -163,12 +164,13 @@ public class NSAtom extends Namespace {
if (state.getTagstack().size() >= 2) {
AtomText textElement = null;
- String content;
+ String contentRaw;
if (state.getContentBuf() != null) {
- content = state.getContentBuf().toString();
+ contentRaw = state.getContentBuf().toString();
} else {
- content = "";
+ contentRaw = "";
}
+ String content = SyndStringUtils.trimAllWhitespace(contentRaw);
SyndElement topElement = state.getTagstack().peek();
String top = topElement.getName();
SyndElement secondElement = state.getSecondTag();
@@ -181,9 +183,9 @@ public class NSAtom extends Namespace {
if (ID.equals(top)) {
if (FEED.equals(second) && state.getFeed() != null) {
- state.getFeed().setFeedIdentifier(content);
+ state.getFeed().setFeedIdentifier(contentRaw);
} else if (ENTRY.equals(second) && state.getCurrentItem() != null) {
- state.getCurrentItem().setItemIdentifier(content);
+ state.getCurrentItem().setItemIdentifier(contentRaw);
}
} else if (TITLE.equals(top) && textElement != null) {
if (FEED.equals(second) && state.getFeed() != null) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
index 4fd54156b..859666464 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
@@ -6,6 +6,8 @@ import android.net.Uri;
import androidx.annotation.NonNull;
import android.util.Log;
+import java.net.URLConnection;
+import de.danoeh.antennapod.core.ClientConfig;
import org.apache.commons.io.IOUtils;
import java.io.BufferedInputStream;
@@ -85,7 +87,9 @@ public class ChapterUtils {
in = new CountingInputStream(context.getContentResolver().openInputStream(uri));
} else {
URL url = new URL(p.getStreamUrl());
- in = new CountingInputStream(url.openStream());
+ URLConnection urlConnection = url.openConnection();
+ urlConnection.setRequestProperty("User-Agent", ClientConfig.USER_AGENT);
+ in = new CountingInputStream(urlConnection.getInputStream());
}
List<Chapter> chapters = readChaptersFrom(in);
if (!chapters.isEmpty()) {
@@ -159,7 +163,9 @@ public class ChapterUtils {
input = context.getContentResolver().openInputStream(uri);
} else {
URL url = new URL(media.getStreamUrl());
- input = url.openStream();
+ URLConnection urlConnection = url.openConnection();
+ urlConnection.setRequestProperty("User-Agent", ClientConfig.USER_AGENT);
+ input = urlConnection.getInputStream();
}
if (input != null) {
readOggChaptersFromInputStream(media, input);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java b/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java
index 220a783f3..2a387b7b0 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java
@@ -4,6 +4,7 @@ import android.text.TextUtils;
import androidx.annotation.VisibleForTesting;
import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
@@ -29,6 +30,7 @@ public class FileNameGenerator {
* characters of the given string.
*/
public static String generateFileName(String string) {
+ string = StringUtils.stripAccents(string);
StringBuilder buf = new StringBuilder();
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java b/core/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java
index ebde1e412..a45136432 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java
@@ -6,6 +6,7 @@ package de.danoeh.antennapod.core.util;
public class InvalidFeedException extends Exception {
private static final long serialVersionUID = 1L;
- public InvalidFeedException() {
+ public InvalidFeedException(String message) {
+ super(message);
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java
index 366f86707..813c6d0f7 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java
@@ -39,7 +39,7 @@ public class RewindAfterPauseUtils {
int newPosition = currentPosition - (int) rewindTime;
- return newPosition > 0 ? newPosition : 0;
+ return Math.max(newPosition, 0);
} else {
return currentPosition;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
index e1dffef97..ac7f4848c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
@@ -41,7 +41,7 @@ public final class URLChecker {
String lowerCaseUrl = url.toLowerCase(); // protocol names are case insensitive
if (lowerCaseUrl.startsWith("feed://")) {
if (BuildConfig.DEBUG) Log.d(TAG, "Replacing feed:// with http://");
- return url.replaceFirst("feed://", "http://");
+ return prepareURL(url.substring("feed://".length()));
} else if (lowerCaseUrl.startsWith("pcast://")) {
if (BuildConfig.DEBUG) Log.d(TAG, "Removing pcast://");
return prepareURL(url.substring("pcast://".length()));
@@ -50,7 +50,7 @@ public final class URLChecker {
return prepareURL(url.substring("pcast:".length()));
} else if (lowerCaseUrl.startsWith("itpc")) {
if (BuildConfig.DEBUG) Log.d(TAG, "Replacing itpc:// with http://");
- return url.replaceFirst("itpc://", "http://");
+ return prepareURL(url.substring("itpc://".length()));
} else if (lowerCaseUrl.startsWith(AP_SUBSCRIBE)) {
if (BuildConfig.DEBUG) Log.d(TAG, "Removing antennapod-subscribe://");
return prepareURL(url.substring(AP_SUBSCRIBE.length()));
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java b/core/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java
index 8bd23c2ed..920a1ef8a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java
@@ -8,13 +8,7 @@ public class ChapterStartTimeComparator implements Comparator<Chapter> {
@Override
public int compare(Chapter lhs, Chapter rhs) {
- if (lhs.getStart() == rhs.getStart()) {
- return 0;
- } else if (lhs.getStart() < rhs.getStart()) {
- return -1;
- } else {
- return 1;
- }
+ return Long.compare(lhs.getStart(), rhs.getStart());
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java
index 991089910..a8ca43ccb 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java
@@ -118,9 +118,8 @@ public class AutoUpdateManager {
*/
public static void runImmediate(@NonNull Context context) {
Log.d(TAG, "Run auto update immediately in background.");
- new Thread(() -> {
- DBTasks.refreshAllFeeds(context.getApplicationContext(), true);
- }, "ManualRefreshAllFeeds").start();
+ new Thread(() -> DBTasks.refreshAllFeeds(
+ context.getApplicationContext(), true), "ManualRefreshAllFeeds").start();
}
public static void disableAutoUpdate(Context context) {
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 4b3ffa389..aec53da4c 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
@@ -6,6 +6,7 @@ import android.preference.PreferenceManager;
import android.util.Log;
import android.view.SurfaceHolder;
+import de.danoeh.antennapod.core.ClientConfig;
import org.antennapod.audio.MediaPlayer;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -17,7 +18,7 @@ public class AudioPlayer extends MediaPlayer implements IPlayer {
private static final String TAG = "AudioPlayer";
public AudioPlayer(Context context) {
- super(context);
+ super(context, true, ClientConfig.USER_AGENT);
PreferenceManager.getDefaultSharedPreferences(context)
.registerOnSharedPreferenceChangeListener((sharedPreferences, key) -> {
if (key.equals(UserPreferences.PREF_MEDIA_PLAYER)) {
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 0b849aa1f..d47d26af9 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
@@ -508,6 +508,13 @@ public class PlaybackController {
playbackService.setStartWhenPrepared(true);
playbackService.prepare();
break;
+ default:
+ new PlaybackServiceStarter(activity, media)
+ .startWhenPrepared(true)
+ .streamIfLastWasStream()
+ .start();
+ Log.w(TAG, "Play/Pause button was pressed and PlaybackService state was unknown");
+ break;
}
}
@@ -592,6 +599,13 @@ public class PlaybackController {
}
public void setPlaybackSpeed(float speed) {
+ PlaybackPreferences.setCurrentlyPlayingTemporaryPlaybackSpeed(speed);
+ if (getMedia() != null && getMedia().getMediaType() == MediaType.VIDEO) {
+ UserPreferences.setVideoPlaybackSpeed(speed);
+ } else {
+ UserPreferences.setPlaybackSpeed(speed);
+ }
+
if (playbackService != null) {
playbackService.setSpeed(speed);
} else {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java
index cdf171299..9277af6e6 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java
@@ -39,7 +39,7 @@ class OggInputStream extends InputStream {
private void readOggPage() throws IOException {
// find OggS
int[] buffer = new int[4];
- int c = 0;
+ int c;
boolean isInOggS = false;
while ((c = input.read()) != -1) {
switch (c) {
diff --git a/core/src/main/res/color/filter_dialog_background_dark.xml b/core/src/main/res/color/filter_dialog_background_dark.xml
new file mode 100644
index 000000000..3df2a80dc
--- /dev/null
+++ b/core/src/main/res/color/filter_dialog_background_dark.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@color/accent_dark" android:state_checked="true"/>
+ <item android:color="@color/dialog_filter_inactive_dark" />
+</selector> \ No newline at end of file
diff --git a/core/src/main/res/color/filter_dialog_background_light.xml b/core/src/main/res/color/filter_dialog_background_light.xml
new file mode 100644
index 000000000..930325629
--- /dev/null
+++ b/core/src/main/res/color/filter_dialog_background_light.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@color/accent_light" android:state_checked="true" />
+ <item android:color="@color/dialog_filter_inactive_light" />
+</selector> \ No newline at end of file
diff --git a/core/src/main/res/color/filter_dialog_button_text.xml b/core/src/main/res/color/filter_dialog_button_text.xml
new file mode 100644
index 000000000..fea8b3e74
--- /dev/null
+++ b/core/src/main/res/color/filter_dialog_button_text.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?attr/colorOnSecondary" android:state_checked="true" />
+ <item android:color="?android:textColorPrimary" />
+</selector> \ No newline at end of file
diff --git a/core/src/main/res/color/filter_dialog_clear_dark.xml b/core/src/main/res/color/filter_dialog_clear_dark.xml
new file mode 100644
index 000000000..88e022d0f
--- /dev/null
+++ b/core/src/main/res/color/filter_dialog_clear_dark.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@color/dialog_filter_inactive_dark" android:state_checked="true" />
+ <item android:color="@color/dialog_filter_clear_inactive_dark" />
+</selector> \ No newline at end of file
diff --git a/core/src/main/res/color/filter_dialog_clear_light.xml b/core/src/main/res/color/filter_dialog_clear_light.xml
new file mode 100644
index 000000000..9d513f72a
--- /dev/null
+++ b/core/src/main/res/color/filter_dialog_clear_light.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@color/dialog_filter_inactive_light" android:state_checked="true" />
+ <item android:color="@color/dialog_filter_clear_inactive_light" />
+</selector> \ No newline at end of file
diff --git a/core/src/main/res/drawable/ic_av_skip_black_24dp.xml b/core/src/main/res/drawable/ic_av_skip_black_24dp.xml
new file mode 100644
index 000000000..3ca3734a8
--- /dev/null
+++ b/core/src/main/res/drawable/ic_av_skip_black_24dp.xml
@@ -0,0 +1,7 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+ <path android:fillColor="#FF000000" android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_av_skip_white_24dp.xml b/core/src/main/res/drawable/ic_av_skip_white_24dp.xml
new file mode 100644
index 000000000..9df98de70
--- /dev/null
+++ b/core/src/main/res/drawable/ic_av_skip_white_24dp.xml
@@ -0,0 +1,7 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+ <path android:fillColor="#FFFFFFFF" android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_filter_close.xml b/core/src/main/res/drawable/ic_filter_close.xml
new file mode 100644
index 000000000..9e0a26905
--- /dev/null
+++ b/core/src/main/res/drawable/ic_filter_close.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:bottom="5dp"
+ android:left="5dp"
+ android:right="5dp"
+ android:top="5dp">
+
+ <shape android:shape="oval">
+ <stroke
+ android:width="4dp"
+ android:color="?attr/filter_dialog_clear" />
+ </shape>
+ </item>
+
+ <!-- x -->
+ <item
+ android:bottom="12dp"
+ android:left="12dp"
+ android:right="12dp"
+ android:top="12dp">
+ <rotate
+ android:fromDegrees="135"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:toDegrees="135">
+ <shape android:shape="line">
+ <stroke
+ android:width="4dp"
+ android:color="?attr/filter_dialog_clear" />
+ </shape>
+ </rotate>
+ </item>
+
+ <item
+ android:bottom="12dp"
+ android:left="12dp"
+ android:right="12dp"
+ android:top="12dp">
+ <rotate
+ android:fromDegrees="45"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:toDegrees="45">
+ <shape android:shape="line">
+ <stroke
+ android:width="4dp"
+ android:color="?attr/filter_dialog_clear" />
+ </shape>
+
+ </rotate>
+ </item>
+
+</layer-list> \ No newline at end of file
diff --git a/core/src/main/res/values-ca/strings.xml b/core/src/main/res/values-ca/strings.xml
index 25739cea3..1a72af232 100644
--- a/core/src/main/res/values-ca/strings.xml
+++ b/core/src/main/res/values-ca/strings.xml
@@ -19,7 +19,6 @@
<string name="cancel_download_label">Cancel·la\nBaixada</string>
<string name="playback_history_label">Historial de reproducció</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Sincronitzar amb altres dispositius</string>
<string name="gpodnet_auth_label">Inici de sessió a gpodder.net</string>
<string name="episode_cache_full_title">La memòria cau d\'episodis és plena</string>
<string name="episode_cache_full_message">S\'ha arribat al límit de la memòria cau d\'episodis. Pots incrementar-ne la capacitat a la configuració.</string>
@@ -91,7 +90,6 @@
<item quantity="one">1 dia després d\'acabar</item>
<item quantity="other">%d dies després d\'acabar</item>
</plurals>
- <string name="num_selected_label">%d sel·leccionat</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Marca-ho tot com a llegit</string>
<string name="mark_all_read_msg">S\'han marcat tots els episodis com a llegits</string>
@@ -234,7 +232,6 @@
<string name="storage_pref">Emmagatzematge</string>
<string name="project_pref">Projecte</string>
<string name="queue_label">Cua</string>
- <string name="integrations_label">Integracions</string>
<string name="automation">Automatització</string>
<string name="download_pref_details">Detalls</string>
<string name="import_export_pref">Importa/Exporta</string>
@@ -304,12 +301,8 @@
<string name="pref_gpodnet_logout_toast">Heu sortit de la sessió</string>
<string name="pref_gpodnet_setlogin_information_title">Dades d\'inici de sessió</string>
<string name="pref_gpodnet_setlogin_information_sum">Canvia les dades d\'inici de sessió del vostre compte de gpodder.net</string>
- <string name="pref_gpodnet_sync_changes_title">Sincronitza els canvis ara</string>
<string name="pref_gpodnet_sync_changes_sum">Sincronitza amb gpodder.net les subscripcions i els estats dels episodis.</string>
- <string name="pref_gpodnet_full_sync_title">Sincronitza per complet ara mateix</string>
<string name="pref_gpodnet_full_sync_sum">Sincronitza amb gpodder.net totes les subscripcions i els estats dels episodis.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Darrer intent de sincronització: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Sincronització en marxa</string>
<string name="pref_gpodnet_login_status"><![CDATA[Connectat com a <i>%1$s</i> amb el dispositiu <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Notifica els errors de sincronització</string>
<string name="pref_gpodnet_notifications_sum">Aquest paràmetre no s\'aplica als errors d\'autenticació. </string>
@@ -357,6 +350,7 @@
<string name="search_status_no_results">No s\'ha trobat cap resultat</string>
<string name="search_label">Cerca</string>
<string name="no_results_for_query">No s\'han trobat resultats per \"%1$s\"</string>
+ <!--Synchronization-->
<!--import and export-->
<string name="opml_import_label">Importació d\'OPML</string>
<string name="opml_reader_error">S\'ha produït un error en llegir el document OPML: </string>
@@ -558,4 +552,5 @@
<string name="notification_channel_error">Errors</string>
<string name="notification_channel_error_description">Mostrar si quelcom va malament, per exemple si una baixada o sincronització fallen.</string>
<!--Widget settings-->
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-cs/strings.xml b/core/src/main/res/values-cs/strings.xml
index 577f97d17..01f5ad018 100644
--- a/core/src/main/res/values-cs/strings.xml
+++ b/core/src/main/res/values-cs/strings.xml
@@ -19,7 +19,6 @@
<string name="cancel_download_label">Zrušit stahování</string>
<string name="playback_history_label">Historie přehrávání</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Synchronizovat s ostatními přístroji</string>
<string name="gpodnet_auth_label">Login pro gpodder.net</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>
@@ -212,8 +211,6 @@
<string name="ascending">Vzestupně</string>
<string name="descending">Sestupně</string>
<string name="clear_queue_confirmation_msg">Potvrďte prosím, že chcete vyčistit tuto frontu a VŠECHNY v ní obsažené epizody</string>
- <string name="sort_old_to_new">Od nejstaršího po nejnovější</string>
- <string name="sort_new_to_old">Od nejnovějšího po nejstarší</string>
<string name="time_left_label">Zbývající čas:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Stáhnout modul</string>
@@ -291,12 +288,8 @@
<string name="pref_gpodnet_logout_toast">Úspěšně odhlášeno</string>
<string name="pref_gpodnet_setlogin_information_title">Změna přihlašovacích údajů</string>
<string name="pref_gpodnet_setlogin_information_sum">Změní přihlašovací údaje k vašemu gpodder.net účtu.</string>
- <string name="pref_gpodnet_sync_changes_title">Synchronizovat změny</string>
<string name="pref_gpodnet_sync_changes_sum">Synchronizovat odběr a změny stavu epizody s gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">Plná synchronizace</string>
<string name="pref_gpodnet_full_sync_sum">Synchronizovat všechny odběry a stav epizod s gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Poslední pokus o synchronizaci: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Synchronizace spuštěna</string>
<string name="pref_gpodnet_login_status"><![CDATA[Přihlášen jako <i>%1$s</i> z přístroje <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Zobrazovat upozornění na chyby synchronizace</string>
<string name="pref_gpodnet_notifications_sum">Toto nastavení se netýká chyb přihlášení.</string>
@@ -337,6 +330,7 @@
<string name="search_status_no_results">Žádné výsledky</string>
<string name="search_label">Vyhledat</string>
<string name="no_results_for_query">Nebyly nalezeny žádné výsledky pro \"%1$s\"</string>
+ <!--Synchronization-->
<!--import and export-->
<string name="opml_import_label">OPML import</string>
<string name="opml_reader_error">Došlo k chybě při čtení OPML dokumentu:</string>
@@ -535,4 +529,5 @@
<!--Notification channels-->
<string name="notification_channel_downloading">Stahuji</string>
<!--Widget settings-->
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-da/strings.xml b/core/src/main/res/values-da/strings.xml
index f53f37ab5..479492a7f 100644
--- a/core/src/main/res/values-da/strings.xml
+++ b/core/src/main/res/values-da/strings.xml
@@ -20,7 +20,6 @@
<string name="cancel_download_label">Annuller\noverførsel</string>
<string name="playback_history_label">Afspilningshistorik</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Synkronisér med andre enheder</string>
<string name="gpodnet_auth_label">Login til gpodder.net</string>
<string name="episode_cache_full_title">Mellemlageret for udsendelser er fuldt</string>
<string name="episode_cache_full_message">Der er ikke mere plads i mellemlageret for udsendelser. Du kan øge størrelsen på mellemlageret i Indstillinger.</string>
@@ -86,7 +85,7 @@
<string name="auto_download_apply_to_items_message">Den nye <i>Automatisk overførsel</i>-indstilling vil automatisk blive anvendt på nye udsendelser.\nVil du også anvende den på tidligere udsendelser?</string>
<string name="auto_delete_label">Slet udsendelser automatisk</string>
<string name="feed_volume_reduction">Lydstyrkereduktion</string>
- <string name="feed_volume_reduction_summary">Skru ned for lydstyrken for udsendelser i dette feed: \%s</string>
+ <string name="feed_volume_reduction_summary">Skru lyd ned for episoder i dette feed</string>
<string name="feed_volume_reduction_off">Fra</string>
<string name="feed_volume_reduction_light">Lidt</string>
<string name="feed_volume_reduction_heavy">Meget</string>
@@ -106,7 +105,10 @@
<item quantity="one">1 dag efter færdig afspilning</item>
<item quantity="other">%d dage efter færdig afspilning</item>
</plurals>
- <string name="num_selected_label">%d valgt</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">%d valgt</item>
+ <item quantity="other">%d valgte</item>
+ </plurals>
<string name="loading_more">Indlæser mere ...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Marker alle som afspillet</string>
@@ -127,11 +129,13 @@
<string name="share_link_with_position_label">Del webadresse for udsendelse med position</string>
<string name="share_file_label">Del fil</string>
<string name="share_website_url_label">Del webstedets adresse</string>
+ <string name="share_feed_url_label">Del podcast URL</string>
<string name="share_item_url_label">Del webadresse for mediefil</string>
<string name="share_item_url_with_position_label">Del webadresse for mediefil med position</string>
<string name="feed_delete_confirmation_msg">Bekræft venligst at du ønsker at slette podcasten \"%1$s\" og ALLE dens udsendelser (inklusive overførte udsendelser)</string>
<string name="feed_remover_msg">Fjerner podcast</string>
<string name="load_complete_feed">Opdater komplet podcast</string>
+ <string name="multi_select">Vælg flere</string>
<string name="select_all_above">Vælg alt ovenfor</string>
<string name="select_all_below">Vælg alt nedenfor</string>
<string name="hide_unplayed_episodes_label">Uafspillede</string>
@@ -146,6 +150,7 @@
<string name="filtered_label">Filtrerede</string>
<string name="refresh_failed_msg">{fa-exclamation-circle} Sidste opdatering fejlede</string>
<string name="open_podcast">Åbn podcast</string>
+ <string name="please_wait_for_data">Vær venlig og vent til data\'et er indlæst</string>
<!--actions on feeditems-->
<string name="download_label">Hent</string>
<plurals name="downloading_batch_label">
@@ -168,6 +173,7 @@
<string name="marked_as_read_label">Markeret som afspillet</string>
<string name="mark_read_no_media_label">Marker som læst</string>
<string name="marked_as_read_no_media_label">Markeret som læst</string>
+ <string name="play_this_to_seek_position">Skift til position, du bliver nødt til at afspille episode</string>
<plurals name="marked_read_batch_label">
<item quantity="one">%d udsendelse markeret som afspillet.</item>
<item quantity="other">%d udsendelser markeret som afspillet.</item>
@@ -199,6 +205,7 @@
<string name="deactivate_auto_download">Slå Automatisk overførsel fra</string>
<string name="reset_position">Nulstil afspilningsposition</string>
<string name="removed_item">Element fjernet</string>
+ <string name="no_items_selected">Intet valgte</string>
<!--Download messages and labels-->
<string name="download_successful">lykkedes</string>
<string name="download_pending">Afventer overførsel</string>
@@ -236,6 +243,7 @@
<string name="download_type_feed">Feed</string>
<string name="download_type_media">Mediefil</string>
<string name="download_request_error_dialog_message_prefix">En fejl opstod ved overførsel af filen:\u0020</string>
+ <string name="null_value_podcast_error">Kan ikke vises. Ingen podcast angivet.</string>
<string name="authentication_notification_title">Godkendelse kræves</string>
<string name="authentication_notification_msg">Ressourcen du efterspurgte kræver brugernavn og adgangskode</string>
<string name="confirm_mobile_download_dialog_title">Bekræft brug af mobildata</string>
@@ -267,6 +275,7 @@
<string name="unlock_queue">Lås kø op</string>
<string name="queue_locked">Kø låst</string>
<string name="queue_unlocked">Kø låst op</string>
+ <string name="queue_lock_warning">Hvis du låser køen, kan du ikke swipe eller flytte rundt på episoder.</string>
<string name="checkbox_do_not_show_again">Vis ikke igen</string>
<string name="clear_queue_label">Ryd kø</string>
<string name="undo">Fortryd</string>
@@ -283,8 +292,6 @@
<string name="ascending">Stigende</string>
<string name="descending">Faldende</string>
<string name="clear_queue_confirmation_msg">Bekræft venligst at du vil rydde ALLE udsendelser fra køen</string>
- <string name="sort_old_to_new">Gamle til nye</string>
- <string name="sort_new_to_old">Nye til gamle</string>
<string name="time_left_label">Tid tilbage:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Hent plugin</string>
@@ -293,29 +300,38 @@
<string name="enable_sonic">Slå Sonic til</string>
<!--Empty list labels-->
<string name="no_items_header_label">Ingen udsendelser i køen</string>
+ <string name="no_items_label">Tilføj en episode ved at downloade den, eller lang tryk på episoden og klik \"Tilføj til afspilningsliste\"</string>
<string name="no_shownotes_label">Denne udsendelse har ingen beskrivelse.</string>
<string name="no_run_downloads_head_label">Ingen overførsler i gang</string>
+ <string name="no_run_downloads_label">Du kan downloade episode ved podcastens beskrivelse</string>
<string name="no_comp_downloads_head_label">Ingen overførte udsendelser</string>
<string name="no_log_downloads_head_label">Ingen overførselslog</string>
+ <string name="no_log_downloads_label">Download raport vil blive vist her når muligt</string>
<string name="no_history_head_label">Ingen historik</string>
+ <string name="no_history_label">Når du har hørt en episode, vil den blive vist her.</string>
<string name="no_all_episodes_head_label">Ingen udsendelser</string>
<string name="no_all_episodes_label">Når du tilføjer en podcast, vil udsendelserne blive vist her.</string>
+ <string name="no_new_episodes_head_label">Ingen nye episoder</string>
<string name="no_new_episodes_label">Når nye udsendelser ankommer, vil de blive vist her.</string>
<string name="no_fav_episodes_head_label">Ingen foretrukne udsendelser</string>
<string name="no_fav_episodes_label">Du kan føje udsendelser til foretrukne ved at trykke længe på dem</string>
<string name="no_chapters_head_label">Ingen kapitler</string>
<string name="no_chapters_label">Denne udsendelse har ingen kapitler.</string>
<string name="no_subscriptions_head_label">Ingen abonnementer</string>
+ <string name="no_subscriptions_label">For at abonnere på en podcast, klik plus ikonet nedenfor</string>
<!--Preferences-->
<string name="storage_pref">Lagring</string>
+ <string name="storage_sum">Automatisk sletning, Importer, Exporter af episoder</string>
<string name="project_pref">Projekt</string>
<string name="queue_label">Kø</string>
- <string name="integrations_label">Integrerede tjenester</string>
+ <string name="synchronization_pref">synkronisering</string>
+ <string name="synchronization_sum">Synkroniser med andre enheder ved hjælp af gpodder.net</string>
<string name="automation">Automatisering</string>
<string name="download_pref_details">Detaljer</string>
<string name="import_export_pref">Import/eksport</string>
<string name="import_export_search_keywords">sikkerhedskopiering, sikkerhedskopi, backup, gendan, gendannelse, restore</string>
<string name="appearance">Udseende</string>
+ <string name="external_elements">Externe elementer</string>
<string name="interruptions">Afbrydelser</string>
<string name="preference_search_hint">Søg...</string>
<string name="preference_search_no_results">Ingen resultater</string>
@@ -353,6 +369,8 @@
<string name="pref_unpauseOnBluetoothReconnect_title">Bluetooth forbundet igen</string>
<string name="pref_stream_over_download_title">Foretræk streaming</string>
<string name="pref_mobileUpdate_title">Mobile opdateringer</string>
+ <string name="pref_mobileUpdate_refresh">Opdatere podcast</string>
+ <string name="pref_mobileUpdate_images">Omslag billeder</string>
<string name="pref_mobileUpdate_auto_download">Hent automatisk</string>
<string name="pref_mobileUpdate_episode_download">Download af udsendelser</string>
<string name="pref_mobileUpdate_streaming">Streaming</string>
@@ -372,6 +390,7 @@
<string name="pref_automatic_download_on_battery_sum">Tillad automatisk overførsel, når batteriet ikke oplades</string>
<string name="pref_parallel_downloads_title">Parallelle overførsler</string>
<string name="pref_episode_cache_title">Mellemlager for udsendelser</string>
+ <string name="pref_episode_cover_title">Brug afsnit omslag</string>
<string name="pref_theme_title_use_system">Brug systemtema</string>
<string name="pref_theme_title_light">Lys</string>
<string name="pref_theme_title_dark">Mørk</string>
@@ -386,17 +405,15 @@
<string name="pref_gpodnet_logout_toast">Loggede ud</string>
<string name="pref_gpodnet_setlogin_information_title">Ændr loginoplysninger</string>
<string name="pref_gpodnet_setlogin_information_sum">Ændr din gpodder.net-kontos loginoplysninger.</string>
- <string name="pref_gpodnet_sync_changes_title">Synkroniser ændringer nu</string>
+ <string name="pref_gpodnet_sync_changes_title">Synkroniser nu</string>
<string name="pref_gpodnet_sync_changes_sum">Synkroniser tilstandsændringer for abonnementer og udsendelser med gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">Fuld synkronisering nu</string>
<string name="pref_gpodnet_full_sync_sum">Synkroniser tilstande for alle abonnementer og udsendelser med gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Sidste synkroniseringsforsøg: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Synkronisering startet</string>
<string name="pref_gpodnet_login_status"><![CDATA[Logget ind som <i>%1$s</i> med enheden <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Vis notifikationer med synkroniseringsfejl</string>
<string name="pref_gpodnet_notifications_sum">Denne indstilling vedrører ikke godkendelsesfejl.</string>
<string name="pref_playback_speed_title">Afspilningshastigheder</string>
<string name="pref_playback_speed_sum">Tilpas tilgængelige hastigheder for lydafspilning med variabel hastighed</string>
+ <string name="pref_feed_skip">Overspring automatisk</string>
<string name="pref_fast_forward">Tidshop for fremadspoling</string>
<string name="pref_fast_forward_sum">Indstil antallet af sekunder, der skal springes fremad, når der trykkes på fremadspolingsknappen</string>
<string name="pref_rewind">Tidshop for tilbagespoling</string>
@@ -426,8 +443,10 @@
<string name="pref_smart_mark_as_played_disabled">Slået fra</string>
<string name="pref_image_cache_size_title">Størrelse på mellemlager (cache) for billeder</string>
<string name="pref_image_cache_size_sum">Størrelse på diskmellemlageret (disk cache) for billeder</string>
+ <string name="visit_user_forum">Bruger froum</string>
<string name="bug_report_title">Rapportér fejl i appen</string>
<string name="open_bug_tracker">Åbn programfejlsdatabase</string>
+ <string name="export_logs">Eksportere log</string>
<string name="copy_to_clipboard">Kopier til udklipsholder</string>
<string name="copied_to_clipboard">Kopieret til udklipsholder</string>
<string name="experimental_pref">Eksperimentelt</string>
@@ -441,6 +460,8 @@
<string name="pref_enqueue_downloaded_title">Sæt overførte udsendelser i kø</string>
<string name="pref_enqueue_downloaded_summary">Føj downloadede udsendelser til køen</string>
<string name="media_player_builtin">Indbygget Android-afspiller</string>
+ <string name="media_player_switch_to_exoplayer">Skift til ExoPlayer</string>
+ <string name="media_player_switched_to_exoplayer">Skiftet til ExoPlayer.</string>
<string name="pref_videoBehavior_title">Når videoen forlades</string>
<string name="pref_videoBehavior_sum">Opførsel når videoafspilning forlades</string>
<string name="stop_playback">Stop afspilning</string>
@@ -458,12 +479,22 @@
<string name="back_button_go_to_page_title">Vælg side</string>
<!--About screen-->
<string name="about_pref">Om</string>
+ <string name="antennapod_version">AntennaPod version</string>
+ <string name="developers">Udviklere</string>
<string name="translators">Oversættere</string>
+ <string name="privacy_policy">Privatlivspolitik</string>
+ <string name="licenses">Licenser</string>
<!--Search-->
<string name="search_status_no_results">Fandt ingen resultater</string>
<string name="search_label">Søg</string>
<string name="no_results_for_query">Ingen resultater fundet for \"%1$s\"</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">Synkronisering startet</string>
+ <string name="sync_status_error">Synkronisering mislykkedes</string>
<!--import and export-->
+ <string name="database">Database</string>
+ <string name="opml">OPML</string>
+ <string name="html">HTML</string>
<string name="opml_import_label">OPML-import</string>
<string name="opml_reader_error">Der opstod en fejl, da OPML-dokumentet blev forsøgt indlæst</string>
<string name="opml_import_error_no_file">Ingen fil valgt!</string>
@@ -471,6 +502,9 @@
<string name="deselect_all_label">Fravælg alle</string>
<string name="opml_export_label">OPML eksport</string>
<string name="html_export_label">HTML-eksport</string>
+ <string name="database_export_label">Eksportere database</string>
+ <string name="database_import_label">Importere database</string>
+ <string name="please_wait">Vent...</string>
<string name="export_error_label">Eksportfejl</string>
<string name="export_success_title">Eksport lykkedes</string>
<string name="export_success_sum">Den eksporterede fil blev skrevet til:\n\n%1$s</string>
@@ -482,6 +516,7 @@
<string name="disable_sleeptimer_label">Slå søvntimer fra</string>
<string name="sleep_timer_label">Søvn timer</string>
<string name="time_dialog_invalid_input">Ugyldig indtastning: tid skal være et heltal</string>
+ <string name="shake_to_reset_label">Ryst for at nulstille</string>
<string name="time_seconds">sekunder</string>
<string name="time_minutes">minutter</string>
<string name="time_hours">timer</string>
@@ -556,9 +591,13 @@
<!--Online feed view-->
<string name="subscribe_label">Abonner</string>
<string name="subscribing_label">Abonnerer ...</string>
+ <string name="preview_episode">Forhåndsvisning</string>
+ <string name="stop_preview">Stop forhåndsvisning</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Spol tilbage</string>
<string name="fast_forward_label">Spol frem</string>
+ <string name="increase_speed">Øg hastighed</string>
+ <string name="decrease_speed">Mindsk hastighed</string>
<string name="media_type_audio_label">Lyd</string>
<string name="media_type_video_label">Video</string>
<string name="navigate_upwards_label">Naviger opad</string>
@@ -566,6 +605,8 @@
<string name="in_queue_label">Udsendelse er i køen</string>
<string name="drag_handle_content_description">Træk for at ændre dette elements placering</string>
<string name="load_next_page_label">Indlæs næste side</string>
+ <string name="switch_pages">Skift sider</string>
+ <string name="apply_action">Anvend handling</string>
<!--Feed information screen-->
<string name="authentication_label">Godkendelse</string>
<string name="authentication_descr">Ændr dit brugernavn og adgangskode for denne podcast og dens udsendelser.</string>
@@ -584,6 +625,7 @@
<string name="search_podcast_hint">Søg efter podcast ...</string>
<string name="search_itunes_label">Søg i iTunes</string>
<string name="search_fyyd_label">Søg i fyyd</string>
+ <string name="advanced">Avanceret</string>
<string name="browse_gpoddernet_label">Gennemse gpodder.net</string>
<string name="discover">Opdag</string>
<string name="discover_more">mere »</string>
@@ -614,6 +656,12 @@
<string name="sort_date_old_new">Dato (gammel \u2192 ny)</string>
<string name="sort_duration_short_long">Varighed (kort \u2192 lang)</string>
<string name="sort_duration_long_short">Varighed (lang \u2192 kort)</string>
+ <string name="sort_a_z">A \u2192 Z</string>
+ <string name="sort_z_a">Z \u2192 A</string>
+ <string name="sort_new_old">Ny \u2192 Gammel</string>
+ <string name="sort_old_new">Gammel \u2192 Ny</string>
+ <string name="sort_short_long">Kort \u2192 Lang</string>
+ <string name="sort_long_short">Lang \u2192 Kort</string>
<!--Rating dialog-->
<string name="rating_title">Kan du lide AntennaPod?</string>
<string name="rating_message">Vi vil sætte pris på, hvis du vil bedømme AntennaPod.</string>
@@ -629,6 +677,7 @@
<string name="audio_effects">Lydeffekter</string>
<string name="stereo_to_mono">Gør stereo til mono</string>
<string name="sonic_only">Kun Sonic</string>
+ <string name="exoplayer_only">Kun ExoPlayer</string>
<!--proxy settings-->
<string name="proxy_type_label">Type</string>
<string name="host_label">Vært</string>
@@ -642,6 +691,7 @@
<string name="proxy_host_invalid_error">Vært er ikke en gyldig IP-adresse eller et gyldigt domæne</string>
<string name="proxy_port_invalid_error">Port ikke gyldig</string>
<!--Subscriptions fragment-->
+ <string name="subscription_num_columns">Antal kolonner</string>
<!--Casting-->
<string name="cast_media_route_menu_title">Afspil på …</string>
<string name="cast_disconnect_label">Afbryd cast-sessionen</string>
@@ -662,6 +712,10 @@
<string name="notification_channel_downloading_description">Vises samtidig med den hentes.</string>
<string name="notification_channel_playing">Spiller nu</string>
<string name="notification_channel_error">Fejl</string>
+ <string name="notification_channel_auto_download">Automatisk hentninger</string>
<!--Widget settings-->
+ <string name="widget_settings">Kontrol opsætning</string>
+ <string name="widget_create_button">Opret kontrol</string>
<string name="widget_opacity">Ugennemsigtighed</string>
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-de/strings.xml b/core/src/main/res/values-de/strings.xml
index f2dbc5f5b..2ba6a9d72 100644
--- a/core/src/main/res/values-de/strings.xml
+++ b/core/src/main/res/values-de/strings.xml
@@ -20,7 +20,6 @@
<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_summary">Mit anderen Geräten synchronisieren</string>
<string name="gpodnet_auth_label">gpodder.net Anmeldung</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>
@@ -86,7 +85,7 @@
<string name="auto_download_apply_to_items_message">Die neue <i>Auto-Download</i>-Einstellung wird automatisch auf neue Episoden angewandt.\nMöchtest du sie auch auf schon veröffentlichte Episoden anwenden?</string>
<string name="auto_delete_label">Episode automatisch löschen</string>
<string name="feed_volume_reduction">Lautstärke reduzieren</string>
- <string name="feed_volume_reduction_summary">Lautstärke reduzieren für Episoden aus diesem Feed: %s</string>
+ <string name="feed_volume_reduction_summary">Lautstärke reduzieren für Episoden aus diesem Podcast: %1$s</string>
<string name="feed_volume_reduction_off">Aus</string>
<string name="feed_volume_reduction_light">Schwach</string>
<string name="feed_volume_reduction_heavy">Stark</string>
@@ -106,7 +105,10 @@
<item quantity="one">1 Tag nachdem fertig gespielt</item>
<item quantity="other">%d Tage nachdem fertig gespielt</item>
</plurals>
- <string name="num_selected_label">%d ausgewählt</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">%d ausgewählt</item>
+ <item quantity="other">%d ausgewählt</item>
+ </plurals>
<string name="loading_more">Lade mehr...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Alle als gespielt markieren</string>
@@ -203,6 +205,7 @@
<string name="deactivate_auto_download">Automatischen Download deaktivieren</string>
<string name="reset_position">Wiedergabe-Position zurücksetzen</string>
<string name="removed_item">Element entfernt</string>
+ <string name="no_items_selected">Keine Einträge ausgewählt</string>
<!--Download messages and labels-->
<string name="download_successful">erfolgreich</string>
<string name="download_pending">Download anstehend</string>
@@ -266,6 +269,7 @@
<string name="player_buffering_msg">Puffert</string>
<string name="player_go_to_picture_in_picture">Bild-in-Bild-Modus</string>
<string name="unknown_media_key">AntennaPod - Unbekannte Medientaste: %1$d</string>
+ <string name="error_file_not_found">Datei nicht gefunden</string>
<!--Queue operations-->
<string name="lock_queue">Warteschlange sperren</string>
<string name="unlock_queue">Warteschlange entsperren</string>
@@ -288,8 +292,6 @@
<string name="ascending">Aufsteigend</string>
<string name="descending">Absteigend</string>
<string name="clear_queue_confirmation_msg">Bitte bestätige, dass ALLE Episoden aus der Warteschlange entfernt werden sollen</string>
- <string name="sort_old_to_new">Alt zu neu</string>
- <string name="sort_new_to_old">Neu zu alt</string>
<string name="time_left_label">Zeit übrig:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Plugin herunterladen</string>
@@ -324,8 +326,8 @@
<string name="storage_sum">Automatisches Löschen von Episoden, Importieren, Exportieren</string>
<string name="project_pref">Projekt</string>
<string name="queue_label">Warteschlange</string>
- <string name="integrations_label">Einbindungen</string>
- <string name="integrations_sum">Synchronisierung</string>
+ <string name="synchronization_pref">Synchronisation</string>
+ <string name="synchronization_sum">Synchronisiere über gpodder.net mit anderen Geräten</string>
<string name="automation">Automatisierung</string>
<string name="download_pref_details">Details</string>
<string name="import_export_pref">Import/Export</string>
@@ -416,18 +418,22 @@
<string name="pref_gpodnet_logout_toast">Abmeldung war erfolgreich</string>
<string name="pref_gpodnet_setlogin_information_title">Anmeldeinformationen ändern</string>
<string name="pref_gpodnet_setlogin_information_sum">Ändere die Anmeldeinformationen deines gpodder.net Profils</string>
- <string name="pref_gpodnet_sync_changes_title">Jetzt Änderungen synchronisieren</string>
+ <string name="pref_gpodnet_sync_changes_title">Jetzt synchronisieren</string>
<string name="pref_gpodnet_sync_changes_sum">Änderungen an Abonnement- und Episoden-Status mit gpodder.net synchronisieren.</string>
- <string name="pref_gpodnet_full_sync_title">Jetzt komplett synchronisieren</string>
+ <string name="pref_gpodnet_full_sync_title">Komplette Synchronisation erzwingen</string>
<string name="pref_gpodnet_full_sync_sum">Kompletten Abonnement- und Episoden-Status mit gpodder.net synchronisieren.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Letzter Synchronisierungsversuch: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Synchronisation gestartet</string>
<string name="pref_gpodnet_login_status"><![CDATA[Eingeloggt als <i>%1$s</i> mit dem Gerät <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Zeige Benachrichtungen bei Synchronisierungsfehlern</string>
<string name="pref_gpodnet_notifications_sum">Diese Einstellung gilt nicht für Authentifizierungsfehler.</string>
<string name="pref_playback_speed_title">Wiedergabegeschwindigkeiten</string>
<string name="pref_playback_speed_sum">Lege die verfügbaren Werte für die Veränderung der Wiedergabeschwindigkeit fest</string>
<string name="pref_feed_playback_speed_sum">Abspielgeschwindigkeit für Episoden dieses Podcasts</string>
+ <string name="pref_feed_skip">Automatisches Überspringen</string>
+ <string name="pref_feed_skip_sum">Einleitung und Ende überspringen.</string>
+ <string name="pref_feed_skip_ending">Ende überspringen</string>
+ <string name="pref_feed_skip_intro">Anfang überspringen</string>
+ <string name="pref_feed_skip_ending_toast">Letzte %d Sekunden übersprungen</string>
+ <string name="pref_feed_skip_intro_toast">Erste %d Sekunden übersprungen</string>
<string name="pref_playback_time_respects_speed_title">Medieninfo an Abspielgeschwindigkeit anpassen</string>
<string name="pref_playback_time_respects_speed_sum">Abspielposition und Dauer werden auf Abspielgeschwindigkeit angepasst</string>
<string name="pref_fast_forward">Vorspulzeit</string>
@@ -448,6 +454,8 @@
<string name="pref_lockscreen_background_sum">Verwende das aktuelle Episodenbild als Lockscreen-Hintergrund. Es wird als Nebeneffekt auch in anderen Apps gezeigt.</string>
<string name="pref_showDownloadReport_title">Zeige Download-Bericht</string>
<string name="pref_showDownloadReport_sum">Wenn Downloads fehlschlagen, erstelle einen Bericht, der die Details des Fehlschlages beschreibt.</string>
+ <string name="pref_showAutoDownloadReport_title">Zeige Bericht über Automatische Downloads</string>
+ <string name="pref_showAutoDownloadReport_sum">Zeige eine Benachrichtigung für automatisch heruntergeladene Episoden.</string>
<string name="pref_expand_notify_unsupport_toast">Android-Versionen vor 4.1 unterstützen keine erweiterten Benachrichtigungen.</string>
<string name="pref_enqueue_location_title">Position beim Einreihen</string>
<string name="pref_enqueue_location_sum">Füge Episoden %1$s hinzu</string>
@@ -476,6 +484,8 @@
<string name="pref_enqueue_downloaded_title">Downloads einreihen</string>
<string name="pref_enqueue_downloaded_summary">Füge heruntergeladene Episoden zur Warteschlange hinzu</string>
<string name="media_player_builtin">Androids eingebauter Abspieler</string>
+ <string name="media_player_switch_to_exoplayer">Zu ExoPlayer wechseln</string>
+ <string name="media_player_switched_to_exoplayer">Zu ExoPlayer gewechselt.</string>
<string name="pref_skip_silence_title">Stille im Ton überspringen</string>
<string name="pref_videoBehavior_title">Beim Beenden von Videos</string>
<string name="pref_videoBehavior_sum">Verhalten beim Verlassen der Video-Wiedergabe</string>
@@ -508,6 +518,14 @@
<string name="search_status_no_results">Keine Ergebnisse gefunden</string>
<string name="search_label">Suchen</string>
<string name="no_results_for_query">Es wurden keine Ergebnisse für \"%1$s\" gefunden</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">Synchronisation gestartet</string>
+ <string name="sync_status_episodes_upload">Lade Episoden-Änderungen hoch…</string>
+ <string name="sync_status_episodes_download">Lade Episoden-Änderungen herunter…</string>
+ <string name="sync_status_upload_played">Lade Abspiel-Status hoch…</string>
+ <string name="sync_status_subscriptions">Synchronisiere Abonnements…</string>
+ <string name="sync_status_success">Synchronisation erfolgreich</string>
+ <string name="sync_status_error">Synchronisation fehlgeschlagen</string>
<!--import and export-->
<string name="import_export_summary">Abonnements und Warteschlange auf ein anderes Gerät übertragen</string>
<string name="database">Datenbank</string>
@@ -527,6 +545,7 @@
<string name="html_export_label">HTML Export</string>
<string name="database_export_label">Datenbank exportieren</string>
<string name="database_import_label">Datenbank importieren</string>
+ <string name="database_import_warning">Das Importieren einer Datenbank ersetzt alle Abonnements und abgespielte Episoden. Ein Export als Backup wird empfohlen. Möchtest du die Datenbank wirklich ersetzen?</string>
<string name="please_wait">Bitte warten...</string>
<string name="export_error_label">Exportfehler</string>
<string name="export_success_title">Export erfolgreich</string>
@@ -618,16 +637,23 @@
<string name="subscribe_label">Abonnieren</string>
<string name="subscribing_label">Abonniere…</string>
<string name="preview_episode">Vorschau</string>
+ <string name="stop_preview">Vorschau stoppen</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Zurückspulen</string>
<string name="fast_forward_label">Vorspulen</string>
+ <string name="increase_speed">Geschwindigkeit erhöhen</string>
+ <string name="decrease_speed">Geschwindigkeit reduzieren</string>
<string name="media_type_audio_label">Audio</string>
<string name="media_type_video_label">Video</string>
<string name="navigate_upwards_label">Nach oben navigieren</string>
<string name="status_downloading_label">Episode wird heruntergeladen</string>
<string name="in_queue_label">Episode befindet sich in der Warteschlange</string>
+ <string name="is_favorite_label">Episode ist als Favorit markiert</string>
<string name="drag_handle_content_description">Ziehe, um die Position dieses Objekts zu verändern</string>
<string name="load_next_page_label">Nächste Seite laden</string>
+ <string name="switch_pages">Seiten wechseln</string>
+ <string name="position">Position: %1$s</string>
+ <string name="apply_action">Aktion anwenden</string>
<!--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>
@@ -648,10 +674,12 @@
<string name="search_podcast_hint">Podcast suchen…</string>
<string name="search_itunes_label">iTunes durchsuchen</string>
<string name="search_fyyd_label">fyyd durchsuchen</string>
+ <string name="advanced">Fortgeschritten</string>
<string name="add_podcast_by_url">Podcast über URL hinzufügen</string>
<string name="browse_gpoddernet_label">gpodder.net durchsuchen</string>
<string name="discover">Entdecken</string>
<string name="discover_more">mehr »</string>
+ <string name="search_powered_by">Suche bereitgestellt durch %1$s</string>
<string name="filter">Filtern</string>
<!--Episodes apply actions-->
<string name="all_label">Alle</string>
@@ -679,6 +707,12 @@
<string name="sort_date_old_new">Datum (alt \u2192 neu)</string>
<string name="sort_duration_short_long">Dauer (kurz \u2192 lang)</string>
<string name="sort_duration_long_short">Dauer (lang \u2192 kurz)</string>
+ <string name="sort_a_z">A \u2192 Z</string>
+ <string name="sort_z_a">Z \u2192 A</string>
+ <string name="sort_new_old">Neu \u2192 Alt</string>
+ <string name="sort_old_new">Alt \u2192 Neu</string>
+ <string name="sort_short_long">Kurz \u2192 Lang</string>
+ <string name="sort_long_short">Lang \u2192 Kurz</string>
<!--Rating dialog-->
<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>
@@ -732,8 +766,14 @@
<string name="notification_channel_playing_description">Erlaubt es, die Wiedergabe zu steuern. Dies ist die Hauptbenachrichtigung, die du siehst, während ein Podcast abgespielt wird.</string>
<string name="notification_channel_error">Fehler</string>
<string name="notification_channel_error_description">Wird gezeigt, wenn etwas schief gegangen ist, etwa wenn das Herunterladen oder die gpodder-Synchronisierung fehlschlägt.</string>
+ <string name="notification_channel_auto_download">Automatische Downloads</string>
+ <string name="notification_channel_episode_auto_download">Wird angezeigt, wenn Episoden automatisch heruntergeladen worden sind.</string>
<!--Widget settings-->
<string name="widget_settings">Widget-Einstellungen</string>
<string name="widget_create_button">Widget erstellen</string>
<string name="widget_opacity">Deckkraft</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">Einstellung erfolgreich aktualisiert.</string>
+ <string name="on_demand_config_stream_text">Es sieht so aus als würdest du viel streamen. Möchtest du in Listen den Streamen-Button anzeigen?</string>
+ <string name="on_demand_config_download_text">Es sieht so aus als würdest du viel herunterladen. Möchtest du in Listen den Herunterladen-Button anzeigen?</string>
</resources>
diff --git a/core/src/main/res/values-es/strings.xml b/core/src/main/res/values-es/strings.xml
index 02c221258..b8f1f0b25 100644
--- a/core/src/main/res/values-es/strings.xml
+++ b/core/src/main/res/values-es/strings.xml
@@ -20,7 +20,6 @@
<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_summary">Sincronizar con otros dispositivos</string>
<string name="gpodnet_auth_label">Iniciar sesión en gpodder.net</string>
<string name="episode_cache_full_title">Almacenamiento de episodios completo</string>
<string name="episode_cache_full_message">Se ha alcanzado el límite de almacenamiento de episodios. Puede aumentar el tamaño en opciones.</string>
@@ -86,7 +85,7 @@
<string name="auto_download_apply_to_items_message">La nueva opción <i>descarga automática</i> se aplicará automáticamente a episodios nuevos.\n¿También desea aplicarlo a episodios anteriores?</string>
<string name="auto_delete_label">Borrar episodio automáticamente</string>
<string name="feed_volume_reduction">Reducción de volumen</string>
- <string name="feed_volume_reduction_summary">Bajar el volumen de los episodios de este feed: \%s</string>
+ <string name="feed_volume_reduction_summary">Bajar el volumen para episodios de este feed: %1$s</string>
<string name="feed_volume_reduction_off">Apagado</string>
<string name="feed_volume_reduction_light">Ligero</string>
<string name="feed_volume_reduction_heavy">Fuerte</string>
@@ -106,7 +105,10 @@
<item quantity="one">1 día después de acabar</item>
<item quantity="other">%d días después de acabar</item>
</plurals>
- <string name="num_selected_label">%dseleccionado</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">1%d seleccionado</item>
+ <item quantity="other">%d seleccionado</item>
+ </plurals>
<string name="loading_more">Cargando mas...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Marcar todos como reproducidos</string>
@@ -203,6 +205,7 @@
<string name="deactivate_auto_download">Desactivar descarga automática</string>
<string name="reset_position">Restablecer la posición de reproducción</string>
<string name="removed_item">Elemento elminado</string>
+ <string name="no_items_selected">No hay elementos seleccionados</string>
<!--Download messages and labels-->
<string name="download_successful">exitosa</string>
<string name="download_pending">Descarga pendiente</string>
@@ -289,8 +292,6 @@
<string name="ascending">Ascendente</string>
<string name="descending">Descendente</string>
<string name="clear_queue_confirmation_msg">Confirme que quiere borrar TODOS los episodios de la cola</string>
- <string name="sort_old_to_new">Nuevo a viejo</string>
- <string name="sort_new_to_old">Viejo a nuevo</string>
<string name="time_left_label">Tiempo restante:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Descargar complemento</string>
@@ -325,8 +326,8 @@
<string name="storage_sum">Auto borrar espisodio, Importar, Exportar</string>
<string name="project_pref">Proyecto</string>
<string name="queue_label">Cola</string>
- <string name="integrations_label">Integraciones</string>
- <string name="integrations_sum">Sincronización</string>
+ <string name="synchronization_pref">Sincronización</string>
+ <string name="synchronization_sum">Sincronizar con otros dispositivos usando gpodder.net</string>
<string name="automation">Automatización</string>
<string name="download_pref_details">Detalles</string>
<string name="import_export_pref">Importar/Exportar</string>
@@ -417,18 +418,22 @@
<string name="pref_gpodnet_logout_toast">Ha cerrado la sesión correctamente</string>
<string name="pref_gpodnet_setlogin_information_title">Cambiar información de inicio de sesión</string>
<string name="pref_gpodnet_setlogin_information_sum">Modificar datos de inicio de sesión en gpodder.net.</string>
- <string name="pref_gpodnet_sync_changes_title">Sincronizar cambios ahora</string>
+ <string name="pref_gpodnet_sync_changes_title">Sincronizar ahora</string>
<string name="pref_gpodnet_sync_changes_sum">Sincronizar cambios de suscripción y episodios con gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">Sincronización completa</string>
+ <string name="pref_gpodnet_full_sync_title">Forzar la sincronización completa</string>
<string name="pref_gpodnet_full_sync_sum">Sincronizar todas las suscripciones y episodios con gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Último intento de sincronización: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Sincronización iniciada</string>
<string name="pref_gpodnet_login_status"><![CDATA[Identificado como <i>%1$s</i> con dispositivo <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Mostrar errores de sincronización</string>
<string name="pref_gpodnet_notifications_sum">Este ajuste no afecta a los errores de autenticación.</string>
<string name="pref_playback_speed_title">Velocidades de reproducción</string>
<string name="pref_playback_speed_sum">Personalice las velocidades disponibles en la reproducción de audio a velocidad variable</string>
<string name="pref_feed_playback_speed_sum">La velocidad a la que comenzarán los episodios de este podcast</string>
+ <string name="pref_feed_skip">Saltar automático</string>
+ <string name="pref_feed_skip_sum">Saltar introducción y créditos finales.</string>
+ <string name="pref_feed_skip_ending">Saltar los últimos</string>
+ <string name="pref_feed_skip_intro">Saltar episodio</string>
+ <string name="pref_feed_skip_ending_toast">Saltados los últimos %d segundos</string>
+ <string name="pref_feed_skip_intro_toast">Saltados los primeros %d segundos</string>
<string name="pref_playback_time_respects_speed_title">Ajustar la información del medio según la velocidad de reproducción</string>
<string name="pref_playback_time_respects_speed_sum">La posición y duración están adaptadas a la velocidad de reproducción</string>
<string name="pref_fast_forward">Intervalo de avance</string>
@@ -479,6 +484,8 @@
<string name="pref_enqueue_downloaded_title">Añadir descargados a la cola</string>
<string name="pref_enqueue_downloaded_summary">Añadir episodios descargados a la cola</string>
<string name="media_player_builtin">Reproductor Android integrado</string>
+ <string name="media_player_switch_to_exoplayer">Cambiar a ExoPlayer</string>
+ <string name="media_player_switched_to_exoplayer">Cambiado a ExoPlayer</string>
<string name="pref_skip_silence_title">Saltar silencio en audio</string>
<string name="pref_videoBehavior_title">Al salir del vídeo</string>
<string name="pref_videoBehavior_sum">Comportamiento al salir de la reproducción de video</string>
@@ -511,6 +518,14 @@
<string name="search_status_no_results">No se han encontrado resultados</string>
<string name="search_label">Buscar</string>
<string name="no_results_for_query">No se han encontrado resultados de \"%1$s\"</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">Sincronización iniciada</string>
+ <string name="sync_status_episodes_upload">Subiendo cambios de episodio...</string>
+ <string name="sync_status_episodes_download">Descargando cambios de episodios...</string>
+ <string name="sync_status_upload_played">Subiendo estado de reproducción...</string>
+ <string name="sync_status_subscriptions">Sincronizando suscripciones...</string>
+ <string name="sync_status_success">Sincronización exitosa</string>
+ <string name="sync_status_error">Error en la sincronización</string>
<!--import and export-->
<string name="import_export_summary">Mover las suscripciones y la cola a otro dispositivo</string>
<string name="database">Base de datos</string>
@@ -530,6 +545,7 @@
<string name="html_export_label">Exportar a HTML</string>
<string name="database_export_label">Exportar base de datos</string>
<string name="database_import_label">Importar base de datos</string>
+ <string name="database_import_warning">La importación de una base de datos reemplazará todas las suscripciones actuales y el historial de reproducción. Debes exportar la base de datos actual como una copia de seguridad. ¿Quieres reemplazarla?</string>
<string name="please_wait">Por favor espera...</string>
<string name="export_error_label">Error en la exportación</string>
<string name="export_success_title">Exportación exitosa</string>
@@ -621,16 +637,23 @@
<string name="subscribe_label">Suscribirse</string>
<string name="subscribing_label">Suscribiendo...</string>
<string name="preview_episode">Vista Previa</string>
+ <string name="stop_preview">Detener la vista previa</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Retroceso</string>
<string name="fast_forward_label">Avance</string>
+ <string name="increase_speed">Aumentar velocidad</string>
+ <string name="decrease_speed">Reducir velocidad</string>
<string name="media_type_audio_label">Audio</string>
<string name="media_type_video_label">Vídeo</string>
<string name="navigate_upwards_label">Navegar hacia arriba</string>
<string name="status_downloading_label">El episodio se está descargando</string>
<string name="in_queue_label">El episodio está en la cola</string>
+ <string name="is_favorite_label">Episodio marcado como favorito</string>
<string name="drag_handle_content_description">Arrastrar para cambiar la posición de este ítem</string>
<string name="load_next_page_label">Cargar la página siguiente</string>
+ <string name="switch_pages">Cambiar páginas</string>
+ <string name="position">Posición: %1$s</string>
+ <string name="apply_action">Aplicar acción</string>
<!--Feed information screen-->
<string name="authentication_label">Autenticación</string>
<string name="authentication_descr">Cambiar nombre y contraseña de este pódcast y sus episodios</string>
@@ -656,6 +679,7 @@
<string name="browse_gpoddernet_label">Explorar en gpodder.net</string>
<string name="discover">Descubrir</string>
<string name="discover_more">más »</string>
+ <string name="search_powered_by">Búsqueda gracias a %1$s</string>
<string name="filter">Filtro</string>
<!--Episodes apply actions-->
<string name="all_label">Todos</string>
@@ -683,6 +707,12 @@
<string name="sort_date_old_new">Fecha (Antiguo \u2192 Nuevo)</string>
<string name="sort_duration_short_long">Duración (Corto \u2192 Largo)</string>
<string name="sort_duration_long_short">Duración (Largo \u2192 Corto)</string>
+ <string name="sort_a_z">A \u2192 Z</string>
+ <string name="sort_z_a">Z \u2192 A</string>
+ <string name="sort_new_old">Nuevo \u2192 Viejo</string>
+ <string name="sort_old_new">Viejo \u2192 Nuevo</string>
+ <string name="sort_short_long">Breve \u2192 Largo</string>
+ <string name="sort_long_short">Largo \u2192 Breve</string>
<!--Rating dialog-->
<string name="rating_title">¿Te gusta AntennaPod?</string>
<string name="rating_message">Estaríamos muy agradecidos si nos dedicas un poco de tiempo para valorar AntennaPod.</string>
@@ -742,4 +772,8 @@
<string name="widget_settings">Configuraciones del Widget</string>
<string name="widget_create_button">Crear widget</string>
<string name="widget_opacity">Opacidad</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">Configuración actualizada satisfactoriamente.</string>
+ <string name="on_demand_config_stream_text">Parece que usas mucho el stream. ¿Quieres mostrar el botón de stream en la lista de episodios?</string>
+ <string name="on_demand_config_download_text">Parece que usas mucho las descargas. ¿Quieres mostrar el botón de descargar en la lista de episodios?</string>
</resources>
diff --git a/core/src/main/res/values-et/strings.xml b/core/src/main/res/values-et/strings.xml
index 9599e2d49..8d6c6347b 100644
--- a/core/src/main/res/values-et/strings.xml
+++ b/core/src/main/res/values-et/strings.xml
@@ -19,7 +19,6 @@
<string name="cancel_download_label">Tühista\nLaadi alla</string>
<string name="playback_history_label">Esitamise ajalugu</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Süngi teiste seadmetega</string>
<string name="gpodnet_auth_label">gpodder.net kasutajanimi</string>
<string name="episode_cache_full_title">Saadete vahemälu on täis</string>
<string name="episode_cache_full_message">Saadete vahemälu limiit on täis. Vahemälu limiiti saab suurendada seadete alt.</string>
@@ -97,7 +96,6 @@
<item quantity="one">1 päev pärast lõpetamist</item>
<item quantity="other">%d päeva pärast lõpetamist</item>
</plurals>
- <string name="num_selected_label">%d valitud</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Märgi kuulatuks</string>
<string name="mark_all_read_msg">Märgi kõik saated kuulatuks</string>
@@ -269,8 +267,6 @@
<string name="ascending">Kasvavalt</string>
<string name="descending">Kahanevalt</string>
<string name="clear_queue_confirmation_msg">Palun kinnita, et tahad puhastada järjekorra KÕIGIST selles olevatest saadetest</string>
- <string name="sort_old_to_new">Vanemad enne</string>
- <string name="sort_new_to_old">Uuemad enne</string>
<string name="time_left_label">Aega jäänud:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Laadi plugin alla</string>
@@ -303,7 +299,6 @@
<string name="storage_pref">Salvestusruum</string>
<string name="project_pref">Projekt</string>
<string name="queue_label">Järjekord</string>
- <string name="integrations_label">Integratsioon</string>
<string name="automation">Automaatika</string>
<string name="download_pref_details">Üksikasjad</string>
<string name="import_export_pref">Import/eksport</string>
@@ -389,12 +384,8 @@
<string name="pref_gpodnet_logout_toast">Väljalogimine oli edukas</string>
<string name="pref_gpodnet_setlogin_information_title">Muuda kasutajakonto infot</string>
<string name="pref_gpodnet_setlogin_information_sum">Muuda oma gpodder.net konto sisselogimise andmeid.</string>
- <string name="pref_gpodnet_sync_changes_title">Sünkrooni muudatused kohe</string>
<string name="pref_gpodnet_sync_changes_sum">Sünkroniseeri oma tellimuste ja saadete olekute muutuseid gpodder.net-iga</string>
- <string name="pref_gpodnet_full_sync_title">Täielik sünkroonimine kohe</string>
<string name="pref_gpodnet_full_sync_sum">Sünkroniseeri kõiki tellimusi ja saate olekuid gpodder.net-iga.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Viimane sünkroniseerimise katse: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Sünkroonimine on käivitatud</string>
<string name="pref_gpodnet_login_status"><![CDATA[Sisseloginud kui <i>%1$s</i> seadmega <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Kuva sünkroniseerimise vigu teadaannetena</string>
<string name="pref_gpodnet_notifications_sum">See seadistus ei rakendu autentimise vigadele.</string>
@@ -478,6 +469,7 @@
<string name="search_status_no_results">Ei leitud midagi</string>
<string name="search_label">Otsi</string>
<string name="no_results_for_query">\"%1$s\" otsimine ei andnud tulemusi</string>
+ <!--Synchronization-->
<!--import and export-->
<string name="opml_import_label">OPML import</string>
<string name="opml_reader_error">OPML dokumendi lugemisel tekkis tõrge:</string>
@@ -687,4 +679,5 @@
<!--Widget settings-->
<string name="widget_create_button">Lisa vidin</string>
<string name="widget_opacity">Läbipaistvus</string>
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-eu/strings.xml b/core/src/main/res/values-eu/strings.xml
index a51709875..2536b2d3c 100644
--- a/core/src/main/res/values-eu/strings.xml
+++ b/core/src/main/res/values-eu/strings.xml
@@ -20,14 +20,13 @@
<string name="cancel_download_label">Deskarga ezeztatu</string>
<string name="playback_history_label">Erreprodukzio historia</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Sinkronizatzen beste gailu batzuekin</string>
<string name="gpodnet_auth_label">Saioa hasi gpodder.net-en</string>
<string name="episode_cache_full_title">Saioen katxea beteta</string>
<string name="episode_cache_full_message">Saioen katxeta mugara iritsi da. Ezarpenetan katxearen tamaina handitu dezakezu.</string>
<string name="playback_statistics_label">Irakurketa</string>
<string name="download_statistics_label">Deskargak</string>
<!--Statistics fragment-->
- <string name="total_time_listened_to_podcasts">Ikusitako podcasten denbora osoa:</string>
+ <string name="total_time_listened_to_podcasts">Ikusitako podcast denen denbora:</string>
<string name="statistics_details_dialog">%1$d kanpo %2$d hasitako saioetatik. %3$s \n\nErreproduzituak %4$setatik.</string>
<string name="statistics_mode">Estatistika modua</string>
<string name="statistics_mode_normal">Benetan ikusitakoen iraupena kalkulatzea. Bi aldiz ikustean bi aldiz kontatzen da; ikusita bezala markatzea, berriz, ez da kontatzen</string>
@@ -70,7 +69,7 @@
<string name="cover_label">Irudia</string>
<string name="error_label">Errorea</string>
<string name="error_msg_prefix">Errorea gertatu da:</string>
- <string name="needs_storage_permission">Baimenak behar dira hori egiteko</string>
+ <string name="needs_storage_permission">Biltegiratze baimenak behar dira hori egiteko</string>
<string name="refresh_label">Eguneratu</string>
<string name="external_storage_error_msg">Ez da kanpo biltegirik aurkitu. Ziurtatu zure kanpo biltegia muntatuta dagoela aplikazioa ondo ibil dadin.</string>
<string name="chapters_label">Kapituluak</string>
@@ -86,10 +85,10 @@
<string name="auto_download_apply_to_items_message">Aukera berria <i>deskarga automatikoa</i> automatikoki aplikatuko zaie saio berriei. Nahi duzu aurreko saioei ere aplikatzea?</string>
<string name="auto_delete_label">Ezabatu saioa automatikoki</string>
<string name="feed_volume_reduction">Bolumenaren kudeaketa</string>
- <string name="feed_volume_reduction_summary">Podcast hauen bolumena murriztu: \%s</string>
- <string name="feed_volume_reduction_off">Bat ere ez</string>
- <string name="feed_volume_reduction_light">Argia</string>
- <string name="feed_volume_reduction_heavy">Forte </string>
+ <string name="feed_volume_reduction_summary">Podcast hauen bolumena gutxitu: %1$s</string>
+ <string name="feed_volume_reduction_off">Itzalita</string>
+ <string name="feed_volume_reduction_light">Gozoa</string>
+ <string name="feed_volume_reduction_heavy">Indartsua</string>
<string name="parallel_downloads_suffix">\u0020deskarga paraleloak</string>
<string name="feed_auto_download_global">Globala aurrez zehaztua</string>
<string name="feed_auto_download_always">Beti</string>
@@ -106,7 +105,10 @@
<item quantity="one">1 egun bukatu ondoren</item>
<item quantity="other">%d bukatu ondoren</item>
</plurals>
- <string name="num_selected_label">%d aukeratua</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">%d aukeratua</item>
+ <item quantity="other">%d aukeratua</item>
+ </plurals>
<string name="loading_more">Kargatzen...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Markatu denak ikusita bezala</string>
@@ -153,7 +155,7 @@
<string name="download_label">Deskargatu</string>
<plurals name="downloading_batch_label">
<item quantity="one">Deskargatzen %d saioa.</item>
- <item quantity="other">Deskargatzen %d saioak.</item>
+ <item quantity="other">Deskargatzen %d saio.</item>
</plurals>
<string name="play_label">Ikusi</string>
<string name="pause_label">Pausatu</string>
@@ -170,7 +172,7 @@
<string name="mark_read_label">Markatu ikusita bezala</string>
<string name="marked_as_read_label">Ikusita bezala markatua</string>
<string name="mark_read_no_media_label">Markatu iraurrita gisa</string>
- <string name="marked_as_read_no_media_label">Markatu irakurrita gisa</string>
+ <string name="marked_as_read_no_media_label">Irakurrita gisa markatua</string>
<string name="play_this_to_seek_position">Posizioetara jauzi egiteko, pasartea erreproduzitu behar duzu</string>
<plurals name="marked_read_batch_label">
<item quantity="one">%d saio markatuta ikusita bezala.</item>
@@ -182,7 +184,7 @@
<item quantity="one">%d saio markatuta ikusita bezala.</item>
<item quantity="other">%d saio markatuta ez ikusita bezala.</item>
</plurals>
- <string name="add_to_queue_label">Ilaran gehitu</string>
+ <string name="add_to_queue_label">Gehitu ilaran</string>
<string name="added_to_queue_label">Ilaran gehitua</string>
<plurals name="added_to_queue_batch_label">
<item quantity="one">%d saio ilaran gehitua.</item>
@@ -193,16 +195,17 @@
<item quantity="one">%d saio ilaratik kenduta.</item>
<item quantity="other">%d saio ilaratik kenduta.</item>
</plurals>
- <string name="add_to_favorite_label">Gogokoetara gehitu</string>
+ <string name="add_to_favorite_label">Gehitu gogokoetara</string>
<string name="added_to_favorites">Gogokoetara gehitua</string>
- <string name="remove_from_favorite_label">Gogokoetatik kendu</string>
+ <string name="remove_from_favorite_label">Kendu gogokoetatik</string>
<string name="removed_from_favorites">Gogokoetatik kendua</string>
<string name="visit_website_label">Bisitatu web gunea</string>
- <string name="skip_episode_label">Saioa baztertu</string>
+ <string name="skip_episode_label">Baztertu saioa</string>
<string name="activate_auto_download">Aktibatu deskarga automatikoa</string>
<string name="deactivate_auto_download">Desaktibatu deskarga automatikoa</string>
<string name="reset_position">Berrezarri erreprodukzioaren tokia</string>
<string name="removed_item">Ezabatutako elementua</string>
+ <string name="no_items_selected">Ez da elementurik hautatu</string>
<!--Download messages and labels-->
<string name="download_successful">arrakastatsua</string>
<string name="download_pending">Deskargatzeko zain</string>
@@ -222,7 +225,7 @@
<string name="download_error_forbidden">Debekaturik</string>
<string name="download_canceled_msg">Deskarga ezeztatua</string>
<string name="download_canceled_autodownload_enabled_msg">Deskarga ezeztatua\aktibatu da <i>Auto deskarga</i> elementu honetan</string>
- <string name="download_report_title">Deskargak osatu dira errorea(k) d(it)uela</string>
+ <string name="download_report_title">Deskarga(k) osatu d(ir)a errorea(k) d(it)uela</string>
<string name="auto_download_report_title">Deskargatu automatikoak osatuta</string>
<string name="download_report_content_title">Deskargen txostena</string>
<string name="download_error_malformed_url">URL-ren formatu okerra</string>
@@ -241,15 +244,15 @@
<string name="download_type_media">Media artxibategia</string>
<string name="download_request_error_dialog_message_prefix">Errore bat gertatu da fitxategia deskargatzen saiatzean:\u0020</string>
<string name="null_value_podcast_error">Ez da erakutsi zitekeen podcast-ik eman.</string>
- <string name="authentication_notification_title">Eskatutako autentifikazioa</string>
+ <string name="authentication_notification_title">Egiaztatzea beharrezkoa da</string>
<string name="authentication_notification_msg">Eskatutako baliabideak erabiltzaile bat eta pasahitza behar ditu</string>
<string name="confirm_mobile_download_dialog_title">Baieztatu deskarga sare mugikor bidez</string>
<string name="confirm_mobile_download_dialog_message_not_in_queue">Datu-sare mugikorren bidezko deskargak desaktibatu dira konfigurazioan.\n\n Aukeratu daiteke saio ilarari eranstea edo deskargak aldi baterako baimentzea.\n\n<small>10 minutura haien aukeraketa gogora araziko da.</small></string>
<string name="confirm_mobile_download_dialog_message">Datu mugikorren sareko deskargak desaktibatu dira konfigurazioan.\n\n Deskargak aldi baterako baimendu nahi dituzu?\n\n<small>10 minutura haien aukeraketa gogora araziko da.</small></string>
- <string name="confirm_mobile_streaming_notification_title">Berretsi zuzenekoa mugikorrean</string>
+ <string name="confirm_mobile_streaming_notification_title">Berretsi datu mugikor bidezko zuzenekoa</string>
<string name="confirm_mobile_streaming_notification_message">Konexioaren datu bidezko zuzenekoa desgaiturik dago ezarpenetan. Sakatu halere ikusteko.</string>
<string name="confirm_mobile_streaming_button_always">Baimendu beti</string>
- <string name="confirm_mobile_download_dialog_only_add_to_queue">Ilaran gehitu</string>
+ <string name="confirm_mobile_download_dialog_only_add_to_queue">Gehitu ilaran</string>
<string name="confirm_mobile_download_dialog_enable_temporarily">Baimendu aldi baterako</string>
<!--Mediaplayer messages-->
<string name="player_error_msg">Errorea!</string>
@@ -268,18 +271,18 @@
<string name="unknown_media_key">AntennaPod - Media tekla ezezaguna: %1$d</string>
<string name="error_file_not_found">Ez da artxibategirik aurkitu</string>
<!--Queue operations-->
- <string name="lock_queue">Ilara blokeatu</string>
- <string name="unlock_queue">Ilara desblokeatu</string>
+ <string name="lock_queue">Blokeatu ilara</string>
+ <string name="unlock_queue">Desblokeatu ilara</string>
<string name="queue_locked">Ilara blokeaturik</string>
<string name="queue_unlocked">Ilara desblokeaturik</string>
<string name="queue_lock_warning">Ilara blokeatzen baduzu, ezin izango dituzu saioak mugitu edo markatu.</string>
<string name="checkbox_do_not_show_again">Ez erakutsi berriro</string>
- <string name="clear_queue_label">Ilara hustu</string>
+ <string name="clear_queue_label">Hustu ilara</string>
<string name="undo">Desegin</string>
- <string name="move_to_top_label">Hasierara eraman</string>
- <string name="move_to_bottom_label">Bukaerara eraman</string>
+ <string name="move_to_top_label">Eraman hasierara</string>
+ <string name="move_to_bottom_label">Eraman bukaerara</string>
<string name="sort">Antolatu</string>
- <string name="keep_sorted">Antolatuta eduki</string>
+ <string name="keep_sorted">Eduki antolatuta</string>
<string name="date">Data</string>
<string name="duration">Iraupena</string>
<string name="episode_title">Saioaren izenburua</string>
@@ -289,8 +292,6 @@
<string name="ascending">Gorantz</string>
<string name="descending">Beherantz</string>
<string name="clear_queue_confirmation_msg">Ziurtatu ilarako saio DENAK ezabatu nahi dituzula</string>
- <string name="sort_old_to_new">Berritik zaharrera</string>
- <string name="sort_new_to_old">Zaharretik berrira</string>
<string name="time_left_label">Gelditzen den denbora:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Deskargatu osagarria</string>
@@ -325,8 +326,8 @@
<string name="storage_sum">Ezabatze automatikoa, jaso, bidali</string>
<string name="project_pref">Proiektua</string>
<string name="queue_label">Ilara</string>
- <string name="integrations_label">Integrazioak</string>
- <string name="integrations_sum">Sinkronizazioa</string>
+ <string name="synchronization_pref">Sinkronizazioa</string>
+ <string name="synchronization_sum">Sinkronizatzen gpodder.net erabiltzen duten beste gailu batzuekin</string>
<string name="automation">Automatizazioa</string>
<string name="download_pref_details">Xehetasunak</string>
<string name="import_export_pref">Inportatu/esportatu</string>
@@ -365,7 +366,7 @@
<string name="pref_autoUpdateIntervallOrTime_sum">Zehaztu tarte bat edo eguneko ordu jakin bat podcastak automatikoki freskatzeko</string>
<string name="pref_autoUpdateIntervallOrTime_message">Zuk ahal duzu <i>tartea</i> gustuko \"2orduro\" <i>eguneko ordua </i> \"7:00 AM\" adibidez edo <i>desgaitu</i> eguneraketa automatikoak\n\n<small>Oharra: Eguneraketa orduak ez dira zehatzak. Atzerapen txiki bat eman daiteke.</small></string>
<string name="pref_autoUpdateIntervallOrTime_Disable">Desgaitu</string>
- <string name="pref_autoUpdateIntervallOrTime_Interval">Tartea zehaztu</string>
+ <string name="pref_autoUpdateIntervallOrTime_Interval">Zehaztu tartea</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Zehaztu eguneko ordua</string>
<string name="pref_autoUpdateIntervallOrTime_every">%1$sdenak</string>
<string name="pref_autoUpdateIntervallOrTime_at">%1$setan</string>
@@ -377,7 +378,7 @@
<string name="pref_stream_over_download_sum">Zuzenean botoia erakusten du, zerrendetan deskargatzeko botoiaren ordez.</string>
<string name="pref_mobileUpdate_title">Sare bidezko eguneraketak</string>
<string name="pref_mobileUpdate_sum">Aukeratu datu mugikorrez deskarga daitekeena</string>
- <string name="pref_mobileUpdate_refresh">Jaarri egunean podcastak</string>
+ <string name="pref_mobileUpdate_refresh">Jarri egunean podcastak</string>
<string name="pref_mobileUpdate_images">Azaleko irudiak</string>
<string name="pref_mobileUpdate_auto_download">Deskargatu automatikoki</string>
<string name="pref_mobileUpdate_episode_download">Saioaren deskarga</string>
@@ -417,19 +418,23 @@
<string name="pref_gpodnet_logout_toast">Saioa ongi itxi duzu</string>
<string name="pref_gpodnet_setlogin_information_title">Aldatu saio hasieraren informazioa</string>
<string name="pref_gpodnet_setlogin_information_sum">Aldatu saio hasierako datuak zure gpodder.net-en kontuan.</string>
- <string name="pref_gpodnet_sync_changes_title">Sinkronizatu aldaketak orain</string>
+ <string name="pref_gpodnet_sync_changes_title">Sinkronizatu orain</string>
<string name="pref_gpodnet_sync_changes_sum">Sinkronizatu harpidetza aldaketak eta saioak gpodder.net-ekin</string>
- <string name="pref_gpodnet_full_sync_title">Era bat sinkronizaturik</string>
+ <string name="pref_gpodnet_full_sync_title">Sinkronizazio osoa behartu</string>
<string name="pref_gpodnet_full_sync_sum">Sinkronizatu harpidetza denak eta saioak gpodder.net-ekin</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Azken sinkronizatze saiakera: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Sinkronizatzen hasi da</string>
<string name="pref_gpodnet_login_status"><![CDATA[Horrela hasi du saioa <i>%1$s</i> gailu honekin <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Erakutsi sinkronizatze erroreak</string>
<string name="pref_gpodnet_notifications_sum">Ezarpen honek ez du eraginik saio hasierako erroretan eraginik.</string>
<string name="pref_playback_speed_title">Erreproduzitzeko abiadurak</string>
<string name="pref_playback_speed_sum">Pertsonalizatu eskura dauden abiadurak audio erreproduzitzeko abiadura aldakorrean</string>
<string name="pref_feed_playback_speed_sum">Podcast hauen berezko irakurtze abiadura</string>
- <string name="pref_playback_time_respects_speed_title">Doitu medioaren informazioa erreprodukzio-abiaduraren arabera doitzea</string>
+ <string name="pref_feed_skip">Salto automatikoa</string>
+ <string name="pref_feed_skip_sum">Saltatu sarrera eta amaiera kredituak.</string>
+ <string name="pref_feed_skip_ending">Saltatu azkena</string>
+ <string name="pref_feed_skip_intro">Saltatu lehenengoa</string>
+ <string name="pref_feed_skip_ending_toast">Salto egin azken%d segundo</string>
+ <string name="pref_feed_skip_intro_toast">Salto egin hasierako%d segundo</string>
+ <string name="pref_playback_time_respects_speed_title">Doitu medioaren informazioa erreprodukzio-abiaduraren arabera</string>
<string name="pref_playback_time_respects_speed_sum">Posizioa eta iraupena erreprodukzio-abiadurara egokituta daude.</string>
<string name="pref_fast_forward">Aurrera egiteko tartea</string>
<string name="pref_fast_forward_sum">Pertsonalizatu zenbat segundu egingo duen aurrera aurrera botoia sakatzean
@@ -481,6 +486,8 @@
<string name="pref_enqueue_downloaded_title">Gehitu deskargatutakoak ilarara</string>
<string name="pref_enqueue_downloaded_summary">Gehitu deskargatutako saioak ilarara</string>
<string name="media_player_builtin">Integratutako Android erreproduzitzailea</string>
+ <string name="media_player_switch_to_exoplayer">Aldatu ExoPlayer-era</string>
+ <string name="media_player_switched_to_exoplayer">ExoPlayer-era aldatu da.</string>
<string name="pref_skip_silence_title">Jauzi egin ixilunea audioan</string>
<string name="pref_videoBehavior_title">Bideotik irtetean</string>
<string name="pref_videoBehavior_sum">Jokaera bideo erreproduzitzetik irtetean</string>
@@ -513,6 +520,14 @@
<string name="search_status_no_results">Ez da emaitzarik aurkitu</string>
<string name="search_label">Bilatu</string>
<string name="no_results_for_query">Ez da \"%1$s\"emaitzarik aurkitu</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">Sinkronizatzen hasi da</string>
+ <string name="sync_status_episodes_upload">Saio aldaketak kargatzen…</string>
+ <string name="sync_status_episodes_download">Saio aldaketak deskargatzen ...</string>
+ <string name="sync_status_upload_played">Ikusitakoen egoera kargatzen…</string>
+ <string name="sync_status_subscriptions">Harpidetzak sinkronizatzen ...</string>
+ <string name="sync_status_success">Sinkronizazioa amaitu da</string>
+ <string name="sync_status_error">Sinkronizazioak huts egin du</string>
<!--import and export-->
<string name="import_export_summary">Kopiatu harpidetza eta irakurketa zerrenda beste gailu batean</string>
<string name="database">Datu basea</string>
@@ -523,7 +538,7 @@
<string name="opml_import_summary">Ekarri zure harpidetzak podcast-en beste aplikazio batetik</string>
<string name="database_export_summary">Bidali beste gailu batera harpidetzak, ikusitako saioak eta irakur zerrenda</string>
<string name="database_import_summary">Ekarri AntennaPodera datu basea beste gailu batetik</string>
- <string name="opml_import_label">Inportatu OPML Importtik</string>
+ <string name="opml_import_label">Inportatu OPMLtik</string>
<string name="opml_reader_error">Errorea OPML dokkumentua irakurtzean:</string>
<string name="opml_import_error_no_file">Artxibategi bat aukeratu behar duzu!</string>
<string name="select_all_label">Aukeratu dena</string>
@@ -532,6 +547,7 @@
<string name="html_export_label">HTMLra esportatu</string>
<string name="database_export_label">Bidali datu basea</string>
<string name="database_import_label">Ekarri datu basea</string>
+ <string name="database_import_warning">Datu-base bat inportatzeak egungo harpidetza guztiak eta erreprodukzio-historia ordezkatuko ditu. Egungo datu-basea esportatu behar duzu segurtasun-kopia gisa. Ordezkatu nahi duzu?</string>
<string name="please_wait">Itxaron mesedez...</string>
<string name="export_error_label">Errorea esportatzean</string>
<string name="export_success_title">Esportatzea ongi burutu da</string>
@@ -623,16 +639,23 @@
<string name="subscribe_label">Eman izena</string>
<string name="subscribing_label">Harpidetzen...</string>
<string name="preview_episode">Aurretiko ikuspegia</string>
+ <string name="stop_preview">Gelditu aurretiko ikuspegia</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Atzera egin</string>
<string name="fast_forward_label">Aurrera egin</string>
+ <string name="increase_speed">Handitu abiadura</string>
+ <string name="decrease_speed">Gutxitu abiadura</string>
<string name="media_type_audio_label">Audioa</string>
<string name="media_type_video_label">Bideoa</string>
<string name="navigate_upwards_label">Nabigatu gorantz </string>
<string name="status_downloading_label">Saioa deskargatzen ari da</string>
<string name="in_queue_label">Saioa ilaran dago</string>
+ <string name="is_favorite_label">Saioa gogokoa bezala markatu da</string>
<string name="drag_handle_content_description">Arrastatu elementu honen posizioa aldatzeko</string>
<string name="load_next_page_label">Hurrengo orria kargatu</string>
+ <string name="switch_pages">Aldatu orriak</string>
+ <string name="position">Kokalekua: %1$s</string>
+ <string name="apply_action">Aplikatu ekintza</string>
<!--Feed information screen-->
<string name="authentication_label">Egiaztatzea</string>
<string name="authentication_descr">Aldatu podcast honen eta bere saioen erabiltzaile izena eta pasahitza.</string>
@@ -654,10 +677,11 @@
<string name="search_itunes_label">Bilatu itunes-en</string>
<string name="search_fyyd_label">Bilatu fyyd-en</string>
<string name="advanced">Aurreratua</string>
- <string name="add_podcast_by_url">Gehitu podcaasta URL bidez</string>
+ <string name="add_podcast_by_url">Gehitu podcasta URL bidez</string>
<string name="browse_gpoddernet_label">Bilatu gpodder.net-en bilatu</string>
<string name="discover">Aurkitu</string>
<string name="discover_more">gehiago »</string>
+ <string name="search_powered_by">Honek bultzatutako bilaketa:%1$s</string>
<string name="filter">Iragazia</string>
<!--Episodes apply actions-->
<string name="all_label">Denak</string>
@@ -685,6 +709,12 @@
<string name="sort_date_old_new">Data (zaharra \u2192 berria)</string>
<string name="sort_duration_short_long">Iraupena (motza\u2192 luzea)</string>
<string name="sort_duration_long_short">Iraupena (luzea\u2192 motza)</string>
+ <string name="sort_a_z">A \u2192 Z</string>
+ <string name="sort_z_a">Z \u2192 A</string>
+ <string name="sort_new_old">Berria \u2192 zaharra</string>
+ <string name="sort_old_new">Zaharra \u2192 berria</string>
+ <string name="sort_short_long">Motza \u2192 luzea</string>
+ <string name="sort_long_short">Luzea \u2192 motza</string>
<!--Rating dialog-->
<string name="rating_title">Gustuko duzu AntennaPod?</string>
<string name="rating_message">Oso eskertuta egongo ginateke AntennaPod baloratzeko denbora pixka bat eskainiko bazenigu.</string>
@@ -744,4 +774,8 @@
<string name="widget_settings">Widget ezarpenak</string>
<string name="widget_create_button">widget-a sortu</string>
<string name="widget_opacity">Opakutasuna</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">Konfigurazio eguneratua, arrakastaz.</string>
+ <string name="on_demand_config_stream_text">Badirudi asko transmititzen duzula. Saio-zerrendek transmisio-botoiak erakustea nahi duzu?</string>
+ <string name="on_demand_config_download_text">Badirudi asko deskargatzen duzula. Gertaera-zerrendek deskarga-botoiak erakustea nahi duzu?</string>
</resources>
diff --git a/core/src/main/res/values-fa/strings.xml b/core/src/main/res/values-fa/strings.xml
index 6c483cbfb..f060ee338 100644
--- a/core/src/main/res/values-fa/strings.xml
+++ b/core/src/main/res/values-fa/strings.xml
@@ -20,7 +20,6 @@
<string name="cancel_download_label">لغو\nبارگیری</string>
<string name="playback_history_label">تاریخچه پخش</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">همگام‌سازی با دیگر دستگاه‌ها</string>
<string name="gpodnet_auth_label">gpodder.net ورود</string>
<string name="episode_cache_full_title">ظرفیت حافظه پنهان تکمیل شده است</string>
<string name="episode_cache_full_message">حد مجاز تکمیل شده است. شما می‌توانید اندازه حافظه پنهان را در تنظیمات افزایش دهید.</string>
@@ -105,7 +104,6 @@
<item quantity="one">%dروز بعد از اتمام</item>
<item quantity="other">%dروز بعد از اتمام</item>
</plurals>
- <string name="num_selected_label">%d انتخاب شده</string>
<string name="loading_more">بارگیری بیشتر…</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">علامت‌گذاری همه به‌عنوان پخش‌شده</string>
@@ -288,8 +286,6 @@
<string name="ascending">صعودی</string>
<string name="descending">نزولی</string>
<string name="clear_queue_confirmation_msg">لطفاً تأیید کنید که می‌خواهید صف را از همهٔ قسمت‌های درونش پاک‌سازی کنید</string>
- <string name="sort_old_to_new">قدیمی به جدید</string>
- <string name="sort_new_to_old">جدید به قدیمی</string>
<string name="time_left_label">زمان مانده:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">بارگیری افزایه</string>
@@ -324,8 +320,6 @@
<string name="storage_sum">حذف خودکار قسمت، درون‌ریزی، برون‌ریزی</string>
<string name="project_pref">پروژه</string>
<string name="queue_label">صف</string>
- <string name="integrations_label">یک‌پارچگی‌ها</string>
- <string name="integrations_sum">هم‌گام‌سازی</string>
<string name="automation">اتوماسیون</string>
<string name="download_pref_details">جزئیات</string>
<string name="import_export_pref">وارد/صادر کرد</string>
@@ -340,6 +334,10 @@
<string name="media_player">پخش‌کننده رسانه</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_auto_delete_title">حذف خودکار</string>
<string name="playback_pref">پخش</string>
<string name="network_pref">شبکه</string>
@@ -388,6 +386,7 @@
<!--Search-->
<string name="search_status_no_results">نتیجه‌ای یافت نشد</string>
<string name="search_label">جستجو</string>
+ <!--Synchronization-->
<!--import and export-->
<string name="select_all_label">انتخاب همه</string>
<string name="deselect_all_label">انتخاب هیچ</string>
@@ -479,4 +478,5 @@
<!--Notification channels-->
<string name="notification_channel_auto_download">بارگیری‌های خودکار</string>
<!--Widget settings-->
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-fi/strings.xml b/core/src/main/res/values-fi/strings.xml
index 05e8404f1..3b94dbe85 100644
--- a/core/src/main/res/values-fi/strings.xml
+++ b/core/src/main/res/values-fi/strings.xml
@@ -2,6 +2,7 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--Activity and fragment titles-->
<string name="feed_update_receiver_name">Päivitä tilaukset</string>
+ <string name="feeds_label">Podcastit</string>
<string name="statistics_label">Tilastot</string>
<string name="add_feed_label">Lisää Podcast</string>
<string name="episodes_label">Jaksot</string>
@@ -19,10 +20,11 @@
<string name="cancel_download_label">Peruuta\nLataus</string>
<string name="playback_history_label">Soittohistoria</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Synkronoi toisiin laitteisiin</string>
<string name="gpodnet_auth_label">gpodder.net Kirjautuminen</string>
<string name="episode_cache_full_title">Jaksojen välimuisti täynnä</string>
<string name="episode_cache_full_message">Jaksojen välimuistin rajoitus on ylitetty. Voit lisätä välimuistin kokoa Asetuksissa.</string>
+ <string name="playback_statistics_label">Toisto</string>
+ <string name="download_statistics_label">Lataukset</string>
<!--Statistics fragment-->
<string name="total_time_listened_to_podcasts">Podcasteja soitettu yhteensä:</string>
<string name="statistics_details_dialog">%1$d jakso %2$d:sta aloitettu.\n\nSoitettu %3$s jaksoa %4$s:sta.</string>
@@ -30,6 +32,8 @@
<string name="statistics_mode_normal">Laske oikeasti soitettu aikamäärä. Uudelleensoitto lasketaan kahdesti, mutta soitetuksi merkattua ei lasketa.</string>
<string name="statistics_mode_count_all">Laske yhteen kaikki soitetuksi merketatut podcastit</string>
<string name="statistics_speed_not_counted">Huomio: Soittonopeutta ei lasketa mukaan.</string>
+ <string name="statistics_reset_data">Nollaa tilastotiedot</string>
+ <string name="statistics_reset_data_msg">Tämä poistaa kaikkien jaksojen soiton keston historian. Haluatko varmasti jatkaa?</string>
<!--Download Statistics fragment-->
<!--Main activity-->
<string name="drawer_open">Avaa menu</string>
@@ -95,7 +99,6 @@
<item quantity="one">1 päivä lataamisen jälkeen</item>
<item quantity="other">%d päivää lataamisen jälkeen</item>
</plurals>
- <string name="num_selected_label">%d valittu</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Merkkaa kaikki soitetuksi</string>
<string name="mark_all_read_msg">Merkkaa kaikki episodit soitetuiksi</string>
@@ -258,8 +261,6 @@
<string name="ascending">Nouseva</string>
<string name="descending">Laskeva</string>
<string name="clear_queue_confirmation_msg">Varmista että haluat tyhjentää jonon KAIKISTA jaksoista</string>
- <string name="sort_old_to_new">Vanhasta uuteen</string>
- <string name="sort_new_to_old">Uudesta vanhaan</string>
<string name="time_left_label">Aikaa jäljellä:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Lataa plugin</string>
@@ -290,7 +291,6 @@
<string name="storage_pref">Tallennus</string>
<string name="project_pref">Projekti</string>
<string name="queue_label">Jono</string>
- <string name="integrations_label">Integraatiot</string>
<string name="automation">Automaatio</string>
<string name="download_pref_details">Tietoja</string>
<string name="import_export_pref">Tuo/Vie</string>
@@ -363,12 +363,8 @@
<string name="pref_gpodnet_logout_toast">Uloskirjautuminen onnistui</string>
<string name="pref_gpodnet_setlogin_information_title">Vaihda kirjautumistietoja</string>
<string name="pref_gpodnet_setlogin_information_sum">Vaihda kirjautumistietoja gpodder.net tiliisi.</string>
- <string name="pref_gpodnet_sync_changes_title">Synkronoi muutokset nyt</string>
<string name="pref_gpodnet_sync_changes_sum">Synkronoi tilaukset ja jaksojen tilojen muutokset gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">Täysi synkronointi nyt</string>
<string name="pref_gpodnet_full_sync_sum">Synkronoi kaikki tilaukset ja jaksojen tilastot gpodder.net</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Viimeisin synkronointiyritys: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Synkronointi aloitettu</string>
<string name="pref_gpodnet_login_status"><![CDATA[Kirjauduttu <i>%1$s</i> laitteella <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Näytä synkronointivirheet ilmoituksissa</string>
<string name="pref_gpodnet_notifications_sum">Tämä asetus ei vaikuta autentikointivirheisiin.</string>
@@ -434,6 +430,7 @@
<string name="search_status_no_results">Ei löydetty tuloksia</string>
<string name="search_label">Etsi</string>
<string name="no_results_for_query">Ei löydetty tuloksia \"%1$s\"</string>
+ <!--Synchronization-->
<!--import and export-->
<string name="opml_import_label">OPML tuonti</string>
<string name="opml_reader_error">Virhe lukiessa OPML dokumenttia:</string>
@@ -640,4 +637,5 @@
<string name="notification_channel_error">Virheet</string>
<string name="notification_channel_error_description">Näytetään kun jotain meni vikaan, esimerkiksi jos lataus tai gpodder synkronointi epäonnistui.</string>
<!--Widget settings-->
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-fr/strings.xml b/core/src/main/res/values-fr/strings.xml
index c49f6b0ba..85423fb8a 100644
--- a/core/src/main/res/values-fr/strings.xml
+++ b/core/src/main/res/values-fr/strings.xml
@@ -20,7 +20,6 @@
<string name="cancel_download_label">Annuler les téléchargements</string>
<string name="playback_history_label">Journal de lecture</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Synchroniser avec d\'autres appareils</string>
<string name="gpodnet_auth_label">Identifiants gpodder.net</string>
<string name="episode_cache_full_title">L\'emplacement pour stocker les épisodes est plein</string>
<string name="episode_cache_full_message">Le nombre maximal d\'épisodes téléchargés a été atteint. Vous pouvez changer ce nombre dans les paramètres.</string>
@@ -28,7 +27,7 @@
<string name="download_statistics_label">Téléchargements</string>
<!--Statistics fragment-->
<string name="total_time_listened_to_podcasts">Durée totale d\'écoute :</string>
- <string name="statistics_details_dialog">%1$d épisodes sur %2$d commencés.\n\nLu %3$s sur %4$s.</string>
+ <string name="statistics_details_dialog">%1$d épisodes démarrés sur %2$d\nsoit %3$s de lues sur %4$s.</string>
<string name="statistics_mode">Type de statistiques</string>
<string name="statistics_mode_normal">Calculer la durée réellement écoutée. Les épisodes écoutés deux fois comptent double alors que ceux simplement marqués lus ne sont pas comptés</string>
<string name="statistics_mode_count_all">Additionner tous les podcasts marqués comme lus</string>
@@ -86,8 +85,8 @@
<string name="auto_download_apply_to_items_message">Le nouveau paramètre <i>Téléchargement Automatique</i> sera automatiquement appliqué sur chaque nouvel épisode.\nVoulez-vous faire de même avec les épisodes précédents ?</string>
<string name="auto_delete_label">Suppression automatique des épisodes</string>
<string name="feed_volume_reduction">Réduction du volume</string>
- <string name="feed_volume_reduction_summary">Réduction du volume pour les épisodes de ce podcast : \%s</string>
- <string name="feed_volume_reduction_off">pas de réduction</string>
+ <string name="feed_volume_reduction_summary">Réduction du volume des épisodes : %1$s</string>
+ <string name="feed_volume_reduction_off">aucune</string>
<string name="feed_volume_reduction_light">faible</string>
<string name="feed_volume_reduction_heavy">importante</string>
<string name="parallel_downloads_suffix">\u0020téléchargements parallèles</string>
@@ -106,7 +105,10 @@
<item quantity="one">1 jour après avoir été écouté</item>
<item quantity="other">%d jours après avoir été écouté</item>
</plurals>
- <string name="num_selected_label">%d sélectionné(s)</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">%d sélectionné</item>
+ <item quantity="other">%d sélectionnés</item>
+ </plurals>
<string name="loading_more">Chargement...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Marquer tous les épisodes comme lus</string>
@@ -158,7 +160,7 @@
<string name="play_label">Lire</string>
<string name="pause_label">Pause</string>
<string name="stream_label">Streaming</string>
- <string name="delete_label">Effacer</string>
+ <string name="delete_label">Supprimer</string>
<string name="delete_failed">Suppression du fichier impossible. Redémarrer pourrait aider.</string>
<string name="delete_episode_label">Suppression de l\'épisode</string>
<plurals name="deleted_episode_batch_label">
@@ -203,6 +205,7 @@
<string name="deactivate_auto_download">Désactiver téléchargement automatique</string>
<string name="reset_position">Réinitialiser la position de lecture</string>
<string name="removed_item">Élément retiré</string>
+ <string name="no_items_selected">Rien n\'a été sélectionné</string>
<!--Download messages and labels-->
<string name="download_successful">terminé</string>
<string name="download_pending">Téléchargement en attente</string>
@@ -289,8 +292,6 @@
<string name="ascending">Ordre croissant</string>
<string name="descending">Ordre décroissant</string>
<string name="clear_queue_confirmation_msg">Veuillez confirmer que vous voulez bien supprimer TOUS les épisodes de la liste de lecture</string>
- <string name="sort_old_to_new">Ancien à récent</string>
- <string name="sort_new_to_old">Récent à ancien</string>
<string name="time_left_label">Durée restante :\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Télécharger une extension</string>
@@ -325,8 +326,8 @@
<string name="storage_sum">Suppression automatique, importation, exportation</string>
<string name="project_pref">Projet</string>
<string name="queue_label">Liste de lecture</string>
- <string name="integrations_label">Intégrations</string>
- <string name="integrations_sum">Synchronisation</string>
+ <string name="synchronization_pref">Synchronisation</string>
+ <string name="synchronization_sum">Utiliser gpodder.net pour synchroniser avec d\'autres appareils</string>
<string name="automation">Automatisation</string>
<string name="download_pref_details">Détails</string>
<string name="import_export_pref">Importation / Exportation</string>
@@ -341,7 +342,7 @@
<string name="media_player">Lecteur multimédia</string>
<string name="pref_episode_cleanup_title">Nettoyage des épisodes</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_pauseOnDisconnect_sum">Interrompre la lecture quand les écouteurs ou le bluetooth sont déconnectés</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Reprendre la lecture quand des écouteurs sont branchés</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Reprendre la lecture quand le Bluetooth se reconnecte</string>
<string name="pref_hardwareForwardButtonSkips_title">Le bouton \"saut avant\" saute l\'épisode</string>
@@ -351,7 +352,7 @@
<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>
- <string name="pref_smart_mark_as_played_sum">Les épisodes seront marqués comme lus même s\'il reste quelques secondes à écouter</string>
+ <string name="pref_smart_mark_as_played_sum">Les épisodes seront marqués comme lus même s\'il reste quelques secondes pour les finir</string>
<string name="pref_smart_mark_as_played_title">Marquer comme lu intelligemment</string>
<string name="pref_skip_keeps_episodes_sum">Garder les épisodes quand ils sont passés</string>
<string name="pref_skip_keeps_episodes_title">Garder les épisodes passés</string>
@@ -363,7 +364,7 @@
<string name="network_pref_sum">Intervalle / Heure de mise à jour, contrôle des téléchargements, utilisation de la connexion mobile</string>
<string name="pref_autoUpdateIntervallOrTime_title">Intervalle / Heure de mise à jour</string>
<string name="pref_autoUpdateIntervallOrTime_sum">Indiquer un intervalle ou une heure spécifique de mise à jour des podcasts</string>
- <string name="pref_autoUpdateIntervallOrTime_message">Vous pouvez définir un <i>intervalle</i> comme \"toutes les 2 heures\" ou une <i>heure précise</i> comme \"7:00\" ou désactiver les mises à jours automatique.\n\n<small>Note: les heures de mise à jour ne sont pas précises. Vous pouvez avoir un petit délai.</small></string>
+ <string name="pref_autoUpdateIntervallOrTime_message">Vous pouvez définir un <i>intervalle</i> comme \"toutes les 2 heures\" ou une <i>heure précise</i> comme \"7:00\" ou désactiver les mises à jours automatique.\n\n<small>Note : les heures de mise à jour ne sont pas précises. Il peut y avoir un décalage.</small></string>
<string name="pref_autoUpdateIntervallOrTime_Disable">Désactiver</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Intervalle</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Heure</string>
@@ -374,7 +375,7 @@
<string name="pref_unpauseOnHeadsetReconnect_title">Connexion des écouteurs</string>
<string name="pref_unpauseOnBluetoothReconnect_title">Connexion du Bluetooth</string>
<string name="pref_stream_over_download_title">Préférer le streaming</string>
- <string name="pref_stream_over_download_sum">Afficher dans les listes le bouton du streaming au lieu de celui du téléchargement.</string>
+ <string name="pref_stream_over_download_sum">Afficher dans les listes le bouton du streaming au lieu de celui du téléchargement</string>
<string name="pref_mobileUpdate_title">Utilisation de la connexion mobile</string>
<string name="pref_mobileUpdate_sum">Choisir ce qui est autorisé lorsque la connexion mobile est utilisée</string>
<string name="pref_mobileUpdate_refresh">Mise à jour des podcasts</string>
@@ -419,18 +420,22 @@
<string name="pref_gpodnet_setlogin_information_sum">Modifier les information de connexion pour votre compte gpodder.net</string>
<string name="pref_gpodnet_sync_changes_title">Synchroniser maintenant</string>
<string name="pref_gpodnet_sync_changes_sum">Synchroniser l\'état des abonnements et des épisodes avec gpodder.net</string>
- <string name="pref_gpodnet_full_sync_title">Tout synchroniser maintenant</string>
+ <string name="pref_gpodnet_full_sync_title">Forcer une synchronisation totale</string>
<string name="pref_gpodnet_full_sync_sum">Synchroniser tous les abonnements et tous les états des épisodes avec gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Dernière tentative de synchronisation : %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Synchronisation démarrée</string>
<string name="pref_gpodnet_login_status"><![CDATA[Connecté comme <i>%1$s</i> avec l\'appareil <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Notification des erreurs de synchronisation</string>
<string name="pref_gpodnet_notifications_sum">Ce paramètre ne s\'applique pas aux erreurs d\'authentification.</string>
<string name="pref_playback_speed_title">Vitesses de lecture</string>
<string name="pref_playback_speed_sum">Définir les vitesses disponibles lors de la lecture audio</string>
- <string name="pref_feed_playback_speed_sum">Vitesse de lecture par défaut pour les épisodes de ce podcast</string>
+ <string name="pref_feed_playback_speed_sum">Vitesse de lecture par défaut des épisodes</string>
+ <string name="pref_feed_skip">Saut automatique</string>
+ <string name="pref_feed_skip_sum">Sauter le début et la fin des épisodes</string>
+ <string name="pref_feed_skip_ending">Sauter à la fin</string>
+ <string name="pref_feed_skip_intro">Sauter au début</string>
+ <string name="pref_feed_skip_ending_toast">%d dernières secondes sautées</string>
+ <string name="pref_feed_skip_intro_toast">%d premières secondes sautées</string>
<string name="pref_playback_time_respects_speed_title">Ajuster les informations en fonction la vitesse de lecture</string>
- <string name="pref_playback_time_respects_speed_sum">La position et la durée affichée tiendront compte de la vitesse de lecture.</string>
+ <string name="pref_playback_time_respects_speed_sum">La position et la durée affichée tiendront compte de la vitesse de lecture</string>
<string name="pref_fast_forward">Durée du saut avant</string>
<string name="pref_fast_forward_sum">Nombre de secondes à sauter quand le bouton \"saut avant\" est pressé</string>
<string name="pref_rewind">Durée du saut arrière</string>
@@ -447,9 +452,9 @@
<string name="pref_compact_notification_buttons_dialog_error">Vous ne pouvez pas choisir plus de %1$d éléments.</string>
<string name="pref_lockscreen_background_title">Changer l’arrière plan de l\'écran de verrouillage</string>
<string name="pref_lockscreen_background_sum">Placer l\'image de l’épisode en arrière plan de l\'écran de verrouillage. Cela aura aussi pour effet de montrer l\'image dans les autres applications.</string>
- <string name="pref_showDownloadReport_title">Afficher le rapport de téléchargements</string>
+ <string name="pref_showDownloadReport_title">Afficher le rapport des téléchargements</string>
<string name="pref_showDownloadReport_sum">Si les téléchargements échouent, générer un rapport détaillé des échecs.</string>
- <string name="pref_showAutoDownloadReport_title">Rapport de téléchargement automatique</string>
+ <string name="pref_showAutoDownloadReport_title">Rapport du téléchargement automatique</string>
<string name="pref_showAutoDownloadReport_sum">Afficher une notification pour les épisodes téléchargés automatiquement.</string>
<string name="pref_expand_notify_unsupport_toast">Les versions d\'Android antérieures à 4.1 ne sont pas compatibles avec les notifications élargies</string>
<string name="pref_enqueue_location_title">Emplacement des épisodes téléchargés</string>
@@ -479,6 +484,8 @@
<string name="pref_enqueue_downloaded_title">Ajouter à la liste après téléchargement</string>
<string name="pref_enqueue_downloaded_summary">Mettre les épisodes dans la la liste de lecture après téléchargement</string>
<string name="media_player_builtin">Lecteur natif d\'Android</string>
+ <string name="media_player_switch_to_exoplayer">Utiliser ExoPlayer pour la lecture</string>
+ <string name="media_player_switched_to_exoplayer">Lecteur changé pour ExoPlayer</string>
<string name="pref_skip_silence_title">Supprimer les silences audios</string>
<string name="pref_videoBehavior_title">Sorti du lecteur pendant une vidéo</string>
<string name="pref_videoBehavior_sum">Définir ce qu\'il se passe si une vidéo est quittée pendant sa lecture</string>
@@ -496,7 +503,7 @@
<string name="back_button_go_to_page">Aller à la page...</string>
<string name="back_button_go_to_page_title">Sélectionner une page</string>
<string name="pref_delete_removes_from_queue_title">Supprimer retire de la liste de lecture</string>
- <string name="pref_delete_removes_from_queue_sum">Retirer de la liste de lecture les épisodes quand ils sont supprimés.</string>
+ <string name="pref_delete_removes_from_queue_sum">Retirer de la liste de lecture un épisode quand son fichier est supprimé.</string>
<!--About screen-->
<string name="about_pref">À propos</string>
<string name="antennapod_version">Version d\'AntennaPod</string>
@@ -506,11 +513,19 @@
<string name="translators_summary">La traduction est faite par les utilisateurs d\'AntennaPod sur Transifex</string>
<string name="privacy_policy">Politique de confidentialité</string>
<string name="licenses">Licences</string>
- <string name="licenses_summary">AntennaPod s\'appuie sur d\'autres logiciels</string>
+ <string name="licenses_summary">AntennaPod utilise le code d\'autres logiciels</string>
<!--Search-->
<string name="search_status_no_results">Aucun résultat trouvé</string>
<string name="search_label">Recherche</string>
<string name="no_results_for_query">Aucun résultat trouvé pour \"%1$s\"</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">Synchronisation démarrée</string>
+ <string name="sync_status_episodes_upload">Export des statuts des épisodes...</string>
+ <string name="sync_status_episodes_download">Import des statuts des épisodes...</string>
+ <string name="sync_status_upload_played">Export des statuts de lecture...</string>
+ <string name="sync_status_subscriptions">Synchronisation des abonnements...</string>
+ <string name="sync_status_success">Synchronisation réussie</string>
+ <string name="sync_status_error">Echec de la synchronisation</string>
<!--import and export-->
<string name="import_export_summary">Copier les abonnements et la liste de lecture sur un autre appareil</string>
<string name="database">Base de données</string>
@@ -520,16 +535,17 @@
<string name="opml_export_summary">Transférer vos abonnements à une autre application de podcasts</string>
<string name="opml_import_summary">Importer les abonnements d\'une autre application de podcasts</string>
<string name="database_export_summary">Transférer les abonnements, les épisodes écoutés et la liste de lecture sur un autre appareil</string>
- <string name="database_import_summary">Importer une base de donnée AntennaPod d\'un autre appareil</string>
- <string name="opml_import_label">Import OPML</string>
+ <string name="database_import_summary">Importer une base de données AntennaPod d\'un autre appareil</string>
+ <string name="opml_import_label">Importer un fichier OPML</string>
<string name="opml_reader_error">Une erreur s\'est produite pendant la lecture du fichier OPML :</string>
<string name="opml_import_error_no_file">Aucun fichier sélectionné !</string>
<string name="select_all_label">Tout choisir</string>
<string name="deselect_all_label">Ne rien choisir</string>
- <string name="opml_export_label">Export OPML</string>
- <string name="html_export_label">Export HTML</string>
- <string name="database_export_label">Export de la base de données</string>
- <string name="database_import_label">Import de la base de données</string>
+ <string name="opml_export_label">Exporter un fichier OPML</string>
+ <string name="html_export_label">Exporter un fichier HTML</string>
+ <string name="database_export_label">Exporter la base de données</string>
+ <string name="database_import_label">Importer la base de données</string>
+ <string name="database_import_warning">Importer une base de données remplacera tout vos abonnements et votre historique de lecture. Il est conseillé d\'exporter votre base de données actuelle pour avoir une sauvegarde. Confirmez-vous l\'import ?</string>
<string name="please_wait">Merci de patienter...</string>
<string name="export_error_label">Erreur d\'exportation</string>
<string name="export_success_title">Export réussi</string>
@@ -537,7 +553,7 @@
<string name="opml_import_ask_read_permission">L\'accès au stockage externe est requis pour lire le fichier OPML</string>
<string name="import_select_file">Sélectionner le fichier à importer</string>
<string name="import_ok">Import réussi.\n\nAppuyer sur OK pour redémarrer AntennaPod</string>
- <string name="import_no_downgrade">La base de donnée a été exportée avec une version plus récente d\'AntennaPod. L\'application actuelle ne sait pas comment l\'importer.</string>
+ <string name="import_no_downgrade">La base de données a été exportée avec une version plus récente d\'AntennaPod. L\'application actuelle ne sait pas comment l\'importer.</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Activer le minuteur</string>
<string name="disable_sleeptimer_label">Désactiver le minuteur</string>
@@ -615,28 +631,35 @@
<string name="pref_pausePlaybackForFocusLoss_sum">Mettre en pause la lecture au lieu de baisser le volume quand une autre application joue un son</string>
<string name="pref_pausePlaybackForFocusLoss_title">Mettre en pause lors d\'interruptions</string>
<string name="pref_resumeAfterCall_sum">Reprendre la lecture après un appel téléphonique</string>
- <string name="pref_resumeAfterCall_title">Reprendre après appel</string>
+ <string name="pref_resumeAfterCall_title">Reprendre après un appel</string>
<string name="pref_restart_required">AntennaPod doit être redémarré afin que ce changement prenne effet</string>
<!--Online feed view-->
<string name="subscribe_label">S\'abonner</string>
<string name="subscribing_label">Abonnement en cours...</string>
- <string name="preview_episode">Préécouter</string>
+ <string name="preview_episode">Prélecture</string>
+ <string name="stop_preview">Arrêter la prélecture</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Saut arrière</string>
<string name="fast_forward_label">Saut avant</string>
+ <string name="increase_speed">Augmenter la vitesse</string>
+ <string name="decrease_speed">Diminuer la vitesse</string>
<string name="media_type_audio_label">Audio</string>
<string name="media_type_video_label">Vidéo</string>
<string name="navigate_upwards_label">Naviguer vers le haut</string>
<string name="status_downloading_label">L\'épisode est en train d\'être téléchargé</string>
<string name="in_queue_label">L\'épisode est dans la liste de lecture</string>
+ <string name="is_favorite_label">L\'épisode a été ajouté aux favoris</string>
<string name="drag_handle_content_description">Faire glisser pour changer la position de cet élément</string>
<string name="load_next_page_label">Charger la page suivante</string>
+ <string name="switch_pages">Changer les pages</string>
+ <string name="position">Position : %1$s</string>
+ <string name="apply_action">Appliquer l\'action</string>
<!--Feed information screen-->
<string name="authentication_label">Authentification</string>
- <string name="authentication_descr">Identifiant et mot de passe pour ce podcast et ses épisodes.</string>
+ <string name="authentication_descr">Identifiant et mot de passe pour ce podcast.</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 permettant de décider si un épisode est à inclure ou exclure des téléchargements automatiques</string>
+ <string name="episode_filters_description">Liste de mots permettant de décider 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>
@@ -656,6 +679,7 @@
<string name="browse_gpoddernet_label">Chercher sur gpodder.net</string>
<string name="discover">Découvrir</string>
<string name="discover_more">plus »</string>
+ <string name="search_powered_by">Recherche avec %1$s</string>
<string name="filter">Filtrer</string>
<!--Episodes apply actions-->
<string name="all_label">Tous</string>
@@ -683,6 +707,12 @@
<string name="sort_date_old_new">Date (Ancien \u2192 Récent)</string>
<string name="sort_duration_short_long">Durée (Courte \u2192 Longue)</string>
<string name="sort_duration_long_short">Durée (Longue \u2192 Courte)</string>
+ <string name="sort_a_z">A \u2192 Z</string>
+ <string name="sort_z_a">Z \u2192 A</string>
+ <string name="sort_new_old">Récent \u2192 Ancien</string>
+ <string name="sort_old_new">Ancien \u2192 Récent</string>
+ <string name="sort_short_long">Court \u2192 Long</string>
+ <string name="sort_long_short">Long \u2192 Court</string>
<!--Rating dialog-->
<string name="rating_title">Vous aimez AntennaPod ?</string>
<string name="rating_message">Nous vous serions reconnaissant de prendre un peu de temps pour noter AntennaPod.</string>
@@ -742,4 +772,8 @@
<string name="widget_settings">Préférences des widgets</string>
<string name="widget_create_button">Créer un widget</string>
<string name="widget_opacity">Opacité</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">Paramètre mis à jour.</string>
+ <string name="on_demand_config_stream_text">Il semble que vous streamez beaucoup. Voulez-vous que la liste des épisodes montre le bouton de streaming ?</string>
+ <string name="on_demand_config_download_text">Il semble que vous téléchargez beaucoup. Voulez-vous que la liste des épisodes montre le bouton de téléchargement ?</string>
</resources>
diff --git a/core/src/main/res/values-gl/strings.xml b/core/src/main/res/values-gl/strings.xml
index edf5f6043..7ae7d4767 100644
--- a/core/src/main/res/values-gl/strings.xml
+++ b/core/src/main/res/values-gl/strings.xml
@@ -20,7 +20,6 @@
<string name="cancel_download_label">Cancelar\nDescarga</string>
<string name="playback_history_label">Historial de reprodución</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Sincronizar con outros dispositivos</string>
<string name="gpodnet_auth_label">gpodder.net Conexión</string>
<string name="episode_cache_full_title">Caché de episodios chea</string>
<string name="episode_cache_full_message">Acadouse o límite de espazo na caché de episodios. Podes incrementalo nos Axustes do tamaño da caché.</string>
@@ -86,7 +85,7 @@
<string name="auto_download_apply_to_items_message">A nova función <i>Descarga automática</i> aplicarase automáticamente aos novos episodios.\nQueres que tamén se aplique aos episodios publicados con anterioridade?</string>
<string name="auto_delete_label">Borrado automático do episodio</string>
<string name="feed_volume_reduction">Redución do volume</string>
- <string name="feed_volume_reduction_summary">Baixar o volume para os episodios desta fonte: \%s</string>
+ <string name="feed_volume_reduction_summary">Baixar o volume para os episodios desta fonte: %1$s</string>
<string name="feed_volume_reduction_off">Apagado</string>
<string name="feed_volume_reduction_light">Claro</string>
<string name="feed_volume_reduction_heavy">Forte</string>
@@ -106,7 +105,10 @@
<item quantity="one">1 día despois de rematar</item>
<item quantity="other">%d días despois de rematar</item>
</plurals>
- <string name="num_selected_label">%d escollido</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">%d seleccionado</item>
+ <item quantity="other">%d seleccionados</item>
+ </plurals>
<string name="loading_more">Cargando máis...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Marcar todo como reproducido</string>
@@ -203,6 +205,7 @@
<string name="deactivate_auto_download">Desactivar a descarga automática</string>
<string name="reset_position">Reiniciar a posición de reprodución</string>
<string name="removed_item">Elmento eleminado</string>
+ <string name="no_items_selected">Sen selección</string>
<!--Download messages and labels-->
<string name="download_successful">exitoso</string>
<string name="download_pending">Descarga pendente</string>
@@ -289,8 +292,6 @@
<string name="ascending">Ascendente</string>
<string name="descending">Descendente</string>
<string name="clear_queue_confirmation_msg">Por favor confirme que quere limpar a cola e TODOS os episodios nela</string>
- <string name="sort_old_to_new">Antigo a novo</string>
- <string name="sort_new_to_old">Novo a antigo</string>
<string name="time_left_label">Tempo restante:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Descargar engadido</string>
@@ -325,8 +326,8 @@
<string name="storage_sum">Borrado automático do episodio, Importar, Exportar</string>
<string name="project_pref">Proxecto</string>
<string name="queue_label">Cola</string>
- <string name="integrations_label">Integracións</string>
- <string name="integrations_sum">Sincronización</string>
+ <string name="synchronization_pref">Sincronización</string>
+ <string name="synchronization_sum">Sincronizar con outros dispositivos usando gpodder.net</string>
<string name="automation">Automatizado</string>
<string name="download_pref_details">Detalles</string>
<string name="import_export_pref">Importar/Exportar</string>
@@ -417,18 +418,22 @@
<string name="pref_gpodnet_logout_toast">Desconectouse correctamente</string>
<string name="pref_gpodnet_setlogin_information_title">Cambiar a información de conexión</string>
<string name="pref_gpodnet_setlogin_information_sum">Cambiar a información de conexión da súa conta gpodder.net</string>
- <string name="pref_gpodnet_sync_changes_title">Sincronizar os cambios agora</string>
+ <string name="pref_gpodnet_sync_changes_title">Sincronizar agora</string>
<string name="pref_gpodnet_sync_changes_sum">Sincronizar os datos de subscrición e estado dos episodios con gpodder.net</string>
- <string name="pref_gpodnet_full_sync_title">Sincronice todo agora</string>
+ <string name="pref_gpodnet_full_sync_title">Forzar sincronización completa</string>
<string name="pref_gpodnet_full_sync_sum">Sincronizar todas as subscricións e estados de episodios con gpodder.net</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Último intento de sincronización: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Sincronización iniciada</string>
<string name="pref_gpodnet_login_status"><![CDATA[Conectada como <i>%1$s</i> co dispositivo <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Mostrar notificacións de erros na sincronización.</string>
<string name="pref_gpodnet_notifications_sum">Esta preferencia non se aplica a fallos na autenticación.</string>
<string name="pref_playback_speed_title">Velocidades de reprodución</string>
<string name="pref_playback_speed_sum">Personaliza a velocidade variable de reprodución de audio</string>
<string name="pref_feed_playback_speed_sum">A velocidade para reproducir o contido dos episodios deste podcast</string>
+ <string name="pref_feed_skip">Salto automático</string>
+ <string name="pref_feed_skip_sum">Saltar introducións e créditos finais.</string>
+ <string name="pref_feed_skip_ending">Saltar o final</string>
+ <string name="pref_feed_skip_intro">Saltar o principio</string>
+ <string name="pref_feed_skip_ending_toast">Saltados os últimos %d segundos</string>
+ <string name="pref_feed_skip_intro_toast">Saltados os primeiros %d segundos</string>
<string name="pref_playback_time_respects_speed_title">Axustar info dos medios a velocidade de reprodución</string>
<string name="pref_playback_time_respects_speed_sum">A posición mostrada e a duración están adaptadas a velocidade de reprodución</string>
<string name="pref_fast_forward">Avance rápido Salta tempo</string>
@@ -479,6 +484,8 @@
<string name="pref_enqueue_downloaded_title">Foron descargados os elementos da cola</string>
<string name="pref_enqueue_downloaded_summary">Engadir os episodios descargados a cola</string>
<string name="media_player_builtin">Reprodutor android nativo</string>
+ <string name="media_player_switch_to_exoplayer">Cambiar a ExoPlayer</string>
+ <string name="media_player_switched_to_exoplayer">Cambiaches a ExoPlayer.</string>
<string name="pref_skip_silence_title">Saltar silencio no Audio</string>
<string name="pref_videoBehavior_title">Ao saír do vídeo</string>
<string name="pref_videoBehavior_sum">Comportamento cando saia do vídeo</string>
@@ -511,6 +518,14 @@
<string name="search_status_no_results">Non se atoparon resultados</string>
<string name="search_label">Buscar</string>
<string name="no_results_for_query">Non hai resultados para \"%1$s\"</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">Comezou a sincr.</string>
+ <string name="sync_status_episodes_upload">Subindo cambios nos episodios...</string>
+ <string name="sync_status_episodes_download">Descargando cambios nos episodios...</string>
+ <string name="sync_status_upload_played">Subindo estado de reprodución...</string>
+ <string name="sync_status_subscriptions">Sincronizando subscricións...</string>
+ <string name="sync_status_success">Sincronización correcta</string>
+ <string name="sync_status_error">Fallou a sincronización</string>
<!--import and export-->
<string name="import_export_summary">Mover subscricións e cola a outro dispositivo</string>
<string name="database">Base de datos</string>
@@ -530,6 +545,7 @@
<string name="html_export_label">Exportar HTML</string>
<string name="database_export_label">Exportar base de datos</string>
<string name="database_import_label">Importar base de datos</string>
+ <string name="database_import_warning">Ao importar a base de datos substituirás todas as subscricións actuais e historial de reprodución. Deberías exportar a base de datos actual como copia de apoio. Desexas substituíla?</string>
<string name="please_wait">Agarda...</string>
<string name="export_error_label">Fallo ao exportar</string>
<string name="export_success_title">Exportado con éxito</string>
@@ -621,16 +637,23 @@
<string name="subscribe_label">Subscribir</string>
<string name="subscribing_label">Subscribindo...</string>
<string name="preview_episode">Vista previa</string>
+ <string name="stop_preview">Deter vista previa</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Rebobinar</string>
<string name="fast_forward_label">Avance rápido</string>
+ <string name="increase_speed">Aumentar velocidade</string>
+ <string name="decrease_speed">Diminuír velocidade</string>
<string name="media_type_audio_label">Son</string>
<string name="media_type_video_label">Vídeo</string>
<string name="navigate_upwards_label">Navegar hacia arriba</string>
<string name="status_downloading_label">Estase a descargar o episodio</string>
<string name="in_queue_label">O episodio está na cola</string>
+ <string name="is_favorite_label">Episodio marcado como favorito</string>
<string name="drag_handle_content_description">Arrastre para mudar a posición de este elemento</string>
<string name="load_next_page_label">Cargar a seguinte páxina</string>
+ <string name="switch_pages">Cambiar de páxina</string>
+ <string name="position">Posición: %1$s</string>
+ <string name="apply_action">Aplicar acción</string>
<!--Feed information screen-->
<string name="authentication_label">Autenticación</string>
<string name="authentication_descr">Cambiar o seu nome de usuaria e contrasinal para este podcast e os seus episodios.</string>
@@ -656,6 +679,7 @@
<string name="browse_gpoddernet_label">Buscar en gpodder.net</string>
<string name="discover">Descubrir</string>
<string name="discover_more">máis »</string>
+ <string name="search_powered_by">Busca xestionada por %1$s</string>
<string name="filter">Filtrado</string>
<!--Episodes apply actions-->
<string name="all_label">Todo</string>
@@ -683,6 +707,12 @@
<string name="sort_date_old_new">Data (Vello \u2192 Novo)</string>
<string name="sort_duration_short_long">Duración (Curto \u2192 Longo)</string>
<string name="sort_duration_long_short">Duración (Longo \u2192 Curto)</string>
+ <string name="sort_a_z">A \u2192 Z</string>
+ <string name="sort_z_a">Z \u2192 A</string>
+ <string name="sort_new_old">Novo \u2192 Antigo</string>
+ <string name="sort_old_new">Antigo \u2192 Novo</string>
+ <string name="sort_short_long">Curto \u2192 Longo</string>
+ <string name="sort_long_short">Longo \u2192 Curto</string>
<!--Rating dialog-->
<string name="rating_title">Goza de AntennaPod?</string>
<string name="rating_message">Agradeceríamos que dedicase un intre a valorar AntennaPod.</string>
@@ -742,4 +772,8 @@
<string name="widget_settings">Axustes do Widget</string>
<string name="widget_create_button">Crear widget</string>
<string name="widget_opacity">Opacidade</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">Actualizouse o axuste.</string>
+ <string name="on_demand_config_stream_text">Semella que prefires a Difusión. Queres que a lista de episodios mostre botóns de Difusión?</string>
+ <string name="on_demand_config_download_text">Semella que prefires as Descargas. Queres que a lista de episodios mostre botóns de Descarga?</string>
</resources>
diff --git a/core/src/main/res/values-hi/strings.xml b/core/src/main/res/values-hi/strings.xml
index e0dc438d7..ee843fae4 100644
--- a/core/src/main/res/values-hi/strings.xml
+++ b/core/src/main/res/values-hi/strings.xml
@@ -19,7 +19,6 @@
<string name="cancel_download_label">डाउनलोड रद्द करें</string>
<string name="playback_history_label">प्लेबैक इतिहास</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">अन्य उपकरण के साथ समक्रमिक करें</string>
<string name="gpodnet_auth_label">gpodder.net लॉगिन</string>
<string name="episode_cache_full_title">एपिसोड कैश भर गया है</string>
<string name="episode_cache_full_message">एपिसोड कैश सीमा तक पहुंच गया है। आप सेटिंग में कैश का आकार बढ़ा सकते हैं।</string>
@@ -267,6 +266,7 @@
<!--Search-->
<string name="search_status_no_results">कोई परिणाम नहीं मिले</string>
<string name="search_label">खोज</string>
+ <!--Synchronization-->
<!--import and export-->
<string name="opml_import_label">OPML आयात</string>
<string name="select_all_label">सभी का चयन करें</string>
@@ -336,4 +336,5 @@
<!--Casting-->
<!--Notification channels-->
<!--Widget settings-->
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-hu/strings.xml b/core/src/main/res/values-hu/strings.xml
index db47ccf3d..23cf5df9f 100644
--- a/core/src/main/res/values-hu/strings.xml
+++ b/core/src/main/res/values-hu/strings.xml
@@ -2,6 +2,7 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--Activity and fragment titles-->
<string name="feed_update_receiver_name">Feliratkozások frissítése</string>
+ <string name="feeds_label">Podcastok</string>
<string name="statistics_label">Statisztika</string>
<string name="add_feed_label">Podcast hozzáadása</string>
<string name="episodes_label">Epizódok</string>
@@ -16,13 +17,14 @@
<string name="downloads_log_label">Napló</string>
<string name="subscriptions_label">Feliratkozások</string>
<string name="subscriptions_list_label">Feliratkozások listája</string>
- <string name="cancel_download_label">Letöltés\nmegállítása</string>
+ <string name="cancel_download_label">Letöltés\nmegszakítása</string>
<string name="playback_history_label">Lejátszási napló</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Szinkronizáció más eszközökkel</string>
<string name="gpodnet_auth_label">gpodder.net bejelentkezés</string>
<string name="episode_cache_full_title">Epizód tárhely megtelt</string>
<string name="episode_cache_full_message">Az epizódok tárolására megadott maximális tárhely megtelt. A mérete a beállításokban növelhető meg.</string>
+ <string name="playback_statistics_label">Lejátszás</string>
+ <string name="download_statistics_label">Letöltések</string>
<!--Statistics fragment-->
<string name="total_time_listened_to_podcasts">A lejátszott podcastok összideje:</string>
<string name="statistics_details_dialog">%1$d/%2$d epizód elindítva.\n\n%3$s/%4$s lejátszva.</string>
@@ -31,7 +33,9 @@
<string name="statistics_mode_count_all">Az összes lejátszottnak jelölt podcast összeszámolása</string>
<string name="statistics_speed_not_counted">Megjegyzés: a lejátszási sebesség nem lesz beleszámítva.</string>
<string name="statistics_reset_data">Statisztikai adatok alaphelyzetbe állítása</string>
+ <string name="statistics_reset_data_msg">Ez törli az összes epizód lejátszási hosszát. Biztos, hogy folytatja?</string>
<!--Download Statistics fragment-->
+ <string name="total_size_downloaded_podcasts">A letöltött podcastok összmérete:</string>
<!--Main activity-->
<string name="drawer_open">Menü megnyitása</string>
<string name="drawer_close">Menü bezárása</string>
@@ -80,6 +84,11 @@
<string name="auto_download_apply_to_items_title">Alkalmazás az előző epizódokra</string>
<string name="auto_download_apply_to_items_message">A beállított <i>Automatikus letöltés</i> az új epizódokra lesz érvényes.\nAlkalmazza a korábban közzétett epizódokra is?</string>
<string name="auto_delete_label">Epizód automatikus törlése</string>
+ <string name="feed_volume_reduction">Hangerőcsökkentés</string>
+ <string name="feed_volume_reduction_summary">Az ebbe a csatornába tartozó epizódok hangerejének csökkentése: %1$s</string>
+ <string name="feed_volume_reduction_off">Ki</string>
+ <string name="feed_volume_reduction_light">Enyhe</string>
+ <string name="feed_volume_reduction_heavy">Erős</string>
<string name="parallel_downloads_suffix">\u0020párhuzamos letöltés</string>
<string name="feed_auto_download_global">Globális alapértelmezett</string>
<string name="feed_auto_download_always">Mindig</string>
@@ -96,7 +105,11 @@
<item quantity="one">befejezés után 1 nappal</item>
<item quantity="other">befejezés után %d nappal</item>
</plurals>
- <string name="num_selected_label">%d kiválasztva</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">%d kiválasztva</item>
+ <item quantity="other">%d kiválasztva</item>
+ </plurals>
+ <string name="loading_more">Továbbiak betöltése…</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Az összes megjelölése lejátszottként</string>
<string name="mark_all_read_msg">Az összes epizód lejátszottnak jelölve</string>
@@ -116,11 +129,13 @@
<string name="share_link_with_position_label">Epizód URL megosztása pozícióval</string>
<string name="share_file_label">Fájl megosztása</string>
<string name="share_website_url_label">Honlap URL megosztása</string>
+ <string name="share_feed_url_label">Podcast URL megosztása</string>
<string name="share_item_url_label">Médiafájl URL megosztása</string>
<string name="share_item_url_with_position_label">Médiafájl URL megosztása pozícióval</string>
<string name="feed_delete_confirmation_msg">Erősítse meg, hogy törli a(z) „%1$s” podcastot, és az ÖSSZES epizódját (a letöltött epizódokat is beleértve).</string>
<string name="feed_remover_msg">Podcast eltávolítása</string>
<string name="load_complete_feed">Teljes podcast frissítése</string>
+ <string name="multi_select">Több kiválasztása</string>
<string name="select_all_above">Az összes felette lévő kiválasztása</string>
<string name="select_all_below">Az összes alatta lévő kiválasztása</string>
<string name="hide_unplayed_episodes_label">Nem lejátszott</string>
@@ -135,6 +150,7 @@
<string name="filtered_label">Szűrt</string>
<string name="refresh_failed_msg">{fa-exclamation-circle} A legutóbbi frissítés sikertelen</string>
<string name="open_podcast">Podcast megnyitása</string>
+ <string name="please_wait_for_data">Várjon az adatok betöltésére</string>
<!--actions on feeditems-->
<string name="download_label">Letöltés</string>
<plurals name="downloading_batch_label">
@@ -155,11 +171,15 @@
<string name="removed_new_flag_label">Az „új” jelző eltávolítva</string>
<string name="mark_read_label">Megjelölés lejátszottként</string>
<string name="marked_as_read_label">Megjelölve lejátszottként</string>
+ <string name="mark_read_no_media_label">Megjelölés olvasottként</string>
+ <string name="marked_as_read_no_media_label">Megjelölve olvasottként</string>
+ <string name="play_this_to_seek_position">A pozíciókra ugráshoz le kell játszania az epizódot</string>
<plurals name="marked_read_batch_label">
<item quantity="one">%d epizód megjelölve lejátszottként.</item>
<item quantity="other">%d epizód megjelölve lejátszottként.</item>
</plurals>
<string name="mark_unread_label">Megjelölés nem lejátszottként</string>
+ <string name="mark_unread_label_no_media">Megjelölés olvasatlanként</string>
<plurals name="marked_unread_batch_label">
<item quantity="one">%d epizód megjelölve nem lejátszottként.</item>
<item quantity="other">%d epizód megjelölve nem lejátszottként.</item>
@@ -185,6 +205,7 @@
<string name="deactivate_auto_download">Automatikus letöltés kikapcsolása</string>
<string name="reset_position">Lejátszási pozíció visszaállítása</string>
<string name="removed_item">Elem eltávolítva</string>
+ <string name="no_items_selected">Nincs elem kiválasztva</string>
<!--Download messages and labels-->
<string name="download_successful">sikeres</string>
<string name="download_pending">Letöltés várakozik</string>
@@ -205,6 +226,7 @@
<string name="download_canceled_msg">Letöltés megszakítva</string>
<string name="download_canceled_autodownload_enabled_msg">Letöltés megszakítva\n<i>Automatikus letöltése</i> letiltva az elemnél</string>
<string name="download_report_title">A letöltések hibákkal fejeződtek be</string>
+ <string name="auto_download_report_title">Elkészültek az automatikus letöltések</string>
<string name="download_report_content_title">Letöltési jelentés</string>
<string name="download_error_malformed_url">Hibás URL</string>
<string name="download_error_io_error">Ki-/bemeneti hiba</string>
@@ -241,16 +263,19 @@
<string name="playback_error_server_died">A kiszolgálókapcsolat megszakadt</string>
<string name="playback_error_unsupported">Nem támogatott médiatípus</string>
<string name="playback_error_timeout">Műveleti időtúllépés</string>
+ <string name="playback_error_source">A médiafájl nem érhető el</string>
<string name="playback_error_unknown">Ismeretlen hiba</string>
<string name="no_media_playing_label">Nincs médialejátszás</string>
<string name="player_buffering_msg">Pufferelés</string>
<string name="player_go_to_picture_in_picture">Kép a képben mód</string>
<string name="unknown_media_key">AntennaPod – Ismeretlen médiabillentyű: %1$d</string>
+ <string name="error_file_not_found">A fájl nem találhat</string>
<!--Queue operations-->
<string name="lock_queue">Lejátszási sor zárolása</string>
<string name="unlock_queue">Lejátszási sor feloldása</string>
<string name="queue_locked">Lejátszási sor zárolva</string>
<string name="queue_unlocked">Lejátszási sor feloldva</string>
+ <string name="queue_lock_warning">Ha zárolja a sort, akkor többé nem seperheti ki vagy rendezheti át az epizódokat</string>
<string name="checkbox_do_not_show_again">Ne mutassa újra</string>
<string name="clear_queue_label">Lejátszási sor kiürítése</string>
<string name="undo">Visszavonás</string>
@@ -267,12 +292,11 @@
<string name="ascending">Növekvő</string>
<string name="descending">Csökkenő</string>
<string name="clear_queue_confirmation_msg">Erősítse meg, hogy törölni akarja az ÖSSZES epizódot a sorból</string>
- <string name="sort_old_to_new">Régitől az újig</string>
- <string name="sort_new_to_old">Újtól a régiig</string>
<string name="time_left_label">Hátralévő idő:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Bővítmény letöltése</string>
<string name="no_playback_plugin_title">A bővítmény nincs telepítve</string>
+ <string name="no_playback_plugin_or_sonic_msg">A változó lejátszási sebesség működéséhez azt javasoljuk, hogy engedélyezze a beépített Sonic médialejátszót.</string>
<string name="set_playback_speed_label">Lejátszási sebesség</string>
<string name="enable_sonic">Sonic engedélyezése</string>
<!--Empty list labels-->
@@ -299,9 +323,11 @@
<string name="no_subscriptions_label">Podcastra való feliratkozáshoz nyomja meg az alábbi plusz ikont.</string>
<!--Preferences-->
<string name="storage_pref">Tároló</string>
+ <string name="storage_sum">Epizódok automatikus törlése, importálása, exportálása</string>
<string name="project_pref">Projekt</string>
<string name="queue_label">Lejátszási sor</string>
- <string name="integrations_label">Integrációk</string>
+ <string name="synchronization_pref">Szinkronizálás</string>
+ <string name="synchronization_sum">Szinkronizáció más eszközökkel a gpodder.net segítségével</string>
<string name="automation">Automatizálás</string>
<string name="download_pref_details">Részletek</string>
<string name="import_export_pref">Importálás/exportálás</string>
@@ -333,8 +359,11 @@
<string name="pref_favorite_keeps_episodes_sum">Epizódok megtartása, ha kedvencnek vannak jelölve</string>
<string name="pref_favorite_keeps_episodes_title">Kedvenc epizódok megtartása</string>
<string name="playback_pref">Lejátszás</string>
+ <string name="playback_pref_sum">Fejhallgató-vezérlők, léptetési időközök, lejátszási sor</string>
<string name="network_pref">Hálózat</string>
+ <string name="network_pref_sum">Frissítési időköz, letöltésvezérlők, mobil adathasználat</string>
<string name="pref_autoUpdateIntervallOrTime_title">Frissítési intervallum vagy időpont</string>
+ <string name="pref_autoUpdateIntervallOrTime_sum">Adjon meg egy intervallumot vagy egy adott időpontot, amikor a podcastok automatikusan frissítésre kerülnek</string>
<string name="pref_autoUpdateIntervallOrTime_message">Megadhat egy &lt;i&gt;intervallumot&lt;/i&gt;, mint „2 óránként”, megadhat egy konkrét &lt;i&gt;időpontot&lt;/i&gt;, mint „de. 7:00” vagy letilthatja &lt;i&gt;letilthatja&lt;/i&gt; a frissítéseket.\n\nMegjegyzés: A frissítési idők nem pontosak. Rövid késleltetést tapasztalhat.&lt;small&gt;</string>
<string name="pref_autoUpdateIntervallOrTime_Disable">Letiltás</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Intervallum megadása</string>
@@ -349,11 +378,13 @@
<string name="pref_stream_over_download_sum">Letöltés gomb helyett adatátvitel gomb megjelenítése listákban.</string>
<string name="pref_mobileUpdate_title">Frissítések mobil adatkapcsolaton</string>
<string name="pref_mobileUpdate_sum">Válassza ki, hogy mit engedélyez mobil adatkapcsolaton keresztül</string>
+ <string name="pref_mobileUpdate_refresh">Podcast frissítése</string>
<string name="pref_mobileUpdate_images">Borítóképek</string>
<string name="pref_mobileUpdate_auto_download">Automatikus letöltés</string>
<string name="pref_mobileUpdate_episode_download">Epizódletöltés</string>
<string name="pref_mobileUpdate_streaming">Adatátvitel</string>
<string name="user_interface_label">Felhasználói felület</string>
+ <string name="user_interface_sum">Megjelenés, feliratkozási sorrend, képernyőzár</string>
<string name="pref_set_theme_title">Téma kiválasztása</string>
<string name="pref_nav_drawer_items_title">Navigációs fiók elemeinek beállítása</string>
<string name="pref_nav_drawer_items_sum">A navigációs fiókban megjelenő elemek módosítása.</string>
@@ -372,6 +403,7 @@
<string name="pref_episode_cache_title">Epizód tárhely</string>
<string name="pref_episode_cache_summary">Az eszközön tárolt letöltött epizódok száma. Az automatikus letöltés felfüggesztésre kerül, ha eléri ezt a számot.</string>
<string name="pref_episode_cover_title">Epizód borítókép használata</string>
+ <string name="pref_episode_cover_summary">Epizódspecifikus borító használata, ha lehetséges. Ha nincs bekapcsolva, akkor az alkalmazás mindig a podcast borítóját fogja használni.</string>
<string name="pref_theme_title_use_system">Rendszertéma használata</string>
<string name="pref_theme_title_light">Világos</string>
<string name="pref_theme_title_dark">Sötét</string>
@@ -386,17 +418,20 @@
<string name="pref_gpodnet_logout_toast">Kijelentkezés sikeres</string>
<string name="pref_gpodnet_setlogin_information_title">Bejelentkezési adatok módosítása</string>
<string name="pref_gpodnet_setlogin_information_sum">A gpodder.net fiókjához használt bejelentkezési adatok módosítása.</string>
- <string name="pref_gpodnet_sync_changes_title">Változások szinkronizálása most</string>
+ <string name="pref_gpodnet_sync_changes_title">Szinkronizálás most</string>
<string name="pref_gpodnet_sync_changes_sum">A feliratkozásai és epizódállapotainak szinkronizálása a gpodder.nettel.</string>
- <string name="pref_gpodnet_full_sync_title">Teljes szinkronizálás most</string>
+ <string name="pref_gpodnet_full_sync_title">Teljes szinkronizáció kényszerítése</string>
<string name="pref_gpodnet_full_sync_sum">Az összes feliratkozásának és epizódállapotainak szinkronizálása a gpodder.nettel.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Legutóbbi szinkronizálási kísérlet: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Szinkronizálás elkezdődött</string>
<string name="pref_gpodnet_login_status"><![CDATA[Bejelentkezve mint <i>%1$s</i>, a(z) <i>%2$s</i> eszközzel]]></string>
<string name="pref_gpodnet_notifications_title">Szinkronizálási hibaértesítések megjelenítése</string>
<string name="pref_gpodnet_notifications_sum">Ez a beállítás a hitelesítési hibákra nem érvényes.</string>
<string name="pref_playback_speed_title">Lejátszási sebességek</string>
<string name="pref_playback_speed_sum">A változó sebességű hanglejátszáshoz elérhető sebességek testreszabása</string>
+ <string name="pref_feed_playback_speed_sum">A podcast epizódjainak indításakor használandó lejátszási sebesség</string>
+ <string name="pref_feed_skip">Automatikus kihagyás</string>
+ <string name="pref_feed_skip_sum">Bevezetők és lezárások kihagyása</string>
+ <string name="pref_feed_skip_ending_toast">Utolsó %d másodperc kihagyvas</string>
+ <string name="pref_feed_skip_intro_toast">Első %d másodperc kihagyva</string>
<string name="pref_playback_time_respects_speed_title">Médiainformáció hozzáigazítása a lejátszási sebességhez</string>
<string name="pref_playback_time_respects_speed_sum">A megjelenített pozíció és hossz a lejátszási sebességhez lesz igazítva</string>
<string name="pref_fast_forward">Előretekerés mértéke</string>
@@ -409,14 +444,16 @@
<string name="pref_expandNotify_sum">Ez általában kibővíti az értesítést, hogy megjelenítse a lejátszási gombokat.</string>
<string name="pref_persistNotify_title">Állandó lejátszásvezérlők</string>
<string name="pref_persistNotify_sum">Az értesítés és a zárképernyőn megjelenő vezérlők megtartása a lejátszás szüneteltetésekor.</string>
- <string name="pref_compact_notification_buttons_title">Zárképernyő gombok beállítása</string>
- <string name="pref_compact_notification_buttons_sum">A zárképernyőn megjelenő lejátszási gombok módosítása. A lejátszás/szüneteltetés gombok mindig szerepel.</string>
+ <string name="pref_compact_notification_buttons_title">Zárképerny-gombok beállítása</string>
+ <string name="pref_compact_notification_buttons_sum">A zárképernyőn megjelenő lejátszási gombok módosítása. A lejátszás/szüneteltetés gombok mindig szerepelnek.</string>
<string name="pref_compact_notification_buttons_dialog_title">Válasszon legfeljebb %1$d elemet</string>
<string name="pref_compact_notification_buttons_dialog_error">Legfeljebb %1$d elemet választhat.</string>
<string name="pref_lockscreen_background_title">Képernyőzár háttérkép beállítása</string>
<string name="pref_lockscreen_background_sum">A képernyőzár háttérképének beállítása a jelenlegi epizód képére. Mellékhatásként, ez a harmadik féltől származó alkalmazásokban is megjeleníti a képet.</string>
<string name="pref_showDownloadReport_title">Letöltési jelentés megtekintése</string>
<string name="pref_showDownloadReport_sum">Ha a letöltések sikertelenek, előállít egy jelentést, amely részletezi a hibát</string>
+ <string name="pref_showAutoDownloadReport_title">Automatikus letöltési jelentés megjelenítése</string>
+ <string name="pref_showAutoDownloadReport_sum">Értesítés megjelenítése az automatikusan letöltött epizódokhoz.</string>
<string name="pref_expand_notify_unsupport_toast">A 4.1 előtti Android verziók nem támogatják a bővített értesítéseket.</string>
<string name="pref_enqueue_location_title">Hely sorbaállítása</string>
<string name="pref_enqueue_location_sum">Epizódok hozzáadása ehhez: %1$s</string>
@@ -426,8 +463,10 @@
<string name="pref_smart_mark_as_played_disabled">Letiltva</string>
<string name="pref_image_cache_size_title">Kép gyorsítótár mérete</string>
<string name="pref_image_cache_size_sum">Kép gyorsítótár mérete a lemezen.</string>
+ <string name="visit_user_forum">Felhasználói fórum</string>
<string name="bug_report_title">Hibajelentés</string>
<string name="open_bug_tracker">Hibakövető megnyitása</string>
+ <string name="export_logs">Naplók exportálása</string>
<string name="copy_to_clipboard">Másolás vágólapra</string>
<string name="copied_to_clipboard">Vágólapra másolva</string>
<string name="experimental_pref">Kísérleti</string>
@@ -443,6 +482,8 @@
<string name="pref_enqueue_downloaded_title">Letöltött elemek sorbaállítása</string>
<string name="pref_enqueue_downloaded_summary">Letöltött epizódok sorhoz adása</string>
<string name="media_player_builtin">Beépített androidos lejátszó</string>
+ <string name="media_player_switch_to_exoplayer">Váltás az ExoPlayerre</string>
+ <string name="media_player_switched_to_exoplayer">Átváltva az ExoPlayerre.</string>
<string name="pref_skip_silence_title">Csend kihagyása a hangokban</string>
<string name="pref_videoBehavior_title">A videóból kilépéskor</string>
<string name="pref_videoBehavior_sum">Viselkedés a videolejátszás elhagyásakor</string>
@@ -475,25 +516,41 @@
<string name="search_status_no_results">Nincsenek találatok</string>
<string name="search_label">Keresés</string>
<string name="no_results_for_query">Nincs találat a következőre: „%1$s”</string>
+ <!--Synchronization-->
<!--import and export-->
+ <string name="import_export_summary">Feliratkozások áthelyezése, és sorbaállítás egy másik eszközön</string>
+ <string name="database">Adatbázis</string>
+ <string name="opml">OPML</string>
+ <string name="html">HTML</string>
+ <string name="html_export_summary">Feliratkozások megjelenítése egy barát számára</string>
+ <string name="opml_export_summary">A feliratkozásai átküldése egy másik podcast alkalmazásnak</string>
+ <string name="opml_import_summary">Feliratkozások importálása egy másik podcast alkalmazásból</string>
+ <string name="database_export_summary">Feliratkozások, meghallgatott epizódok és a lejátszási sor átküldése egy másik eszközök lévő AntennaPodnak</string>
+ <string name="database_import_summary">AntennaPod adatbázis importálása egy másik eszközről</string>
<string name="opml_import_label">OPML importálása</string>
- <string name="opml_reader_error">Hiba történt az OPML dokumentum olvasásakor:</string>
+ <string name="opml_reader_error">Hiba történt az OPML-dokumentum olvasásakor:</string>
<string name="opml_import_error_no_file">Nincs fájl kiválasztva!</string>
<string name="select_all_label">Összes kiválasztása</string>
<string name="deselect_all_label">Összes kiválasztásának megszüntetése</string>
<string name="opml_export_label">OPML exportálása</string>
<string name="html_export_label">HTML exportálása</string>
+ <string name="database_export_label">Adatbázis exportálása</string>
+ <string name="database_import_label">Adatbázis importálása</string>
+ <string name="please_wait">Várjon…</string>
<string name="export_error_label">Exportálási hiba</string>
<string name="export_success_title">Exportálás sikeres</string>
<string name="export_success_sum">Az exportált fájl ide lett kiírva:\n\n%1$s</string>
<string name="opml_import_ask_read_permission">A külső tároló elérése szükséges az OPML fájl olvasásához</string>
<string name="import_select_file">Importálandó fájl kiválasztása</string>
<string name="import_ok">Importálás sikeres.\n\nNyomja meg az OK gombot az AntennaPod újraindításához</string>
+ <string name="import_no_downgrade">Az adatbázis az AntennaPod egy újabb verziójából lett exportálva. A jelenlegi telepítése még nem tudja, hogyan kezelje ezt a fájlt.</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Alvási időzítő beállítása</string>
<string name="disable_sleeptimer_label">Alvási időzítő letiltása</string>
<string name="sleep_timer_label">Alvási időzít</string>
<string name="time_dialog_invalid_input">Érvénytelen bemenet, az időnek egész számnak kell lennie</string>
+ <string name="shake_to_reset_label">Rázás a visszaállításához</string>
+ <string name="timer_vibration_label">Rövid vibrálás a befejezés előtt</string>
<string name="time_seconds">másodperc</string>
<string name="time_minutes">perc</string>
<string name="time_hours">óra</string>
@@ -569,6 +626,7 @@
<!--Online feed view-->
<string name="subscribe_label">Feliratkozás</string>
<string name="subscribing_label">Feliratkozás…</string>
+ <string name="preview_episode">Előnézet</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Visszatekerés</string>
<string name="fast_forward_label">Előretekerés</string>
@@ -589,6 +647,7 @@
<string name="episode_filters_exclude">Kihagyás</string>
<string name="episode_filters_hint">Különálló szavak\n„Több szó”</string>
<string name="keep_updated">Frissítse</string>
+ <string name="keep_updated_summary">Vegye bele ezt a podcastot is az összes podcast (automatikus) frissítésébe</string>
<string name="auto_download_disabled_globally">Az automatikus letöltés ki van kapcsolva a fő AntennaPod beállításokban</string>
<!--Progress information-->
<string name="progress_upgrading_database">Az adatbázis frissítése</string>
@@ -598,6 +657,8 @@
<string name="search_podcast_hint">Podcast keresése…</string>
<string name="search_itunes_label">Keresés az iTunes-on</string>
<string name="search_fyyd_label">Keresés a fyyden</string>
+ <string name="advanced">Speciális</string>
+ <string name="add_podcast_by_url">Podcast hozzáadása URL alapján</string>
<string name="browse_gpoddernet_label">A gpodder.net böngészése</string>
<string name="discover">Felfedezés</string>
<string name="discover_more">több »</string>
@@ -681,8 +742,11 @@
<string name="notification_channel_playing_description">Lehetővé teszi a lejátszás vezérlését. Ez a fő értesítés, amit a podcast lejátszásakor lát.</string>
<string name="notification_channel_error">Hibák</string>
<string name="notification_channel_error_description">Akkor látszik, ha hiba történt, például ha a letöltés vagy a gpodder szinkronizálás sikertelen.</string>
+ <string name="notification_channel_auto_download">Automatikus letöltések</string>
+ <string name="notification_channel_episode_auto_download">Akkor jelenik meg, ha az epizódok automatikusan letöltésre kerültek.</string>
<!--Widget settings-->
<string name="widget_settings">Widget beállítások</string>
<string name="widget_create_button">Widget létrehozása</string>
<string name="widget_opacity">Átlátszatlanság</string>
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-it/strings.xml b/core/src/main/res/values-it/strings.xml
index d61bc9b3c..988e5472b 100644
--- a/core/src/main/res/values-it/strings.xml
+++ b/core/src/main/res/values-it/strings.xml
@@ -4,7 +4,7 @@
<string name="feed_update_receiver_name">Aggiorna iscrizioni</string>
<string name="feeds_label">Podcast</string>
<string name="statistics_label">Statistiche</string>
- <string name="add_feed_label">Aggiungi un podcast</string>
+ <string name="add_feed_label">Aggiungi podcast</string>
<string name="episodes_label">Episodi</string>
<string name="all_episodes_short_label">Tutti</string>
<string name="new_episodes_label">Novità</string>
@@ -12,7 +12,7 @@
<string name="new_label">Nuovo</string>
<string name="settings_label">Impostazioni</string>
<string name="downloads_label">Download</string>
- <string name="downloads_running_label">In esecuzione</string>
+ <string name="downloads_running_label">In corso</string>
<string name="downloads_completed_label">Completati</string>
<string name="downloads_log_label">Registro</string>
<string name="subscriptions_label">Iscrizioni</string>
@@ -20,27 +20,26 @@
<string name="cancel_download_label">Annulla\nil download</string>
<string name="playback_history_label">Cronologia riproduzioni</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Sincronizza con altri dispositivi</string>
<string name="gpodnet_auth_label">Accesso a gpodder.net</string>
<string name="episode_cache_full_title">Cache degli episodi piena</string>
- <string name="episode_cache_full_message">Lo spazio di memoria della cache degli episodi è esaurito. Puoi aumentarlo nelle Impostazioni</string>
+ <string name="episode_cache_full_message">Il limite della cache degli episodi è stato raggiunto. Puoi aumentare la dimensione della cache nelle Impostazioni.</string>
<string name="playback_statistics_label">Riproduzione</string>
<string name="download_statistics_label">Download</string>
<!--Statistics fragment-->
<string name="total_time_listened_to_podcasts">Tempo totale di riproduzione:</string>
<string name="statistics_details_dialog">%1$d di %2$d episodi iniziati.\n\nRiprodotti %3$s di %4$s.</string>
<string name="statistics_mode">Modalità di calcolo</string>
- <string name="statistics_mode_normal">Tempo di riproduzione reale. Riprodurre due volte un episodio verrà contato doppio, segnarlo come riprodotto no.</string>
+ <string name="statistics_mode_normal">Tempo di riproduzione reale. Riprodurre due volte un episodio verrà contato doppio, segnarlo come riprodotto no</string>
<string name="statistics_mode_count_all">Somma il tempo di riproduzione di tutti i podcast segnati come riprodotti</string>
<string name="statistics_speed_not_counted">Avviso: la velocità di riproduzione non viene considerata.</string>
<string name="statistics_reset_data">Resetta statistiche</string>
- <string name="statistics_reset_data_msg">Verranno eliminate le statistiche sul tempo di riproduzione di tutti gli episodi. Sei sicuro?</string>
+ <string name="statistics_reset_data_msg">Verranno eliminate le statistiche sul tempo di riproduzione di tutti gli episodi. Procedo?</string>
<!--Download Statistics fragment-->
<string name="total_size_downloaded_podcasts">Dimensione totale podcast scaricati:</string>
<!--Main activity-->
<string name="drawer_open">Apri il menù</string>
<string name="drawer_close">Chiudi il menù</string>
- <string name="drawer_preferences">Preferenze del drawer</string>
+ <string name="drawer_preferences">Preferenze del menu</string>
<string name="drawer_feed_order_unplayed_episodes">Ordina per contatore</string>
<string name="drawer_feed_order_alphabetical">Ordina alfabeticamente</string>
<string name="drawer_feed_order_last_update">Ordina per data di pubblicazione</string>
@@ -49,7 +48,7 @@
<string name="drawer_feed_counter_new">Numero di episodi nuovi</string>
<string name="drawer_feed_counter_unplayed">Numero di episodi non riprodotti</string>
<string name="drawer_feed_counter_downloaded">Numero di episodi scaricati</string>
- <string name="drawer_feed_counter_none">Nulla</string>
+ <string name="drawer_feed_counter_none">Nessuno</string>
<!--Webview actions-->
<string name="open_in_browser_label">Apri nel browser</string>
<string name="copy_url_label">Copia URL</string>
@@ -84,10 +83,10 @@
<string name="auto_download_label">Includi nei download automatici</string>
<string name="auto_download_apply_to_items_title">Applica agli episodi precedenti</string>
<string name="auto_download_apply_to_items_message">L\'opzione <i>Download automatico</i> verrà applicata ai nuovi episodi.\nVuoi applicarla anche agli episodi precedenti?</string>
- <string name="auto_delete_label">Elimina episodi automaticamente</string>
+ <string name="auto_delete_label">Eliminazione automatica episodi</string>
<string name="feed_volume_reduction">Riduzione del volume</string>
- <string name="feed_volume_reduction_summary">Riduci il volume degli episodi di questo feed: \%s</string>
- <string name="feed_volume_reduction_off">Off</string>
+ <string name="feed_volume_reduction_summary">Riduci il volume degli episodi di questo feed: %1$s</string>
+ <string name="feed_volume_reduction_off">Spento</string>
<string name="feed_volume_reduction_light">Leggero</string>
<string name="feed_volume_reduction_heavy">Deciso</string>
<string name="parallel_downloads_suffix">\u0020download paralleli</string>
@@ -106,16 +105,19 @@
<item quantity="one">1 giorno dopo il completamento</item>
<item quantity="other">%d giorni dopo il completamento</item>
</plurals>
- <string name="num_selected_label">%d selezionati</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">%d selezionato</item>
+ <item quantity="other">%d selezionati</item>
+ </plurals>
<string name="loading_more">Caricamento successivi...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Segna tutti come riprodotti</string>
<string name="mark_all_read_msg">Segnati tutti gli episodi come riprodotti</string>
<string name="mark_all_read_confirmation_msg">Conferma che desideri segnare tutti gli episodi come riprodotti.</string>
- <string name="mark_all_read_feed_confirmation_msg">Conferma che desideri segnare come riprodotti tutti gli episodi del podcast.</string>
+ <string name="mark_all_read_feed_confirmation_msg">Conferma che desideri segnare tutti gli episodi del podcast come riprodotti.</string>
<string name="remove_all_new_flags_label">Rimuovi tutti i flag \"nuovo\"</string>
- <string name="removed_all_new_flags_msg">Flag \"nuovo\" rimossi</string>
- <string name="remove_all_new_flags_confirmation_msg">Conferma di voler rimuovere tutti i flag \"nuovo\" da tutti gli episodi.</string>
+ <string name="removed_all_new_flags_msg">Rimossi tutti i flag \"nuovo\"</string>
+ <string name="remove_all_new_flags_confirmation_msg">Conferma di voler rimuovere il flag \"nuovo\" da tutti gli episodi.</string>
<string name="show_info_label">Informazioni</string>
<string name="show_feed_settings_label">Mostra impostazioni podcast</string>
<string name="feed_info_label">Info podcast</string>
@@ -134,8 +136,8 @@
<string name="feed_remover_msg">Rimozione podcast in corso</string>
<string name="load_complete_feed">Aggiorna podcast completo</string>
<string name="multi_select">Selezione multipla</string>
- <string name="select_all_above">Seleziona tutti sopra</string>
- <string name="select_all_below">Seleziona tutti sotto</string>
+ <string name="select_all_above">Seleziona tutti in su</string>
+ <string name="select_all_below">Seleziona tutti in giù</string>
<string name="hide_unplayed_episodes_label">Non riprodotti</string>
<string name="hide_paused_episodes_label">In pausa</string>
<string name="hide_played_episodes_label">Riprodotti</string>
@@ -143,8 +145,8 @@
<string name="hide_not_queued_episodes_label">Non in coda</string>
<string name="hide_downloaded_episodes_label">Scaricati</string>
<string name="hide_not_downloaded_episodes_label">Non scaricati</string>
- <string name="hide_has_media_label">Pulizia dell\'episodio</string>
- <string name="hide_is_favorite_label">E\' preferito</string>
+ <string name="hide_has_media_label">Con media</string>
+ <string name="hide_is_favorite_label">Preferiti</string>
<string name="filtered_label">Filtrati</string>
<string name="refresh_failed_msg">{fa-exclamation-circle} Ultimo aggiornamento fallito</string>
<string name="open_podcast">Apri podcast</string>
@@ -159,7 +161,7 @@
<string name="pause_label">Pausa</string>
<string name="stream_label">Stream</string>
<string name="delete_label">Elimina</string>
- <string name="delete_failed">Impossibile eliminare il file. Il riavvio del dispositivo potrebbe aiutare.</string>
+ <string name="delete_failed">Impossibile eliminare il file. Prova a riavviare il dispositivo.</string>
<string name="delete_episode_label">Elimina episodio</string>
<plurals name="deleted_episode_batch_label">
<item quantity="one">%d episodio eliminato.</item>
@@ -203,6 +205,7 @@
<string name="deactivate_auto_download">Disattiva il download automatico</string>
<string name="reset_position">Azzera la posizione di riproduzione</string>
<string name="removed_item">Elemento rimosso</string>
+ <string name="no_items_selected">Nessun elemento selezionato</string>
<!--Download messages and labels-->
<string name="download_successful">successo</string>
<string name="download_pending">Download in attesa</string>
@@ -218,7 +221,7 @@
<string name="download_error_connection_error">Errore di connessione</string>
<string name="download_error_unknown_host">Host sconosciuto</string>
<string name="download_error_unauthorized">Errore di autenticazione</string>
- <string name="download_error_file_type_type">Errore del formato file</string>
+ <string name="download_error_file_type_type">Errore del tipo di file</string>
<string name="download_error_forbidden">Proibito</string>
<string name="download_canceled_msg">Download annullato</string>
<string name="download_canceled_autodownload_enabled_msg">Download annullato\n<i>Download automatico</i> disabilitato per questo elemento</string>
@@ -240,12 +243,12 @@
<string name="download_type_feed">Feed</string>
<string name="download_type_media">File multimediali</string>
<string name="download_request_error_dialog_message_prefix">Rilevato errore durante il download del file:\u0020</string>
- <string name="null_value_podcast_error">Non è stato fornito alcun podcast da mostrare.</string>
+ <string name="null_value_podcast_error">Nessun è stato fornito alcun podcast che possa essere mostrato.</string>
<string name="authentication_notification_title">Autenticazione richiesta</string>
<string name="authentication_notification_msg">La risorsa che hai richiesto richiede un nome utente e una password</string>
<string name="confirm_mobile_download_dialog_title">Conferma download su rete mobile</string>
- <string name="confirm_mobile_download_dialog_message_not_in_queue">Il download tramite rete mobile è disattivato nelle impostazioni.\n\nPuoi scegliere di aggiungere semplicemente l\'episodio alla coda o consentire temporaneamente i download.\n\n<small>La scelta sarà valida per 10 minuti.</small></string>
- <string name="confirm_mobile_download_dialog_message">Il download tramite rete mobile è disattivato nelle impostazioni.\n\nVuoi abilitare temporaneamente il download?\n\n<small>La scelta verrà ricordata per 10 minuti.</small></string>
+ <string name="confirm_mobile_download_dialog_message_not_in_queue">Il download tramite rete mobile è disattivato nelle impostazioni.\n\nPuoi scegliere di aggiungere semplicemente l\'episodio alla coda o consentire temporaneamente i download.\n\n<small>La scelta sarà valida per 10 minuti.</small></string>
+ <string name="confirm_mobile_download_dialog_message">Il download tramite rete mobile è disattivato nelle impostazioni.\n\nVuoi abilitare temporaneamente il download?\n\n<small>La scelta sarà valida per 10 minuti.</small></string>
<string name="confirm_mobile_streaming_notification_title">Conferma streaming su rete mobile</string>
<string name="confirm_mobile_streaming_notification_message">Lo streaming su rete mobile è disattivato nelle impostazioni. Tocca per avviare comunque.</string>
<string name="confirm_mobile_streaming_button_always">Consenti sempre</string>
@@ -279,7 +282,7 @@
<string name="move_to_top_label">Sposta all\'inizio</string>
<string name="move_to_bottom_label">Sposta in fondo</string>
<string name="sort">Ordina</string>
- <string name="keep_sorted">Mantieni ordinato</string>
+ <string name="keep_sorted">Mantieni ordine</string>
<string name="date">Per data</string>
<string name="duration">Per durata</string>
<string name="episode_title">Titolo episodio</string>
@@ -288,9 +291,7 @@
<string name="smart_shuffle">Casuale intelligente</string>
<string name="ascending">In ordine crescente</string>
<string name="descending">In ordine decrescente</string>
- <string name="clear_queue_confirmation_msg">Per favore conferma che vuoi rimuovere dalla coda TUTTI gli episodi in essa presenti.</string>
- <string name="sort_old_to_new">Dal meno recente</string>
- <string name="sort_new_to_old">Dal più recente</string>
+ <string name="clear_queue_confirmation_msg">Per favore conferma che vuoi rimuovere dalla coda TUTTI gli episodi presenti.</string>
<string name="time_left_label">Tempo residuo:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Scarica plugin</string>
@@ -300,14 +301,14 @@
<string name="enable_sonic">Abilita Sonic</string>
<!--Empty list labels-->
<string name="no_items_header_label">Nessun episodio in coda</string>
- <string name="no_items_label">Aggiungi un episodio scaricandolo o tenendo premuto e selezionando \"Aggiungi alla coda\"</string>
+ <string name="no_items_label">Aggiungine uno scaricandolo o selezionando \"Aggiungi alla coda\" dopo aver tenuto premuto su di esso.</string>
<string name="no_shownotes_label">Questo episodio non ha note.</string>
<string name="no_run_downloads_head_label">Nessun download in corso</string>
- <string name="no_run_downloads_label">Puoi scaricare gli episodi dalla vista dettagliata del podcast.</string>
+ <string name="no_run_downloads_label">Puoi scaricare gli episodi dalla schermata del podcast.</string>
<string name="no_comp_downloads_head_label">Nessun episodio scaricato</string>
- <string name="no_comp_downloads_label">Puoi scaricare gli episodi dalla vista dettagliata del podcast.</string>
+ <string name="no_comp_downloads_label">Puoi scaricare gli episodi dalla schermata del podcast.</string>
<string name="no_log_downloads_head_label">Nessun registro</string>
- <string name="no_log_downloads_label">Il registro dei download apparirà qui quando disponibile.</string>
+ <string name="no_log_downloads_label">Il registro dei download apparirà qui quando presente.</string>
<string name="no_history_head_label">Nessuna cronologia</string>
<string name="no_history_label">Ogni episodio ascoltato apparirà qui.</string>
<string name="no_all_episodes_head_label">Nessun episodio</string>
@@ -322,15 +323,15 @@
<string name="no_subscriptions_label">Per aggiungere un podcast, premi il tasto + in basso.</string>
<!--Preferences-->
<string name="storage_pref">Memoria</string>
- <string name="storage_sum">Eliminazione episodi, import, export</string>
+ <string name="storage_sum">Eliminazione episodi, importazione, esportazione</string>
<string name="project_pref">Progetto</string>
<string name="queue_label">Coda</string>
- <string name="integrations_label">Integrazioni</string>
- <string name="integrations_sum">Sincronizzazione</string>
+ <string name="synchronization_pref">Sincronizzazione</string>
+ <string name="synchronization_sum">Sincronizza con altri dispositivi tramite gpodder.net</string>
<string name="automation">Automazione</string>
<string name="download_pref_details">Dettagli</string>
<string name="import_export_pref">Importa/Esporta</string>
- <string name="import_export_search_keywords">backup, ripristina, ripristino</string>
+ <string name="import_export_search_keywords">backup, ripristina, ripristino, importa, esporta</string>
<string name="appearance">Aspetto</string>
<string name="external_elements">Elementi esterni</string>
<string name="interruptions">Interruzioni</string>
@@ -338,24 +339,24 @@
<string name="preference_search_hint">Cerca...</string>
<string name="preference_search_no_results">Nessun risultato</string>
<string name="preference_search_clear_history">Svuota cronologia</string>
- <string name="media_player">Media player</string>
+ <string name="media_player">Riproduttore multimediale</string>
<string name="pref_episode_cleanup_title">Pulizia episodi</string>
- <string name="pref_episode_cleanup_summary">Gli episodi che non sono in coda e non sono tra i preferiti potrebbero essere rimossi se i Download automatici richiedono altro spazio.</string>
- <string name="pref_pauseOnDisconnect_sum">Sospendi la riproduzione quando le cuffie o il bluetooth vengono disconnessi</string>
+ <string name="pref_episode_cleanup_summary">Gli episodi non in coda e che non sono tra i preferiti potrebbero essere rimossi se i Download automatici richiedono altro spazio.</string>
+ <string name="pref_pauseOnDisconnect_sum">Sospende la riproduzione quando le cuffie o il bluetooth vengono disconnessi</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Riprendi la riproduzione quando vengono riconnesse le cuffie</string>
- <string name="pref_unpauseOnBluetoothReconnect_sum">Riprendi la riproduzione quando il Bluetooth si riconnette</string>
+ <string name="pref_unpauseOnBluetoothReconnect_sum">Riprende la riproduzione quando il Bluetooth si riconnette</string>
<string name="pref_hardwareForwardButtonSkips_title">Il tasto Avanti salta la traccia</string>
- <string name="pref_hardwareForwardButtonSkips_sum">Quando viene premuto il tasto Avanti sul dispositivo bluetooth connesso, passa all\'episodio successivo invece di andare avanti veloce</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Premendo il tasto Avanti sul dispositivo Bluetooth connesso, passa all\'episodio successivo invece di andare avanti veloce</string>
<string name="pref_hardwarePreviousButtonRestarts_title">Il tasto Indietro riavvia la traccia</string>
- <string name="pref_hardwarePreviousButtonRestarts_sum">Quando viene premuto il tasto fisico Indietro, viene riavviata la traccia invece di saltare indietro</string>
- <string name="pref_followQueue_sum">Passa al prossimo episodio in coda quando viene completata la riproduzione</string>
+ <string name="pref_hardwarePreviousButtonRestarts_sum">Premendo il tasto fisico Indietro, viene riavviata la traccia invece riavvolgere alcuni secondi</string>
+ <string name="pref_followQueue_sum">Passa al successivo episodio della coda quando viene completata la riproduzione</string>
<string name="pref_auto_delete_sum">Elimina l\'episodio quando viene completata la riproduzione</string>
<string name="pref_auto_delete_title">Elimina automaticamente</string>
<string name="pref_smart_mark_as_played_sum">Contrassegna gli episodi come riprodotti anche se rimangono alcuni secondi da riprodurre</string>
<string name="pref_smart_mark_as_played_title">Marcatura intelligente</string>
- <string name="pref_skip_keeps_episodes_sum">Mantieni in coda gli episodi quando vengono saltati</string>
+ <string name="pref_skip_keeps_episodes_sum">Mantiene gli episodi nella coda quando vengono saltati</string>
<string name="pref_skip_keeps_episodes_title">Manteni gli episodi saltati</string>
- <string name="pref_favorite_keeps_episodes_sum">Mantieni gli episodi quando sono segnati come Preferiti</string>
+ <string name="pref_favorite_keeps_episodes_sum">Mantiene gli episodi se sono segnati come Preferiti</string>
<string name="pref_favorite_keeps_episodes_title">Mantieni episodi preferiti</string>
<string name="playback_pref">Riproduzione</string>
<string name="playback_pref_sum">Controllo cuffie, salto intervalli, coda</string>
@@ -363,7 +364,7 @@
<string name="network_pref_sum">Intervallo aggiornamento, controllo download, dati</string>
<string name="pref_autoUpdateIntervallOrTime_title">Intervallo o orario di aggiornamento</string>
<string name="pref_autoUpdateIntervallOrTime_sum">Imposta l\'intervallo o l\'orario specifico per l\'aggiornamento automatico dei podcast</string>
- <string name="pref_autoUpdateIntervallOrTime_message">Puoi impostare un <i>intervallo</i> come \"ogni 2 ore\", <i>un\'ora del giorno</i> specifica come \"7:00\" oppure <i>disabilitare</i> gli aggiornamenti automatici.\n\n<small>Nota: I tempi di aggiornamento non sono perfetti. Potrebbero esserci dei leggeri ritardi.</small></string>
+ <string name="pref_autoUpdateIntervallOrTime_message">Puoi impostare un <i>intervallo</i> come \"ogni 2 ore\", <i>un\'ora del giorno</i> specifica come \"7:00\" oppure <i>disabilitare</i> gli aggiornamenti automatici.\n\n<small>Nota: Gli orari di aggiornamento non sono perfetti. Potrebbero esserci dei leggeri ritardi.</small></string>
<string name="pref_autoUpdateIntervallOrTime_Disable">Disabilita</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Imposta Intervallo</string>
<string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Imposta orario</string>
@@ -374,7 +375,7 @@
<string name="pref_unpauseOnHeadsetReconnect_title">Riconnessione cuffie</string>
<string name="pref_unpauseOnBluetoothReconnect_title">Riconnessione Bluetooth</string>
<string name="pref_stream_over_download_title">Preferisci streaming</string>
- <string name="pref_stream_over_download_sum">Mostra il tasto stream nelle liste al posto del tasto download.</string>
+ <string name="pref_stream_over_download_sum">Negli elenchi mostra il tasto stream al posto del tasto download.</string>
<string name="pref_mobileUpdate_title">Aggiornamenti su rete mobile</string>
<string name="pref_mobileUpdate_sum">Seleziona quali operazioni sono consentite su reti mobili a consumo</string>
<string name="pref_mobileUpdate_refresh">Aggiornamento podcast</string>
@@ -390,7 +391,7 @@
<string name="pref_nav_drawer_feed_order_title">Imposta l\'ordine delle iscrizioni</string>
<string name="pref_nav_drawer_feed_order_sum">Modifica l\'ordine delle iscrizioni</string>
<string name="pref_nav_drawer_feed_counter_title">Contatore delle iscrizioni</string>
- <string name="pref_nav_drawer_feed_counter_sum">Cambia il criterio di calcolo per il contatore delle iscrizioni. Può influenzare l\'ordinamento delle iscrizioni se \'l\'ordine delle iscrizioni\' è impostato in modalità \'contatore\'.</string>
+ <string name="pref_nav_drawer_feed_counter_sum">Cambia il criterio di calcolo del contatore delle iscrizioni. Influenza anche l\'ordinamento quando è impostato su \'Ordina per contatore\'.</string>
<string name="pref_set_theme_sum">Cambia l\'aspetto di AntennaPod</string>
<string name="pref_automatic_download_title">Download automatico</string>
<string name="pref_automatic_download_sum">Configura il download automatico degli episodi</string>
@@ -402,7 +403,7 @@
<string name="pref_episode_cache_title">Cache degli episodi</string>
<string name="pref_episode_cache_summary">Numero di episodi scaricati memorizzabili sul dispositivo. I download automatici vengono interrotti se si raggiunge questo valore.</string>
<string name="pref_episode_cover_title">Usa immagine episodio</string>
- <string name="pref_episode_cover_summary">Usa l\'immagine dell\'episodio se disponibile. Se disattivata, verrà usata sempre l\'immagine del podcast.</string>
+ <string name="pref_episode_cover_summary">Visualizza l\'immagine dell\'episodio se disponibile. Se disattivata, verrà usata sempre l\'immagine del podcast.</string>
<string name="pref_theme_title_use_system">Usa tema di sistema</string>
<string name="pref_theme_title_light">Chiaro</string>
<string name="pref_theme_title_dark">Scuro</string>
@@ -417,18 +418,22 @@
<string name="pref_gpodnet_logout_toast">Logout effettuato</string>
<string name="pref_gpodnet_setlogin_information_title">Cambia le informazioni di login</string>
<string name="pref_gpodnet_setlogin_information_sum">Cambia le informazioni di login per il tuo account gpodder.net.</string>
- <string name="pref_gpodnet_sync_changes_title">Esegui sincronizzazione delle modifiche</string>
- <string name="pref_gpodnet_sync_changes_sum">Sincronizza l\'iscrizione e lo stato dell\'episodio con gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">Esegui sincronizzazione completa</string>
+ <string name="pref_gpodnet_sync_changes_title">Sincronizza ora</string>
+ <string name="pref_gpodnet_sync_changes_sum">Sincronizza modifiche all\'iscrizione e allo stato dell\'episodio con gpodder.net.</string>
+ <string name="pref_gpodnet_full_sync_title">Forza sincronizzazione completa</string>
<string name="pref_gpodnet_full_sync_sum">Sincronizza le iscrizioni e lo stato di tutti gli episodi con gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Ultimo tentativo: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Sincronizzazione avviata</string>
<string name="pref_gpodnet_login_status"><![CDATA[Accesso come <i>%1$s</i> con il dispositivo <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Notifica gli errori di sincronizzazione</string>
<string name="pref_gpodnet_notifications_sum">Non si applica agli errori di autenticazione.</string>
<string name="pref_playback_speed_title">Velocità di riproduzione</string>
<string name="pref_playback_speed_sum">Personalizza le velocità disponibili per la riproduzione audio a velocità variabile</string>
- <string name="pref_feed_playback_speed_sum">Velocità da usare all\'avvio della riproduzione di un episodio di questo podcast</string>
+ <string name="pref_feed_playback_speed_sum">Velocità da usare per la riproduzione degli episodi di questo podcast</string>
+ <string name="pref_feed_skip">Salta automaticamente</string>
+ <string name="pref_feed_skip_sum">Salta alcuni secondi all\'inizio o alla fine.</string>
+ <string name="pref_feed_skip_ending">Salta gli ultimi</string>
+ <string name="pref_feed_skip_intro">Salta i primi</string>
+ <string name="pref_feed_skip_ending_toast">Ultimi %d secondi saltati</string>
+ <string name="pref_feed_skip_intro_toast">Primi %d secondi saltati</string>
<string name="pref_playback_time_respects_speed_title">Adatta info alla velocità di riproduzione</string>
<string name="pref_playback_time_respects_speed_sum">La posizione del cursore e la durata si adattano alla velocità di riproduzione scelta.</string>
<string name="pref_fast_forward">Tempo di salto in avanti</string>
@@ -438,10 +443,10 @@
<string name="pref_gpodnet_sethostname_title">Imposta l\'hostname</string>
<string name="pref_gpodnet_sethostname_use_default_host">Usa l\'host di default</string>
<string name="pref_expandNotify_title">Priorità notifiche superiori</string>
- <string name="pref_expandNotify_sum">Espande la notifica per mostrare i tasti di riproduzione.</string>
+ <string name="pref_expandNotify_sum">Di solito espande la notifica per mostrare i tasti di riproduzione.</string>
<string name="pref_persistNotify_title">Controlli di riproduzione persistenti</string>
- <string name="pref_persistNotify_sum">Mantieni le notifiche e i controlli del blocco dello schermo quando la riproduzione è in pausa.</string>
- <string name="pref_compact_notification_buttons_title">Pulsanti su schermata di blocco</string>
+ <string name="pref_persistNotify_sum">Mantiene le notifiche e i controlli del blocco schermo anche quando la riproduzione è in pausa.</string>
+ <string name="pref_compact_notification_buttons_title">Pulsanti schermata di blocco</string>
<string name="pref_compact_notification_buttons_sum">Modifica i pulsanti di riproduzione mostrati nella schermata di blocco. Play/Pausa è sempre presente.</string>
<string name="pref_compact_notification_buttons_dialog_title">Seleziona al massimo %1$d voci</string>
<string name="pref_compact_notification_buttons_dialog_error">Puoi selezionare al massimo %1$d voci.</string>
@@ -453,9 +458,9 @@
<string name="pref_showAutoDownloadReport_sum">Mostra una notifica per gli episodi scaricati automaticamente.</string>
<string name="pref_expand_notify_unsupport_toast">Le versioni Android precedenti alla 4.1 non supportano le notifiche estese.</string>
<string name="pref_enqueue_location_title">Posizione in coda</string>
- <string name="pref_enqueue_location_sum">Aggiungi episodi a: %1$s</string>
- <string name="enqueue_location_back">Retro</string>
- <string name="enqueue_location_front">Fronte</string>
+ <string name="pref_enqueue_location_sum">Posizione nuovi episodi: %1$s</string>
+ <string name="enqueue_location_back">Alla fine</string>
+ <string name="enqueue_location_front">All\'inizio</string>
<string name="enqueue_location_after_current">Dopo l\'episodio attuale</string>
<string name="pref_smart_mark_as_played_disabled">Disabilitato</string>
<string name="pref_image_cache_size_title">Dimensione cache delle immagini</string>
@@ -464,7 +469,7 @@
<string name="bug_report_title">Segnala un problema</string>
<string name="open_bug_tracker">Apri il bug tracker</string>
<string name="export_logs">Esporta log</string>
- <string name="copy_to_clipboard">Copia degli appunti</string>
+ <string name="copy_to_clipboard">Copia negli appunti</string>
<string name="copied_to_clipboard">Copiato negli appunti</string>
<string name="experimental_pref">Sperimentale</string>
<string name="pref_media_player_message">Seleziona il media player da usare per riprodurre i file</string>
@@ -474,11 +479,13 @@
<string name="pref_faq">Domande frequenti - FAQ</string>
<string name="pref_no_browser_found">Nessun browser web trovato.</string>
<string name="pref_cast_title">Supporto a Chromecast</string>
- <string name="pref_cast_message_play_flavor">Abilita il supporto per la riproduzione multimediale remota sui device Cast (Chromecast, casse esterne o Android TV)</string>
+ <string name="pref_cast_message_play_flavor">Abilita il supporto per la riproduzione multimediale remota su dispositivi Cast (Chromecast, casse esterne o Android TV)</string>
<string name="pref_cast_message_free_flavor">Chromecast richiede librerie proprietarie di terze parti che sono disabilitate in questa versione di AntennaPod</string>
<string name="pref_enqueue_downloaded_title">Aggiungi i download alla coda</string>
- <string name="pref_enqueue_downloaded_summary">Aggiungi gli episodi scaricati alla coda di riproduzione</string>
+ <string name="pref_enqueue_downloaded_summary">Aggiunge gli episodi alla coda quando vengono scaricati</string>
<string name="media_player_builtin">Player Android integrato</string>
+ <string name="media_player_switch_to_exoplayer">Passa ad ExoPlayer</string>
+ <string name="media_player_switched_to_exoplayer">Passaggio ad ExoPlayer eseguito.</string>
<string name="pref_skip_silence_title">Salta il silenzio audio</string>
<string name="pref_videoBehavior_title">Uscita dal video</string>
<string name="pref_videoBehavior_sum">Comportamento quando si termina una riproduzione video</string>
@@ -492,11 +499,11 @@
<string name="back_button_double_tap">Doppio tap per uscire</string>
<string name="back_button_show_prompt">Conferma l\'uscita</string>
<string name="close_prompt">Sei sicuro di voler chiudere AntennaPod?</string>
- <string name="double_tap_toast">Premi nuovamente il tasto indietro per uscire</string>
- <string name="back_button_go_to_page">Vai alla pagina...</string>
- <string name="back_button_go_to_page_title">Seleziona pagina</string>
+ <string name="double_tap_toast">Premi nuovamente il tasto Indietro per uscire</string>
+ <string name="back_button_go_to_page">Vai alla schermata...</string>
+ <string name="back_button_go_to_page_title">Seleziona schermata</string>
<string name="pref_delete_removes_from_queue_title">Rimuovi dalla coda gli eliminati</string>
- <string name="pref_delete_removes_from_queue_sum">Rimuovi automaticamente un episodio dalla coda quando viene eliminato.</string>
+ <string name="pref_delete_removes_from_queue_sum">Quando un episodio viene eliminato lo rimuove automaticamente dalla coda.</string>
<!--About screen-->
<string name="about_pref">Informazioni</string>
<string name="antennapod_version">Versione di AntennaPod</string>
@@ -511,18 +518,26 @@
<string name="search_status_no_results">Nessun risultato trovato</string>
<string name="search_label">Ricerca</string>
<string name="no_results_for_query">Nessun risultato trovato per \"%1$s\"</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">Sincronizzazione avviata</string>
+ <string name="sync_status_episodes_upload">Caricamento modifiche dell\'episodio...</string>
+ <string name="sync_status_episodes_download">Download modifiche dell\'episodio...</string>
+ <string name="sync_status_upload_played">Invio stato della riproduzione...</string>
+ <string name="sync_status_subscriptions">Sincronizzazione iscrizioni...</string>
+ <string name="sync_status_success">Sincronizzazione eseguita con successo</string>
+ <string name="sync_status_error">Sincronizzazione fallita</string>
<!--import and export-->
<string name="import_export_summary">Sposta le iscrizioni e la coda su un altro dispositivo.</string>
<string name="database">Database</string>
<string name="opml">OPML</string>
<string name="html">HTML</string>
<string name="html_export_summary">Mostra le tue iscrizioni ad un amico</string>
- <string name="opml_export_summary">Sposta le tue iscrizioni su un\'altra app per i podcast</string>
+ <string name="opml_export_summary">Sposta le tue iscrizioni in un\'altra app per i podcast</string>
<string name="opml_import_summary">Importa le tue iscrizioni da un\'altra app per i podcast</string>
<string name="database_export_summary">Sposta le iscrizioni, gli episodi ascoltati e la coda su AntennaPod di un altro dispositivo</string>
- <string name="database_import_summary">Importa database di AntennaPod da un altro dispositivo</string>
+ <string name="database_import_summary">Importa il database di AntennaPod da un altro dispositivo</string>
<string name="opml_import_label">Importa da OPML</string>
- <string name="opml_reader_error">E\' stato riscontrato un errore nell\'apertura del documento OPML</string>
+ <string name="opml_reader_error">Errore in fase di lettura del documento OPML:</string>
<string name="opml_import_error_no_file">Nessun file selezionato!</string>
<string name="select_all_label">Seleziona tutti</string>
<string name="deselect_all_label">Deseleziona tutti</string>
@@ -530,14 +545,15 @@
<string name="html_export_label">Esporta in HTML</string>
<string name="database_export_label">Esporta database</string>
<string name="database_import_label">Importa database</string>
+ <string name="database_import_warning">L\'importazione di un database sostituirà tutte le iscrizioni attuali e la cronologia di riproduzione. Dovresti eseguire un backup del tuo database attuale. Vuoi proseguire?</string>
<string name="please_wait">Attendi...</string>
<string name="export_error_label">Errore di esportazione</string>
<string name="export_success_title">Esportazione eseguita</string>
<string name="export_success_sum">Il file esportato è stato salvato in:\n\n%1$s</string>
- <string name="opml_import_ask_read_permission">E\' necessario accedere alla memoria esterna per leggere il file OPML</string>
+ <string name="opml_import_ask_read_permission">E\' richiesto l\'accesso alla memoria esterna per leggere il file OPML</string>
<string name="import_select_file">Scegli file da importare</string>
<string name="import_ok">Importazione eseguita.\n\nPremi OK per riavviare AntennaPod</string>
- <string name="import_no_downgrade">Il database è stato esportato da una versione più recente di AntennaPod. La tua applicazione attuale non sa ancora come gestire questo file.</string>
+ <string name="import_no_downgrade">Questo database è stato esportato da una versione più recente di AntennaPod. La tua applicazione attuale non sa ancora come gestire questo file.</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Imposta timer</string>
<string name="disable_sleeptimer_label">Disabilita il timer di spegnimento</string>
@@ -598,8 +614,8 @@
<string name="selected_folder_label">Seleziona la cartella:</string>
<string name="create_folder_label">Crea una cartella</string>
<string name="choose_data_directory">Scegli la cartella per i dati</string>
- <string name="choose_data_directory_message">Scegli la base della tua cartella dati. AntennaPod creerà le sottocartelle appropriate.</string>
- <string name="choose_data_directory_permission_rationale">E\' necessario accedere alla memoria esterna per cambiare la cartella dei dati</string>
+ <string name="choose_data_directory_message">Scegli dove salvare la tua cartella dati. AntennaPod creerà le sottocartelle appropriate.</string>
+ <string name="choose_data_directory_permission_rationale">Accesso alla memoria esterna richiesto per poter cambiare la cartella dei dati</string>
<string name="choose_data_directory_available_space">%1$s di %2$s liberi</string>
<string name="create_folder_msg">Creare una nuova directory con nome \"%1$s\"?</string>
<string name="create_folder_success">Crea una nuova directory</string>
@@ -614,27 +630,34 @@
<string name="set_to_default_folder">Scegli la cartella predefinita</string>
<string name="pref_pausePlaybackForFocusLoss_sum">Quando un\'altra app emette un suono, sospendi la riproduzione invece di abbassare il volume</string>
<string name="pref_pausePlaybackForFocusLoss_title">Pausa su interruzione</string>
- <string name="pref_resumeAfterCall_sum">Riprendi la riproduzione al termine di una chiamata</string>
+ <string name="pref_resumeAfterCall_sum">Riprende la riproduzione al termine di una chiamata</string>
<string name="pref_resumeAfterCall_title">Riprendi dopo la chiamata</string>
<string name="pref_restart_required">AntennaPod deve essere riavviato per applicare le modifiche.</string>
<!--Online feed view-->
<string name="subscribe_label">Abbonati</string>
- <string name="subscribing_label">Sottoscrizione...</string>
+ <string name="subscribing_label">Iscrizione...</string>
<string name="preview_episode">Anteprima</string>
+ <string name="stop_preview">Ferma anteprima</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Riavvolgi</string>
<string name="fast_forward_label">Avanti veloce</string>
+ <string name="increase_speed">Aumenta velocità</string>
+ <string name="decrease_speed">Riduci velocità</string>
<string name="media_type_audio_label">Audio</string>
<string name="media_type_video_label">Video</string>
<string name="navigate_upwards_label">Naviga verso l\'alto</string>
<string name="status_downloading_label">L\'episodio sta venendo scaricato</string>
<string name="in_queue_label">L\'episodio è in coda</string>
+ <string name="is_favorite_label">Episodio contrassegnato come preferito</string>
<string name="drag_handle_content_description">Trascina per cambiare la posizione di questo oggetto</string>
<string name="load_next_page_label">Carica la pagina successiva</string>
+ <string name="switch_pages">Cambia schermata</string>
+ <string name="position">Posizione: %1$s</string>
+ <string name="apply_action">Applica la scelta</string>
<!--Feed information screen-->
<string name="authentication_label">Autenticazione</string>
- <string name="authentication_descr">Cambia il tuo nome utente e la tua password per questo podcast e i suoi episodi.</string>
- <string name="auto_download_settings_label">Impostazioni download automatici</string>
+ <string name="authentication_descr">Cambia il nome utente e la password per questo podcast e i suoi episodi.</string>
+ <string name="auto_download_settings_label">Impostazioni download automatico</string>
<string name="episode_filters_label">Filtro degli episodi</string>
<string name="episode_filters_description">Elenco di termini per filtrare gli episodi da includere o escludere dai download automatici.</string>
<string name="episode_filters_include">Includi</string>
@@ -642,7 +665,7 @@
<string name="episode_filters_hint">Parole singole \n\"Parole multiple\"</string>
<string name="keep_updated">Mantieni aggiornato</string>
<string name="keep_updated_summary">Includi questo podcast nell\'auto-aggiornamento generale</string>
- <string name="auto_download_disabled_globally">Il download automatico è disabilitato nelle Impostazioni generali.</string>
+ <string name="auto_download_disabled_globally">Il download automatico è disabilitato nelle impostazioni generali.</string>
<!--Progress information-->
<string name="progress_upgrading_database">Aggiornamento del database</string>
<!--AntennaPodSP-->
@@ -652,30 +675,31 @@
<string name="search_itunes_label">Cerca su iTunes</string>
<string name="search_fyyd_label">Cerca su fyyd</string>
<string name="advanced">Avanzate</string>
- <string name="add_podcast_by_url">Aggiungi podcast via URL</string>
+ <string name="add_podcast_by_url">Aggiungi podcast da URL</string>
<string name="browse_gpoddernet_label">Esplora gpodder.net</string>
<string name="discover">Scopri</string>
<string name="discover_more">altro »</string>
- <string name="filter">Filtro</string>
+ <string name="search_powered_by">Ricerca fornita da %1$s</string>
+ <string name="filter">Filtra</string>
<!--Episodes apply actions-->
<string name="all_label">Tutto</string>
<string name="selected_all_label">Seleziona tutti gli episodi</string>
- <string name="none_label">Nulla</string>
+ <string name="none_label">Nessuno</string>
<string name="deselected_all_label">Deseleziona tutti gli episodi</string>
<string name="played_label">Riprodotti</string>
- <string name="selected_played_label">Selezionati gli episodi riprodotti</string>
+ <string name="selected_played_label">Episodi riprodotti selezionati</string>
<string name="unplayed_label">Non riprodotti</string>
- <string name="selected_unplayed_label">Selezionati gli episodi non riprodotti</string>
+ <string name="selected_unplayed_label">Episodi non riprodotti selezionati</string>
<string name="downloaded_label">Scaricati</string>
- <string name="selected_downloaded_label">Seleziona gli episodi scaricati</string>
+ <string name="selected_downloaded_label">Episodi scaricati selezionati</string>
<string name="not_downloaded_label">Non scaricati</string>
- <string name="selected_not_downloaded_label">Seleziona gli episodi non scaricati</string>
+ <string name="selected_not_downloaded_label">Episodi non scaricati selezionati</string>
<string name="queued_label">In coda</string>
- <string name="selected_queued_label">Seleziona gli episodi in coda</string>
+ <string name="selected_queued_label">Episodi in coda selezionati</string>
<string name="not_queued_label">Non in coda</string>
- <string name="selected_not_queued_label">Seleziona gli episodi non in coda</string>
- <string name="has_media">Ha media</string>
- <string name="selected_has_media_label">Seleziona gli episodi con elementi multimediali</string>
+ <string name="selected_not_queued_label">Episodi non in coda selezionati</string>
+ <string name="has_media">Con media</string>
+ <string name="selected_has_media_label">Episodi con elementi multimediali selezionati</string>
<!--Sort-->
<string name="sort_title_a_z">Titolo (A \u2192 Z)</string>
<string name="sort_title_z_a">Titolo (Z \u2192 A)</string>
@@ -683,6 +707,12 @@
<string name="sort_date_old_new">Data (Vecchi \u2192 Nuovi)</string>
<string name="sort_duration_short_long">Durata (Corti \u2192 Lunghi)</string>
<string name="sort_duration_long_short">Durata (Lunghi \u2192 Corti)</string>
+ <string name="sort_a_z">A \u2192 Z</string>
+ <string name="sort_z_a">Z \u2192 A</string>
+ <string name="sort_new_old">Nuovo \u2192 Vecchio</string>
+ <string name="sort_old_new">Vecchio \u2192 Nuovo</string>
+ <string name="sort_short_long">Corto \u2192 Lungo</string>
+ <string name="sort_long_short">Lungo \u2192 Corto</string>
<!--Rating dialog-->
<string name="rating_title">Ti piace AntennaPod?</string>
<string name="rating_message">Ci farebbe molto piacere se potessi valutare AntennaPod.</string>
@@ -704,7 +734,7 @@
<string name="host_label">Host</string>
<string name="port_label">Porta</string>
<string name="optional_hint">(Opzionale)</string>
- <string name="proxy_test_label">Test</string>
+ <string name="proxy_test_label">Verifica</string>
<string name="proxy_checking">Controllo in corso...</string>
<string name="proxy_test_successful">Test avvenuto con successo</string>
<string name="proxy_test_failed">Test fallito</string>
@@ -720,26 +750,30 @@
<string name="cast_failed_to_play">Avvio della riproduzione del media fallito</string>
<string name="cast_failed_to_stop">Arresto della riproduzione del media fallito</string>
<string name="cast_failed_to_pause">Pausa della riproduzione del media fallita</string>
- <string name="cast_failed_setting_volume">Impostazione del volume fallita</string>
+ <string name="cast_failed_setting_volume">Regolazione del volume fallita</string>
<string name="cast_failed_no_connection">Nessuna connessione al dispositivo di ricezione</string>
<string name="cast_failed_no_connection_trans">Connessione al dispositivo persa. L\'applicazione sta cercando di ristabilire la connessione, se possibile. Per favore attendi qualche secondo e riprova.</string>
- <string name="cast_failed_status_request">Sincronizzazione con il dispositivo ricevente fallita</string>
- <string name="cast_failed_seek">Ricerca della nuova posizione sul dispositivo ricevente fallita</string>
+ <string name="cast_failed_status_request">Sincronizzazione con il dispositivo cast fallita</string>
+ <string name="cast_failed_seek">Ricerca della nuova posizione sul dispositivo cast fallita</string>
<string name="cast_failed_receiver_player_error">Il dispositivo ricevente ha restituito un errore grave</string>
<string name="cast_failed_media_error_skipping">Errore nella riproduzione. Salto...</string>
<!--Notification channels-->
<string name="notification_channel_user_action">Azione richesta</string>
- <string name="notification_channel_user_action_description">Mostra se è richesto un tuo intervento, per esempio se è necessario inserire la password.</string>
- <string name="notification_channel_downloading">Scaricando</string>
- <string name="notification_channel_downloading_description">Mostra mentre è in corso il download</string>
+ <string name="notification_channel_user_action_description">Visualizzato se è richiesto un intervento, ad esempio se è necessario inserire la password.</string>
+ <string name="notification_channel_downloading">Scaricamento</string>
+ <string name="notification_channel_downloading_description">Visualizzato mentre il download è in corso</string>
<string name="notification_channel_playing">In riproduzione</string>
- <string name="notification_channel_playing_description">Permette di controllare la riproduzione. Questa è la principale notifica visibile quando un prodcast è in riproduzione.</string>
+ <string name="notification_channel_playing_description">Permette di controllare la riproduzione. E\' la principale notifica visualizzata quando un podcast è in riproduzione.</string>
<string name="notification_channel_error">Errori</string>
- <string name="notification_channel_error_description">Mostrato se qualcosa è andato storto, per esempio se fallisce il download o la sincronizzazione di gpodder.</string>
+ <string name="notification_channel_error_description">Viene mostrato se qualcosa fallisce, ad esempio il download o la sincronizzazione di gpodder.</string>
<string name="notification_channel_auto_download">Download automatici</string>
- <string name="notification_channel_episode_auto_download">Mostra quando un episodio viene scaricato automaticamente.</string>
+ <string name="notification_channel_episode_auto_download">Viene mostrato quando un episodio è stato scaricato automaticamente.</string>
<!--Widget settings-->
<string name="widget_settings">Impostazioni widget</string>
<string name="widget_create_button">Crea widget</string>
<string name="widget_opacity">Opacità</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">Impostazione aggiornata correttamente.</string>
+ <string name="on_demand_config_stream_text">Sembra che ascolti molto in streaming. Vuoi che gli elenchi degli episodi mostrino i pulsanti per lo streaming?</string>
+ <string name="on_demand_config_download_text">Sembra che scarichi molto. Vuoi che gli elenchi degli episodi mostrino i pulsanti per il download?</string>
</resources>
diff --git a/core/src/main/res/values-iw/strings.xml b/core/src/main/res/values-iw/strings.xml
index cdd31c600..2b9f57f52 100644
--- a/core/src/main/res/values-iw/strings.xml
+++ b/core/src/main/res/values-iw/strings.xml
@@ -20,7 +20,6 @@
<string name="cancel_download_label">ביטול\nהורדה</string>
<string name="playback_history_label">היסטוריית ניגון</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">סנכרון עם מכשירים אחרים</string>
<string name="gpodnet_auth_label">כניסה אל gpodder.net</string>
<string name="episode_cache_full_title">מטמון הפרקים מלא</string>
<string name="episode_cache_full_message">מטמון הפרקים התמלא. ניתן להגדיל את גודל המטמון בהגדרות.</string>
@@ -86,7 +85,7 @@
<string name="auto_download_apply_to_items_message">הגדרות ה<i>הורדה האוטומטית</i> החדשות יחולו אוטומטית על פרקים חדשים.\nלהחיל אותן גם על פרקים שפורסמו בעבר?</string>
<string name="auto_delete_label">מחיקת פרק באופן אוטומטי</string>
<string name="feed_volume_reduction">הנמכת עצמת שמע</string>
- <string name="feed_volume_reduction_summary">להנמיך את עצמת השמע עבור פרקים בהזנה זו: \%s</string>
+ <string name="feed_volume_reduction_summary">להנמיך את עצמת השמע לפרקים של ההזנה הזאת: %1$s</string>
<string name="feed_volume_reduction_off">כבוי</string>
<string name="feed_volume_reduction_light">טיפה</string>
<string name="feed_volume_reduction_heavy">מאוד</string>
@@ -105,12 +104,17 @@
<item quantity="other">%d שעות לאחר הסיום</item>
</plurals>
<plurals name="episode_cleanup_days_after_listening">
- <item quantity="one">יום אחרי סיום</item>
- <item quantity="two">%d ימים לאחר סיום </item>
+ <item quantity="one">יום לאחר סיום</item>
+ <item quantity="two">יומיים לאחר סיום </item>
<item quantity="many">%d ימים לאחר סיום </item>
<item quantity="other">%d ימים לאחר סיום </item>
</plurals>
- <string name="num_selected_label">%d נבחרו</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">נבחר אחד</item>
+ <item quantity="two">נבחרו %d</item>
+ <item quantity="many">נבחרו %d</item>
+ <item quantity="other">נבחרו %d</item>
+ </plurals>
<string name="loading_more">נטענים עוד…</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">לסמן הכול כנוגנו</string>
@@ -219,6 +223,7 @@
<string name="deactivate_auto_download">השבתת הורדה אוטומטית</string>
<string name="reset_position">איפוס מיקום הנגינה</string>
<string name="removed_item">פריט הוסר</string>
+ <string name="no_items_selected">לא נבחרו פריטים</string>
<!--Download messages and labels-->
<string name="download_successful">הצלחה</string>
<string name="download_pending">הורדה ממתינה</string>
@@ -246,7 +251,7 @@
<string name="download_error_request_error">שגיאת בקשה</string>
<string name="download_error_db_access">שגיאת גישה למסד הנתונים</string>
<plurals name="downloads_left">
- <item quantity="one">נותרה הורדה %d</item>
+ <item quantity="one">נותרה הורדה אחת</item>
<item quantity="two">נותרו %d הורדות</item>
<item quantity="many">נותרו %d הורדות</item>
<item quantity="other">נותרו %d הורדות</item>
@@ -281,7 +286,7 @@
<string name="playback_error_source">לא ניתן לגשת לקובץ המדיה</string>
<string name="playback_error_unknown">שגיאה לא ידועה</string>
<string name="no_media_playing_label">אין מדיה מתנגנת</string>
- <string name="player_buffering_msg">החוצץ מתמלא</string>
+ <string name="player_buffering_msg">המטמון מתמלא</string>
<string name="player_go_to_picture_in_picture">מצב תמונה בתוך תמונה</string>
<string name="unknown_media_key">אנטנה־פּוֹד - מפתח מדיה לא ידוע: %1$d</string>
<string name="error_file_not_found">הקובץ לא נמצא</string>
@@ -307,8 +312,6 @@
<string name="ascending">בסדר עולה</string>
<string name="descending">בסדר יורד</string>
<string name="clear_queue_confirmation_msg">נא לאשר את פינוי התור מכל הפרקים שבו</string>
- <string name="sort_old_to_new">חדש לישן</string>
- <string name="sort_new_to_old">ישן לחדש</string>
<string name="time_left_label">זמן שנותר:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">הורדת תוסף</string>
@@ -343,8 +346,8 @@
<string name="storage_sum">מחיקה אוטומטית של פרקים, ייבוא, ייצוא</string>
<string name="project_pref">מיזם</string>
<string name="queue_label">תור</string>
- <string name="integrations_label">שילובים</string>
- <string name="integrations_sum">סנכרון</string>
+ <string name="synchronization_pref">סנכרון</string>
+ <string name="synchronization_sum">סנכרון עם מכשירים אחרים דרך gpodder.net</string>
<string name="automation">אוטומציה</string>
<string name="download_pref_details">פרטים</string>
<string name="import_export_pref">ייבוא/ייצוא</string>
@@ -435,18 +438,22 @@
<string name="pref_gpodnet_logout_toast">הצלחת לצאת</string>
<string name="pref_gpodnet_setlogin_information_title">שינוי פרטי הכניסה</string>
<string name="pref_gpodnet_setlogin_information_sum">שינוי פרטי הכניסה לחשבון ה־gpodder.net שלך.</string>
- <string name="pref_gpodnet_sync_changes_title">סנכרון השינויים כעת</string>
+ <string name="pref_gpodnet_sync_changes_title">לסנכרן כעת</string>
<string name="pref_gpodnet_sync_changes_sum">סנכרון שינויי מצב במינויים ובפרקים מול gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">סנכרון מלא כעת</string>
+ <string name="pref_gpodnet_full_sync_title">לכפות סנכרון מלא</string>
<string name="pref_gpodnet_full_sync_sum">סנכרון כל המינויים ומצבי הפרקים עם gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">ניסיון הסנכרון האחרון: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">הסנכרון התחיל</string>
<string name="pref_gpodnet_login_status"><![CDATA[נכנסת בשם <i>%1$s</i> עם ההתקן <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">הצגת התרעות שגיאות סנכרון</string>
<string name="pref_gpodnet_notifications_sum">הגדרה זו אינה חלה על שגיאות אימות.</string>
<string name="pref_playback_speed_title">מהירויות ניגון</string>
<string name="pref_playback_speed_sum">בחירת המהירויות הזמינות למהירות נגינה משתנה</string>
<string name="pref_feed_playback_speed_sum">המהירות שתחול על פרקים בפודקאסט זה כשאלו מתחילים להתנגן</string>
+ <string name="pref_feed_skip">לדלג אוטומטית</string>
+ <string name="pref_feed_skip_sum">לדלג על הקדמה ותודות בסיום.</string>
+ <string name="pref_feed_skip_ending">לדלג על האחרון</string>
+ <string name="pref_feed_skip_intro">לדלג על הראשון</string>
+ <string name="pref_feed_skip_ending_toast">%d השניות האחרונות דולגו</string>
+ <string name="pref_feed_skip_intro_toast">%d השניות הראשונות דולגו</string>
<string name="pref_playback_time_respects_speed_title">להתאים את פרטי המדיה למהירות הנגינה</string>
<string name="pref_playback_time_respects_speed_sum">המיקום המוצג והמשך מותאמים למהירות הנגינה</string>
<string name="pref_fast_forward">זמן דילוג בהאצה קדימה</string>
@@ -497,6 +504,8 @@
<string name="pref_enqueue_downloaded_title">הוספת הורדות לתור</string>
<string name="pref_enqueue_downloaded_summary">הוספת פרקים שהתקבלו לתור</string>
<string name="media_player_builtin">הנגן המובנה ב־Android</string>
+ <string name="media_player_switch_to_exoplayer">מעבר ל־ExoPlayer</string>
+ <string name="media_player_switched_to_exoplayer">הועבר ל־ExoPlayer.</string>
<string name="pref_skip_silence_title">דילוג על שקט בקטעי ההאזנה</string>
<string name="pref_videoBehavior_title">בעת יציאה מסרטון</string>
<string name="pref_videoBehavior_sum">התנהגות בעת יציאה מנגינת סרטון</string>
@@ -517,18 +526,26 @@
<string name="pref_delete_removes_from_queue_sum">הסרת פרק מהתור אוטומטית עם מחיקתו.</string>
<!--About screen-->
<string name="about_pref">על אודות</string>
- <string name="antennapod_version">גרסת אנטנהפּוֹד</string>
+ <string name="antennapod_version">גרסת אנטנה־פּוֹד</string>
<string name="developers">מפתחים</string>
- <string name="developers_summary">כולם יכולים לסייע בשיפור אנטנהפּוֹד</string>
+ <string name="developers_summary">כולם יכולים לסייע בשיפור אנטנה־פּוֹד</string>
<string name="translators">מתרגמים</string>
- <string name="translators_summary">תרגומים נוצרים על ידי משתמשים של אנטנהפּוֹד בעזרת Transifex</string>
+ <string name="translators_summary">תרגומים נוצרים על ידי משתמשים של אנטנה־פּוֹד בעזרת Transifex</string>
<string name="privacy_policy">מדיניות פרטיות</string>
<string name="licenses">רישיונות</string>
- <string name="licenses_summary">היישומון אנטנהפּוֹד משתמש בתכניות נהדרות נוספות</string>
+ <string name="licenses_summary">היישומון אנטנה־פּוֹד משתמש בתכניות נהדרות נוספות</string>
<!--Search-->
<string name="search_status_no_results">לא נמצאו תוצאות</string>
<string name="search_label">חיפוש</string>
<string name="no_results_for_query">לא נמצאו תוצאות עבור „%1$s”</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">הסנכרון החל</string>
+ <string name="sync_status_episodes_upload">השינויים לפרק נשלחים…</string>
+ <string name="sync_status_episodes_download">השינויים לפרק מתקבלים…</string>
+ <string name="sync_status_upload_played">מצב הנגינה נשלח…</string>
+ <string name="sync_status_subscriptions">המינויים מסונכרנים…</string>
+ <string name="sync_status_success">הסנכרון הצליח</string>
+ <string name="sync_status_error">הסנכרון נכשל</string>
<!--import and export-->
<string name="import_export_summary">העברת מינויים ותור למכשיר אחר</string>
<string name="database">מסד נתונים</string>
@@ -548,6 +565,7 @@
<string name="html_export_label">ייצוא HTML</string>
<string name="database_export_label">ייצוא מסד הנתונים</string>
<string name="database_import_label">ייבוא מסד נתונים</string>
+ <string name="database_import_warning">ייבוא מסד נתונים יחליף את כל המינויים הנוכחיים שלך לרבות היסטוריית הנגינה. עליך תחילה לייצא את מסד הנתונים הנוכחי שלך כגיבוי. להמשיך בהחלפה?</string>
<string name="please_wait">נא להמתין…</string>
<string name="export_error_label">שגיאת ייצוא</string>
<string name="export_success_title">הייצוא הצליח</string>
@@ -645,16 +663,23 @@
<string name="subscribe_label">הרשמה</string>
<string name="subscribing_label">מתבצע רישום…</string>
<string name="preview_episode">תצוגה מקדימה</string>
+ <string name="stop_preview">עצירת התצוגה המקדימה</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">חזרה לאחור</string>
<string name="fast_forward_label">הרצה קדימה</string>
+ <string name="increase_speed">האצה</string>
+ <string name="decrease_speed">האטה</string>
<string name="media_type_audio_label">שמע</string>
<string name="media_type_video_label">וידאו</string>
<string name="navigate_upwards_label">ניווט כלפי מעלה</string>
<string name="status_downloading_label">הפרק יורד</string>
<string name="in_queue_label">הפרק בתור</string>
+ <string name="is_favorite_label">הפרק מסומן כמועדף</string>
<string name="drag_handle_content_description">גרור לשינוי מיקום פריט זה</string>
<string name="load_next_page_label">טעינת הדף הבא</string>
+ <string name="switch_pages">החלפת עמודים</string>
+ <string name="position">מיקום: %1$s</string>
+ <string name="apply_action">החלת פעולה</string>
<!--Feed information screen-->
<string name="authentication_label">אימות</string>
<string name="authentication_descr">שינוי שם המשתמש והססמה שלך לפודקאסט הזה ולפרקים שלו.</string>
@@ -680,6 +705,7 @@
<string name="browse_gpoddernet_label">עיון ב־gpodder.net</string>
<string name="discover">עיון</string>
<string name="discover_more">עוד »</string>
+ <string name="search_powered_by">החיפוש מופעל על ידי %1$s</string>
<string name="filter">מסנן</string>
<!--Episodes apply actions-->
<string name="all_label">הכול</string>
@@ -707,6 +733,12 @@
<string name="sort_date_old_new">תאריך (ישן \u2192 חדש)</string>
<string name="sort_duration_short_long">משך (קצר \u2192 ארוך)</string>
<string name="sort_duration_long_short">משך (קצר \u2192 ארוך)</string>
+ <string name="sort_a_z">א \u2192 ת</string>
+ <string name="sort_z_a">ת \u2192 א</string>
+ <string name="sort_new_old">חדש \u2192 ישן</string>
+ <string name="sort_old_new">ישן \u2192 חדש</string>
+ <string name="sort_short_long">קצר \u2192 ארוך</string>
+ <string name="sort_long_short">ארוך \u2192 קצר</string>
<!--Rating dialog-->
<string name="rating_title">היישומון אנטנה־פּוֹד נושא חן בעיניך?</string>
<string name="rating_message">מאוד נשמח לקבל דירוג על אנטנה־פּוֹד אם יש לך זמן לכך.</string>
@@ -766,4 +798,8 @@
<string name="widget_settings">הגדרות וידג׳ט</string>
<string name="widget_create_button">יצירת וידג׳</string>
<string name="widget_opacity">אטימות</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">ההגדרות עודכנו בהצלחה.</string>
+ <string name="on_demand_config_stream_text">נראה כי הזרמה משמשת אותך רבות. מעניין אותך שרשימות פרקים יציגו כפתורי הזרמה?</string>
+ <string name="on_demand_config_download_text">נראה כי הורדה משמשת אותך רבות. מעניין אותך שרשימות פרקים יציגו כפתורי הורדה?</string>
</resources>
diff --git a/core/src/main/res/values-ja/strings.xml b/core/src/main/res/values-ja/strings.xml
index 5798714c3..b1d14e9d4 100644
--- a/core/src/main/res/values-ja/strings.xml
+++ b/core/src/main/res/values-ja/strings.xml
@@ -2,6 +2,7 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--Activity and fragment titles-->
<string name="feed_update_receiver_name">購読を更新</string>
+ <string name="feeds_label">ポッドキャスト</string>
<string name="statistics_label">統計情報</string>
<string name="add_feed_label">フィードを追加</string>
<string name="episodes_label">エピソード</string>
@@ -19,10 +20,11 @@
<string name="cancel_download_label">ダウンロードをキャンセル</string>
<string name="playback_history_label">再生履歴</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">他のデバイスと同期</string>
<string name="gpodnet_auth_label">gpodder.net ログイン</string>
<string name="episode_cache_full_title">エピソードキャッシュが一杯です</string>
<string name="episode_cache_full_message">エピソードキャッシュが制限に達しました。設定でキャッシュサイズを増やすことができます。</string>
+ <string name="playback_statistics_label">再生</string>
+ <string name="download_statistics_label">ダウンロード</string>
<!--Statistics fragment-->
<string name="total_time_listened_to_podcasts">ポッドキャストを再生した合計時間:</string>
<string name="statistics_details_dialog">%2$d から %1$d のエピソードが開始しました。\n\n%4$s から%3$s を再生しました。</string>
@@ -33,6 +35,7 @@
<string name="statistics_reset_data">統計情報のデータをリセット</string>
<string name="statistics_reset_data_msg">これにより、すべてのエピソードを再生した期間の履歴が消去されます。 続行しますか?</string>
<!--Download Statistics fragment-->
+ <string name="total_size_downloaded_podcasts">ダウンロード済のポッドキャストのサイズ合計:</string>
<!--Main activity-->
<string name="drawer_open">メニューを開く</string>
<string name="drawer_close">メニューを閉じる</string>
@@ -81,6 +84,10 @@
<string name="auto_download_apply_to_items_title">前のエピソードに適用</string>
<string name="auto_download_apply_to_items_message">新しい <i>自動ダウンロード</i> の設定は、自動的に新しいエピソードに適用されます。\n以前に公開されたエピソードにも適用しますか?</string>
<string name="auto_delete_label">エピソードを自動削除</string>
+ <string name="feed_volume_reduction">ボリューム削減</string>
+ <string name="feed_volume_reduction_off">オフ</string>
+ <string name="feed_volume_reduction_light">ライト</string>
+ <string name="feed_volume_reduction_heavy">ヘビー</string>
<string name="parallel_downloads_suffix">\u0020パラレル ダウンロード</string>
<string name="feed_auto_download_global">全般のデフォルト</string>
<string name="feed_auto_download_always">常に</string>
@@ -95,7 +102,7 @@
<plurals name="episode_cleanup_days_after_listening">
<item quantity="other">完了 %d 日後</item>
</plurals>
- <string name="num_selected_label">%d 選択</string>
+ <string name="loading_more">さらに読み込んでいます…</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">すべて再生済としてマーク</string>
<string name="mark_all_read_msg">すべてのエピソードを再生済にしました</string>
@@ -115,11 +122,13 @@
<string name="share_link_with_position_label">エピソード URL を位置と共に共有</string>
<string name="share_file_label">ファイルを共有</string>
<string name="share_website_url_label">ウェブサイト URLを共有</string>
+ <string name="share_feed_url_label">ポッドキャスト URL を共有</string>
<string name="share_item_url_label">メディアファイル URLを共有</string>
<string name="share_item_url_with_position_label">メディアファイル URL を位置と共に共有</string>
<string name="feed_delete_confirmation_msg">ポッドキャスト \"%1$s\" とすべての(ダウンロード済を含む)エピソードを削除することを確認してください。</string>
<string name="feed_remover_msg">ポッドキャストを削除しています</string>
<string name="load_complete_feed">ポッドキャストをすべて更新</string>
+ <string name="multi_select">複数選択</string>
<string name="select_all_above">上のすべてを選択</string>
<string name="select_all_below">下のすべてを選択</string>
<string name="hide_unplayed_episodes_label">未再生</string>
@@ -134,6 +143,7 @@
<string name="filtered_label">フィルターしました</string>
<string name="refresh_failed_msg">{fa-exclamation-circle} 前回更新に失敗しました</string>
<string name="open_podcast">ポッドキャストを開く</string>
+ <string name="please_wait_for_data">データが読み込まれるまでしばらくお待ちください</string>
<!--actions on feeditems-->
<string name="download_label">ダウンロード</string>
<plurals name="downloading_batch_label">
@@ -152,10 +162,14 @@
<string name="removed_new_flag_label">\"新規\" フラグを削除しました</string>
<string name="mark_read_label">再生済としてマーク</string>
<string name="marked_as_read_label">再生済としてマークしました</string>
+ <string name="mark_read_no_media_label">既読にする</string>
+ <string name="marked_as_read_no_media_label">既読にしました</string>
+ <string name="play_this_to_seek_position">位置にジャンプするには、エピソードを再生する必要があります</string>
<plurals name="marked_read_batch_label">
<item quantity="other">%d エピソードを再生済にしました。</item>
</plurals>
<string name="mark_unread_label">未再生としてマーク</string>
+ <string name="mark_unread_label_no_media">未読にする</string>
<plurals name="marked_unread_batch_label">
<item quantity="other">%d エピソードを未再生にしました。</item>
</plurals>
@@ -198,6 +212,7 @@
<string name="download_canceled_msg">ダウンロードをキャンセルしました</string>
<string name="download_canceled_autodownload_enabled_msg">ダウンロードをキャンセルしました\nこのアイテムの <i>自動ダウンロード</i> を無効にしました</string>
<string name="download_report_title">ダウンロードがエラーで完了しました</string>
+ <string name="auto_download_report_title">自動ダウンロードが完了しました</string>
<string name="download_report_content_title">ダウンロード レポート</string>
<string name="download_error_malformed_url">不正な形式のURL</string>
<string name="download_error_io_error">IOエラー</string>
@@ -233,11 +248,13 @@
<string name="playback_error_server_died">サーバーがダウンしています</string>
<string name="playback_error_unsupported">サポートされていないメディアタイプ</string>
<string name="playback_error_timeout">操作がタイムアウトしました</string>
+ <string name="playback_error_source">メディアファイルにアクセスできません</string>
<string name="playback_error_unknown">不明なエラー</string>
<string name="no_media_playing_label">再生するメディアがありません</string>
<string name="player_buffering_msg">バッファー中</string>
<string name="player_go_to_picture_in_picture">ピクチャ-イン-ピクチャ モード</string>
<string name="unknown_media_key">AntennaPod - 不明なメディアキー: %1$d</string>
+ <string name="error_file_not_found">ファイルが見つかりません</string>
<!--Queue operations-->
<string name="lock_queue">キューをロック</string>
<string name="unlock_queue">キューのロックを解除</string>
@@ -260,8 +277,6 @@
<string name="ascending">昇順</string>
<string name="descending">降順</string>
<string name="clear_queue_confirmation_msg">クリアする、キューに含まれるすべてのエピソードを確認してください。</string>
- <string name="sort_old_to_new">古いものから新しいもの</string>
- <string name="sort_new_to_old">新しいものから古いもの</string>
<string name="time_left_label">残り時間:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">プラグインをダウンロード</string>
@@ -293,9 +308,9 @@
<string name="no_subscriptions_label">ポッドキャストを購読するには、下のプラスアイコンを押してください。</string>
<!--Preferences-->
<string name="storage_pref">ストレージ</string>
+ <string name="storage_sum">エピソードの自動削除、インポート、エクスポート</string>
<string name="project_pref">プロジェクト</string>
<string name="queue_label">キュー</string>
- <string name="integrations_label">統合</string>
<string name="automation">自動</string>
<string name="download_pref_details">詳細</string>
<string name="import_export_pref">インポート/エクスポート</string>
@@ -327,8 +342,11 @@
<string name="pref_favorite_keeps_episodes_sum">エピソードをお気に入りに追加した時に残しておきます</string>
<string name="pref_favorite_keeps_episodes_title">お気に入りのエピソードを残す</string>
<string name="playback_pref">再生</string>
+ <string name="playback_pref_sum">ヘッドフォン制御、スキップ間隔、キュー</string>
<string name="network_pref">ネットワーク</string>
+ <string name="network_pref_sum">更新間隔、ダウンロード制御、モバイル通信</string>
<string name="pref_autoUpdateIntervallOrTime_title">間隔または時間を更新</string>
+ <string name="pref_autoUpdateIntervallOrTime_sum">自動的にポッドキャストを更新する間隔または時刻を指定してください</string>
<string name="pref_autoUpdateIntervallOrTime_message">\"2 時間ごと\" のような <i>間隔</i> 、\"7:00 AM\" のような特定の <i>時間</i> 、または自動更新を完全に <i>無効</i> にセットすることができます。\n\n<small>ご注意ください: 更新時間は正確ではありません。少し遅延が発生する可能性があります。</small></string>
<string name="pref_autoUpdateIntervallOrTime_Disable">無効</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">間隔をセット</string>
@@ -343,11 +361,13 @@
<string name="pref_stream_over_download_sum">ダウンロードボタンの代わりにストリームボタンをリストに表示します。</string>
<string name="pref_mobileUpdate_title">モバイル更新</string>
<string name="pref_mobileUpdate_sum">モバイルデータ接続時に許可するものを選択します</string>
+ <string name="pref_mobileUpdate_refresh">ポッドキャスト更新</string>
<string name="pref_mobileUpdate_images">カバー画像</string>
<string name="pref_mobileUpdate_auto_download">自動ダウンロード</string>
<string name="pref_mobileUpdate_episode_download">エピソードのダウンロード</string>
<string name="pref_mobileUpdate_streaming">ストリーミング</string>
<string name="user_interface_label">インターフェース</string>
+ <string name="user_interface_sum">外観、購読注文、ロック画面</string>
<string name="pref_set_theme_title">テーマを選択</string>
<string name="pref_nav_drawer_items_title">ナビゲーションドロワーを変更</string>
<string name="pref_nav_drawer_items_sum">ナビゲーションドロワーに表示するアイテムを変更します。</string>
@@ -381,17 +401,14 @@
<string name="pref_gpodnet_logout_toast">ログアウトしました</string>
<string name="pref_gpodnet_setlogin_information_title">ログイン情報を変更</string>
<string name="pref_gpodnet_setlogin_information_sum">gpodder.netアカウントのログイン情報を変更します。</string>
- <string name="pref_gpodnet_sync_changes_title">今すぐ変更を同期</string>
<string name="pref_gpodnet_sync_changes_sum">購読とエピソードの状態の変更を gpodder.net で同期します。</string>
- <string name="pref_gpodnet_full_sync_title">今すぐ完全に同期</string>
<string name="pref_gpodnet_full_sync_sum">すべての購読とエピソードの状態を gpodder.net で同期します。</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">最後に同期を試行: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">同期を開始しました</string>
<string name="pref_gpodnet_login_status"><![CDATA[<i>%1$s</i> としてデバイス <i>%2$s</i> でログインしました]]></string>
<string name="pref_gpodnet_notifications_title">同期エラーの通知を表示</string>
<string name="pref_gpodnet_notifications_sum">この設定は、認証エラーには適用されません。</string>
<string name="pref_playback_speed_title">再生速度</string>
<string name="pref_playback_speed_sum">可変速度音声再生に使用可能な速度をカスタマイズします</string>
+ <string name="pref_feed_playback_speed_sum">このポッドキャストでエピソードのオーディオ再生を開始するときに使用する速度</string>
<string name="pref_playback_time_respects_speed_title">メディア情報を再生速度に調整</string>
<string name="pref_playback_time_respects_speed_sum">表示される位置と時間が再生速度に調整されます</string>
<string name="pref_fast_forward">早送りのスキップ時間</string>
@@ -412,6 +429,8 @@
<string name="pref_lockscreen_background_sum">ロック画面の背景を、現在のエピソードの画像に設定します。副作用として、これはサードパーティのアプリケーションでも画像を表示します。</string>
<string name="pref_showDownloadReport_title">ダウンロード レポートを表示</string>
<string name="pref_showDownloadReport_sum">ダウンロードが失敗した場合、失敗の詳細を表示するレポートを生成します。</string>
+ <string name="pref_showAutoDownloadReport_title">自動ダウンロード レポートを表示</string>
+ <string name="pref_showAutoDownloadReport_sum">自動ダウンロードされたエピソードの通知を表示します。</string>
<string name="pref_expand_notify_unsupport_toast">Androidバージョン4.1以前では、拡張通知をサポートしていません。</string>
<string name="pref_enqueue_location_title">キューに入れる場所</string>
<string name="pref_enqueue_location_sum">エピソードを追加: %1$s</string>
@@ -421,8 +440,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="visit_user_forum">ユーザーフォーラム</string>
<string name="bug_report_title">バグを報告</string>
<string name="open_bug_tracker">バグトラッカーを開く</string>
+ <string name="export_logs">エピソードのログ</string>
<string name="copy_to_clipboard">クリップボードにコピー</string>
<string name="copied_to_clipboard">クリップボードにコピーしました</string>
<string name="experimental_pref">実験的</string>
@@ -470,7 +491,17 @@
<string name="search_status_no_results">見つかりませんでした</string>
<string name="search_label">検索</string>
<string name="no_results_for_query">\"%1$s\" の結果は見つかりませんでした</string>
+ <!--Synchronization-->
<!--import and export-->
+ <string name="import_export_summary">購読とキューを別のデバイスに移動</string>
+ <string name="database">データベース</string>
+ <string name="opml">OPML</string>
+ <string name="html">HTML</string>
+ <string name="html_export_summary">あなたの購読を友達に表示</string>
+ <string name="opml_export_summary">購読を別のポッドキャストアプリに転送する</string>
+ <string name="opml_import_summary">別のポッドキャストアプリから購読をインポートする</string>
+ <string name="database_export_summary">購読、再生したエピソード、キューを別のデバイスのAntennaPodに転送する</string>
+ <string name="database_import_summary">AntennaPod データベースを別のデバイスからインポートする</string>
<string name="opml_import_label">OPMLインポート</string>
<string name="opml_reader_error">OPMLドキュメントの読み込み中にエラーが発生しました:</string>
<string name="opml_import_error_no_file">ファイルが選択されていません!</string>
@@ -478,17 +509,23 @@
<string name="deselect_all_label">選択解除</string>
<string name="opml_export_label">OPMLエクスポート</string>
<string name="html_export_label">HTML エクスポート</string>
+ <string name="database_export_label">データベースのエクスポート</string>
+ <string name="database_import_label">データベースのインポート</string>
+ <string name="please_wait">しばらくお待ちください…</string>
<string name="export_error_label">エクスポートエラー</string>
<string name="export_success_title">エクスポートしました</string>
<string name="export_success_sum">エクスポートしたファイルを書き込みました:\n\n%1$s</string>
<string name="opml_import_ask_read_permission">OPML ファイルを読み込むために、外部ストレージへのアクセスが必要です</string>
<string name="import_select_file">インポートするファイルを選択してください</string>
<string name="import_ok">インポートが成功しました。\n\nOKを押してAntennaPodを再起動してください。</string>
+ <string name="import_no_downgrade">このデータベースは、AntennaPodの新しいバージョンでエクスポートされました。 現在インストールされたアプリでは、このファイルの処理方法がまだわかりません。</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">スリープタイマーをセット</string>
<string name="disable_sleeptimer_label">スリープタイマーを無効にする</string>
<string name="sleep_timer_label">スリープタイマー</string>
<string name="time_dialog_invalid_input">入力が正しくありません、時間は数字で入力してください</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>
@@ -561,6 +598,7 @@
<!--Online feed view-->
<string name="subscribe_label">購読</string>
<string name="subscribing_label">購読中…</string>
+ <string name="preview_episode">プレビュー</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">巻き戻し</string>
<string name="fast_forward_label">早送り</string>
@@ -581,6 +619,7 @@
<string name="episode_filters_exclude">含まない</string>
<string name="episode_filters_hint">単一の単語 \n\"複数の 単語\"</string>
<string name="keep_updated">更新済を保持</string>
+ <string name="keep_updated_summary">すべてのポッドキャストを (自動)更新する時にこのポッドキャストを含めます</string>
<string name="auto_download_disabled_globally">メインの AntennaPod 設定で自動ダウンロードが無効になっています</string>
<!--Progress information-->
<string name="progress_upgrading_database">データベースをアップグレードしています</string>
@@ -590,6 +629,8 @@
<string name="search_podcast_hint">ポッドキャストの検索…</string>
<string name="search_itunes_label">iTunes を検索</string>
<string name="search_fyyd_label">fyydを検索</string>
+ <string name="advanced">詳細</string>
+ <string name="add_podcast_by_url">URLでポッドキャストを追加</string>
<string name="browse_gpoddernet_label">gpodder.netを参照</string>
<string name="discover">発見</string>
<string name="discover_more">さらに »</string>
@@ -673,8 +714,11 @@
<string name="notification_channel_playing_description">再生をコントロールできます。これはポッドキャスト再生中のメイン通知です。</string>
<string name="notification_channel_error">エラー</string>
<string name="notification_channel_error_description">ダウンロードや gpodder の同期に失敗した場合など、何か問題が発生した場合に表示されます。</string>
+ <string name="notification_channel_auto_download">自動ダウンロード</string>
+ <string name="notification_channel_episode_auto_download">エピソードが自動ダウンロードされた時に表示します。</string>
<!--Widget settings-->
<string name="widget_settings">ウィジェット設定</string>
<string name="widget_create_button">ウィジェットを作成</string>
<string name="widget_opacity">透明度</string>
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-ko/strings.xml b/core/src/main/res/values-ko/strings.xml
index f9f67ec46..04e732a3c 100644
--- a/core/src/main/res/values-ko/strings.xml
+++ b/core/src/main/res/values-ko/strings.xml
@@ -20,7 +20,6 @@
<string name="cancel_download_label">다운로드\n취소</string>
<string name="playback_history_label">재생 기록</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">다른 장비와 동기화</string>
<string name="gpodnet_auth_label">gpodder.net 로그인</string>
<string name="episode_cache_full_title">에피소드 캐시 꽉 참</string>
<string name="episode_cache_full_message">에피소드 캐시 한계값에 도달했습니다. 설정에서 캐시 크기를 늘릴 수 있습니다.</string>
@@ -86,7 +85,7 @@
<string name="auto_download_apply_to_items_message">새로운 <i>자동 다운로드</i> 설정은 자동으로 새로운 에피소드에 적용됩니다. 예전 에피소드에도 적용하시겠습니까?</string>
<string name="auto_delete_label">에피소드 자동 삭제</string>
<string name="feed_volume_reduction">볼륨 줄이기</string>
- <string name="feed_volume_reduction_summary">이 피드의 에피소드에 대해 볼륨을 줄이기: \%s</string>
+ <string name="feed_volume_reduction_summary">이 피드의 에피소드에 대해 볼륨을 줄이기: %1$s</string>
<string name="feed_volume_reduction_off">끄기</string>
<string name="feed_volume_reduction_light">가볍게</string>
<string name="feed_volume_reduction_heavy">무겁게</string>
@@ -104,7 +103,9 @@
<plurals name="episode_cleanup_days_after_listening">
<item quantity="other">재생이 끝나고 나서 %d일 뒤</item>
</plurals>
- <string name="num_selected_label">%d개 선택</string>
+ <plurals name="num_selected_label">
+ <item quantity="other">%d개 선택</item>
+ </plurals>
<string name="loading_more">더 읽어들이기…</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">모두 재생했다고 표시</string>
@@ -195,6 +196,7 @@
<string name="deactivate_auto_download">자동 다운로드 해제</string>
<string name="reset_position">재생 위치 초기화</string>
<string name="removed_item">항목 제거됨</string>
+ <string name="no_items_selected">선택 없음</string>
<!--Download messages and labels-->
<string name="download_successful">성공</string>
<string name="download_pending">다운로드 지연 중</string>
@@ -280,8 +282,6 @@
<string name="ascending">오름차순</string>
<string name="descending">내림차순</string>
<string name="clear_queue_confirmation_msg">내부의 모든 에피소드를 지울지 확인하십시오.</string>
- <string name="sort_old_to_new">과거에서 최근</string>
- <string name="sort_new_to_old">최근에서 과거</string>
<string name="time_left_label">남은 시간:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">플러그인 다운로드</string>
@@ -316,8 +316,8 @@
<string name="storage_sum">에피소드 자동 삭제, 가져오기, 내보내기</string>
<string name="project_pref">프로젝트</string>
<string name="queue_label">대기열</string>
- <string name="integrations_label">연동 기능</string>
- <string name="integrations_sum">동기화</string>
+ <string name="synchronization_pref">동기화</string>
+ <string name="synchronization_sum">gpodder.net 사용하는 다른 장비와 동기화</string>
<string name="automation">자동</string>
<string name="download_pref_details">자세히</string>
<string name="import_export_pref">가져오기/내보내기</string>
@@ -408,18 +408,22 @@
<string name="pref_gpodnet_logout_toast">로그아웃 성공</string>
<string name="pref_gpodnet_setlogin_information_title">로그인 정보 바꾸기</string>
<string name="pref_gpodnet_setlogin_information_sum">gpodder.net 계정의 로그인 정보를 바꿉니다.</string>
- <string name="pref_gpodnet_sync_changes_title">변경 사항 지금 동기화</string>
+ <string name="pref_gpodnet_sync_changes_title">지금 동기화</string>
<string name="pref_gpodnet_sync_changes_sum">gpodder.net의 구독과 에피소드 상태 변화를 동기화합니다.</string>
- <string name="pref_gpodnet_full_sync_title">지금 전체 동기화</string>
+ <string name="pref_gpodnet_full_sync_title">전체 동기화 강제</string>
<string name="pref_gpodnet_full_sync_sum">gpodder.net의 모든 구독과 에피소드 상태를 동기화합니다.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">최근 동기화 시도: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">동기화 시작함</string>
<string name="pref_gpodnet_login_status"><![CDATA[<i>%1$s</i> 사용자로 로그인, <i>%2$s</i> 장치]]></string>
<string name="pref_gpodnet_notifications_title">동기화 오류 알림 표시</string>
<string name="pref_gpodnet_notifications_sum">이 설정은 인증 오류에는 적용되지 않습니다.</string>
<string name="pref_playback_speed_title">재생 속도</string>
<string name="pref_playback_speed_sum">여러가지 오디오 재생 속도 직접 설정</string>
<string name="pref_feed_playback_speed_sum">이 팟캐스트의 에피소드를 재생할 때 사용할 오디오 재생 속도</string>
+ <string name="pref_feed_skip">자동 건너뛰기</string>
+ <string name="pref_feed_skip_sum">소개 및 마지막 크레디트 건너뛰기</string>
+ <string name="pref_feed_skip_ending">마지막 건너뛰기</string>
+ <string name="pref_feed_skip_intro">처음 건너뛰기</string>
+ <string name="pref_feed_skip_ending_toast">마지막 %d초 건너뜀</string>
+ <string name="pref_feed_skip_intro_toast">처음 %d초 건너뜀</string>
<string name="pref_playback_time_respects_speed_title">미디어 정보를 재생 속도에 맞게 조정</string>
<string name="pref_playback_time_respects_speed_sum">재생 속도에 맞춰 재생 위치와 재생 시간을 표시합니다</string>
<string name="pref_fast_forward">빠르게 감기 건너뛰기 시간</string>
@@ -470,6 +474,8 @@
<string name="pref_enqueue_downloaded_title">다운로드한 항목 대기열에 추가</string>
<string name="pref_enqueue_downloaded_summary">다운로드한 에피소드를 대기열에 추가</string>
<string name="media_player_builtin">내장 안드로이드 플레이어</string>
+ <string name="media_player_switch_to_exoplayer">ExoPlayer로 전환</string>
+ <string name="media_player_switched_to_exoplayer">ExoPlayer로 전환함.</string>
<string name="pref_skip_silence_title">오디오에서 묵음 구간 건너뛰기</string>
<string name="pref_videoBehavior_title">기존 비디오에 대해</string>
<string name="pref_videoBehavior_sum">비디오 재생을 떠날 때 동작</string>
@@ -502,6 +508,14 @@
<string name="search_status_no_results">검색 결과가 없습니다</string>
<string name="search_label">검색</string>
<string name="no_results_for_query">\"%1$s\" 검색 결과가 없습니다</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">동기화 시작함</string>
+ <string name="sync_status_episodes_upload">에피소드 변경 업로드 중...</string>
+ <string name="sync_status_episodes_download">에피소드 변경 다운로드 중...</string>
+ <string name="sync_status_upload_played">재생한 상태 업로드 중...</string>
+ <string name="sync_status_subscriptions">구독 정보 동기화 중...</string>
+ <string name="sync_status_success">동기화 성공</string>
+ <string name="sync_status_error">동기화 실패</string>
<!--import and export-->
<string name="import_export_summary">구독 목록 및 대기열을 다른 장치로 옮기기</string>
<string name="database">데이터베이스</string>
@@ -521,6 +535,7 @@
<string name="html_export_label">HTML 내보내기</string>
<string name="database_export_label">데이터베이스 내보내기</string>
<string name="database_import_label">데이터베이스 가져오기</string>
+ <string name="database_import_warning">데이터베이스 가져오기를 하면 모든 구독과 재생 히스토리가 가져온 내용으로 바뀝니다. 백업을 하려면 현재 데이터베이스를 내보내기 해야 합니다. 정말로 데이터베이스를 바꾸시겠습니까?</string>
<string name="please_wait">기다리십시오…</string>
<string name="export_error_label">내보내기 오류</string>
<string name="export_success_title">내보내기 성공</string>
@@ -609,16 +624,23 @@
<string name="subscribe_label">구독</string>
<string name="subscribing_label">구독하는 중…</string>
<string name="preview_episode">미리보기</string>
+ <string name="stop_preview">미리 보기 중지</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">뒤로 감기</string>
<string name="fast_forward_label">앞으로 감기</string>
+ <string name="increase_speed">속도 증가</string>
+ <string name="decrease_speed">속도 감소</string>
<string name="media_type_audio_label">오디오</string>
<string name="media_type_video_label">비디오</string>
<string name="navigate_upwards_label">위 단계로 이동</string>
<string name="status_downloading_label">에피소드를 다운로드하는 중입니다</string>
<string name="in_queue_label">에피소드가 대기열에 들어 있습니다</string>
+ <string name="is_favorite_label">에피소드를 좋아한다고 표시되었습니다</string>
<string name="drag_handle_content_description">이 항목의 위치를 바꾸려면 드래그하십시오</string>
<string name="load_next_page_label">다음 페이지 읽기</string>
+ <string name="switch_pages">페이지 전환</string>
+ <string name="position">위치: %1$s</string>
+ <string name="apply_action">동작 적용</string>
<!--Feed information screen-->
<string name="authentication_label">인증</string>
<string name="authentication_descr">이 팟캐스트와 에피소드에 대한 사용자 이름과 비밀번호를 바꿉니다.</string>
@@ -644,6 +666,7 @@
<string name="browse_gpoddernet_label">gpodder.net 둘러보기</string>
<string name="discover">발견</string>
<string name="discover_more">더 보기 »</string>
+ <string name="search_powered_by">검색 기능 제공 %1$s</string>
<string name="filter">필터</string>
<!--Episodes apply actions-->
<string name="all_label">모두</string>
@@ -671,6 +694,12 @@
<string name="sort_date_old_new">시각 (과거 \u2192 최근)</string>
<string name="sort_duration_short_long">길이 (짧음 \u2192 김)</string>
<string name="sort_duration_long_short">길이 (김 \u2192 짧음)</string>
+ <string name="sort_a_z">A \u2192 Z</string>
+ <string name="sort_z_a">Z \u2192 A</string>
+ <string name="sort_new_old">최근 \u2192 과거</string>
+ <string name="sort_old_new">과거 \u2192 최근</string>
+ <string name="sort_short_long">짧음 \u2192 김</string>
+ <string name="sort_long_short">김 \u2192 짧음</string>
<!--Rating dialog-->
<string name="rating_title">안테나팟이 마음에 드시나요?</string>
<string name="rating_message">안테나팟을 평가하는데 시간을 잠깐 내주시면 감사하겠습니다.</string>
@@ -730,4 +759,8 @@
<string name="widget_settings">위젯 설정</string>
<string name="widget_create_button">위젯 만들기</string>
<string name="widget_opacity">불투명 정도</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">성공적으로 설정 업데이트함.</string>
+ <string name="on_demand_config_stream_text">평소에 스트리밍을 많이 이용하는 것 같습니다. 에피소드 목록에서 스트리밍 버튼을 표시할까요?</string>
+ <string name="on_demand_config_download_text">평소에 다운로드를 많이 이용하는 것 같습니다. 에피소드 목록에서 다운로드 버튼을 표시할까요?</string>
</resources>
diff --git a/core/src/main/res/values-lt/strings.xml b/core/src/main/res/values-lt/strings.xml
index 8646a8356..ad6f4bc71 100644
--- a/core/src/main/res/values-lt/strings.xml
+++ b/core/src/main/res/values-lt/strings.xml
@@ -19,7 +19,6 @@
<string name="cancel_download_label">Atšaukti\natsiuntimą</string>
<string name="playback_history_label">Atkūrimo istorija</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Sinchronizuojama su kitais įrenginiais</string>
<string name="gpodnet_auth_label">gpodder.net prisijungimas</string>
<string name="episode_cache_full_title">Epizodų podėlis pilnas</string>
<string name="episode_cache_full_message">Pasiektas epizodų podėlio dydžio limitas. Nustatymuose galite padidinti podėlio dydį.</string>
@@ -263,7 +262,6 @@
<string name="storage_pref">Laikmena</string>
<string name="project_pref">Projektas</string>
<string name="queue_label">Eilė</string>
- <string name="integrations_label">Integracijos</string>
<string name="automation">Automatizacija</string>
<string name="download_pref_details">Išsamiau</string>
<string name="import_export_pref">Importas/Eksportas</string>
@@ -335,12 +333,8 @@
<string name="pref_gpodnet_logout_toast">Sėkmingai atsijungta</string>
<string name="pref_gpodnet_setlogin_information_title">Keisti prisijungimo duomenis</string>
<string name="pref_gpodnet_setlogin_information_sum">Keisti prisijungimo prie „gpodder.net“ paskyros duomenis.</string>
- <string name="pref_gpodnet_sync_changes_title">Sinchronizuoti pakeitimus dabar</string>
<string name="pref_gpodnet_sync_changes_sum">Sinchronizuoti prenumeratų bei epizodų būsenų pasikeitimus su „gpodder.net“.</string>
- <string name="pref_gpodnet_full_sync_title">Pradėti pilną sinchronizavimą dabar</string>
<string name="pref_gpodnet_full_sync_sum">Sinchronizuoti visas prenumeratas bei epizodų būsenas su „gpodder.net“.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Paskutinis sinchronizavimo bandymas: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Pradėtas sinchronizavimas</string>
<string name="pref_gpodnet_login_status"><![CDATA[Prisijungta kaip <i>%1$s</i> naudojant įrenginį <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Rodyti sinchronizavimo klaidų pranešimus</string>
<string name="pref_gpodnet_notifications_sum">Šis nustatymas negalioja tapatumo nustatymo klaidoms.</string>
@@ -404,6 +398,7 @@
<string name="search_status_no_results">Nieko nerasta</string>
<string name="search_label">Paieška</string>
<string name="no_results_for_query">Rezultatų paieškai \"%1$s\" nėra.</string>
+ <!--Synchronization-->
<!--import and export-->
<string name="opml_import_label">OPML importas</string>
<string name="opml_reader_error">Skaitant OPML failą įvyko klaida:</string>
@@ -612,4 +607,5 @@ Spauskite „OK“, kad paleisti „AntennaPod“ iš naujo.</string>
<string name="notification_channel_error">Klaidos</string>
<string name="notification_channel_error_description">Rodomas, kai įvykstą kažkas nenumatyto, pavyzdžiui, nepavykus atsiuntimui ar „gpodder“ sinchronizavimui.</string>
<!--Widget settings-->
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-nb/strings.xml b/core/src/main/res/values-nb/strings.xml
index 2bb531396..fd2c927b9 100644
--- a/core/src/main/res/values-nb/strings.xml
+++ b/core/src/main/res/values-nb/strings.xml
@@ -20,19 +20,19 @@
<string name="cancel_download_label">Avbryt\nLast ned</string>
<string name="playback_history_label">Avspillingshistorikk</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Synkroniser med andre enheter</string>
<string name="gpodnet_auth_label">gpodder.net-innlogging</string>
<string name="episode_cache_full_title">Hurtigbuffer for episoder er full</string>
- <string name="episode_cache_full_message">Grensen for størrelse på hurtigbuffer er nådd. Du kan øke størrelsen på hurtigbuffer i instillingene.</string>
+ <string name="episode_cache_full_message">Grensen for størrelse på hurtigbuffer er nådd. Du kan øke størrelsen på hurtigbuffer i innstillingene.</string>
<string name="playback_statistics_label">Avspilling</string>
<string name="download_statistics_label">Nedlastinger</string>
<!--Statistics fragment-->
- <string name="total_time_listened_to_podcasts">Sum av avspilte podcaster:</string>
+ <string name="total_time_listened_to_podcasts">Sum av tid i avspilte podkaster:</string>
<string name="statistics_details_dialog">Startet %1$d av %2$d episoder.\n\nAvspilt %3$s av %4$s.</string>
<string name="statistics_mode">Statistikk modus</string>
- <string name="statistics_mode_normal">Kalkuler faktisk avspilt varighet. Dobbel avspilling telles to ganger, mens markering som avspilt telles ikke</string>
+ <string name="statistics_mode_normal">Beregn faktisk avspilt varighet. Dobbel avspilling telles to ganger, mens markering som avspilt telles ikke</string>
+ <string name="statistics_mode_count_all">Oppsummer alle podkaster merket som avspilt</string>
<string name="statistics_speed_not_counted">Merk: Avspillingshastighet tas aldri med i betraktningen.</string>
- <string name="statistics_reset_data">Tilbakestille statistikkdata</string>
+ <string name="statistics_reset_data">Tilbakestill statistikkdata</string>
<string name="statistics_reset_data_msg">Dette vil slette historikk om varighet som er spilt for alle episoder. Er du sikker på at du vil fortsette?</string>
<!--Download Statistics fragment-->
<string name="total_size_downloaded_podcasts">Total størrelse på nedlastede podkaster:</string>
@@ -72,7 +72,7 @@
<string name="needs_storage_permission">Lagringstillatelse er nødvendig for denne operasjonen</string>
<string name="refresh_label">Oppdater</string>
<string name="external_storage_error_msg">Finner ikke ekstern lagring. Sjekk at det eksterne lagringsmediet er montert.</string>
- <string name="chapters_label">Kapittel</string>
+ <string name="chapters_label">Kapitler</string>
<string name="chapter_duration">Varighet: %1$s</string>
<string name="description_label">Beskrivelse</string>
<string name="episodes_suffix">\u0020episoder</string>
@@ -85,18 +85,21 @@
<string name="auto_download_apply_to_items_message">Den nye <i>Automatisk nedlasting</i>-innstillingen vil automatisk aktiveres for nye episoder.\nØnsker du å aktivere den for tidligere utgitte episoder også?</string>
<string name="auto_delete_label">Slett episode automatisk</string>
<string name="feed_volume_reduction">Volumreduksjon</string>
- <string name="feed_volume_reduction_summary">Skru ned volumet for episoder av denne strømmen: \%s</string>
<string name="feed_volume_reduction_off">Av</string>
- <string name="feed_volume_reduction_light">Lys</string>
+ <string name="feed_volume_reduction_light">Lett</string>
<string name="feed_volume_reduction_heavy">Tung</string>
<string name="parallel_downloads_suffix">\u0020samtidige nedlastinger</string>
<string name="feed_auto_download_global">Global standard</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="send_label">Send...</string>
<string name="episode_cleanup_never">Aldri</string>
<string name="episode_cleanup_queue_removal">Når ikke i kø</string>
- <string name="episode_cleanup_after_listening">Etter den er ferdig</string>
+ <string name="episode_cleanup_after_listening">Etter fullført avspilling</string>
+ <plurals name="episode_cleanup_hours_after_listening">
+ <item quantity="one">1 time etter fullført avspilling</item>
+ <item quantity="other">%d timer etter fullført avspilling</item>
+ </plurals>
<plurals name="episode_cleanup_days_after_listening">
<item quantity="one">1 dag etter fullført avspilling</item>
<item quantity="other">%d dager etter fullført avspilling</item>
@@ -107,6 +110,9 @@
<string name="mark_all_read_msg">Marker alle episoder som avspilt</string>
<string name="mark_all_read_confirmation_msg">Vennligst bekreft at du ønsker å markere alle episoder som avspilt.</string>
<string name="mark_all_read_feed_confirmation_msg">Bekreft at du ønsker å markere alle episoder i denne podkasten som avspilt.</string>
+ <string name="remove_all_new_flags_label">Fjern alle \"Ny\"-markeringer</string>
+ <string name="removed_all_new_flags_msg">Fjernet alle \"Ny\"-markeringer</string>
+ <string name="remove_all_new_flags_confirmation_msg">Bekreft at du ønsker å fjerne \"Ny\"-markeringen fra alle episoder</string>
<string name="show_info_label">Vis informasjon</string>
<string name="show_feed_settings_label">Vis podkastinnstillinger</string>
<string name="feed_info_label">Podkastinfo</string>
@@ -121,7 +127,12 @@
<string name="share_feed_url_label">Del podkastens URL</string>
<string name="share_item_url_label">Del mediafilens URL</string>
<string name="share_item_url_with_position_label">Del mediafilens URL med posisjon</string>
+ <string name="feed_delete_confirmation_msg">Bekreft at du ønsker å slette podkasten \"%1$s\" og ALLE episodene dens (inkludert nedlastede episoder).</string>
<string name="feed_remover_msg">Fjerner podkast</string>
+ <string name="load_complete_feed">Last hele podkasten på nytt</string>
+ <string name="multi_select">Velg flere</string>
+ <string name="select_all_above">Velg alle over</string>
+ <string name="select_all_below">Velg alle under</string>
<string name="hide_unplayed_episodes_label">Ikke avspilt</string>
<string name="hide_paused_episodes_label">Pauset</string>
<string name="hide_played_episodes_label">Avspilt</string>
@@ -129,28 +140,56 @@
<string name="hide_not_queued_episodes_label">Ikke i kø</string>
<string name="hide_downloaded_episodes_label">Nedlastet</string>
<string name="hide_not_downloaded_episodes_label">Ikke nedlastet</string>
- <string name="hide_has_media_label">Har media</string>
+ <string name="hide_has_media_label">Har medier</string>
+ <string name="hide_is_favorite_label">Er favoritt</string>
<string name="filtered_label">Filtrert</string>
<string name="refresh_failed_msg">{fa-exclamation-circle} Siste oppdatering mislyktes</string>
- <string name="open_podcast">Åpne podcast</string>
+ <string name="open_podcast">Åpne podkast</string>
<string name="please_wait_for_data">Vent til dataene er lastet inn</string>
<!--actions on feeditems-->
<string name="download_label">Last ned</string>
+ <plurals name="downloading_batch_label">
+ <item quantity="one">Laster ned %d episode.</item>
+ <item quantity="other">Laster ned %d episoder.</item>
+ </plurals>
<string name="play_label">Spill</string>
<string name="pause_label">Pause</string>
<string name="stream_label">Strøm</string>
<string name="delete_label">Slett</string>
<string name="delete_failed">Kan ikke slette filen. Omstart av enheten kan hjelpe.</string>
+ <string name="delete_episode_label">Slett episode</string>
+ <plurals name="deleted_episode_batch_label">
+ <item quantity="one">%d episode slettet.</item>
+ <item quantity="other">%d episode slettet.</item>
+ </plurals>
+ <string name="remove_new_flag_label">Fjern \"Ny\"-markering</string>
+ <string name="removed_new_flag_label">Fjernet \"Ny\"-markering</string>
<string name="mark_read_label">Marker som avspilt</string>
<string name="marked_as_read_label">Marker som avspilt</string>
<string name="mark_read_no_media_label">Merk som lest</string>
<string name="marked_as_read_no_media_label">Merket som lest</string>
<string name="play_this_to_seek_position">For å hoppe til posisjoner, må du spille episoden</string>
+ <plurals name="marked_read_batch_label">
+ <item quantity="one">%d episode merket som avspilt.</item>
+ <item quantity="other">%d episoder merket som avspilt.</item>
+ </plurals>
<string name="mark_unread_label">Marker som ikke avspilt</string>
<string name="mark_unread_label_no_media">Merk som ulest</string>
+ <plurals name="marked_unread_batch_label">
+ <item quantity="one">%d episode merket som ikke avspilt.</item>
+ <item quantity="other">%d episoder merket som ikke avspilt.</item>
+ </plurals>
<string name="add_to_queue_label">Legg til i kø</string>
<string name="added_to_queue_label">Lagt til i kø</string>
+ <plurals name="added_to_queue_batch_label">
+ <item quantity="one">%d episode lagt til i køen.</item>
+ <item quantity="other">%d episoder lagt til i køen.</item>
+ </plurals>
<string name="remove_from_queue_label">Fjern fra køen</string>
+ <plurals name="removed_from_queue_batch_label">
+ <item quantity="one">%d episode fjernet fra køen.</item>
+ <item quantity="other">%d episoder fjernet fra køen.</item>
+ </plurals>
<string name="add_to_favorite_label">Legg til i favoritter</string>
<string name="added_to_favorites">Legg til i favoritter</string>
<string name="remove_from_favorite_label">Fjern fra favoritter</string>
@@ -166,6 +205,7 @@
<string name="download_pending">Nedlastning venter</string>
<string name="download_running">Nedlasting pågår</string>
<string name="download_error_details">Detaljer</string>
+ <string name="download_error_details_message">%1$s \n\nFil-URL:\n%2$s</string>
<string name="download_error_device_not_found">Lagringsenhet ikke funnet</string>
<string name="download_error_insufficient_space">Ikke nok plass</string>
<string name="download_error_http_data_error">HTTP-datafeil</string>
@@ -180,23 +220,32 @@
<string name="download_canceled_msg">Nedlasting avbrutt</string>
<string name="download_canceled_autodownload_enabled_msg">Nedlasting avbrutt\n<i>Automatisk nedlasting</i> for dette elementet er deaktivert</string>
<string name="download_report_title">Nedlasting fullført med feilmeldinger</string>
+ <string name="auto_download_report_title">Auto-nedlasting fullført</string>
<string name="download_report_content_title">Nedlastingsrapport</string>
<string name="download_error_malformed_url">Ugyldig URL</string>
<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>
+ <plurals name="downloads_left">
+ <item quantity="one">%d nedlasting gjenstår</item>
+ <item quantity="other">%d nedlastinger gjenstår</item>
+ </plurals>
<string name="downloads_processing">Behandler nedlastninger</string>
- <string name="download_notification_title">Laster ned data til podcast</string>
+ <string name="download_notification_title">Laster ned data til podkast</string>
<string name="download_report_content">%1$d nedlastninger lyktes, %2$d mislyktes</string>
<string name="download_log_title_unknown">Ukjent tittel</string>
<string name="download_type_feed">Strøm</string>
<string name="download_type_media">Mediafil</string>
<string name="download_request_error_dialog_message_prefix">En feil oppsto under nedlastningen av filen:\u0020</string>
+ <string name="null_value_podcast_error">Ingen podkast ble gitt som kunne vises.</string>
<string name="authentication_notification_title">Autentisering påkreves</string>
<string name="authentication_notification_msg">Ressursen du forespør krever brukernavn og passord</string>
<string name="confirm_mobile_download_dialog_title">Bekreft nedlasting over mobildata</string>
<string name="confirm_mobile_download_dialog_message_not_in_queue">Nedlasting over mobildata er deaktivert i innstillingene.\n\nDu kan velge å legge episoden til i køen eller tillate midlertidig nedlasting over mobildata.\n\n<small>Valget ditt vil gjelde i 10 minutter.</small></string>
<string name="confirm_mobile_download_dialog_message">Nedlasting over mobildata er deaktivert i innstillingene.\n\nVil du tillate nedlasting over mobildata midlertidig?\n\n<small>Valget ditt vil gjelde i 10 minutter.</small></string>
+ <string name="confirm_mobile_streaming_notification_title">Bekreft mobil strømming</string>
+ <string name="confirm_mobile_streaming_notification_message">Strømming over mobildata er deaktivert i innstillingene. Trykk for å strømme likevel.</string>
+ <string name="confirm_mobile_streaming_button_always">Tillat alltid</string>
<string name="confirm_mobile_download_dialog_only_add_to_queue">Legg til i kø</string>
<string name="confirm_mobile_download_dialog_enable_temporarily">Tillat midlertidig</string>
<!--Mediaplayer messages-->
@@ -206,11 +255,15 @@
<string name="player_ready_msg">Klar</string>
<string name="player_seeking_msg">Oppsøker</string>
<string name="playback_error_server_died">Serveren døde</string>
+ <string name="playback_error_unsupported">Ikke støttet media-type</string>
+ <string name="playback_error_timeout">Operasjon tidsavbrutt</string>
+ <string name="playback_error_source">Kunne ikke hente media-fil</string>
<string name="playback_error_unknown">Ukjent feil</string>
<string name="no_media_playing_label">Ingen media spillende for øyeblikket.</string>
<string name="player_buffering_msg">Bufrer</string>
<string name="player_go_to_picture_in_picture">Bilde-i-bilde-modus</string>
<string name="unknown_media_key">AntennaPod - Ukjent medienøkkel: %1$d</string>
+ <string name="error_file_not_found">Fil ikke funnet</string>
<!--Queue operations-->
<string name="lock_queue">Lås køen</string>
<string name="unlock_queue">Lås opp køen</string>
@@ -223,10 +276,13 @@
<string name="move_to_top_label">Gå til toppen</string>
<string name="move_to_bottom_label">Gå til bunnen</string>
<string name="sort">Sortér</string>
+ <string name="keep_sorted">old sortert</string>
<string name="date">På dato</string>
<string name="duration">På varighet</string>
<string name="episode_title">Episodetittel</string>
+ <string name="feed_title">Podkast-tittel</string>
<string name="random">Tilfeldig</string>
+ <string name="smart_shuffle">Smart blanding</string>
<string name="ascending">Økende</string>
<string name="descending">Synkende</string>
<string name="clear_queue_confirmation_msg">Vennligst bekreft at du ønsker å slette ALLE elementer i køen</string>
@@ -234,27 +290,57 @@
<!--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 avspilling med varierende hastighet skal virke, anbefaler vi å bruke den innebygde Sonic-mediespilleren.</string>
<string name="set_playback_speed_label">Avspillingshastigheter</string>
<string name="enable_sonic">Skru på Sonic</string>
<!--Empty list labels-->
+ <string name="no_items_header_label">Ingen episoder i kø</string>
+ <string name="no_items_label">Legg til en episode ved å laste den ned, eller trykk og hold på en episode og velg \"Legg til i køen\".</string>
<string name="no_shownotes_label">Denne episoden har ingen shownotater</string>
+ <string name="no_run_downloads_head_label">Ingen nedlastinger foregår</string>
+ <string name="no_run_downloads_label">Du kan laste ned episoder på en podkasts \"Detaljer\"-meny.</string>
+ <string name="no_comp_downloads_head_label">Ingen nedlastede episoder</string>
+ <string name="no_comp_downloads_label">Du kan laste ned episoder på en podkasts \"Detaljer\"-meny.</string>
+ <string name="no_log_downloads_head_label">Ingen nedlastingshistorikk</string>
+ <string name="no_log_downloads_label">Nedlastingshistorikk vil vises her når den er tilgjengelig.</string>
<string name="no_history_head_label">Ingen Historikk</string>
<string name="no_history_label">Etter at du har hørt på en episode, vil den vises her.</string>
+ <string name="no_all_episodes_head_label">Ingen episoder</string>
+ <string name="no_all_episodes_label">Når du legger til en podkast vil episodene vises her.</string>
+ <string name="no_new_episodes_head_label">Ingen nye episoder</string>
+ <string name="no_new_episodes_label">Når nye episoder kommer, vil de vises her.</string>
+ <string name="no_fav_episodes_head_label">Ingen favoritt-episoder</string>
+ <string name="no_fav_episodes_label">Du kan markere en episode som favoritt ved å trykke og holde på den.</string>
<string name="no_chapters_head_label">Ingen kapitler</string>
<string name="no_chapters_label">Denne episoden har ingen kapitler.</string>
+ <string name="no_subscriptions_head_label">Ingen abonnementer</string>
+ <string name="no_subscriptions_label">Trykk på pluss-ikonet under for å abonnere på en podkast.</string>
<!--Preferences-->
<string name="storage_pref">Lagring</string>
+ <string name="storage_sum">Auto-slett episoder, importer, eksporter</string>
<string name="project_pref">Prosjekt</string>
<string name="queue_label">Kø</string>
+ <string name="automation">Automasjon</string>
<string name="download_pref_details">Detaljer</string>
+ <string name="import_export_pref">Importer/Eksporter</string>
+ <string name="import_export_search_keywords">backup, gjenopprett, lagre</string>
+ <string name="appearance">Utseende</string>
+ <string name="external_elements">Eksterne elementer</string>
+ <string name="interruptions">Forstyrrelser</string>
+ <string name="playback_control">Avspillingskontroll</string>
<string name="preference_search_hint">Søk...</string>
<string name="preference_search_no_results">Ingen resultater</string>
<string name="preference_search_clear_history">Slett logg</string>
+ <string name="media_player">Mediespiller</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 favoritter skal kunne fjernes hvis auto-nedlasting trenger plass til nye episoder</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 over</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Hopp til neste episode i stedet for å spole når \"Fremover\"-knapp trykkes</string>
<string name="pref_hardwarePreviousButtonRestarts_title">Forriv</string>
+ <string name="pref_hardwarePreviousButtonRestarts_sum">Start episoden på nytt i stedet for å spole når \"Tilbake\"-knapp trykkes</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>
@@ -265,8 +351,11 @@
<string name="pref_favorite_keeps_episodes_sum">Behold episoder når de er merket som favoritt</string>
<string name="pref_favorite_keeps_episodes_title">Behold favorittepisoder</string>
<string name="playback_pref">Avspilling</string>
+ <string name="playback_pref_sum">Hodetelefon-kontroller, spole-intervaller, kø</string>
<string name="network_pref">Nettverk</string>
+ <string name="network_pref_sum">Oppdater intervall, styr nedlasting, mobildata</string>
<string name="pref_autoUpdateIntervallOrTime_title">Oppdateringsintervall eller tidspunkt</string>
+ <string name="pref_autoUpdateIntervallOrTime_sum">Velg et intervall eller et klokkeslett å oppdatere podkastene automatisk på</string>
<string name="pref_autoUpdateIntervallOrTime_message">Du kan sette en <i>intervall</i> som «hver andre time», et <i>spesifikt tidspunkt</i> som «07:00» eller <i>skru av</i> automatiske oppdateringer helt.\n\n<small>Merk: Oppdateringstider er ikke eksakte; du kan oppleve små forsinkelser.</small></string>
<string name="pref_autoUpdateIntervallOrTime_Disable">Skru av</string>
<string name="pref_autoUpdateIntervallOrTime_Interval">Sett intervall</string>
@@ -277,14 +366,24 @@
<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_stream_over_download_title">Foretrekk strømming</string>
+ <string name="pref_stream_over_download_sum">Vis strømmeknapp i stedet for nedlastingsknapp i lister.</string>
<string name="pref_mobileUpdate_title">Mobiloppdateringer</string>
+ <string name="pref_mobileUpdate_sum">Velg hva som skal tillates over mobildata</string>
+ <string name="pref_mobileUpdate_refresh">Last podkast på nytt</string>
+ <string name="pref_mobileUpdate_images">Cover-bilder</string>
+ <string name="pref_mobileUpdate_auto_download">Automatisk nedlasting</string>
+ <string name="pref_mobileUpdate_episode_download">Nedlasting av episoder</string>
+ <string name="pref_mobileUpdate_streaming">Strømming</string>
<string name="user_interface_label">Brukergrensesnitt</string>
+ <string name="user_interface_sum">Utseende, rekkefølge på abonnementer, låseskjerm</string>
<string name="pref_set_theme_title">Velg tema</string>
<string name="pref_nav_drawer_items_title">Velg elementer i navigasjonsskuffen</string>
<string name="pref_nav_drawer_items_sum">Endre hvilke elementer som vises i navigeringsfanen.</string>
- <string name="pref_nav_drawer_feed_order_title">Velg rekkefølge på abbonement</string>
+ <string name="pref_nav_drawer_feed_order_title">Velg rekkefølge på abonnementer</string>
<string name="pref_nav_drawer_feed_order_sum">Endre rekkefølgen på abonnementene dine</string>
- <string name="pref_nav_drawer_feed_counter_title">Velg abbonementsteller</string>
+ <string name="pref_nav_drawer_feed_counter_title">Velg abonnementsteller</string>
+ <string name="pref_nav_drawer_feed_counter_sum">Endre informasjonen som vises av abonnement-telleren. Påvirker også sorteringen av abonnementer hvis rekkefølgen er satt til \"Teller\"</string>
<string name="pref_set_theme_sum">Endre utseendet til AntennaPod</string>
<string name="pref_automatic_download_title">Automatisk nedlasting</string>
<string name="pref_automatic_download_sum">Konfigurer automatisk nedlasting av episoder.</string>
@@ -295,8 +394,12 @@
<string name="pref_parallel_downloads_title">Parallelle nedlastinger</string>
<string name="pref_episode_cache_title">Mellomlager for episoder</string>
<string name="pref_episode_cache_summary">Totalt antall nedlastede episoder bufret på enheten. Automatisk nedlasting vil bli stoppet hvis dette nummeret er nådd.</string>
+ <string name="pref_episode_cover_title">Bruk episode-cover</string>
+ <string name="pref_episode_cover_summary">Bruk et episode-spesifikt cover hvis det er tilgjengelig. Hvis dette ikke er valgt vil appen alltid bruke podkastens cover-bilde.</string>
+ <string name="pref_theme_title_use_system">Bruk systemets tema</string>
<string name="pref_theme_title_light">Lyst</string>
<string name="pref_theme_title_dark">Mørkt</string>
+ <string name="pref_theme_title_trueblack">Sort (AMOLED)</string>
<string name="pref_episode_cache_unlimited">Ulimitert</string>
<string name="pref_update_interval_hours_plural">Timer</string>
<string name="pref_update_interval_hours_singular">Time</string>
@@ -307,38 +410,82 @@
<string name="pref_gpodnet_logout_toast">Utloggelse lyktes</string>
<string name="pref_gpodnet_setlogin_information_title">Endre innloggingsinformasjon</string>
<string name="pref_gpodnet_setlogin_information_sum">Endre innlogginsinformasjonen til din gpodder.net konto</string>
- <string name="pref_gpodnet_sync_changes_title">Synkroniser endringer nå</string>
- <string name="pref_gpodnet_full_sync_title">Synkroniser alt nå</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Siste synkroniseringsforsøk: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Synkronisering startet</string>
+ <string name="pref_gpodnet_sync_changes_sum">Synkroniser abonnement og episoder med gpodder.net.</string>
+ <string name="pref_gpodnet_full_sync_sum">Synkroniser alle abonnement og episoder med gpodder.net.</string>
+ <string name="pref_gpodnet_login_status"><![CDATA[Logget inn som <i>%1$s</i> med enhet <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Vis synkroniseringsfeil varsler</string>
<string name="pref_gpodnet_notifications_sum">Denne instillingen gjelder ikke autentiseringfeil.</string>
<string name="pref_playback_speed_title">Avspillingshastigheter</string>
<string name="pref_playback_speed_sum">Egendefiner hastighetene tilgjengelig for variabel avspillingshastighet</string>
+ <string name="pref_feed_playback_speed_sum">Hastigheten som brukes når episoder av denne podkasten spilles av</string>
+ <string name="pref_playback_time_respects_speed_title">Juster media-info til avspillingshastighet</string>
+ <string name="pref_playback_time_respects_speed_sum">Vist posisjon og varighet tilpasses avspillingshastighet</string>
+ <string name="pref_fast_forward">Hopp fremover</string>
+ <string name="pref_fast_forward_sum">Velg hvor mange sekunder som skal hoppes når \"Spol fremover\"-knappen trykkes</string>
+ <string name="pref_rewind">Hopp tilbake</string>
+ <string name="pref_rewind_sum">Velg hvor mange sekunder som skal hoppes tilbake når \"Spol tilbake\"-knappen trykkes</string>
<string name="pref_gpodnet_sethostname_title">Sett vertsnavn</string>
<string name="pref_gpodnet_sethostname_use_default_host">Bruk standard vert</string>
+ <string name="pref_expandNotify_title">Høy varsling-prioritet</string>
+ <string name="pref_expandNotify_sum">Dette utvider som regel varslingen for å vise kontroller.</string>
<string name="pref_persistNotify_title">Vedvarende avspillingskontroller</string>
<string name="pref_persistNotify_sum">Behold varsel- og låseskjermkontroller når avspilling er satt på pause.</string>
<string name="pref_compact_notification_buttons_title">Velg låseskjermsknapper</string>
+ <string name="pref_compact_notification_buttons_sum">Endre kontrollene på låseskjermen. Spill/pause-knappen er alltid inkludert.</string>
+ <string name="pref_compact_notification_buttons_dialog_title">Velg opp til %1$d ting</string>
+ <string name="pref_compact_notification_buttons_dialog_error">Du kan kun velge opp til %1$d ting.</string>
<string name="pref_lockscreen_background_title">Angi som bakgrunn på låseskjermen</string>
<string name="pref_lockscreen_background_sum">Angir låseskjermbakgrunnsbildet til å være den nåværende episodens bilde. Som en sideeffekt vil dette også vise bildet i tredjepartsapper.</string>
<string name="pref_showDownloadReport_title">Vis nedlastingsrapport</string>
<string name="pref_showDownloadReport_sum">Generer en rapport som viser detaljer dersom nedlastinger feiler.</string>
+ <string name="pref_showAutoDownloadReport_title">Vis rapport fra auto-nedlasting</string>
+ <string name="pref_showAutoDownloadReport_sum">Vis en varsling for automatisk nedlastede episoder</string>
<string name="pref_expand_notify_unsupport_toast">Android-versjoner tidligere enn 4.1 støtter ikke utvidede varsler.</string>
+ <string name="pref_enqueue_location_title">Plassering i køen</string>
+ <string name="pref_enqueue_location_sum">Legg episoder til på: %1$s</string>
<string name="enqueue_location_back">Tilbake</string>
+ <string name="enqueue_location_front">Begynnelsen</string>
+ <string name="enqueue_location_after_current">Etter episoden som spilles</string>
<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="visit_user_forum">Bruker-forum</string>
<string name="bug_report_title">Rapporter feil</string>
+ <string name="open_bug_tracker">Åpne bug-tracker</string>
+ <string name="export_logs">Eksporter logg</string>
<string name="copy_to_clipboard">Kopier til utklippstavle</string>
<string name="copied_to_clipboard">Kopiert til utklippstavlen</string>
<string name="experimental_pref">Eksperimentell</string>
+ <string name="pref_media_player_message">Velg hvilken mediespiller som skal brukes for å spille filer</string>
+ <string name="pref_current_value">Valgt: %1$s</string>
+ <string name="pref_proxy_title">Proxy</string>
+ <string name="pref_proxy_sum">Velg en nettverk-proxy</string>
+ <string name="pref_faq">FAQ (Ofte stilte spørsmål)</string>
<string name="pref_no_browser_found">Ingen nettleser funnet.</string>
<string name="pref_cast_title">Chromecast støtte</string>
+ <string name="pref_cast_message_play_flavor">Aktiver støtte for fjern-avspilling på Cast-enheter (som Chromecast, høyttalere eller Android TV)</string>
+ <string name="pref_cast_message_free_flavor">Chromecast krever proprietær tredjeparts programvare som er deaktivert i denne utgaven av AntennaPod</string>
+ <string name="pref_enqueue_downloaded_title">Legg til nedlastede i køen</string>
<string name="pref_enqueue_downloaded_summary">Legg til nedlastede episoder i køen</string>
+ <string name="media_player_builtin">Innebygd Android-spiller</string>
+ <string name="pref_skip_silence_title">Hopp over stillhet</string>
+ <string name="pref_videoBehavior_title">Når video lukkes</string>
+ <string name="pref_videoBehavior_sum">Oppførsel når video-avspilling lukkes</string>
+ <string name="stop_playback">Stopp avspilling</string>
+ <string name="continue_playback">Fortsett lydavspilling</string>
+ <string name="behavior">Oppførsel</string>
+ <string name="pref_back_button_behavior_title">Tilbake-knappens oppførsel</string>
+ <string name="pref_back_button_behavior_sum">Endrer hva tilbake-knappen gjør</string>
<string name="back_button_default">Standard</string>
+ <string name="back_button_open_drawer">Åpne navigasjon-skuffen</string>
+ <string name="back_button_double_tap">Dobbel-trykk for å lukke</string>
+ <string name="back_button_show_prompt">Bekreft for å lukke</string>
+ <string name="close_prompt">Er du sikker på at du vil lukke AntennaPod?</string>
+ <string name="double_tap_toast">Trykk tilbake-knappen igjen for å lukke</string>
<string name="back_button_go_to_page">Gå til side…</string>
<string name="back_button_go_to_page_title">Velg side</string>
+ <string name="pref_delete_removes_from_queue_title">Sletting fjerner fra køen</string>
+ <string name="pref_delete_removes_from_queue_sum">Å slette en episode fjerner den automatisk også fra køen.</string>
<!--About screen-->
<string name="about_pref">Om</string>
<string name="antennapod_version">AntennaPod versjon</string>
@@ -346,14 +493,24 @@
<string name="developers_summary">Alle kan hjelpe til med å gjøre AntennaPod bedre</string>
<string name="translators">Oversettere</string>
<string name="translators_summary">Oversettelser er laget av brukere av AntennaPod ved hjelp av Transifex</string>
+ <string name="privacy_policy">Personvern</string>
<string name="licenses">Lisenser</string>
<string name="licenses_summary">AntennaPod bruker annen flott programvare</string>
<!--Search-->
<string name="search_status_no_results">Ingen resultater ble funnet</string>
<string name="search_label">Søk</string>
<string name="no_results_for_query">Ingen resultalter for \"%1$s\"</string>
+ <!--Synchronization-->
<!--import and export-->
+ <string name="import_export_summary">Overfør abonnementer og kø til en anen enhet</string>
+ <string name="database">Database</string>
+ <string name="opml">OPML</string>
<string name="html">HTML</string>
+ <string name="html_export_summary">Vis abonnementene dine til en venn</string>
+ <string name="opml_export_summary">Overfør abonnementene dine til en annen podkast-app</string>
+ <string name="opml_import_summary">Importer abonnementene dine fra en annen podkast-app</string>
+ <string name="database_export_summary">Overfør abonnementer, avspilte episoder og kø til AntennaPod på en annen enhet</string>
+ <string name="database_import_summary">Importer AntennaPod-database fra en annen enhet</string>
<string name="opml_import_label">OPML-import</string>
<string name="opml_reader_error">En feil oppstod ved lesing av OPML dokument: </string>
<string name="opml_import_error_no_file">Ingen fil er valgt.</string>
@@ -361,15 +518,23 @@
<string name="deselect_all_label">Opphev alle markeringene</string>
<string name="opml_export_label">OPML-eksportering</string>
<string name="html_export_label">HTML eksport</string>
+ <string name="database_export_label">Database-eksportering</string>
+ <string name="database_import_label">Database-importering</string>
<string name="please_wait">Vennligst vent…</string>
<string name="export_error_label">Feil ved eksportering</string>
+ <string name="export_success_title">Eksportering vellykket!</string>
+ <string name="export_success_sum">Den eksporterte filen ble skrevet til:\n\n%1$s</string>
<string name="opml_import_ask_read_permission">Tilgang til ekstern lagring er nødvendig for å lese OPML filen</string>
<string name="import_select_file">Velg fil å importere</string>
+ <string name="import_ok">Importering vellykket!\n\nTrykk OK for å starte AntennaPod på nytt</string>
+ <string name="import_no_downgrade">Denne databasen ble eksportert fra en nyere versjon av AntennaPod. Din versjon av AntennaPod kan ikke lese denne filen enda.</string>
<!--Sleep timer-->
<string name="set_sleeptimer_label">Sett opp sovetimer</string>
<string name="disable_sleeptimer_label">Deaktiver sovetimer</string>
<string name="sleep_timer_label">Sovetimer</string>
<string name="time_dialog_invalid_input">Ugyldig innspill, tid må være et heltall</string>
+ <string name="shake_to_reset_label">Rist for å tilbakestille</string>
+ <string name="timer_vibration_label">Vibrer rett før slutten</string>
<string name="time_seconds">sekunder</string>
<string name="time_minutes">minutter</string>
<string name="time_hours">timer</string>
@@ -389,7 +554,7 @@
<string name="sleep_timer_enabled_label">Sovetimer aktivert</string>
<!--gpodder.net-->
<string name="gpodnet_taglist_header">KATEGORIER</string>
- <string name="gpodnet_toplist_header">TOPP-PODCASTER</string>
+ <string name="gpodnet_toplist_header">TOPP-PODKASTER</string>
<string name="gpodnet_suggestions_header">FORSLAG</string>
<string name="gpodnet_search_hint">Søk på gpodder.net</string>
<string name="gpodnetauth_login_title">Logg inn</string>
@@ -418,12 +583,14 @@
<string name="gpodnetsync_error_descr">En feil oppsto under synkronisering av:\u0020</string>
<string name="gpodnetsync_pref_report_successful">Vellykket</string>
<string name="gpodnetsync_pref_report_failed">Mislyktes</string>
+ <string name="gpodnetsync_username_characters_error">Brukernavn kan kun inneholde bokstaber, tall, bindestrek og understrek</string>
<!--Directory chooser-->
<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="choose_data_directory_permission_rationale">Tilgang til ekstern lagring er nødvendig for å endre data mappe</string>
+ <string name="choose_data_directory_available_space">%1$s av %2$s ledig</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>
@@ -442,6 +609,8 @@
<string name="pref_restart_required">AntennaPod må startes om for at denne endringen skal lagres.</string>
<!--Online feed view-->
<string name="subscribe_label">Abonner</string>
+ <string name="subscribing_label">Abonnerer...</string>
+ <string name="preview_episode">Forhåndsvisning</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Spol tilbake</string>
<string name="fast_forward_label">Spol fremover</string>
@@ -454,18 +623,26 @@
<string name="load_next_page_label">Last inn neste side</string>
<!--Feed information screen-->
<string name="authentication_label">Autentisering</string>
- <string name="authentication_descr">Endre brukernavnet og passordet for denne podcasten og dens episoder.</string>
+ <string name="authentication_descr">Endre brukernavnet og passordet for denne podkasten og dens episoder.</string>
<string name="auto_download_settings_label">Innstillinger for automatisk nedlastning</string>
<string name="episode_filters_label">Episodefilter</string>
+ <string name="episode_filters_description">Nøkkelord som skal brukes for å avgjøre om en episode skal nedlastes automatisk eller ikke</string>
<string name="episode_filters_include">Inkluder</string>
<string name="episode_filters_exclude">Utelukk</string>
+ <string name="episode_filters_hint">Enkelt-ord \n\"Flere ord\"</string>
<string name="keep_updated">Hold oppdatert</string>
+ <string name="keep_updated_summary">Inkluder denne podkasten når alle podkaster oppdateres</string>
+ <string name="auto_download_disabled_globally">Automatisk nedlasting er deaktivert i AntennaPod-innstillingene</string>
<!--Progress information-->
<string name="progress_upgrading_database">Oppgraderer databasen</string>
<!--AntennaPodSP-->
- <string name="sp_apps_importing_feeds_msg">Importerer abbonementer fra enkeltstående applikasjoner ...</string>
+ <string name="sp_apps_importing_feeds_msg">Importerer abonnementer fra enkeltstående applikasjoner...</string>
<!--Add podcast fragment-->
+ <string name="search_podcast_hint">Søk etter podkast...</string>
<string name="search_itunes_label">Søk på iTunes</string>
+ <string name="search_fyyd_label">Søk med fyyd</string>
+ <string name="advanced">Avansert</string>
+ <string name="add_podcast_by_url">Legg til podkast med URL</string>
<string name="browse_gpoddernet_label">Bla gjennom gpodder.net</string>
<string name="discover">Oppdage</string>
<string name="discover_more">mer »</string>
@@ -484,8 +661,11 @@
<string name="not_downloaded_label">Ikke nedlastet</string>
<string name="selected_not_downloaded_label">Valgte ikke-nedlastede episoder</string>
<string name="queued_label">I kø</string>
+ <string name="selected_queued_label">Valgte episoder i køen</string>
<string name="not_queued_label">Ikke i kø</string>
<string name="selected_not_queued_label">Valgte episoder som ikke er i kø</string>
+ <string name="has_media">Har media</string>
+ <string name="selected_has_media_label">Valgte episoder med media</string>
<!--Sort-->
<string name="sort_title_a_z">Tittel (A \u2192 Z)</string>
<string name="sort_title_z_a">Tittel (Z \u2192 A)</string>
@@ -500,6 +680,7 @@
<string name="rating_later_label">Minn meg på dette senere</string>
<string name="rating_now_label">Naturligvis, kom igjen!</string>
<!--Audio controls-->
+ <string name="audio_controls">Lyd-kontroller</string>
<string name="playback_speed">Avspillingshastighet</string>
<string name="volume">Volum</string>
<string name="left_short">V</string>
@@ -507,6 +688,7 @@
<string name="audio_effects">Lydeffekter</string>
<string name="stereo_to_mono">Nedmiksing: Stereo til mono</string>
<string name="sonic_only">Kun Sonic</string>
+ <string name="exoplayer_only">Kun ExoPlayer</string>
<!--proxy settings-->
<string name="proxy_type_label">Type</string>
<string name="host_label">Vert</string>
@@ -520,14 +702,35 @@
<string name="proxy_host_invalid_error">Vert er ikke en gyldig IP adresse eller domene</string>
<string name="proxy_port_invalid_error">Ikke gyldig port</string>
<!--Subscriptions fragment-->
+ <string name="subscription_num_columns">Antall kolonner</string>
<!--Casting-->
<string name="cast_media_route_menu_title">Spill på...</string>
+ <string name="cast_disconnect_label">Koble fra casting</string>
<string name="cast_not_castable">Valgt media er ikke kompatibel med strømmingsenhet</string>
<string name="cast_failed_to_play">Feilet å starte avspilling av media</string>
<string name="cast_failed_to_stop">Feilter å stoppe avspillingen av media</string>
<string name="cast_failed_to_pause">Feilet å pause avspillingen av media</string>
+ <string name="cast_failed_setting_volume">Kunne ikke justere volum</string>
+ <string name="cast_failed_no_connection">Ikke koblet til noen cast-enhet</string>
+ <string name="cast_failed_no_connection_trans">Tilkoblingen til cast-enheten ble tapt. Appen prøver å gjenopprette tilkoblingen, vennligst vent noen sekunder og prøv igjen.</string>
+ <string name="cast_failed_status_request">Kunne ikke synkronisere med cast-enheten</string>
+ <string name="cast_failed_seek">Kunne ikke spole til ny posisjon på cast-enheten</string>
+ <string name="cast_failed_receiver_player_error">En alvorlig feil har oppstått på mottaker-apilleren</string>
+ <string name="cast_failed_media_error_skipping">Feil ved avspilling av media. Hopper over...</string>
<!--Notification channels-->
+ <string name="notification_channel_user_action">Handling kreves</string>
+ <string name="notification_channel_user_action_description">Vises hvis handling kreves, for eksempel hvis et passord må skrives inn.</string>
<string name="notification_channel_downloading">Laster ned</string>
+ <string name="notification_channel_downloading_description">Vises mens nedlasting foregår.</string>
+ <string name="notification_channel_playing">Spilles nå</string>
+ <string name="notification_channel_playing_description">Kan styrre avspilling. Dette er hoved-varslingen du vil se mens en podkast spilles.</string>
<string name="notification_channel_error">Feil</string>
+ <string name="notification_channel_error_description">Vises hvis noe gikk galt, for eksempel hvis en nedlasting eller gpodder-synkronisering ikke kunne fullføres.</string>
+ <string name="notification_channel_auto_download">Automatiske nedlastinger</string>
+ <string name="notification_channel_episode_auto_download">Vises når episoder har blitt lastet ned automatisk</string>
<!--Widget settings-->
+ <string name="widget_settings">Widget-innstillinger</string>
+ <string name="widget_create_button">Opprett widget</string>
+ <string name="widget_opacity">Gjennomsiktighet</string>
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-nl/strings.xml b/core/src/main/res/values-nl/strings.xml
index fdfd48fa4..8ca668dd8 100644
--- a/core/src/main/res/values-nl/strings.xml
+++ b/core/src/main/res/values-nl/strings.xml
@@ -9,7 +9,7 @@
<string name="all_episodes_short_label">Alle</string>
<string name="new_episodes_label">Nieuw</string>
<string name="favorite_episodes_label">Favorieten</string>
- <string name="new_label">Nieuwe</string>
+ <string name="new_label">Nieuw</string>
<string name="settings_label">Instellingen</string>
<string name="downloads_label">Downloads</string>
<string name="downloads_running_label">Bezig</string>
@@ -20,7 +20,6 @@
<string name="cancel_download_label">Download\nafbreken</string>
<string name="playback_history_label">Afspeelgeschiedenis</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Synchroniseren met andere apparaten</string>
<string name="gpodnet_auth_label">Inloggen op gpodder.net</string>
<string name="episode_cache_full_title">Afleveringscache is vol</string>
<string name="episode_cache_full_message">Het maximum aantal gecachete afleveringen is bereikt. Je kunt dit aantal verhogen in de instellingen.</string>
@@ -86,7 +85,7 @@
<string name="auto_download_apply_to_items_message">De instelling voor <i>Automatisch downloaden</i> wordt automatisch toegepast op toekomstige afleveringen.\nWil je deze ook toepassen op eerder gepubliceerde afleveringen?</string>
<string name="auto_delete_label">Aflevering automatisch verwijderen</string>
<string name="feed_volume_reduction">Volumebeperking</string>
- <string name="feed_volume_reduction_summary">Volume beperken van afleveringen uit deze feed: \%s</string>
+ <string name="feed_volume_reduction_summary">Volume verlagen voor afleveringen uit deze feed: %1$s</string>
<string name="feed_volume_reduction_off">Uit</string>
<string name="feed_volume_reduction_light">Gematigd</string>
<string name="feed_volume_reduction_heavy">Aanzienlijk</string>
@@ -106,7 +105,10 @@
<item quantity="one">1 dag na afronden</item>
<item quantity="other">%d dagen na afronden</item>
</plurals>
- <string name="num_selected_label">%d geselecteerd</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">%d geselecteerd</item>
+ <item quantity="other">%d geselecteerd</item>
+ </plurals>
<string name="loading_more">Bezig met laden...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Alles als afgespeeld markeren</string>
@@ -203,6 +205,7 @@
<string name="deactivate_auto_download">Automatisch downloaden uitschakelen</string>
<string name="reset_position">Afspeelpositie herstellen</string>
<string name="removed_item">Item verwijderd</string>
+ <string name="no_items_selected">Geen items geselecteerd</string>
<!--Download messages and labels-->
<string name="download_successful">voltooid</string>
<string name="download_pending">Download staat in de wachtrij</string>
@@ -289,8 +292,6 @@
<string name="ascending">Oplopend</string>
<string name="descending">Aflopend</string>
<string name="clear_queue_confirmation_msg">Bevestig dat je ALLE afleveringen wilt verwijderen uit de wachtrij</string>
- <string name="sort_old_to_new">Oudste eerst</string>
- <string name="sort_new_to_old">Nieuwste eerst</string>
<string name="time_left_label">Resterende tijd:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Plug-in downloaden</string>
@@ -325,8 +326,8 @@
<string name="storage_sum">Automatisch verwijderen, im- en exporteren</string>
<string name="project_pref">Project</string>
<string name="queue_label">Wachtrij</string>
- <string name="integrations_label">Integraties</string>
- <string name="integrations_sum">Synchronisatie</string>
+ <string name="synchronization_pref">Synchronisatie</string>
+ <string name="synchronization_sum">Synchroniseer met andere apparaten met behulp van gpodder.net</string>
<string name="automation">Automatische acties</string>
<string name="download_pref_details">Details</string>
<string name="import_export_pref">Importeren/Exporteren</string>
@@ -417,18 +418,22 @@
<string name="pref_gpodnet_logout_toast">Uitgelogd</string>
<string name="pref_gpodnet_setlogin_information_title">Inloggegevens wijzigen</string>
<string name="pref_gpodnet_setlogin_information_sum">Wijzig de inloggegevens van je gpodder.net-account.</string>
- <string name="pref_gpodnet_sync_changes_title">Wijzigingen nu synchroniseren</string>
+ <string name="pref_gpodnet_sync_changes_title">Nu synchroniseren</string>
<string name="pref_gpodnet_sync_changes_sum">Synchroniseer gewijzigde abonnementen en afleveringsstatussen met gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">Nu alles synchroniseren</string>
+ <string name="pref_gpodnet_full_sync_title">Volledige synchronisatie afdwingen</string>
<string name="pref_gpodnet_full_sync_sum">Synchroniseer alle abonnementen en afleveringsstatussen met gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Vorige synchronisatie: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Synchroniseren gestart</string>
<string name="pref_gpodnet_login_status"><![CDATA[Ingelogd als <i>%1$s</i> met apparaat <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Melding tonen bij synchronisatiefouten</string>
<string name="pref_gpodnet_notifications_sum">Deze instelling is niet van toepassing op inlogfouten.</string>
<string name="pref_playback_speed_title">Afspeelsnelheden</string>
<string name="pref_playback_speed_sum">Pas de beschikbare snelheden aan voor de variabele audio-afspeelsnelheid</string>
<string name="pref_feed_playback_speed_sum">De te gebruiken snelheid bij het afspelen van afleveringen in deze podcast</string>
+ <string name="pref_feed_skip">Automatisch overslaan</string>
+ <string name="pref_feed_skip_sum">Sla introducties en aftitelingen over.</string>
+ <string name="pref_feed_skip_ending">Laatste overslaan</string>
+ <string name="pref_feed_skip_intro">Eerste overslaan</string>
+ <string name="pref_feed_skip_ending_toast">Laatste %d seconden overgeslagen</string>
+ <string name="pref_feed_skip_intro_toast">Eerste %d seconden overgeslagen</string>
<string name="pref_playback_time_respects_speed_title">Media-informatie aanpassen aan afspeelsnelheid</string>
<string name="pref_playback_time_respects_speed_sum">Getoonde positie en duur worden aangepast aan de afspeelsnelheid</string>
<string name="pref_fast_forward">Snelheid van vooruitspoelen</string>
@@ -479,6 +484,8 @@
<string name="pref_enqueue_downloaded_title">Gedownloade afleveringen in wachtrij</string>
<string name="pref_enqueue_downloaded_summary">Voeg gedownloade afleveringen toe aan de wachtrij</string>
<string name="media_player_builtin">Ingebouwde Android-speler</string>
+ <string name="media_player_switch_to_exoplayer">ExoPlayer gebruiken</string>
+ <string name="media_player_switched_to_exoplayer">Overgeschakeld naar ExoPlayer.</string>
<string name="pref_skip_silence_title">Audiostiltes overslaan</string>
<string name="pref_videoBehavior_title">Bij verlaten van video</string>
<string name="pref_videoBehavior_sum">Wat te doen bij het verlaten van een spelende video</string>
@@ -511,6 +518,14 @@
<string name="search_status_no_results">Er zijn geen resultaten gevonden</string>
<string name="search_label">Zoeken</string>
<string name="no_results_for_query">Geen resultaten gevonden voor \"%1$s\"</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">Synchronisatie gestart</string>
+ <string name="sync_status_episodes_upload">Afleveringswijzigingen aan het uploaden…</string>
+ <string name="sync_status_episodes_download">Afleveringswijzigingen aan het downloaden…</string>
+ <string name="sync_status_upload_played">Afspeelstatus aan het uploaden …</string>
+ <string name="sync_status_subscriptions">Abonnementen aan het synchroniseren…</string>
+ <string name="sync_status_success">Synchronisatie afgerond</string>
+ <string name="sync_status_error">Synchronisatie mislukt</string>
<!--import and export-->
<string name="import_export_summary">Abonnementen en wachtrij overzetten naar ander apparaat</string>
<string name="database">Databank</string>
@@ -530,6 +545,7 @@
<string name="html_export_label">HTML exporteren</string>
<string name="database_export_label">Databank exporteren</string>
<string name="database_import_label">Databank importeren</string>
+ <string name="database_import_warning">Als je een databank importeert, dan worden al je huidige abonnementen en afspeelgeschiedenis vervangen. Exporteer ter back-up je huidige databank. Weet je zeker dat je wilt doorgaan?</string>
<string name="please_wait">Even geduld...</string>
<string name="export_error_label">Exportfout</string>
<string name="export_success_title">Geëxporteerd</string>
@@ -621,16 +637,23 @@
<string name="subscribe_label">Abonneren</string>
<string name="subscribing_label">Bezig met abonneren...</string>
<string name="preview_episode">Voorvertoning</string>
+ <string name="stop_preview">Stop voorvertoning</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Terugspoelen</string>
<string name="fast_forward_label">Vooruitspoelen</string>
+ <string name="increase_speed">Verhoog snelheid</string>
+ <string name="decrease_speed">Verlaag snelheid</string>
<string name="media_type_audio_label">Audio</string>
<string name="media_type_video_label">Video</string>
<string name="navigate_upwards_label">Navigeer naar boven</string>
<string name="status_downloading_label">Aflevering wordt gedownload</string>
<string name="in_queue_label">Aflevering staat in de wachtrij</string>
+ <string name="is_favorite_label">Aflevering als favoriet gemarkeerd</string>
<string name="drag_handle_content_description">Versleep dit item om de positie te veranderen</string>
<string name="load_next_page_label">Volgende pagina laden</string>
+ <string name="switch_pages">Van pagina wisselen</string>
+ <string name="position">Positie: %1$s</string>
+ <string name="apply_action">Toepassen</string>
<!--Feed information screen-->
<string name="authentication_label">Authenticatie</string>
<string name="authentication_descr">Gebruikersnaam en wachtwoord wijzigen voor deze podcast en bijbehorende afleveringen.</string>
@@ -656,6 +679,7 @@
<string name="browse_gpoddernet_label">Verken gpodder.net</string>
<string name="discover">Ontdekken</string>
<string name="discover_more">meer »</string>
+ <string name="search_powered_by">Zoeken via %1$s</string>
<string name="filter">Filter</string>
<!--Episodes apply actions-->
<string name="all_label">Alle</string>
@@ -683,6 +707,12 @@
<string name="sort_date_old_new">Datum (oud \u2192 nieuw)</string>
<string name="sort_duration_short_long">Lengte (kort \u2192 lang)</string>
<string name="sort_duration_long_short">Lengte (lang \u2192 kort)</string>
+ <string name="sort_a_z">A \u2192 Z</string>
+ <string name="sort_z_a">Z \u2192 A</string>
+ <string name="sort_new_old">Nieuw \u2192 Oud</string>
+ <string name="sort_old_new">Oud \u2192 Nieuw</string>
+ <string name="sort_short_long">Kort \u2192 Lang</string>
+ <string name="sort_long_short">Lang \u2192 Kort</string>
<!--Rating dialog-->
<string name="rating_title">Wat vind je van AntennaPod?</string>
<string name="rating_message">We stellen het op prijs als je even de tijd neemt om AntennaPod te beoordelen.</string>
@@ -742,4 +772,8 @@
<string name="widget_settings">Widgetinstellingen</string>
<string name="widget_create_button">Widget maken</string>
<string name="widget_opacity">Doorzichtigheid</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">De instelling is aangepast.</string>
+ <string name="on_demand_config_stream_text">Het lijkt er op dat je vaak streamt. Wil je streamknoppen tonen in de lijst met afleveringen?</string>
+ <string name="on_demand_config_download_text">Het lijkt er op dat je vaak dowloadt. Wil je downloadknoppen tonen in de lijst met afleveringen?</string>
</resources>
diff --git a/core/src/main/res/values-pl/strings.xml b/core/src/main/res/values-pl/strings.xml
index 79febb51a..b06ca5fd1 100644
--- a/core/src/main/res/values-pl/strings.xml
+++ b/core/src/main/res/values-pl/strings.xml
@@ -20,7 +20,6 @@
<string name="cancel_download_label">Anuluj pobieranie</string>
<string name="playback_history_label">Historia odtwarzania</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Synchronizuj z innymi urządzeniami</string>
<string name="gpodnet_auth_label">gpodder.net login</string>
<string name="episode_cache_full_title">Pełna pamięć cache</string>
<string name="episode_cache_full_message">Limit pamięci cache został osiągnięty. Możesz zwiększyć pojemność cache w ustawieniach aplikacji.</string>
@@ -86,7 +85,6 @@
<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</string>
<string name="feed_volume_reduction">Redukcja głośności</string>
- <string name="feed_volume_reduction_summary">Zmniejsz głośność odcinków kanału: \%s</string>
<string name="feed_volume_reduction_off">Wyłączona</string>
<string name="feed_volume_reduction_light">Średnia</string>
<string name="feed_volume_reduction_heavy">Silna</string>
@@ -110,7 +108,6 @@
<item quantity="many">%d dni po odtworzeniu</item>
<item quantity="other">%d dni po odtworzeniu</item>
</plurals>
- <string name="num_selected_label">zaznaczono %d</string>
<string name="loading_more">Ładowanie więcej...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Oznacz wszystkie jako odtworzone</string>
@@ -308,8 +305,6 @@
<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>
- <string name="sort_old_to_new">od najstarszych</string>
- <string name="sort_new_to_old">od najnowszych</string>
<string name="time_left_label">Pozostały czas:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Pobierz wtyczkę</string>
@@ -344,8 +339,6 @@
<string name="storage_sum">Automatyczne kasowanie odcinków, Import, Eksport</string>
<string name="project_pref">Projekt</string>
<string name="queue_label">Kolejka</string>
- <string name="integrations_label">Integracje</string>
- <string name="integrations_sum">Synchronizacja</string>
<string name="automation">Automatyzacja</string>
<string name="download_pref_details">Szczegóły</string>
<string name="import_export_pref">Import/Eksport</string>
@@ -436,12 +429,8 @@
<string name="pref_gpodnet_logout_toast">Wylogowanie się powiodło</string>
<string name="pref_gpodnet_setlogin_information_title">Zmień informacje logowania</string>
<string name="pref_gpodnet_setlogin_information_sum">Zmień dane logowania konta gpodder.net.</string>
- <string name="pref_gpodnet_sync_changes_title">Zsynchronizuj zmiany teraz</string>
<string name="pref_gpodnet_sync_changes_sum">Synchronizuj subskrypcje oraz stan odcinków z pomocą gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">Wykonaj pełną synchronizację teraz</string>
<string name="pref_gpodnet_full_sync_sum">Synchronizuj wszystkie subskrypcje oraz stan odcinków z pomocą gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Ostatnia próba synchronizacji: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Synchronizacja uruchomiona</string>
<string name="pref_gpodnet_login_status"><![CDATA[Zalogowano jako <i>%1$s</i> na urządzeniu <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Pokaż powiadomienia błędów synchronizacji</string>
<string name="pref_gpodnet_notifications_sum">To ustawienie nie dotyczy błędów autoryzacji.</string>
@@ -530,6 +519,7 @@
<string name="search_status_no_results">Brak wyników</string>
<string name="search_label">Szukaj</string>
<string name="no_results_for_query">Brak wyników dla \"%1$s\"</string>
+ <!--Synchronization-->
<!--import and export-->
<string name="import_export_summary">Przenieś subskrypcje i kolejkę na inne urządzenie</string>
<string name="database">Baza danych</string>
@@ -768,4 +758,5 @@ https://gpodder.net/register/</string>
<string name="widget_settings">Ustawienia widżetu</string>
<string name="widget_create_button">Dodaj widżet</string>
<string name="widget_opacity">Nieprzezroczystość</string>
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-pt-rBR/strings.xml b/core/src/main/res/values-pt-rBR/strings.xml
index 05bca4bc1..24f89aa4d 100644
--- a/core/src/main/res/values-pt-rBR/strings.xml
+++ b/core/src/main/res/values-pt-rBR/strings.xml
@@ -2,6 +2,7 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--Activity and fragment titles-->
<string name="feed_update_receiver_name">Atualizar Assinaturas</string>
+ <string name="feeds_label">Podcasts</string>
<string name="statistics_label">Estatísticas</string>
<string name="add_feed_label">Adicionar Podcast</string>
<string name="episodes_label">Episódios</string>
@@ -19,10 +20,10 @@
<string name="cancel_download_label">Cancelar\nDownload</string>
<string name="playback_history_label">Histórico de reprodução</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Sincronizar com outros dispositivos</string>
<string name="gpodnet_auth_label">gpodder.net login</string>
<string name="episode_cache_full_title">Cache de episódios cheio</string>
<string name="episode_cache_full_message">O limite de cache de episódios foi alcançado. Você pode aumentar o tamanho do cache em Configurações.</string>
+ <string name="download_statistics_label">Downloads</string>
<!--Statistics fragment-->
<string name="total_time_listened_to_podcasts">Tempo total de podcasts reproduzidos:</string>
<string name="statistics_details_dialog">%1$d de %2$d episódios iniciados.\n\nReproduzidos %3$s de %4$s.</string>
@@ -79,6 +80,8 @@
<string name="auto_download_apply_to_items_title">Aplicar aos episódios anteriores</string>
<string name="auto_download_apply_to_items_message">A nova configuração de <i>Download Automático</i> será aplicada automaticamente a novos episódios.\nVocê deseja aplicá-la aos episódios anteriores?</string>
<string name="auto_delete_label">Apagar episódio automaticamente</string>
+ <string name="feed_volume_reduction_light">Leve</string>
+ <string name="feed_volume_reduction_heavy">Forte</string>
<string name="parallel_downloads_suffix">\u0020 downloads paralelos</string>
<string name="feed_auto_download_global">Padrão global</string>
<string name="feed_auto_download_always">Sempre</string>
@@ -91,11 +94,15 @@
<item quantity="one">1 dia depois de concluído</item>
<item quantity="other">%d dias depois de concluído</item>
</plurals>
+ <string name="loading_more">Carregando...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Marcar todos como reproduzidos</string>
<string name="mark_all_read_msg">Marcar todos Episódios como reproduzidos</string>
<string name="mark_all_read_confirmation_msg">Por favor, confirme que você deseja marcar todos os episódios como já reproduzidos.</string>
<string name="mark_all_read_feed_confirmation_msg">Favor confirmar que deseja marcar todos os episódios nesse podcast como já ouvidos.</string>
+ <string name="remove_all_new_flags_label">Remover todas as etiquetas de \"novo\"</string>
+ <string name="removed_all_new_flags_msg">Todas as etiquetas de \"novo\" foram removidas</string>
+ <string name="remove_all_new_flags_confirmation_msg">Por favor confirme que você deseja remover as etiquetas de \"novo\" de todos os episódios.</string>
<string name="show_info_label">Mostrar informação</string>
<string name="show_feed_settings_label">Exibir configurações do podcast</string>
<string name="feed_info_label">Informações do podcast</string>
@@ -106,11 +113,14 @@
<string name="share_link_label">Compartilhar a URL do episódio</string>
<string name="share_link_with_position_label">Compartilhar a URL do episódio com posição</string>
<string name="share_file_label">Compartilhar arquivo</string>
+ <string name="share_website_url_label">Compartilhar link do site</string>
+ <string name="share_feed_url_label">Compartilhar link do podcast</string>
<string name="share_item_url_label">Compartilhar a URL do arquivo de mídia</string>
<string name="share_item_url_with_position_label">Compartilhar a URL do arquivo de mídia com posição</string>
<string name="feed_delete_confirmation_msg">Confirme se deseja deletar o podcast \"%1$s\" e todos seus episódios (incluindo os baixados).</string>
<string name="feed_remover_msg">Removendo podcast</string>
<string name="load_complete_feed">Atualizar podcast completamente</string>
+ <string name="multi_select">Seleção múltipla</string>
<string name="select_all_above">Selecionar tudo acima</string>
<string name="select_all_below">Selecionar tudo abaixo</string>
<string name="hide_unplayed_episodes_label">Não reproduzido</string>
@@ -141,13 +151,18 @@
<item quantity="one">%d episódio apagado.</item>
<item quantity="other">%d episódios apagados.</item>
</plurals>
+ <string name="remove_new_flag_label">Remover etiqueta de \"novo\"</string>
+ <string name="removed_new_flag_label">Etiqueta de \"novo\" removida</string>
<string name="mark_read_label">Marcar como reproduzido</string>
<string name="marked_as_read_label">Marcado como reproduzido</string>
+ <string name="mark_read_no_media_label">Marcar como reproduzido</string>
+ <string name="marked_as_read_no_media_label">Marcado como reproduzido</string>
<plurals name="marked_read_batch_label">
<item quantity="one">%d episódio marcado como reproduzido.</item>
<item quantity="other">%d episódios marcados como reproduzidos.</item>
</plurals>
<string name="mark_unread_label">Marcar como não reproduzido</string>
+ <string name="mark_unread_label_no_media">Marcar como não reproduzido</string>
<plurals name="marked_unread_batch_label">
<item quantity="one">%d episódio marcado como não reproduzido.</item>
<item quantity="other">%d episódios marcados como não reproduzidos.</item>
@@ -173,6 +188,7 @@
<string name="deactivate_auto_download">Desativar download automático</string>
<string name="reset_position">Resetar a Posição da Reprodução</string>
<string name="removed_item">Item removido</string>
+ <string name="no_items_selected">Nenhum item selecionado</string>
<!--Download messages and labels-->
<string name="download_successful">com sucesso</string>
<string name="download_pending">Download pendente</string>
@@ -214,6 +230,7 @@
<string name="confirm_mobile_download_dialog_title">Confirmar Download utilizando dados móveis</string>
<string name="confirm_mobile_download_dialog_message_not_in_queue">O download utilizando plano de dados foi desabilitado nas configurações.\n\nVocê pode escolher entre apenas adicionar o episódio na fila ou você pode permitir o download temporáriamente.\n\n<small>Sua escolha será lembrada por 10 minutos.</small></string>
<string name="confirm_mobile_download_dialog_message">O download sobre plano de dados foi desabilitado nas configurações.\n\n Você deseja permitir o download temporáriamente?\n\n<small>Sua escolha será lembrada por 10 minutos</small></string>
+ <string name="confirm_mobile_streaming_button_always">Sempre permitir</string>
<string name="confirm_mobile_download_dialog_only_add_to_queue">Adicionar à fila</string>
<string name="confirm_mobile_download_dialog_enable_temporarily">Permitir temporariamente</string>
<!--Mediaplayer messages-->
@@ -228,16 +245,19 @@
<string name="player_buffering_msg">Armazenando</string>
<string name="player_go_to_picture_in_picture">Modo PIP</string>
<string name="unknown_media_key">AntennaPod - Chave de mídia desconhecida: %1$d</string>
+ <string name="error_file_not_found">Arquivo não encontrado</string>
<!--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="checkbox_do_not_show_again">Não mostrar novamente</string>
<string name="clear_queue_label">Limpar fila</string>
<string name="undo">Desfazer</string>
<string name="move_to_top_label">Mover para o topo</string>
<string name="move_to_bottom_label">Mover para o fim</string>
<string name="sort">Ordenar</string>
+ <string name="keep_sorted">Manter ordenação</string>
<string name="date">Data</string>
<string name="duration">Duração</string>
<string name="episode_title">Titulo do Episodio</string>
@@ -254,13 +274,13 @@
<string name="set_playback_speed_label">Velocidades de Reprodução</string>
<string name="enable_sonic">Habilitar Sonic</string>
<!--Empty list labels-->
+ <string name="no_items_header_label">Nenhum episódio na fila</string>
<string name="no_shownotes_label">Este episódio não possui notas.</string>
<string name="no_chapters_label">Este episódio não possui capítulos</string>
<!--Preferences-->
<string name="storage_pref">Armazenamento</string>
<string name="project_pref">Projeto</string>
<string name="queue_label">Fila</string>
- <string name="integrations_label">Integrações</string>
<string name="automation">Automação</string>
<string name="download_pref_details">Detalhes</string>
<string name="import_export_pref">Importar/Exportar</string>
@@ -330,12 +350,8 @@
<string name="pref_gpodnet_logout_toast">Saiu com sucesso</string>
<string name="pref_gpodnet_setlogin_information_title">Alterar informações de login</string>
<string name="pref_gpodnet_setlogin_information_sum">Alterar informações de login da sua conta gpodder.net</string>
- <string name="pref_gpodnet_sync_changes_title">Sincronizar alterações agora</string>
<string name="pref_gpodnet_sync_changes_sum">Sincronizar as alterações de estado da inscrição e de episódios com o gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">Sincronização total agora</string>
<string name="pref_gpodnet_full_sync_sum">Sincronizar os estados das inscrições e episódios com o gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Última tentativa de sincronização: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Sincronização iniciada</string>
<string name="pref_gpodnet_login_status"><![CDATA[Entrou como <i>%1$s</i> com o dispositivo <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Exibir notificações de erros de sincronismo</string>
<string name="pref_gpodnet_notifications_sum">Essa configuração não se aplica a erros de autenticação.</string>
@@ -397,6 +413,7 @@
<string name="search_status_no_results">Nenhum resultado encontrado</string>
<string name="search_label">Pesquisar</string>
<string name="no_results_for_query">Nenhum resultado para \"%1$s\"</string>
+ <!--Synchronization-->
<!--import and export-->
<string name="opml_import_label">Importação de OPML</string>
<string name="opml_reader_error">Um erro ocorreu ao ler o documento OPML:</string>
@@ -572,6 +589,7 @@
<string name="proxy_host_invalid_error">Host não possui um endereço de IP ou domínio válidos</string>
<string name="proxy_port_invalid_error">Porta inválida</string>
<!--Subscriptions fragment-->
+ <string name="subscription_num_columns">Número de colunas</string>
<!--Casting-->
<string name="cast_media_route_menu_title">Reproduzir em...</string>
<string name="cast_disconnect_label">Desconectar a sessão do cast</string>
@@ -596,4 +614,6 @@
<string name="notification_channel_error">Erros</string>
<string name="notification_channel_error_description">Exibido caso algo dê errado, por exemplo se houver falha no download ou na sincronização com o gpodder.</string>
<!--Widget settings-->
+ <string name="widget_opacity">Opacidade</string>
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-pt/strings.xml b/core/src/main/res/values-pt/strings.xml
index 565426529..375fa5426 100644
--- a/core/src/main/res/values-pt/strings.xml
+++ b/core/src/main/res/values-pt/strings.xml
@@ -20,7 +20,6 @@
<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_summary">Sincronizar com outros dispositivos.</string>
<string name="gpodnet_auth_label">Dados gpodder.net</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>
@@ -86,7 +85,7 @@
<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">Eliminar episódio automaticamente</string>
<string name="feed_volume_reduction">Redução de volume</string>
- <string name="feed_volume_reduction_summary">Reduzir volume para os episódios desta fonte: \%s</string>
+ <string name="feed_volume_reduction_summary">Diminuir volume para os episódios desta fonte: %1$s</string>
<string name="feed_volume_reduction_off">Desligada</string>
<string name="feed_volume_reduction_light">Ligeira</string>
<string name="feed_volume_reduction_heavy">Intensa</string>
@@ -106,7 +105,10 @@
<item quantity="one">1 dia depois de terminar</item>
<item quantity="other">%d dias depois de terminar</item>
</plurals>
- <string name="num_selected_label">%d selecionado</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">%d selecionado</item>
+ <item quantity="other">%d selecionados</item>
+ </plurals>
<string name="loading_more">Carregar mais...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Marcar tudo como reproduzido</string>
@@ -203,6 +205,7 @@
<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>
+ <string name="no_items_selected">Nada selecionado</string>
<!--Download messages and labels-->
<string name="download_successful">sucesso</string>
<string name="download_pending">Descarga pendente</string>
@@ -289,8 +292,6 @@
<string name="ascending">Crescente</string>
<string name="descending">Decrescente</string>
<string name="clear_queue_confirmation_msg">Tem a certeza de que deseja remover todos os episódios da fila de reprodução?</string>
- <string name="sort_old_to_new">Antigo para novo</string>
- <string name="sort_new_to_old">Novo para antigo</string>
<string name="time_left_label">Tempo restante:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Descarregar extra</string>
@@ -325,8 +326,8 @@
<string name="storage_sum">Eliminação automática, importação e exportação</string>
<string name="project_pref">Projeto</string>
<string name="queue_label">Fila</string>
- <string name="integrations_label">Integrações</string>
- <string name="integrations_sum">Sincronização</string>
+ <string name="synchronization_pref">Sincronização</string>
+ <string name="synchronization_sum">Sincronizar com outros dispositivos via gpodder.net</string>
<string name="automation">Automatização</string>
<string name="download_pref_details">Detalhes</string>
<string name="import_export_pref">Importar/Exportar</string>
@@ -417,18 +418,22 @@
<string name="pref_gpodnet_logout_toast">Sessão terminada</string>
<string name="pref_gpodnet_setlogin_information_title">Alterar informação de acesso</string>
<string name="pref_gpodnet_setlogin_information_sum">Alterar a informação de acesso à sua conta gpodder.net</string>
- <string name="pref_gpodnet_sync_changes_title">Sincronizar alterações</string>
+ <string name="pref_gpodnet_sync_changes_title">Sincronizar agora</string>
<string name="pref_gpodnet_sync_changes_sum">Sincronizar subscrição e estado do episódio com o gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">Sincronização total</string>
+ <string name="pref_gpodnet_full_sync_title">Impor sincronização total</string>
<string name="pref_gpodnet_full_sync_sum">Sincronizar todas as subscrições e estados dos episódios com o gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Última tentativa de sincronização: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Sincronização iniciada</string>
<string name="pref_gpodnet_login_status"><![CDATA[Sessão iniciada como <i>%1$s</i> com o dispositivo <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Mostrar erros de sincronização</string>
<string name="pref_gpodnet_notifications_sum">Esta definição não é aplicável aos erros de autenticação.</string>
<string name="pref_playback_speed_title">Velocidades de reprodução</string>
<string name="pref_playback_speed_sum">Personalizar as velocidades de reprodução disponíveis.</string>
<string name="pref_feed_playback_speed_sum">Velocidade utilizada para a reprodução áudio dos episódios deste podcast</string>
+ <string name="pref_feed_skip">Ignorar automaticamente</string>
+ <string name="pref_feed_skip_sum">Ignorar introduções e créditos finais.</string>
+ <string name="pref_feed_skip_ending">Ignorar os últimos</string>
+ <string name="pref_feed_skip_intro">Ignorar os primeiros</string>
+ <string name="pref_feed_skip_ending_toast">Últimos %d segundos ignorados</string>
+ <string name="pref_feed_skip_intro_toast">Primeiros %d segundos ignorados</string>
<string name="pref_playback_time_respects_speed_title">Ajustar informações multimédia à velocidade de reprodução</string>
<string name="pref_playback_time_respects_speed_sum">A posição e a duração serão ajustadas automaticamente à velocidade de reprodução.</string>
<string name="pref_fast_forward">Tempo a avançar</string>
@@ -479,6 +484,8 @@
<string name="pref_enqueue_downloaded_title">Colocar descargas na fila</string>
<string name="pref_enqueue_downloaded_summary">Adicionar à fila os episódios descarregados.</string>
<string name="media_player_builtin">Reprodutor nativo Android</string>
+ <string name="media_player_switch_to_exoplayer">Trocar para ExoPlayer</string>
+ <string name="media_player_switched_to_exoplayer">Trocou para ExoPlayer.</string>
<string name="pref_skip_silence_title">Ignorar silêncio no áudio</string>
<string name="pref_videoBehavior_title">Ao sair do vídeo</string>
<string name="pref_videoBehavior_sum">Comportamento ao sair da reprodução do vídeo.</string>
@@ -511,6 +518,14 @@
<string name="search_status_no_results">Nenhum resultado</string>
<string name="search_label">Pesquisar</string>
<string name="no_results_for_query">Não existem resultados para \"%1$s\"</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">Sincronização iniciada</string>
+ <string name="sync_status_episodes_upload">Atualizar alterações nos episódios...</string>
+ <string name="sync_status_episodes_download">Descarregar alterações nos episódios...</string>
+ <string name="sync_status_upload_played">Carregar estado de reprodução...</string>
+ <string name="sync_status_subscriptions">Sincronizar subscrições...</string>
+ <string name="sync_status_success">Sincronização bem sucedida</string>
+ <string name="sync_status_error">Falha na sincronização</string>
<!--import and export-->
<string name="import_export_summary">Mover subscrições e fila de reprodução para outro dispositivo</string>
<string name="database">Base de dados</string>
@@ -530,6 +545,7 @@
<string name="html_export_label">Exportação HTML</string>
<string name="database_export_label">Exportar base de dados</string>
<string name="database_import_label">Importar base de dados</string>
+ <string name="database_import_warning">A importação de uma base de dados substitui as subscrições atuais e o histórico de reprodução. Deve efetuar um backup da base de dados atual. Substituir?</string>
<string name="please_wait">Aguarde um pouco...</string>
<string name="export_error_label">Erro de exportação</string>
<string name="export_success_title">Exportação com sucesso</string>
@@ -621,16 +637,23 @@
<string name="subscribe_label">Subscrever</string>
<string name="subscribing_label">Subscrição em curso...</string>
<string name="preview_episode">Antevisão</string>
+ <string name="stop_preview">Parar pré-visualização</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Recuo rápido</string>
<string name="fast_forward_label">Avanço rápido</string>
+ <string name="increase_speed">Aumentar velocidade</string>
+ <string name="decrease_speed">Diminuir velocidade</string>
<string name="media_type_audio_label">Áudio</string>
<string name="media_type_video_label">Vídeo</string>
<string name="navigate_upwards_label">Navegar para cima</string>
<string name="status_downloading_label">A descarregar episódio</string>
<string name="in_queue_label">Episódio está na fila</string>
+ <string name="is_favorite_label">Episódio marcado como favorito</string>
<string name="drag_handle_content_description">Arraste para alterar a posição deste item</string>
<string name="load_next_page_label">Carregar próxima página</string>
+ <string name="switch_pages">Trocar de páginas</string>
+ <string name="position">Posição: %1$s</string>
+ <string name="apply_action">Aplicar ação</string>
<!--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>
@@ -656,6 +679,7 @@
<string name="browse_gpoddernet_label">Procurar no gPodder.net</string>
<string name="discover">Descobrir</string>
<string name="discover_more">mais »</string>
+ <string name="search_powered_by">Disponibilizado por %1$s</string>
<string name="filter">Filtro</string>
<!--Episodes apply actions-->
<string name="all_label">Todos</string>
@@ -683,6 +707,12 @@
<string name="sort_date_old_new">Data (Antiga \u2192 Recente)</string>
<string name="sort_duration_short_long">Duração (Curta \u2192 Longa)</string>
<string name="sort_duration_long_short">Duração (Longa \u2192 Curta)</string>
+ <string name="sort_a_z">A \u2192 Z</string>
+ <string name="sort_z_a">Z \u2192 A</string>
+ <string name="sort_new_old">Novo \u2192 Antigo</string>
+ <string name="sort_old_new">Antigo \u2192 Novo</string>
+ <string name="sort_short_long">Curto \u2192 Longo</string>
+ <string name="sort_long_short">Longo \u2192 Curto</string>
<!--Rating dialog-->
<string name="rating_title">Gosta do AntennaPod?</string>
<string name="rating_message">Gostaríamos que dispensasse algum tempo para avaliar o AntennaPod.</string>
@@ -742,4 +772,8 @@
<string name="widget_settings">Definições do widget</string>
<string name="widget_create_button">Criar widget</string>
<string name="widget_opacity">Opacidade</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">Definições atualizadas com sucesso.</string>
+ <string name="on_demand_config_stream_text">Parece que você prefere as emissões. Deseja que a lista de episódios mostre os botões adequados?</string>
+ <string name="on_demand_config_download_text">Parece que você prefere as descargas. Deseja que a lista de episódios mostre os botões adequados?</string>
</resources>
diff --git a/core/src/main/res/values-ru/strings.xml b/core/src/main/res/values-ru/strings.xml
index 607a331cf..fc01e6bad 100644
--- a/core/src/main/res/values-ru/strings.xml
+++ b/core/src/main/res/values-ru/strings.xml
@@ -20,7 +20,6 @@
<string name="cancel_download_label">Отменить загрузку</string>
<string name="playback_history_label">Архив</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Синхронизация с другими устройствами</string>
<string name="gpodnet_auth_label">Войти на gpodder.net</string>
<string name="episode_cache_full_title">Кэш выпусков заполнен</string>
<string name="episode_cache_full_message">Достигнут предел кэша выпусков. Объём кэша можно увеличить в Настройках.</string>
@@ -86,7 +85,6 @@
<string name="auto_download_apply_to_items_message">Новые настройки <i>Автозагрузки</i> будут автоматически применены к новым выпускам. \nХотите ли вы применить их к ранее опубликованным выпускам?</string>
<string name="auto_delete_label">Автоматически удалить выпуск</string>
<string name="feed_volume_reduction">Уменьшение громкости</string>
- <string name="feed_volume_reduction_summary">Уменьшать громкость выпусков этого канала: \%s</string>
<string name="feed_volume_reduction_off">Выключено</string>
<string name="feed_volume_reduction_light">Слабое</string>
<string name="feed_volume_reduction_heavy">Сильное</string>
@@ -110,7 +108,6 @@
<item quantity="many">%d дней после прослушивания</item>
<item quantity="other">%d дней после прослушивания</item>
</plurals>
- <string name="num_selected_label">выбрано: %d</string>
<string name="loading_more">Загружается...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Отметить как прослушанное</string>
@@ -134,7 +131,7 @@
<string name="share_feed_url_label">Поделиться ссылкой на канал</string>
<string name="share_item_url_label">Поделиться ссылкой на файл</string>
<string name="share_item_url_with_position_label">Поделиться ссылкой на файл с отметкой времени</string>
- <string name="feed_delete_confirmation_msg">Подтвердите, что хотите удалить подкаст «%1$s» и все его эпизоды (включая загруженные).</string>
+ <string name="feed_delete_confirmation_msg">Подтвердите, что хотите удалить подкаст «%1$s» и все его выпуски (включая загруженные).</string>
<string name="feed_remover_msg">Подкаст удаляется</string>
<string name="load_complete_feed">Обновить весь подкаст</string>
<string name="multi_select">Множественный выбор</string>
@@ -307,8 +304,6 @@
<string name="ascending">По возрастанию</string>
<string name="descending">По убыванию</string>
<string name="clear_queue_confirmation_msg">Подтвердите, что хотите удалить из очереди все выпуски.</string>
- <string name="sort_old_to_new">От старых к новым</string>
- <string name="sort_new_to_old">От новых к старым</string>
<string name="time_left_label">Осталось времени:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Загрузить плагин</string>
@@ -317,7 +312,7 @@
<string name="set_playback_speed_label">Скорость воспроизведения</string>
<string name="enable_sonic">Включить Sonic</string>
<!--Empty list labels-->
- <string name="no_items_header_label">Нет эпизодов в очереди</string>
+ <string name="no_items_header_label">Нет выпусков в очереди</string>
<string name="no_items_label">Добавьте выпуск, загрузив его, или после долгого нажатия на выпуск выберите «Добавить в очередь».</string>
<string name="no_shownotes_label">Этот выпуск не содержит примечаний.</string>
<string name="no_run_downloads_head_label">Нет запущенных загрузок</string>
@@ -343,12 +338,11 @@
<string name="storage_sum">Автоматическое удаление выпусков, импорт, экспорт</string>
<string name="project_pref">Проект</string>
<string name="queue_label">Очередь</string>
- <string name="integrations_label">Интеграция</string>
- <string name="integrations_sum">Синхронизация</string>
+ <string name="synchronization_pref">Синхронизация</string>
<string name="automation">Автоматизация</string>
<string name="download_pref_details">Подробнее</string>
<string name="import_export_pref">Импорт/экспорт</string>
- <string name="import_export_search_keywords">резервирование, восстановление, сохранить, копия, бэкап, пропал</string>
+ <string name="import_export_search_keywords">резервирование, восстановление, резервная, копия, бекап, бэкап</string>
<string name="appearance">Внешний вид</string>
<string name="external_elements">Внешние органы управления</string>
<string name="interruptions">Прерывания</string>
@@ -367,7 +361,7 @@
<string name="pref_hardwarePreviousButtonRestarts_title">В начало кнопкой перемотки назад</string>
<string name="pref_hardwarePreviousButtonRestarts_sum">При нажатии на физическую кнопку перемотки назад переходить к началу выпуска вместо перемотки назад</string>
<string name="pref_followQueue_sum">После завершения воспроизведения перейти к следующему в очереди</string>
- <string name="pref_auto_delete_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>
@@ -435,18 +429,15 @@
<string name="pref_gpodnet_logout_toast">Выход произведён успешно</string>
<string name="pref_gpodnet_setlogin_information_title">Изменить информацию авторизации</string>
<string name="pref_gpodnet_setlogin_information_sum">Изменить информацию авторизации для аккаунта gpodder.net</string>
- <string name="pref_gpodnet_sync_changes_title">Синхронизировать изменения</string>
<string name="pref_gpodnet_sync_changes_sum">Синхронизировать изменения подписок и выпусков при помощи gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">Синхронизировать полностью</string>
<string name="pref_gpodnet_full_sync_sum">Синхронизировать состояния всех подписок и выпусков при помощи gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Предыдущая попытка синхронизации: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Синхронизация запущена</string>
<string name="pref_gpodnet_login_status"><![CDATA[Вход как <i>%1$s</i> с устройства <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Показывать уведомления об ошибках синхронизации</string>
<string name="pref_gpodnet_notifications_sum">Не затрагивает ошибки авторизации.</string>
<string name="pref_playback_speed_title">Скорости воспроизведения</string>
<string name="pref_playback_speed_sum">Выбрать значения скорости, доступные при воспроизведении</string>
<string name="pref_feed_playback_speed_sum">Скорость, с которой будут изначально воспроизводиться выпуски этого подкаста</string>
+ <string name="pref_feed_skip_intro_toast">Пропусить первые %d секунд</string>
<string name="pref_playback_time_respects_speed_title">Подстройка метаданных под скорость воспроизведения</string>
<string name="pref_playback_time_respects_speed_sum">Значения позиции и длительности зависят от скорости воспроизведения</string>
<string name="pref_fast_forward">Интервал быстрой перемотки вперед</string>
@@ -468,7 +459,7 @@
<string name="pref_showDownloadReport_title">Показывать отчёт о загрузках</string>
<string name="pref_showDownloadReport_sum">Если загрузка не удаётся, показывать отчёт с подробностями об ошибке.</string>
<string name="pref_showAutoDownloadReport_title">Показывать результаты автозагрузки</string>
- <string name="pref_showAutoDownloadReport_sum">Показывать уведомление при автоматической загрузке эпизодов.</string>
+ <string name="pref_showAutoDownloadReport_sum">Показывать уведомление при автоматической загрузке выпусков</string>
<string name="pref_expand_notify_unsupport_toast">Версии Android ниже 4.1 не поддерживают расширенные уведомления.</string>
<string name="pref_enqueue_location_title">Размещение в очереди</string>
<string name="pref_enqueue_location_sum">Добавлять выпуски %1$s</string>
@@ -476,8 +467,8 @@
<string name="enqueue_location_front">в начало</string>
<string name="enqueue_location_after_current">за текущим выпуском</string>
<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="pref_image_cache_size_title">Размер кеша изображений</string>
+ <string name="pref_image_cache_size_sum">Размер дискового кеша изображений</string>
<string name="visit_user_forum">Форум пользователей</string>
<string name="bug_report_title">Сообщить об ошибке</string>
<string name="open_bug_tracker">Перейти в систему отслеживания ошибок</string>
@@ -510,7 +501,7 @@
<string name="back_button_double_tap">Выход двойным касанием</string>
<string name="back_button_show_prompt">Подтверджение выхода</string>
<string name="close_prompt">Уверены, что хотите закрыть AntennaPod?</string>
- <string name="double_tap_toast">Нажмите кнопку \"Назад\" еще раз, чтобы выйти</string>
+ <string name="double_tap_toast">Нажмите кнопку «Назад» ещё раз, чтобы выйти</string>
<string name="back_button_go_to_page">Перейти к странице…</string>
<string name="back_button_go_to_page_title">Выберите страницу</string>
<string name="pref_delete_removes_from_queue_title">Убирать удаленные из очереди</string>
@@ -529,6 +520,9 @@
<string name="search_status_no_results">Ничего не найдено</string>
<string name="search_label">Поиск</string>
<string name="no_results_for_query">По запросу «%1$s» ничего не найдено</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">Синхронизация запущена</string>
+ <string name="sync_status_subscriptions">Синхронизация подписок ...</string>
<!--import and export-->
<string name="import_export_summary">Перенести подписку и очередь на другое устройство</string>
<string name="database">База данных</string>
@@ -650,11 +644,14 @@
<!--Content descriptions for image buttons-->
<string name="rewind_label">Назад</string>
<string name="fast_forward_label">Вперёд</string>
+ <string name="increase_speed">Увеличить скорость</string>
+ <string name="decrease_speed">Уменьшить скорость</string>
<string name="media_type_audio_label">Аудио</string>
<string name="media_type_video_label">Видео</string>
<string name="navigate_upwards_label">Перейти выше</string>
<string name="status_downloading_label">Выпуск загружается</string>
<string name="in_queue_label">Выпуск в очереди</string>
+ <string name="is_favorite_label">Эпизод отмечен как избранный</string>
<string name="drag_handle_content_description">Перетяните чтобы изменить позицию этого элемента</string>
<string name="load_next_page_label">Загрузить следующую страницу</string>
<!--Feed information screen-->
@@ -768,4 +765,6 @@
<string name="widget_settings">Настройки виджета</string>
<string name="widget_create_button">Создать виджет</string>
<string name="widget_opacity">Непрозрачность</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">Настройки успешно обновлены.</string>
</resources>
diff --git a/core/src/main/res/values-sv/strings.xml b/core/src/main/res/values-sv/strings.xml
index ed17da956..f5d85e18c 100644
--- a/core/src/main/res/values-sv/strings.xml
+++ b/core/src/main/res/values-sv/strings.xml
@@ -20,7 +20,6 @@
<string name="cancel_download_label">Avbryt\nNedladdning</string>
<string name="playback_history_label">Uppspelningshistorik</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Synkronisera med andra enheter</string>
<string name="gpodnet_auth_label">Inloggning till gpodder.net</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>
@@ -86,7 +85,7 @@
<string name="auto_download_apply_to_items_message">Den nya inställningen <i>Automatisk nedladdning</i> kommer automatiskt att appliceras på nya episoder.\nVill du även applicera det på tidigare publicerade episoder?</string>
<string name="auto_delete_label">Automatisk episodborttagning</string>
<string name="feed_volume_reduction">Volymreducering</string>
- <string name="feed_volume_reduction_summary">Sänk volymen för episoder från detta flöde: \1%s</string>
+ <string name="feed_volume_reduction_summary">Sänk volymen för episoder i detta flöde: %1$s</string>
<string name="feed_volume_reduction_off">Av</string>
<string name="feed_volume_reduction_light">Lätt</string>
<string name="feed_volume_reduction_heavy">Tungt</string>
@@ -106,7 +105,10 @@
<item quantity="one">1 dag efter färdigspelad</item>
<item quantity="other">%d dagar efter färdigspelad</item>
</plurals>
- <string name="num_selected_label">1%d valda</string>
+ <plurals name="num_selected_label">
+ <item quantity="one">%d vald</item>
+ <item quantity="other">%d vald</item>
+ </plurals>
<string name="loading_more">Laddar mer...</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Markera alla som spelade</string>
@@ -203,6 +205,7 @@
<string name="deactivate_auto_download">Avaktivera automatisk nedladdning</string>
<string name="reset_position">Nollställ uppspelningspositionen</string>
<string name="removed_item">Borttagen</string>
+ <string name="no_items_selected">Inget valt</string>
<!--Download messages and labels-->
<string name="download_successful">lyckades</string>
<string name="download_pending">Avvaktar nedladdning</string>
@@ -289,8 +292,6 @@
<string name="ascending">Stigande</string>
<string name="descending">Fallande</string>
<string name="clear_queue_confirmation_msg">Bekräfta att du vill rensa kön från ALLA episoder.</string>
- <string name="sort_old_to_new">Gammal till ny</string>
- <string name="sort_new_to_old">Ny till gammal</string>
<string name="time_left_label">Återstående tid:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Ladda ner tillägg</string>
@@ -325,8 +326,8 @@
<string name="storage_sum">Automatisk episodradering, Import, Export</string>
<string name="project_pref">Projekt</string>
<string name="queue_label">Kö</string>
- <string name="integrations_label">Integrationer</string>
- <string name="integrations_sum">Synkronisering</string>
+ <string name="synchronization_pref">Synkronisering</string>
+ <string name="synchronization_sum">Synkronisera med andra enheter via gpodder.net</string>
<string name="automation">Automatisering</string>
<string name="download_pref_details">Detaljer</string>
<string name="import_export_pref">Importera/Exportera</string>
@@ -417,18 +418,22 @@
<string name="pref_gpodnet_logout_toast">Utloggning lyckades</string>
<string name="pref_gpodnet_setlogin_information_title">Ändra inloggningsinformation</string>
<string name="pref_gpodnet_setlogin_information_sum">Ändra inloggningsinformationen för ditt gpodder.net konto.</string>
- <string name="pref_gpodnet_sync_changes_title">Synkronisera ändringar nu</string>
+ <string name="pref_gpodnet_sync_changes_title">Synkronisera nu</string>
<string name="pref_gpodnet_sync_changes_sum">Synkronisera ändringar i prenumerationer och episodstatus med gpodder.net.</string>
- <string name="pref_gpodnet_full_sync_title">Full synkronisering nu</string>
+ <string name="pref_gpodnet_full_sync_title">Tvinga full synkronisering</string>
<string name="pref_gpodnet_full_sync_sum">Synkronisera alla prenumerationer och episodstatus med gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Senaste synkroniseringsförsök: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Synkronisering startad</string>
<string name="pref_gpodnet_login_status"><![CDATA[Inloggad som <i>%1$s</i> med enhet <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Visa notifieringar om synkroniseringsfel</string>
<string name="pref_gpodnet_notifications_sum">Denna inställning påverkar inte autentiseringsfel.</string>
<string name="pref_playback_speed_title">Uppspelningshastigheter</string>
<string name="pref_playback_speed_sum">Anpassa de tillgängliga hastigheterna för variabel uppspelningshastighet.</string>
<string name="pref_feed_playback_speed_sum">Uppspelningshastigheten att använda för episoder i denna podcast</string>
+ <string name="pref_feed_skip">Automatisk överhoppning</string>
+ <string name="pref_feed_skip_sum">Hoppa över intron och outron.</string>
+ <string name="pref_feed_skip_ending">Hoppa över slut</string>
+ <string name="pref_feed_skip_intro">Hoppa över början</string>
+ <string name="pref_feed_skip_ending_toast">Hoppade över %d sista sekunderna</string>
+ <string name="pref_feed_skip_intro_toast">Hoppade över %d första sekunderna</string>
<string name="pref_playback_time_respects_speed_title">Justera mediainfo till uppspelningshastigheten</string>
<string name="pref_playback_time_respects_speed_sum">Visad position och totallängd anpassas till uppspelningshastigheten</string>
<string name="pref_fast_forward">Snabbspolningslängd</string>
@@ -479,6 +484,8 @@
<string name="pref_enqueue_downloaded_title">Köa Nedladdade</string>
<string name="pref_enqueue_downloaded_summary">Lägg nedladdade episoder i uppspelningskön</string>
<string name="media_player_builtin">Andriods inbyggda spelare</string>
+ <string name="media_player_switch_to_exoplayer">Byt till ExoPlayer</string>
+ <string name="media_player_switched_to_exoplayer">Bytte till ExpPlayer.</string>
<string name="pref_skip_silence_title">Hoppa över tystnad i ljud</string>
<string name="pref_videoBehavior_title">Vid avslutande av video</string>
<string name="pref_videoBehavior_sum">Beteende när videouppspelning avslutas</string>
@@ -511,6 +518,14 @@
<string name="search_status_no_results">Inga resultat hittades</string>
<string name="search_label">Sök</string>
<string name="no_results_for_query">Inga resultat hittades för \"%1$s\"</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">Synkning startad</string>
+ <string name="sync_status_episodes_upload">Laddar upp episodändringar...</string>
+ <string name="sync_status_episodes_download">Laddar ner episodändringar...</string>
+ <string name="sync_status_upload_played">Laddar upp spelliststatus</string>
+ <string name="sync_status_subscriptions">Synkroniserar prenumerationer</string>
+ <string name="sync_status_success">Synkronisering lyckades</string>
+ <string name="sync_status_error">Synkronisering misslyckades</string>
<!--import and export-->
<string name="import_export_summary">Flytta prenumerationer och kö till annan enhet</string>
<string name="database">Databas</string>
@@ -530,6 +545,7 @@
<string name="html_export_label">HTML export</string>
<string name="database_export_label">Databasexport</string>
<string name="database_import_label">Databasimport</string>
+ <string name="database_import_warning">Importering av en databas kommer att ersätta alla dina befintliga prenumerationer och spelhistoriken. Du bör exportera din nuvarande databas som en backup. Vill du ersätta den?</string>
<string name="please_wait">Vänta...</string>
<string name="export_error_label">Exporteringsfel</string>
<string name="export_success_title">Exporten lyckades</string>
@@ -621,16 +637,23 @@
<string name="subscribe_label">Prenumerera</string>
<string name="subscribing_label">Prenumererar...</string>
<string name="preview_episode">Förhandsvisning</string>
+ <string name="stop_preview">Stoppa förhandsvisning</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">Backa</string>
<string name="fast_forward_label">Snabbspola</string>
+ <string name="increase_speed">Öka hastigheten</string>
+ <string name="decrease_speed">Sänk hastigheten</string>
<string name="media_type_audio_label">Ljud</string>
<string name="media_type_video_label">Video</string>
<string name="navigate_upwards_label">Navigera upp</string>
<string name="status_downloading_label">Episoden laddas ner</string>
<string name="in_queue_label">Episoden är i kön</string>
+ <string name="is_favorite_label">Episoden är markerad som favorit</string>
<string name="drag_handle_content_description">Dra för att ändra dess position</string>
<string name="load_next_page_label">Ladda nästa sida</string>
+ <string name="switch_pages">Byt sida</string>
+ <string name="position">Position: %1$s</string>
+ <string name="apply_action">Utför åtgärd</string>
<!--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>
@@ -656,6 +679,7 @@
<string name="browse_gpoddernet_label">Bläddra på gpodder.net</string>
<string name="discover">Upptäck</string>
<string name="discover_more">mer »</string>
+ <string name="search_powered_by">Sökt med %1$s</string>
<string name="filter">Filtrera</string>
<!--Episodes apply actions-->
<string name="all_label">Alla</string>
@@ -683,6 +707,12 @@
<string name="sort_date_old_new">Datum (Gammal \u2192 Ny)</string>
<string name="sort_duration_short_long">Längd (Kort \u2192 Lång)</string>
<string name="sort_duration_long_short">Längd (Lång \u2192 Kort)</string>
+ <string name="sort_a_z">A \u2192 Ö</string>
+ <string name="sort_z_a">Ö \u2192 A</string>
+ <string name="sort_new_old">Ny \u2192 Gammal</string>
+ <string name="sort_old_new">Gammal \u2192 Ny</string>
+ <string name="sort_short_long">Kort \u2192 Lång</string>
+ <string name="sort_long_short">Kort \u2192 Kort</string>
<!--Rating dialog-->
<string name="rating_title">Gillar du AntennaPod?</string>
<string name="rating_message">Vi skulle uppskatta om du tog dig tid att betygsätta AntennaPod.</string>
@@ -742,4 +772,8 @@
<string name="widget_settings">Widgetinställningar</string>
<string name="widget_create_button">Skapa widget</string>
<string name="widget_opacity">Opacitet</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">Inställningen sparad.</string>
+ <string name="on_demand_config_stream_text">Det verkar som att du strömmar mycket. Vill du att episodlistan ska visa strömmningsknapparna?</string>
+ <string name="on_demand_config_download_text">Det verkar som at du laddar ner mycket. Vill du att episodlistan ska visa nedladdningsknapparna?</string>
</resources>
diff --git a/core/src/main/res/values-tr/strings.xml b/core/src/main/res/values-tr/strings.xml
index 75d96ef88..84d67e5b9 100644
--- a/core/src/main/res/values-tr/strings.xml
+++ b/core/src/main/res/values-tr/strings.xml
@@ -19,7 +19,6 @@
<string name="cancel_download_label">İndirmeyi İptal Et</string>
<string name="playback_history_label">Çalma geçmişi</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Diğer cihazlarla senkronize et</string>
<string name="gpodnet_auth_label">gpodder.net giriş</string>
<string name="episode_cache_full_title">Bölüm önbelleği dolu</string>
<string name="episode_cache_full_message">Bölüm önbelleği limitine ulaşıldı. Ayarlardan önbellek limitini arttırabilirsiniz. </string>
@@ -229,7 +228,6 @@
<string name="storage_pref">Depolama</string>
<string name="project_pref">Proje</string>
<string name="queue_label">Kuyruk</string>
- <string name="integrations_label">Entegrasyon</string>
<string name="automation">Otomasyon</string>
<string name="download_pref_details">Detaylar</string>
<string name="import_export_pref">Al/Aktar</string>
@@ -315,6 +313,7 @@
<!--Search-->
<string name="search_status_no_results">Sonuç bulunamadı</string>
<string name="search_label">Ara</string>
+ <!--Synchronization-->
<!--import and export-->
<string name="opml_import_label">OPML içe aktar</string>
<string name="select_all_label">Hepsini seç</string>
@@ -450,4 +449,5 @@
<string name="cast_failed_seek">Yayın aygıtındaki yeni pozisyona erişilemedi</string>
<!--Notification channels-->
<!--Widget settings-->
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-uk/strings.xml b/core/src/main/res/values-uk/strings.xml
index fc2b84609..24a405e45 100644
--- a/core/src/main/res/values-uk/strings.xml
+++ b/core/src/main/res/values-uk/strings.xml
@@ -19,7 +19,6 @@
<string name="cancel_download_label">Скасувати\nзавантаження</string>
<string name="playback_history_label">Історія</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">Синхронізація з іншими пристроями</string>
<string name="gpodnet_auth_label">Автентифікуватися на gpodder.net</string>
<string name="episode_cache_full_title">Кеш епізодів заповнений</string>
<string name="episode_cache_full_message">Досягнута межа розміру кешу епізодів. Розмір кешу можна збільшити в налаштуваннях.</string>
@@ -101,7 +100,6 @@
<item quantity="many">%d днів після закінчення</item>
<item quantity="other">%d днів після закінчення</item>
</plurals>
- <string name="num_selected_label">%d помічено</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">Позначити всі як відтворені</string>
<string name="mark_all_read_msg">Позначено всі епізоди як відтворені</string>
@@ -277,8 +275,6 @@
<string name="ascending">За зростанням</string>
<string name="descending">За спаданням</string>
<string name="clear_queue_confirmation_msg">Будь ласка, підтвердіть що ви бажаєте вилучити всі епізоди з черги.</string>
- <string name="sort_old_to_new">Спочатку старіші</string>
- <string name="sort_new_to_old">Спочатку новіші</string>
<string name="time_left_label">Залишилось:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">Завантажити додаток</string>
@@ -311,7 +307,6 @@
<string name="storage_pref">Зберігання</string>
<string name="project_pref">Проект</string>
<string name="queue_label">Черга</string>
- <string name="integrations_label">Інтеграції</string>
<string name="automation">Автоматизація</string>
<string name="download_pref_details">Детально</string>
<string name="import_export_pref">Імпорт/Експорт</string>
@@ -388,12 +383,8 @@
<string name="pref_gpodnet_logout_toast">Успішно закрили доступ</string>
<string name="pref_gpodnet_setlogin_information_title">Змінити інформацію для входу</string>
<string name="pref_gpodnet_setlogin_information_sum">Змінити інформацію щодо облікового запису gpodder.net</string>
- <string name="pref_gpodnet_sync_changes_title">Синхронізувати зміни негайно</string>
<string name="pref_gpodnet_sync_changes_sum">Синхронізувати підписки та зміни стану епізодів з gpodder.net</string>
- <string name="pref_gpodnet_full_sync_title">Виконати повну синхронізацію негайно</string>
<string name="pref_gpodnet_full_sync_sum">Синхронізувати всі підписки та стан епізодів з gpodder.net.</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">Остання спроба синхронізації: %1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">Cинхронізація почалась</string>
<string name="pref_gpodnet_login_status"><![CDATA[Ви увійшли як <i>%1$s</i> з пристрою <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Повідомляти про помилки синхронізації</string>
<string name="pref_gpodnet_notifications_sum">Це налаштування не застосовується до помилок автентифікації.</string>
@@ -472,6 +463,7 @@
<string name="search_status_no_results">Жодних результатів немає</string>
<string name="search_label">Пошук</string>
<string name="no_results_for_query">Нічого не знайдено за запитом \"%1$s\"</string>
+ <!--Synchronization-->
<!--import and export-->
<string name="opml_import_label">OPML імпорт</string>
<string name="opml_reader_error">Помилка при читанні документа OPML:</string>
@@ -688,4 +680,5 @@
<string name="widget_settings">Налаштування віджету</string>
<string name="widget_create_button">Створити віджет</string>
<string name="widget_opacity">Непрозорість</string>
+ <!--On-Demand configuration-->
</resources>
diff --git a/core/src/main/res/values-zh-rCN/strings.xml b/core/src/main/res/values-zh-rCN/strings.xml
index 85acd763f..6b02a07e6 100644
--- a/core/src/main/res/values-zh-rCN/strings.xml
+++ b/core/src/main/res/values-zh-rCN/strings.xml
@@ -20,7 +20,6 @@
<string name="cancel_download_label">取消下载</string>
<string name="playback_history_label">播放历史</string>
<string name="gpodnet_main_label">gpodder.net</string>
- <string name="gpodnet_summary">与其他设备同步</string>
<string name="gpodnet_auth_label">gpodder.net 登录</string>
<string name="episode_cache_full_title">曲目缓存已满</string>
<string name="episode_cache_full_message">已达到曲目缓存限制,可以在设置中提高缓存大小。</string>
@@ -86,7 +85,7 @@
<string name="auto_download_apply_to_items_message">新的 <i>自动下载</i> 设置将会自动应用到新的节目上。\n你想应用到之前的节目吗?</string>
<string name="auto_delete_label">自动删除剧集</string>
<string name="feed_volume_reduction">音量下调</string>
- <string name="feed_volume_reduction_summary">调低这个订阅源内播客的播放音量: \%s</string>
+ <string name="feed_volume_reduction_summary">调低这个订阅中节目的音量:%1$s</string>
<string name="feed_volume_reduction_off">关闭</string>
<string name="feed_volume_reduction_light">轻微</string>
<string name="feed_volume_reduction_heavy">显著</string>
@@ -104,7 +103,9 @@
<plurals name="episode_cleanup_days_after_listening">
<item quantity="other">结束后 %d 天</item>
</plurals>
- <string name="num_selected_label">已选中 %d 个</string>
+ <plurals name="num_selected_label">
+ <item quantity="other">已选中%d</item>
+ </plurals>
<string name="loading_more">正加载更多…</string>
<!--Actions on feeds-->
<string name="mark_all_read_label">全部标识已读</string>
@@ -195,6 +196,7 @@
<string name="deactivate_auto_download">关闭自动下载</string>
<string name="reset_position">重置播放进度</string>
<string name="removed_item">已删除项</string>
+ <string name="no_items_selected">未选中项目</string>
<!--Download messages and labels-->
<string name="download_successful">成功</string>
<string name="download_pending">下载等待</string>
@@ -280,8 +282,6 @@
<string name="ascending">升序</string>
<string name="descending">降序</string>
<string name="clear_queue_confirmation_msg">请确认您要清除队列中的全部曲目</string>
- <string name="sort_old_to_new">从旧到新</string>
- <string name="sort_new_to_old">从新到旧</string>
<string name="time_left_label">计时剩余:\u0020</string>
<!--Variable Speed-->
<string name="download_plugin_label">插件下载</string>
@@ -316,8 +316,8 @@
<string name="storage_sum">播客剧集自动删除、导入和导出</string>
<string name="project_pref">项目</string>
<string name="queue_label">播放列表</string>
- <string name="integrations_label">插件</string>
- <string name="integrations_sum">同步</string>
+ <string name="synchronization_pref">同步</string>
+ <string name="synchronization_sum">用gpodder.net与其他设备同步</string>
<string name="automation">自动化</string>
<string name="download_pref_details">细节</string>
<string name="import_export_pref">导入/导出</string>
@@ -409,18 +409,22 @@
<string name="pref_gpodnet_logout_toast">注销成功</string>
<string name="pref_gpodnet_setlogin_information_title">改变登录信息</string>
<string name="pref_gpodnet_setlogin_information_sum">改变 gpodder.net 账户登录信息.</string>
- <string name="pref_gpodnet_sync_changes_title">立即同步改动</string>
+ <string name="pref_gpodnet_sync_changes_title">现在同步</string>
<string name="pref_gpodnet_sync_changes_sum">和gpodder.net同步订阅和节目状态</string>
- <string name="pref_gpodnet_full_sync_title">立即完整同步</string>
+ <string name="pref_gpodnet_full_sync_title">强制完整同步</string>
<string name="pref_gpodnet_full_sync_sum">与gpodder.net同步所有订阅和节目状态</string>
- <string name="pref_gpodnet_sync_sum_last_sync_line">最后同步尝试于:%1$s (%2$s)</string>
- <string name="pref_gpodnet_sync_started">已开始同步</string>
<string name="pref_gpodnet_login_status"><![CDATA[在设备 <i>%2$s</i> 上以 <i>%1$s</i> 身份登录]]></string>
<string name="pref_gpodnet_notifications_title">显示同步失败的提示信息</string>
<string name="pref_gpodnet_notifications_sum">该设置无法适用于验证错误。</string>
<string name="pref_playback_speed_title">播放速度</string>
<string name="pref_playback_speed_sum">自定义音频播放速度</string>
<string name="pref_feed_playback_speed_sum">开始播放此播客中剧集时使用的速度</string>
+ <string name="pref_feed_skip">自动跳过</string>
+ <string name="pref_feed_skip_sum">跳过开头结尾</string>
+ <string name="pref_feed_skip_ending">跳过最后多少秒</string>
+ <string name="pref_feed_skip_intro">跳过开头多少秒</string>
+ <string name="pref_feed_skip_ending_toast">跳过最后%d秒</string>
+ <string name="pref_feed_skip_intro_toast">跳过最初%d秒</string>
<string name="pref_playback_time_respects_speed_title">根据回放速度调整媒体信息</string>
<string name="pref_playback_time_respects_speed_sum">显示的播放位置和持续时间已根据回放速度进行调整</string>
<string name="pref_fast_forward">快进跳过时间</string>
@@ -471,6 +475,8 @@
<string name="pref_enqueue_downloaded_title">已下载队列</string>
<string name="pref_enqueue_downloaded_summary">向队列添加已下载的节目</string>
<string name="media_player_builtin">内置安卓播放器</string>
+ <string name="media_player_switch_to_exoplayer">转到ExoPlayer</string>
+ <string name="media_player_switched_to_exoplayer">已转至ExoPlayer</string>
<string name="pref_skip_silence_title">跳过没有声音的音频</string>
<string name="pref_videoBehavior_title">退出视频后</string>
<string name="pref_videoBehavior_sum">离开视频播放后的行为</string>
@@ -503,6 +509,14 @@
<string name="search_status_no_results">没有找到任何结果</string>
<string name="search_label">搜索</string>
<string name="no_results_for_query">未找到关于 \"%1$s\" 的结果</string>
+ <!--Synchronization-->
+ <string name="sync_status_started">同步已开始</string>
+ <string name="sync_status_episodes_upload">正上传节目更改...</string>
+ <string name="sync_status_episodes_download">正下载节目更改...</string>
+ <string name="sync_status_upload_played">上传播放状态中...</string>
+ <string name="sync_status_subscriptions">同步订阅中...</string>
+ <string name="sync_status_success">成功同步</string>
+ <string name="sync_status_error">同步失败</string>
<!--import and export-->
<string name="import_export_summary">移动订阅和队列到另一台设备</string>
<string name="database">数据库</string>
@@ -522,6 +536,7 @@
<string name="html_export_label">导出为 HTML 文件</string>
<string name="database_export_label">数据库导出</string>
<string name="database_import_label">数据库导入</string>
+ <string name="database_import_warning">导入数据库将替换所有当前订阅和播放历史记录。您应该将当前数据库导出为备份。您要替换吗?</string>
<string name="please_wait">请等待...</string>
<string name="export_error_label">导出出错</string>
<string name="export_success_title">成功导出</string>
@@ -610,16 +625,23 @@
<string name="subscribe_label">订阅</string>
<string name="subscribing_label">订阅中...</string>
<string name="preview_episode">预览</string>
+ <string name="stop_preview">停止预览</string>
<!--Content descriptions for image buttons-->
<string name="rewind_label">回放</string>
<string name="fast_forward_label">快进</string>
+ <string name="increase_speed">加快速度</string>
+ <string name="decrease_speed">放慢速度</string>
<string name="media_type_audio_label">音频</string>
<string name="media_type_video_label">视频</string>
<string name="navigate_upwards_label">向上导航</string>
<string name="status_downloading_label">曲目正在下载</string>
<string name="in_queue_label">曲目已经在播放列表中</string>
+ <string name="is_favorite_label">节目被标记为收藏</string>
<string name="drag_handle_content_description">拖动以变更本项目的位置</string>
<string name="load_next_page_label">载入下一页</string>
+ <string name="switch_pages">切换页面</string>
+ <string name="position">位置:%1$s</string>
+ <string name="apply_action">应用动作</string>
<!--Feed information screen-->
<string name="authentication_label">验证</string>
<string name="authentication_descr">给本播客及曲目变更用户名及密码</string>
@@ -645,6 +667,7 @@
<string name="browse_gpoddernet_label">浏览 gpodder.net</string>
<string name="discover">发现</string>
<string name="discover_more">更多</string>
+ <string name="search_powered_by">搜索由%1$s驱动</string>
<string name="filter">过滤器</string>
<!--Episodes apply actions-->
<string name="all_label">全部</string>
@@ -672,6 +695,12 @@
<string name="sort_date_old_new">日期 (旧 \u2192 新)</string>
<string name="sort_duration_short_long">时长 (短 \u2192 长)</string>
<string name="sort_duration_long_short">时长 (长 \u2192 短)</string>
+ <string name="sort_a_z">A \u2192 Z</string>
+ <string name="sort_z_a">Z \u2192 A</string>
+ <string name="sort_new_old">新\u2192旧</string>
+ <string name="sort_old_new">旧\u2192新</string>
+ <string name="sort_short_long">短\u2192长</string>
+ <string name="sort_long_short">长\u2192短</string>
<!--Rating dialog-->
<string name="rating_title">喜欢 AntennaPod?</string>
<string name="rating_message">如您能在百忙之外抽时间评价一下AntennaPod,我们感激不尽.</string>
@@ -731,4 +760,8 @@
<string name="widget_settings">小部件设置</string>
<string name="widget_create_button">创建小部件</string>
<string name="widget_opacity">不透明度</string>
+ <!--On-Demand configuration-->
+ <string name="on_demand_config_setting_changed">成功更新设置</string>
+ <string name="on_demand_config_stream_text">看起来你在线播放了很多节目。你想要剧集列表显示流按钮吗?</string>
+ <string name="on_demand_config_download_text">看起来你下载了很多节目。你想要播放列表显示下载按钮吗?</string>
</resources>
diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml
index dc79905cd..ba6c2f196 100644
--- a/core/src/main/res/values/arrays.xml
+++ b/core/src/main/res/values/arrays.xml
@@ -233,6 +233,16 @@
<item>3</item>
</string-array>
+ <string-array name="nav_drawer_feed_filter_values">
+ <item>0</item>
+ <item>1</item>
+ </string-array>
+
+ <string-array name="nav_drawer_feed_filter_options">
+ <item>@string/no_filter_label</item>
+ <item>@string/hide_subscriptions_where_counter_is_zero</item>
+ </string-array>
+
<string-array name="media_player_options">
<item>@string/media_player_builtin</item>
<item>@string/media_player_sonic</item>
@@ -245,30 +255,6 @@
<item>exoplayer</item>
</string-array>
- <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>
- <item>@string/hide_queued_episodes_label</item>
- <item>@string/hide_not_queued_episodes_label</item>
- <item>@string/hide_downloaded_episodes_label</item>
- <item>@string/hide_not_downloaded_episodes_label</item>
- <item>@string/hide_has_media_label</item>
- <item>@string/hide_is_favorite_label</item>
- </string-array>
-
- <string-array name="episode_filter_values">
- <item>unplayed</item>
- <item>paused</item>
- <item>played</item>
- <item>queued</item>
- <item>not_queued</item>
- <item>downloaded</item>
- <item>not_downloaded</item>
- <item>has_media</item>
- <item>is_favorite</item>
- </string-array>
-
<!-- sort for podcast screen, not for queue -->
<string-array name="feed_episodes_sort_options">
<item>@string/sort_date_new_old</item>
diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml
index 2d8cbb4cb..4a18f6ae6 100644
--- a/core/src/main/res/values/attrs.xml
+++ b/core/src/main/res/values/attrs.xml
@@ -52,11 +52,14 @@
<attr name="currently_playing_background" format="color"/>
<attr name="ic_bookmark" format="reference"/>
<attr name="ic_settings_speed" format="reference" />
+ <attr name="ic_settings_skip" format="reference" />
<attr name="drawer_activated_color" format="color"/>
<attr name="batch_edit_fab_icon" format="reference"/>
<attr name="action_icon_color" format="color"/>
<attr name="scrollbar_thumb" format="reference"/>
<attr name="background_elevated" format="color"/>
+ <attr name="filter_dialog_clear" format="reference"/>
+ <attr name="filter_dialog_button_background" format="reference"/>
<declare-styleable name="SquareImageView">
<attr name="direction" format="enum">
diff --git a/core/src/main/res/values/colors.xml b/core/src/main/res/values/colors.xml
index b9c5eca0d..ed0b239a5 100644
--- a/core/src/main/res/values/colors.xml
+++ b/core/src/main/res/values/colors.xml
@@ -29,4 +29,9 @@
<color name="master_switch_background_light">#DDDDDD</color>
<color name="master_switch_background_dark">#191919</color>
+ <!-- filter dialog -->
+ <color name="dialog_filter_clear_inactive_light">#666666</color>
+ <color name="dialog_filter_clear_inactive_dark">#bbbbbb</color>
+ <color name="dialog_filter_inactive_light">#eeeeee</color>
+ <color name="dialog_filter_inactive_dark">#555555</color>
</resources>
diff --git a/core/src/main/res/values/dimens.xml b/core/src/main/res/values/dimens.xml
index 41a24f6fa..4702a5302 100644
--- a/core/src/main/res/values/dimens.xml
+++ b/core/src/main/res/values/dimens.xml
@@ -38,4 +38,6 @@
<dimen name="media_router_controller_playback_control_start_padding">24dp</dimen>
<dimen name="media_router_controller_bottom_margin">8dp</dimen>
+ <dimen name="nav_drawer_max_screen_size">480dp</dimen>
+
</resources>
diff --git a/core/src/main/res/values/ids.xml b/core/src/main/res/values/ids.xml
index 1d1777ef1..3c173b72d 100644
--- a/core/src/main/res/values/ids.xml
+++ b/core/src/main/res/values/ids.xml
@@ -1,28 +1,36 @@
<resources>
-
- <item name="action_bar_refresh" type="id"/>
- <item name="action_bar_add" type="id"/>
- <item name="clear_queue_item" type="id"/>
+ <!-- Menu items -->
<item name="select_all_item" type="id"/>
<item name="deselect_all_item" type="id"/>
- <item name="search_item" type="id"/>
- <item name="enqueue_all_item" type="id"/>
- <item name="download_all_item" type="id"/>
<item name="clear_history_item" type="id"/>
<item name="open_in_browser_item" type="id"/>
<item name="copy_url_item" type="id"/>
<item name="share_url_item" type="id"/>
<item name="go_to_position_item" type="id"/>
- <item name="organize_queue_item" type="id"/>
<item name="drag_handle" type="id"/>
<item name="skip_episode_item" type="id"/>
<item name="move_to_top_item" type="id"/>
<item name="move_to_bottom_item" type="id"/>
- <item name="image_disk_cache_key" type="id"/>
- <item name="imageloader_key" type="id"/>
+
+ <!-- View types -->
+ <item name="view_type_episode_item" type="id"/>
+
+ <!-- Notifications need unique IDs to update/cancel them -->
<item name="notification_gpodnet_sync_error" type="id"/>
<item name="notification_gpodnet_sync_autherror" type="id"/>
- <item name="undobar_button" type="id"/>
- <item name="undobar_message" type="id"/>
- <item name="episode_item_view_holder" type="id"/>
+ <item name="notification_downloading" type="id"/>
+ <item name="notification_download_report" type="id"/>
+ <item name="notification_auto_download_report" type="id"/>
+ <item name="notification_playing" type="id"/>
+ <item name="notification_streaming_confirmation" type="id"/>
+
+ <!-- PendingIntent objects that use the same action but different extras need to use a unique request code -->
+ <item name="pending_intent_download_service_notification" type="id"/>
+ <item name="pending_intent_download_service_auth" type="id"/>
+ <item name="pending_intent_download_service_report" type="id"/>
+ <item name="pending_intent_download_service_autodownload_report" type="id"/>
+ <item name="pending_intent_allow_stream_always" type="id"/>
+ <item name="pending_intent_allow_stream_this_time" type="id"/>
+ <item name="pending_intent_player_activity" type="id"/>
+ <item name="pending_intent_sync_error" type="id"/>
</resources> \ No newline at end of file
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index a0408a07a..ef4602558 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -136,12 +136,13 @@
<string name="feed_settings_label">Podcast settings</string>
<string name="rename_feed_label">Rename podcast</string>
<string name="remove_feed_label">Remove podcast</string>
- <string name="share_label">Share&#8230;</string>
+ <string name="share_label">Share</string>
+ <string name="share_label_with_ellipses">Share…</string>
<string name="share_link_label">Share Episode URL</string>
<string name="share_link_with_position_label">Share Episode URL with Position</string>
<string name="share_file_label">Share File</string>
- <string name="share_website_url_label">Share Website URL</string>
- <string name="share_feed_url_label">Share Podcast URL</string>
+ <string name="share_website_url_label">Website address</string>
+ <string name="share_feed_url_label">Podcast feed URL</string>
<string name="share_item_url_label">Share Media File URL</string>
<string name="share_item_url_with_position_label">Share Media File URL with Position</string>
<string name="feed_delete_confirmation_msg">Please confirm that you want to delete the podcast \"%1$s\" and ALL its episodes (including downloaded episodes).</string>
@@ -152,14 +153,9 @@
<string name="select_all_above">Select all above</string>
<string name="select_all_below">Select all below</string>
<string name="hide_unplayed_episodes_label">Unplayed</string>
- <string name="hide_paused_episodes_label">Paused</string>
- <string name="hide_played_episodes_label">Played</string>
<string name="hide_queued_episodes_label">Queued</string>
<string name="hide_not_queued_episodes_label">Not queued</string>
- <string name="hide_downloaded_episodes_label">Downloaded</string>
- <string name="hide_not_downloaded_episodes_label">Not downloaded</string>
<string name="hide_has_media_label">Has media</string>
- <string name="hide_is_favorite_label">Is favorite</string>
<string name="filtered_label">Filtered</string>
<string name="refresh_failed_msg">{fa-exclamation-circle} Last Refresh failed</string>
<string name="open_podcast">Open Podcast</string>
@@ -316,8 +312,9 @@
<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, we recommend to enable the built-in Sonic mediaplayer.</string>
- <string name="set_playback_speed_label">Playback Speeds</string>
<string name="enable_sonic">Enable Sonic</string>
+ <string name="speed_presets">Presets</string>
+ <string name="preset_already_exists">%1$.2fx is already saved as a preset.</string>
<!-- Empty list labels -->
<string name="no_items_header_label">No queued episodes</string>
@@ -392,7 +389,7 @@
<string name="pref_autoUpdateIntervallOrTime_every">every %1$s</string>
<string name="pref_autoUpdateIntervallOrTime_at">at %1$s</string>
<string name="pref_followQueue_title">Continuous Playback</string>
- <string name="pref_pauseOnHeadsetDisconnect_title">Headphones Disconnect</string>
+ <string name="pref_pauseOnHeadsetDisconnect_title">Headphones or Bluetooth disconnect</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Headphones Reconnect</string>
<string name="pref_unpauseOnBluetoothReconnect_title">Bluetooth Reconnect</string>
<string name="pref_stream_over_download_title">Prefer Streaming</string>
@@ -405,7 +402,7 @@
<string name="pref_mobileUpdate_episode_download">Episode download</string>
<string name="pref_mobileUpdate_streaming">Streaming</string>
<string name="user_interface_label">User Interface</string>
- <string name="user_interface_sum">Appearance, Subscription order, Lockscreen</string>
+ <string name="user_interface_sum">Appearance, Subscriptions, Lockscreen</string>
<string name="pref_set_theme_title">Select Theme</string>
<string name="pref_nav_drawer_items_title">Set Navigation Drawer items</string>
<string name="pref_nav_drawer_items_sum">Change which items appear in the navigation drawer.</string>
@@ -446,8 +443,7 @@
<string name="pref_gpodnet_login_status"><![CDATA[Logged in as <i>%1$s</i> with device <i>%2$s</i>]]></string>
<string name="pref_gpodnet_notifications_title">Show sync error notifications</string>
<string name="pref_gpodnet_notifications_sum">This setting does not apply to authentication errors.</string>
- <string name="pref_playback_speed_title">Playback Speeds</string>
- <string name="pref_playback_speed_sum">Customize the speeds available for variable speed audio playback</string>
+ <string name="pref_playback_speed_sum">Customize the speeds available for variable speed playback</string>
<string name="pref_feed_playback_speed_sum">The speed to use when starting audio playback for episodes in this podcast</string>
<string name="pref_feed_skip">Auto Skip</string>
<string name="pref_feed_skip_sum">Skip introductions and ending credits.</string>
@@ -527,6 +523,11 @@
<string name="back_button_go_to_page_title">Select page</string>
<string name="pref_delete_removes_from_queue_title">Delete removes from Queue</string>
<string name="pref_delete_removes_from_queue_sum">Automatically remove an episode from the queue when it is deleted.</string>
+ <string name="pref_filter_feed_title">Subscription Filter</string>
+ <string name="pref_filter_feed_sum">Filter your subscriptions in navigation drawer and subscriptions screen.</string>
+ <string name="hide_subscriptions_where_counter_is_zero">Hide if counter is zero</string>
+ <string name="no_filter_label">None</string>
+ <string name="subscriptions_are_filtered">Subscriptions are filtered.</string>
<!-- About screen -->
<string name="about_pref">About</string>
@@ -581,6 +582,8 @@
<string name="import_select_file">Select file to import</string>
<string name="import_ok">Import successful.\n\nPlease press OK to restart AntennaPod</string>
<string name="import_no_downgrade">This database was exported with a newer version of AntennaPod. Your current installation does not yet know how to handle this file.</string>
+ <string name="favorites_export_label">Favorites export</string>
+ <string name="favorites_export_summary">Export saved favorites to file</string>
<!-- Sleep timer -->
<string name="set_sleeptimer_label">Set sleep timer</string>
@@ -728,7 +731,7 @@
<!-- Episodes apply actions -->
<string name="all_label">All</string>
<string name="selected_all_label">Selected all Episodes</string>
- <string name="none_label">None</string>
+ <string name="select_none_label">None</string>
<string name="deselected_all_label">Deselected all Episodes</string>
<string name="played_label">Played</string>
<string name="selected_played_label">Selected played Episodes</string>
@@ -738,13 +741,23 @@
<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="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="has_media">Has media</string>
<string name="selected_has_media_label">Selected episodes with media</string>
+ <string name="hide_is_favorite_label">Is favorite</string>
+ <string name="not_favorite">Not favorite</string>
+ <string name="hide_downloaded_episodes_label">Downloaded</string>
+ <string name="hide_not_downloaded_episodes_label">Not downloaded</string>
+ <string name="queued_label">Queued</string>
+ <string name="not_queued_label">Not queued</string>
+ <string name="has_media">Has media</string>
+ <string name="no_media">No media</string>
+ <string name="hide_paused_episodes_label">Paused</string>
+ <string name="not_paused">Not paused</string>
+ <string name="hide_played_episodes_label">Played</string>
+ <string name="not_played">Not played</string>
+
<!-- Sort -->
<string name="sort_title_a_z">Title (A \u2192 Z)</string>
<string name="sort_title_z_a">Title (Z \u2192 A)</string>
@@ -767,6 +780,12 @@
<string name="rating_later_label">Remind me later</string>
<string name="rating_now_label">Sure, let\'s do this!</string>
+ <!-- Share episode dialog -->
+ <string name="share_dialog_include_label">Include:</string>
+ <string name="share_playback_position_dialog_label">Playback position</string>
+ <string name="share_dialog_media_file_label">Media file URL</string>
+ <string name="share_dialog_episode_website_label">Episode webpage</string>
+
<!-- Audio controls -->
<string name="audio_controls">Audio controls</string>
<string name="playback_speed">Playback Speed</string>
diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml
index c72cd3e53..972174da5 100644
--- a/core/src/main/res/values/styles.xml
+++ b/core/src/main/res/values/styles.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android">
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<style name="Theme.AntennaPod.Light" parent="Theme.Base.AntennaPod.Light">
<!-- Room for API dependent attributes -->
@@ -35,6 +35,7 @@
<item name="av_fast_forward">@drawable/ic_av_fast_forward_black_48dp</item>
<item name="av_skip">@drawable/ic_av_skip_black_48dp</item>
<item name="ic_settings_speed">@drawable/ic_playback_speed_black</item>
+ <item name="ic_settings_skip">@drawable/ic_av_skip_black_24dp</item>
<item name="ic_delete">@drawable/ic_delete_black</item>
<item name="content_new">@drawable/ic_add_black</item>
<item name="content_remove_from_queue">@drawable/ic_remove_black</item>
@@ -72,6 +73,8 @@
<item name="ic_key">@drawable/ic_key_black</item>
<item name="ic_volume_adaption">@drawable/ic_volume_adaption_black</item>
<item name="scrollbar_thumb">@drawable/scrollbar_thumb_light</item>
+ <item name="filter_dialog_clear">@color/filter_dialog_clear_light</item>
+ <item name="filter_dialog_button_background">@color/filter_dialog_background_light</item>
</style>
<style name="Theme.AntennaPod.Dark" parent="Theme.Base.AntennaPod.Dark">
@@ -109,6 +112,7 @@
<item name="av_play">@drawable/ic_av_play_white_48dp</item>
<item name="av_skip">@drawable/ic_av_skip_white_48dp</item>
<item name="ic_settings_speed">@drawable/ic_playback_speed_white</item>
+ <item name="ic_settings_skip">@drawable/ic_av_skip_white_24dp</item>
<item name="ic_delete">@drawable/ic_delete_white</item>
<item name="content_new">@drawable/ic_add_white</item>
<item name="content_remove_from_queue">@drawable/ic_remove_white</item>
@@ -146,6 +150,8 @@
<item name="ic_key">@drawable/ic_key_white</item>
<item name="ic_volume_adaption">@drawable/ic_volume_adaption_white</item>
<item name="scrollbar_thumb">@drawable/scrollbar_thumb_dark</item>
+ <item name="filter_dialog_clear">@color/filter_dialog_clear_dark</item>
+ <item name="filter_dialog_button_background">@color/filter_dialog_background_dark</item>
</style>
<style name="Theme.AntennaPod.TrueBlack" parent="Theme.Base.AntennaPod.TrueBlack">
@@ -259,7 +265,6 @@
<style name="AntennaPod.TextView.UnreadIndicator" parent="@android:style/TextAppearance.Small">
<item name="android:textSize">@dimen/text_size_micro</item>
<item name="android:textColor">?attr/colorAccent</item>
- <item name="android:text">@string/new_label</item>
<item name="android:textAllCaps">true</item>
</style>
diff --git a/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java b/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java
index 60fd5f4ee..09d9f4623 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.core;
import android.content.Context;
+import android.content.Intent;
import android.util.Log;
-
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
@@ -12,6 +12,7 @@ import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
import de.danoeh.antennapod.core.preferences.UsageStatistics;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.ProviderInstallerInterceptor;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.NetworkUtils;
@@ -64,6 +65,18 @@ public class ClientConfig {
} else {
Log.v(TAG, "Cast is disabled. All Cast-related initialization will be skipped.");
}
+ ProviderInstaller.installIfNeededAsync(context, new ProviderInstaller.ProviderInstallListener() {
+ @Override
+ public void onProviderInstalled() {
+ Log.e(TAG, "onProviderInstalled");
+ }
+
+ @Override
+ public void onProviderInstallFailed(int i, Intent intent) {
+ Log.e(TAG, "onProviderInstallFailed");
+ }
+ });
+ ProviderInstallerInterceptor.installer = () -> installSslProvider(context);
AntennapodHttpClient.setCacheDirectory(new File(context.getCacheDir(), "okhttp"));
SleepTimerPreferences.init(context);
RxJavaErrorHandlerSetup.setupRxJavaErrorHandler();
diff --git a/core/src/test/java/de/danoeh/antennapod/core/feed/VolumeAdaptionSettingTest.java b/core/src/test/java/de/danoeh/antennapod/core/feed/VolumeAdaptionSettingTest.java
index 45c86cb83..e933ce034 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/feed/VolumeAdaptionSettingTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/feed/VolumeAdaptionSettingTest.java
@@ -5,7 +5,7 @@ import org.junit.Test;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
public class VolumeAdaptionSettingTest {
diff --git a/core/src/test/java/de/danoeh/antennapod/core/storage/ItemEnqueuePositionCalculatorTest.java b/core/src/test/java/de/danoeh/antennapod/core/storage/ItemEnqueuePositionCalculatorTest.java
index 80777d036..ed7d2fa75 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/storage/ItemEnqueuePositionCalculatorTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/storage/ItemEnqueuePositionCalculatorTest.java
@@ -13,6 +13,7 @@ import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
+import de.danoeh.antennapod.core.feed.FeedComponent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.FeedMother;
@@ -27,6 +28,7 @@ import static de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocat
import static de.danoeh.antennapod.core.util.CollectionTestUtil.concat;
import static de.danoeh.antennapod.core.util.CollectionTestUtil.list;
import static de.danoeh.antennapod.core.util.FeedItemUtil.getIdList;
+import static java.util.Collections.emptyList;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
@@ -248,13 +250,13 @@ public class ItemEnqueuePositionCalculatorTest {
assertEquals(message, idsExpected, getIdList(queue));
}
- static final List<FeedItem> QUEUE_EMPTY = Collections.unmodifiableList(Arrays.asList());
+ static final List<FeedItem> QUEUE_EMPTY = Collections.unmodifiableList(emptyList());
static final List<FeedItem> QUEUE_DEFAULT =
Collections.unmodifiableList(Arrays.asList(
createFeedItem(11), createFeedItem(12), createFeedItem(13), createFeedItem(14)));
static final List<Long> QUEUE_DEFAULT_IDS =
- QUEUE_DEFAULT.stream().map(fi -> fi.getId()).collect(Collectors.toList());
+ QUEUE_DEFAULT.stream().map(FeedComponent::getId).collect(Collectors.toList());
static Playable getCurrentlyPlaying(long idCurrentlyPlaying) {
diff --git a/core/src/test/java/de/danoeh/antennapod/core/util/FeedItemUtilTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/FeedItemUtilTest.java
index 2560ac6a0..a3744035b 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/util/FeedItemUtilTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/util/FeedItemUtilTest.java
@@ -7,6 +7,7 @@ import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -55,7 +56,7 @@ public class FeedItemUtilTest {
FeedItem feedItem = new FeedItem();
feedItem.setLink(itemLink);
feedItem.setFeed(feed);
- feed.setItems(Arrays.asList(feedItem));
+ feed.setItems(Collections.singletonList(feedItem));
return feedItem;
}
}
diff --git a/core/src/test/java/de/danoeh/antennapod/core/util/LongLongMapTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/LongLongMapTest.java
index 0ed77eb9f..21df71bec 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/util/LongLongMapTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/util/LongLongMapTest.java
@@ -3,6 +3,8 @@ package de.danoeh.antennapod.core.util;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
public class LongLongMapTest {
@@ -13,7 +15,7 @@ public class LongLongMapTest {
assertEquals("LongLongMap{}", map.toString());
assertEquals(0, map.get(42));
assertEquals(-1, map.get(42, -1));
- assertEquals(false, map.delete(42));
+ assertFalse(map.delete(42));
assertEquals(-1, map.indexOfKey(42));
assertEquals(-1, map.indexOfValue(42));
assertEquals(1, map.hashCode());
@@ -29,7 +31,7 @@ public class LongLongMapTest {
assertEquals(42, map.get(17, -1));
assertEquals(0, map.indexOfKey(17));
assertEquals(0, map.indexOfValue(42));
- assertEquals(true, map.delete(17));
+ assertTrue(map.delete(17));
}
@Test
@@ -45,7 +47,7 @@ public class LongLongMapTest {
assertEquals(1, map.indexOfKey(17));
assertEquals(1, map.indexOfValue(42));
for(int i=0; i < 100; i++) {
- assertEquals(true, map.delete(i * 17));
+ assertTrue(map.delete(i * 17));
}
}
diff --git a/infrastructure.md b/infrastructure.md
new file mode 100644
index 000000000..87a8bacb7
--- /dev/null
+++ b/infrastructure.md
@@ -0,0 +1,65 @@
+# AntennaPod infrastructure
+
+This document describes what services and accounts are in use for AntennaPod. The goal is to make it clear who has which passwords and keys.
+
+## App distribution
+- F-Droid
+ - Automatic updates from GitHub tags
+ - F-Droid's signing keys
+- Google Play
+ - Developer account owned by @mfietz
+ - @ByteHamster has (nearly full) access
+ - Can not manage permissions
+ - Upload using Gradle Play Publisher
+ - API key: @ByteHamster
+ - AntennaPod signing keys
+ - @mfietz, @ByteHamster, @danieloeh
+- Amazon App Store
+ - Outdated
+ - None of the current developers has access
+
+## Web
+- Main website (https://antennapod.org)
+ - Hosted on GitHub Pages
+ - Source: https://github.com/AntennaPod/antennapod.github.io
+ - Maintainer: @Keunes
+- Forum (https://forum.antennapod.org)
+ - Hosted by @ByteHamster (personal root server)
+ - Powered by [Discourse](https://github.com/discourse/discourse)
+ - Admin: @ByteHamster
+ - Moderators: @ByteHamster, @Keunes
+- Domain/DNS (`antennapod.org`)
+ - Managed by @mfietz
+- Google Groups
+ - https://groups.google.com/forum/#!forum/antennapod
+ - No longer used, replaced with forum (https://forum.antennapod.org)
+ - Owners: @mfietz, @danieloeh, @ByteHamster, @Keunes
+- Wiki
+ - https://github.com/AntennaPod/AntennaPod/wiki
+ - Managed on GitHub
+ - Mostly unmaintained
+
+## Email
+- `@antennapod.org`
+ - Managed by @ByteHamster (mailbox only for `info@`)
+ - Used for the required contact address on Google Play
+ - Auto responder tells users to write on forum or GitHub instead
+- `@forum.antennapod.org`
+ - Managed by @ByteHamster (catch-all mailbox)
+ - Used by the forum, checked every 5 minutes
+ - Allows to post+reply via email
+
+## Social media
+- Twitter
+ - https://twitter.com/antennapod
+ - Email address of @mfietz
+ - @ByteHamster and @mfietz have the password
+
+## Development
+- Translations
+ - https://transifex.com/antennapod/antennapod
+ - Pulled manually before releasing
+ - Team managers @mfietz, @ByteHamster
+- Source repo
+ - https://github.com/AntennaPod
+ - Organization owners: @ByteHamster, @danieloeh, @mfietz, @TomHennen