diff options
author | ByteHamster <ByteHamster@users.noreply.github.com> | 2022-05-08 21:47:26 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-08 21:47:26 +0200 |
commit | 6e5004be22f20e3a51697909bf4d1e423252b83c (patch) | |
tree | 127297582c587aa07b1a25050251ec1ab6db246c /app/src/main/java/de/danoeh/antennapod | |
parent | bfb811d29e611146855f77df5dd97b9fb664cf25 (diff) | |
parent | 850529856a0dfdab701b6720f35f15ee13a090c2 (diff) | |
download | AntennaPod-6e5004be22f20e3a51697909bf4d1e423252b83c.zip |
Merge pull request #5872 from ByteHamster/multi-select-all-episodes
Multi-Select on 'All episodes' screen
Diffstat (limited to 'app/src/main/java/de/danoeh/antennapod')
11 files changed, 221 insertions, 95 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..088caf70a 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<EpisodeItemViewHol public void updateItems(List<FeedItem> items) { episodes = items; notifyDataSetChanged(); + updateTitle(); } @Override @@ -194,6 +195,7 @@ public class EpisodeItemListAdapter extends SelectableAdapter<EpisodeItemViewHol setSelected(0, longPressedPosition, true); return true; } else if (item.getItemId() == R.id.select_all_below) { + shouldSelectLazyLoadedItems = true; setSelected(longPressedPosition + 1, getItemCount(), true); return true; } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SelectableAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SelectableAdapter.java index 43f749ff3..70d00cbff 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/SelectableAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/SelectableAdapter.java @@ -15,11 +15,14 @@ import java.util.HashSet; /** * Used by Recyclerviews that need to provide ability to select items. */ -abstract class SelectableAdapter<T extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<T> { +public abstract class SelectableAdapter<T extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<T> { + public static final int COUNT_AUTOMATICALLY = -1; private ActionMode actionMode; private final HashSet<Long> 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; @@ -34,6 +37,7 @@ abstract class SelectableAdapter<T extends RecyclerView.ViewHolder> extends Recy onSelectModeListener.onStartSelectMode(); } + shouldSelectLazyLoadedItems = false; selectedIds.clear(); selectedIds.add(getItemId(pos)); notifyDataSetChanged(); @@ -56,9 +60,10 @@ abstract class SelectableAdapter<T extends RecyclerView.ViewHolder> 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 +74,7 @@ abstract class SelectableAdapter<T extends RecyclerView.ViewHolder> extends Recy public void onDestroyActionMode(ActionMode mode) { callOnEndSelectMode(); actionMode = null; + shouldSelectLazyLoadedItems = false; selectedIds.clear(); notifyDataSetChanged(); } @@ -147,13 +153,21 @@ abstract class SelectableAdapter<T extends RecyclerView.ViewHolder> extends Recy } } - private void updateTitle() { + void updateTitle() { 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) { @@ -166,6 +180,18 @@ abstract class SelectableAdapter<T extends RecyclerView.ViewHolder> extends Recy } } + public boolean shouldSelectLazyLoadedItems() { + 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..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 @@ -102,7 +101,12 @@ public class AllEpisodesFragment extends EpisodesListFragment { @NonNull @Override - protected List<FeedItem> loadMoreData() { + protected List<FeedItem> loadMoreData(int page) { 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/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java index 18c5d8514..d82b3ff0c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java @@ -120,8 +120,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 b658e5f08..03dbc6ae4 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; @@ -22,15 +23,20 @@ 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.adapter.SelectableAdapter; 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; +import io.reactivex.Completable; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -59,7 +65,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 +78,7 @@ public abstract class EpisodesListFragment extends Fragment { ProgressBar progLoading; View loadingMoreView; EmptyViewHandler emptyView; + SpeedDialView speedDialView; @NonNull List<FeedItem> episodes = new ArrayList<>(); @@ -130,21 +137,6 @@ public abstract class EpisodesListFragment extends Fragment { 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, @@ -174,17 +166,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,9 +213,72 @@ 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 -> { + 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<FeedItem> 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 @@ -249,7 +300,7 @@ public abstract class EpisodesListFragment extends Fragment { } isLoadingMore = true; loadingMoreView.setVisibility(View.VISIBLE); - disposable = Observable.fromCallable(this::loadMoreData) + disposable = Observable.fromCallable(() -> loadMoreData(page)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(data -> { @@ -258,6 +309,9 @@ public abstract class EpisodesListFragment extends Fragment { } 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 @@ -292,14 +346,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 + "]"); @@ -395,14 +473,15 @@ public abstract class EpisodesListFragment extends Fragment { 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); @@ -422,5 +501,12 @@ public abstract class EpisodesListFragment extends Fragment { * @return The items from the next page of data */ @NonNull - protected abstract List<FeedItem> loadMoreData(); + protected abstract List<FeedItem> loadMoreData(int page); + + /** + * 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..30eec8780 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; @@ -47,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 @@ -98,7 +98,12 @@ public class FavoriteEpisodesFragment extends EpisodesListFragment { @NonNull @Override - protected List<FeedItem> loadMoreData() { + protected List<FeedItem> loadMoreData(int page) { 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/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/InboxFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java index abb04b2f3..067e7466c 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; } @@ -113,7 +116,12 @@ public class InboxFragment extends EpisodesListFragment implements Toolbar.OnMen @NonNull @Override - protected List<FeedItem> loadMoreData() { + protected List<FeedItem> loadMoreData(int page) { 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/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..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 @@ -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<FeedItem> selectedItems; + private final int actionId; + private int totalNumItems = 0; + private Snackbar snackbar = null; - public EpisodeMultiSelectActionHandler(MainActivity activity, List<FeedItem> 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<FeedItem> 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<FeedItem> 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<FeedItem> 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<FeedItem> 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<FeedItem> 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<FeedItem> items) { // download the check episodes in the same order as they are currently displayed List<DownloadRequest> 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<FeedItem> 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,22 @@ public class EpisodeMultiSelectActionHandler { } private void showMessage(@PluralsRes int msgId, int numItems) { - activity.showSnackbarAbovePlayer(activity.getResources() - .getQuantityString(msgId, numItems, numItems), Snackbar.LENGTH_LONG); + totalNumItems += numItems; + 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() { - long[] checkedIds = new long[selectedItems.size()]; - for (int i = 0; i < selectedItems.size(); ++i) { - checkedIds[i] = selectedItems.get(i).getId(); + private long[] getSelectedIds(List<FeedItem> items) { + long[] checkedIds = new long[items.size()]; + for (int i = 0; i < items.size(); ++i) { + checkedIds[i] = items.get(i).getId(); } return checkedIds; } 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) { |