From e9b3cc34fe211ab3b03c30c6c483078b99ba7561 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 14 Apr 2024 11:45:12 +0200 Subject: [PATCH] Optionally display subscriptions as a simple list (#7087) --- .../subscriptions/SubscriptionFragment.java | 30 +++- .../subscriptions/SubscriptionViewHolder.java | 104 +++++++++++ .../SubscriptionsRecyclerAdapter.java | 165 ++++++------------ .../res/layout/fragment_subscriptions.xml | 2 +- ...on_item.xml => subscription_grid_item.xml} | 4 +- .../res/layout/subscription_list_item.xml | 91 ++++++++++ app/src/main/res/menu/subscriptions.xml | 3 + app/src/main/res/values/ids.xml | 3 + ui/i18n/src/main/res/values/strings.xml | 1 + 9 files changed, 278 insertions(+), 125 deletions(-) create mode 100644 app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionViewHolder.java rename app/src/main/res/layout/{subscription_item.xml => subscription_grid_item.xml} (97%) create mode 100644 app/src/main/res/layout/subscription_list_item.xml diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionFragment.java index a62e8775f..1176c948d 100644 --- a/app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionFragment.java @@ -64,8 +64,9 @@ public class SubscriptionFragment extends Fragment private static final String KEY_UP_ARROW = "up_arrow"; private static final String ARGUMENT_FOLDER = "folder"; - private static final int MIN_NUM_COLUMNS = 2; + private static final int MIN_NUM_COLUMNS = 1; private static final int[] COLUMN_CHECKBOX_IDS = { + R.id.subscription_display_list, R.id.subscription_num_columns_2, R.id.subscription_num_columns_3, R.id.subscription_num_columns_4, @@ -85,9 +86,8 @@ public class SubscriptionFragment extends Fragment private SharedPreferences prefs; private FloatingActionButton subscriptionAddButton; - private SpeedDialView speedDialView; - + private RecyclerView.ItemDecoration itemDecoration; private List listItems; public static SubscriptionFragment newInstance(String folderTitle) { @@ -121,7 +121,7 @@ public class SubscriptionFragment extends Fragment } ((MainActivity) getActivity()).setupToolbarToggle(toolbar, displayUpArrow); toolbar.inflateMenu(R.menu.subscriptions); - for (int i = 0; i < COLUMN_CHECKBOX_IDS.length; i++) { + for (int i = 1; i < COLUMN_CHECKBOX_IDS.length; i++) { // Do this in Java to localize numbers toolbar.getMenu().findItem(COLUMN_CHECKBOX_IDS[i]) .setTitle(String.format(Locale.getDefault(), "%d", i + MIN_NUM_COLUMNS)); @@ -136,7 +136,6 @@ public class SubscriptionFragment extends Fragment } subscriptionRecycler = root.findViewById(R.id.subscriptions_grid); - subscriptionRecycler.addItemDecoration(new SubscriptionsRecyclerAdapter.GridDividerItemDecorator()); registerForContextMenu(subscriptionRecycler); subscriptionRecycler.addOnScrollListener(new LiftOnScrollListener(root.findViewById(R.id.appbar))); subscriptionAdapter = new SubscriptionsRecyclerAdapter((MainActivity) getActivity()) { @@ -209,6 +208,9 @@ public class SubscriptionFragment extends Fragment } else if (itemId == R.id.subscriptions_sort) { FeedSortDialog.showDialog(requireContext()); return true; + } else if (itemId == R.id.subscription_display_list) { + setColumnNumber(1); + return true; } else if (itemId == R.id.subscription_num_columns_2) { setColumnNumber(2); return true; @@ -232,10 +234,22 @@ public class SubscriptionFragment extends Fragment } private void setColumnNumber(int columns) { - GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), - columns, RecyclerView.VERTICAL, false); + if (itemDecoration != null) { + subscriptionRecycler.removeItemDecoration(itemDecoration); + itemDecoration = null; + } + RecyclerView.LayoutManager layoutManager; + if (columns == 1 && getDefaultNumOfColumns() == 5) { // Tablet + layoutManager = new GridLayoutManager(getContext(), 2, RecyclerView.VERTICAL, false); + } else if (columns == 1) { + layoutManager = new GridLayoutManager(getContext(), 1, RecyclerView.VERTICAL, false); + } else { + layoutManager = new GridLayoutManager(getContext(), columns, RecyclerView.VERTICAL, false); + itemDecoration = new SubscriptionsRecyclerAdapter.GridDividerItemDecorator(); + subscriptionRecycler.addItemDecoration(itemDecoration); + } subscriptionAdapter.setColumnCount(columns); - subscriptionRecycler.setLayoutManager(gridLayoutManager); + subscriptionRecycler.setLayoutManager(layoutManager); prefs.edit().putInt(PREF_NUM_COLUMNS, columns).apply(); refreshToolbarState(); } diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionViewHolder.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionViewHolder.java new file mode 100644 index 000000000..b28c50bd1 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionViewHolder.java @@ -0,0 +1,104 @@ +package de.danoeh.antennapod.ui.screen.subscriptions; + +import android.graphics.drawable.Drawable; +import android.view.View; +import android.widget.CheckBox; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.appcompat.content.res.AppCompatResources; +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.RecyclerView; +import com.google.android.material.elevation.SurfaceColors; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.model.feed.Feed; +import de.danoeh.antennapod.storage.database.NavDrawerData; +import de.danoeh.antennapod.storage.preferences.UserPreferences; +import de.danoeh.antennapod.ui.CoverLoader; + +import java.lang.ref.WeakReference; +import java.text.NumberFormat; + +public class SubscriptionViewHolder extends RecyclerView.ViewHolder { + public final TextView title; + public final ImageView coverImage; + public final TextView count; + public final TextView fallbackTitle; + public final FrameLayout selectView; + public final CheckBox selectCheckbox; + public final CardView card; + public final View errorIcon; + public final WeakReference mainActivityRef; + + public SubscriptionViewHolder(@NonNull View itemView, MainActivity mainActivity) { + super(itemView); + title = itemView.findViewById(R.id.titleLabel); + coverImage = itemView.findViewById(R.id.coverImage); + count = itemView.findViewById(R.id.countViewPill); + fallbackTitle = itemView.findViewById(R.id.fallbackTitleLabel); + selectView = itemView.findViewById(R.id.selectContainer); + selectCheckbox = itemView.findViewById(R.id.selectCheckBox); + card = itemView.findViewById(R.id.outerContainer); + errorIcon = itemView.findViewById(R.id.errorIcon); + this.mainActivityRef = new WeakReference<>(mainActivity); + } + + public void bind(NavDrawerData.DrawerItem drawerItem, int columnCount) { + if (selectView != null) { + Drawable drawable = AppCompatResources.getDrawable(selectView.getContext(), + R.drawable.ic_checkbox_background); + selectView.setBackground(drawable); // Setting this in XML crashes API <= 21 + } + title.setText(drawerItem.getTitle()); + fallbackTitle.setText(drawerItem.getTitle()); + coverImage.setContentDescription(drawerItem.getTitle()); + if (drawerItem.getCounter() > 0) { + count.setText(NumberFormat.getInstance().format(drawerItem.getCounter())); + count.setVisibility(View.VISIBLE); + } else { + count.setVisibility(View.GONE); + } + + CoverLoader coverLoader = new CoverLoader(); + boolean textAndImageCombined; + if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) { + Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed; + textAndImageCombined = feed.isLocalFeed() && feed.getImageUrl() != null + && feed.getImageUrl().startsWith(Feed.PREFIX_GENERATIVE_COVER); + coverLoader.withUri(feed.getImageUrl()); + errorIcon.setVisibility(feed.hasLastUpdateFailed() ? View.VISIBLE : View.GONE); + } else { + textAndImageCombined = true; + coverLoader.withResource(R.drawable.ic_tag); + errorIcon.setVisibility(View.GONE); + } + if (UserPreferences.shouldShowSubscriptionTitle() || columnCount == 1) { + // No need for fallback title when already showing title + fallbackTitle.setVisibility(View.GONE); + } else { + coverLoader.withPlaceholderView(fallbackTitle, textAndImageCombined); + } + coverLoader.withCoverView(coverImage); + coverLoader.load(); + + if (card != null) { + float density = mainActivityRef.get().getResources().getDisplayMetrics().density; + card.setCardBackgroundColor(SurfaceColors.getColorForElevation(mainActivityRef.get(), 1 * density)); + } + + int textPadding = columnCount <= 3 ? 16 : 8; + title.setPadding(textPadding, textPadding, textPadding, textPadding); + fallbackTitle.setPadding(textPadding, textPadding, textPadding, textPadding); + + int textSize = 14; + if (columnCount == 3) { + textSize = 15; + } else if (columnCount == 2) { + textSize = 16; + } + title.setTextSize(textSize); + fallbackTitle.setTextSize(textSize); + } +} \ No newline at end of file diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionsRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionsRecyclerAdapter.java index fecb191b3..2ca09ff4f 100644 --- a/app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionsRecyclerAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/subscriptions/SubscriptionsRecyclerAdapter.java @@ -3,7 +3,6 @@ package de.danoeh.antennapod.ui.screen.subscriptions; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.os.Build; import android.view.ContextMenu; import android.view.InputDevice; @@ -13,39 +12,27 @@ import android.view.MenuItem; import android.view.MotionEvent; 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.appcompat.content.res.AppCompatResources; -import androidx.cardview.widget.CardView; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.RecyclerView; - -import com.google.android.material.elevation.SurfaceColors; -import java.lang.ref.WeakReference; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.List; - import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; -import de.danoeh.antennapod.ui.CoverLoader; -import de.danoeh.antennapod.ui.SelectableAdapter; -import de.danoeh.antennapod.storage.preferences.UserPreferences; -import de.danoeh.antennapod.storage.database.NavDrawerData; -import de.danoeh.antennapod.ui.screen.feed.FeedItemlistFragment; import de.danoeh.antennapod.model.feed.Feed; +import de.danoeh.antennapod.storage.database.NavDrawerData; +import de.danoeh.antennapod.storage.preferences.UserPreferences; +import de.danoeh.antennapod.ui.SelectableAdapter; +import de.danoeh.antennapod.ui.common.ThemeUtils; +import de.danoeh.antennapod.ui.screen.feed.FeedItemlistFragment; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; /** * Adapter for subscriptions */ -public class SubscriptionsRecyclerAdapter extends SelectableAdapter +public class SubscriptionsRecyclerAdapter extends SelectableAdapter implements View.OnCreateContextMenuListener { - private static final int COVER_WITH_TITLE = 1; - private final WeakReference mainActivityRef; private List listItems; private NavDrawerData.DrawerItem selectedItem = null; @@ -74,30 +61,49 @@ public class SubscriptionsRecyclerAdapter extends SelectableAdapter setSelected(holder.getBindingAdapterPosition(), isChecked)); + holder.count.setVisibility(View.GONE); + } else { + holder.itemView.setBackgroundResource(android.R.color.transparent); + if (isSelected(position)) { + holder.itemView.setBackgroundColor(0x88000000 + + (0xffffff & ThemeUtils.getColorFromAttr(mainActivityRef.get(), R.attr.colorAccent))); + } } - holder.selectCheckbox.setChecked((isSelected(position))); - holder.selectCheckbox.setOnCheckedChangeListener((buttonView, isChecked) - -> setSelected(holder.getBindingAdapterPosition(), isChecked)); - holder.coverImage.setAlpha(0.6f); - holder.count.setVisibility(View.GONE); } else { - holder.selectView.setVisibility(View.GONE); - holder.coverImage.setAlpha(1.0f); + holder.itemView.setBackgroundResource(android.R.color.transparent); + if (holder.selectView != null) { + holder.selectCheckbox.setVisibility(View.GONE); + holder.selectView.setVisibility(View.GONE); + holder.coverImage.setAlpha(1.0f); + } } holder.itemView.setOnLongClickListener(v -> { @@ -127,7 +133,8 @@ public class SubscriptionsRecyclerAdapter extends SelectableAdapter { if (isFeed) { if (inActionMode()) { - holder.selectCheckbox.setChecked(!isSelected(holder.getBindingAdapterPosition())); + setSelected(holder.getBindingAdapterPosition(), !isSelected(holder.getBindingAdapterPosition())); + notifyItemChanged(holder.getBindingAdapterPosition()); } else { Fragment fragment = FeedItemlistFragment .newInstance(((NavDrawerData.FeedDrawerItem) drawerItem).feed.getId()); @@ -206,82 +213,12 @@ public class SubscriptionsRecyclerAdapter extends SelectableAdapter 0) { - count.setText(NumberFormat.getInstance().format(drawerItem.getCounter())); - count.setVisibility(View.VISIBLE); - } else { - count.setVisibility(View.GONE); - } - - CoverLoader coverLoader = new CoverLoader(); - boolean textAndImageCombined; - if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) { - Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed; - textAndImageCombined = feed.isLocalFeed() && feed.getImageUrl() != null - && feed.getImageUrl().startsWith(Feed.PREFIX_GENERATIVE_COVER); - coverLoader.withUri(feed.getImageUrl()); - errorIcon.setVisibility(feed.hasLastUpdateFailed() ? View.VISIBLE : View.GONE); - } else { - textAndImageCombined = true; - coverLoader.withResource(R.drawable.ic_tag); - errorIcon.setVisibility(View.GONE); - } - if (UserPreferences.shouldShowSubscriptionTitle()) { - // No need for fallback title when already showing title - fallbackTitle.setVisibility(View.GONE); - } else { - coverLoader.withPlaceholderView(fallbackTitle, textAndImageCombined); - } - coverLoader.withCoverView(coverImage); - coverLoader.load(); - - float density = mainActivityRef.get().getResources().getDisplayMetrics().density; - card.setCardBackgroundColor(SurfaceColors.getColorForElevation(mainActivityRef.get(), 1 * density)); - - int textPadding = columnCount <= 3 ? 16 : 8; - title.setPadding(textPadding, textPadding, textPadding, textPadding); - fallbackTitle.setPadding(textPadding, textPadding, textPadding, textPadding); - - int textSize = 14; - if (columnCount == 3) { - textSize = 15; - } else if (columnCount == 2) { - textSize = 16; - } - title.setTextSize(textSize); - fallbackTitle.setTextSize(textSize); + if (columnCount == 1) { + return R.id.view_type_subscription_list; + } else if (UserPreferences.shouldShowSubscriptionTitle()) { + return R.id.view_type_subscription_grid_with_title; + } else { + return R.id.view_type_subscription_grid_without_title; } } diff --git a/app/src/main/res/layout/fragment_subscriptions.xml b/app/src/main/res/layout/fragment_subscriptions.xml index ac40bf5a4..dbf0fc11d 100644 --- a/app/src/main/res/layout/fragment_subscriptions.xml +++ b/app/src/main/res/layout/fragment_subscriptions.xml @@ -61,7 +61,7 @@ android:layout_gravity="center_horizontal" android:paddingBottom="88dp" tools:itemCount="2" - tools:listitem="@layout/subscription_item" /> + tools:listitem="@layout/subscription_grid_item" /> diff --git a/app/src/main/res/layout/subscription_item.xml b/app/src/main/res/layout/subscription_grid_item.xml similarity index 97% rename from app/src/main/res/layout/subscription_item.xml rename to app/src/main/res/layout/subscription_grid_item.xml index b3271ffa3..f5130a020 100644 --- a/app/src/main/res/layout/subscription_item.xml +++ b/app/src/main/res/layout/subscription_grid_item.xml @@ -26,7 +26,6 @@ + android:layout_height="wrap_content" + android:layout_margin="1px"> + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/subscriptions.xml b/app/src/main/res/menu/subscriptions.xml index 3a2614149..95764aedb 100644 --- a/app/src/main/res/menu/subscriptions.xml +++ b/app/src/main/res/menu/subscriptions.xml @@ -31,6 +31,9 @@ + diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index 8c4091390..545e79da7 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -14,4 +14,7 @@ + + + diff --git a/ui/i18n/src/main/res/values/strings.xml b/ui/i18n/src/main/res/values/strings.xml index 6a4238779..b86792f20 100644 --- a/ui/i18n/src/main/res/values/strings.xml +++ b/ui/i18n/src/main/res/values/strings.xml @@ -823,6 +823,7 @@ Number of columns + List Errors