RecyclerView context menus (with ripple)

This commit is contained in:
Martin Fietz 2015-11-06 00:20:59 +01:00
parent 32a47d0f65
commit 51aba83ae2
5 changed files with 82 additions and 88 deletions

View File

@ -7,8 +7,10 @@ import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@ -51,6 +53,8 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
private final boolean showOnlyNewEpisodes;
private final WeakReference<MainActivity> mainActivityRef;
private int position = -1;
public AllEpisodesRecycleAdapter(Context context,
MainActivity mainActivity,
ItemAccess itemAccess,
@ -96,6 +100,10 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
public void onBindViewHolder(final Holder holder, int position) {
final FeedItem item = itemAccess.getItem(position);
if (item == null) return;
holder.itemView.setOnLongClickListener(v -> {
this.position = position;
return false;
});
holder.item = item;
holder.position = position;
holder.placeholder.setVisibility(View.VISIBLE);
@ -189,6 +197,10 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
return itemAccess.getItem(position);
}
public int getPosition() {
return position;
}
private class CoverTarget extends GlideDrawableImageViewTarget {
private final WeakReference<Uri> fallback;
@ -235,63 +247,8 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
}
};
private Menu popupMenu;
private final FeedItemMenuHandler.MenuInterface contextMenuInterface = new FeedItemMenuHandler.MenuInterface() {
@Override
public void setItemVisibility(int id, boolean visible) {
if(popupMenu == null) {
return;
}
MenuItem item = popupMenu.findItem(id);
if (item != null) {
item.setVisible(visible);
}
}
};
private final boolean showContextMenu(View view) {
// Create a PopupMenu, giving it the clicked view for an anchor
MainActivity mainActivity = this.mainActivityRef.get();
if (mainActivity == null) {
Log.d(TAG, "mainActivity is null");
return false;
}
PopupMenu popup = new PopupMenu(mainActivity, view);
Menu menu = popup.getMenu();
// Inflate our menu resource into the PopupMenu's Menu
popup.getMenuInflater().inflate(R.menu.allepisodes_context, popup.getMenu());
Holder holder = (Holder) view.getTag();
FeedItem item = holder.item;
if (item == null) {
return false;
}
popupMenu = menu;
FeedItemMenuHandler.onPrepareMenu(context, contextMenuInterface, item, true, null);
// Set a listener so we are notified if a menu item is clicked
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
try {
FeedItemMenuHandler.onMenuItemClicked(context, menuItem.getItemId(), item);
return true;
} catch (DownloadRequestException e) {
e.printStackTrace();
}
return false;
}
});
popup.show();
return true;
}
public class Holder extends RecyclerView.ViewHolder
implements View.OnClickListener, View.OnLongClickListener{
implements View.OnClickListener, View.OnCreateContextMenuListener {
TextView placeholder;
TextView title;
TextView pubDate;
@ -308,7 +265,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
public Holder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
itemView.setOnCreateContextMenuListener(this);
}
@Override
@ -321,12 +278,30 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
public FeedItem getFeedItem() { return item; }
public int getItemPosition() { return position; }
@Override
public boolean onLongClick(View view) {
return showContextMenu(view);
public void onCreateContextMenu(final ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
FeedItem item = itemAccess.getItem(getAdapterPosition());
MenuInflater inflater = mainActivityRef.get().getMenuInflater();
inflater.inflate(R.menu.allepisodes_context, menu);
if (item != null) {
menu.setHeaderTitle(item.getTitle());
}
FeedItemMenuHandler.MenuInterface contextMenuInterface = (id, visible) -> {
if (menu == null) {
return;
}
MenuItem item1 = menu.findItem(id);
if (item1 != null) {
item1.setVisible(visible);
}
};
FeedItemMenuHandler.onPrepareMenu(mainActivityRef.get(), contextMenuInterface, item, true,
null);
}
}
public interface ItemAccess {

View File

@ -58,6 +58,8 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
private boolean locked;
private int position = -1;
public QueueRecyclerAdapter(MainActivity mainActivity,
ItemAccess itemAccess,
ActionButtonCallback actionButtonCallback,
@ -84,13 +86,19 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
public void onBindViewHolder(ViewHolder holder, int pos) {
FeedItem item = itemAccess.getItem(pos);
holder.bind(item);
holder.position = pos;
holder.itemView.setOnLongClickListener(v -> {
position = pos;
return false;
});
}
public int getItemCount() {
return itemAccess.getCount();
}
public int getPosition() {
return position;
}
public class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener, View.OnCreateContextMenuListener {
@ -106,7 +114,6 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
private final ImageButton butSecondary;
private FeedItem item;
private int position;
public ViewHolder(View v) {
super(v);

View File

@ -18,6 +18,7 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ProgressBar;
import android.widget.Toast;
@ -39,7 +40,9 @@ import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.view.DividerItemDecoration;
import rx.Observable;
@ -260,6 +263,28 @@ public class AllEpisodesFragment extends Fragment {
}
@Override
public boolean onContextItemSelected(MenuItem item) {
if(!isVisible()) {
return false;
}
int pos = listAdapter.getPosition();
FeedItem selectedItem = itemAccess.getItem(pos);
if (selectedItem == null) {
Log.i(TAG, "Selected item at position " + pos + " was null, ignoring selection");
return super.onContextItemSelected(item);
}
try {
return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
} catch (DownloadRequestException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
return true;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return onCreateViewHelper(inflater, container, savedInstanceState,
@ -280,6 +305,7 @@ public class AllEpisodesFragment extends Fragment {
recyclerView.setHasFixedSize(true);
RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(getActivity(), null);
recyclerView.addItemDecoration(itemDecoration);
registerForContextMenu(recyclerView);
progLoading = (ProgressBar) root.findViewById(R.id.progLoading);

View File

@ -79,9 +79,6 @@ public class QueueFragment extends Fragment {
private TextView txtvEmpty;
private ProgressBar progLoading;
private ContextMenu contextMenu;
private AdapterView.AdapterContextMenuInfo lastMenuInfo = null;
private List<FeedItem> queue;
private List<Downloader> downloaderList;
@ -166,7 +163,10 @@ public class QueueFragment extends Fragment {
recyclerAdapter.notifyDataSetChanged();
break;
case MOVED:
// ItemTouchHelper already handled everything
int from = FeedItemUtil.indexOfItemWithId(queue, event.item.getId());
int to = event.position;
Collections.swap(queue, from, to);
recyclerAdapter.notifyItemMoved(from, to);
break;
}
}
@ -217,7 +217,6 @@ public class QueueFragment extends Fragment {
}
private void resetViewState() {
unregisterForContextMenu(recyclerView);
blockDownloadObserverUpdate = false;
if (downloadObserver != null) {
downloadObserver.onPause();
@ -319,32 +318,19 @@ public class QueueFragment extends Fragment {
} else {
return true;
}
}
private final FeedItemMenuHandler.MenuInterface contextMenuInterface = new FeedItemMenuHandler.MenuInterface() {
@Override
public void setItemVisibility(int id, boolean visible) {
if(contextMenu == null) {
return;
}
MenuItem item = contextMenu.findItem(id);
if (item != null) {
item.setVisible(visible);
}
}
};
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
if(menuInfo == null) {
menuInfo = lastMenuInfo;
if(!isVisible()) {
return false;
}
FeedItem selectedItem = itemAccess.getItem(menuInfo.position);
int pos = recyclerAdapter.getPosition();
FeedItem selectedItem = itemAccess.getItem(pos);
if (selectedItem == null) {
Log.i(TAG, "Selected item at position " + menuInfo.position + " was null, ignoring selection");
Log.i(TAG, "Selected item at position " + pos + " was null, ignoring selection");
return super.onContextItemSelected(item);
}
@ -371,6 +357,7 @@ public class QueueFragment extends Fragment {
RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(getActivity(), null);
recyclerView.addItemDecoration(itemDecoration);
recyclerView.setHasFixedSize(true);
registerForContextMenu(recyclerView);
itemTouchHelper = new ItemTouchHelper(
new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT) {
@ -380,8 +367,6 @@ public class QueueFragment extends Fragment {
int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();
Log.d(TAG, "move(" + from + ", " + to + ")");
Collections.swap(queue, from, to);
recyclerAdapter.notifyItemMoved(from, to);
DBWriter.moveQueueItem(from, to, true);
return true;
}

View File

@ -5,6 +5,7 @@
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_threeline_height"
android:orientation="horizontal"
android:background="?attr/selectableItemBackground"
tools:background="@android:color/darker_gray">
<RelativeLayout