summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/src')
-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.java6
-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/playback/PlaybackTest.java2
-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.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java6
-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.java24
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java110
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.java2
-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.java15
-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.java7
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/TextOnlyFeedsTest.java2
-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/playback/TimelineTest.java4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java8
-rw-r--r--app/src/free/java/de/danoeh/antennapod/dialog/RatingDialog.java (renamed from app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java)2
-rw-r--r--app/src/main/AndroidManifest.xml13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java5
-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.java142
-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.java22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java64
-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/ChaptersListAdapter.java2
-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.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/FeedSortDialog.java38
-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.java90
-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/SleepTimerDialog.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java82
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java201
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java44
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/PodcastIndexPodcastSearcher.java126
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java12
-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.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java110
-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.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java12
-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.java67
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java10
-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.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java11
-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.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java79
-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.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java42
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java5
-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/AutoDownloadPreferencesFragment.java4
-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.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java2
-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/LockableBottomSheetBehavior.java12
-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/res/layout-sw720dp/main.xml46
-rw-r--r--app/src/main/res/layout/addfeed.xml52
-rw-r--r--app/src/main/res/layout/all_episodes_fragment.xml28
-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.xml2
-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.xml18
-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/filter_dialog.xml11
-rw-r--r--app/src/main/res/layout/filter_dialog_row.xml61
-rw-r--r--app/src/main/res/layout/fragment_itunes_search.xml47
-rw-r--r--app/src/main/res/layout/fragment_subscriptions.xml41
-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_list.xml7
-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/quick_feed_discovery.xml38
-rw-r--r--app/src/main/res/layout/search_fragment.xml13
-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/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.xml9
-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.xml6
-rw-r--r--app/src/main/res/xml/automotive_app_desc.xml2
-rw-r--r--app/src/main/res/xml/feed_settings.xml4
-rw-r--r--app/src/main/res/xml/preferences.xml4
-rw-r--r--app/src/main/res/xml/preferences_autodownload.xml5
-rw-r--r--app/src/main/res/xml/preferences_gpodder.xml2
-rw-r--r--app/src/main/res/xml/preferences_network.xml4
-rw-r--r--app/src/main/res/xml/preferences_playback.xml28
-rw-r--r--app/src/main/res/xml/preferences_storage.xml6
-rw-r--r--app/src/main/res/xml/preferences_user_interface.xml42
-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/activity/CastEnabledActivity.java2
-rw-r--r--app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java6
-rw-r--r--app/src/play/java/de/danoeh/antennapod/dialog/RatingDialog.java122
153 files changed, 2678 insertions, 1039 deletions
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..83d7a4d22 100644
--- a/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java
@@ -2,9 +2,9 @@ package de.test.antennapod.entities;
import android.annotation.SuppressLint;
import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
+import androidx.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/playback/PlaybackTest.java b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java
index 0a3a9f13a..419cf2096 100644
--- a/app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java
@@ -3,7 +3,7 @@ package de.test.antennapod.playback;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
+import androidx.preference.PreferenceManager;
import android.view.View;
import androidx.test.filters.LargeTest;
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..6c36da13e 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
@@ -2,7 +2,7 @@ package de.test.antennapod.storage;
import android.content.Context;
import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
+import androidx.preference.PreferenceManager;
import java.io.File;
import java.io.IOException;
@@ -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..d7ebf2351 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
@@ -2,7 +2,7 @@ package de.test.antennapod.storage;
import android.content.Context;
import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
+import androidx.preference.PreferenceManager;
import java.io.File;
import java.io.IOException;
@@ -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 090cd2213..595a9794f 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;
@@ -29,6 +29,8 @@ import static java.util.Collections.singletonList;
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;
/**
@@ -45,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);
@@ -68,7 +70,7 @@ public class DBTasksTest {
}
Feed newFeed = DBTasks.updateFeed(context, feed)[0];
- assertTrue(newFeed == feed);
+ assertSame(feed, newFeed);
assertTrue(feed.getId() != 0);
for (FeedItem item : feed.getItems()) {
assertFalse(item.isPlayed());
@@ -123,13 +125,13 @@ public class DBTasksTest {
}
final Feed newFeed = DBTasks.updateFeed(context, feed)[0];
- 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);
}
@@ -155,7 +157,7 @@ public class DBTasksTest {
feed.setItems(list);
final Feed newFeed = DBTasks.updateFeed(context, feed)[0];
- assertTrue(feed != newFeed);
+ assertNotSame(newFeed, feed);
final Feed feedFromDB = DBReader.getFeed(newFeed.getId());
final FeedItem feedItemFromDB = feedFromDB.getItems().get(0);
@@ -163,21 +165,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 d82e366da..d300e23e7 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
@@ -3,11 +3,11 @@ package de.test.antennapod.storage;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
-import android.preference.PreferenceManager;
+import androidx.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();
@@ -465,11 +471,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<>());
@@ -498,7 +504,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);
@@ -516,14 +522,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);
@@ -541,7 +547,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();
@@ -550,8 +556,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();
}
@@ -565,7 +571,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++) {
@@ -595,7 +601,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++) {
@@ -609,7 +615,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);
@@ -631,7 +637,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);
@@ -698,11 +704,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
index b49be9a04..8bd4f1be6 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.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/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..9bf89980c 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
@@ -3,11 +3,10 @@ package de.test.antennapod.ui;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
-import android.preference.PreferenceManager;
+import androidx.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..5f79e935c 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/SpeedChangeTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/SpeedChangeTest.java
@@ -3,9 +3,9 @@ package de.test.antennapod.ui;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
+import androidx.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/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/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/main/java/de/danoeh/antennapod/dialog/RatingDialog.java b/app/src/free/java/de/danoeh/antennapod/dialog/RatingDialog.java
index 7cb274708..255da6eaf 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
+++ b/app/src/free/java/de/danoeh/antennapod/dialog/RatingDialog.java
@@ -110,4 +110,4 @@ public class RatingDialog {
.setOnCancelListener(dialog1 -> resetStartDate())
.create();
}
-}
+} \ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1f730b8a9..fb205b1c3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -36,7 +36,9 @@
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"
+ android:allowAudioPlaybackCapture="true">
<meta-data android:name="android.webkit.WebView.MetricsOptOut"
@@ -50,6 +52,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,8 +80,8 @@
<activity
android:name=".activity.MainActivity"
- android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
- android:windowSoftInputMode="stateHidden"
+ android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|density|uiMode|keyboard|navigation"
+ android:windowSoftInputMode="stateAlwaysHidden"
android:launchMode="singleTask"
android:label="@string/app_name">
</activity>
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 fde7c0484..d2618eb08 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/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 fffe5be60..6f237e1aa 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,16 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
+import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -19,6 +25,7 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
+import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
@@ -31,7 +38,10 @@ import com.google.android.material.snackbar.Snackbar;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.event.MessageEvent;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
+import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.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,11 +78,12 @@ public class MainActivity extends CastEnabledActivity {
public static final String EXTRA_FEED_ID = "fragment_feed_id";
public static final String EXTRA_OPEN_PLAYER = "open_player";
public static final String EXTRA_REFRESH_ON_START = "refresh_on_start";
+ public static final String EXTRA_STARTED_FROM_SEARCH = "started_from_search";
public static final String KEY_GENERATED_VIEW_ID = "generated_view_id";
- 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();
@@ -100,10 +111,17 @@ public class MainActivity extends CastEnabledActivity {
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);
@@ -175,12 +193,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);
}
@@ -188,7 +212,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(Looper.getMainLooper()).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);
@@ -282,7 +310,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) {
@@ -316,13 +347,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
@@ -375,7 +428,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) {
@@ -398,7 +451,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)
@@ -453,7 +508,11 @@ public class MainActivity extends CastEnabledActivity {
if (tag != null) {
loadFragment(tag, args);
} else if (feedId > 0) {
- loadFeedFragmentById(feedId, args);
+ if (intent.getBooleanExtra(EXTRA_STARTED_FROM_SEARCH, false)) {
+ loadChildFragment(FeedItemlistFragment.newInstance(feedId));
+ } else {
+ loadFeedFragmentById(feedId, args);
+ }
}
sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
} else if (intent.getBooleanExtra(EXTRA_OPEN_PLAYER, false)) {
@@ -487,4 +546,53 @@ public class MainActivity extends CastEnabledActivity {
public Snackbar showSnackbarAbovePlayer(int text, int duration) {
return showSnackbarAbovePlayer(getResources().getText(text), duration);
}
+
+ //Hardware keyboard support
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
+ Integer customKeyCode = null;
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_P:
+ customKeyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
+ break;
+ case KeyEvent.KEYCODE_J: //Fallthrough
+ case KeyEvent.KEYCODE_A:
+ case KeyEvent.KEYCODE_COMMA:
+ customKeyCode = KeyEvent.KEYCODE_MEDIA_REWIND;
+ break;
+ case KeyEvent.KEYCODE_K: //Fallthrough
+ case KeyEvent.KEYCODE_D:
+ case KeyEvent.KEYCODE_PERIOD:
+ customKeyCode = KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
+ break;
+ case KeyEvent.KEYCODE_PLUS: //Fallthrough
+ case KeyEvent.KEYCODE_W:
+ audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
+ AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
+ return true;
+ case KeyEvent.KEYCODE_MINUS: //Fallthrough
+ case KeyEvent.KEYCODE_S:
+ audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
+ AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI);
+ return true;
+ case KeyEvent.KEYCODE_M:
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
+ AudioManager.ADJUST_TOGGLE_MUTE, AudioManager.FLAG_SHOW_UI);
+ return true;
+ }
+ break;
+ }
+
+ if (customKeyCode != null) {
+ Intent intent = new Intent(this, PlaybackService.class);
+ intent.putExtra(MediaButtonReceiver.EXTRA_KEYCODE, customKeyCode);
+ ContextCompat.startForegroundService(this, intent);
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
}
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 beb6e0a9f..3bacdc75f 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);
}
@@ -509,6 +508,8 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
// feed.getId() is always 0, we have to retrieve the id from the feed list from
// the database
Intent intent = MainActivity.getIntentToOpenFeed(this, getFeedId(feed));
+ intent.putExtra(MainActivity.EXTRA_STARTED_FROM_SEARCH,
+ getIntent().getBooleanExtra(MainActivity.EXTRA_STARTED_FROM_SEARCH, false));
finish();
startActivity(intent);
}
@@ -606,9 +607,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/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
index e2db81739..2d4510e8f 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -3,14 +3,18 @@ package de.danoeh.antennapod.activity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
+import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
+import android.view.KeyEvent;
import android.view.animation.AlphaAnimation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;
+
+import androidx.appcompat.view.menu.ActionMenuItem;
import androidx.core.view.WindowCompat;
import androidx.appcompat.app.ActionBar;
import android.text.TextUtils;
@@ -188,7 +192,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
videoControlsHider.stop();
if (System.currentTimeMillis() - lastScreenTap < 300) {
- if (event.getX() > v.getMeasuredWidth() / 2) {
+ if (event.getX() > v.getMeasuredWidth() / 2.0f) {
onFastForward();
showSkipAnimation(true);
} else {
@@ -481,4 +485,62 @@ public class VideoplayerActivity extends MediaplayerActivity {
}
+
+ //Hardware keyboard support
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_P: //Fallthrough
+ case KeyEvent.KEYCODE_SPACE:
+ onPlayPause();
+ toggleVideoControlsVisibility();
+ return true;
+ case KeyEvent.KEYCODE_J: //Fallthrough
+ case KeyEvent.KEYCODE_A:
+ case KeyEvent.KEYCODE_COMMA:
+ onRewind();
+ showSkipAnimation(false);
+ return true;
+ case KeyEvent.KEYCODE_K: //Fallthrough
+ case KeyEvent.KEYCODE_D:
+ case KeyEvent.KEYCODE_PERIOD:
+ onFastForward();
+ showSkipAnimation(true);
+ return true;
+ case KeyEvent.KEYCODE_F: //Fallthrough
+ case KeyEvent.KEYCODE_ESCAPE:
+ //Exit fullscreen mode
+ onBackPressed();
+ return true;
+ case KeyEvent.KEYCODE_I:
+ compatEnterPictureInPicture();
+ return true;
+ case KeyEvent.KEYCODE_PLUS: //Fallthrough
+ case KeyEvent.KEYCODE_W:
+ audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
+ AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
+ return true;
+ case KeyEvent.KEYCODE_MINUS: //Fallthrough
+ case KeyEvent.KEYCODE_S:
+ audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
+ AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI);
+ return true;
+ case KeyEvent.KEYCODE_M:
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
+ AudioManager.ADJUST_TOGGLE_MUTE, AudioManager.FLAG_SHOW_UI);
+ return true;
+ }
+ break;
+ }
+
+ //Go to x% of video:
+ if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
+ controller.seekTo((int) (0.1f * (keyCode - KeyEvent.KEYCODE_0) * controller.getDuration()));
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
}
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/ChaptersListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
index cb72a9150..002147071 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
@@ -63,7 +63,7 @@ public class ChaptersListAdapter extends RecyclerView.Adapter<ChaptersListAdapte
duration = media.getDuration() - sc.getStart();
}
holder.duration.setText(context.getString(R.string.chapter_duration,
- Converter.getDurationStringLong((int) duration)));
+ Converter.getDurationStringLocalized(context, (int) duration)));
if (sc.getLink() == null) {
holder.link.setVisibility(View.GONE);
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..92ed7b052 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -5,7 +5,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
-import android.preference.PreferenceManager;
+import androidx.preference.PreferenceManager;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
@@ -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.getSubscriptionsFilter().isEnabled() && 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/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
index ac1e94437..c3177668a 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -220,7 +220,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);
@@ -236,7 +236,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];
@@ -413,7 +413,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/FeedSortDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FeedSortDialog.java
new file mode 100644
index 000000000..96d1b9b67
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/FeedSortDialog.java
@@ -0,0 +1,38 @@
+package de.danoeh.antennapod.dialog;
+
+import android.content.Context;
+
+import androidx.appcompat.app.AlertDialog;
+
+import org.greenrobot.eventbus.EventBus;
+
+import java.util.Arrays;
+import java.util.List;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+
+public class FeedSortDialog {
+ public static void showDialog(Context context) {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ dialog.setTitle(context.getString(R.string.pref_nav_drawer_feed_order_title));
+ dialog.setNegativeButton(android.R.string.cancel, (d, listener) -> d.dismiss());
+
+ int selected = UserPreferences.getFeedOrder();
+ List<String> entryValues =
+ Arrays.asList(context.getResources().getStringArray(R.array.nav_drawer_feed_order_values));
+ final int selectedIndex = entryValues.indexOf("" + selected);
+
+ String[] items = context.getResources().getStringArray(R.array.nav_drawer_feed_order_options);
+ dialog.setSingleChoiceItems(items, selectedIndex, (d, which) -> {
+ if (selectedIndex != which) {
+ UserPreferences.setFeedOrder(entryValues.get(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..98f6cc117 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.dialog;
import android.app.Dialog;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
@@ -11,27 +12,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 +60,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 +72,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);
@@ -152,7 +95,7 @@ public class PlaybackControlsDialog extends DialogFragment {
barRightVolume.setEnabled(false);
}
- final CheckBox skipSilence = (CheckBox) dialog.findViewById(R.id.skipSilence);
+ final CheckBox skipSilence = dialog.findViewById(R.id.skipSilence);
skipSilence.setChecked(UserPreferences.isSkipSilence());
if (!UserPreferences.useExoplayer()) {
skipSilence.setEnabled(false);
@@ -217,16 +160,7 @@ public class PlaybackControlsDialog extends DialogFragment {
butAudioTracks.setText(audioTracks.get(selectedAudioTrack));
butAudioTracks.setOnClickListener(v -> {
controller.setAudioTrack((selectedAudioTrack + 1) % audioTracks.size());
- new Handler().postDelayed(this::setupAudioTracks, 500);
+ new Handler(Looper.getMainLooper()).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/SleepTimerDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
index a9c54e879..274c3b7bd 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.dialog;
+import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
@@ -137,6 +138,7 @@ public class SleepTimerDialog extends DialogFragment {
if (controller != null) {
controller.setSleepTimer(time);
}
+ closeKeyboard(content);
} catch (NumberFormatException e) {
e.printStackTrace();
Snackbar.make(content, R.string.time_dialog_invalid_input, Snackbar.LENGTH_LONG).show();
@@ -153,4 +155,9 @@ public class SleepTimerDialog extends DialogFragment {
timeDisplay.setVisibility(controller.sleepTimerActive() ? View.VISIBLE : View.GONE);
time.setText(Converter.getDurationStringLong((int) controller.getSleepTimerTimeLeft()));
}
+
+ private void closeKeyboard(View content) {
+ InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(content.getWindowToken(), 0);
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java
new file mode 100644
index 000000000..a8915480c
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java
@@ -0,0 +1,82 @@
+package de.danoeh.antennapod.dialog;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+
+import androidx.appcompat.app.AlertDialog;
+
+import org.greenrobot.eventbus.EventBus;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.core.feed.SubscriptionsFilter;
+import de.danoeh.antennapod.core.feed.SubscriptionsFilterGroup;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.view.RecursiveRadioGroup;
+
+public class SubscriptionsFilterDialog {
+ public static void showDialog(Context context) {
+ SubscriptionsFilter subscriptionsFilter = UserPreferences.getSubscriptionsFilter();
+ final Set<String> filterValues = new HashSet<>(Arrays.asList(subscriptionsFilter.getValues()));
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(context.getString(R.string.pref_filter_feed_title));
+
+ LayoutInflater inflater = LayoutInflater.from(context);
+ LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.filter_dialog, null, false);
+ builder.setView(layout);
+
+ for (SubscriptionsFilterGroup item : SubscriptionsFilterGroup.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);
+ if (item.values.length == 2) {
+ filter2.setText(item.values[1].displayName);
+ filter2.setTag(item.values[1].filterId);
+ } else {
+ filter2.setVisibility(View.GONE);
+ }
+ layout.addView(row);
+ }
+
+ for (String filterId : filterValues) {
+ if (!TextUtils.isEmpty(filterId)) {
+ ((RadioButton) layout.findViewWithTag(filterId)).setChecked(true);
+ }
+ }
+
+ 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);
+ builder.show();
+ }
+
+ private static void updateFilter(Set<String> filterValues) {
+ SubscriptionsFilter subscriptionsFilter = new SubscriptionsFilter(filterValues.toArray(new String[0]));
+ UserPreferences.setSubscriptionsFilter(subscriptionsFilter);
+ EventBus.getDefault().post(new UnreadItemsUpdateEvent());
+ }
+}
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..1fc7a77b2 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,170 @@
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.setPositiveButton(R.string.enable_sonic, (dialog, which) ->
+ UserPreferences.enableSonic());
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/discovery/ItunesTopListLoader.java b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java
index e93a89ef0..e1034f89b 100644
--- a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.discovery;
import android.content.Context;
+import android.content.SharedPreferences;
import android.util.Log;
import de.danoeh.antennapod.R;
@@ -23,24 +24,46 @@ import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
+import static android.content.Context.MODE_PRIVATE;
+
public class ItunesTopListLoader {
private static final String TAG = "ITunesTopListLoader";
private final Context context;
+ public static final String PREF_KEY_COUNTRY_CODE = "country_code";
+ public static final String PREFS = "CountryRegionPrefs";
+ public static final String DISCOVER_HIDE_FAKE_COUNTRY_CODE = "00";
+ public static final String COUNTRY_CODE_UNSET = "99";
public ItunesTopListLoader(Context context) {
this.context = context;
}
- public Single<List<PodcastSearchResult>> loadToplist(int limit) {
+ public Single<List<PodcastSearchResult>> loadToplist() {
+ String defaultCountry = Locale.getDefault().getCountry();
+ SharedPreferences prefs = context.getSharedPreferences(PREFS, MODE_PRIVATE);
+ String countryCode = prefs.getString(PREF_KEY_COUNTRY_CODE, COUNTRY_CODE_UNSET);
+ return this.loadToplist(countryCode, 25);
+ }
+
+ public Single<List<PodcastSearchResult>> loadToplist(String country, int limit) {
return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) emitter -> {
- String country = Locale.getDefault().getCountry();
OkHttpClient client = AntennapodHttpClient.getHttpClient();
String feedString;
+ String loadCountry = country;
+ if (COUNTRY_CODE_UNSET.equals(country)) {
+ loadCountry = Locale.getDefault().getCountry();
+ }
try {
- feedString = getTopListFeed(client, country, limit);
+ feedString = getTopListFeed(client, loadCountry, limit);
} catch (IOException e) {
- feedString = getTopListFeed(client, "us", limit);
+ if (COUNTRY_CODE_UNSET.equals(country)) {
+ feedString = getTopListFeed(client, "US", limit);
+ } else {
+ emitter.onError(e);
+ return;
+ }
}
+
List<PodcastSearchResult> podcasts = parseFeed(feedString);
emitter.onSuccess(podcasts);
})
@@ -59,6 +82,9 @@ public class ItunesTopListLoader {
if (response.isSuccessful()) {
return response.body().string();
}
+ if (response.code() == 400) {
+ throw new IOException("iTunes does not have data for the selected country.");
+ }
String prefix = context.getString(R.string.error_msg_prefix);
throw new IOException(prefix + response);
}
@@ -66,8 +92,14 @@ public class ItunesTopListLoader {
private List<PodcastSearchResult> parseFeed(String jsonString) throws JSONException {
JSONObject result = new JSONObject(jsonString);
- JSONObject feed = result.getJSONObject("feed");
- JSONArray entries = feed.getJSONArray("entry");
+ JSONObject feed;
+ JSONArray entries;
+ try {
+ feed = result.getJSONObject("feed");
+ entries = feed.getJSONArray("entry");
+ } catch (JSONException e) {
+ return new ArrayList<>();
+ }
List<PodcastSearchResult> results = new ArrayList<>();
for (int i = 0; i < entries.length(); i++) {
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastIndexPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastIndexPodcastSearcher.java
new file mode 100644
index 000000000..c8e5dc4ef
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastIndexPodcastSearcher.java
@@ -0,0 +1,126 @@
+package de.danoeh.antennapod.discovery;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.core.ClientConfig;
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import io.reactivex.Single;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class PodcastIndexPodcastSearcher implements PodcastSearcher {
+ private static final String PODCASTINDEX_API_URL = "https://api.podcastindex.org/api/1.0/search/byterm?q=%s";
+
+ public PodcastIndexPodcastSearcher() {
+ }
+
+ @Override
+ public Single<List<PodcastSearchResult>> search(String query) {
+ return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
+
+ Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ calendar.clear();
+ Date now = new Date();
+ calendar.setTime(now);
+ long secondsSinceEpoch = calendar.getTimeInMillis() / 1000L;
+ String apiHeaderTime = String.valueOf(secondsSinceEpoch);
+ String data4Hash = BuildConfig.PODCASTINDEX_API_KEY + BuildConfig.PODCASTINDEX_API_SECRET + apiHeaderTime;
+ String hashString = sha1(data4Hash);
+
+ String encodedQuery;
+ try {
+ encodedQuery = URLEncoder.encode(query, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // this won't ever be thrown
+ encodedQuery = query;
+ }
+
+ String formattedUrl = String.format(PODCASTINDEX_API_URL, encodedQuery);
+
+ OkHttpClient client = AntennapodHttpClient.getHttpClient();
+ Request.Builder httpReq = new Request.Builder()
+ .addHeader("X-Auth-Date", apiHeaderTime)
+ .addHeader("X-Auth-Key", BuildConfig.PODCASTINDEX_API_KEY)
+ .addHeader("Authorization", hashString)
+ .addHeader("User-Agent", ClientConfig.USER_AGENT)
+ .url(formattedUrl);
+ List<PodcastSearchResult> podcasts = new ArrayList<>();
+ try {
+ Response response = client.newCall(httpReq.build()).execute();
+
+ if (response.isSuccessful()) {
+ String resultString = response.body().string();
+ JSONObject result = new JSONObject(resultString);
+ JSONArray j = result.getJSONArray("feeds");
+
+ for (int i = 0; i < j.length(); i++) {
+ JSONObject podcastJson = j.getJSONObject(i);
+ PodcastSearchResult podcast = PodcastSearchResult.fromPodcastIndex(podcastJson);
+ if (podcast.feedUrl != null) {
+ podcasts.add(podcast);
+ }
+ }
+ } else {
+ subscriber.onError(new IOException(response.toString()));
+ }
+ } catch (IOException | JSONException e) {
+ subscriber.onError(e);
+ }
+ subscriber.onSuccess(podcasts);
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
+ @Override
+ public Single<String> lookupUrl(String url) {
+ return Single.just(url);
+ }
+
+ @Override
+ public boolean urlNeedsLookup(String url) {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return "Podcastindex.org";
+ }
+
+ private static String sha1(String clearString) {
+ try {
+ MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
+ messageDigest.update(clearString.getBytes("UTF-8"));
+ return toHex(messageDigest.digest());
+ } catch (Exception ignored) {
+ ignored.printStackTrace();
+ return null;
+ }
+ }
+
+ private static String toHex(byte[] bytes) {
+ StringBuilder buffer = new StringBuilder();
+ for (byte b : bytes) {
+ buffer.append(String.format(Locale.getDefault(), "%02x", b));
+ }
+ return buffer.toString();
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
index 0f0c864b1..bba438d1d 100644
--- a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
@@ -103,4 +103,12 @@ public class PodcastSearchResult {
searchHit.getUrl(),
searchHit.getAuthor());
}
+
+ public static PodcastSearchResult fromPodcastIndex(JSONObject json) {
+ String title = json.optString("title", "");
+ String imageUrl = json.optString("image", null);
+ String feedUrl = json.optString("url", null);
+ String author = json.optString("author", null);
+ return new PodcastSearchResult(title, imageUrl, feedUrl, author);
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java
index 3f738424b..ad574cab6 100644
--- a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java
@@ -19,6 +19,7 @@ public class PodcastSearcherRegistry {
searchProviders.add(new SearcherInfo(new ItunesPodcastSearcher(), 1.f));
searchProviders.add(new SearcherInfo(new FyydPodcastSearcher(), 1.f));
searchProviders.add(new SearcherInfo(new GpodnetPodcastSearcher(), 0.0f));
+ searchProviders.add(new SearcherInfo(new PodcastIndexPodcastSearcher(), 0.0f));
}
return searchProviders;
}
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 546684f14..a4646ad64 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -12,9 +12,13 @@ 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.fragment.app.Fragment;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
@@ -22,6 +26,7 @@ import de.danoeh.antennapod.activity.OpmlImportActivity;
import de.danoeh.antennapod.discovery.CombinedSearcher;
import de.danoeh.antennapod.discovery.FyydPodcastSearcher;
import de.danoeh.antennapod.discovery.ItunesPodcastSearcher;
+import de.danoeh.antennapod.discovery.PodcastIndexPodcastSearcher;
import de.danoeh.antennapod.fragment.gpodnet.GpodnetMainFragment;
/**
@@ -36,7 +41,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();
@@ -48,6 +56,8 @@ public class AddFeedFragment extends Fragment {
-> activity.loadChildFragment(OnlineSearchFragment.newInstance(FyydPodcastSearcher.class)));
root.findViewById(R.id.btn_search_gpodder).setOnClickListener(v
-> activity.loadChildFragment(new GpodnetMainFragment()));
+ root.findViewById(R.id.btn_search_podcastindex).setOnClickListener(v
+ -> activity.loadChildFragment(OnlineSearchFragment.newInstance(PodcastIndexPodcastSearcher.class)));
combinedFeedSearchBox = root.findViewById(R.id.combinedFeedSearchBox);
combinedFeedSearchBox.setOnEditorActionListener((v, actionId, event) -> {
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 e32fdb095..3129aa43c 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);
@@ -204,30 +202,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);
@@ -492,11 +489,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 48c25552f..6911687dd 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 -> {
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 13941dd2c..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();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java
index 89d3c7af9..5bc950d50 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java
@@ -1,27 +1,41 @@
package de.danoeh.antennapod.fragment;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ProgressBar;
+import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
+
+import org.greenrobot.eventbus.EventBus;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
+import de.danoeh.antennapod.core.event.DiscoveryDefaultUpdateEvent;
import de.danoeh.antennapod.discovery.ItunesTopListLoader;
import de.danoeh.antennapod.discovery.PodcastSearchResult;
import io.reactivex.disposables.Disposable;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
+
+import static android.content.Context.MODE_PRIVATE;
/**
* Searches iTunes store for top podcasts and displays results in a list.
@@ -29,6 +43,7 @@ import java.util.List;
public class DiscoveryFragment extends Fragment {
private static final String TAG = "ItunesSearchFragment";
+ private SharedPreferences prefs;
/**
* Adapter responsible with the search results.
@@ -46,6 +61,7 @@ public class DiscoveryFragment extends Fragment {
private List<PodcastSearchResult> searchResults;
private List<PodcastSearchResult> topList;
private Disposable disposable;
+ private String countryCode = "US";
/**
* Replace adapter data with provided search results from SearchTask.
@@ -75,6 +91,8 @@ public class DiscoveryFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
+ prefs = getActivity().getSharedPreferences(ItunesTopListLoader.PREFS, MODE_PRIVATE);
+ countryCode = prefs.getString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, Locale.getDefault().getCountry());
}
@Override
@@ -97,13 +115,64 @@ public class DiscoveryFragment extends Fragment {
intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl);
startActivity(intent);
});
+
+ List<String> countryCodeArray = new ArrayList<String>(Arrays.asList(Locale.getISOCountries()));
+ HashMap<String, String> countryCodeNames = new HashMap<String, String>();
+ for (String code: countryCodeArray) {
+ Locale locale = new Locale("", code);
+ String countryName = locale.getDisplayCountry();
+ if (countryName != null) {
+ countryCodeNames.put(code, countryName);
+ }
+ }
+
+ List<String> countryNamesSort = new ArrayList<String>(countryCodeNames.values());
+ Collections.sort(countryNamesSort);
+ countryNamesSort.add(0, getResources().getString(R.string.discover_hide));
+
+ Spinner countrySpinner = root.findViewById(R.id.spinner_country);
+ ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this.getContext(),
+ android.R.layout.simple_spinner_item,
+ countryNamesSort);
+ dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ countrySpinner.setAdapter(dataAdapter);
+ int pos = countryNamesSort.indexOf(countryCodeNames.get(countryCode));
+ countrySpinner.setSelection(pos);
+
+ countrySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> countrySpinner, View view, int position, long id) {
+ String countryName = (String) countrySpinner.getItemAtPosition(position);
+
+ if (countryName.equals(getResources().getString(R.string.discover_hide))) {
+ countryCode = ItunesTopListLoader.DISCOVER_HIDE_FAKE_COUNTRY_CODE;
+ } else {
+ for (Object o : countryCodeNames.keySet()) {
+ if (countryCodeNames.get(o).equals(countryName)) {
+ countryCode = o.toString();
+ break;
+ }
+ }
+ }
+
+ prefs.edit()
+ .putString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, countryCode)
+ .apply();
+
+ EventBus.getDefault().post(new DiscoveryDefaultUpdateEvent());
+ loadToplist(countryCode);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
progressBar = root.findViewById(R.id.progressBar);
txtvError = root.findViewById(R.id.txtvError);
butRetry = root.findViewById(R.id.butRetry);
txtvEmpty = root.findViewById(android.R.id.empty);
- loadToplist();
-
+ loadToplist(countryCode);
return root;
}
@@ -116,28 +185,39 @@ public class DiscoveryFragment extends Fragment {
adapter = null;
}
- private void loadToplist() {
+ private void loadToplist(String country) {
if (disposable != null) {
disposable.dispose();
}
+
gridView.setVisibility(View.GONE);
txtvError.setVisibility(View.GONE);
butRetry.setVisibility(View.GONE);
txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
- ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
- disposable = loader.loadToplist(25).subscribe(podcasts -> {
+ if (country.equals(ItunesTopListLoader.DISCOVER_HIDE_FAKE_COUNTRY_CODE)) {
+ gridView.setVisibility(View.GONE);
+ txtvError.setVisibility(View.VISIBLE);
+ txtvError.setText(getResources().getString(R.string.discover_is_hidden));
+ butRetry.setVisibility(View.GONE);
+ txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
- topList = podcasts;
- updateData(topList);
- }, error -> {
- Log.e(TAG, Log.getStackTraceString(error));
- progressBar.setVisibility(View.GONE);
- txtvError.setText(error.toString());
- txtvError.setVisibility(View.VISIBLE);
- butRetry.setOnClickListener(v -> loadToplist());
- butRetry.setVisibility(View.VISIBLE);
- });
+ } else {
+ ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
+ disposable = loader.loadToplist(country, 25).subscribe(
+ podcasts -> {
+ progressBar.setVisibility(View.GONE);
+ topList = podcasts;
+ updateData(topList);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ txtvError.setText(error.getMessage());
+ txtvError.setVisibility(View.VISIBLE);
+ butRetry.setOnClickListener(v -> loadToplist(country));
+ butRetry.setVisibility(View.VISIBLE);
+ });
+ }
}
}
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 37b842e0c..bc2d85452 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);
@@ -77,7 +80,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..62400d81d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
@@ -6,6 +6,10 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
+import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -120,18 +124,18 @@ 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;
}
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.episodes, menu);
- MenuItemUtils.setupSearchItem(menu, (MainActivity) getActivity(), 0);
+ MenuItemUtils.setupSearchItem(menu, (MainActivity) getActivity(), 0, "");
isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
@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 +180,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;
@@ -214,6 +218,13 @@ public abstract class EpisodesListFragment extends Fragment {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}
+ SwipeRefreshLayout swipeRefreshLayout = root.findViewById(R.id.swipeRefresh);
+ swipeRefreshLayout.setOnRefreshListener(() -> {
+ AutoUpdateManager.runImmediate(requireContext());
+ new Handler(Looper.getMainLooper()).postDelayed(() -> swipeRefreshLayout.setRefreshing(false),
+ getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms));
+ });
+
progLoading = root.findViewById(R.id.progLoading);
progLoading.setVisibility(View.VISIBLE);
loadingMoreView = root.findViewById(R.id.loadingMore);
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 94c9bd056..5d701472f 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -21,6 +21,7 @@ import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
+import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import io.reactivex.Maybe;
@@ -79,8 +80,16 @@ public class ExternalPlayerFragment extends Fragment {
super.onActivityCreated(savedInstanceState);
butPlay.setOnClickListener(v -> {
if (controller != null) {
- controller.playPause();
+ if (controller.getMedia().getMediaType() == MediaType.VIDEO
+ && controller.getStatus() != PlayerStatus.PLAYING) {
+ controller.playPause();
+ getContext().startActivity(PlaybackService
+ .getPlayerActivityIntent(getContext(), controller.getMedia()));
+ } else {
+ controller.playPause();
+ }
}
+
});
loadMediaInfo();
}
@@ -200,7 +209,6 @@ public class ExternalPlayerFragment extends Fragment {
.into(imgvCover);
if (controller != null && controller.isPlayingVideoLocally()) {
- butPlay.setVisibility(View.GONE);
((MainActivity) getActivity()).getBottomSheet().setLocked(true);
((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED);
} else {
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 ab9a867d0..115f8c665 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
@@ -2,8 +2,12 @@ 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.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -24,6 +28,8 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.appbar.AppBarLayout;
@@ -52,6 +58,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 +67,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 +85,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 +107,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 +165,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);
@@ -198,6 +209,18 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
});
EventBus.getDefault().register(this);
+
+ SwipeRefreshLayout swipeRefreshLayout = root.findViewById(R.id.swipeRefresh);
+ swipeRefreshLayout.setOnRefreshListener(() -> {
+ try {
+ DBTasks.forceRefreshFeed(requireContext(), feed, true);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ }
+ new Handler(Looper.getMainLooper()).postDelayed(() -> swipeRefreshLayout.setRefreshing(false),
+ getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms));
+ });
+
loadItems();
return root;
}
@@ -221,7 +244,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;
}
@@ -229,7 +252,11 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
optionsMenu = menu;
FeedMenuHandler.onCreateOptionsMenu(inflater, menu);
iconTintManager.updateTint();
- MenuItemUtils.setupSearchItem(menu, (MainActivity) getActivity(), feedID);
+ if (feed != null) {
+ MenuItemUtils.setupSearchItem(menu, (MainActivity) getActivity(), feedID, feed.getTitle());
+ } else {
+ MenuItemUtils.setupSearchItem(menu, (MainActivity) getActivity(), feedID, "");
+ }
if (feed == null || feed.getLink() == null) {
menu.findItem(R.id.share_link_item).setVisible(false);
menu.findItem(R.id.visit_website_item).setVisible(false);
@@ -239,14 +266,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 (item.getItemId() == R.id.action_search) {
item.getActionView().post(() -> iconTintManager.updateTint());
}
@@ -408,7 +442,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
private void updateSyncProgressBarVisibility() {
if (isUpdatingFeed != updateRefreshMenuItemChecker.isRefreshing()) {
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
}
if (!DownloadRequester.getInstance().isDownloadingFeeds()) {
nextPageLoader.getRoot().setVisibility(View.GONE);
@@ -432,7 +466,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
adapter.updateItems(feed.getItems());
}
- getActivity().supportInvalidateOptionsMenu();
+ getActivity().invalidateOptionsMenu();
updateSyncProgressBarVisibility();
}
@@ -457,8 +491,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);
@@ -485,6 +530,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;
}
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..a82c60d6c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
@@ -14,7 +14,7 @@ import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.SwitchPreference;
+import androidx.preference.SwitchPreferenceCompat;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.settings.SkipIntroEndingChangedEvent;
@@ -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();
@@ -322,7 +322,7 @@ public class FeedSettingsFragment extends Fragment {
}
private void setupKeepUpdatedPreference() {
- SwitchPreference pref = findPreference("keepUpdated");
+ SwitchPreferenceCompat pref = findPreference("keepUpdated");
pref.setChecked(feedPreferences.getKeepUpdated());
pref.setOnPreferenceChangeListener((preference, newValue) -> {
@@ -336,7 +336,7 @@ public class FeedSettingsFragment extends Fragment {
private void setupAutoDownloadGlobalPreference() {
if (!UserPreferences.isEnableAutodownload()) {
- SwitchPreference autodl = findPreference("autoDownload");
+ SwitchPreferenceCompat autodl = findPreference("autoDownload");
autodl.setChecked(false);
autodl.setEnabled(false);
autodl.setSummary(R.string.auto_download_disabled_globally);
@@ -345,7 +345,7 @@ public class FeedSettingsFragment extends Fragment {
}
private void setupAutoDownloadPreference() {
- SwitchPreference pref = findPreference("autoDownload");
+ SwitchPreferenceCompat pref = findPreference("autoDownload");
pref.setEnabled(UserPreferences.isEnableAutodownload());
if (UserPreferences.isEnableAutodownload()) {
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 aaf0fc7d4..337c789fe 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -145,9 +145,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 b6e4190e8..2425a174e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java
@@ -152,13 +152,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 da5710936..f58cafff7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java
@@ -14,6 +14,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
+import android.widget.ProgressBar;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -37,6 +39,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.SubscriptionsFilterDialog;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
@@ -45,6 +48,7 @@ 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.util.List;
@@ -71,6 +75,7 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
private int position = -1;
private NavListAdapter navAdapter;
private Disposable disposable;
+ private ProgressBar progressBar;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@@ -78,6 +83,7 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.nav_list, container, false);
+ progressBar = root.findViewById(R.id.progressBar);
ListView navList = root.findViewById(R.id.nav_list);
navAdapter = new NavListAdapter(itemAccess, getActivity());
navList.setAdapter(navAdapter);
@@ -86,9 +92,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;
@@ -232,18 +237,18 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
startActivity(intent);
}
- @Subscribe
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
loadData();
}
- @Subscribe
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onFeedListChanged(FeedListUpdateEvent event) {
loadData();
}
- @Subscribe
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onQueueChanged(QueueEvent event) {
Log.d(TAG, "onQueueChanged(" + event + ")");
// we are only interested in the number of queue items, not download status or position
@@ -354,14 +359,20 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
};
private void loadData() {
+ progressBar.setVisibility(View.VISIBLE);
disposable = Observable.fromCallable(DBReader::getNavDrawerData)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- navDrawerData = result;
- updateSelection(); // Selected item might be a feed
- navAdapter.notifyDataSetChanged();
- }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ .subscribe(
+ result -> {
+ navDrawerData = result;
+ updateSelection(); // Selected item might be a feed
+ navAdapter.notifyDataSetChanged();
+ progressBar.setVisibility(View.GONE);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ });
}
@Override
@@ -388,6 +399,9 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
startActivity(intent);
}
}
+ } else if (UserPreferences.getSubscriptionsFilter().isEnabled()
+ && navAdapter.showSubscriptionList) {
+ SubscriptionsFilterDialog.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..435590a0c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java
@@ -18,6 +18,7 @@ import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.TextView;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
import de.danoeh.antennapod.discovery.PodcastSearchResult;
@@ -28,6 +29,8 @@ import io.reactivex.disposables.Disposable;
import java.util.ArrayList;
import java.util.List;
+import static android.view.View.INVISIBLE;
+
public class OnlineSearchFragment extends Fragment {
private static final String TAG = "FyydSearchFragment";
@@ -92,6 +95,7 @@ public class OnlineSearchFragment extends Fragment {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar));
+ root.findViewById(R.id.spinner_country).setVisibility(INVISIBLE);
gridView = root.findViewById(R.id.gridView);
adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
gridView.setAdapter(adapter);
@@ -101,14 +105,15 @@ public class OnlineSearchFragment extends Fragment {
PodcastSearchResult podcast = searchResults.get(position);
Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl);
+ intent.putExtra(MainActivity.EXTRA_STARTED_FROM_SEARCH, true);
startActivity(intent);
});
progressBar = root.findViewById(R.id.progressBar);
txtvError = root.findViewById(R.id.txtvError);
butRetry = root.findViewById(R.id.butRetry);
txtvEmpty = root.findViewById(android.R.id.empty);
-
- txtvEmpty.setText(getString(R.string.search_powered_by, searchProvider.getName()));
+ TextView txtvPoweredBy = root.findViewById(R.id.search_powered_by);
+ txtvPoweredBy.setText(getString(R.string.search_powered_by, searchProvider.getName()));
return root;
}
@@ -126,7 +131,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..122524b48 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();
}
}
@@ -250,7 +246,7 @@ public class QueueFragment extends Fragment {
super.onCreateOptionsMenu(menu, inflater);
if (queue != null) {
inflater.inflate(R.menu.queue, menu);
- MenuItemUtils.setupSearchItem(menu, (MainActivity) getActivity(), 0);
+ MenuItemUtils.setupSearchItem(menu, (MainActivity) getActivity(), 0, "");
MenuItemUtils.refreshLockItem(getActivity(), menu);
// Show Lock Item only if queue is sorted manually
@@ -339,11 +335,9 @@ public class QueueFragment extends Fragment {
if (keepSortedNew) {
SortOrder sortOrder = UserPreferences.getQueueKeepSortedOrder();
DBWriter.reorderQueue(sortOrder, true);
- if (recyclerAdapter != null) {
- recyclerAdapter.setLocked(true);
- }
- } else if (recyclerAdapter != null) {
- recyclerAdapter.setLocked(UserPreferences.isQueueLocked());
+ }
+ if (recyclerAdapter != null) {
+ recyclerAdapter.updateDragDropEnabled();
}
getActivity().invalidateOptionsMenu();
return true;
@@ -384,14 +378,16 @@ 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);
- } else {
- ((MainActivity) getActivity()).showSnackbarAbovePlayer(R.string.queue_unlocked, Snackbar.LENGTH_SHORT);
+ if (queue.size() == 0) {
+ if (locked) {
+ ((MainActivity) getActivity()).showSnackbarAbovePlayer(R.string.queue_locked, Snackbar.LENGTH_SHORT);
+ } else {
+ ((MainActivity) getActivity()).showSnackbarAbovePlayer(R.string.queue_unlocked, 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/QuickFeedDiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
index d6bcdd79c..c994b4d8b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
@@ -1,27 +1,40 @@
package de.danoeh.antennapod.fragment;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.DisplayMetrics;
import androidx.fragment.app.Fragment;
+
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
+import android.widget.Button;
import android.widget.GridView;
+import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
+
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.FeedDiscoverAdapter;
+import de.danoeh.antennapod.core.event.DiscoveryDefaultUpdateEvent;
import de.danoeh.antennapod.discovery.ItunesTopListLoader;
import de.danoeh.antennapod.discovery.PodcastSearchResult;
import io.reactivex.disposables.Disposable;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
+
+import static android.content.Context.MODE_PRIVATE;
public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.OnItemClickListener {
@@ -33,6 +46,8 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
private FeedDiscoverAdapter adapter;
private GridView discoverGridLayout;
private TextView errorTextView;
+ private LinearLayout errorView;
+ private Button errorRetry;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -44,7 +59,10 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
discoverGridLayout = root.findViewById(R.id.discover_grid);
progressBar = root.findViewById(R.id.discover_progress_bar);
- errorTextView = root.findViewById(R.id.discover_error);
+ errorView = root.findViewById(R.id.discover_error);
+ errorTextView = root.findViewById(R.id.discover_error_txtV);
+ errorRetry = root.findViewById(R.id.discover_error_retry_btn);
+ errorRetry.setOnClickListener((listener) -> loadToplist());
adapter = new FeedDiscoverAdapter((MainActivity) getActivity());
discoverGridLayout.setAdapter(adapter);
@@ -67,36 +85,67 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
adapter.updateData(dummies);
loadToplist();
+
+ EventBus.getDefault().register(this);
return root;
}
@Override
public void onDestroy() {
super.onDestroy();
+ EventBus.getDefault().unregister(this);
if (disposable != null) {
disposable.dispose();
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ @SuppressWarnings("unused")
+ public void onDiscoveryDefaultUpdateEvent(DiscoveryDefaultUpdateEvent event) {
+ loadToplist();
+ }
+
private void loadToplist() {
progressBar.setVisibility(View.VISIBLE);
discoverGridLayout.setVisibility(View.INVISIBLE);
- errorTextView.setVisibility(View.GONE);
+ errorView.setVisibility(View.GONE);
+ errorRetry.setVisibility(View.INVISIBLE);
ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
- disposable = loader.loadToplist(NUM_SUGGESTIONS)
- .subscribe(podcasts -> {
- errorTextView.setVisibility(View.GONE);
- progressBar.setVisibility(View.GONE);
- discoverGridLayout.setVisibility(View.VISIBLE);
- adapter.updateData(podcasts);
- }, error -> {
- Log.e(TAG, Log.getStackTraceString(error));
- errorTextView.setText(error.getLocalizedMessage());
- errorTextView.setVisibility(View.VISIBLE);
- progressBar.setVisibility(View.GONE);
- discoverGridLayout.setVisibility(View.INVISIBLE);
- });
+ SharedPreferences prefs = getActivity().getSharedPreferences(ItunesTopListLoader.PREFS, MODE_PRIVATE);
+ String countryCode = prefs.getString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE,
+ Locale.getDefault().getCountry());
+ if (countryCode.equals(ItunesTopListLoader.DISCOVER_HIDE_FAKE_COUNTRY_CODE)) {
+ errorTextView.setText(String.format(getResources().getString(R.string.discover_is_hidden),
+ getResources().getString(R.string.discover_hide)));
+ errorView.setVisibility(View.VISIBLE);
+ progressBar.setVisibility(View.GONE);
+ discoverGridLayout.setVisibility(View.INVISIBLE);
+ errorRetry.setVisibility(View.INVISIBLE);
+ return;
+ }
+
+ disposable = loader.loadToplist(countryCode, NUM_SUGGESTIONS)
+ .subscribe(
+ podcasts -> {
+ errorView.setVisibility(View.GONE);
+ progressBar.setVisibility(View.GONE);
+ discoverGridLayout.setVisibility(View.VISIBLE);
+ if (podcasts.size() == 0) {
+ errorTextView.setText(getResources().getText(R.string.search_status_no_results));
+ errorView.setVisibility(View.VISIBLE);
+ discoverGridLayout.setVisibility(View.INVISIBLE);
+ } else {
+ adapter.updateData(podcasts);
+ }
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ errorTextView.setText(error.getLocalizedMessage());
+ errorView.setVisibility(View.VISIBLE);
+ progressBar.setVisibility(View.GONE);
+ discoverGridLayout.setVisibility(View.INVISIBLE);
+ errorRetry.setVisibility(View.VISIBLE);
+ });
}
@Override
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 0d33c1282..2061a8ba4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -17,6 +17,9 @@ import androidx.appcompat.widget.SearchView;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.chip.Chip;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
@@ -43,6 +46,7 @@ import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
+import java.util.Collections;
import java.util.List;
/**
@@ -52,6 +56,7 @@ public class SearchFragment extends Fragment {
private static final String TAG = "SearchFragment";
private static final String ARG_QUERY = "query";
private static final String ARG_FEED = "feed";
+ private static final String ARG_FEED_NAME = "feedName";
private EpisodeItemListAdapter adapter;
private FeedSearchResultAdapter adapterFeeds;
@@ -60,6 +65,7 @@ public class SearchFragment extends Fragment {
private EmptyViewHandler emptyViewHandler;
private EpisodeItemListRecyclerView recyclerView;
private List<FeedItem> results;
+ private Chip chip;
/**
* Create a new SearchFragment that searches all feeds.
@@ -79,9 +85,10 @@ public class SearchFragment extends Fragment {
/**
* Create a new SearchFragment that searches one specific feed.
*/
- public static SearchFragment newInstance(String query, long feed) {
+ public static SearchFragment newInstance(String query, long feed, String feedTitle) {
SearchFragment fragment = newInstance(query);
fragment.getArguments().putLong(ARG_FEED, feed);
+ fragment.getArguments().putString(ARG_FEED_NAME, feedTitle);
return fragment;
}
@@ -124,7 +131,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);
@@ -133,6 +139,12 @@ public class SearchFragment extends Fragment {
emptyViewHandler.setIcon(R.attr.action_search);
emptyViewHandler.setTitle(R.string.search_status_no_results);
EventBus.getDefault().register(this);
+
+ chip = layout.findViewById(R.id.feed_title_chip);
+ chip.setOnCloseIconClickListener(v -> {
+ getArguments().putLong(ARG_FEED, 0);
+ search();
+ });
return layout;
}
@@ -174,7 +186,7 @@ public class SearchFragment extends Fragment {
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
- getFragmentManager().popBackStack();
+ getParentFragmentManager().popBackStack();
return true;
}
});
@@ -260,7 +272,13 @@ public class SearchFragment extends Fragment {
progressBar.setVisibility(View.GONE);
this.results = results.first;
adapter.updateItems(results.first);
- adapterFeeds.updateData(results.second);
+ if (getArguments().getLong(ARG_FEED, 0) == 0) {
+ adapterFeeds.updateData(results.second);
+ chip.setVisibility(View.GONE);
+ } else {
+ adapterFeeds.updateData(Collections.emptyList());
+ chip.setText(getArguments().getString(ARG_FEED_NAME, ""));
+ }
String query = getArguments().getString(ARG_QUERY);
emptyViewHandler.setMessage(getString(R.string.no_results_for_query, query));
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
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 ba5d44b4d..70cd6fcb3 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
@@ -5,10 +5,14 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.widget.ProgressBar;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@@ -19,8 +23,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 +40,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 +49,8 @@ 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.SubscriptionsFilterDialog;
+import de.danoeh.antennapod.dialog.FeedSortDialog;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.view.EmptyViewHandler;
@@ -68,6 +77,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 +100,20 @@ 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) -> SubscriptionsFilterDialog.showDialog(requireContext()));
+
+ SwipeRefreshLayout swipeRefreshLayout = root.findViewById(R.id.swipeRefresh);
+ swipeRefreshLayout.setOnRefreshListener(() -> {
+ AutoUpdateManager.runImmediate(requireContext());
+ new Handler(Looper.getMainLooper()).postDelayed(() -> swipeRefreshLayout.setRefreshing(false),
+ getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms));
+ });
return root;
}
@@ -102,7 +122,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 +140,12 @@ public class SubscriptionFragment extends Fragment {
case R.id.refresh_item:
AutoUpdateManager.runImmediate(requireContext());
return true;
+ case R.id.subscriptions_filter:
+ SubscriptionsFilterDialog.showDialog(requireContext());
+ return true;
+ case R.id.subscriptions_sort:
+ FeedSortDialog.showDialog(requireContext());
+ return true;
case R.id.subscription_num_columns_2:
setColumnNumber(2);
return true;
@@ -198,6 +224,18 @@ public class SubscriptionFragment extends Fragment {
emptyView.updateVisibility();
progressBar.setVisibility(View.GONE);
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
+
+ if (UserPreferences.getSubscriptionsFilter().isEnabled()) {
+ 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..4cb50e2f4 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();
@@ -104,6 +104,7 @@ public abstract class PodcastListFragment extends Fragment {
Log.d(TAG, "Selected podcast: " + selection.toString());
Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, selection.getUrl());
+ intent.putExtra(MainActivity.EXTRA_STARTED_FROM_SEARCH, true);
startActivity(intent);
}
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/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
index 6b15e4301..0d6e79e84 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;
@@ -166,7 +168,7 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat {
private void buildEpisodeCleanupPreference() {
final Resources res = getActivity().getResources();
- ListPreference pref = (ListPreference) findPreference(UserPreferences.PREF_EPISODE_CLEANUP);
+ ListPreference pref = findPreference(UserPreferences.PREF_EPISODE_CLEANUP);
String[] values = res.getStringArray(
R.array.episode_cleanup_values);
String[] entries = new String[values.length];
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 f3b4d3003..106b9eef6 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
@@ -38,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";
@@ -86,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() {
@@ -208,11 +207,12 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
}
private void showDatabaseImportSuccessDialog() {
- AlertDialog.Builder d = new AlertDialog.Builder(getContext());
- d.setMessage(R.string.import_ok);
- d.setCancelable(false);
- d.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> PodcastApp.forceRestart());
- d.show();
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setTitle(R.string.successful_import_label);
+ builder.setMessage(R.string.import_ok);
+ builder.setCancelable(false);
+ builder.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> PodcastApp.forceRestart());
+ builder.show();
}
private void showExportSuccessDialog(final String path, final Uri streamUri) {
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 05ea521a9..2d640458e 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
@@ -23,6 +23,7 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
private static final String PREF_FAQ = "prefFaq";
private static final String PREF_VIEW_FORUM = "prefViewForum";
private static final String PREF_SEND_BUG_REPORT = "prefSendBugReport";
+ private static final String PREF_CATEGORY_PROJECT = "project";
private static final String STATISTICS = "statistics";
private static final String PREF_ABOUT = "prefAbout";
@@ -31,6 +32,13 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
addPreferencesFromResource(R.xml.preferences);
setupMainScreen();
setupSearch();
+
+ // If you are writing a spin-off, please update the details on screens like "About" and "Report bug"
+ // and afterwards remove the following lines.
+ String packageName = getContext().getPackageName();
+ if (!"de.danoeh.antennapod".equals(packageName) && !"de.danoeh.antennapod.debug".equals(packageName)) {
+ findPreference(PREF_CATEGORY_PROJECT).setVisible(false);
+ }
}
@Override
@@ -63,14 +71,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;
}
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..1fa1fed58 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 -> {
@@ -109,14 +109,14 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
private void buildSmartMarkAsPlayedPreference() {
final Resources res = getActivity().getResources();
- ListPreference pref = (ListPreference) findPreference(UserPreferences.PREF_SMART_MARK_AS_PLAYED_SECS);
+ ListPreference pref = findPreference(UserPreferences.PREF_SMART_MARK_AS_PLAYED_SECS);
String[] values = res.getStringArray(R.array.smart_mark_as_played_values);
String[] entries = new String[values.length];
for (int x = 0; x < values.length; x++) {
if(x == 0) {
entries[x] = res.getString(R.string.pref_smart_mark_as_played_disabled);
} else {
- Integer v = Integer.parseInt(values[x]);
+ 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/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
index a44623f48..689a72ba7 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
@@ -1,7 +1,6 @@
package de.danoeh.antennapod.fragment.preferences;
import android.content.Context;
-import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import com.google.android.material.snackbar.Snackbar;
@@ -9,9 +8,10 @@ import androidx.appcompat.app.AlertDialog;
import androidx.preference.PreferenceFragmentCompat;
import android.widget.ListView;
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.SubscriptionsFilterDialog;
+import de.danoeh.antennapod.dialog.FeedSortDialog;
import de.danoeh.antennapod.fragment.NavDrawerFragment;
import org.apache.commons.lang3.ArrayUtils;
@@ -75,6 +75,18 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat {
return true;
});
+ findPreference(UserPreferences.PREF_FILTER_FEED)
+ .setOnPreferenceClickListener((preference -> {
+ SubscriptionsFilterDialog.showDialog(requireContext());
+ return true;
+ }));
+
+ findPreference(UserPreferences.PREF_DRAWER_FEED_ORDER)
+ .setOnPreferenceClickListener((preference -> {
+ FeedSortDialog.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 1f15f66ec..bddafb75e 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,20 +63,9 @@ 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);
}
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()) {
@@ -243,20 +234,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/menuhandler/MenuItemUtils.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
index ff98ac609..6b3c99975 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
@@ -31,7 +31,7 @@ public class MenuItemUtils extends de.danoeh.antennapod.core.menuhandler.MenuIte
ta.recycle();
}
- public static void setupSearchItem(Menu menu, MainActivity activity, long feedId) {
+ public static void setupSearchItem(Menu menu, MainActivity activity, long feedId, String feedTitle) {
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) searchItem.getActionView();
sv.setBackgroundColor(ThemeUtils.getColorFromAttr(activity, android.R.attr.windowBackground));
@@ -40,7 +40,7 @@ public class MenuItemUtils extends de.danoeh.antennapod.core.menuhandler.MenuIte
@Override
public boolean onQueryTextSubmit(String s) {
sv.clearFocus();
- activity.loadChildFragment(SearchFragment.newInstance(s, feedId));
+ activity.loadChildFragment(SearchFragment.newInstance(s, feedId, feedTitle));
searchItem.collapseActionView();
return true;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java
index 007457c24..94e60ef61 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java
@@ -4,7 +4,7 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Build;
-import androidx.preference.SwitchPreference;
+import androidx.preference.SwitchPreferenceCompat;
import androidx.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.util.TypedValue;
@@ -12,7 +12,7 @@ import android.widget.TextView;
import de.danoeh.antennapod.R;
-public class MasterSwitchPreference extends SwitchPreference {
+public class MasterSwitchPreference extends SwitchPreferenceCompat {
public MasterSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
index 7a282fc82..64dd03b00 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.preferences;
import android.content.Context;
import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
+import androidx.preference.PreferenceManager;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.error.CrashReportWriter;
diff --git a/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java b/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
index 1f28b5c49..f9c10041e 100644
--- a/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
+++ b/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
@@ -3,7 +3,7 @@ package de.danoeh.antennapod.spa;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
+import androidx.preference.PreferenceManager;
import android.util.Log;
import de.danoeh.antennapod.BuildConfig;
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/LockableBottomSheetBehavior.java b/app/src/main/java/de/danoeh/antennapod/view/LockableBottomSheetBehavior.java
index 8e8d98fc9..1b96c7c4f 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/LockableBottomSheetBehavior.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/LockableBottomSheetBehavior.java
@@ -47,11 +47,11 @@ public class LockableBottomSheetBehavior<V extends View> extends ViewPagerBottom
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild,
- View target, int nestedScrollAxes) {
+ View target, int axes, int type) {
boolean handled = false;
if (!isLocked) {
- handled = super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
+ handled = super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type);
}
return handled;
@@ -59,16 +59,16 @@ public class LockableBottomSheetBehavior<V extends View> extends ViewPagerBottom
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target,
- int dx, int dy, int[] consumed) {
+ int dx, int dy, int[] consumed, int type) {
if (!isLocked) {
- super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
+ super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
}
}
@Override
- public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
+ public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target, int type) {
if (!isLocked) {
- super.onStopNestedScroll(coordinatorLayout, child, target);
+ super.onStopNestedScroll(coordinatorLayout, child, target, type);
}
}
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/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/addfeed.xml b/app/src/main/res/layout/addfeed.xml
index 9d14d209a..3d9b1ec17 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"
@@ -90,71 +90,55 @@
android:id="@+id/btn_add_via_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:drawablePadding="8dp"
- app:drawableStartCompat="?attr/content_new"
- app:drawableLeftCompat="?attr/content_new"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:background="?android:attr/selectableItemBackground"
- android:textColor="?android:attr/textColorPrimary"
- android:clickable="true"
+ app:drawableStartCompat="?attr/feed"
+ app:drawableLeftCompat="?attr/feed"
+ style="@style/AddPodcastTextView"
android:text="@string/add_podcast_by_url"/>
<TextView
android:id="@+id/btn_search_itunes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:drawablePadding="8dp"
app:drawableStartCompat="?attr/action_search"
app:drawableLeftCompat="?attr/action_search"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:background="?android:attr/selectableItemBackground"
- android:textColor="?android:attr/textColorPrimary"
- android:clickable="true"
+ style="@style/AddPodcastTextView"
android:text="@string/search_itunes_label"/>
<TextView
android:id="@+id/btn_search_fyyd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:drawablePadding="8dp"
app:drawableStartCompat="?attr/action_search"
app:drawableLeftCompat="?attr/action_search"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:background="?android:attr/selectableItemBackground"
- android:textColor="?android:attr/textColorPrimary"
- android:clickable="true"
+ style="@style/AddPodcastTextView"
android:text="@string/search_fyyd_label"/>
<TextView
android:id="@+id/btn_search_gpodder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:drawablePadding="8dp"
app:drawableStartCompat="?attr/action_search"
app:drawableLeftCompat="?attr/action_search"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:background="?android:attr/selectableItemBackground"
- android:textColor="?android:attr/textColorPrimary"
- android:clickable="true"
+ style="@style/AddPodcastTextView"
android:text="@string/browse_gpoddernet_label"/>
<TextView
+ android:id="@+id/btn_search_podcastindex"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:drawableStartCompat="?attr/action_search"
+ app:drawableLeftCompat="?attr/action_search"
+ style="@style/AddPodcastTextView"
+ android:text="@string/search_podcastindex_label"/>
+
+ <TextView
android:id="@+id/btn_opml_import"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:drawablePadding="8dp"
app:drawableStartCompat="?attr/av_download"
app:drawableLeftCompat="?attr/av_download"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:background="?android:attr/selectableItemBackground"
- android:textColor="?android:attr/textColorPrimary"
- android:clickable="true"
- android:text="@string/opml_import_label"/>
+ style="@style/AddPodcastTextView"
+ android:text="@string/opml_add_podcast_label"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
diff --git a/app/src/main/res/layout/all_episodes_fragment.xml b/app/src/main/res/layout/all_episodes_fragment.xml
index 73f061a0f..3b560967c 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"
@@ -17,19 +16,26 @@
android:visibility="gone"
tools:text="(i) Information" />
- <de.danoeh.antennapod.view.EpisodeItemListRecyclerView
- android:id="@android:id/list"
+ <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+ android:id="@+id/swipeRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
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:layout_above="@id/loadingMore"
- tools:itemCount="13"
- tools:listitem="@layout/feeditemlist_item" />
+ android:layout_above="@id/loadingMore">
+
+ <de.danoeh.antennapod.view.EpisodeItemListRecyclerView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="0dp"
+ android:layout_marginBottom="0dp"
+ android:paddingTop="@dimen/list_vertical_padding"
+ android:paddingBottom="@dimen/list_vertical_padding"
+ android:paddingHorizontal="@dimen/additional_horizontal_spacing"
+ tools:itemCount="13"
+ tools:listitem="@layout/feeditemlist_item" />
+
+ </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progLoading"
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 a5e2f82ce..225fdd98c 100644
--- a/app/src/main/res/layout/audioplayer_fragment.xml
+++ b/app/src/main/res/layout/audioplayer_fragment.xml
@@ -185,7 +185,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 fb156d6e6..5460d0609 100644
--- a/app/src/main/res/layout/cover_fragment.xml
+++ b/app/src/main/res/layout/cover_fragment.xml
@@ -12,7 +12,7 @@
<de.danoeh.antennapod.view.SquareImageView
android:id="@+id/imgvCover"
- android:layout_width="200dp"
+ android:layout_width="0dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:layout_marginLeft="16dp"
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..6dc484e2f 100644
--- a/app/src/main/res/layout/feed_item_list_fragment.xml
+++ b/app/src/main/res/layout/feed_item_list_fragment.xml
@@ -48,11 +48,19 @@
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
- <de.danoeh.antennapod.view.EpisodeItemListRecyclerView
- android:id="@+id/recyclerView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:layout_behavior="@string/appbar_scrolling_view_behavior" />
+ <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+ android:id="@+id/swipeRefresh"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior">
+
+ <de.danoeh.antennapod.view.EpisodeItemListRecyclerView
+ android:id="@+id/recyclerView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingHorizontal="@dimen/additional_horizontal_spacing" />
+
+ </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progLoading"
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 f8912b93e..005702c59 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/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_itunes_search.xml b/app/src/main/res/layout/fragment_itunes_search.xml
index 228bfb803..6e00bdf0d 100644
--- a/app/src/main/res/layout/fragment_itunes_search.xml
+++ b/app/src/main/res/layout/fragment_itunes_search.xml
@@ -4,18 +4,35 @@
android:layout_width="match_parent"
android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto">
- <androidx.appcompat.widget.Toolbar
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="?attr/actionBarSize"
- android:theme="?attr/actionBarTheme"
- android:layout_alignParentTop="true"
- app:navigationIcon="?homeAsUpIndicator"
- app:title="@string/discover"
- android:id="@+id/toolbar"/>
+ android:orientation="horizontal"
+ android:id="@+id/browsing"
+ android:layout_alignParentTop="true">
+ <androidx.appcompat.widget.Toolbar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minHeight="?attr/actionBarSize"
+ android:theme="?attr/actionBarTheme"
+ app:navigationIcon="?homeAsUpIndicator"
+ app:title="@string/discover"
+ android:id="@+id/toolbar"/>
+
+ <android.widget.Spinner
+ android:id="@+id/spinner_country"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right|end"
+ android:gravity="right|end"
+ android:isScrollContainer="true"
+ android:minHeight="?attr/actionBarSize"
+ android:spinnerMode="dropdown"
+ android:textAlignment="textEnd" />
+ </LinearLayout>
<GridView
- android:layout_below="@id/toolbar"
+ android:layout_below="@id/browsing"
android:id="@+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -36,6 +53,7 @@
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
+ android:visibility="gone"
android:text="@string/search_status_no_results" />
<ProgressBar
@@ -71,4 +89,17 @@
tools:visibility="visible"
tools:background="@android:color/holo_red_light" />
+ <TextView
+ android:id="@+id/search_powered_by"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="?android:attr/textColorTertiary"
+ android:text="@string/discover_powered_by_itunes"
+ android:textSize="12sp"
+ android:padding="4dp"
+ android:background="?android:attr/windowBackground"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
+ android:textAlignment="textEnd"/>
</RelativeLayout>
diff --git a/app/src/main/res/layout/fragment_subscriptions.xml b/app/src/main/res/layout/fragment_subscriptions.xml
index f37a6febd..d08e0c501 100644
--- a/app/src/main/res/layout/fragment_subscriptions.xml
+++ b/app/src/main/res/layout/fragment_subscriptions.xml
@@ -14,17 +14,38 @@
app:title="@string/subscriptions_label"
android:id="@+id/toolbar"/>
- <GridView
- android:layout_below="@id/toolbar"
- android:id="@+id/subscriptions_grid"
+ <TextView
+ android:id="@+id/feeds_filtered_message"
android:layout_width="match_parent"
- android:numColumns="3"
- android:horizontalSpacing="2dp"
- android:verticalSpacing="2dp"
- android:layout_height="match_parent"
- android:layout_gravity="center_horizontal"
- android:paddingBottom="88dp"
- android:clipToPadding="false"/>
+ 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" />
+
+ <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+ android:id="@+id/swipeRefresh"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_below="@id/feeds_filtered_message">
+
+ <GridView
+ android:id="@+id/subscriptions_grid"
+ android:layout_width="match_parent"
+ android:numColumns="3"
+ android:horizontalSpacing="2dp"
+ android:verticalSpacing="2dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal"
+ android:paddingBottom="88dp"
+ android:clipToPadding="false"/>
+
+ </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progLoading"
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_list.xml b/app/src/main/res/layout/nav_list.xml
index c26d0b8ed..ed850cc86 100644
--- a/app/src/main/res/layout/nav_list.xml
+++ b/app/src/main/res/layout/nav_list.xml
@@ -71,4 +71,11 @@
android:paddingTop="8dp"
android:scrollbarStyle="outsideOverlay"
tools:listitem="@layout/nav_listitem" />
+
+ <ProgressBar
+ style="?android:attr/progressBarStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/progressBar"
+ android:layout_centerVertical="true"/>
</RelativeLayout>
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/quick_feed_discovery.xml b/app/src/main/res/layout/quick_feed_discovery.xml
index a274fcdc7..0c55311e3 100644
--- a/app/src/main/res/layout/quick_feed_discovery.xml
+++ b/app/src/main/res/layout/quick_feed_discovery.xml
@@ -4,6 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<LinearLayout
@@ -54,12 +55,43 @@
android:layout_centerInParent="true"
android:layout_marginTop="30dp"/>
- <TextView
+ <LinearLayout
android:id="@+id/discover_error"
- android:textColor="@color/download_failed_red"
android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:layout_centerInParent="true"
- android:layout_height="wrap_content"/>
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/discover_error_txtV"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_margin="16dp"
+ android:textSize="@dimen/text_size_small"
+ tools:text="Error message"
+ tools:background="@android:color/holo_red_light" />
+
+ <Button
+ android:id="@+id/discover_error_retry_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:text="@string/retry_label"
+ tools:background="@android:color/holo_red_light" />
+ </LinearLayout>
</RelativeLayout>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="?android:attr/textColorTertiary"
+ android:text="@string/discover_powered_by_itunes"
+ android:textSize="12sp"
+ android:layout_gravity="right|end"
+ android:paddingHorizontal="4dp"
+ android:textAlignment="textEnd"/>
+
</LinearLayout>
diff --git a/app/src/main/res/layout/search_fragment.xml b/app/src/main/res/layout/search_fragment.xml
index 19cd87409..28d4778f7 100644
--- a/app/src/main/res/layout/search_fragment.xml
+++ b/app/src/main/res/layout/search_fragment.xml
@@ -14,6 +14,15 @@
app:title="@string/search_label"
android:id="@+id/toolbar"/>
+ <com.google.android.material.chip.Chip
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/toolbar"
+ android:id="@+id/feed_title_chip"
+ android:layout_marginLeft="10dp"
+ android:layout_marginRight="0dp"
+ app:closeIconVisible="true"/>
+
<ProgressBar
android:layout_centerInParent="true"
android:id="@+id/progressBar"
@@ -23,7 +32,7 @@
android:layout_gravity="center"/>
<androidx.recyclerview.widget.RecyclerView
- android:layout_below="@id/toolbar"
+ android:layout_below="@id/feed_title_chip"
android:id="@+id/recyclerViewFeeds"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -36,7 +45,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 0072754d5..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="@tools:sample/avatars"
- 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/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..b7dc95299 100644
--- a/app/src/main/res/menu/subscriptions.xml
+++ b/app/src/main/res/menu/subscriptions.xml
@@ -9,6 +9,15 @@
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/subscriptions_sort"
+ android:title="@string/sort"
+ 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..cb8f9e082
--- /dev/null
+++ b/app/src/main/res/values/integers.xml
@@ -0,0 +1,6 @@
+<?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>
+ <integer name="swipe_to_refresh_duration_in_ms">750</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 9f8392f44..a6820a4ad 100644
--- a/app/src/main/res/xml/feed_settings.xml
+++ b/app/src/main/res/xml/feed_settings.xml
@@ -3,7 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="feedSettingsScreen">
- <SwitchPreference
+ <SwitchPreferenceCompat
android:key="keepUpdated"
android:icon="?attr/navigation_refresh"
android:title="@string/keep_updated"
@@ -45,7 +45,7 @@
android:key="volumeReduction"/>
<PreferenceCategory android:title="@string/auto_download_settings_label">
- <SwitchPreference
+ <SwitchPreferenceCompat
android:key="autoDownload"
android:title="@string/auto_download_label"/>
<Preference
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index b69f27473..0a19a36b1 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -44,7 +44,9 @@
android:title="@string/statistics_label"
android:icon="?attr/statistics" />
- <PreferenceCategory android:title="@string/project_pref">
+ <PreferenceCategory
+ android:key="project"
+ android:title="@string/project_pref">
<Preference
android:key="prefFaq"
android:title="@string/pref_faq"
diff --git a/app/src/main/res/xml/preferences_autodownload.xml b/app/src/main/res/xml/preferences_autodownload.xml
index 333224aa0..2b541afa3 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
@@ -23,12 +22,12 @@
android:title="@string/pref_episode_cleanup_title"
android:summary="@string/pref_episode_cleanup_summary"
android:entryValues="@array/episode_cleanup_values"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:key="prefEnableAutoDownloadOnBattery"
android:title="@string/pref_automatic_download_on_battery_title"
android:summary="@string/pref_automatic_download_on_battery_sum"
android:defaultValue="true"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:key="prefEnableAutoDownloadWifiFilter"
android:title="@string/pref_autodl_wifi_filter_title"
android:summary="@string/pref_autodl_wifi_filter_sum"/>
diff --git a/app/src/main/res/xml/preferences_gpodder.xml b/app/src/main/res/xml/preferences_gpodder.xml
index 5789f5f84..d8478faf2 100644
--- a/app/src/main/res/xml/preferences_gpodder.xml
+++ b/app/src/main/res/xml/preferences_gpodder.xml
@@ -26,7 +26,7 @@
<Preference
android:key="pref_gpodnet_hostname"
android:title="@string/pref_gpodnet_sethostname_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:key="pref_gpodnet_notifications"
android:title="@string/pref_gpodnet_notifications_title"
android:summary="@string/pref_gpodnet_notifications_sum"
diff --git a/app/src/main/res/xml/preferences_network.xml b/app/src/main/res/xml/preferences_network.xml
index 5d1831ef0..f51b9561e 100644
--- a/app/src/main/res/xml/preferences_network.xml
+++ b/app/src/main/res/xml/preferences_network.xml
@@ -29,13 +29,13 @@
numberpicker:maxValue="50"
android:key="prefParallelDownloads"
android:title="@string/pref_parallel_downloads_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="true"
android:enabled="true"
android:key="prefShowDownloadReport"
android:summary="@string/pref_showDownloadReport_sum"
android:title="@string/pref_showDownloadReport_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="false"
android:enabled="true"
android:key="prefShowAutoDownloadReport"
diff --git a/app/src/main/res/xml/preferences_playback.xml b/app/src/main/res/xml/preferences_playback.xml
index 32bf383d7..161332d2f 100644
--- a/app/src/main/res/xml/preferences_playback.xml
+++ b/app/src/main/res/xml/preferences_playback.xml
@@ -2,33 +2,33 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/interruptions">
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="true"
android:enabled="true"
android:key="prefPauseOnHeadsetDisconnect"
android:summary="@string/pref_pauseOnDisconnect_sum"
android:title="@string/pref_pauseOnHeadsetDisconnect_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="true"
android:enabled="true"
android:dependency="prefPauseOnHeadsetDisconnect"
android:key="prefUnpauseOnHeadsetReconnect"
android:summary="@string/pref_unpauseOnHeadsetReconnect_sum"
android:title="@string/pref_unpauseOnHeadsetReconnect_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="false"
android:enabled="true"
android:dependency="prefPauseOnHeadsetDisconnect"
android:key="prefUnpauseOnBluetoothReconnect"
android:summary="@string/pref_unpauseOnBluetoothReconnect_sum"
android:title="@string/pref_unpauseOnBluetoothReconnect_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="false"
android:enabled="true"
android:key="prefPauseForFocusLoss"
android:summary="@string/pref_pausePlaybackForFocusLoss_sum"
android:title="@string/pref_pausePlaybackForFocusLoss_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="true"
android:enabled="true"
android:key="prefResumeAfterCall"
@@ -44,13 +44,13 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/playback_control">
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="false"
android:enabled="true"
android:key="prefHardwareForwardButtonSkips"
android:summary="@string/pref_hardwareForwardButtonSkips_sum"
android:title="@string/pref_hardwareForwardButtonSkips_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="false"
android:enabled="true"
android:key="prefHardwarePreviousButtonRestarts"
@@ -67,13 +67,13 @@
<Preference
android:key="prefPlaybackSpeedLauncher"
android:summary="@string/pref_playback_speed_sum"
- android:title="@string/pref_playback_speed_title"/>
- <SwitchPreference
+ android:title="@string/playback_speed"/>
+ <SwitchPreferenceCompat
android:defaultValue="false"
android:key="prefPlaybackTimeRespectsSpeed"
android:summary="@string/pref_playback_time_respects_speed_sum"
android:title="@string/pref_playback_time_respects_speed_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="false"
android:key="prefStreamOverDownload"
android:summary="@string/pref_stream_over_download_sum"
@@ -81,7 +81,7 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/queue_label">
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="true"
android:enabled="true"
android:key="prefEnqueueDownloaded"
@@ -93,7 +93,7 @@
android:entryValues="@array/enqueue_location_values"
android:key="prefEnqueueLocation"
android:title="@string/pref_enqueue_location_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="true"
android:enabled="true"
android:key="prefFollowQueue"
@@ -106,7 +106,7 @@
android:key="prefSmartMarkAsPlayedSecs"
android:summary="@string/pref_smart_mark_as_played_sum"
android:title="@string/pref_smart_mark_as_played_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="true"
android:enabled="true"
android:key="prefSkipKeepsEpisode"
@@ -125,7 +125,7 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/experimental_pref">
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="false"
android:enabled="true"
android:key="prefCast"
diff --git a/app/src/main/res/xml/preferences_storage.xml b/app/src/main/res/xml/preferences_storage.xml
index 18e2abb31..d3d570e6c 100644
--- a/app/src/main/res/xml/preferences_storage.xml
+++ b/app/src/main/res/xml/preferences_storage.xml
@@ -13,19 +13,19 @@
android:key="prefImageCacheSize"
android:summary="@string/pref_image_cache_size_sum"
android:defaultValue="100"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="false"
android:enabled="true"
android:key="prefAutoDelete"
android:summary="@string/pref_auto_delete_sum"
android:title="@string/pref_auto_delete_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="true"
android:enabled="true"
android:key="prefFavoriteKeepsEpisode"
android:summary="@string/pref_favorite_keeps_episodes_sum"
android:title="@string/pref_favorite_keeps_episodes_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="false"
android:enabled="true"
android:key="prefDeleteRemovesFromQueue"
diff --git a/app/src/main/res/xml/preferences_user_interface.xml b/app/src/main/res/xml/preferences_user_interface.xml
index a2fc970e0..203e14d42 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,35 +14,38 @@
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
+ <SwitchPreferenceCompat
android:title="@string/pref_episode_cover_title"
android:key="prefEpisodeCover"
android:summary="@string/pref_episode_cover_summary"
android:defaultValue="true"
android:enabled="true"/>
</PreferenceCategory>
+ <PreferenceCategory android:title="@string/subscriptions_label">
+ <Preference
+ android:title="@string/pref_nav_drawer_feed_order_title"
+ android:key="prefDrawerFeedOrder"
+ android:summary="@string/pref_nav_drawer_feed_order_sum"/>
+ <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="prefSubscriptionsFilter"
+ android:summary="@string/pref_filter_feed_sum" />
+ </PreferenceCategory>
<PreferenceCategory android:title="@string/external_elements">
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="false"
android:enabled="true"
android:key="prefExpandNotify"
android:summary="@string/pref_expandNotify_sum"
android:title="@string/pref_expandNotify_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="true"
android:enabled="true"
android:key="prefPersistNotify"
@@ -53,7 +55,7 @@
android:key="prefCompactNotificationButtons"
android:summary="@string/pref_compact_notification_buttons_sum"
android:title="@string/pref_compact_notification_buttons_title"/>
- <SwitchPreference
+ <SwitchPreferenceCompat
android:defaultValue="true"
android:enabled="true"
android:key="prefLockscreenBackground"
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/activity/CastEnabledActivity.java b/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
index 10678f556..753feb3e7 100644
--- a/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
+++ b/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
@@ -3,7 +3,7 @@ package de.danoeh.antennapod.activity;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.os.Bundle;
-import android.preference.PreferenceManager;
+import androidx.preference.PreferenceManager;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
diff --git a/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java b/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java
index bf5b85c82..6d8450a18 100644
--- a/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java
+++ b/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java
@@ -290,10 +290,10 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
View playbackControlLayout = View.inflate(getContext(), R.layout.media_router_controller, wrapper);
- titleView = (TextView) playbackControlLayout.findViewById(R.id.mrc_control_title);
- subtitleView = (TextView) playbackControlLayout.findViewById(R.id.mrc_control_subtitle);
+ titleView = playbackControlLayout.findViewById(R.id.mrc_control_title);
+ subtitleView = playbackControlLayout.findViewById(R.id.mrc_control_subtitle);
playbackControlLayout.findViewById(R.id.mrc_control_title_container).setOnClickListener(onClickListener);
- playPauseButton = (ImageButton) playbackControlLayout.findViewById(R.id.mrc_control_play_pause);
+ playPauseButton = playbackControlLayout.findViewById(R.id.mrc_control_play_pause);
playPauseButton.setOnClickListener(v -> {
PlaybackStateCompat state;
if (mediaController != null && (state = mediaController.getPlaybackState()) != null) {
diff --git a/app/src/play/java/de/danoeh/antennapod/dialog/RatingDialog.java b/app/src/play/java/de/danoeh/antennapod/dialog/RatingDialog.java
new file mode 100644
index 000000000..cfadf0772
--- /dev/null
+++ b/app/src/play/java/de/danoeh/antennapod/dialog/RatingDialog.java
@@ -0,0 +1,122 @@
+package de.danoeh.antennapod.dialog;
+
+import android.app.Activity;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import androidx.annotation.VisibleForTesting;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.TimeUnit;
+
+import com.google.android.play.core.review.ReviewInfo;
+import com.google.android.play.core.review.ReviewManager;
+import com.google.android.play.core.review.ReviewManagerFactory;
+import com.google.android.play.core.tasks.Task;
+
+public class RatingDialog {
+
+ private RatingDialog() {
+ }
+
+ private static final String TAG = RatingDialog.class.getSimpleName();
+ private static final int AFTER_DAYS = 14;
+
+ private static WeakReference<Context> mContext;
+ private static SharedPreferences mPreferences;
+
+ private static final String PREFS_NAME = "RatingPrefs";
+ private static final String KEY_RATED = "KEY_WAS_RATED";
+ private static final String KEY_FIRST_START_DATE = "KEY_FIRST_HIT_DATE";
+ private static final String KEY_NUMBER_OF_REVIEWS = "NUMBER_OF_REVIEW_ATTEMPTS";
+
+ public static void init(Context context) {
+ mContext = new WeakReference<>(context);
+ mPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+
+ long firstDate = mPreferences.getLong(KEY_FIRST_START_DATE, 0);
+ if (firstDate == 0) {
+ resetStartDate();
+ }
+ }
+
+ public static void check() {
+ if (shouldShow()) {
+ try {
+ showInAppReview();
+ } catch (Exception e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ }
+ }
+
+ private static void showInAppReview() {
+ Context context = mContext.get();
+ if (context == null) {
+ return;
+ }
+
+ ReviewManager manager = ReviewManagerFactory.create(context);
+ Task<ReviewInfo> request = manager.requestReviewFlow();
+
+ request.addOnCompleteListener(task -> {
+ if (task.isSuccessful()) {
+ ReviewInfo reviewInfo = task.getResult();
+ Task<Void> flow = manager.launchReviewFlow((Activity) context, reviewInfo);
+ flow.addOnCompleteListener(task1 -> {
+ int previousAttempts = mPreferences.getInt(KEY_NUMBER_OF_REVIEWS, 0);
+ if (previousAttempts >= 3) {
+ saveRated();
+ } else {
+ resetStartDate();
+ mPreferences
+ .edit()
+ .putInt(KEY_NUMBER_OF_REVIEWS, previousAttempts + 1)
+ .apply();
+ }
+ Log.i("ReviewDialog", "Successfully finished in-app review");
+ })
+ .addOnFailureListener(error -> {
+ Log.i("ReviewDialog", "failed in reviewing process");
+ });
+ }
+ })
+ .addOnFailureListener(error -> {
+ Log.i("ReviewDialog", "failed to get in-app review request");
+ });
+ }
+
+ private static boolean rated() {
+ return mPreferences.getBoolean(KEY_RATED, false);
+ }
+
+ @VisibleForTesting
+ public static void saveRated() {
+ mPreferences
+ .edit()
+ .putBoolean(KEY_RATED, true)
+ .apply();
+ }
+
+ private static void resetStartDate() {
+ mPreferences
+ .edit()
+ .putLong(KEY_FIRST_START_DATE, System.currentTimeMillis())
+ .apply();
+ }
+
+ private static boolean shouldShow() {
+ if (rated()) {
+ return false;
+ }
+
+ long now = System.currentTimeMillis();
+ long firstDate = mPreferences.getLong(KEY_FIRST_START_DATE, now);
+ long diff = now - firstDate;
+ long diffDays = TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
+ return diffDays >= AFTER_DAYS;
+ }
+}