Added basic proof of concept for displaying folders

This commit is contained in:
ByteHamster 2020-11-02 19:56:26 +01:00
parent b3c69f1a20
commit 2a2c495835
7 changed files with 227 additions and 70 deletions

View File

@ -11,6 +11,7 @@ import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.NavDrawerData;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.LongList;
import org.junit.After;
@ -313,8 +314,8 @@ public class DBReaderTest {
final int NUM_FEEDS = 10;
final int NUM_ITEMS = 10;
DBTestUtils.saveFeedlist(NUM_FEEDS, NUM_ITEMS, true);
DBReader.NavDrawerData navDrawerData = DBReader.getNavDrawerData();
assertEquals(NUM_FEEDS, navDrawerData.feeds.size());
NavDrawerData navDrawerData = DBReader.getNavDrawerData();
assertEquals(NUM_FEEDS, navDrawerData.items.size());
assertEquals(0, navDrawerData.numNewItems);
assertEquals(0, navDrawerData.queueSize);
}
@ -342,8 +343,8 @@ public class DBReaderTest {
adapter.close();
DBReader.NavDrawerData navDrawerData = DBReader.getNavDrawerData();
assertEquals(NUM_FEEDS, navDrawerData.feeds.size());
NavDrawerData navDrawerData = DBReader.getNavDrawerData();
assertEquals(NUM_FEEDS, navDrawerData.items.size());
assertEquals(NUM_NEW, navDrawerData.numNewItems);
assertEquals(NUM_QUEUE, navDrawerData.queueSize);
}

View File

@ -23,6 +23,8 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.NavDrawerData;
import de.danoeh.antennapod.core.util.ThemeUtils;
import de.danoeh.antennapod.fragment.AddFeedFragment;
import de.danoeh.antennapod.fragment.DownloadsFragment;
import de.danoeh.antennapod.fragment.EpisodesFragment;
@ -56,7 +58,7 @@ public class NavListAdapter extends BaseAdapter
*/
public static final String SUBSCRIPTION_LIST_TAG = "SubscriptionList";
private static List<String> tags;
private static List<String> fragmentTags;
private static String[] titles;
private final ItemAccess itemAccess;
@ -96,7 +98,7 @@ public class NavListAdapter extends BaseAdapter
showSubscriptionList = false;
}
tags = newTags;
fragmentTags = newTags;
notifyDataSetChanged();
}
@ -140,7 +142,7 @@ public class NavListAdapter extends BaseAdapter
}
public List<String> getTags() {
return Collections.unmodifiableList(tags);
return Collections.unmodifiableList(fragmentTags);
}
@ -157,7 +159,7 @@ public class NavListAdapter extends BaseAdapter
public Object getItem(int position) {
int viewType = getItemViewType(position);
if (viewType == VIEW_TYPE_NAV) {
return getLabel(tags.get(position));
return getLabel(fragmentTags.get(position));
} else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
return "";
} else {
@ -167,12 +169,22 @@ public class NavListAdapter extends BaseAdapter
@Override
public long getItemId(int position) {
return position;
int viewType = getItemViewType(position);
if (viewType == VIEW_TYPE_SUBSCRIPTION) {
return itemAccess.getItem(position - getSubscriptionOffset()).id;
} else {
return -position - 1; //TODO
}
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getItemViewType(int position) {
if (0 <= position && position < tags.size()) {
if (0 <= position && position < fragmentTags.size()) {
return VIEW_TYPE_NAV;
} else if (position < getSubscriptionOffset()) {
return VIEW_TYPE_SECTION_DIVIDER;
@ -187,7 +199,7 @@ public class NavListAdapter extends BaseAdapter
}
public int getSubscriptionOffset() {
return tags.size() > 0 ? tags.size() + 1 : 0;
return fragmentTags.size() > 0 ? fragmentTags.size() + 1 : 0;
}
@ -200,7 +212,13 @@ public class NavListAdapter extends BaseAdapter
} else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
v = getSectionDividerView(convertView, parent);
} else {
v = getFeedView(position, convertView, parent);
int itemPos = position - getSubscriptionOffset();
NavDrawerData.DrawerItem item = itemAccess.getItem(itemPos);
if (item.type == NavDrawerData.DrawerItem.Type.FEED) {
v = getFeedView((NavDrawerData.FeedDrawerItem) item, convertView, parent);
} else {
v = getFolderView((NavDrawerData.FolderDrawerItem) item, convertView, parent);
}
}
if (v != null && viewType != VIEW_TYPE_SECTION_DIVIDER) {
TypedValue typedValue = new TypedValue();
@ -243,7 +261,7 @@ public class NavListAdapter extends BaseAdapter
holder.count.setVisibility(View.GONE);
holder.count.setOnClickListener(null);
String tag = tags.get(position);
String tag = fragmentTags.get(position);
if (tag.equals(QueueFragment.TAG)) {
int queueSize = itemAccess.getQueueSize();
if (queueSize > 0) {
@ -282,7 +300,7 @@ public class NavListAdapter extends BaseAdapter
}
}
holder.image.setImageDrawable(getDrawable(tags.get(position)));
holder.image.setImageDrawable(getDrawable(fragmentTags.get(position)));
return convertView;
}
@ -311,13 +329,12 @@ public class NavListAdapter extends BaseAdapter
return convertView;
}
private View getFeedView(int position, View convertView, ViewGroup parent) {
private View getFeedView(NavDrawerData.FeedDrawerItem drawerItem, View convertView, ViewGroup parent) {
Feed feed = drawerItem.feed;
Activity context = activity.get();
if(context == null) {
if (context == null) {
return null;
}
int feedPos = position - getSubscriptionOffset();
Feed feed = itemAccess.getItem(feedPos);
FeedHolder holder;
if (convertView == null) {
@ -364,6 +381,39 @@ public class NavListAdapter extends BaseAdapter
} else {
holder.count.setVisibility(View.GONE);
}
convertView.setPadding(drawerItem.layer * 50, 0, 0, 0); // TODO
return convertView;
}
private View getFolderView(NavDrawerData.FolderDrawerItem drawerItem, View convertView, ViewGroup parent) {
Activity context = activity.get();
if (context == null) {
return null;
}
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.title.setText(drawerItem.name);
holder.failure.setVisibility(View.GONE);
holder.count.setText("?");
convertView.setPadding(drawerItem.layer * 50, 0, 0, 0); // TODO
return convertView;
}
@ -382,7 +432,7 @@ public class NavListAdapter extends BaseAdapter
public interface ItemAccess {
int getCount();
Feed getItem(int position);
NavDrawerData.DrawerItem getItem(int position);
int getSelectedItemIndex();
int getQueueSize();
int getNumberOfNewItems();

View File

@ -23,6 +23,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
import de.danoeh.antennapod.core.storage.NavDrawerData;
import de.danoeh.antennapod.fragment.AddFeedFragment;
import de.danoeh.antennapod.fragment.FeedItemlistFragment;
import jp.shts.android.library.TriangleLabelView;
@ -63,7 +64,7 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
@Override
public long getItemId(int position) {
return itemAccess.getItem(position).getId();
return position; // TODO
}
@Override
@ -133,7 +134,7 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
public interface ItemAccess {
int getCount();
Feed getItem(int position);
NavDrawerData.DrawerItem getItem(int position);
int getFeedCounter(long feedId);
}
}

View File

@ -37,6 +37,7 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.NavDrawerData;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.dialog.SubscriptionsFilterDialog;
@ -50,7 +51,11 @@ import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class NavDrawerFragment extends Fragment implements AdapterView.OnItemClickListener,
AdapterView.OnItemLongClickListener, SharedPreferences.OnSharedPreferenceChangeListener {
@ -70,12 +75,14 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
NavListAdapter.SUBSCRIPTION_LIST_TAG
};
private DBReader.NavDrawerData navDrawerData;
private NavDrawerData navDrawerData;
private List<NavDrawerData.DrawerItem> flatItemList;
private int selectedNavListIndex = -1;
private int position = -1;
private NavListAdapter navAdapter;
private Disposable disposable;
private ProgressBar progressBar;
private Set<String> openFolders = new HashSet<>();
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@ -107,9 +114,10 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
} else if (StringUtils.isNumeric(lastNavFragment)) { // last fragment was not a list, but a feed
long feedId = Long.parseLong(lastNavFragment);
if (navDrawerData != null) {
List<Feed> feeds = navDrawerData.feeds;
for (int i = 0; i < feeds.size(); i++) {
if (feeds.get(i).getId() == feedId) {
List<NavDrawerData.DrawerItem> items = flatItemList;
for (int i = 0; i < items.size(); i++) {
if (items.get(i).type == NavDrawerData.DrawerItem.Type.FEED
&& ((NavDrawerData.FeedDrawerItem) items.get(i)).feed.getId() == feedId) {
selectedNavListIndex = navAdapter.getSubscriptionOffset() + i;
break;
}
@ -149,8 +157,11 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
}
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.nav_feed_context, menu);
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
menu.setHeaderTitle(feed.getTitle());
NavDrawerData.DrawerItem drawerItem = flatItemList.get(position - navAdapter.getSubscriptionOffset());
if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
menu.setHeaderTitle(((NavDrawerData.FeedDrawerItem) drawerItem).feed.getTitle());
}
// episodes are not loaded, so we cannot check if the podcast has new or unplayed ones!
}
@ -161,7 +172,14 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
if (position < 0) {
return false;
}
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
NavDrawerData.DrawerItem drawerItem = flatItemList.get(position - navAdapter.getSubscriptionOffset());
if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
return onFeedContextMenuClicked(((NavDrawerData.FeedDrawerItem) drawerItem).feed, item);
}
return false;
}
private boolean onFeedContextMenuClicked(Feed feed, MenuItem item) {
switch (item.getItemId()) {
case R.id.remove_all_new_flags_item:
ConfirmationDialog removeAllNewFlagsConfirmationDialog = new ConfirmationDialog(getContext(),
@ -300,17 +318,17 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
private final NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
@Override
public int getCount() {
if (navDrawerData != null) {
return navDrawerData.feeds.size();
if (flatItemList != null) {
return flatItemList.size();
} else {
return 0;
}
}
@Override
public Feed getItem(int position) {
if (navDrawerData != null && 0 <= position && position < navDrawerData.feeds.size()) {
return navDrawerData.feeds.get(position);
public NavDrawerData.DrawerItem getItem(int position) {
if (flatItemList != null && 0 <= position && position < flatItemList.size()) {
return flatItemList.get(position);
} else {
return null;
}
@ -368,6 +386,7 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
.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);
@ -377,6 +396,20 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
});
}
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
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int viewType = parent.getAdapter().getItemViewType(position);
@ -391,14 +424,27 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
}
} else {
int pos = position - navAdapter.getSubscriptionOffset();
long feedId = navDrawerData.feeds.get(pos).getId();
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).loadFeedFragmentById(feedId, null);
((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED);
NavDrawerData.DrawerItem clickedItem = flatItemList.get(pos);
if (clickedItem.type == NavDrawerData.DrawerItem.Type.FEED) {
long feedId = ((NavDrawerData.FeedDrawerItem) clickedItem).feed.getId();
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).loadFeedFragmentById(feedId, null);
((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED);
} else {
Intent intent = new Intent(getActivity(), MainActivity.class);
intent.putExtra(MainActivity.EXTRA_FEED_ID, feedId);
startActivity(intent);
}
} else {
Intent intent = new Intent(getActivity(), MainActivity.class);
intent.putExtra(MainActivity.EXTRA_FEED_ID, feedId);
startActivity(intent);
NavDrawerData.FolderDrawerItem folder = ((NavDrawerData.FolderDrawerItem) clickedItem);
if (openFolders.contains(folder.name)) {
openFolders.remove(folder.name);
} else {
openFolders.add(folder.name);
}
flatItemList = makeFlatDrawerData(navDrawerData.items);
navAdapter.notifyDataSetChanged();
}
}
} else if (UserPreferences.getSubscriptionsFilter().isEnabled()

View File

@ -45,6 +45,7 @@ import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBReader;
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.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
@ -71,7 +72,7 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
private static final String PREF_NUM_COLUMNS = "columns";
private GridView subscriptionGridLayout;
private DBReader.NavDrawerData navDrawerData;
private NavDrawerData navDrawerData;
private SubscriptionsAdapter subscriptionAdapter;
private FloatingActionButton subscriptionAddButton;
private ProgressBar progressBar;
@ -370,16 +371,16 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
@Override
public int getCount() {
if (navDrawerData != null) {
return navDrawerData.feeds.size();
return navDrawerData.items.size();
} else {
return 0;
}
}
@Override
public Feed getItem(int position) {
if (navDrawerData != null && 0 <= position && position < navDrawerData.feeds.size()) {
return navDrawerData.feeds.get(position);
public NavDrawerData.DrawerItem getItem(int position) {
if (navDrawerData != null && 0 <= position && position < navDrawerData.items.size()) {
return navDrawerData.items.get(position);
} else {
return null;
}

View File

@ -10,7 +10,6 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -866,32 +865,26 @@ public final class DBReader {
int numNewItems = adapter.getNumberOfNewItems();
int numDownloadedItems = adapter.getNumberOfDownloadedEpisodes();
NavDrawerData result = new NavDrawerData(feeds, queueSize, numNewItems, numDownloadedItems,
List<NavDrawerData.DrawerItem> items = new ArrayList<>();
for (int i = 0, feedsSize = feeds.size(); i < feedsSize; i++) {
items.add(new NavDrawerData.FeedDrawerItem(feeds.get(i), 0, i));
}
List<NavDrawerData.DrawerItem> folderItems = new ArrayList<>();
for (int i = 0, feedsSize = feeds.size(); i < feedsSize; i++) {
folderItems.add(new NavDrawerData.FeedDrawerItem(feeds.get(i), 1, 10001 + i));
}
items.add(new NavDrawerData.FolderDrawerItem("Folder 1", folderItems, 0, 10000));
List<NavDrawerData.DrawerItem> folderItems2 = new ArrayList<>();
for (int i = 0, feedsSize = feeds.size(); i < feedsSize; i++) {
folderItems2.add(new NavDrawerData.FeedDrawerItem(feeds.get(i), 1, 20001 + i));
}
items.add(new NavDrawerData.FolderDrawerItem("Folder 2", folderItems2, 0, 20000));
NavDrawerData result = new NavDrawerData(items, queueSize, numNewItems, numDownloadedItems,
feedCounters, UserPreferences.getEpisodeCleanupAlgorithm().getReclaimableItems());
adapter.close();
return result;
}
public static class NavDrawerData {
public final List<Feed> feeds;
public final int queueSize;
public final int numNewItems;
public final int numDownloadedItems;
public final LongIntMap feedCounters;
public final int reclaimableSpace;
public NavDrawerData(List<Feed> feeds,
int queueSize,
int numNewItems,
int numDownloadedItems,
LongIntMap feedIndicatorValues,
int reclaimableSpace) {
this.feeds = feeds;
this.queueSize = queueSize;
this.numNewItems = numNewItems;
this.numDownloadedItems = numDownloadedItems;
this.feedCounters = feedIndicatorValues;
this.reclaimableSpace = reclaimableSpace;
}
}
}

View File

@ -0,0 +1,65 @@
package de.danoeh.antennapod.core.storage;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.util.LongIntMap;
import java.util.List;
public class NavDrawerData {
public final List<DrawerItem> items;
public final int queueSize;
public final int numNewItems;
public final int numDownloadedItems;
public final LongIntMap feedCounters;
public final int reclaimableSpace;
public NavDrawerData(List<DrawerItem> feeds,
int queueSize,
int numNewItems,
int numDownloadedItems,
LongIntMap feedIndicatorValues,
int reclaimableSpace) {
this.items = feeds;
this.queueSize = queueSize;
this.numNewItems = numNewItems;
this.numDownloadedItems = numDownloadedItems;
this.feedCounters = feedIndicatorValues;
this.reclaimableSpace = reclaimableSpace;
}
public static class DrawerItem {
public enum Type {
FOLDER, FEED
}
public final Type type;
public final int layer;
public final long id;
public DrawerItem(Type type, int layer, long id) {
this.type = type;
this.layer = layer;
this.id = id;
}
}
public static class FolderDrawerItem extends DrawerItem {
public final List<DrawerItem> children;
public final String name;
public FolderDrawerItem(String name, List<DrawerItem> children, int layer, long id) {
super(DrawerItem.Type.FOLDER, layer, id);
this.children = children;
this.name = name;
}
}
public static class FeedDrawerItem extends DrawerItem {
public final Feed feed;
public FeedDrawerItem(Feed feed, int layer, long id) {
super(DrawerItem.Type.FEED, layer, id);
this.feed = feed;
}
}
}