Merge pull request #4634 from AntennaPod/folders
Add subscriptions to tags/folders
This commit is contained in:
commit
dd0502c0d6
|
@ -30,7 +30,6 @@ import java.util.List;
|
|||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.longClick;
|
||||
import static androidx.test.espresso.action.ViewActions.scrollTo;
|
||||
import static androidx.test.espresso.action.ViewActions.swipeUp;
|
||||
import static androidx.test.espresso.intent.Intents.intended;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
|
||||
|
@ -123,7 +122,7 @@ public class NavigationDrawerTest {
|
|||
for (int i = 0; i < uiTestUtils.hostedFeeds.size(); i++) {
|
||||
Feed f = uiTestUtils.hostedFeeds.get(i);
|
||||
openNavDrawer();
|
||||
onDrawerItem(withText(f.getTitle())).perform(scrollTo(), click());
|
||||
onDrawerItem(withText(f.getTitle())).perform(click());
|
||||
onView(isRoot()).perform(waitForView(allOf(isDescendantOfA(withId(R.id.appBar)),
|
||||
withText(f.getTitle()), isDisplayed()), 1000));
|
||||
}
|
||||
|
|
|
@ -18,9 +18,10 @@ import java.io.IOException;
|
|||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.scrollTo;
|
||||
import static androidx.test.espresso.action.ViewActions.swipeUp;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static de.test.antennapod.EspressoTestUtils.onDrawerItem;
|
||||
import static de.test.antennapod.EspressoTestUtils.openNavDrawer;
|
||||
|
@ -61,7 +62,8 @@ public class TextOnlyFeedsTest {
|
|||
uiTestUtils.addLocalFeedData(false);
|
||||
final Feed feed = uiTestUtils.hostedFeeds.get(0);
|
||||
openNavDrawer();
|
||||
onDrawerItem(withText(feed.getTitle())).perform(scrollTo(), click());
|
||||
onView(withId(R.id.nav_list)).perform(swipeUp());
|
||||
onDrawerItem(withText(feed.getTitle())).perform(click());
|
||||
onView(withText(feed.getItemAtIndex(0).getTitle())).perform(click());
|
||||
onView(isRoot()).perform(waitForView(withText(R.string.mark_read_no_media_label), 3000));
|
||||
onView(withText(R.string.mark_read_no_media_label)).perform(click());
|
||||
|
|
|
@ -21,6 +21,7 @@ import de.danoeh.antennapod.activity.MainActivity;
|
|||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
|
||||
public class CoverLoader {
|
||||
private int resource = 0;
|
||||
private String uri;
|
||||
private String fallbackUri;
|
||||
private TextView txtvPlaceholder;
|
||||
|
@ -37,6 +38,11 @@ public class CoverLoader {
|
|||
return this;
|
||||
}
|
||||
|
||||
public CoverLoader withResource(int resource) {
|
||||
this.resource = resource;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CoverLoader withFallbackUri(String uri) {
|
||||
fallbackUri = uri;
|
||||
return this;
|
||||
|
@ -66,6 +72,12 @@ public class CoverLoader {
|
|||
}
|
||||
|
||||
public void load() {
|
||||
if (resource != 0) {
|
||||
imgvCover.setImageResource(resource);
|
||||
CoverTarget.setPlaceholderVisibility(txtvPlaceholder, textAndImageCombined);
|
||||
return;
|
||||
}
|
||||
|
||||
RequestOptions options = new RequestOptions()
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
|
@ -106,15 +118,7 @@ public class CoverLoader {
|
|||
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
|
||||
TextView txtvPlaceholder = placeholder.get();
|
||||
if (txtvPlaceholder != null) {
|
||||
if (textAndImageCombined) {
|
||||
int bgColor = txtvPlaceholder.getContext().getResources().getColor(R.color.feed_text_bg);
|
||||
txtvPlaceholder.setBackgroundColor(bgColor);
|
||||
} else {
|
||||
txtvPlaceholder.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
setPlaceholderVisibility(placeholder.get(), textAndImageCombined);
|
||||
ImageView ivCover = cover.get();
|
||||
ivCover.setImageDrawable(resource);
|
||||
}
|
||||
|
@ -124,5 +128,16 @@ public class CoverLoader {
|
|||
ImageView ivCover = cover.get();
|
||||
ivCover.setImageDrawable(placeholder);
|
||||
}
|
||||
|
||||
static void setPlaceholderVisibility(TextView placeholder, boolean textAndImageCombined) {
|
||||
if (placeholder != null) {
|
||||
if (textAndImageCombined) {
|
||||
int bgColor = placeholder.getContext().getResources().getColor(R.color.feed_text_bg);
|
||||
placeholder.setBackgroundColor(bgColor);
|
||||
} else {
|
||||
placeholder.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +1,21 @@
|
|||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
|
@ -23,6 +24,7 @@ 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.fragment.AddFeedFragment;
|
||||
import de.danoeh.antennapod.fragment.DownloadsFragment;
|
||||
import de.danoeh.antennapod.fragment.EpisodesFragment;
|
||||
|
@ -30,6 +32,7 @@ import de.danoeh.antennapod.fragment.NavDrawerFragment;
|
|||
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
|
||||
import de.danoeh.antennapod.fragment.QueueFragment;
|
||||
import de.danoeh.antennapod.fragment.SubscriptionFragment;
|
||||
import de.danoeh.antennapod.ui.common.ThemeUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
@ -42,10 +45,9 @@ import java.util.List;
|
|||
/**
|
||||
* BaseAdapter for the navigation drawer
|
||||
*/
|
||||
public class NavListAdapter extends BaseAdapter
|
||||
public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder>
|
||||
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_SECTION_DIVIDER = 1;
|
||||
private static final int VIEW_TYPE_SUBSCRIPTION = 2;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -133,19 +135,18 @@ public class NavListAdapter extends BaseAdapter
|
|||
default:
|
||||
return null;
|
||||
}
|
||||
TypedArray ta = context.obtainStyledAttributes(new int[] { icon } );
|
||||
TypedArray ta = context.obtainStyledAttributes(new int[] { icon });
|
||||
Drawable result = ta.getDrawable(0);
|
||||
ta.recycle();
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<String> getTags() {
|
||||
return Collections.unmodifiableList(tags);
|
||||
public List<String> getFragmentTags() {
|
||||
return Collections.unmodifiableList(fragmentTags);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
public int getItemCount() {
|
||||
int baseCount = getSubscriptionOffset();
|
||||
if (showSubscriptionList) {
|
||||
baseCount += itemAccess.getCount();
|
||||
|
@ -154,25 +155,18 @@ public class NavListAdapter extends BaseAdapter
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
public long getItemId(int position) {
|
||||
int viewType = getItemViewType(position);
|
||||
if (viewType == VIEW_TYPE_NAV) {
|
||||
return getLabel(tags.get(position));
|
||||
} else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
|
||||
return "";
|
||||
if (viewType == VIEW_TYPE_SUBSCRIPTION) {
|
||||
return itemAccess.getItem(position - getSubscriptionOffset()).id;
|
||||
} else {
|
||||
return itemAccess.getItem(position);
|
||||
return -position - 1; // IDs are >0
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@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;
|
||||
|
@ -181,69 +175,67 @@ public class NavListAdapter extends BaseAdapter
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
return VIEW_TYPE_COUNT;
|
||||
}
|
||||
|
||||
public int getSubscriptionOffset() {
|
||||
return tags.size() > 0 ? tags.size() + 1 : 0;
|
||||
return fragmentTags.size() > 0 ? fragmentTags.size() + 1 : 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
LayoutInflater inflater = LayoutInflater.from(activity.get());
|
||||
if (viewType == VIEW_TYPE_NAV) {
|
||||
return new NavHolder(inflater.inflate(R.layout.nav_listitem, parent, false));
|
||||
} else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
|
||||
return new DividerHolder(inflater.inflate(R.layout.nav_section_item, parent, false));
|
||||
} else {
|
||||
return new FeedHolder(inflater.inflate(R.layout.nav_listitem, parent, false));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
public void onBindViewHolder(@NonNull Holder holder, int position) {
|
||||
int viewType = getItemViewType(position);
|
||||
View v;
|
||||
if (viewType == VIEW_TYPE_NAV) {
|
||||
v = getNavView((String) getItem(position), position, convertView, parent);
|
||||
} else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
|
||||
v = getSectionDividerView(convertView, parent);
|
||||
} else {
|
||||
v = getFeedView(position, convertView, parent);
|
||||
}
|
||||
if (v != null && viewType != VIEW_TYPE_SECTION_DIVIDER) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
|
||||
if (position == itemAccess.getSelectedItemIndex()) {
|
||||
v.getContext().getTheme().resolveAttribute(R.attr.drawer_activated_color, typedValue, true);
|
||||
v.setBackgroundResource(typedValue.resourceId);
|
||||
holder.itemView.setOnCreateContextMenuListener(null);
|
||||
if (viewType == VIEW_TYPE_NAV) {
|
||||
bindNavView(getLabel(fragmentTags.get(position)), position, (NavHolder) holder);
|
||||
} else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
|
||||
bindSectionDivider((DividerHolder) holder);
|
||||
} else {
|
||||
int itemPos = position - getSubscriptionOffset();
|
||||
NavDrawerData.DrawerItem item = itemAccess.getItem(itemPos);
|
||||
bindListItem(item, (FeedHolder) holder);
|
||||
if (item.type == NavDrawerData.DrawerItem.Type.FEED) {
|
||||
bindFeedView((NavDrawerData.FeedDrawerItem) item, (FeedHolder) holder);
|
||||
holder.itemView.setOnCreateContextMenuListener(itemAccess);
|
||||
} else {
|
||||
v.getContext().getTheme().resolveAttribute(android.R.attr.windowBackground, typedValue, true);
|
||||
v.setBackgroundResource(typedValue.resourceId);
|
||||
bindFolderView((NavDrawerData.FolderDrawerItem) item, (FeedHolder) holder);
|
||||
}
|
||||
}
|
||||
return v;
|
||||
if (viewType != VIEW_TYPE_SECTION_DIVIDER) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
|
||||
activity.get().getTheme().resolveAttribute(itemAccess.isSelected(position)
|
||||
? R.attr.drawer_activated_color : android.R.attr.windowBackground, typedValue, true);
|
||||
holder.itemView.setBackgroundResource(typedValue.resourceId);
|
||||
|
||||
holder.itemView.setOnClickListener(v -> itemAccess.onItemClick(position));
|
||||
holder.itemView.setOnLongClickListener(v -> itemAccess.onItemLongClick(position));
|
||||
}
|
||||
}
|
||||
|
||||
private View getNavView(String title, int position, View convertView, ViewGroup parent) {
|
||||
private void bindNavView(String title, int position, NavHolder holder) {
|
||||
Activity context = activity.get();
|
||||
if(context == null) {
|
||||
return null;
|
||||
if (context == 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);
|
||||
|
||||
// reset for re-use
|
||||
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) {
|
||||
|
@ -262,78 +254,64 @@ public class NavListAdapter extends BaseAdapter
|
|||
holder.count.setText(NumberFormat.getInstance().format(sum));
|
||||
holder.count.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else if(tag.equals(DownloadsFragment.TAG) && UserPreferences.isEnableAutodownload()) {
|
||||
} else if (tag.equals(DownloadsFragment.TAG) && UserPreferences.isEnableAutodownload()) {
|
||||
int epCacheSize = UserPreferences.getEpisodeCacheSize();
|
||||
// don't count episodes that can be reclaimed
|
||||
int spaceUsed = itemAccess.getNumberOfDownloadedItems() -
|
||||
itemAccess.getReclaimableItems();
|
||||
int spaceUsed = itemAccess.getNumberOfDownloadedItems()
|
||||
- itemAccess.getReclaimableItems();
|
||||
|
||||
if (epCacheSize > 0 && spaceUsed >= epCacheSize) {
|
||||
holder.count.setText("{md-disc-full 150%}");
|
||||
Iconify.addIcons(holder.count);
|
||||
holder.count.setVisibility(View.VISIBLE);
|
||||
holder.count.setOnClickListener(v ->
|
||||
new AlertDialog.Builder(context)
|
||||
new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.episode_cache_full_title)
|
||||
.setMessage(R.string.episode_cache_full_message)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {})
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> { })
|
||||
.show()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
holder.image.setImageDrawable(getDrawable(tags.get(position)));
|
||||
|
||||
return convertView;
|
||||
holder.image.setImageDrawable(getDrawable(fragmentTags.get(position)));
|
||||
}
|
||||
|
||||
private View getSectionDividerView(View convertView, ViewGroup parent) {
|
||||
private void bindSectionDivider(DividerHolder holder) {
|
||||
Activity context = activity.get();
|
||||
if(context == null) {
|
||||
return null;
|
||||
if (context == 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) {
|
||||
convertView.setEnabled(true);
|
||||
feedsFilteredMsg.setText("{md-info-outline} " + context.getString(R.string.subscriptions_are_filtered));
|
||||
Iconify.addIcons(feedsFilteredMsg);
|
||||
feedsFilteredMsg.setVisibility(View.VISIBLE);
|
||||
holder.itemView.setEnabled(true);
|
||||
holder.feedsFilteredMsg.setText("{md-info-outline} "
|
||||
+ context.getString(R.string.subscriptions_are_filtered));
|
||||
Iconify.addIcons(holder.feedsFilteredMsg);
|
||||
holder.feedsFilteredMsg.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
convertView.setEnabled(false);
|
||||
feedsFilteredMsg.setVisibility(View.GONE);
|
||||
holder.itemView.setEnabled(false);
|
||||
holder.feedsFilteredMsg.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
private View getFeedView(int position, View convertView, ViewGroup parent) {
|
||||
Activity context = activity.get();
|
||||
if(context == null) {
|
||||
return null;
|
||||
}
|
||||
int feedPos = position - getSubscriptionOffset();
|
||||
Feed feed = itemAccess.getItem(feedPos);
|
||||
|
||||
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);
|
||||
private void bindListItem(NavDrawerData.DrawerItem item, FeedHolder holder) {
|
||||
if (item.getCounter() > 0) {
|
||||
holder.count.setVisibility(View.VISIBLE);
|
||||
holder.count.setText(NumberFormat.getInstance().format(item.getCounter()));
|
||||
} else {
|
||||
holder = (FeedHolder) convertView.getTag();
|
||||
holder.count.setVisibility(View.GONE);
|
||||
}
|
||||
holder.title.setText(item.getTitle());
|
||||
int padding = (int) (activity.get().getResources().getDimension(R.dimen.thumbnail_length_navlist) / 2);
|
||||
holder.itemView.setPadding(item.getLayer() * padding, 0, 0, 0);
|
||||
}
|
||||
|
||||
private void bindFeedView(NavDrawerData.FeedDrawerItem drawerItem, FeedHolder holder) {
|
||||
Feed feed = drawerItem.feed;
|
||||
Activity context = activity.get();
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Glide.with(context)
|
||||
|
@ -346,9 +324,7 @@ public class NavListAdapter extends BaseAdapter
|
|||
.dontAnimate())
|
||||
.into(holder.image);
|
||||
|
||||
holder.title.setText(feed.getTitle());
|
||||
|
||||
if(feed.hasLastUpdateFailed()) {
|
||||
if (feed.hasLastUpdateFailed()) {
|
||||
RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) holder.title.getLayoutParams();
|
||||
p.addRule(RelativeLayout.LEFT_OF, R.id.itxtvFailure);
|
||||
holder.failure.setVisibility(View.VISIBLE);
|
||||
|
@ -357,39 +333,87 @@ public class NavListAdapter extends BaseAdapter
|
|||
p.addRule(RelativeLayout.LEFT_OF, R.id.txtvCount);
|
||||
holder.failure.setVisibility(View.GONE);
|
||||
}
|
||||
int counter = itemAccess.getFeedCounter(feed.getId());
|
||||
if(counter > 0) {
|
||||
holder.count.setVisibility(View.VISIBLE);
|
||||
holder.count.setText(NumberFormat.getInstance().format(counter));
|
||||
} else {
|
||||
}
|
||||
|
||||
private void bindFolderView(NavDrawerData.FolderDrawerItem folder, FeedHolder holder) {
|
||||
Activity context = activity.get();
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
if (folder.isOpen) {
|
||||
holder.count.setVisibility(View.GONE);
|
||||
}
|
||||
return convertView;
|
||||
Glide.with(context).clear(holder.image);
|
||||
holder.image.setImageResource(ThemeUtils.getDrawableFromAttr(context, R.attr.ic_folder));
|
||||
holder.failure.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
static class NavHolder {
|
||||
ImageView image;
|
||||
TextView title;
|
||||
TextView count;
|
||||
static class Holder extends RecyclerView.ViewHolder {
|
||||
public Holder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
}
|
||||
|
||||
static class FeedHolder {
|
||||
ImageView image;
|
||||
TextView title;
|
||||
IconTextView failure;
|
||||
TextView count;
|
||||
static class DividerHolder extends Holder {
|
||||
final TextView feedsFilteredMsg;
|
||||
|
||||
public DividerHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
feedsFilteredMsg = itemView.findViewById(R.id.nav_feeds_filtered_message);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ItemAccess {
|
||||
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 extends View.OnCreateContextMenuListener {
|
||||
int getCount();
|
||||
Feed getItem(int position);
|
||||
int getSelectedItemIndex();
|
||||
|
||||
NavDrawerData.DrawerItem getItem(int position);
|
||||
|
||||
boolean isSelected(int position);
|
||||
|
||||
int getQueueSize();
|
||||
|
||||
int getNumberOfNewItems();
|
||||
|
||||
int getNumberOfDownloadedItems();
|
||||
|
||||
int getReclaimableItems();
|
||||
int getFeedCounter(long feedId);
|
||||
|
||||
int getFeedCounterSum();
|
||||
|
||||
void onItemClick(int position);
|
||||
|
||||
boolean onItemLongClick(int position);
|
||||
|
||||
@Override
|
||||
void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,17 +21,16 @@ 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.FeedItemlistFragment;
|
||||
import de.danoeh.antennapod.fragment.SubscriptionFragment;
|
||||
import de.danoeh.antennapod.ui.common.ThemeUtils;
|
||||
import jp.shts.android.library.TriangleLabelView;
|
||||
|
||||
/**
|
||||
* Adapter for subscriptions
|
||||
*/
|
||||
public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnItemClickListener {
|
||||
|
||||
/** placeholder object that indicates item should be added */
|
||||
public static final Object ADD_ITEM_OBJ = new Object();
|
||||
|
||||
/** 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";
|
||||
|
||||
|
@ -60,7 +59,7 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
|
|||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return itemAccess.getItem(position).getId();
|
||||
return ((NavDrawerData.DrawerItem) getItem(position)).id;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,11 +82,13 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
|
|||
holder = (Holder) convertView.getTag();
|
||||
}
|
||||
|
||||
final Feed feed = (Feed) getItem(position);
|
||||
if (feed == null) return null;
|
||||
final NavDrawerData.DrawerItem drawerItem = (NavDrawerData.DrawerItem) getItem(position);
|
||||
if (drawerItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
holder.feedTitle.setText(feed.getTitle());
|
||||
holder.imageView.setContentDescription(feed.getTitle());
|
||||
holder.feedTitle.setText(drawerItem.getTitle());
|
||||
holder.imageView.setContentDescription(drawerItem.getTitle());
|
||||
holder.feedTitle.setVisibility(View.VISIBLE);
|
||||
|
||||
// Fix TriangleLabelView corner for RTL
|
||||
|
@ -96,30 +97,46 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
|
|||
holder.count.setCorner(TriangleLabelView.Corner.TOP_LEFT);
|
||||
}
|
||||
|
||||
int count = itemAccess.getFeedCounter(feed.getId());
|
||||
if(count > 0) {
|
||||
holder.count.setPrimaryText(
|
||||
NumberFormat.getInstance().format(itemAccess.getFeedCounter(feed.getId())));
|
||||
if (drawerItem.getCounter() > 0) {
|
||||
holder.count.setPrimaryText(NumberFormat.getInstance().format(drawerItem.getCounter()));
|
||||
holder.count.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.count.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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(ThemeUtils.getDrawableFromAttr(mainActivityRef.get(), R.attr.ic_folder))
|
||||
.withPlaceholderView(holder.feedTitle, true)
|
||||
.withCoverView(holder.imageView)
|
||||
.load();
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
Fragment fragment = FeedItemlistFragment.newInstance(getItemId(position));
|
||||
mainActivityRef.get().loadChildFragment(fragment);
|
||||
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 {
|
||||
|
@ -130,7 +147,7 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
|
|||
|
||||
public interface ItemAccess {
|
||||
int getCount();
|
||||
Feed getItem(int position);
|
||||
int getFeedCounter(long feedId);
|
||||
|
||||
NavDrawerData.DrawerItem getItem(int position);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
package de.danoeh.antennapod.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.android.material.chip.Chip;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.FeedPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.databinding.EditTagsDialogBinding;
|
||||
import de.danoeh.antennapod.view.ItemOffsetDecoration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TagSettingsDialog extends DialogFragment {
|
||||
public static final String TAG = "TagSettingsDialog";
|
||||
private static final String ARG_FEED_PREFERENCES = "feed_preferences";
|
||||
private List<String> displayedTags;
|
||||
|
||||
public static TagSettingsDialog newInstance(FeedPreferences preferences) {
|
||||
TagSettingsDialog fragment = new TagSettingsDialog();
|
||||
Bundle args = new Bundle();
|
||||
args.putSerializable(ARG_FEED_PREFERENCES, preferences);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
FeedPreferences preferences = (FeedPreferences) getArguments().getSerializable(ARG_FEED_PREFERENCES);
|
||||
displayedTags = new ArrayList<>(preferences.getTags());
|
||||
displayedTags.remove(FeedPreferences.TAG_ROOT);
|
||||
|
||||
EditTagsDialogBinding viewBinding = EditTagsDialogBinding.inflate(getLayoutInflater());
|
||||
viewBinding.tagsRecycler.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
||||
viewBinding.tagsRecycler.addItemDecoration(new ItemOffsetDecoration(getContext(), 4));
|
||||
TagSelectionAdapter adapter = new TagSelectionAdapter();
|
||||
adapter.setHasStableIds(true);
|
||||
viewBinding.tagsRecycler.setAdapter(adapter);
|
||||
viewBinding.rootFolderCheckbox.setChecked(preferences.getTags().contains(FeedPreferences.TAG_ROOT));
|
||||
|
||||
|
||||
viewBinding.newTagButton.setOnClickListener(v -> {
|
||||
String name = viewBinding.newTagEditText.getText().toString().trim();
|
||||
if (TextUtils.isEmpty(name) || displayedTags.contains(name)) {
|
||||
return;
|
||||
}
|
||||
displayedTags.add(name);
|
||||
viewBinding.newTagEditText.setText("");
|
||||
adapter.notifyDataSetChanged();
|
||||
});
|
||||
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
|
||||
dialog.setView(viewBinding.getRoot());
|
||||
dialog.setTitle(R.string.feed_folders_label);
|
||||
dialog.setPositiveButton(android.R.string.ok, (d, input) -> {
|
||||
preferences.getTags().clear();
|
||||
preferences.getTags().addAll(displayedTags);
|
||||
if (viewBinding.rootFolderCheckbox.isChecked()) {
|
||||
preferences.getTags().add(FeedPreferences.TAG_ROOT);
|
||||
}
|
||||
DBWriter.setFeedPreferences(preferences);
|
||||
});
|
||||
dialog.setNegativeButton(R.string.cancel_label, null);
|
||||
return dialog.create();
|
||||
}
|
||||
|
||||
public class TagSelectionAdapter extends RecyclerView.Adapter<TagSelectionAdapter.ViewHolder> {
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public TagSelectionAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
Chip chip = new Chip(getContext());
|
||||
chip.setCloseIconVisible(true);
|
||||
chip.setCloseIconResource(R.drawable.ic_delete_black);
|
||||
return new TagSelectionAdapter.ViewHolder(chip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull TagSelectionAdapter.ViewHolder holder, int position) {
|
||||
holder.chip.setText(displayedTags.get(position));
|
||||
holder.chip.setOnCloseIconClickListener(v -> {
|
||||
displayedTags.remove(position);
|
||||
notifyDataSetChanged();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return displayedTags.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return displayedTags.get(position).hashCode();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
Chip chip;
|
||||
|
||||
ViewHolder(Chip itemView) {
|
||||
super(itemView);
|
||||
chip = itemView;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ import de.danoeh.antennapod.core.storage.DBWriter;
|
|||
import de.danoeh.antennapod.dialog.AuthenticationDialog;
|
||||
import de.danoeh.antennapod.dialog.EpisodeFilterDialog;
|
||||
import de.danoeh.antennapod.dialog.FeedPreferenceSkipDialog;
|
||||
import de.danoeh.antennapod.dialog.TagSettingsDialog;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.MaybeOnSubscribe;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
|
@ -105,6 +106,7 @@ public class FeedSettingsFragment extends Fragment {
|
|||
private static final CharSequence PREF_CATEGORY_AUTO_DOWNLOAD = "autoDownloadCategory";
|
||||
private static final String PREF_FEED_PLAYBACK_SPEED = "feedPlaybackSpeed";
|
||||
private static final String PREF_AUTO_SKIP = "feedAutoSkip";
|
||||
private static final String PREF_TAGS = "tags";
|
||||
private static final DecimalFormat SPEED_FORMAT =
|
||||
new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.US));
|
||||
|
||||
|
@ -160,6 +162,7 @@ public class FeedSettingsFragment extends Fragment {
|
|||
setupPlaybackSpeedPreference();
|
||||
setupFeedAutoSkipPreference();
|
||||
setupEpisodeNotificationPreference();
|
||||
setupTags();
|
||||
|
||||
updateAutoDeleteSummary();
|
||||
updateVolumeReductionValue();
|
||||
|
@ -395,6 +398,13 @@ public class FeedSettingsFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
private void setupTags() {
|
||||
findPreference(PREF_TAGS).setOnPreferenceClickListener(preference -> {
|
||||
TagSettingsDialog.newInstance(feedPreferences).show(getChildFragmentManager(), TagSettingsDialog.TAG);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setupEpisodeNotificationPreference() {
|
||||
SwitchPreferenceCompat pref = findPreference("episodeNotification");
|
||||
|
||||
|
|
|
@ -12,15 +12,16 @@ import android.view.MenuInflater;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
|
@ -34,6 +35,7 @@ import de.danoeh.antennapod.core.feed.Feed;
|
|||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
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.dialog.RemoveFeedDialog;
|
||||
import de.danoeh.antennapod.dialog.SubscriptionsFilterDialog;
|
||||
import de.danoeh.antennapod.dialog.RenameFeedDialog;
|
||||
|
@ -46,12 +48,15 @@ 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.Set;
|
||||
|
||||
public class NavDrawerFragment extends Fragment implements AdapterView.OnItemClickListener,
|
||||
AdapterView.OnItemLongClickListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public class NavDrawerFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
@VisibleForTesting
|
||||
public static final String PREF_LAST_FRAGMENT_TAG = "prefLastFragmentTag";
|
||||
private static final String PREF_OPEN_FOLDERS = "prefOpenFolders";
|
||||
@VisibleForTesting
|
||||
public static final String PREF_NAME = "NavDrawerPrefs";
|
||||
public static final String TAG = "NavDrawerFragment";
|
||||
|
@ -66,12 +71,13 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
|
|||
NavListAdapter.SUBSCRIPTION_LIST_TAG
|
||||
};
|
||||
|
||||
private DBReader.NavDrawerData navDrawerData;
|
||||
private int selectedNavListIndex = -1;
|
||||
private int position = -1;
|
||||
private NavDrawerData navDrawerData;
|
||||
private List<NavDrawerData.DrawerItem> flatItemList;
|
||||
private NavDrawerData.DrawerItem contextPressedItem = null;
|
||||
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,
|
||||
|
@ -79,40 +85,21 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
|
|||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
View root = inflater.inflate(R.layout.nav_list, container, false);
|
||||
|
||||
SharedPreferences preferences = getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
|
||||
openFolders = new HashSet<>(preferences.getStringSet(PREF_OPEN_FOLDERS, new HashSet<>())); // Must not modify
|
||||
|
||||
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.setHasStableIds(true);
|
||||
navList.setAdapter(navAdapter);
|
||||
navList.setOnItemClickListener(this);
|
||||
navList.setOnItemLongClickListener(this);
|
||||
registerForContextMenu(navList);
|
||||
updateSelection();
|
||||
navList.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
|
||||
root.findViewById(R.id.nav_settings).setOnClickListener(v ->
|
||||
startActivity(new Intent(getActivity(), PreferenceActivity.class)));
|
||||
getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
.registerOnSharedPreferenceChangeListener(this);
|
||||
return root;
|
||||
}
|
||||
|
||||
private void updateSelection() {
|
||||
String lastNavFragment = getLastNavFragment(getContext());
|
||||
int tagIndex = navAdapter.getTags().indexOf(lastNavFragment);
|
||||
if (tagIndex >= 0) {
|
||||
selectedNavListIndex = tagIndex;
|
||||
} 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) {
|
||||
selectedNavListIndex = navAdapter.getSubscriptionOffset() + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
navAdapter.notifyDataSetChanged();
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,29 +122,25 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
|
|||
@Override
|
||||
public void onCreateContextMenu(@NonNull ContextMenu menu, @NonNull View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
if (v.getId() != R.id.nav_list) {
|
||||
return;
|
||||
}
|
||||
AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
int position = adapterInfo.position;
|
||||
if (position < navAdapter.getSubscriptionOffset()) {
|
||||
return;
|
||||
if (contextPressedItem.type != NavDrawerData.DrawerItem.Type.FEED) {
|
||||
return; // Should actually never happen because the context menu is not set up for other items
|
||||
}
|
||||
|
||||
MenuInflater inflater = getActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.nav_feed_context, menu);
|
||||
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
|
||||
menu.setHeaderTitle(feed.getTitle());
|
||||
menu.setHeaderTitle(((NavDrawerData.FeedDrawerItem) contextPressedItem).feed.getTitle());
|
||||
// episodes are not loaded, so we cannot check if the podcast has new or unplayed ones!
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(@NonNull MenuItem item) {
|
||||
final int position = this.position;
|
||||
this.position = -1; // reset
|
||||
if (position < 0) {
|
||||
return false;
|
||||
if (contextPressedItem.type == NavDrawerData.DrawerItem.Type.FEED) {
|
||||
return onFeedContextMenuClicked(((NavDrawerData.FeedDrawerItem) contextPressedItem).feed, item);
|
||||
}
|
||||
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
|
||||
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(),
|
||||
|
@ -189,13 +172,7 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
|
|||
return true;
|
||||
case R.id.remove_item:
|
||||
RemoveFeedDialog.show(getContext(), feed, () -> {
|
||||
if (selectedNavListIndex == position) {
|
||||
if (getActivity() instanceof MainActivity) {
|
||||
((MainActivity) getActivity()).loadFragment(EpisodesFragment.TAG, null);
|
||||
} else {
|
||||
showMainActivity(EpisodesFragment.TAG);
|
||||
}
|
||||
}
|
||||
((MainActivity) getActivity()).loadFragment(EpisodesFragment.TAG, null);
|
||||
});
|
||||
return true;
|
||||
default:
|
||||
|
@ -203,12 +180,6 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
|
|||
}
|
||||
}
|
||||
|
||||
private void showMainActivity(String tag) {
|
||||
Intent intent = new Intent(getActivity(), MainActivity.class);
|
||||
intent.putExtra(MainActivity.EXTRA_FRAGMENT_TAG, tag);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
|
||||
loadData();
|
||||
|
@ -261,7 +232,7 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
|
|||
});
|
||||
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
|
||||
UserPreferences.setHiddenDrawerItems(hiddenDrawerItems);
|
||||
updateSelection();
|
||||
navAdapter.notifyDataSetChanged(); // Update selection
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel_label, null);
|
||||
builder.create().show();
|
||||
|
@ -270,25 +241,39 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelectedItemIndex() {
|
||||
return selectedNavListIndex;
|
||||
public boolean isSelected(int position) {
|
||||
String lastNavFragment = getLastNavFragment(getContext());
|
||||
if (position < navAdapter.getSubscriptionOffset()) {
|
||||
return navAdapter.getFragmentTags().get(position).equals(lastNavFragment);
|
||||
} else if (StringUtils.isNumeric(lastNavFragment)) { // last fragment was not a list, but a feed
|
||||
long feedId = Long.parseLong(lastNavFragment);
|
||||
if (navDrawerData != null) {
|
||||
NavDrawerData.DrawerItem itemToCheck = flatItemList.get(
|
||||
position - navAdapter.getSubscriptionOffset());
|
||||
if (itemToCheck.type == NavDrawerData.DrawerItem.Type.FEED) {
|
||||
// When the same feed is displayed multiple times, it should be highlighted multiple times.
|
||||
return ((NavDrawerData.FeedDrawerItem) itemToCheck).feed.getId() == feedId;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -311,11 +296,6 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
|
|||
return (navDrawerData != null) ? navDrawerData.reclaimableSpace : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFeedCounter(long feedId) {
|
||||
return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFeedCounterSum() {
|
||||
if (navDrawerData == null) {
|
||||
|
@ -328,16 +308,82 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
|
|||
return sum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(int position) {
|
||||
int viewType = navAdapter.getItemViewType(position);
|
||||
if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER) {
|
||||
if (position < navAdapter.getSubscriptionOffset()) {
|
||||
String tag = navAdapter.getFragmentTags().get(position);
|
||||
((MainActivity) getActivity()).loadFragment(tag, null);
|
||||
((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||
} else {
|
||||
int pos = position - navAdapter.getSubscriptionOffset();
|
||||
NavDrawerData.DrawerItem clickedItem = flatItemList.get(pos);
|
||||
|
||||
if (clickedItem.type == NavDrawerData.DrawerItem.Type.FEED) {
|
||||
long feedId = ((NavDrawerData.FeedDrawerItem) clickedItem).feed.getId();
|
||||
((MainActivity) getActivity()).loadFeedFragmentById(feedId, null);
|
||||
((MainActivity) getActivity()).getBottomSheet()
|
||||
.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||
} else {
|
||||
NavDrawerData.FolderDrawerItem folder = ((NavDrawerData.FolderDrawerItem) clickedItem);
|
||||
if (openFolders.contains(folder.name)) {
|
||||
openFolders.remove(folder.name);
|
||||
} else {
|
||||
openFolders.add(folder.name);
|
||||
}
|
||||
|
||||
getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
.edit()
|
||||
.putStringSet(PREF_OPEN_FOLDERS, openFolders)
|
||||
.apply();
|
||||
|
||||
disposable = Observable.fromCallable(() -> makeFlatDrawerData(navDrawerData.items, 0))
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
result -> {
|
||||
flatItemList = result;
|
||||
navAdapter.notifyDataSetChanged();
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
}
|
||||
} else if (UserPreferences.getSubscriptionsFilter().isEnabled()
|
||||
&& navAdapter.showSubscriptionList) {
|
||||
SubscriptionsFilterDialog.showDialog(requireContext());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemLongClick(int position) {
|
||||
if (position < navAdapter.getFragmentTags().size()) {
|
||||
showDrawerPreferencesDialog();
|
||||
return true;
|
||||
} else {
|
||||
contextPressedItem = flatItemList.get(position - navAdapter.getSubscriptionOffset());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
NavDrawerFragment.this.onCreateContextMenu(menu, v, menuInfo);
|
||||
}
|
||||
};
|
||||
|
||||
private void loadData() {
|
||||
disposable = Observable.fromCallable(DBReader::getNavDrawerData)
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
disposable = Observable.fromCallable(
|
||||
() -> {
|
||||
NavDrawerData data = DBReader.getNavDrawerData();
|
||||
return new Pair<>(data, makeFlatDrawerData(data.items, 0));
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
result -> {
|
||||
navDrawerData = result;
|
||||
updateSelection(); // Selected item might be a feed
|
||||
navDrawerData = result.first;
|
||||
flatItemList = result.second;
|
||||
navAdapter.notifyDataSetChanged();
|
||||
progressBar.setVisibility(View.GONE); // Stays hidden once there is something in the list
|
||||
}, error -> {
|
||||
|
@ -346,45 +392,20 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
int viewType = parent.getAdapter().getItemViewType(position);
|
||||
if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER) {
|
||||
if (position < navAdapter.getSubscriptionOffset()) {
|
||||
String tag = navAdapter.getTags().get(position);
|
||||
if (getActivity() instanceof MainActivity) {
|
||||
((MainActivity) getActivity()).loadFragment(tag, null);
|
||||
((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||
} else {
|
||||
showMainActivity(tag);
|
||||
}
|
||||
} 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);
|
||||
} else {
|
||||
Intent intent = new Intent(getActivity(), MainActivity.class);
|
||||
intent.putExtra(MainActivity.EXTRA_FEED_ID, feedId);
|
||||
startActivity(intent);
|
||||
private List<NavDrawerData.DrawerItem> makeFlatDrawerData(List<NavDrawerData.DrawerItem> items, int layer) {
|
||||
List<NavDrawerData.DrawerItem> flatItems = new ArrayList<>();
|
||||
for (NavDrawerData.DrawerItem item : items) {
|
||||
item.setLayer(layer);
|
||||
flatItems.add(item);
|
||||
if (item.type == NavDrawerData.DrawerItem.Type.FOLDER) {
|
||||
NavDrawerData.FolderDrawerItem folder = ((NavDrawerData.FolderDrawerItem) item);
|
||||
folder.isOpen = openFolders.contains(folder.name);
|
||||
if (folder.isOpen) {
|
||||
flatItems.addAll(makeFlatDrawerData(((NavDrawerData.FolderDrawerItem) item).children, layer + 1));
|
||||
}
|
||||
}
|
||||
} else if (UserPreferences.getSubscriptionsFilter().isEnabled()
|
||||
&& navAdapter.showSubscriptionList) {
|
||||
SubscriptionsFilterDialog.showDialog(requireContext());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (position < navAdapter.getTags().size()) {
|
||||
showDrawerPreferencesDialog();
|
||||
return true;
|
||||
} else {
|
||||
this.position = position;
|
||||
return false;
|
||||
}
|
||||
return flatItems;
|
||||
}
|
||||
|
||||
public static void saveLastNavFragment(Context context, String tag) {
|
||||
|
@ -409,8 +430,7 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli
|
|||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (PREF_LAST_FRAGMENT_TAG.equals(key)) {
|
||||
updateSelection();
|
||||
navAdapter.notifyDataSetChanged();
|
||||
navAdapter.notifyDataSetChanged(); // Update selection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.widget.TextView;
|
|||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
|
@ -44,6 +45,7 @@ import de.danoeh.antennapod.core.service.download.DownloadService;
|
|||
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.download.AutoUpdateManager;
|
||||
import de.danoeh.antennapod.dialog.RemoveFeedDialog;
|
||||
import de.danoeh.antennapod.dialog.SubscriptionsFilterDialog;
|
||||
|
@ -68,6 +70,7 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
|||
private static final String PREFS = "SubscriptionFragment";
|
||||
private static final String PREF_NUM_COLUMNS = "columns";
|
||||
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[] COLUMN_CHECKBOX_IDS = {
|
||||
|
@ -77,21 +80,30 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
|||
R.id.subscription_num_columns_5};
|
||||
|
||||
private GridView subscriptionGridLayout;
|
||||
private DBReader.NavDrawerData navDrawerData;
|
||||
private List<NavDrawerData.DrawerItem> listItems;
|
||||
private SubscriptionsAdapter subscriptionAdapter;
|
||||
private FloatingActionButton subscriptionAddButton;
|
||||
private ProgressBar progressBar;
|
||||
private EmptyViewHandler emptyView;
|
||||
private TextView feedsFilteredMsg;
|
||||
private Toolbar toolbar;
|
||||
private String displayedFolder = null;
|
||||
|
||||
private int mPosition = -1;
|
||||
private Feed selectedFeed = null;
|
||||
private boolean isUpdatingFeeds = false;
|
||||
private boolean displayUpArrow;
|
||||
|
||||
private Disposable disposable;
|
||||
private SharedPreferences prefs;
|
||||
|
||||
public static SubscriptionFragment newInstance(String folderTitle) {
|
||||
SubscriptionFragment fragment = new SubscriptionFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putString(ARGUMENT_FOLDER, folderTitle);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -119,6 +131,13 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
|||
}
|
||||
refreshToolbarState();
|
||||
|
||||
if (getArguments() != null) {
|
||||
displayedFolder = getArguments().getString(ARGUMENT_FOLDER, null);
|
||||
if (displayedFolder != null) {
|
||||
toolbar.setTitle(displayedFolder);
|
||||
}
|
||||
}
|
||||
|
||||
subscriptionGridLayout = root.findViewById(R.id.subscriptions_grid);
|
||||
subscriptionGridLayout.setNumColumns(prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns()));
|
||||
registerForContextMenu(subscriptionGridLayout);
|
||||
|
@ -231,12 +250,23 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
|||
disposable.dispose();
|
||||
}
|
||||
emptyView.hide();
|
||||
disposable = Observable.fromCallable(DBReader::getNavDrawerData)
|
||||
disposable = Observable.fromCallable(
|
||||
() -> {
|
||||
NavDrawerData data = DBReader.getNavDrawerData();
|
||||
List<NavDrawerData.DrawerItem> items = data.items;
|
||||
for (NavDrawerData.DrawerItem item : items) {
|
||||
if (item.type == NavDrawerData.DrawerItem.Type.FOLDER
|
||||
&& item.getTitle().equals(displayedFolder)) {
|
||||
return ((NavDrawerData.FolderDrawerItem) item).children;
|
||||
}
|
||||
}
|
||||
return items;
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
result -> {
|
||||
navDrawerData = result;
|
||||
listItems = result;
|
||||
subscriptionAdapter.notifyDataSetChanged();
|
||||
emptyView.updateVisibility();
|
||||
progressBar.setVisibility(View.GONE); // Keep hidden to avoid flickering while refreshing
|
||||
|
@ -264,37 +294,24 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
|||
AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
int position = adapterInfo.position;
|
||||
|
||||
Object selectedObject = subscriptionAdapter.getItem(position);
|
||||
if (selectedObject.equals(SubscriptionsAdapter.ADD_ITEM_OBJ)) {
|
||||
mPosition = position;
|
||||
return;
|
||||
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;
|
||||
}
|
||||
|
||||
Feed feed = (Feed) selectedObject;
|
||||
|
||||
MenuInflater inflater = requireActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.nav_feed_context, menu);
|
||||
|
||||
menu.setHeaderTitle(feed.getTitle());
|
||||
|
||||
mPosition = position;
|
||||
menu.setHeaderTitle(selectedObject.getTitle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
final int position = mPosition;
|
||||
mPosition = -1; // reset
|
||||
if (position < 0) {
|
||||
if (selectedFeed == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object selectedObject = subscriptionAdapter.getItem(position);
|
||||
if (selectedObject.equals(SubscriptionsAdapter.ADD_ITEM_OBJ)) {
|
||||
// this is the add object, do nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
Feed feed = (Feed) selectedObject;
|
||||
Feed feed = selectedFeed;
|
||||
selectedFeed = null;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.remove_all_new_flags_item:
|
||||
displayConfirmationDialog(
|
||||
|
@ -359,25 +376,20 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
|||
private final SubscriptionsAdapter.ItemAccess itemAccess = new SubscriptionsAdapter.ItemAccess() {
|
||||
@Override
|
||||
public int getCount() {
|
||||
if (navDrawerData != null) {
|
||||
return navDrawerData.feeds.size();
|
||||
if (listItems != null) {
|
||||
return listItems.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 (listItems != null && 0 <= position && position < listItems.size()) {
|
||||
return listItems.get(position);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFeedCounter(long feedId) {
|
||||
return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/tagsRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/rootFolderCheckbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/feed_folders_include_root" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<EditText
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:inputType="text"
|
||||
android:ems="10"
|
||||
android:id="@+id/newTagEditText"/>
|
||||
|
||||
<ImageButton
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="?attr/content_new"
|
||||
android:contentDescription="@string/new_label"
|
||||
android:id="@+id/newTagButton"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -12,6 +12,7 @@
|
|||
android:theme="?attr/actionBarTheme"
|
||||
android:layout_alignParentTop="true"
|
||||
app:title="@string/subscriptions_label"
|
||||
app:navigationIcon="?homeAsUpIndicator"
|
||||
android:id="@+id/toolbar"/>
|
||||
|
||||
<TextView
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
android:background="?android:attr/listDivider"
|
||||
tools:background="@android:color/holo_red_dark" />
|
||||
|
||||
<ListView
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/nav_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -23,6 +23,12 @@
|
|||
android:title="@string/authentication_label"
|
||||
android:summary="@string/authentication_descr"/>
|
||||
|
||||
<Preference
|
||||
android:key="tags"
|
||||
android:icon="?attr/ic_folder"
|
||||
android:title="@string/feed_folders_label"
|
||||
android:summary="@string/feed_folders_summary"/>
|
||||
|
||||
<ListPreference
|
||||
android:key="feedPlaybackSpeed"
|
||||
android:icon="?attr/ic_settings_speed"
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package de.danoeh.antennapod.core.feed;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class FeedFilter {
|
||||
public class FeedFilter implements Serializable {
|
||||
|
||||
private static final String TAG = "FeedFilter";
|
||||
|
||||
|
|
|
@ -7,12 +7,19 @@ import android.text.TextUtils;
|
|||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Contains preferences for a single feed.
|
||||
*/
|
||||
public class FeedPreferences {
|
||||
public class FeedPreferences implements Serializable {
|
||||
|
||||
public static final float SPEED_USE_GLOBAL = -1;
|
||||
public static final String TAG_ROOT = "#root";
|
||||
public static final String TAG_SEPARATOR = "\u001e";
|
||||
|
||||
public enum AutoDeleteAction {
|
||||
GLOBAL,
|
||||
|
@ -33,17 +40,19 @@ public class FeedPreferences {
|
|||
private int feedSkipIntro;
|
||||
private int feedSkipEnding;
|
||||
private boolean showEpisodeNotification;
|
||||
private final Set<String> tags = new HashSet<>();
|
||||
|
||||
public FeedPreferences(long feedID, boolean autoDownload, AutoDeleteAction autoDeleteAction,
|
||||
VolumeAdaptionSetting volumeAdaptionSetting, String username, String password) {
|
||||
this(feedID, autoDownload, true, autoDeleteAction, volumeAdaptionSetting,
|
||||
username, password, new FeedFilter(), SPEED_USE_GLOBAL, 0, 0, false);
|
||||
username, password, new FeedFilter(), SPEED_USE_GLOBAL, 0, 0, false, new HashSet<>());
|
||||
}
|
||||
|
||||
private FeedPreferences(long feedID, boolean autoDownload, boolean keepUpdated,
|
||||
AutoDeleteAction autoDeleteAction, VolumeAdaptionSetting volumeAdaptionSetting,
|
||||
String username, String password, @NonNull FeedFilter filter, float feedPlaybackSpeed,
|
||||
int feedSkipIntro, int feedSkipEnding, boolean showEpisodeNotification) {
|
||||
int feedSkipIntro, int feedSkipEnding, boolean showEpisodeNotification,
|
||||
Set<String> tags) {
|
||||
this.feedID = feedID;
|
||||
this.autoDownload = autoDownload;
|
||||
this.keepUpdated = keepUpdated;
|
||||
|
@ -56,6 +65,7 @@ public class FeedPreferences {
|
|||
this.feedSkipIntro = feedSkipIntro;
|
||||
this.feedSkipEnding = feedSkipEnding;
|
||||
this.showEpisodeNotification = showEpisodeNotification;
|
||||
this.tags.addAll(tags);
|
||||
}
|
||||
|
||||
public static FeedPreferences fromCursor(Cursor cursor) {
|
||||
|
@ -72,6 +82,7 @@ public class FeedPreferences {
|
|||
int indexAutoSkipIntro = cursor.getColumnIndex(PodDBAdapter.KEY_FEED_SKIP_INTRO);
|
||||
int indexAutoSkipEnding = cursor.getColumnIndex(PodDBAdapter.KEY_FEED_SKIP_ENDING);
|
||||
int indexEpisodeNotification = cursor.getColumnIndex(PodDBAdapter.KEY_EPISODE_NOTIFICATION);
|
||||
int indexTags = cursor.getColumnIndex(PodDBAdapter.KEY_FEED_TAGS);
|
||||
|
||||
long feedId = cursor.getLong(indexId);
|
||||
boolean autoDownload = cursor.getInt(indexAutoDownload) > 0;
|
||||
|
@ -88,6 +99,10 @@ public class FeedPreferences {
|
|||
int feedAutoSkipIntro = cursor.getInt(indexAutoSkipIntro);
|
||||
int feedAutoSkipEnding = cursor.getInt(indexAutoSkipEnding);
|
||||
boolean showNotification = cursor.getInt(indexEpisodeNotification) > 0;
|
||||
String tagsString = cursor.getString(indexTags);
|
||||
if (TextUtils.isEmpty(tagsString)) {
|
||||
tagsString = TAG_ROOT;
|
||||
}
|
||||
return new FeedPreferences(feedId,
|
||||
autoDownload,
|
||||
autoRefresh,
|
||||
|
@ -99,8 +114,8 @@ public class FeedPreferences {
|
|||
feedPlaybackSpeed,
|
||||
feedAutoSkipIntro,
|
||||
feedAutoSkipEnding,
|
||||
showNotification
|
||||
);
|
||||
showNotification,
|
||||
new HashSet<>(Arrays.asList(tagsString.split(TAG_SEPARATOR))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -240,6 +255,14 @@ public class FeedPreferences {
|
|||
return feedSkipEnding;
|
||||
}
|
||||
|
||||
public Set<String> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public String getTagsAsString() {
|
||||
return TextUtils.join(TAG_SEPARATOR, tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* getter for preference if notifications should be display for new episodes.
|
||||
* @return true for displaying notifications
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.io.File;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -874,32 +875,34 @@ 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<>();
|
||||
Map<String, NavDrawerData.FolderDrawerItem> folders = new HashMap<>();
|
||||
for (Feed feed : feeds) {
|
||||
for (String tag : feed.getPreferences().getTags()) {
|
||||
NavDrawerData.FeedDrawerItem drawerItem = new NavDrawerData.FeedDrawerItem(feed, feed.getId(),
|
||||
feedCounters.get(feed.getId()));
|
||||
if (FeedPreferences.TAG_ROOT.equals(tag)) {
|
||||
items.add(drawerItem);
|
||||
continue;
|
||||
}
|
||||
NavDrawerData.FolderDrawerItem folder;
|
||||
if (folders.containsKey(tag)) {
|
||||
folder = folders.get(tag);
|
||||
} else {
|
||||
folder = new NavDrawerData.FolderDrawerItem(tag);
|
||||
folders.put(tag, folder);
|
||||
}
|
||||
drawerItem.id |= folder.id;
|
||||
folder.children.add(drawerItem);
|
||||
}
|
||||
}
|
||||
List<NavDrawerData.FolderDrawerItem> foldersSorted = new ArrayList<>(folders.values());
|
||||
Collections.sort(foldersSorted, (o1, o2) -> o1.getTitle().compareToIgnoreCase(o2.getTitle()));
|
||||
items.addAll(foldersSorted);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,6 +319,8 @@ class DBUpgrader {
|
|||
+ " SET " + PodDBAdapter.KEY_DESCRIPTION + " = content_encoded, content_encoded = NULL "
|
||||
+ "WHERE length(" + PodDBAdapter.KEY_DESCRIPTION + ") < length(content_encoded)");
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + " SET content_encoded = NULL");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_FEED_TAGS + " TEXT;");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
package de.danoeh.antennapod.core.storage;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.util.LongIntMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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 abstract static class DrawerItem {
|
||||
public enum Type {
|
||||
FOLDER, FEED
|
||||
}
|
||||
|
||||
public final Type type;
|
||||
private int layer;
|
||||
public long id;
|
||||
|
||||
public DrawerItem(Type type, long id) {
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getLayer() {
|
||||
return layer;
|
||||
}
|
||||
|
||||
public void setLayer(int layer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
public abstract String getTitle();
|
||||
|
||||
public abstract int getCounter();
|
||||
}
|
||||
|
||||
public static class FolderDrawerItem extends DrawerItem {
|
||||
public final List<DrawerItem> children = new ArrayList<>();
|
||||
public final String name;
|
||||
public boolean isOpen;
|
||||
|
||||
public FolderDrawerItem(String name) {
|
||||
super(DrawerItem.Type.FOLDER, (long) name.hashCode() << 20); // Keep IDs >0 but make room for many feeds
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getCounter() {
|
||||
int sum = 0;
|
||||
for (DrawerItem item : children) {
|
||||
sum += item.getCounter();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FeedDrawerItem extends DrawerItem {
|
||||
public final Feed feed;
|
||||
public final int counter;
|
||||
|
||||
public FeedDrawerItem(Feed feed, long id, int counter) {
|
||||
super(DrawerItem.Type.FEED, id);
|
||||
this.feed = feed;
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return feed.getTitle();
|
||||
}
|
||||
|
||||
public int getCounter() {
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -115,6 +115,7 @@ public class PodDBAdapter {
|
|||
public static final String KEY_FEED_PLAYBACK_SPEED = "feed_playback_speed";
|
||||
public static final String KEY_FEED_SKIP_INTRO = "feed_skip_intro";
|
||||
public static final String KEY_FEED_SKIP_ENDING = "feed_skip_ending";
|
||||
public static final String KEY_FEED_TAGS = "tags";
|
||||
public static final String KEY_EPISODE_NOTIFICATION = "episode_notification";
|
||||
|
||||
// Table names
|
||||
|
@ -152,6 +153,7 @@ public class PodDBAdapter {
|
|||
+ KEY_AUTO_DELETE_ACTION + " INTEGER DEFAULT 0,"
|
||||
+ KEY_FEED_PLAYBACK_SPEED + " REAL DEFAULT " + SPEED_USE_GLOBAL + ","
|
||||
+ KEY_FEED_VOLUME_ADAPTION + " INTEGER DEFAULT 0,"
|
||||
+ KEY_FEED_TAGS + " TEXT,"
|
||||
+ KEY_FEED_SKIP_INTRO + " INTEGER DEFAULT 0,"
|
||||
+ KEY_FEED_SKIP_ENDING + " INTEGER DEFAULT 0,"
|
||||
+ KEY_EPISODE_NOTIFICATION + " INTEGER DEFAULT 0)";
|
||||
|
@ -255,6 +257,7 @@ public class PodDBAdapter {
|
|||
TABLE_NAME_FEEDS + "." + KEY_INCLUDE_FILTER,
|
||||
TABLE_NAME_FEEDS + "." + KEY_EXCLUDE_FILTER,
|
||||
TABLE_NAME_FEEDS + "." + KEY_FEED_PLAYBACK_SPEED,
|
||||
TABLE_NAME_FEEDS + "." + KEY_FEED_TAGS,
|
||||
TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_INTRO,
|
||||
TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_ENDING,
|
||||
TABLE_NAME_FEEDS + "." + KEY_EPISODE_NOTIFICATION
|
||||
|
@ -447,6 +450,7 @@ public class PodDBAdapter {
|
|||
values.put(KEY_INCLUDE_FILTER, prefs.getFilter().getIncludeFilter());
|
||||
values.put(KEY_EXCLUDE_FILTER, prefs.getFilter().getExcludeFilter());
|
||||
values.put(KEY_FEED_PLAYBACK_SPEED, prefs.getFeedPlaybackSpeed());
|
||||
values.put(KEY_FEED_TAGS, prefs.getTagsAsString());
|
||||
values.put(KEY_FEED_SKIP_INTRO, prefs.getFeedSkipIntro());
|
||||
values.put(KEY_FEED_SKIP_ENDING, prefs.getFeedSkipEnding());
|
||||
values.put(KEY_EPISODE_NOTIFICATION, prefs.getShowEpisodeNotification());
|
||||
|
|
|
@ -731,9 +731,12 @@
|
|||
<string name="apply_action">Apply action</string>
|
||||
<string name="play_chapter">Play chapter</string>
|
||||
|
||||
<!-- Feed information screen -->
|
||||
<!-- Feed settings/information screen -->
|
||||
<string name="authentication_label">Authentication</string>
|
||||
<string name="authentication_descr">Change your username and password for this podcast and its episodes.</string>
|
||||
<string name="feed_folders_label">Folders</string>
|
||||
<string name="feed_folders_summary">Change the folders in which this podcast is displayed.</string>
|
||||
<string name="feed_folders_include_root">Show in main list</string>
|
||||
<string name="auto_download_settings_label">Auto Download Settings</string>
|
||||
<string name="episode_filters_label">Episode Filter</string>
|
||||
<string name="episode_filters_description">List of terms used to decide if an episode should be included or excluded when auto downloading</string>
|
||||
|
|
|
@ -322,8 +322,8 @@ public class DbReaderTest {
|
|||
final int numFeeds = 10;
|
||||
final int numItems = 10;
|
||||
DbTestUtils.saveFeedlist(numFeeds, numItems, true);
|
||||
DBReader.NavDrawerData navDrawerData = DBReader.getNavDrawerData();
|
||||
assertEquals(numFeeds, navDrawerData.feeds.size());
|
||||
NavDrawerData navDrawerData = DBReader.getNavDrawerData();
|
||||
assertEquals(numFeeds, navDrawerData.items.size());
|
||||
assertEquals(0, navDrawerData.numNewItems);
|
||||
assertEquals(0, navDrawerData.queueSize);
|
||||
}
|
||||
|
@ -351,8 +351,8 @@ public class DbReaderTest {
|
|||
|
||||
adapter.close();
|
||||
|
||||
DBReader.NavDrawerData navDrawerData = DBReader.getNavDrawerData();
|
||||
assertEquals(numFeeds, navDrawerData.feeds.size());
|
||||
NavDrawerData navDrawerData = DBReader.getNavDrawerData();
|
||||
assertEquals(numFeeds, navDrawerData.items.size());
|
||||
assertEquals(numNew, navDrawerData.numNewItems);
|
||||
assertEquals(numQueue, navDrawerData.queueSize);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue