Converted nav list to RecyclerView

This commit is contained in:
ByteHamster 2020-11-02 20:20:37 +01:00
parent 2a2c495835
commit f978d307a9
3 changed files with 145 additions and 187 deletions

View File

@ -1,20 +1,19 @@
package de.danoeh.antennapod.adapter; package de.danoeh.antennapod.adapter;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.RequestOptions;
import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.Iconify;
@ -44,10 +43,9 @@ import java.util.List;
/** /**
* BaseAdapter for the navigation drawer * BaseAdapter for the navigation drawer
*/ */
public class NavListAdapter extends BaseAdapter public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder>
implements SharedPreferences.OnSharedPreferenceChangeListener { implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final int VIEW_TYPE_COUNT = 3;
public static final int VIEW_TYPE_NAV = 0; public static final int VIEW_TYPE_NAV = 0;
public static final int VIEW_TYPE_SECTION_DIVIDER = 1; public static final int VIEW_TYPE_SECTION_DIVIDER = 1;
private static final int VIEW_TYPE_SUBSCRIPTION = 2; private static final int VIEW_TYPE_SUBSCRIPTION = 2;
@ -145,9 +143,8 @@ public class NavListAdapter extends BaseAdapter
return Collections.unmodifiableList(fragmentTags); return Collections.unmodifiableList(fragmentTags);
} }
@Override @Override
public int getCount() { public int getItemCount() {
int baseCount = getSubscriptionOffset(); int baseCount = getSubscriptionOffset();
if (showSubscriptionList) { if (showSubscriptionList) {
baseCount += itemAccess.getCount(); baseCount += itemAccess.getCount();
@ -155,18 +152,6 @@ public class NavListAdapter extends BaseAdapter
return baseCount; return baseCount;
} }
@Override
public Object getItem(int position) {
int viewType = getItemViewType(position);
if (viewType == VIEW_TYPE_NAV) {
return getLabel(fragmentTags.get(position));
} else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
return "";
} else {
return itemAccess.getItem(position);
}
}
@Override @Override
public long getItemId(int position) { public long getItemId(int position) {
int viewType = getItemViewType(position); int viewType = getItemViewType(position);
@ -177,11 +162,6 @@ public class NavListAdapter extends BaseAdapter
} }
} }
@Override
public boolean hasStableIds() {
return true;
}
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if (0 <= position && position < fragmentTags.size()) { if (0 <= position && position < fragmentTags.size()) {
@ -193,68 +173,59 @@ public class NavListAdapter extends BaseAdapter
} }
} }
@Override
public int getViewTypeCount() {
return VIEW_TYPE_COUNT;
}
public int getSubscriptionOffset() { public int getSubscriptionOffset() {
return fragmentTags.size() > 0 ? fragmentTags.size() + 1 : 0; return fragmentTags.size() > 0 ? fragmentTags.size() + 1 : 0;
} }
@NonNull
@Override
public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_NAV) {
return new NavHolder(View.inflate(activity.get(), R.layout.nav_listitem, null));
} else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
return new DividerHolder(View.inflate(activity.get(), R.layout.nav_section_item, null));
} else {
return new FeedHolder(View.inflate(activity.get(), R.layout.nav_listitem, null));
}
}
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public void onBindViewHolder(@NonNull Holder holder, int position) {
int viewType = getItemViewType(position); int viewType = getItemViewType(position);
View v;
if (viewType == VIEW_TYPE_NAV) { if (viewType == VIEW_TYPE_NAV) {
v = getNavView((String) getItem(position), position, convertView, parent); bindNavView(getLabel(fragmentTags.get(position)), position, (NavHolder) holder);
} else if (viewType == VIEW_TYPE_SECTION_DIVIDER) { } else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
v = getSectionDividerView(convertView, parent); bindSectionDivider((DividerHolder) holder);
} else { } else {
int itemPos = position - getSubscriptionOffset(); int itemPos = position - getSubscriptionOffset();
NavDrawerData.DrawerItem item = itemAccess.getItem(itemPos); NavDrawerData.DrawerItem item = itemAccess.getItem(itemPos);
if (item.type == NavDrawerData.DrawerItem.Type.FEED) { if (item.type == NavDrawerData.DrawerItem.Type.FEED) {
v = getFeedView((NavDrawerData.FeedDrawerItem) item, convertView, parent); bindFeedView((NavDrawerData.FeedDrawerItem) item, (FeedHolder) holder);
} else { } else {
v = getFolderView((NavDrawerData.FolderDrawerItem) item, convertView, parent); bindFolderView((NavDrawerData.FolderDrawerItem) item, (FeedHolder) holder);
} }
} }
if (v != null && viewType != VIEW_TYPE_SECTION_DIVIDER) { if (viewType != VIEW_TYPE_SECTION_DIVIDER) {
TypedValue typedValue = new TypedValue(); TypedValue typedValue = new TypedValue();
if (position == itemAccess.getSelectedItemIndex()) { if (position == itemAccess.getSelectedItemIndex()) {
v.getContext().getTheme().resolveAttribute(R.attr.drawer_activated_color, typedValue, true); activity.get().getTheme().resolveAttribute(R.attr.drawer_activated_color, typedValue, true);
v.setBackgroundResource(typedValue.resourceId); holder.itemView.setBackgroundResource(typedValue.resourceId);
} else { } else {
v.getContext().getTheme().resolveAttribute(android.R.attr.windowBackground, typedValue, true); activity.get().getTheme().resolveAttribute(android.R.attr.windowBackground, typedValue, true);
v.setBackgroundResource(typedValue.resourceId); holder.itemView.setBackgroundResource(typedValue.resourceId);
}
}
return v;
} }
private View getNavView(String title, int position, View convertView, ViewGroup parent) { holder.itemView.setOnClickListener(v -> itemAccess.onItemClick(position));
holder.itemView.setOnLongClickListener(v -> itemAccess.onItemLongClick(position));
}
}
private void bindNavView(String title, int position, NavHolder holder) {
Activity context = activity.get(); Activity context = activity.get();
if(context == null) { if(context == null) {
return null; return;
} }
NavHolder holder;
if (convertView == null) {
holder = new NavHolder();
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.nav_listitem, parent, false);
holder.image = convertView.findViewById(R.id.imgvCover);
holder.title = convertView.findViewById(R.id.txtvTitle);
holder.count = convertView.findViewById(R.id.txtvCount);
convertView.setTag(holder);
} else {
holder = (NavHolder) convertView.getTag();
}
holder.title.setText(title); holder.title.setText(title);
// reset for re-use // reset for re-use
@ -301,56 +272,30 @@ public class NavListAdapter extends BaseAdapter
} }
holder.image.setImageDrawable(getDrawable(fragmentTags.get(position))); holder.image.setImageDrawable(getDrawable(fragmentTags.get(position)));
return convertView;
} }
private View getSectionDividerView(View convertView, ViewGroup parent) { private void bindSectionDivider(DividerHolder holder) {
Activity context = activity.get(); Activity context = activity.get();
if(context == null) { if(context == null) {
return null; return;
} }
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.nav_section_item, parent, false);
TextView feedsFilteredMsg = convertView.findViewById(R.id.nav_feeds_filtered_message);
if (UserPreferences.getSubscriptionsFilter().isEnabled() && showSubscriptionList) { if (UserPreferences.getSubscriptionsFilter().isEnabled() && showSubscriptionList) {
convertView.setEnabled(true); holder.itemView.setEnabled(true);
feedsFilteredMsg.setText("{md-info-outline} " + context.getString(R.string.subscriptions_are_filtered)); holder.feedsFilteredMsg.setText("{md-info-outline} " + context.getString(R.string.subscriptions_are_filtered));
Iconify.addIcons(feedsFilteredMsg); Iconify.addIcons(holder.feedsFilteredMsg);
feedsFilteredMsg.setVisibility(View.VISIBLE); holder.feedsFilteredMsg.setVisibility(View.VISIBLE);
} else { } else {
convertView.setEnabled(false); holder.itemView.setEnabled(false);
feedsFilteredMsg.setVisibility(View.GONE); holder.feedsFilteredMsg.setVisibility(View.GONE);
}
} }
return convertView; private void bindFeedView(NavDrawerData.FeedDrawerItem drawerItem, FeedHolder holder) {
}
private View getFeedView(NavDrawerData.FeedDrawerItem drawerItem, View convertView, ViewGroup parent) {
Feed feed = drawerItem.feed; Feed feed = drawerItem.feed;
Activity context = activity.get(); Activity context = activity.get();
if (context == null) { if (context == null) {
return null; return;
}
FeedHolder holder;
if (convertView == null) {
holder = new FeedHolder();
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.nav_listitem, parent, false);
holder.image = convertView.findViewById(R.id.imgvCover);
holder.title = convertView.findViewById(R.id.txtvTitle);
holder.failure = convertView.findViewById(R.id.itxtvFailure);
holder.count = convertView.findViewById(R.id.txtvCount);
convertView.setTag(holder);
} else {
holder = (FeedHolder) convertView.getTag();
} }
Glide.with(context) Glide.with(context)
@ -381,31 +326,13 @@ public class NavListAdapter extends BaseAdapter
} else { } else {
holder.count.setVisibility(View.GONE); holder.count.setVisibility(View.GONE);
} }
convertView.setPadding(drawerItem.layer * 50, 0, 0, 0); // TODO holder.itemView.setPadding(drawerItem.layer * 50, 0, 0, 0); // TODO
return convertView;
} }
private View getFolderView(NavDrawerData.FolderDrawerItem drawerItem, View convertView, ViewGroup parent) { private void bindFolderView(NavDrawerData.FolderDrawerItem drawerItem, FeedHolder holder) {
Activity context = activity.get(); Activity context = activity.get();
if (context == null) { if (context == null) {
return null; return;
}
FeedHolder holder;
if (convertView == null) {
holder = new FeedHolder();
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.nav_listitem, parent, false);
holder.image = convertView.findViewById(R.id.imgvCover);
holder.title = convertView.findViewById(R.id.txtvTitle);
holder.failure = convertView.findViewById(R.id.itxtvFailure);
holder.count = convertView.findViewById(R.id.txtvCount);
convertView.setTag(holder);
} else {
holder = (FeedHolder) convertView.getTag();
} }
holder.image.setImageResource(ThemeUtils.getDrawableFromAttr(context, R.attr.ic_folder)); holder.image.setImageResource(ThemeUtils.getDrawableFromAttr(context, R.attr.ic_folder));
@ -413,21 +340,50 @@ public class NavListAdapter extends BaseAdapter
holder.failure.setVisibility(View.GONE); holder.failure.setVisibility(View.GONE);
holder.count.setText("?"); holder.count.setText("?");
convertView.setPadding(drawerItem.layer * 50, 0, 0, 0); // TODO holder.itemView.setPadding(drawerItem.layer * 50, 0, 0, 0); // TODO
return convertView;
} }
static class NavHolder { static class Holder extends RecyclerView.ViewHolder {
ImageView image; public Holder(@NonNull View itemView) {
TextView title; super(itemView);
TextView count; }
} }
static class FeedHolder { static class DividerHolder extends Holder {
ImageView image; final TextView feedsFilteredMsg;
TextView title;
IconTextView failure; public DividerHolder(@NonNull View itemView) {
TextView count; super(itemView);
feedsFilteredMsg = itemView.findViewById(R.id.nav_feeds_filtered_message);
}
}
static class NavHolder extends Holder {
final ImageView image;
final TextView title;
final TextView count;
public NavHolder(@NonNull View itemView) {
super(itemView);
image = itemView.findViewById(R.id.imgvCover);
title = itemView.findViewById(R.id.txtvTitle);
count = itemView.findViewById(R.id.txtvCount);
}
}
static class FeedHolder extends Holder {
final ImageView image;
final TextView title;
final IconTextView failure;
final TextView count;
public FeedHolder(@NonNull View itemView) {
super(itemView);
image = itemView.findViewById(R.id.imgvCover);
title = itemView.findViewById(R.id.txtvTitle);
failure = itemView.findViewById(R.id.itxtvFailure);
count = itemView.findViewById(R.id.txtvCount);
}
} }
public interface ItemAccess { public interface ItemAccess {
@ -440,6 +396,8 @@ public class NavListAdapter extends BaseAdapter
int getReclaimableItems(); int getReclaimableItems();
int getFeedCounter(long feedId); int getFeedCounter(long feedId);
int getFeedCounterSum(); int getFeedCounterSum();
void onItemClick(int position);
boolean onItemLongClick(int position);
} }
} }

View File

@ -21,6 +21,8 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetBehavior;
import de.danoeh.antennapod.R; import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.MainActivity;
@ -57,8 +59,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
public class NavDrawerFragment extends Fragment implements AdapterView.OnItemClickListener, public class NavDrawerFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener {
AdapterView.OnItemLongClickListener, SharedPreferences.OnSharedPreferenceChangeListener {
@VisibleForTesting @VisibleForTesting
public static final String PREF_LAST_FRAGMENT_TAG = "prefLastFragmentTag"; public static final String PREF_LAST_FRAGMENT_TAG = "prefLastFragmentTag";
@VisibleForTesting @VisibleForTesting
@ -91,11 +92,11 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
View root = inflater.inflate(R.layout.nav_list, container, false); View root = inflater.inflate(R.layout.nav_list, container, false);
progressBar = root.findViewById(R.id.progressBar); progressBar = root.findViewById(R.id.progressBar);
ListView navList = root.findViewById(R.id.nav_list); RecyclerView navList = root.findViewById(R.id.nav_list);
navAdapter = new NavListAdapter(itemAccess, getActivity()); navAdapter = new NavListAdapter(itemAccess, getActivity());
navAdapter.setHasStableIds(true);
navList.setAdapter(navAdapter); navList.setAdapter(navAdapter);
navList.setOnItemClickListener(this); navList.setLayoutManager(new LinearLayoutManager(getContext()));
navList.setOnItemLongClickListener(this);
registerForContextMenu(navList); registerForContextMenu(navList);
updateSelection(); updateSelection();
@ -376,43 +377,9 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
return sum; return sum;
} }
};
private void loadData() {
progressBar.setVisibility(View.VISIBLE);
disposable = Observable.fromCallable(DBReader::getNavDrawerData)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
result -> {
navDrawerData = result;
flatItemList = makeFlatDrawerData(navDrawerData.items); // TODO: This is the main thread!
updateSelection(); // Selected item might be a feed
navAdapter.notifyDataSetChanged();
progressBar.setVisibility(View.GONE);
}, error -> {
Log.e(TAG, Log.getStackTraceString(error));
progressBar.setVisibility(View.GONE);
});
}
private List<NavDrawerData.DrawerItem> makeFlatDrawerData(List<NavDrawerData.DrawerItem> items) {
List<NavDrawerData.DrawerItem> flatItems = new ArrayList<>();
for (NavDrawerData.DrawerItem item : items) {
flatItems.add(item);
if (item.type == NavDrawerData.DrawerItem.Type.FOLDER) {
NavDrawerData.FolderDrawerItem folder = ((NavDrawerData.FolderDrawerItem) item);
if (openFolders.contains(folder.name)) {
flatItems.addAll(makeFlatDrawerData(((NavDrawerData.FolderDrawerItem) item).children));
}
}
}
return flatItems;
}
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(int position) {
int viewType = parent.getAdapter().getItemViewType(position); int viewType = navAdapter.getItemViewType(position);
if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER) { if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER) {
if (position < navAdapter.getSubscriptionOffset()) { if (position < navAdapter.getSubscriptionOffset()) {
String tag = navAdapter.getTags().get(position); String tag = navAdapter.getTags().get(position);
@ -454,15 +421,48 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
} }
@Override @Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { public boolean onItemLongClick(int position) {
if (position < navAdapter.getTags().size()) { if (position < navAdapter.getTags().size()) {
showDrawerPreferencesDialog(); showDrawerPreferencesDialog();
return true; return true;
} else { } else {
this.position = position; NavDrawerFragment.this.position = position;
return false; return false;
} }
} }
};
private void loadData() {
progressBar.setVisibility(View.VISIBLE);
disposable = Observable.fromCallable(DBReader::getNavDrawerData)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
result -> {
navDrawerData = result;
flatItemList = makeFlatDrawerData(navDrawerData.items); // TODO: This is the main thread!
updateSelection(); // Selected item might be a feed
navAdapter.notifyDataSetChanged();
progressBar.setVisibility(View.GONE);
}, error -> {
Log.e(TAG, Log.getStackTraceString(error));
progressBar.setVisibility(View.GONE);
});
}
private List<NavDrawerData.DrawerItem> makeFlatDrawerData(List<NavDrawerData.DrawerItem> items) {
List<NavDrawerData.DrawerItem> flatItems = new ArrayList<>();
for (NavDrawerData.DrawerItem item : items) {
flatItems.add(item);
if (item.type == NavDrawerData.DrawerItem.Type.FOLDER) {
NavDrawerData.FolderDrawerItem folder = ((NavDrawerData.FolderDrawerItem) item);
if (openFolders.contains(folder.name)) {
flatItems.addAll(makeFlatDrawerData(((NavDrawerData.FolderDrawerItem) item).children));
}
}
}
return flatItems;
}
public static void saveLastNavFragment(Context context, String tag) { public static void saveLastNavFragment(Context context, String tag) {
Log.d(TAG, "saveLastNavFragment(tag: " + tag + ")"); Log.d(TAG, "saveLastNavFragment(tag: " + tag + ")");

View File

@ -57,7 +57,7 @@
android:background="?android:attr/listDivider" android:background="?android:attr/listDivider"
tools:background="@android:color/holo_red_dark" /> tools:background="@android:color/holo_red_dark" />
<ListView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/nav_list" android:id="@+id/nav_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"