Feed multi select (#5261)
This commit is contained in:
parent
91967409cb
commit
eacc90af29
@ -76,21 +76,19 @@ public class EpisodeItemListAdapter extends SelectableAdapter<EpisodeItemViewHol
|
||||
int position = ArrayUtils.indexOf(ids, item.getId());
|
||||
activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position));
|
||||
} else {
|
||||
toggleSelection(pos);
|
||||
toggleSelection(holder.getBindingAdapterPosition());
|
||||
}
|
||||
});
|
||||
holder.itemView.setOnCreateContextMenuListener(this);
|
||||
holder.itemView.setOnLongClickListener(v -> {
|
||||
longPressedItem = item;
|
||||
longPressedPosition = pos;
|
||||
longPressedItem = getItem(holder.getBindingAdapterPosition());
|
||||
longPressedPosition = holder.getBindingAdapterPosition();
|
||||
return false;
|
||||
});
|
||||
|
||||
if (inActionMode()) {
|
||||
holder.secondaryActionButton.setVisibility(View.GONE);
|
||||
holder.selectCheckBox.setOnClickListener(v -> {
|
||||
toggleSelection(pos);
|
||||
});
|
||||
holder.selectCheckBox.setOnClickListener(v -> toggleSelection(holder.getBindingAdapterPosition()));
|
||||
holder.selectCheckBox.setChecked(isSelected(pos));
|
||||
holder.selectCheckBox.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
|
@ -1,152 +0,0 @@
|
||||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.core.text.TextUtilsCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
|
||||
import de.danoeh.antennapod.core.storage.NavDrawerData;
|
||||
import de.danoeh.antennapod.fragment.FeedItemlistFragment;
|
||||
import de.danoeh.antennapod.fragment.SubscriptionFragment;
|
||||
import jp.shts.android.library.TriangleLabelView;
|
||||
|
||||
/**
|
||||
* Adapter for subscriptions
|
||||
*/
|
||||
public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnItemClickListener {
|
||||
/** the position in the view that holds the add item; 0 is the first, -1 is the last position */
|
||||
private static final String TAG = "SubscriptionsAdapter";
|
||||
|
||||
private final WeakReference<MainActivity> mainActivityRef;
|
||||
private final ItemAccess itemAccess;
|
||||
|
||||
public SubscriptionsAdapter(MainActivity mainActivity, ItemAccess itemAccess) {
|
||||
this.mainActivityRef = new WeakReference<>(mainActivity);
|
||||
this.itemAccess = itemAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return itemAccess.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return itemAccess.getItem(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return ((NavDrawerData.DrawerItem) getItem(position)).id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
Holder holder;
|
||||
|
||||
if (convertView == null) {
|
||||
holder = new Holder();
|
||||
|
||||
LayoutInflater layoutInflater =
|
||||
(LayoutInflater) mainActivityRef.get().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = layoutInflater.inflate(R.layout.subscription_item, parent, false);
|
||||
holder.feedTitle = convertView.findViewById(R.id.txtvTitle);
|
||||
holder.imageView = convertView.findViewById(R.id.imgvCover);
|
||||
holder.count = convertView.findViewById(R.id.triangleCountView);
|
||||
|
||||
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (Holder) convertView.getTag();
|
||||
}
|
||||
|
||||
final NavDrawerData.DrawerItem drawerItem = (NavDrawerData.DrawerItem) getItem(position);
|
||||
if (drawerItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
holder.feedTitle.setText(drawerItem.getTitle());
|
||||
holder.imageView.setContentDescription(drawerItem.getTitle());
|
||||
holder.feedTitle.setVisibility(View.VISIBLE);
|
||||
|
||||
// Fix TriangleLabelView corner for RTL
|
||||
if (TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
|
||||
== ViewCompat.LAYOUT_DIRECTION_RTL) {
|
||||
holder.count.setCorner(TriangleLabelView.Corner.TOP_LEFT);
|
||||
}
|
||||
|
||||
if (drawerItem.getCounter() > 0) {
|
||||
holder.count.setPrimaryText(NumberFormat.getInstance().format(drawerItem.getCounter()));
|
||||
holder.count.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.count.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
|
||||
Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed;
|
||||
boolean textAndImageCombined = feed.isLocalFeed()
|
||||
&& LocalFeedUpdater.getDefaultIconUrl(convertView.getContext()).equals(feed.getImageUrl());
|
||||
new CoverLoader(mainActivityRef.get())
|
||||
.withUri(feed.getImageUrl())
|
||||
.withPlaceholderView(holder.feedTitle, textAndImageCombined)
|
||||
.withCoverView(holder.imageView)
|
||||
.load();
|
||||
} else {
|
||||
new CoverLoader(mainActivityRef.get())
|
||||
.withResource(R.drawable.ic_folder)
|
||||
.withPlaceholderView(holder.feedTitle, true)
|
||||
.withCoverView(holder.imageView)
|
||||
.load();
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final NavDrawerData.DrawerItem drawerItem = (NavDrawerData.DrawerItem) getItem(position);
|
||||
if (drawerItem == null) {
|
||||
return;
|
||||
}
|
||||
if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
|
||||
Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed;
|
||||
Fragment fragment = FeedItemlistFragment.newInstance(feed.getId());
|
||||
mainActivityRef.get().loadChildFragment(fragment);
|
||||
} else if (drawerItem.type == NavDrawerData.DrawerItem.Type.FOLDER) {
|
||||
Fragment fragment = SubscriptionFragment.newInstance(drawerItem.getTitle());
|
||||
mainActivityRef.get().loadChildFragment(fragment);
|
||||
}
|
||||
}
|
||||
|
||||
static class Holder {
|
||||
public TextView feedTitle;
|
||||
public ImageView imageView;
|
||||
public TriangleLabelView count;
|
||||
}
|
||||
|
||||
public interface ItemAccess {
|
||||
int getCount();
|
||||
|
||||
NavDrawerData.DrawerItem getItem(int position);
|
||||
}
|
||||
}
|
@ -0,0 +1,245 @@
|
||||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.text.TextUtilsCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
|
||||
import de.danoeh.antennapod.core.storage.NavDrawerData;
|
||||
import de.danoeh.antennapod.fragment.FeedItemlistFragment;
|
||||
import de.danoeh.antennapod.fragment.SubscriptionFragment;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import jp.shts.android.library.TriangleLabelView;
|
||||
|
||||
/**
|
||||
* Adapter for subscriptions
|
||||
*/
|
||||
public class SubscriptionsRecyclerAdapter extends SelectableAdapter<SubscriptionsRecyclerAdapter.SubscriptionViewHolder>
|
||||
implements View.OnCreateContextMenuListener {
|
||||
private final WeakReference<MainActivity> mainActivityRef;
|
||||
private List<NavDrawerData.DrawerItem> listItems;
|
||||
private Feed selectedFeed = null;
|
||||
int longPressedPosition = 0; // used to init actionMode
|
||||
|
||||
public SubscriptionsRecyclerAdapter(MainActivity mainActivity) {
|
||||
super(mainActivity);
|
||||
this.mainActivityRef = new WeakReference<>(mainActivity);
|
||||
this.listItems = new ArrayList<>();
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
public Object getItem(int position) {
|
||||
return listItems.get(position);
|
||||
}
|
||||
|
||||
public Feed getSelectedFeed() {
|
||||
return selectedFeed;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public SubscriptionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View itemView = LayoutInflater.from(mainActivityRef.get()).inflate(R.layout.subscription_item, parent, false);
|
||||
return new SubscriptionViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull SubscriptionViewHolder holder, int position) {
|
||||
NavDrawerData.DrawerItem drawerItem = listItems.get(position);
|
||||
boolean isFeed = drawerItem.type == NavDrawerData.DrawerItem.Type.FEED;
|
||||
holder.bind(drawerItem);
|
||||
holder.itemView.setOnCreateContextMenuListener(this);
|
||||
if (inActionMode()) {
|
||||
if (isFeed) {
|
||||
holder.selectCheckbox.setVisibility(View.VISIBLE);
|
||||
holder.selectView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
holder.selectCheckbox.setChecked((isSelected(position)));
|
||||
holder.selectCheckbox.setOnCheckedChangeListener((buttonView, isChecked)
|
||||
-> setSelected(holder.getBindingAdapterPosition(), isChecked));
|
||||
holder.imageView.setAlpha(0.6f);
|
||||
holder.count.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.selectView.setVisibility(View.GONE);
|
||||
holder.imageView.setAlpha(1.0f);
|
||||
}
|
||||
|
||||
holder.itemView.setOnLongClickListener(v -> {
|
||||
if (!inActionMode()) {
|
||||
if (isFeed) {
|
||||
selectedFeed = ((NavDrawerData.FeedDrawerItem) getItem(holder.getBindingAdapterPosition())).feed;
|
||||
longPressedPosition = holder.getBindingAdapterPosition();
|
||||
} else {
|
||||
selectedFeed = null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (isFeed) {
|
||||
if (inActionMode()) {
|
||||
holder.selectCheckbox.setChecked(!isSelected(holder.getBindingAdapterPosition()));
|
||||
} else {
|
||||
Fragment fragment = FeedItemlistFragment
|
||||
.newInstance(((NavDrawerData.FeedDrawerItem) drawerItem).feed.getId());
|
||||
mainActivityRef.get().loadChildFragment(fragment);
|
||||
}
|
||||
} else if (!inActionMode()) {
|
||||
Fragment fragment = SubscriptionFragment.newInstance(drawerItem.getTitle());
|
||||
mainActivityRef.get().loadChildFragment(fragment);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return listItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return listItems.get(position).id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
if (selectedFeed != null && !inActionMode()) {
|
||||
MenuInflater inflater = mainActivityRef.get().getMenuInflater();
|
||||
inflater.inflate(R.menu.nav_feed_context, menu);
|
||||
menu.setHeaderTitle(selectedFeed.getTitle());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.multi_select) {
|
||||
startSelectMode(longPressedPosition);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Feed> getSelectedItems() {
|
||||
List<Feed> items = new ArrayList<>();
|
||||
for (int i = 0; i < getItemCount(); i++) {
|
||||
if (isSelected(i)) {
|
||||
NavDrawerData.DrawerItem drawerItem = listItems.get(i);
|
||||
if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
|
||||
Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed;
|
||||
items.add(feed);
|
||||
}
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
public void setItems(List<NavDrawerData.DrawerItem> listItems) {
|
||||
this.listItems = listItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(int pos, boolean selected) {
|
||||
NavDrawerData.DrawerItem drawerItem = listItems.get(pos);
|
||||
if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
|
||||
super.setSelected(pos, selected);
|
||||
}
|
||||
}
|
||||
|
||||
public class SubscriptionViewHolder extends RecyclerView.ViewHolder {
|
||||
private final TextView feedTitle;
|
||||
private final ImageView imageView;
|
||||
private final TriangleLabelView count;
|
||||
private final FrameLayout selectView;
|
||||
private final CheckBox selectCheckbox;
|
||||
|
||||
public SubscriptionViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
feedTitle = itemView.findViewById(R.id.txtvTitle);
|
||||
imageView = itemView.findViewById(R.id.imgvCover);
|
||||
count = itemView.findViewById(R.id.triangleCountView);
|
||||
selectView = itemView.findViewById(R.id.selectView);
|
||||
selectCheckbox = itemView.findViewById(R.id.selectCheckBox);
|
||||
}
|
||||
|
||||
public void bind(NavDrawerData.DrawerItem drawerItem) {
|
||||
feedTitle.setText(drawerItem.getTitle());
|
||||
imageView.setContentDescription(drawerItem.getTitle());
|
||||
feedTitle.setVisibility(View.VISIBLE);
|
||||
if (TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
|
||||
== ViewCompat.LAYOUT_DIRECTION_RTL) {
|
||||
count.setCorner(TriangleLabelView.Corner.TOP_LEFT);
|
||||
}
|
||||
|
||||
if (drawerItem.getCounter() > 0) {
|
||||
count.setPrimaryText(NumberFormat.getInstance().format(drawerItem.getCounter()));
|
||||
count.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
count.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
|
||||
Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed;
|
||||
boolean textAndImageCombind = feed.isLocalFeed()
|
||||
&& LocalFeedUpdater.getDefaultIconUrl(itemView.getContext()).equals(feed.getImageUrl());
|
||||
new CoverLoader(mainActivityRef.get())
|
||||
.withUri(feed.getImageUrl())
|
||||
.withPlaceholderView(feedTitle, textAndImageCombind)
|
||||
.withCoverView(imageView)
|
||||
.load();
|
||||
} else {
|
||||
new CoverLoader(mainActivityRef.get())
|
||||
.withResource(R.drawable.ic_folder)
|
||||
.withPlaceholderView(feedTitle, true)
|
||||
.withCoverView(imageView)
|
||||
.load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static float convertDpToPixel(Context context, float dp) {
|
||||
return dp * context.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
public static class GridDividerItemDecorator extends RecyclerView.ItemDecoration {
|
||||
@Override
|
||||
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
||||
super.onDraw(c, parent, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(@NonNull Rect outRect,
|
||||
@NonNull View view,
|
||||
@NonNull RecyclerView parent,
|
||||
@NonNull RecyclerView.State state) {
|
||||
super.getItemOffsets(outRect, view, parent, state);
|
||||
Context context = parent.getContext();
|
||||
int insetOffset = (int) convertDpToPixel(context, 1f);
|
||||
outRect.set(insetOffset, insetOffset, insetOffset, insetOffset);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,10 @@ import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
@ -16,10 +20,17 @@ public class RemoveFeedDialog {
|
||||
private static final String TAG = "RemoveFeedDialog";
|
||||
|
||||
public static void show(Context context, Feed feed, Runnable onSuccess) {
|
||||
int messageId = feed.isLocalFeed() ? R.string.feed_delete_confirmation_local_msg
|
||||
: R.string.feed_delete_confirmation_msg;
|
||||
String message = context.getString(messageId, feed.getTitle());
|
||||
List<Feed> feeds = Collections.singletonList(feed);
|
||||
String message = getMessageId(context, feeds);
|
||||
showDialog(context, feeds, message, onSuccess);
|
||||
}
|
||||
|
||||
public static void show(Context context, List<Feed> feeds, Runnable onSuccess) {
|
||||
String message = getMessageId(context, feeds);
|
||||
showDialog(context, feeds, message, onSuccess);
|
||||
}
|
||||
|
||||
private static void showDialog(Context context, List<Feed> feeds, String message, Runnable onSuccess) {
|
||||
ConfirmationDialog dialog = new ConfirmationDialog(context, R.string.remove_feed_label, message) {
|
||||
@Override
|
||||
public void onConfirmButtonPressed(DialogInterface clickedDialog) {
|
||||
@ -31,12 +42,17 @@ public class RemoveFeedDialog {
|
||||
progressDialog.setCancelable(false);
|
||||
progressDialog.show();
|
||||
|
||||
Completable.fromCallable(() -> DBWriter.deleteFeed(context, feed.getId()).get())
|
||||
Completable.fromCallable(() -> {
|
||||
for (Feed feed : feeds) {
|
||||
DBWriter.deleteFeed(context, feed.getId()).get();
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
() -> {
|
||||
Log.d(TAG, "Feed was deleted");
|
||||
Log.d(TAG, "Feed(s) deleted");
|
||||
if (onSuccess != null) {
|
||||
onSuccess.run();
|
||||
}
|
||||
@ -49,4 +65,17 @@ public class RemoveFeedDialog {
|
||||
};
|
||||
dialog.createNewDialog().show();
|
||||
}
|
||||
|
||||
private static String getMessageId(Context context, List<Feed> feeds) {
|
||||
if (feeds.size() == 1) {
|
||||
if (feeds.get(0).isLocalFeed()) {
|
||||
return context.getString(R.string.feed_delete_confirmation_local_msg);
|
||||
} else {
|
||||
return context.getString(R.string.feed_delete_confirmation_msg, feeds.get(0).getTitle());
|
||||
}
|
||||
} else {
|
||||
return context.getString(R.string.feed_delete_confirmation_msg_batch);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -7,41 +7,44 @@ import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.GridView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
import com.leinardi.android.speeddial.SpeedDialView;
|
||||
|
||||
import de.danoeh.antennapod.dialog.TagSettingsDialog;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.SubscriptionsAdapter;
|
||||
import de.danoeh.antennapod.adapter.SubscriptionsRecyclerAdapter;
|
||||
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
|
||||
import de.danoeh.antennapod.core.event.DownloadEvent;
|
||||
import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
|
||||
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
|
||||
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
|
||||
import de.danoeh.antennapod.dialog.TagSettingsDialog;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadService;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
@ -49,24 +52,24 @@ import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.storage.NavDrawerData;
|
||||
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
|
||||
import de.danoeh.antennapod.dialog.RemoveFeedDialog;
|
||||
import de.danoeh.antennapod.dialog.SubscriptionsFilterDialog;
|
||||
import de.danoeh.antennapod.dialog.FeedSortDialog;
|
||||
import de.danoeh.antennapod.dialog.RemoveFeedDialog;
|
||||
import de.danoeh.antennapod.dialog.RenameFeedDialog;
|
||||
import de.danoeh.antennapod.dialog.SubscriptionsFilterDialog;
|
||||
import de.danoeh.antennapod.fragment.actions.FeedMultiSelectActionHandler;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.view.EmptyViewHandler;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
/**
|
||||
* Fragment for displaying feed subscriptions
|
||||
*/
|
||||
public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItemClickListener {
|
||||
|
||||
public class SubscriptionFragment extends Fragment
|
||||
implements Toolbar.OnMenuItemClickListener,
|
||||
SubscriptionsRecyclerAdapter.OnSelectModeListener {
|
||||
public static final String TAG = "SubscriptionFragment";
|
||||
private static final String PREFS = "SubscriptionFragment";
|
||||
private static final String PREF_NUM_COLUMNS = "columns";
|
||||
@ -80,23 +83,24 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
||||
R.id.subscription_num_columns_4,
|
||||
R.id.subscription_num_columns_5};
|
||||
|
||||
private GridView subscriptionGridLayout;
|
||||
private List<NavDrawerData.DrawerItem> listItems;
|
||||
private SubscriptionsAdapter subscriptionAdapter;
|
||||
private RecyclerView subscriptionRecycler;
|
||||
private SubscriptionsRecyclerAdapter subscriptionAdapter;
|
||||
private FloatingActionButton subscriptionAddButton;
|
||||
private ProgressBar progressBar;
|
||||
private EmptyViewHandler emptyView;
|
||||
private TextView feedsFilteredMsg;
|
||||
private Toolbar toolbar;
|
||||
private String displayedFolder = null;
|
||||
|
||||
private Feed selectedFeed = null;
|
||||
private boolean isUpdatingFeeds = false;
|
||||
private boolean displayUpArrow;
|
||||
|
||||
private Disposable disposable;
|
||||
private SharedPreferences prefs;
|
||||
|
||||
private SpeedDialView speedDialView;
|
||||
|
||||
private List<NavDrawerData.DrawerItem> listItems;
|
||||
|
||||
public static SubscriptionFragment newInstance(String folderTitle) {
|
||||
SubscriptionFragment fragment = new SubscriptionFragment();
|
||||
Bundle args = new Bundle();
|
||||
@ -139,9 +143,15 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
||||
}
|
||||
}
|
||||
|
||||
subscriptionGridLayout = root.findViewById(R.id.subscriptions_grid);
|
||||
subscriptionGridLayout.setNumColumns(prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns()));
|
||||
registerForContextMenu(subscriptionGridLayout);
|
||||
subscriptionRecycler = root.findViewById(R.id.subscriptions_grid);
|
||||
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(),
|
||||
prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns()),
|
||||
RecyclerView.VERTICAL,
|
||||
false);
|
||||
subscriptionRecycler.setLayoutManager(gridLayoutManager);
|
||||
subscriptionRecycler.addItemDecoration(new SubscriptionsRecyclerAdapter.GridDividerItemDecorator());
|
||||
gridLayoutManager.setSpanCount(prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns()));
|
||||
registerForContextMenu(subscriptionRecycler);
|
||||
subscriptionAddButton = root.findViewById(R.id.subscriptions_add);
|
||||
progressBar = root.findViewById(R.id.progLoading);
|
||||
|
||||
@ -155,6 +165,25 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> swipeRefreshLayout.setRefreshing(false),
|
||||
getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms));
|
||||
});
|
||||
|
||||
speedDialView = root.findViewById(R.id.fabSD);
|
||||
speedDialView.inflate(R.menu.nav_feed_action_speeddial);
|
||||
speedDialView.setOnChangeListener(new SpeedDialView.OnChangeListener() {
|
||||
@Override
|
||||
public boolean onMainActionSelected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onToggleChanged(boolean isOpen) {
|
||||
}
|
||||
});
|
||||
speedDialView.setOnActionSelectedListener(actionItem -> {
|
||||
new FeedMultiSelectActionHandler((MainActivity) getActivity(), subscriptionAdapter.getSelectedItems())
|
||||
.handleAction(actionItem.getId());
|
||||
return true;
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -204,7 +233,9 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
||||
}
|
||||
|
||||
private void setColumnNumber(int columns) {
|
||||
subscriptionGridLayout.setNumColumns(columns);
|
||||
GridLayoutManager gridLayoutManager = (GridLayoutManager) subscriptionRecycler.getLayoutManager();
|
||||
gridLayoutManager.setSpanCount(columns);
|
||||
subscriptionAdapter.notifyDataSetChanged();
|
||||
prefs.edit().putInt(PREF_NUM_COLUMNS, columns).apply();
|
||||
refreshToolbarState();
|
||||
}
|
||||
@ -214,18 +245,16 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
||||
emptyView.setIcon(R.drawable.ic_folder);
|
||||
emptyView.setTitle(R.string.no_subscriptions_head_label);
|
||||
emptyView.setMessage(R.string.no_subscriptions_label);
|
||||
emptyView.attachToListView(subscriptionGridLayout);
|
||||
emptyView.attachToRecyclerView(subscriptionRecycler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
subscriptionAdapter = new SubscriptionsAdapter((MainActivity) getActivity(), itemAccess);
|
||||
subscriptionGridLayout.setAdapter(subscriptionAdapter);
|
||||
subscriptionGridLayout.setOnItemClickListener(subscriptionAdapter);
|
||||
subscriptionAdapter = new SubscriptionsRecyclerAdapter((MainActivity) getActivity());
|
||||
subscriptionAdapter.setOnSelectModeListener(this);
|
||||
subscriptionRecycler.setAdapter(subscriptionAdapter);
|
||||
setupEmptyView();
|
||||
|
||||
subscriptionAddButton.setOnClickListener(view -> {
|
||||
if (getActivity() instanceof MainActivity) {
|
||||
((MainActivity) getActivity()).loadChildFragment(new AddFeedFragment());
|
||||
@ -247,6 +276,10 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
|
||||
if (subscriptionAdapter != null) {
|
||||
subscriptionAdapter.endSelectMode();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSubscriptions() {
|
||||
@ -271,6 +304,7 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
||||
.subscribe(
|
||||
result -> {
|
||||
listItems = result;
|
||||
subscriptionAdapter.setItems(result);
|
||||
subscriptionAdapter.notifyDataSetChanged();
|
||||
emptyView.updateVisibility();
|
||||
progressBar.setVisibility(View.GONE); // Keep hidden to avoid flickering while refreshing
|
||||
@ -292,34 +326,13 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
||||
return getResources().getInteger(R.integer.subscriptions_default_num_of_columns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
if (menuInfo == null) {
|
||||
return;
|
||||
}
|
||||
AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
int position = adapterInfo.position;
|
||||
|
||||
NavDrawerData.DrawerItem selectedObject = (NavDrawerData.DrawerItem) subscriptionAdapter.getItem(position);
|
||||
|
||||
if (selectedObject.type == NavDrawerData.DrawerItem.Type.FEED) {
|
||||
MenuInflater inflater = requireActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.nav_feed_context, menu);
|
||||
selectedFeed = ((NavDrawerData.FeedDrawerItem) selectedObject).feed;
|
||||
}
|
||||
menu.setHeaderTitle(selectedObject.getTitle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
if (selectedFeed == null) {
|
||||
Feed feed = subscriptionAdapter.getSelectedFeed();
|
||||
if (feed == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Feed feed = selectedFeed;
|
||||
selectedFeed = null;
|
||||
final int itemId = item.getItemId();
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.remove_all_new_flags_item) {
|
||||
displayConfirmationDialog(
|
||||
R.string.remove_all_new_flags_label,
|
||||
@ -335,6 +348,9 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
||||
} else if (itemId == R.id.remove_item) {
|
||||
RemoveFeedDialog.show(getContext(), feed, null);
|
||||
return true;
|
||||
} else if (itemId == R.id.multi_select) {
|
||||
speedDialView.setVisibility(View.VISIBLE);
|
||||
return subscriptionAdapter.onContextItemSelected(item);
|
||||
}
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
@ -376,23 +392,23 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
||||
private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker =
|
||||
() -> DownloadService.isRunning && DownloadRequester.getInstance().isDownloadingFeeds();
|
||||
|
||||
private final SubscriptionsAdapter.ItemAccess itemAccess = new SubscriptionsAdapter.ItemAccess() {
|
||||
@Override
|
||||
public int getCount() {
|
||||
if (listItems != null) {
|
||||
return listItems.size();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onEndSelectMode() {
|
||||
speedDialView.close();
|
||||
speedDialView.setVisibility(View.GONE);
|
||||
subscriptionAdapter.setItems(listItems);
|
||||
subscriptionAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavDrawerData.DrawerItem getItem(int position) {
|
||||
if (listItems != null && 0 <= position && position < listItems.size()) {
|
||||
return listItems.get(position);
|
||||
} else {
|
||||
return null;
|
||||
@Override
|
||||
public void onStartSelectMode() {
|
||||
List<NavDrawerData.DrawerItem> feedsOnly = new ArrayList<>();
|
||||
for (NavDrawerData.DrawerItem item : listItems) {
|
||||
if (item.type == NavDrawerData.DrawerItem.Type.FEED) {
|
||||
feedsOnly.add(item);
|
||||
}
|
||||
}
|
||||
};
|
||||
subscriptionAdapter.setItems(feedsOnly);
|
||||
subscriptionAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,139 @@
|
||||
package de.danoeh.antennapod.fragment.actions;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.PluralsRes;
|
||||
import androidx.core.util.Consumer;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.dialog.RemoveFeedDialog;
|
||||
import de.danoeh.antennapod.fragment.preferences.dialog.PreferenceListDialog;
|
||||
import de.danoeh.antennapod.fragment.preferences.dialog.PreferenceSwitchDialog;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
||||
|
||||
public class FeedMultiSelectActionHandler {
|
||||
private static final String TAG = "FeedSelectHandler";
|
||||
private final MainActivity activity;
|
||||
private final List<Feed> selectedItems;
|
||||
|
||||
public FeedMultiSelectActionHandler(MainActivity activity, List<Feed> selectedItems) {
|
||||
this.activity = activity;
|
||||
this.selectedItems = selectedItems;
|
||||
}
|
||||
|
||||
public void handleAction(int id) {
|
||||
if (id == R.id.remove_item) {
|
||||
RemoveFeedDialog.show(activity, selectedItems, null);
|
||||
} else if (id == R.id.keep_updated) {
|
||||
keepUpdatedPrefHandler();
|
||||
} else if (id == R.id.autodownload) {
|
||||
autoDownloadPrefHandler();
|
||||
} else if (id == R.id.autoDeleteDownload) {
|
||||
autoDeleteEpisodesPrefHandler();
|
||||
} else if (id == R.id.playback_speed) {
|
||||
playbackSpeedPrefHandler();
|
||||
} else {
|
||||
Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=" + id);
|
||||
}
|
||||
}
|
||||
|
||||
private void autoDownloadPrefHandler() {
|
||||
PreferenceSwitchDialog preferenceSwitchDialog = new PreferenceSwitchDialog(activity,
|
||||
activity.getString(R.string.auto_download_settings_label),
|
||||
activity.getString(R.string.auto_download_label));
|
||||
preferenceSwitchDialog.setOnPreferenceChangedListener(new PreferenceSwitchDialog.OnPreferenceChangedListener() {
|
||||
@Override
|
||||
public void preferenceChanged(boolean enabled) {
|
||||
saveFeedPreferences(feedPreferences -> feedPreferences.setAutoDownload(enabled));
|
||||
}
|
||||
});
|
||||
preferenceSwitchDialog.openDialog();
|
||||
}
|
||||
|
||||
private static final DecimalFormat SPEED_FORMAT =
|
||||
new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.US));
|
||||
|
||||
private void playbackSpeedPrefHandler() {
|
||||
final String[] speeds = activity.getResources().getStringArray(R.array.playback_speed_values);
|
||||
String[] values = new String[speeds.length + 1];
|
||||
values[0] = SPEED_FORMAT.format(FeedPreferences.SPEED_USE_GLOBAL);
|
||||
|
||||
String[] entries = new String[speeds.length + 1];
|
||||
entries[0] = activity.getString(R.string.feed_auto_download_global);
|
||||
|
||||
System.arraycopy(speeds, 0, values, 1, speeds.length);
|
||||
System.arraycopy(speeds, 0, entries, 1, speeds.length);
|
||||
|
||||
PreferenceListDialog preferenceListDialog = new PreferenceListDialog(activity,
|
||||
activity.getString(R.string.playback_speed));
|
||||
preferenceListDialog.openDialog(entries);
|
||||
preferenceListDialog.setOnPreferenceChangedListener(pos -> {
|
||||
saveFeedPreferences(feedPreferences -> {
|
||||
feedPreferences.setFeedPlaybackSpeed(Float.parseFloat((String) values[pos]));
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void autoDeleteEpisodesPrefHandler() {
|
||||
PreferenceListDialog preferenceListDialog = new PreferenceListDialog(activity,
|
||||
"Auto delete episodes");
|
||||
String[] items = activity.getResources().getStringArray(R.array.spnAutoDeleteItems);
|
||||
String[] values = activity.getResources().getStringArray(R.array.spnAutoDeleteValues);
|
||||
preferenceListDialog.openDialog(items);
|
||||
preferenceListDialog.setOnPreferenceChangedListener(which -> {
|
||||
FeedPreferences.AutoDeleteAction autoDeleteAction = null;
|
||||
switch (values[which]) {
|
||||
case "global":
|
||||
autoDeleteAction = FeedPreferences.AutoDeleteAction.GLOBAL;
|
||||
break;
|
||||
case "always":
|
||||
autoDeleteAction = FeedPreferences.AutoDeleteAction.YES;
|
||||
break;
|
||||
case "never":
|
||||
autoDeleteAction = FeedPreferences.AutoDeleteAction.NO;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
FeedPreferences.AutoDeleteAction finalAutoDeleteAction = autoDeleteAction;
|
||||
saveFeedPreferences(feedPreferences -> {
|
||||
feedPreferences.setAutoDeleteAction(finalAutoDeleteAction);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void keepUpdatedPrefHandler() {
|
||||
PreferenceSwitchDialog preferenceSwitchDialog = new PreferenceSwitchDialog(activity,
|
||||
activity.getString(R.string.kept_updated),
|
||||
activity.getString(R.string.keep_updated_summary));
|
||||
preferenceSwitchDialog.setOnPreferenceChangedListener(keepUpdated -> {
|
||||
saveFeedPreferences(feedPreferences -> {
|
||||
feedPreferences.setKeepUpdated(keepUpdated);
|
||||
});
|
||||
});
|
||||
preferenceSwitchDialog.openDialog();
|
||||
}
|
||||
|
||||
private void showMessage(@PluralsRes int msgId, int numItems) {
|
||||
activity.showSnackbarAbovePlayer(activity.getResources()
|
||||
.getQuantityString(msgId, numItems, numItems), Snackbar.LENGTH_LONG);
|
||||
}
|
||||
|
||||
private void saveFeedPreferences(Consumer<FeedPreferences> preferencesConsumer) {
|
||||
for (Feed feed : selectedItems) {
|
||||
preferencesConsumer.accept(feed.getPreferences());
|
||||
DBWriter.setFeedPreferences(feed.getPreferences());
|
||||
}
|
||||
showMessage(R.plurals.updated_feeds_batch_label, selectedItems.size());
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package de.danoeh.antennapod.fragment.preferences.dialog;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
|
||||
public class PreferenceListDialog {
|
||||
protected Context context;
|
||||
private String title;
|
||||
private OnPreferenceChangedListener onPreferenceChangedListener;
|
||||
private int selectedPos = 0;
|
||||
|
||||
public PreferenceListDialog(Context context, String title) {
|
||||
this.context = context;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public interface OnPreferenceChangedListener {
|
||||
/**
|
||||
* Notified when user confirms preference
|
||||
*
|
||||
* @param pos The index of the item that was selected
|
||||
*/
|
||||
|
||||
void preferenceChanged(int pos);
|
||||
}
|
||||
|
||||
public void openDialog(String[] items) {
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(title);
|
||||
builder.setSingleChoiceItems(items, selectedPos, (dialog, which) -> {
|
||||
selectedPos = which;
|
||||
});
|
||||
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
|
||||
if (onPreferenceChangedListener != null && selectedPos >= 0) {
|
||||
onPreferenceChangedListener.preferenceChanged(selectedPos);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel_label, null);
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public void setOnPreferenceChangedListener(OnPreferenceChangedListener onPreferenceChangedListener) {
|
||||
this.onPreferenceChangedListener = onPreferenceChangedListener;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package de.danoeh.antennapod.fragment.preferences.dialog;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
|
||||
public class PreferenceSwitchDialog {
|
||||
protected Context context;
|
||||
private String title;
|
||||
private String text;
|
||||
private OnPreferenceChangedListener onPreferenceChangedListener;
|
||||
|
||||
public PreferenceSwitchDialog(Context context, String title, String text) {
|
||||
this.context = context;
|
||||
this.title = title;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public interface OnPreferenceChangedListener {
|
||||
/**
|
||||
* Notified when user confirms preference
|
||||
*
|
||||
* @param enabled The preference
|
||||
*/
|
||||
|
||||
void preferenceChanged(boolean enabled);
|
||||
}
|
||||
|
||||
public void openDialog() {
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(title);
|
||||
|
||||
LayoutInflater inflater = LayoutInflater.from(this.context);
|
||||
View layout = inflater.inflate(R.layout.dialog_switch_preference, null, false);
|
||||
SwitchCompat switchButton = layout.findViewById(R.id.dialogSwitch);
|
||||
switchButton.setText(text);
|
||||
builder.setView(layout);
|
||||
|
||||
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
|
||||
if (onPreferenceChangedListener != null) {
|
||||
onPreferenceChangedListener.preferenceChanged(switchButton.isChecked());
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel_label, null);
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public void setOnPreferenceChangedListener(OnPreferenceChangedListener onPreferenceChangedListener) {
|
||||
this.onPreferenceChangedListener = onPreferenceChangedListener;
|
||||
}
|
||||
}
|
15
app/src/main/res/layout/dialog_switch_preference.xml
Normal file
15
app/src/main/res/layout/dialog_switch_preference.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="24dp">
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/dialogSwitch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="Switch" />
|
||||
|
||||
</LinearLayout>
|
@ -1,33 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
android:layout_alignParentTop="true"
|
||||
app:title="@string/subscriptions_label"
|
||||
app:navigationIcon="?homeAsUpIndicator"
|
||||
android:id="@+id/toolbar"/>
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
android:layout_alignParentTop="true"
|
||||
app:title="@string/subscriptions_label"
|
||||
app:navigationIcon="?homeAsUpIndicator" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/feeds_filtered_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/toolbar"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:gravity="start"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="@dimen/text_size_small" />
|
||||
android:id="@+id/feeds_filtered_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/toolbar"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:gravity="start"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="@dimen/text_size_small" />
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipeRefresh"
|
||||
@ -35,35 +36,36 @@
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/feeds_filtered_message">
|
||||
|
||||
<GridView
|
||||
android:id="@+id/subscriptions_grid"
|
||||
android:layout_width="match_parent"
|
||||
android:numColumns="3"
|
||||
android:horizontalSpacing="2dp"
|
||||
android:verticalSpacing="2dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:paddingBottom="88dp"
|
||||
android:clipToPadding="false"/>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/subscriptions_grid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:paddingBottom="88dp"
|
||||
android:clipToPadding="false" />
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progLoading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminateOnly="true"
|
||||
android:visibility="visible"/>
|
||||
android:id="@+id/progLoading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminateOnly="true"
|
||||
android:visibility="visible" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/subscriptions_add"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:contentDescription="@string/add_feed_label"
|
||||
app:srcCompat="@drawable/ic_add"/>
|
||||
android:id="@+id/subscriptions_add"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:contentDescription="@string/add_feed_label"
|
||||
app:srcCompat="@drawable/ic_add" />
|
||||
|
||||
<include
|
||||
layout="@layout/multi_select_speed_dial" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:squareImageView="http://schemas.android.com/apk/de.danoeh.antennapod"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:foreground="?attr/selectableItemBackground">
|
||||
|
||||
<de.danoeh.antennapod.ui.common.SquareImageView
|
||||
@ -15,7 +15,7 @@
|
||||
android:background="@color/non_square_icon_background"
|
||||
android:scaleType="fitCenter"
|
||||
squareImageView:direction="width"
|
||||
tools:src="@mipmap/ic_launcher_round" />
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<com.joanzapata.iconify.widget.IconTextView
|
||||
android:id="@+id/txtvTitle"
|
||||
@ -46,4 +46,20 @@
|
||||
app:primaryTextColor="?attr/colorOnSecondary"
|
||||
app:primaryTextSize="12sp" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/selectView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ic_checkbox_background">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/selectCheckBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="0dp"
|
||||
android:minHeight="0dp"
|
||||
android:layout_margin="8dp" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
28
app/src/main/res/menu/nav_feed_action_speeddial.xml
Normal file
28
app/src/main/res/menu/nav_feed_action_speeddial.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/remove_item"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/remove_feed_label"
|
||||
android:icon="@drawable/ic_delete"/>
|
||||
<item
|
||||
android:id="@+id/keep_updated"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/keep_updated"
|
||||
android:icon="@drawable/ic_refresh"/>
|
||||
<item
|
||||
android:id="@+id/autodownload"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/auto_download_label"
|
||||
android:icon="@drawable/ic_download"/>
|
||||
<item
|
||||
android:id="@+id/autoDeleteDownload"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/auto_delete_label"
|
||||
android:icon="@drawable/ic_delete_auto"/>
|
||||
<item
|
||||
android:id="@+id/playback_speed"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/playback_speed"
|
||||
android:icon="@drawable/ic_playback_speed"/>
|
||||
</menu>
|
@ -21,4 +21,8 @@
|
||||
android:menuCategory="container"
|
||||
android:title="@string/remove_feed_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/multi_select"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/multi_select" />
|
||||
</menu>
|
||||
|
10
core/src/main/res/drawable/ic_checkbox_background.xml
Normal file
10
core/src/main/res/drawable/ic_checkbox_background.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="56dp"
|
||||
android:height="56dp"
|
||||
android:viewportWidth="15.1"
|
||||
android:viewportHeight="15.1">
|
||||
<path
|
||||
android:pathData="M-7.4167,3.2465a11.2253,11.8267 0,1 0,22.4506 0a11.2253,11.8267 0,1 0,-22.4506 0z"
|
||||
android:strokeWidth="0"
|
||||
android:fillColor="#BBFFFFFF"/>
|
||||
</vector>
|
15
core/src/main/res/drawable/ic_delete_auto.xml
Normal file
15
core/src/main/res/drawable/ic_delete_auto.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M15,2l-3.5,0l-1,-1l-5,0l-1,1l-3.5,0l0,2l14,0z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M16,9c-0.7,0 -1.37,0.1 -2,0.29V5H2v12c0,1.1 0.9,2 2,2h5.68c1.12,2.36 3.53,4 6.32,4c3.87,0 7,-3.13 7,-7C23,12.13 19.87,9 16,9zM9,16c0,0.34 0.03,0.67 0.08,1H4V7h8v3.26C10.19,11.53 9,13.62 9,16zM16,21c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5s5,2.24 5,5S18.76,21 16,21z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M16.5,12l-1.5,0l0,5l3.6,2.1l0.8,-1.2l-2.9,-1.7z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
@ -171,6 +171,7 @@
|
||||
<string name="share_website_url_label">Website address</string>
|
||||
<string name="share_feed_url_label">Podcast feed URL</string>
|
||||
<string name="feed_delete_confirmation_msg">Please confirm that you want to delete the podcast \"%1$s\" and ALL its episodes (including downloaded episodes).</string>
|
||||
<string name="feed_delete_confirmation_msg_batch">Please confirm that you want to remove the selected podcasts and ALL their episodes (including downloaded episodes).</string>
|
||||
<string name="feed_delete_confirmation_local_msg">Please confirm that you want to remove the podcast \"%1$s\". The files in the local source folder will not be deleted.</string>
|
||||
<string name="feed_remover_msg">Removing podcast</string>
|
||||
<string name="load_complete_feed">Refresh complete podcast</string>
|
||||
@ -182,6 +183,10 @@
|
||||
<string name="open_podcast">Open Podcast</string>
|
||||
<string name="please_wait_for_data">Please wait until the data is loaded</string>
|
||||
<string name="updates_disabled_label">Updates disabled</string>
|
||||
<plurals name="updated_feeds_batch_label">
|
||||
<item quantity="one">%d subscription updated.</item>
|
||||
<item quantity="other">%d subscriptions updated.</item>
|
||||
</plurals>
|
||||
<string name="add_to_folder">Add to folder</string>
|
||||
|
||||
<!-- actions on feeditems -->
|
||||
|
Loading…
x
Reference in New Issue
Block a user