From 1fa0c32142c0c288adf8784c6c032ae3fa4a6611 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 7 May 2022 10:52:45 +0200 Subject: [PATCH 1/7] Multi-Select on 'All episodes' screen --- .../fragment/EpisodesListFragment.java | 65 ++++++++++++++++--- .../antennapod/fragment/InboxFragment.java | 3 + .../main/res/layout/all_episodes_fragment.xml | 33 +++++----- 3 files changed, 78 insertions(+), 23 deletions(-) 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 b658e5f08..d47544e6f 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -22,12 +22,15 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; +import com.google.android.material.snackbar.Snackbar; +import com.leinardi.android.speeddial.SpeedDialView; import de.danoeh.antennapod.adapter.EpisodeItemListAdapter; import de.danoeh.antennapod.event.FeedListUpdateEvent; import de.danoeh.antennapod.event.playback.PlaybackPositionEvent; import de.danoeh.antennapod.event.PlayerStatusEvent; import de.danoeh.antennapod.event.UnreadItemsUpdateEvent; import de.danoeh.antennapod.core.menuhandler.MenuItemUtils; +import de.danoeh.antennapod.fragment.actions.EpisodeMultiSelectActionHandler; import de.danoeh.antennapod.ui.common.PagedToolbarFragment; import de.danoeh.antennapod.view.EpisodeItemListRecyclerView; import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; @@ -59,7 +62,7 @@ import io.reactivex.schedulers.Schedulers; /** * Shows unread or recently published episodes */ -public abstract class EpisodesListFragment extends Fragment { +public abstract class EpisodesListFragment extends Fragment implements EpisodeItemListAdapter.OnSelectModeListener { public static final String TAG = "EpisodesListFragment"; protected static final int EPISODES_PER_PAGE = 150; @@ -72,6 +75,7 @@ public abstract class EpisodesListFragment extends Fragment { ProgressBar progLoading; View loadingMoreView; EmptyViewHandler emptyView; + SpeedDialView speedDialView; @NonNull List episodes = new ArrayList<>(); @@ -174,17 +178,13 @@ public abstract class EpisodesListFragment extends Fragment { // The method is called on all fragments in a ViewPager, so this needs to be ignored in invisible ones. // Apparently, none of the visibility check method works reliably on its own, so we just use all. return false; - } - if (item.getItemId() == R.id.share_item) { - return true; // avoids that the position is reset when we need it in the submenu - } - - if (listAdapter.getLongPressedItem() == null) { + } else if (listAdapter.getLongPressedItem() == null) { Log.i(TAG, "Selected item or listAdapter was null, ignoring selection"); return super.onContextItemSelected(item); + } else if (listAdapter.onContextItemSelected(item)) { + return true; } FeedItem selectedItem = listAdapter.getLongPressedItem(); - return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem); } @@ -225,6 +225,31 @@ public abstract class EpisodesListFragment extends Fragment { createRecycleAdapter(recyclerView, emptyView); emptyView.hide(); + speedDialView = root.findViewById(R.id.fabSD); + speedDialView.setOverlayLayout(root.findViewById(R.id.fabSDOverlay)); + speedDialView.inflate(R.menu.episodes_apply_action_speeddial); + speedDialView.setOnChangeListener(new SpeedDialView.OnChangeListener() { + @Override + public boolean onMainActionSelected() { + return false; + } + + @Override + public void onToggleChanged(boolean open) { + if (open && listAdapter.getSelectedCount() == 0) { + ((MainActivity) getActivity()).showSnackbarAbovePlayer(R.string.no_items_selected, + Snackbar.LENGTH_SHORT); + speedDialView.close(); + } + } + }); + speedDialView.setOnActionSelectedListener(actionItem -> { + new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), listAdapter.getSelectedItems()) + .handleAction(actionItem.getId()); + listAdapter.endSelectMode(); + return true; + }); + return root; } @@ -292,14 +317,38 @@ public abstract class EpisodesListFragment extends Fragment { @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); + if (!inActionMode()) { + menu.findItem(R.id.multi_select).setVisible(true); + } MenuItemUtils.setOnClickListeners(menu, EpisodesListFragment.this::onContextItemSelected); } }; + listAdapter.setOnSelectModeListener(this); listAdapter.updateItems(episodes); recyclerView.setAdapter(listAdapter); emptyViewHandler.updateAdapter(listAdapter); } + @Override + public void onDestroyView() { + super.onDestroyView(); + if (listAdapter != null) { + listAdapter.endSelectMode(); + } + listAdapter = null; + } + + @Override + public void onStartSelectMode() { + speedDialView.setVisibility(View.VISIBLE); + } + + @Override + public void onEndSelectMode() { + speedDialView.close(); + speedDialView.setVisibility(View.GONE); + } + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(FeedItemEvent event) { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java index abb04b2f3..5063da9a4 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java @@ -67,6 +67,9 @@ public class InboxFragment extends EpisodesListFragment implements Toolbar.OnMen SwipeActions swipeActions = new SwipeActions(this, TAG).attachTo(recyclerView); swipeActions.setFilter(new FeedItemFilter(FeedItemFilter.NEW)); + speedDialView.removeActionItemById(R.id.mark_unread_batch); + speedDialView.removeActionItemById(R.id.remove_from_queue_batch); + speedDialView.removeActionItemById(R.id.delete_batch); return inboxContainer; } diff --git a/app/src/main/res/layout/all_episodes_fragment.xml b/app/src/main/res/layout/all_episodes_fragment.xml index 3b560967c..c1e7e6434 100644 --- a/app/src/main/res/layout/all_episodes_fragment.xml +++ b/app/src/main/res/layout/all_episodes_fragment.xml @@ -2,9 +2,9 @@ + android:layout_height="match_parent" + android:orientation="vertical"> - + @@ -45,7 +45,7 @@ android:indeterminateOnly="true" android:visibility="gone" android:layout_centerInParent="true" - tools:background="@android:color/holo_red_light"/> + tools:background="@android:color/holo_red_light" /> - \ No newline at end of file + + + From 7c0d084ffcc6a17ccac043a76f6640c89dea6272 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 8 May 2022 10:21:39 +0200 Subject: [PATCH 2/7] Automatically select lazy loaded items if necessary --- .../adapter/EpisodeItemListAdapter.java | 2 ++ .../antennapod/adapter/SelectableAdapter.java | 16 ++++++++++++---- .../fragment/EpisodesListFragment.java | 3 +++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java index 53223896f..8fb4a6314 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java @@ -48,6 +48,7 @@ public class EpisodeItemListAdapter extends SelectableAdapter items) { episodes = items; notifyDataSetChanged(); + updateTitle(); } @Override @@ -195,6 +196,7 @@ public class EpisodeItemListAdapter extends SelectableAdapter extends Recy private final HashSet selectedIds = new HashSet<>(); private final Activity activity; private OnSelectModeListener onSelectModeListener; + boolean shouldSelectLazyLoadedItems = false; public SelectableAdapter(Activity activity) { this.activity = activity; @@ -34,6 +35,7 @@ abstract class SelectableAdapter extends Recy onSelectModeListener.onStartSelectMode(); } + shouldSelectLazyLoadedItems = false; selectedIds.clear(); selectedIds.add(getItemId(pos)); notifyDataSetChanged(); @@ -56,9 +58,10 @@ abstract class SelectableAdapter extends Recy @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (item.getItemId() == R.id.select_toggle) { - boolean allSelected = selectedIds.size() == getItemCount(); - setSelected(0, getItemCount(), !allSelected); - toggleSelectAllIcon(item, !allSelected); + boolean selectAll = selectedIds.size() != getItemCount(); + shouldSelectLazyLoadedItems = selectAll; + setSelected(0, getItemCount(), selectAll); + toggleSelectAllIcon(item, selectAll); updateTitle(); return true; } @@ -69,6 +72,7 @@ abstract class SelectableAdapter extends Recy public void onDestroyActionMode(ActionMode mode) { callOnEndSelectMode(); actionMode = null; + shouldSelectLazyLoadedItems = false; selectedIds.clear(); notifyDataSetChanged(); } @@ -147,7 +151,7 @@ abstract class SelectableAdapter extends Recy } } - private void updateTitle() { + void updateTitle() { if (actionMode == null) { return; } @@ -166,6 +170,10 @@ abstract class SelectableAdapter extends Recy } } + public boolean shouldSelectLazyLoadedItems() { + return shouldSelectLazyLoadedItems; + } + public interface OnSelectModeListener { void onStartSelectMode(); 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 d47544e6f..55134cbfa 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -283,6 +283,9 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt } episodes.addAll(data); onFragmentLoaded(episodes); + if (listAdapter.shouldSelectLazyLoadedItems()) { + listAdapter.setSelected(episodes.size() - data.size(), episodes.size(), true); + } }, error -> Log.e(TAG, Log.getStackTraceString(error)), () -> { recyclerView.post(() -> isLoadingMore = false); // Make sure to not always load 2 pages at once From 03220d07748d0908c4cf4e6b260ce828dc5ebaac Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 8 May 2022 10:55:05 +0200 Subject: [PATCH 3/7] Show correct total number for lazy loaded items --- .../adapter/EpisodeItemListAdapter.java | 2 +- .../antennapod/adapter/SelectableAdapter.java | 22 +++++++++++++++++-- .../fragment/AllEpisodesFragment.java | 5 +++++ .../fragment/EpisodesListFragment.java | 14 ++++++++++-- .../fragment/FavoriteEpisodesFragment.java | 6 +++++ .../antennapod/fragment/InboxFragment.java | 5 +++++ .../antennapod/core/storage/DBReader.java | 13 +++++++++++ .../storage/database/PodDBAdapter.java | 8 +++++++ .../database/mapper/FeedItemFilterQuery.java | 2 ++ 9 files changed, 72 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java index 8fb4a6314..088caf70a 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java @@ -195,8 +195,8 @@ public class EpisodeItemListAdapter extends SelectableAdapter extends RecyclerView.Adapter { +public abstract class SelectableAdapter extends RecyclerView.Adapter { + public static final int COUNT_AUTOMATICALLY = -1; private ActionMode actionMode; private final HashSet selectedIds = new HashSet<>(); private final Activity activity; private OnSelectModeListener onSelectModeListener; boolean shouldSelectLazyLoadedItems = false; + private int totalNumberOfItems = COUNT_AUTOMATICALLY; public SelectableAdapter(Activity activity) { this.activity = activity; @@ -155,9 +157,17 @@ abstract class SelectableAdapter extends Recy if (actionMode == null) { return; } + int totalCount = getItemCount(); + int selectedCount = selectedIds.size(); + if (totalNumberOfItems != COUNT_AUTOMATICALLY) { + totalCount = totalNumberOfItems; + if (shouldSelectLazyLoadedItems) { + selectedCount += (totalNumberOfItems - getItemCount()); + } + } actionMode.setTitle(activity.getResources() .getQuantityString(R.plurals.num_selected_label, selectedIds.size(), - selectedIds.size(), getItemCount())); + selectedCount, totalCount)); } public void setOnSelectModeListener(OnSelectModeListener onSelectModeListener) { @@ -174,6 +184,14 @@ abstract class SelectableAdapter extends Recy return shouldSelectLazyLoadedItems; } + /** + * Sets the total number of items that could be lazy-loaded. + * Can also be set to {@link #COUNT_AUTOMATICALLY} to simply use {@link #getItemCount} + */ + public void setTotalNumberOfItems(int totalNumberOfItems) { + this.totalNumberOfItems = totalNumberOfItems; + } + public interface OnSelectModeListener { void onStartSelectMode(); 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 853e7d6f7..2627da3d9 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -105,4 +105,9 @@ public class AllEpisodesFragment extends EpisodesListFragment { protected List loadMoreData() { return DBReader.getRecentlyPublishedEpisodes((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE, feedItemFilter); } + + @Override + protected int loadTotalItemCount() { + return DBReader.getTotalEpisodeCount(feedItemFilter); + } } 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 55134cbfa..e47599e3b 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -5,6 +5,7 @@ import android.os.Bundle; import android.view.ContextMenu; import android.view.KeyEvent; import androidx.annotation.NonNull; +import androidx.core.util.Pair; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.SimpleItemAnimator; @@ -25,6 +26,7 @@ import android.widget.Toast; import com.google.android.material.snackbar.Snackbar; import com.leinardi.android.speeddial.SpeedDialView; import de.danoeh.antennapod.adapter.EpisodeItemListAdapter; +import de.danoeh.antennapod.adapter.SelectableAdapter; import de.danoeh.antennapod.event.FeedListUpdateEvent; import de.danoeh.antennapod.event.playback.PlaybackPositionEvent; import de.danoeh.antennapod.event.PlayerStatusEvent; @@ -447,14 +449,15 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt if (disposable != null) { disposable.dispose(); } - disposable = Observable.fromCallable(this::loadData) + disposable = Observable.fromCallable(() -> new Pair<>(loadData(), loadTotalItemCount())) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(data -> { progLoading.setVisibility(View.GONE); loadingMoreView.setVisibility(View.GONE); hasMoreItems = true; - episodes = data; + episodes = data.first; + listAdapter.setTotalNumberOfItems(data.second); onFragmentLoaded(episodes); if (getParentFragment() instanceof PagedToolbarFragment) { ((PagedToolbarFragment) getParentFragment()).invalidateOptionsMenuIfActive(this); @@ -475,4 +478,11 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt */ @NonNull protected abstract List loadMoreData(); + + /** + * Returns the total number of items that would be returned if {@link #loadMoreData} was called often enough. + */ + protected int loadTotalItemCount() { + return SelectableAdapter.COUNT_AUTOMATICALLY; + } } 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 33aba3b54..56b2b433f 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java @@ -12,6 +12,7 @@ import android.view.View; import android.view.ViewGroup; import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.model.feed.FeedItemFilter; import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; import org.greenrobot.eventbus.Subscribe; @@ -101,4 +102,9 @@ public class FavoriteEpisodesFragment extends EpisodesListFragment { protected List loadMoreData() { return DBReader.getFavoriteItemsList((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE); } + + @Override + protected int loadTotalItemCount() { + return DBReader.getTotalEpisodeCount(new FeedItemFilter(FeedItemFilter.IS_FAVORITE)); + } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java index 5063da9a4..14bfe2951 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java @@ -119,4 +119,9 @@ public class InboxFragment extends EpisodesListFragment implements Toolbar.OnMen protected List loadMoreData() { return DBReader.getNewItemsList((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE); } + + @Override + protected int loadTotalItemCount() { + return DBReader.getTotalEpisodeCount(new FeedItemFilter(FeedItemFilter.NEW)); + } } 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 a55aed9df..cffcbf32f 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 @@ -402,6 +402,19 @@ public final class DBReader { } } + public static int getTotalEpisodeCount(FeedItemFilter filter) { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + try (Cursor cursor = adapter.getTotalEpisodeCountCursor(filter)) { + if (cursor.moveToFirst()) { + return cursor.getInt(0); + } + return -1; + } finally { + adapter.close(); + } + } + /** * Loads the playback history from the database. A FeedItem is in the playback history if playback of the correpsonding episode * has been completed at least once. 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 3f361eb89..41c8e051a 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 @@ -1052,6 +1052,14 @@ public class PodDBAdapter { return db.rawQuery(query, null); } + public final Cursor getTotalEpisodeCountCursor(FeedItemFilter filter) { + String filterQuery = FeedItemFilterQuery.generateFrom(filter); + String whereClause = "".equals(filterQuery) ? "" : " WHERE " + filterQuery; + final String query = "SELECT count(" + TABLE_NAME_FEED_ITEMS + "." + KEY_ID + ") FROM " + TABLE_NAME_FEED_ITEMS + + JOIN_FEED_ITEM_AND_MEDIA + whereClause; + return db.rawQuery(query, null); + } + public Cursor getDownloadedItemsCursor() { final String query = SELECT_FEED_ITEMS_AND_MEDIA + "WHERE " + TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + " > 0"; diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemFilterQuery.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemFilterQuery.java index 1728a905f..6c78af50c 100644 --- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemFilterQuery.java +++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemFilterQuery.java @@ -34,6 +34,8 @@ public class FeedItemFilterQuery { statements.add(keyRead + " = 1 "); } else if (filter.showUnplayed) { statements.add(" NOT " + keyRead + " = 1 "); // Match "New" items (read = -1) as well + } else if (filter.showNew) { + statements.add(keyRead + " = -1 "); } if (filter.showPaused) { statements.add(" (" + keyPosition + " NOT NULL AND " + keyPosition + " > 0 " + ") "); From 072e172996ea82af8ac56880ad56714197d3fe7c Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 8 May 2022 11:08:34 +0200 Subject: [PATCH 4/7] Switch around arguments in MultiSelectActionHandler --- .../fragment/CompletedDownloadsFragment.java | 4 +- .../fragment/EpisodesListFragment.java | 4 +- .../fragment/FeedItemlistFragment.java | 4 +- .../antennapod/fragment/QueueFragment.java | 4 +- .../EpisodeMultiSelectActionHandler.java | 79 ++++++++++--------- 5 files changed, 51 insertions(+), 44 deletions(-) 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 22a7a877c..cab7ba452 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java @@ -115,8 +115,8 @@ public class CompletedDownloadsFragment extends Fragment } }); speedDialView.setOnActionSelectedListener(actionItem -> { - new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), adapter.getSelectedItems()) - .handleAction(actionItem.getId()); + new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), actionItem.getId()) + .handleAction(adapter.getSelectedItems()); adapter.endSelectMode(); return true; }); 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 e47599e3b..06c8148e5 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -246,8 +246,8 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt } }); speedDialView.setOnActionSelectedListener(actionItem -> { - new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), listAdapter.getSelectedItems()) - .handleAction(actionItem.getId()); + new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), actionItem.getId()) + .handleAction(listAdapter.getSelectedItems()); listAdapter.endSelectMode(); return true; }); 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 a42abd724..80a65e518 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -197,8 +197,8 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem } }); speedDialBinding.fabSD.setOnActionSelectedListener(actionItem -> { - new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), adapter.getSelectedItems()) - .handleAction(actionItem.getId()); + new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), actionItem.getId()) + .handleAction(adapter.getSelectedItems()); adapter.endSelectMode(); return true; }); 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 2a89519a5..61f45f0f9 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -505,8 +505,8 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi } }); speedDialView.setOnActionSelectedListener(actionItem -> { - new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), recyclerAdapter.getSelectedItems()) - .handleAction(actionItem.getId()); + new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), actionItem.getId()) + .handleAction(recyclerAdapter.getSelectedItems()); recyclerAdapter.endSelectMode(); return true; }); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/actions/EpisodeMultiSelectActionHandler.java b/app/src/main/java/de/danoeh/antennapod/fragment/actions/EpisodeMultiSelectActionHandler.java index 17642874e..aad611e5d 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/actions/EpisodeMultiSelectActionHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/actions/EpisodeMultiSelectActionHandler.java @@ -21,35 +21,37 @@ import de.danoeh.antennapod.model.feed.FeedItem; public class EpisodeMultiSelectActionHandler { private static final String TAG = "EpisodeSelectHandler"; private final MainActivity activity; - private final List selectedItems; + private final int actionId; + private int totalNumItems = 0; + private Snackbar snackbar = null; - public EpisodeMultiSelectActionHandler(MainActivity activity, List selectedItems) { + public EpisodeMultiSelectActionHandler(MainActivity activity, int actionId) { this.activity = activity; - this.selectedItems = selectedItems; + this.actionId = actionId; } - public void handleAction(int id) { - if (id == R.id.add_to_queue_batch) { - queueChecked(); - } else if (id == R.id.remove_from_queue_batch) { - removeFromQueueChecked(); - } else if (id == R.id.mark_read_batch) { - markedCheckedPlayed(); - } else if (id == R.id.mark_unread_batch) { - markedCheckedUnplayed(); - } else if (id == R.id.download_batch) { - downloadChecked(); - } else if (id == R.id.delete_batch) { - deleteChecked(); + public void handleAction(List items) { + if (actionId == R.id.add_to_queue_batch) { + queueChecked(items); + } else if (actionId == R.id.remove_from_queue_batch) { + removeFromQueueChecked(items); + } else if (actionId == R.id.mark_read_batch) { + markedCheckedPlayed(items); + } else if (actionId == R.id.mark_unread_batch) { + markedCheckedUnplayed(items); + } else if (actionId == R.id.download_batch) { + downloadChecked(items); + } else if (actionId == R.id.delete_batch) { + deleteChecked(items); } else { - Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=" + id); + Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=" + actionId); } } - private void queueChecked() { + private void queueChecked(List items) { // Check if an episode actually contains any media files before adding it to queue - LongList toQueue = new LongList(selectedItems.size()); - for (FeedItem episode : selectedItems) { + LongList toQueue = new LongList(items.size()); + for (FeedItem episode : items) { if (episode.hasMedia()) { toQueue.add(episode.getId()); } @@ -58,28 +60,28 @@ public class EpisodeMultiSelectActionHandler { showMessage(R.plurals.added_to_queue_batch_label, toQueue.size()); } - private void removeFromQueueChecked() { - long[] checkedIds = getSelectedIds(); + private void removeFromQueueChecked(List items) { + long[] checkedIds = getSelectedIds(items); DBWriter.removeQueueItem(activity, true, checkedIds); showMessage(R.plurals.removed_from_queue_batch_label, checkedIds.length); } - private void markedCheckedPlayed() { - long[] checkedIds = getSelectedIds(); + private void markedCheckedPlayed(List items) { + long[] checkedIds = getSelectedIds(items); DBWriter.markItemPlayed(FeedItem.PLAYED, checkedIds); showMessage(R.plurals.marked_read_batch_label, checkedIds.length); } - private void markedCheckedUnplayed() { - long[] checkedIds = getSelectedIds(); + private void markedCheckedUnplayed(List items) { + long[] checkedIds = getSelectedIds(items); DBWriter.markItemPlayed(FeedItem.UNPLAYED, checkedIds); showMessage(R.plurals.marked_unread_batch_label, checkedIds.length); } - private void downloadChecked() { + private void downloadChecked(List items) { // download the check episodes in the same order as they are currently displayed List requests = new ArrayList<>(); - for (FeedItem episode : selectedItems) { + for (FeedItem episode : items) { if (episode.hasMedia() && !episode.getFeed().isLocalFeed()) { requests.add(DownloadRequestCreator.create(episode.getMedia()).build()); } @@ -88,9 +90,9 @@ public class EpisodeMultiSelectActionHandler { showMessage(R.plurals.downloading_batch_label, requests.size()); } - private void deleteChecked() { + private void deleteChecked(List items) { int countHasMedia = 0; - for (FeedItem feedItem : selectedItems) { + for (FeedItem feedItem : items) { if (feedItem.hasMedia() && feedItem.getMedia().isDownloaded()) { countHasMedia++; DBWriter.deleteFeedMediaOfItem(activity, feedItem.getMedia().getId()); @@ -100,14 +102,19 @@ public class EpisodeMultiSelectActionHandler { } private void showMessage(@PluralsRes int msgId, int numItems) { - activity.showSnackbarAbovePlayer(activity.getResources() - .getQuantityString(msgId, numItems, numItems), Snackbar.LENGTH_LONG); + totalNumItems += numItems; + String text = activity.getResources().getQuantityString(msgId, totalNumItems, totalNumItems); + if (snackbar != null) { + snackbar.setText(text); + } else { + snackbar = activity.showSnackbarAbovePlayer(text, Snackbar.LENGTH_LONG); + } } - private long[] getSelectedIds() { - long[] checkedIds = new long[selectedItems.size()]; - for (int i = 0; i < selectedItems.size(); ++i) { - checkedIds[i] = selectedItems.get(i).getId(); + private long[] getSelectedIds(List items) { + long[] checkedIds = new long[items.size()]; + for (int i = 0; i < items.size(); ++i) { + checkedIds[i] = items.get(i).getId(); } return checkedIds; } From 2e999aef6271664578f95a9cf2a365857525b4ac Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 8 May 2022 11:18:11 +0200 Subject: [PATCH 5/7] Apply action to items that are not loaded yet --- .../fragment/AllEpisodesFragment.java | 2 +- .../fragment/EpisodesListFragment.java | 27 +++++++++++++++---- .../fragment/FavoriteEpisodesFragment.java | 2 +- .../antennapod/fragment/InboxFragment.java | 2 +- .../EpisodeMultiSelectActionHandler.java | 15 ++++++----- 5 files changed, 34 insertions(+), 14 deletions(-) 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 2627da3d9..51dcb664c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -102,7 +102,7 @@ public class AllEpisodesFragment extends EpisodesListFragment { @NonNull @Override - protected List loadMoreData() { + protected List loadMoreData(int page) { return DBReader.getRecentlyPublishedEpisodes((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE, feedItemFilter); } 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 06c8148e5..9409c7c3a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -36,6 +36,7 @@ import de.danoeh.antennapod.fragment.actions.EpisodeMultiSelectActionHandler; import de.danoeh.antennapod.ui.common.PagedToolbarFragment; import de.danoeh.antennapod.view.EpisodeItemListRecyclerView; import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; +import io.reactivex.Completable; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -246,9 +247,25 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt } }); speedDialView.setOnActionSelectedListener(actionItem -> { - new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), actionItem.getId()) - .handleAction(listAdapter.getSelectedItems()); - listAdapter.endSelectMode(); + EpisodeMultiSelectActionHandler handler = + new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), actionItem.getId()); + Completable.fromAction( + () -> { + handler.handleAction(listAdapter.getSelectedItems()); + if (listAdapter.shouldSelectLazyLoadedItems()) { + int applyPage = page + 1; + List nextPage; + do { + nextPage = loadMoreData(applyPage); + handler.handleAction(nextPage); + applyPage++; + } while (nextPage.size() == EPISODES_PER_PAGE); + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(() -> listAdapter.endSelectMode(), + error -> Log.e(TAG, Log.getStackTraceString(error))); return true; }); @@ -276,7 +293,7 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt } isLoadingMore = true; loadingMoreView.setVisibility(View.VISIBLE); - disposable = Observable.fromCallable(this::loadMoreData) + disposable = Observable.fromCallable(() -> loadMoreData(page)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(data -> { @@ -477,7 +494,7 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt * @return The items from the next page of data */ @NonNull - protected abstract List loadMoreData(); + protected abstract List loadMoreData(int page); /** * Returns the total number of items that would be returned if {@link #loadMoreData} was called often enough. 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 56b2b433f..cc45a7d35 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java @@ -99,7 +99,7 @@ public class FavoriteEpisodesFragment extends EpisodesListFragment { @NonNull @Override - protected List loadMoreData() { + protected List loadMoreData(int page) { return DBReader.getFavoriteItemsList((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java index 14bfe2951..067e7466c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java @@ -116,7 +116,7 @@ public class InboxFragment extends EpisodesListFragment implements Toolbar.OnMen @NonNull @Override - protected List loadMoreData() { + protected List loadMoreData(int page) { return DBReader.getNewItemsList((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/actions/EpisodeMultiSelectActionHandler.java b/app/src/main/java/de/danoeh/antennapod/fragment/actions/EpisodeMultiSelectActionHandler.java index aad611e5d..0dc416e0e 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/actions/EpisodeMultiSelectActionHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/actions/EpisodeMultiSelectActionHandler.java @@ -103,12 +103,15 @@ public class EpisodeMultiSelectActionHandler { private void showMessage(@PluralsRes int msgId, int numItems) { totalNumItems += numItems; - String text = activity.getResources().getQuantityString(msgId, totalNumItems, totalNumItems); - if (snackbar != null) { - snackbar.setText(text); - } else { - snackbar = activity.showSnackbarAbovePlayer(text, Snackbar.LENGTH_LONG); - } + activity.runOnUiThread(() -> { + String text = activity.getResources().getQuantityString(msgId, totalNumItems, totalNumItems); + if (snackbar != null) { + snackbar.setText(text); + snackbar.show(); // Resets the timeout + } else { + snackbar = activity.showSnackbarAbovePlayer(text, Snackbar.LENGTH_LONG); + } + }); } private long[] getSelectedIds(List items) { From 934e2802f8a6f9552489726ef1a43f1476eda233 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 8 May 2022 11:24:59 +0200 Subject: [PATCH 6/7] Remove 'mark all as read' button Now available through multi-select --- .../fragment/AllEpisodesFragment.java | 1 - .../fragment/EpisodesListFragment.java | 15 ----- .../fragment/FavoriteEpisodesFragment.java | 1 - .../menuhandler/FeedMenuHandler.java | 15 ----- app/src/main/res/menu/episodes.xml | 8 --- .../antennapod/core/storage/DBWriter.java | 30 ---------- .../antennapod/core/storage/DbWriterTest.java | 56 ------------------- ui/i18n/src/main/res/values/strings.xml | 4 -- 8 files changed, 130 deletions(-) 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 51dcb664c..46a648e57 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -66,7 +66,6 @@ public class AllEpisodesFragment extends EpisodesListFragment { public void onPrepareOptionsMenu(@NonNull Menu menu) { super.onPrepareOptionsMenu(menu); menu.findItem(R.id.filter_items).setVisible(true); - menu.findItem(R.id.mark_all_read_item).setVisible(true); } @Override 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 9409c7c3a..0f75c2fb7 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -137,21 +137,6 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt if (itemId == R.id.refresh_item) { AutoUpdateManager.runImmediate(requireContext()); return true; - } else if (itemId == R.id.mark_all_read_item) { - ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(getActivity(), - R.string.mark_all_read_label, - R.string.mark_all_read_confirmation_msg) { - - @Override - public void onConfirmButtonPressed(DialogInterface dialog) { - dialog.dismiss(); - DBWriter.markAllItemsRead(); - ((MainActivity) getActivity()).showSnackbarAbovePlayer( - R.string.mark_all_read_msg, Toast.LENGTH_SHORT); - } - }; - markAllReadConfirmationDialog.createNewDialog().show(); - return true; } else if (itemId == R.id.remove_all_inbox_item) { ConfirmationDialog removeAllNewFlagsConfirmationDialog = new ConfirmationDialog(getActivity(), R.string.remove_all_inbox_label, 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 cc45a7d35..30eec8780 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java @@ -48,7 +48,6 @@ public class FavoriteEpisodesFragment extends EpisodesListFragment { public void onPrepareOptionsMenu(@NonNull Menu menu) { super.onPrepareOptionsMenu(menu); menu.findItem(R.id.filter_items).setVisible(false); - menu.findItem(R.id.mark_all_read_item).setVisible(false); } @NonNull diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java index bfe269caa..de6056063 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java @@ -1,13 +1,11 @@ package de.danoeh.antennapod.menuhandler; import android.content.Context; -import android.content.DialogInterface; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import androidx.annotation.NonNull; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.util.IntentUtils; @@ -56,19 +54,6 @@ public class FeedMenuHandler { DBTasks.forceRefreshCompleteFeed(context, selectedFeed); } else if (itemId == R.id.sort_items) { showSortDialog(context, selectedFeed); - } else if (itemId == R.id.mark_all_read_item) { - ConfirmationDialog conDialog = new ConfirmationDialog(context, - R.string.mark_all_read_label, - R.string.mark_all_read_feed_confirmation_msg) { - - @Override - public void onConfirmButtonPressed( - DialogInterface dialog) { - dialog.dismiss(); - DBWriter.markFeedRead(selectedFeed.getId()); - } - }; - conDialog.createNewDialog().show(); } else if (itemId == R.id.visit_website_item) { IntentUtils.openInBrowser(context, selectedFeed.getLink()); } else if (itemId == R.id.share_item) { diff --git a/app/src/main/res/menu/episodes.xml b/app/src/main/res/menu/episodes.xml index 75f7df861..4e6da923b 100644 --- a/app/src/main/res/menu/episodes.xml +++ b/app/src/main/res/menu/episodes.xml @@ -24,12 +24,4 @@ android:visible="false" custom:showAsAction="ifRoom"/> - - diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java index df4094590..ff8c990db 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java @@ -731,36 +731,6 @@ public class DBWriter { }); } - /** - * Sets the 'read'-attribute of all FeedItems of a specific Feed to PLAYED. - * - * @param feedId ID of the Feed. - */ - public static Future markFeedRead(final long feedId) { - return dbExec.submit(() -> { - final PodDBAdapter adapter = PodDBAdapter.getInstance(); - adapter.open(); - adapter.setFeedItems(FeedItem.PLAYED, feedId); - adapter.close(); - - EventBus.getDefault().post(new UnreadItemsUpdateEvent()); - }); - } - - /** - * Sets the 'read'-attribute of all FeedItems to PLAYED. - */ - public static Future markAllItemsRead() { - return dbExec.submit(() -> { - final PodDBAdapter adapter = PodDBAdapter.getInstance(); - adapter.open(); - adapter.setFeedItems(FeedItem.PLAYED); - adapter.close(); - - EventBus.getDefault().post(new UnreadItemsUpdateEvent()); - }); - } - /** * Sets the 'read'-attribute of all NEW FeedItems to UNPLAYED. */ diff --git a/core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java b/core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java index de1e78408..533b517d5 100644 --- a/core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java +++ b/core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java @@ -751,34 +751,6 @@ public class DbWriterTest { } } - @Test - public void testMarkFeedRead() throws Exception { - final int numItems = 10; - Feed feed = new Feed("url", null, "title"); - feed.setItems(new ArrayList<>()); - for (int i = 0; i < numItems; i++) { - FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, - new Date(), FeedItem.UNPLAYED, feed); - feed.getItems().add(item); - } - - PodDBAdapter adapter = PodDBAdapter.getInstance(); - adapter.open(); - adapter.setCompleteFeed(feed); - adapter.close(); - - assertTrue(feed.getId() != 0); - for (FeedItem item : feed.getItems()) { - assertTrue(item.getId() != 0); - } - - DBWriter.markFeedRead(feed.getId()).get(TIMEOUT, TimeUnit.SECONDS); - List loadedItems = DBReader.getFeedItemList(feed); - for (FeedItem item : loadedItems) { - assertTrue(item.isPlayed()); - } - } - @Test public void testRemoveAllNewFlags() throws Exception { final int numItems = 10; @@ -807,34 +779,6 @@ public class DbWriterTest { } } - @Test - public void testMarkAllItemsReadSameFeed() throws Exception { - final int numItems = 10; - Feed feed = new Feed("url", null, "title"); - feed.setItems(new ArrayList<>()); - for (int i = 0; i < numItems; i++) { - FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, - new Date(), FeedItem.UNPLAYED, feed); - feed.getItems().add(item); - } - - PodDBAdapter adapter = PodDBAdapter.getInstance(); - adapter.open(); - adapter.setCompleteFeed(feed); - adapter.close(); - - assertTrue(feed.getId() != 0); - for (FeedItem item : feed.getItems()) { - assertTrue(item.getId() != 0); - } - - DBWriter.markAllItemsRead().get(TIMEOUT, TimeUnit.SECONDS); - List loadedItems = DBReader.getFeedItemList(feed); - for (FeedItem item : loadedItems) { - assertTrue(item.isPlayed()); - } - } - private static Feed createTestFeed(int numItems) { Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); diff --git a/ui/i18n/src/main/res/values/strings.xml b/ui/i18n/src/main/res/values/strings.xml index f42188982..836c418a9 100644 --- a/ui/i18n/src/main/res/values/strings.xml +++ b/ui/i18n/src/main/res/values/strings.xml @@ -152,10 +152,6 @@ Your subscriptions have new episodes. - Mark all as played - Marked all Episodes as played - Please confirm that you want to mark all episodes as being played. - Please confirm that you want to mark all episodes in this podcast as being played. Remove all from inbox Removed all from inbox Please confirm that you want to remove all from the inbox. From 850529856a0dfdab701b6720f35f15ee13a090c2 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 8 May 2022 11:46:21 +0200 Subject: [PATCH 7/7] Confirm mark as played/unplayed --- .../fragment/EpisodesListFragment.java | 60 +++++++++++++------ ui/i18n/src/main/res/values/strings.xml | 2 + 2 files changed, 43 insertions(+), 19 deletions(-) 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 0f75c2fb7..03dbc6ae4 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -232,31 +232,53 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt } }); speedDialView.setOnActionSelectedListener(actionItem -> { - EpisodeMultiSelectActionHandler handler = - new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), actionItem.getId()); - Completable.fromAction( - () -> { - handler.handleAction(listAdapter.getSelectedItems()); - if (listAdapter.shouldSelectLazyLoadedItems()) { - int applyPage = page + 1; - List nextPage; - do { - nextPage = loadMoreData(applyPage); - handler.handleAction(nextPage); - applyPage++; - } while (nextPage.size() == EPISODES_PER_PAGE); - } - }) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(() -> listAdapter.endSelectMode(), - error -> Log.e(TAG, Log.getStackTraceString(error))); + int confirmationString = 0; + if (listAdapter.getSelectedItems().size() >= 25 || listAdapter.shouldSelectLazyLoadedItems()) { + // Should ask for confirmation + if (actionItem.getId() == R.id.mark_read_batch) { + confirmationString = R.string.multi_select_mark_played_confirmation; + } else if (actionItem.getId() == R.id.mark_unread_batch) { + confirmationString = R.string.multi_select_mark_unplayed_confirmation; + } + } + if (confirmationString == 0) { + performMultiSelectAction(actionItem.getId()); + } else { + new ConfirmationDialog(getActivity(), R.string.multi_select, confirmationString) { + @Override + public void onConfirmButtonPressed(DialogInterface dialog) { + performMultiSelectAction(actionItem.getId()); + } + }.createNewDialog().show(); + } return true; }); return root; } + private void performMultiSelectAction(int actionItemId) { + EpisodeMultiSelectActionHandler handler = + new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), actionItemId); + Completable.fromAction( + () -> { + handler.handleAction(listAdapter.getSelectedItems()); + if (listAdapter.shouldSelectLazyLoadedItems()) { + int applyPage = page + 1; + List nextPage; + do { + nextPage = loadMoreData(applyPage); + handler.handleAction(nextPage); + applyPage++; + } while (nextPage.size() == EPISODES_PER_PAGE); + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(() -> listAdapter.endSelectMode(), + error -> Log.e(TAG, Log.getStackTraceString(error))); + } + private void setupLoadMoreScrollListener() { recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override diff --git a/ui/i18n/src/main/res/values/strings.xml b/ui/i18n/src/main/res/values/strings.xml index 836c418a9..8c8dd1b2f 100644 --- a/ui/i18n/src/main/res/values/strings.xml +++ b/ui/i18n/src/main/res/values/strings.xml @@ -155,6 +155,8 @@ Remove all from inbox Removed all from inbox Please confirm that you want to remove all from the inbox. + Please confirm that you want to mark all selected items as played. + Please confirm that you want to mark all selected items as unplayed. Show information Show podcast settings Podcast settings