From 25ddd73f244dc6444ed052942d763384f5c58cac Mon Sep 17 00:00:00 2001 From: GitStart <1501599+gitstart@users.noreply.github.com> Date: Wed, 22 Feb 2023 20:04:04 +0100 Subject: [PATCH] Add sort option to episodes screen (#6286) --- .../antennapod/playback/PlaybackTest.java | 7 ++- .../fragment/AllEpisodesFragment.java | 55 ++++++++++++++++++- .../fragment/EpisodesListFragment.java | 13 +---- app/src/main/res/menu/episodes.xml | 9 ++- .../export/favorites/FavoritesWriter.java | 3 +- .../service/playback/PlaybackService.java | 3 +- .../antennapod/core/storage/DBReader.java | 6 +- .../storage/database/PodDBAdapter.java | 8 ++- 8 files changed, 83 insertions(+), 21 deletions(-) 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 bb3c0bf67..426a30bb8 100644 --- a/app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java +++ b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java @@ -13,6 +13,7 @@ import androidx.test.rule.ActivityTestRule; import de.danoeh.antennapod.core.receiver.MediaButtonReceiver; import de.danoeh.antennapod.model.feed.FeedItemFilter; +import de.danoeh.antennapod.model.feed.SortOrder; import de.danoeh.antennapod.playback.base.PlayerStatus; import org.awaitility.Awaitility; import org.hamcrest.Matcher; @@ -252,7 +253,8 @@ public class PlaybackTest { openNavDrawer(); onDrawerItem(withText(R.string.episodes_label)).perform(click()); - final List episodes = DBReader.getRecentlyPublishedEpisodes(0, 10, FeedItemFilter.unfiltered()); + final List episodes = DBReader.getRecentlyPublishedEpisodes(0, 10, + FeedItemFilter.unfiltered(), SortOrder.DATE_NEW_OLD); Matcher allEpisodesMatcher = allOf(withId(R.id.recyclerView), isDisplayed(), hasMinimumChildCount(2)); onView(isRoot()).perform(waitForView(allEpisodesMatcher, 1000)); onView(allEpisodesMatcher).perform(actionOnItemAtPosition(0, clickChildViewWithId(R.id.secondaryActionButton))); @@ -287,7 +289,8 @@ public class PlaybackTest { uiTestUtils.addLocalFeedData(true); DBWriter.clearQueue().get(); activityTestRule.launchActivity(new Intent()); - final List episodes = DBReader.getRecentlyPublishedEpisodes(0, 10, FeedItemFilter.unfiltered()); + final List episodes = DBReader.getRecentlyPublishedEpisodes(0, 10, + FeedItemFilter.unfiltered(), SortOrder.DATE_NEW_OLD); startLocalPlayback(); FeedMedia media = episodes.get(0).getMedia(); 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 dbf314876..dfbaf9695 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -9,13 +9,17 @@ import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.dialog.AllEpisodesFilterDialog; +import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedItemFilter; +import de.danoeh.antennapod.model.feed.SortOrder; import org.apache.commons.lang3.StringUtils; import org.greenrobot.eventbus.Subscribe; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; /** * Shows all episodes (possibly filtered by user). @@ -24,20 +28,55 @@ public class AllEpisodesFragment extends EpisodesListFragment { public static final String TAG = "EpisodesFragment"; private static final String PREF_NAME = "PrefAllEpisodesFragment"; private static final String PREF_FILTER = "filter"; + public static final String PREF_SORT = "prefEpisodesSort"; + private SharedPreferences prefs; @NonNull @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View root = super.onCreateView(inflater, container, savedInstanceState); toolbar.inflateMenu(R.menu.episodes); + inflateSortMenu(); toolbar.setTitle(R.string.episodes_label); updateToolbar(); updateFilterUi(); + prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); txtvInformation.setOnClickListener( v -> AllEpisodesFilterDialog.newInstance(getFilter()).show(getChildFragmentManager(), null)); return root; } + private void inflateSortMenu() { + MenuItem sortItem = toolbar.getMenu().findItem(R.id.episodes_sort); + getActivity().getMenuInflater().inflate(R.menu.sort_menu, sortItem.getSubMenu()); + + // Remove the sorting options that are not needed in this fragment + toolbar.getMenu().findItem(R.id.sort_episode_title).setVisible(false); + toolbar.getMenu().findItem(R.id.sort_feed_title).setVisible(false); + toolbar.getMenu().findItem(R.id.sort_random).setVisible(false); + toolbar.getMenu().findItem(R.id.sort_smart_shuffle).setVisible(false); + toolbar.getMenu().findItem(R.id.keep_sorted).setVisible(false); + } + + @NonNull + @Override + protected List loadData() { + return DBReader.getRecentlyPublishedEpisodes(0, page * EPISODES_PER_PAGE, + getFilter(), getSortOrder()); + } + + @NonNull + @Override + protected List loadMoreData(int page) { + return DBReader.getRecentlyPublishedEpisodes((page - 1) * EPISODES_PER_PAGE, + EPISODES_PER_PAGE, getFilter(), getSortOrder()); + } + + @Override + protected int loadTotalItemCount() { + return DBReader.getTotalEpisodeCount(getFilter()); + } + @Override protected FeedItemFilter getFilter() { SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); @@ -71,13 +110,23 @@ public class AllEpisodesFragment extends EpisodesListFragment { } onFilterChanged(new AllEpisodesFilterDialog.AllEpisodesFilterChangedEvent(new HashSet<>(filter))); return true; + } else { + SortOrder sortOrder = MenuItemToSortOrderConverter.convert(item); + if (sortOrder != null) { + saveSortOrderAndRefresh(sortOrder); + return true; + } } return false; } + private void saveSortOrderAndRefresh(SortOrder type) { + prefs.edit().putString(PREF_SORT, "" + type.code).apply(); + loadItems(); + } + @Subscribe public void onFilterChanged(AllEpisodesFilterDialog.AllEpisodesFilterChangedEvent event) { - SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); prefs.edit().putString(PREF_FILTER, StringUtils.join(event.filterValues, ",")).apply(); updateFilterUi(); page = 1; @@ -96,4 +145,8 @@ public class AllEpisodesFragment extends EpisodesListFragment { toolbar.getMenu().findItem(R.id.action_favorites).setIcon( getFilter().showIsFavorite ? R.drawable.ic_star : R.drawable.ic_star_border); } + + private SortOrder getSortOrder() { + return SortOrder.fromCodeString(prefs.getString(PREF_SORT, "" + SortOrder.DATE_NEW_OLD.code)); + } } 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 1384b5d78..5ba323372 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -31,7 +31,6 @@ import de.danoeh.antennapod.core.event.DownloadEvent; import de.danoeh.antennapod.core.event.DownloaderUpdate; import de.danoeh.antennapod.core.menuhandler.MenuItemUtils; import de.danoeh.antennapod.core.service.download.DownloadService; -import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.util.FeedItemUtil; import de.danoeh.antennapod.core.util.download.AutoUpdateManager; import de.danoeh.antennapod.event.FeedItemEvent; @@ -442,18 +441,12 @@ public abstract class EpisodesListFragment extends Fragment } @NonNull - protected List loadData() { - return DBReader.getRecentlyPublishedEpisodes(0, page * EPISODES_PER_PAGE, getFilter()); - } + protected abstract List loadData(); @NonNull - protected List loadMoreData(int page) { - return DBReader.getRecentlyPublishedEpisodes((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE, getFilter()); - } + protected abstract List loadMoreData(int page); - protected int loadTotalItemCount() { - return DBReader.getTotalEpisodeCount(getFilter()); - } + protected abstract int loadTotalItemCount(); protected abstract FeedItemFilter getFilter(); diff --git a/app/src/main/res/menu/episodes.xml b/app/src/main/res/menu/episodes.xml index 2841fc12f..358573c93 100644 --- a/app/src/main/res/menu/episodes.xml +++ b/app/src/main/res/menu/episodes.xml @@ -21,7 +21,7 @@ android:icon="@drawable/ic_filter" android:menuCategory="container" android:title="@string/filter" - custom:showAsAction="always"/> + custom:showAsAction="ifRoom"/> + + + + diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java b/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java index 092329229..5ccfc93fe 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java @@ -18,6 +18,7 @@ import de.danoeh.antennapod.core.export.ExportWriter; import de.danoeh.antennapod.model.feed.Feed; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.model.feed.SortOrder; /** Writes saved favorites to file. */ public class FavoritesWriter implements ExportWriter { @@ -43,7 +44,7 @@ public class FavoritesWriter implements ExportWriter { String feedTemplate = IOUtils.toString(feedTemplateStream, UTF_8); List allFavorites = DBReader.getRecentlyPublishedEpisodes(0, Integer.MAX_VALUE, - new FeedItemFilter(FeedItemFilter.IS_FAVORITE)); + new FeedItemFilter(FeedItemFilter.IS_FAVORITE), SortOrder.DATE_NEW_OLD); Map> favoriteByFeed = getFeedMap(allFavorites); writer.append(templateParts[0]); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index 176a78f0f..36a056c5d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -52,6 +52,7 @@ import de.danoeh.antennapod.event.playback.PlaybackServiceEvent; import de.danoeh.antennapod.event.PlayerErrorEvent; import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent; import de.danoeh.antennapod.model.feed.FeedItemFilter; +import de.danoeh.antennapod.model.feed.SortOrder; import de.danoeh.antennapod.playback.base.PlaybackServiceMediaPlayer; import de.danoeh.antennapod.playback.base.PlayerStatus; import de.danoeh.antennapod.playback.cast.CastPsmp; @@ -417,7 +418,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { } else if (parentId.equals(getResources().getString(R.string.episodes_label))) { feedItems = DBReader.getRecentlyPublishedEpisodes(0, MAX_ANDROID_AUTO_EPISODES_PER_FEED, - new FeedItemFilter(FeedItemFilter.UNPLAYED)); + new FeedItemFilter(FeedItemFilter.UNPLAYED), SortOrder.DATE_NEW_OLD); } else if (parentId.startsWith("FeedId:")) { long feedId = Long.parseLong(parentId.split(":")[1]); feedItems = DBReader.getFeedItemList(DBReader.getFeed(feedId)); diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index 4641e366c..62b1db3cb 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -366,12 +366,12 @@ public final class DBReader { * @param filter The filter describing which episodes to filter out. */ @NonNull - public static List getRecentlyPublishedEpisodes(int offset, int limit, FeedItemFilter filter) { + public static List getRecentlyPublishedEpisodes(int offset, int limit, + FeedItemFilter filter, SortOrder sortOrder) { Log.d(TAG, "getRecentlyPublishedEpisodes() called with: offset=" + offset + ", limit=" + limit); - PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - try (Cursor cursor = adapter.getRecentlyPublishedItemsCursor(offset, limit, filter)) { + try (Cursor cursor = adapter.getRecentlyPublishedItemsCursor(offset, limit, filter, sortOrder)) { List items = extractItemlistFromCursor(adapter, cursor); loadAdditionalFeedItemListData(items); return items; diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java index bcb57f3bb..bb0218a0b 100644 --- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java +++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java @@ -45,6 +45,8 @@ import org.apache.commons.io.FileUtils; import static de.danoeh.antennapod.model.feed.FeedPreferences.SPEED_USE_GLOBAL; import static de.danoeh.antennapod.model.feed.SortOrder.toCodeString; +import de.danoeh.antennapod.storage.database.mapper.FeedItemSortQuery; + /** * Implements methods for accessing the database */ @@ -1059,11 +1061,13 @@ public class PodDBAdapter { return db.rawQuery(query, null); } - public final Cursor getRecentlyPublishedItemsCursor(int offset, int limit, FeedItemFilter filter) { + public final Cursor getRecentlyPublishedItemsCursor(int offset, int limit, + FeedItemFilter filter, SortOrder sortOrder) { + String orderByQuery = FeedItemSortQuery.generateFrom(sortOrder); String filterQuery = FeedItemFilterQuery.generateFrom(filter); String whereClause = "".equals(filterQuery) ? "" : " WHERE " + filterQuery; final String query = SELECT_FEED_ITEMS_AND_MEDIA + whereClause - + " ORDER BY " + KEY_PUBDATE + " DESC LIMIT " + offset + ", " + limit; + + "ORDER BY " + orderByQuery + " LIMIT " + offset + ", " + limit; return db.rawQuery(query, null); }