summaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
authorseeto <65185819+peakvalleytech@users.noreply.github.com>2021-08-23 14:46:38 -0700
committerGitHub <noreply@github.com>2021-08-23 23:46:38 +0200
commiteacc90af299220c60fd504ef7970775aa344b44c (patch)
tree371df8b11c5c1e14515e662963ce3f61438a8bac /app/src/main
parent91967409cb9399637f7a7b6eef52c039c1145ef3 (diff)
downloadAntennaPod-eacc90af299220c60fd504ef7970775aa344b44c.zip
Feed multi select (#5261)
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java152
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java245
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/RemoveFeedDialog.java39
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java168
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java139
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceListDialog.java49
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceSwitchDialog.java57
-rw-r--r--app/src/main/res/layout/dialog_switch_preference.xml15
-rw-r--r--app/src/main/res/layout/fragment_subscriptions.xml102
-rw-r--r--app/src/main/res/layout/subscription_item.xml24
-rw-r--r--app/src/main/res/menu/nav_feed_action_speeddial.xml28
-rw-r--r--app/src/main/res/menu/nav_feed_context.xml4
13 files changed, 739 insertions, 293 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 674b5f86e..f6b47d8e5 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/EpisodeItemListAdapter.java
@@ -76,21 +76,19 @@ public class EpisodeItemListAdapter extends SelectableAdapter<EpisodeItemViewHol
int position = ArrayUtils.indexOf(ids, item.getId());
activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position));
} else {
- toggleSelection(pos);
+ toggleSelection(holder.getBindingAdapterPosition());
}
});
holder.itemView.setOnCreateContextMenuListener(this);
holder.itemView.setOnLongClickListener(v -> {
- longPressedItem = item;
- longPressedPosition = pos;
+ longPressedItem = getItem(holder.getBindingAdapterPosition());
+ longPressedPosition = holder.getBindingAdapterPosition();
return false;
});
if (inActionMode()) {
holder.secondaryActionButton.setVisibility(View.GONE);
- holder.selectCheckBox.setOnClickListener(v -> {
- toggleSelection(pos);
- });
+ holder.selectCheckBox.setOnClickListener(v -> toggleSelection(holder.getBindingAdapterPosition()));
holder.selectCheckBox.setChecked(isSelected(pos));
holder.selectCheckBox.setVisibility(View.VISIBLE);
} else {
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java
deleted file mode 100644
index 0af6960d7..000000000
--- a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java
+++ /dev/null
@@ -1,152 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import android.content.Context;
-
-import androidx.core.text.TextUtilsCompat;
-import androidx.core.view.ViewCompat;
-import androidx.fragment.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.lang.ref.WeakReference;
-import java.text.NumberFormat;
-import java.util.Locale;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.model.feed.Feed;
-import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
-import de.danoeh.antennapod.core.storage.NavDrawerData;
-import de.danoeh.antennapod.fragment.FeedItemlistFragment;
-import de.danoeh.antennapod.fragment.SubscriptionFragment;
-import jp.shts.android.library.TriangleLabelView;
-
-/**
- * Adapter for subscriptions
- */
-public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnItemClickListener {
- /** the position in the view that holds the add item; 0 is the first, -1 is the last position */
- private static final String TAG = "SubscriptionsAdapter";
-
- private final WeakReference<MainActivity> mainActivityRef;
- private final ItemAccess itemAccess;
-
- public SubscriptionsAdapter(MainActivity mainActivity, ItemAccess itemAccess) {
- this.mainActivityRef = new WeakReference<>(mainActivity);
- this.itemAccess = itemAccess;
- }
-
- @Override
- public int getCount() {
- return itemAccess.getCount();
- }
-
- @Override
- public Object getItem(int position) {
- return itemAccess.getItem(position);
- }
-
- @Override
- public boolean hasStableIds() {
- return true;
- }
-
- @Override
- public long getItemId(int position) {
- return ((NavDrawerData.DrawerItem) getItem(position)).id;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Holder holder;
-
- if (convertView == null) {
- holder = new Holder();
-
- LayoutInflater layoutInflater =
- (LayoutInflater) mainActivityRef.get().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- convertView = layoutInflater.inflate(R.layout.subscription_item, parent, false);
- holder.feedTitle = convertView.findViewById(R.id.txtvTitle);
- holder.imageView = convertView.findViewById(R.id.imgvCover);
- holder.count = convertView.findViewById(R.id.triangleCountView);
-
-
- convertView.setTag(holder);
- } else {
- holder = (Holder) convertView.getTag();
- }
-
- final NavDrawerData.DrawerItem drawerItem = (NavDrawerData.DrawerItem) getItem(position);
- if (drawerItem == null) {
- return null;
- }
-
- holder.feedTitle.setText(drawerItem.getTitle());
- holder.imageView.setContentDescription(drawerItem.getTitle());
- holder.feedTitle.setVisibility(View.VISIBLE);
-
- // Fix TriangleLabelView corner for RTL
- if (TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
- == ViewCompat.LAYOUT_DIRECTION_RTL) {
- holder.count.setCorner(TriangleLabelView.Corner.TOP_LEFT);
- }
-
- if (drawerItem.getCounter() > 0) {
- holder.count.setPrimaryText(NumberFormat.getInstance().format(drawerItem.getCounter()));
- holder.count.setVisibility(View.VISIBLE);
- } else {
- holder.count.setVisibility(View.GONE);
- }
-
- if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
- Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed;
- boolean textAndImageCombined = feed.isLocalFeed()
- && LocalFeedUpdater.getDefaultIconUrl(convertView.getContext()).equals(feed.getImageUrl());
- new CoverLoader(mainActivityRef.get())
- .withUri(feed.getImageUrl())
- .withPlaceholderView(holder.feedTitle, textAndImageCombined)
- .withCoverView(holder.imageView)
- .load();
- } else {
- new CoverLoader(mainActivityRef.get())
- .withResource(R.drawable.ic_folder)
- .withPlaceholderView(holder.feedTitle, true)
- .withCoverView(holder.imageView)
- .load();
- }
- return convertView;
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- final NavDrawerData.DrawerItem drawerItem = (NavDrawerData.DrawerItem) getItem(position);
- if (drawerItem == null) {
- return;
- }
- if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
- Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed;
- Fragment fragment = FeedItemlistFragment.newInstance(feed.getId());
- mainActivityRef.get().loadChildFragment(fragment);
- } else if (drawerItem.type == NavDrawerData.DrawerItem.Type.FOLDER) {
- Fragment fragment = SubscriptionFragment.newInstance(drawerItem.getTitle());
- mainActivityRef.get().loadChildFragment(fragment);
- }
- }
-
- static class Holder {
- public TextView feedTitle;
- public ImageView imageView;
- public TriangleLabelView count;
- }
-
- public interface ItemAccess {
- int getCount();
-
- NavDrawerData.DrawerItem getItem(int position);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java
new file mode 100644
index 000000000..689f4fcbc
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java
@@ -0,0 +1,245 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.core.text.TextUtilsCompat;
+import androidx.core.view.ViewCompat;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.lang.ref.WeakReference;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
+import de.danoeh.antennapod.core.storage.NavDrawerData;
+import de.danoeh.antennapod.fragment.FeedItemlistFragment;
+import de.danoeh.antennapod.fragment.SubscriptionFragment;
+import de.danoeh.antennapod.model.feed.Feed;
+import jp.shts.android.library.TriangleLabelView;
+
+/**
+ * Adapter for subscriptions
+ */
+public class SubscriptionsRecyclerAdapter extends SelectableAdapter<SubscriptionsRecyclerAdapter.SubscriptionViewHolder>
+ implements View.OnCreateContextMenuListener {
+ private final WeakReference<MainActivity> mainActivityRef;
+ private List<NavDrawerData.DrawerItem> listItems;
+ private Feed selectedFeed = null;
+ int longPressedPosition = 0; // used to init actionMode
+
+ public SubscriptionsRecyclerAdapter(MainActivity mainActivity) {
+ super(mainActivity);
+ this.mainActivityRef = new WeakReference<>(mainActivity);
+ this.listItems = new ArrayList<>();
+ setHasStableIds(true);
+ }
+
+ public Object getItem(int position) {
+ return listItems.get(position);
+ }
+
+ public Feed getSelectedFeed() {
+ return selectedFeed;
+ }
+
+ @NonNull
+ @Override
+ public SubscriptionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View itemView = LayoutInflater.from(mainActivityRef.get()).inflate(R.layout.subscription_item, parent, false);
+ return new SubscriptionViewHolder(itemView);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull SubscriptionViewHolder holder, int position) {
+ NavDrawerData.DrawerItem drawerItem = listItems.get(position);
+ boolean isFeed = drawerItem.type == NavDrawerData.DrawerItem.Type.FEED;
+ holder.bind(drawerItem);
+ holder.itemView.setOnCreateContextMenuListener(this);
+ if (inActionMode()) {
+ if (isFeed) {
+ holder.selectCheckbox.setVisibility(View.VISIBLE);
+ holder.selectView.setVisibility(View.VISIBLE);
+ }
+ holder.selectCheckbox.setChecked((isSelected(position)));
+ holder.selectCheckbox.setOnCheckedChangeListener((buttonView, isChecked)
+ -> setSelected(holder.getBindingAdapterPosition(), isChecked));
+ holder.imageView.setAlpha(0.6f);
+ holder.count.setVisibility(View.GONE);
+ } else {
+ holder.selectView.setVisibility(View.GONE);
+ holder.imageView.setAlpha(1.0f);
+ }
+
+ holder.itemView.setOnLongClickListener(v -> {
+ if (!inActionMode()) {
+ if (isFeed) {
+ selectedFeed = ((NavDrawerData.FeedDrawerItem) getItem(holder.getBindingAdapterPosition())).feed;
+ longPressedPosition = holder.getBindingAdapterPosition();
+ } else {
+ selectedFeed = null;
+ }
+ }
+ return false;
+ });
+
+ holder.itemView.setOnClickListener(v -> {
+ if (isFeed) {
+ if (inActionMode()) {
+ holder.selectCheckbox.setChecked(!isSelected(holder.getBindingAdapterPosition()));
+ } else {
+ Fragment fragment = FeedItemlistFragment
+ .newInstance(((NavDrawerData.FeedDrawerItem) drawerItem).feed.getId());
+ mainActivityRef.get().loadChildFragment(fragment);
+ }
+ } else if (!inActionMode()) {
+ Fragment fragment = SubscriptionFragment.newInstance(drawerItem.getTitle());
+ mainActivityRef.get().loadChildFragment(fragment);
+ }
+ });
+
+ }
+
+ @Override
+ public int getItemCount() {
+ return listItems.size();
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return listItems.get(position).id;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ if (selectedFeed != null && !inActionMode()) {
+ MenuInflater inflater = mainActivityRef.get().getMenuInflater();
+ inflater.inflate(R.menu.nav_feed_context, menu);
+ menu.setHeaderTitle(selectedFeed.getTitle());
+ }
+ }
+
+ public boolean onContextItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.multi_select) {
+ startSelectMode(longPressedPosition);
+ return true;
+ }
+ return false;
+ }
+
+ public List<Feed> getSelectedItems() {
+ List<Feed> items = new ArrayList<>();
+ for (int i = 0; i < getItemCount(); i++) {
+ if (isSelected(i)) {
+ NavDrawerData.DrawerItem drawerItem = listItems.get(i);
+ if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
+ Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed;
+ items.add(feed);
+ }
+ }
+ }
+ return items;
+ }
+
+ public void setItems(List<NavDrawerData.DrawerItem> listItems) {
+ this.listItems = listItems;
+ }
+
+ @Override
+ public void setSelected(int pos, boolean selected) {
+ NavDrawerData.DrawerItem drawerItem = listItems.get(pos);
+ if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
+ super.setSelected(pos, selected);
+ }
+ }
+
+ public class SubscriptionViewHolder extends RecyclerView.ViewHolder {
+ private final TextView feedTitle;
+ private final ImageView imageView;
+ private final TriangleLabelView count;
+ private final FrameLayout selectView;
+ private final CheckBox selectCheckbox;
+
+ public SubscriptionViewHolder(@NonNull View itemView) {
+ super(itemView);
+ feedTitle = itemView.findViewById(R.id.txtvTitle);
+ imageView = itemView.findViewById(R.id.imgvCover);
+ count = itemView.findViewById(R.id.triangleCountView);
+ selectView = itemView.findViewById(R.id.selectView);
+ selectCheckbox = itemView.findViewById(R.id.selectCheckBox);
+ }
+
+ public void bind(NavDrawerData.DrawerItem drawerItem) {
+ feedTitle.setText(drawerItem.getTitle());
+ imageView.setContentDescription(drawerItem.getTitle());
+ feedTitle.setVisibility(View.VISIBLE);
+ if (TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
+ == ViewCompat.LAYOUT_DIRECTION_RTL) {
+ count.setCorner(TriangleLabelView.Corner.TOP_LEFT);
+ }
+
+ if (drawerItem.getCounter() > 0) {
+ count.setPrimaryText(NumberFormat.getInstance().format(drawerItem.getCounter()));
+ count.setVisibility(View.VISIBLE);
+ } else {
+ count.setVisibility(View.GONE);
+ }
+
+ if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
+ Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed;
+ boolean textAndImageCombind = feed.isLocalFeed()
+ && LocalFeedUpdater.getDefaultIconUrl(itemView.getContext()).equals(feed.getImageUrl());
+ new CoverLoader(mainActivityRef.get())
+ .withUri(feed.getImageUrl())
+ .withPlaceholderView(feedTitle, textAndImageCombind)
+ .withCoverView(imageView)
+ .load();
+ } else {
+ new CoverLoader(mainActivityRef.get())
+ .withResource(R.drawable.ic_folder)
+ .withPlaceholderView(feedTitle, true)
+ .withCoverView(imageView)
+ .load();
+ }
+ }
+ }
+
+ public static float convertDpToPixel(Context context, float dp) {
+ return dp * context.getResources().getDisplayMetrics().density;
+ }
+
+ public static class GridDividerItemDecorator extends RecyclerView.ItemDecoration {
+ @Override
+ public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.onDraw(c, parent, state);
+ }
+
+ @Override
+ public void getItemOffsets(@NonNull Rect outRect,
+ @NonNull View view,
+ @NonNull RecyclerView parent,
+ @NonNull RecyclerView.State state) {
+ super.getItemOffsets(outRect, view, parent, state);
+ Context context = parent.getContext();
+ int insetOffset = (int) convertDpToPixel(context, 1f);
+ outRect.set(insetOffset, insetOffset, insetOffset, insetOffset);
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/RemoveFeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/RemoveFeedDialog.java
index f42f0870d..c4ae5e058 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/RemoveFeedDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/RemoveFeedDialog.java
@@ -4,6 +4,10 @@ import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.Log;
+
+import java.util.Collections;
+import java.util.List;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.model.feed.Feed;
@@ -16,10 +20,17 @@ public class RemoveFeedDialog {
private static final String TAG = "RemoveFeedDialog";
public static void show(Context context, Feed feed, Runnable onSuccess) {
- int messageId = feed.isLocalFeed() ? R.string.feed_delete_confirmation_local_msg
- : R.string.feed_delete_confirmation_msg;
- String message = context.getString(messageId, feed.getTitle());
+ List<Feed> feeds = Collections.singletonList(feed);
+ String message = getMessageId(context, feeds);
+ showDialog(context, feeds, message, onSuccess);
+ }
+
+ public static void show(Context context, List<Feed> feeds, Runnable onSuccess) {
+ String message = getMessageId(context, feeds);
+ showDialog(context, feeds, message, onSuccess);
+ }
+ private static void showDialog(Context context, List<Feed> feeds, String message, Runnable onSuccess) {
ConfirmationDialog dialog = new ConfirmationDialog(context, R.string.remove_feed_label, message) {
@Override
public void onConfirmButtonPressed(DialogInterface clickedDialog) {
@@ -31,12 +42,17 @@ public class RemoveFeedDialog {
progressDialog.setCancelable(false);
progressDialog.show();
- Completable.fromCallable(() -> DBWriter.deleteFeed(context, feed.getId()).get())
+ Completable.fromCallable(() -> {
+ for (Feed feed : feeds) {
+ DBWriter.deleteFeed(context, feed.getId()).get();
+ }
+ return null;
+ })
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
() -> {
- Log.d(TAG, "Feed was deleted");
+ Log.d(TAG, "Feed(s) deleted");
if (onSuccess != null) {
onSuccess.run();
}
@@ -49,4 +65,17 @@ public class RemoveFeedDialog {
};
dialog.createNewDialog().show();
}
+
+ private static String getMessageId(Context context, List<Feed> feeds) {
+ if (feeds.size() == 1) {
+ if (feeds.get(0).isLocalFeed()) {
+ return context.getString(R.string.feed_delete_confirmation_local_msg);
+ } else {
+ return context.getString(R.string.feed_delete_confirmation_msg, feeds.get(0).getTitle());
+ }
+ } else {
+ return context.getString(R.string.feed_delete_confirmation_msg_batch);
+ }
+
+ }
}
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 9fcdc6f02..b720f1167 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
@@ -7,41 +7,44 @@ import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
-import android.widget.ProgressBar;
-import androidx.annotation.NonNull;
-import androidx.annotation.StringRes;
-import androidx.appcompat.widget.Toolbar;
-import androidx.fragment.app.Fragment;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
-
import android.util.Log;
-import android.view.ContextMenu;
import android.view.LayoutInflater;
-import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.GridView;
+import android.widget.ProgressBar;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+import androidx.appcompat.widget.Toolbar;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.joanzapata.iconify.Iconify;
+import com.leinardi.android.speeddial.SpeedDialView;
+
+import de.danoeh.antennapod.dialog.TagSettingsDialog;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.adapter.SubscriptionsAdapter;
+import de.danoeh.antennapod.adapter.SubscriptionsRecyclerAdapter;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.dialog.TagSettingsDialog;
-import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -49,24 +52,24 @@ import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.storage.NavDrawerData;
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
-import de.danoeh.antennapod.dialog.RemoveFeedDialog;
-import de.danoeh.antennapod.dialog.SubscriptionsFilterDialog;
import de.danoeh.antennapod.dialog.FeedSortDialog;
+import de.danoeh.antennapod.dialog.RemoveFeedDialog;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
+import de.danoeh.antennapod.dialog.SubscriptionsFilterDialog;
+import de.danoeh.antennapod.fragment.actions.FeedMultiSelectActionHandler;
+import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Observable;
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;
/**
* Fragment for displaying feed subscriptions
*/
-public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItemClickListener {
-
+public class SubscriptionFragment extends Fragment
+ implements Toolbar.OnMenuItemClickListener,
+ SubscriptionsRecyclerAdapter.OnSelectModeListener {
public static final String TAG = "SubscriptionFragment";
private static final String PREFS = "SubscriptionFragment";
private static final String PREF_NUM_COLUMNS = "columns";
@@ -80,23 +83,24 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
R.id.subscription_num_columns_4,
R.id.subscription_num_columns_5};
- private GridView subscriptionGridLayout;
- private List<NavDrawerData.DrawerItem> listItems;
- private SubscriptionsAdapter subscriptionAdapter;
+ private RecyclerView subscriptionRecycler;
+ private SubscriptionsRecyclerAdapter subscriptionAdapter;
private FloatingActionButton subscriptionAddButton;
private ProgressBar progressBar;
private EmptyViewHandler emptyView;
private TextView feedsFilteredMsg;
private Toolbar toolbar;
private String displayedFolder = null;
-
- private Feed selectedFeed = null;
private boolean isUpdatingFeeds = false;
private boolean displayUpArrow;
private Disposable disposable;
private SharedPreferences prefs;
+ private SpeedDialView speedDialView;
+
+ private List<NavDrawerData.DrawerItem> listItems;
+
public static SubscriptionFragment newInstance(String folderTitle) {
SubscriptionFragment fragment = new SubscriptionFragment();
Bundle args = new Bundle();
@@ -139,9 +143,15 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
}
}
- subscriptionGridLayout = root.findViewById(R.id.subscriptions_grid);
- subscriptionGridLayout.setNumColumns(prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns()));
- registerForContextMenu(subscriptionGridLayout);
+ subscriptionRecycler = root.findViewById(R.id.subscriptions_grid);
+ GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(),
+ prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns()),
+ RecyclerView.VERTICAL,
+ false);
+ subscriptionRecycler.setLayoutManager(gridLayoutManager);
+ subscriptionRecycler.addItemDecoration(new SubscriptionsRecyclerAdapter.GridDividerItemDecorator());
+ gridLayoutManager.setSpanCount(prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns()));
+ registerForContextMenu(subscriptionRecycler);
subscriptionAddButton = root.findViewById(R.id.subscriptions_add);
progressBar = root.findViewById(R.id.progLoading);
@@ -155,6 +165,25 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
new Handler(Looper.getMainLooper()).postDelayed(() -> swipeRefreshLayout.setRefreshing(false),
getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms));
});
+
+ speedDialView = root.findViewById(R.id.fabSD);
+ speedDialView.inflate(R.menu.nav_feed_action_speeddial);
+ speedDialView.setOnChangeListener(new SpeedDialView.OnChangeListener() {
+ @Override
+ public boolean onMainActionSelected() {
+ return false;
+ }
+
+ @Override
+ public void onToggleChanged(boolean isOpen) {
+ }
+ });
+ speedDialView.setOnActionSelectedListener(actionItem -> {
+ new FeedMultiSelectActionHandler((MainActivity) getActivity(), subscriptionAdapter.getSelectedItems())
+ .handleAction(actionItem.getId());
+ return true;
+ });
+
return root;
}
@@ -204,7 +233,9 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
}
private void setColumnNumber(int columns) {
- subscriptionGridLayout.setNumColumns(columns);
+ GridLayoutManager gridLayoutManager = (GridLayoutManager) subscriptionRecycler.getLayoutManager();
+ gridLayoutManager.setSpanCount(columns);
+ subscriptionAdapter.notifyDataSetChanged();
prefs.edit().putInt(PREF_NUM_COLUMNS, columns).apply();
refreshToolbarState();
}
@@ -214,18 +245,16 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
emptyView.setIcon(R.drawable.ic_folder);
emptyView.setTitle(R.string.no_subscriptions_head_label);
emptyView.setMessage(R.string.no_subscriptions_label);
- emptyView.attachToListView(subscriptionGridLayout);
+ emptyView.attachToRecyclerView(subscriptionRecycler);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
-
- subscriptionAdapter = new SubscriptionsAdapter((MainActivity) getActivity(), itemAccess);
- subscriptionGridLayout.setAdapter(subscriptionAdapter);
- subscriptionGridLayout.setOnItemClickListener(subscriptionAdapter);
+ subscriptionAdapter = new SubscriptionsRecyclerAdapter((MainActivity) getActivity());
+ subscriptionAdapter.setOnSelectModeListener(this);
+ subscriptionRecycler.setAdapter(subscriptionAdapter);
setupEmptyView();
-
subscriptionAddButton.setOnClickListener(view -> {
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).loadChildFragment(new AddFeedFragment());
@@ -247,6 +276,10 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
if (disposable != null) {
disposable.dispose();
}
+
+ if (subscriptionAdapter != null) {
+ subscriptionAdapter.endSelectMode();
+ }
}
private void loadSubscriptions() {
@@ -271,6 +304,7 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
.subscribe(
result -> {
listItems = result;
+ subscriptionAdapter.setItems(result);
subscriptionAdapter.notifyDataSetChanged();
emptyView.updateVisibility();
progressBar.setVisibility(View.GONE); // Keep hidden to avoid flickering while refreshing
@@ -293,33 +327,12 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
}
@Override
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
- if (menuInfo == null) {
- return;
- }
- AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
- int position = adapterInfo.position;
-
- NavDrawerData.DrawerItem selectedObject = (NavDrawerData.DrawerItem) subscriptionAdapter.getItem(position);
-
- if (selectedObject.type == NavDrawerData.DrawerItem.Type.FEED) {
- MenuInflater inflater = requireActivity().getMenuInflater();
- inflater.inflate(R.menu.nav_feed_context, menu);
- selectedFeed = ((NavDrawerData.FeedDrawerItem) selectedObject).feed;
- }
- menu.setHeaderTitle(selectedObject.getTitle());
- }
-
- @Override
public boolean onContextItemSelected(MenuItem item) {
- if (selectedFeed == null) {
+ Feed feed = subscriptionAdapter.getSelectedFeed();
+ if (feed == null) {
return false;
}
-
- Feed feed = selectedFeed;
- selectedFeed = null;
- final int itemId = item.getItemId();
+ int itemId = item.getItemId();
if (itemId == R.id.remove_all_new_flags_item) {
displayConfirmationDialog(
R.string.remove_all_new_flags_label,
@@ -335,6 +348,9 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
} else if (itemId == R.id.remove_item) {
RemoveFeedDialog.show(getContext(), feed, null);
return true;
+ } else if (itemId == R.id.multi_select) {
+ speedDialView.setVisibility(View.VISIBLE);
+ return subscriptionAdapter.onContextItemSelected(item);
}
return super.onContextItemSelected(item);
}
@@ -376,23 +392,23 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker =
() -> DownloadService.isRunning && DownloadRequester.getInstance().isDownloadingFeeds();
- private final SubscriptionsAdapter.ItemAccess itemAccess = new SubscriptionsAdapter.ItemAccess() {
- @Override
- public int getCount() {
- if (listItems != null) {
- return listItems.size();
- } else {
- return 0;
- }
- }
+ @Override
+ public void onEndSelectMode() {
+ speedDialView.close();
+ speedDialView.setVisibility(View.GONE);
+ subscriptionAdapter.setItems(listItems);
+ subscriptionAdapter.notifyDataSetChanged();
+ }
- @Override
- public NavDrawerData.DrawerItem getItem(int position) {
- if (listItems != null && 0 <= position && position < listItems.size()) {
- return listItems.get(position);
- } else {
- return null;
+ @Override
+ public void onStartSelectMode() {
+ List<NavDrawerData.DrawerItem> feedsOnly = new ArrayList<>();
+ for (NavDrawerData.DrawerItem item : listItems) {
+ if (item.type == NavDrawerData.DrawerItem.Type.FEED) {
+ feedsOnly.add(item);
}
}
- };
+ subscriptionAdapter.setItems(feedsOnly);
+ subscriptionAdapter.notifyDataSetChanged();
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java b/app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java
new file mode 100644
index 000000000..f160b2241
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java
@@ -0,0 +1,139 @@
+package de.danoeh.antennapod.fragment.actions;
+
+import android.util.Log;
+
+import androidx.annotation.PluralsRes;
+import androidx.core.util.Consumer;
+
+import com.google.android.material.snackbar.Snackbar;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.List;
+import java.util.Locale;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.dialog.RemoveFeedDialog;
+import de.danoeh.antennapod.fragment.preferences.dialog.PreferenceListDialog;
+import de.danoeh.antennapod.fragment.preferences.dialog.PreferenceSwitchDialog;
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.model.feed.FeedPreferences;
+
+public class FeedMultiSelectActionHandler {
+ private static final String TAG = "FeedSelectHandler";
+ private final MainActivity activity;
+ private final List<Feed> selectedItems;
+
+ public FeedMultiSelectActionHandler(MainActivity activity, List<Feed> selectedItems) {
+ this.activity = activity;
+ this.selectedItems = selectedItems;
+ }
+
+ public void handleAction(int id) {
+ if (id == R.id.remove_item) {
+ RemoveFeedDialog.show(activity, selectedItems, null);
+ } else if (id == R.id.keep_updated) {
+ keepUpdatedPrefHandler();
+ } else if (id == R.id.autodownload) {
+ autoDownloadPrefHandler();
+ } else if (id == R.id.autoDeleteDownload) {
+ autoDeleteEpisodesPrefHandler();
+ } else if (id == R.id.playback_speed) {
+ playbackSpeedPrefHandler();
+ } else {
+ Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=" + id);
+ }
+ }
+
+ private void autoDownloadPrefHandler() {
+ PreferenceSwitchDialog preferenceSwitchDialog = new PreferenceSwitchDialog(activity,
+ activity.getString(R.string.auto_download_settings_label),
+ activity.getString(R.string.auto_download_label));
+ preferenceSwitchDialog.setOnPreferenceChangedListener(new PreferenceSwitchDialog.OnPreferenceChangedListener() {
+ @Override
+ public void preferenceChanged(boolean enabled) {
+ saveFeedPreferences(feedPreferences -> feedPreferences.setAutoDownload(enabled));
+ }
+ });
+ preferenceSwitchDialog.openDialog();
+ }
+
+ private static final DecimalFormat SPEED_FORMAT =
+ new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.US));
+
+ private void playbackSpeedPrefHandler() {
+ final String[] speeds = activity.getResources().getStringArray(R.array.playback_speed_values);
+ String[] values = new String[speeds.length + 1];
+ values[0] = SPEED_FORMAT.format(FeedPreferences.SPEED_USE_GLOBAL);
+
+ String[] entries = new String[speeds.length + 1];
+ entries[0] = activity.getString(R.string.feed_auto_download_global);
+
+ System.arraycopy(speeds, 0, values, 1, speeds.length);
+ System.arraycopy(speeds, 0, entries, 1, speeds.length);
+
+ PreferenceListDialog preferenceListDialog = new PreferenceListDialog(activity,
+ activity.getString(R.string.playback_speed));
+ preferenceListDialog.openDialog(entries);
+ preferenceListDialog.setOnPreferenceChangedListener(pos -> {
+ saveFeedPreferences(feedPreferences -> {
+ feedPreferences.setFeedPlaybackSpeed(Float.parseFloat((String) values[pos]));
+ });
+
+ });
+ }
+
+ private void autoDeleteEpisodesPrefHandler() {
+ PreferenceListDialog preferenceListDialog = new PreferenceListDialog(activity,
+ "Auto delete episodes");
+ String[] items = activity.getResources().getStringArray(R.array.spnAutoDeleteItems);
+ String[] values = activity.getResources().getStringArray(R.array.spnAutoDeleteValues);
+ preferenceListDialog.openDialog(items);
+ preferenceListDialog.setOnPreferenceChangedListener(which -> {
+ FeedPreferences.AutoDeleteAction autoDeleteAction = null;
+ switch (values[which]) {
+ case "global":
+ autoDeleteAction = FeedPreferences.AutoDeleteAction.GLOBAL;
+ break;
+ case "always":
+ autoDeleteAction = FeedPreferences.AutoDeleteAction.YES;
+ break;
+ case "never":
+ autoDeleteAction = FeedPreferences.AutoDeleteAction.NO;
+ break;
+ default:
+ }
+ FeedPreferences.AutoDeleteAction finalAutoDeleteAction = autoDeleteAction;
+ saveFeedPreferences(feedPreferences -> {
+ feedPreferences.setAutoDeleteAction(finalAutoDeleteAction);
+ });
+ });
+ }
+
+ private void keepUpdatedPrefHandler() {
+ PreferenceSwitchDialog preferenceSwitchDialog = new PreferenceSwitchDialog(activity,
+ activity.getString(R.string.kept_updated),
+ activity.getString(R.string.keep_updated_summary));
+ preferenceSwitchDialog.setOnPreferenceChangedListener(keepUpdated -> {
+ saveFeedPreferences(feedPreferences -> {
+ feedPreferences.setKeepUpdated(keepUpdated);
+ });
+ });
+ preferenceSwitchDialog.openDialog();
+ }
+
+ private void showMessage(@PluralsRes int msgId, int numItems) {
+ activity.showSnackbarAbovePlayer(activity.getResources()
+ .getQuantityString(msgId, numItems, numItems), Snackbar.LENGTH_LONG);
+ }
+
+ private void saveFeedPreferences(Consumer<FeedPreferences> preferencesConsumer) {
+ for (Feed feed : selectedItems) {
+ preferencesConsumer.accept(feed.getPreferences());
+ DBWriter.setFeedPreferences(feed.getPreferences());
+ }
+ showMessage(R.plurals.updated_feeds_batch_label, selectedItems.size());
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceListDialog.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceListDialog.java
new file mode 100644
index 000000000..d5c487d1d
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceListDialog.java
@@ -0,0 +1,49 @@
+package de.danoeh.antennapod.fragment.preferences.dialog;
+
+import android.content.Context;
+
+import androidx.appcompat.app.AlertDialog;
+
+import de.danoeh.antennapod.R;
+
+public class PreferenceListDialog {
+ protected Context context;
+ private String title;
+ private OnPreferenceChangedListener onPreferenceChangedListener;
+ private int selectedPos = 0;
+
+ public PreferenceListDialog(Context context, String title) {
+ this.context = context;
+ this.title = title;
+ }
+
+ public interface OnPreferenceChangedListener {
+ /**
+ * Notified when user confirms preference
+ *
+ * @param pos The index of the item that was selected
+ */
+
+ void preferenceChanged(int pos);
+ }
+
+ public void openDialog(String[] items) {
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(title);
+ builder.setSingleChoiceItems(items, selectedPos, (dialog, which) -> {
+ selectedPos = which;
+ });
+ builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
+ if (onPreferenceChangedListener != null && selectedPos >= 0) {
+ onPreferenceChangedListener.preferenceChanged(selectedPos);
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_label, null);
+ builder.create().show();
+ }
+
+ public void setOnPreferenceChangedListener(OnPreferenceChangedListener onPreferenceChangedListener) {
+ this.onPreferenceChangedListener = onPreferenceChangedListener;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceSwitchDialog.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceSwitchDialog.java
new file mode 100644
index 000000000..cc7c92194
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceSwitchDialog.java
@@ -0,0 +1,57 @@
+package de.danoeh.antennapod.fragment.preferences.dialog;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.widget.SwitchCompat;
+
+import de.danoeh.antennapod.R;
+
+public class PreferenceSwitchDialog {
+ protected Context context;
+ private String title;
+ private String text;
+ private OnPreferenceChangedListener onPreferenceChangedListener;
+
+ public PreferenceSwitchDialog(Context context, String title, String text) {
+ this.context = context;
+ this.title = title;
+ this.text = text;
+ }
+
+ public interface OnPreferenceChangedListener {
+ /**
+ * Notified when user confirms preference
+ *
+ * @param enabled The preference
+ */
+
+ void preferenceChanged(boolean enabled);
+ }
+
+ public void openDialog() {
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(title);
+
+ LayoutInflater inflater = LayoutInflater.from(this.context);
+ View layout = inflater.inflate(R.layout.dialog_switch_preference, null, false);
+ SwitchCompat switchButton = layout.findViewById(R.id.dialogSwitch);
+ switchButton.setText(text);
+ builder.setView(layout);
+
+ builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
+ if (onPreferenceChangedListener != null) {
+ onPreferenceChangedListener.preferenceChanged(switchButton.isChecked());
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_label, null);
+ builder.create().show();
+ }
+
+ public void setOnPreferenceChangedListener(OnPreferenceChangedListener onPreferenceChangedListener) {
+ this.onPreferenceChangedListener = onPreferenceChangedListener;
+ }
+}
diff --git a/app/src/main/res/layout/dialog_switch_preference.xml b/app/src/main/res/layout/dialog_switch_preference.xml
new file mode 100644
index 000000000..87f321c86
--- /dev/null
+++ b/app/src/main/res/layout/dialog_switch_preference.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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="match_parent"
+ android:padding="24dp">
+
+ <androidx.appcompat.widget.SwitchCompat
+ android:id="@+id/dialogSwitch"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:text="Switch" />
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/fragment_subscriptions.xml b/app/src/main/res/layout/fragment_subscriptions.xml
index 61d33f534..6dd112eed 100644
--- a/app/src/main/res/layout/fragment_subscriptions.xml
+++ b/app/src/main/res/layout/fragment_subscriptions.xml
@@ -1,33 +1,34 @@
<?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"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+<RelativeLayout
+ 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">
<androidx.appcompat.widget.Toolbar
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?attr/actionBarSize"
- android:theme="?attr/actionBarTheme"
- android:layout_alignParentTop="true"
- app:title="@string/subscriptions_label"
- app:navigationIcon="?homeAsUpIndicator"
- android:id="@+id/toolbar"/>
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?attr/actionBarSize"
+ android:theme="?attr/actionBarTheme"
+ android:layout_alignParentTop="true"
+ app:title="@string/subscriptions_label"
+ app:navigationIcon="?homeAsUpIndicator" />
<TextView
- android:id="@+id/feeds_filtered_message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/toolbar"
- android:background="?android:attr/selectableItemBackground"
- android:gravity="start"
- android:paddingStart="8dp"
- android:paddingTop="4dp"
- android:paddingEnd="8dp"
- android:paddingBottom="8dp"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_small" />
+ android:id="@+id/feeds_filtered_message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/toolbar"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="start"
+ android:paddingStart="8dp"
+ android:paddingTop="4dp"
+ android:paddingEnd="8dp"
+ android:paddingBottom="8dp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_small" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefresh"
@@ -35,35 +36,36 @@
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.recyclerview.widget.RecyclerView
+ android:id="@+id/subscriptions_grid"
+ android:layout_width="match_parent"
+ 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"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:indeterminateOnly="true"
- android:visibility="visible"/>
+ android:id="@+id/progLoading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:indeterminateOnly="true"
+ android:visibility="visible" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
- android:id="@+id/subscriptions_add"
- android:layout_width="56dp"
- android:layout_height="56dp"
- android:layout_margin="16dp"
- android:layout_alignParentBottom="true"
- android:layout_alignParentEnd="true"
- android:layout_alignParentRight="true"
- android:contentDescription="@string/add_feed_label"
- app:srcCompat="@drawable/ic_add"/>
+ android:id="@+id/subscriptions_add"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
+ android:layout_margin="16dp"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:contentDescription="@string/add_feed_label"
+ app:srcCompat="@drawable/ic_add" />
+
+ <include
+ layout="@layout/multi_select_speed_dial" />
+
</RelativeLayout>
diff --git a/app/src/main/res/layout/subscription_item.xml b/app/src/main/res/layout/subscription_item.xml
index ec918fdac..66628740f 100644
--- a/app/src/main/res/layout/subscription_item.xml
+++ b/app/src/main/res/layout/subscription_item.xml
@@ -1,11 +1,11 @@
-<?xml version='1.0' encoding='utf-8'?>
+<?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:squareImageView="http://schemas.android.com/apk/de.danoeh.antennapod"
xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground">
<de.danoeh.antennapod.ui.common.SquareImageView
@@ -15,7 +15,7 @@
android:background="@color/non_square_icon_background"
android:scaleType="fitCenter"
squareImageView:direction="width"
- tools:src="@mipmap/ic_launcher_round" />
+ tools:src="@tools:sample/avatars" />
<com.joanzapata.iconify.widget.IconTextView
android:id="@+id/txtvTitle"
@@ -46,4 +46,20 @@
app:primaryTextColor="?attr/colorOnSecondary"
app:primaryTextSize="12sp" />
+ <FrameLayout
+ android:id="@+id/selectView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/ic_checkbox_background">
+
+ <CheckBox
+ android:id="@+id/selectCheckBox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="0dp"
+ android:minHeight="0dp"
+ android:layout_margin="8dp" />
+
+ </FrameLayout>
+
</RelativeLayout>
diff --git a/app/src/main/res/menu/nav_feed_action_speeddial.xml b/app/src/main/res/menu/nav_feed_action_speeddial.xml
new file mode 100644
index 000000000..2dfa002bb
--- /dev/null
+++ b/app/src/main/res/menu/nav_feed_action_speeddial.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/remove_item"
+ android:menuCategory="container"
+ android:title="@string/remove_feed_label"
+ android:icon="@drawable/ic_delete"/>
+ <item
+ android:id="@+id/keep_updated"
+ android:menuCategory="container"
+ android:title="@string/keep_updated"
+ android:icon="@drawable/ic_refresh"/>
+ <item
+ android:id="@+id/autodownload"
+ android:menuCategory="container"
+ android:title="@string/auto_download_label"
+ android:icon="@drawable/ic_download"/>
+ <item
+ android:id="@+id/autoDeleteDownload"
+ android:menuCategory="container"
+ android:title="@string/auto_delete_label"
+ android:icon="@drawable/ic_delete_auto"/>
+ <item
+ android:id="@+id/playback_speed"
+ android:menuCategory="container"
+ android:title="@string/playback_speed"
+ android:icon="@drawable/ic_playback_speed"/>
+</menu>
diff --git a/app/src/main/res/menu/nav_feed_context.xml b/app/src/main/res/menu/nav_feed_context.xml
index 4ded52caf..e2b990023 100644
--- a/app/src/main/res/menu/nav_feed_context.xml
+++ b/app/src/main/res/menu/nav_feed_context.xml
@@ -21,4 +21,8 @@
android:menuCategory="container"
android:title="@string/remove_feed_label" />
+ <item
+ android:id="@+id/multi_select"
+ android:menuCategory="container"
+ android:title="@string/multi_select" />
</menu>