mirror of
https://github.com/M66B/FairEmail.git
synced 2025-03-03 18:26:20 +00:00
Recyclerview selection experiment
This commit is contained in:
parent
2f28bf9f55
commit
6b8222f3c5
8 changed files with 221 additions and 3 deletions
Binary file not shown.
|
@ -79,6 +79,7 @@ dependencies {
|
|||
|
||||
implementation "androidx.appcompat:appcompat:$androidx_version"
|
||||
implementation "androidx.recyclerview:recyclerview:$androidx_version"
|
||||
implementation "androidx.recyclerview:recyclerview-selection:$androidx_version"
|
||||
implementation "com.google.android.material:material:$androidx_version"
|
||||
implementation "androidx.browser:browser:$androidx_version"
|
||||
implementation "androidx.constraintlayout:constraintlayout:$constraintlayout_version"
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.content.Intent;
|
|||
import android.graphics.Typeface;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -41,6 +42,8 @@ import androidx.lifecycle.LifecycleOwner;
|
|||
import androidx.lifecycle.Observer;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.paging.PagedListAdapter;
|
||||
import androidx.recyclerview.selection.ItemDetailsLookup;
|
||||
import androidx.recyclerview.selection.SelectionTracker;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
|
@ -48,6 +51,7 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
|
|||
private Context context;
|
||||
private LifecycleOwner owner;
|
||||
private ViewType viewType;
|
||||
private SelectionTracker selectionTracker;
|
||||
|
||||
private boolean debug;
|
||||
private DateFormat df = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.SHORT, SimpleDateFormat.LONG);
|
||||
|
@ -84,12 +88,12 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
|
|||
|
||||
private void wire() {
|
||||
itemView.setOnClickListener(this);
|
||||
itemView.setOnLongClickListener(this);
|
||||
//itemView.setOnLongClickListener(this);
|
||||
}
|
||||
|
||||
private void unwire() {
|
||||
itemView.setOnClickListener(null);
|
||||
itemView.setOnLongClickListener(null);
|
||||
//itemView.setOnLongClickListener(null);
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
|
@ -107,6 +111,8 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
|
|||
private void bindTo(final TupleMessageEx message) {
|
||||
pbLoading.setVisibility(View.GONE);
|
||||
|
||||
itemView.setActivated(selectionTracker.isSelected(message.id));
|
||||
|
||||
if (EntityFolder.DRAFTS.equals(message.folderType) ||
|
||||
EntityFolder.OUTBOX.equals(message.folderType) ||
|
||||
EntityFolder.SENT.equals(message.folderType)) {
|
||||
|
@ -209,6 +215,16 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public ItemDetailsLookup.ItemDetails getItemDetails() {
|
||||
Log.i(Helper.TAG, "getItemDetails");
|
||||
return new MyItemDetail(getAdapterPosition(), getItem(getAdapterPosition()).id);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelectionTracker(SelectionTracker selectionTracker) {
|
||||
Log.i(Helper.TAG, "setSelectionTracker");
|
||||
this.selectionTracker = selectionTracker;
|
||||
}
|
||||
|
||||
AdapterMessage(Context context, LifecycleOwner owner, ViewType viewType) {
|
||||
|
@ -243,6 +259,7 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
|
|||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
holder.unwire();
|
||||
Log.i(Helper.TAG, "onBindViewHolder");
|
||||
|
||||
TupleMessageEx message = getItem(position);
|
||||
if (message == null)
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.view.LayoutInflater;
|
|||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
|
@ -46,6 +47,10 @@ import androidx.lifecycle.LiveData;
|
|||
import androidx.lifecycle.Observer;
|
||||
import androidx.paging.LivePagedListBuilder;
|
||||
import androidx.paging.PagedList;
|
||||
import androidx.recyclerview.selection.OnDragInitiatedListener;
|
||||
import androidx.recyclerview.selection.SelectionPredicates;
|
||||
import androidx.recyclerview.selection.SelectionTracker;
|
||||
import androidx.recyclerview.selection.StorageStrategy;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
|
@ -58,6 +63,7 @@ public class FragmentMessages extends FragmentEx {
|
|||
|
||||
private long primary = -1;
|
||||
private AdapterMessage adapter;
|
||||
private SelectionTracker selectionTracker;
|
||||
|
||||
private static final int PAGE_SIZE = 50;
|
||||
|
||||
|
@ -118,7 +124,14 @@ public class FragmentMessages extends FragmentEx {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
if (selectionTracker != null)
|
||||
selectionTracker.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
// Get arguments
|
||||
|
@ -191,6 +204,53 @@ public class FragmentMessages extends FragmentEx {
|
|||
Log.i(Helper.TAG, "Submit messages=" + messages.size());
|
||||
adapter.submitList(messages);
|
||||
|
||||
selectionTracker = new SelectionTracker.Builder<>(
|
||||
"messages-selection",
|
||||
rvMessage,
|
||||
new MyItemKeyProvider(messages),
|
||||
new MyItemLookup(rvMessage),
|
||||
StorageStrategy.createLongStorage())
|
||||
.withSelectionPredicate(SelectionPredicates.<Long>createSelectAnything())
|
||||
.withOnDragInitiatedListener(new OnDragInitiatedListener() {
|
||||
@Override
|
||||
public boolean onDragInitiated(@NonNull MotionEvent e) {
|
||||
Log.i(Helper.TAG, "onDragInitiated");
|
||||
return true;
|
||||
}
|
||||
}).build();
|
||||
|
||||
|
||||
adapter.setSelectionTracker(selectionTracker);
|
||||
|
||||
selectionTracker.addObserver(new SelectionTracker.SelectionObserver() {
|
||||
@Override
|
||||
public void onItemStateChanged(@NonNull Object key, boolean selected) {
|
||||
Log.i(Helper.TAG, "onItemStateChanged");
|
||||
super.onItemStateChanged(key, selected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectionRefresh() {
|
||||
Log.i(Helper.TAG, "onSelectionRefresh");
|
||||
super.onSelectionRefresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectionChanged() {
|
||||
Log.i(Helper.TAG, "onSelectionChanged");
|
||||
super.onSelectionChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectionRestored() {
|
||||
Log.i(Helper.TAG, "onSelectionRestored");
|
||||
super.onSelectionRestored();
|
||||
}
|
||||
});
|
||||
|
||||
if (savedInstanceState != null)
|
||||
selectionTracker.onRestoreInstanceState(savedInstanceState);
|
||||
|
||||
pbWait.setVisibility(View.GONE);
|
||||
grpReady.setVisibility(View.VISIBLE);
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package eu.faircode.email;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.recyclerview.selection.SelectionTracker;
|
||||
|
||||
public class MyActionModeController implements ActionMode.Callback {
|
||||
private final Context context;
|
||||
private final SelectionTracker selectionTracker;
|
||||
|
||||
public MyActionModeController(Context context, SelectionTracker selectionTracker) {
|
||||
this.context = context;
|
||||
this.selectionTracker = selectionTracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode actionMode) {
|
||||
selectionTracker.clearSelection();
|
||||
}
|
||||
}
|
30
app/src/main/java/eu/faircode/email/MyItemDetail.java
Normal file
30
app/src/main/java/eu/faircode/email/MyItemDetail.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package eu.faircode.email;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.selection.ItemDetailsLookup;
|
||||
|
||||
public class MyItemDetail extends ItemDetailsLookup.ItemDetails<Long> {
|
||||
private final int adapterPosition;
|
||||
private final Long selectionKey;
|
||||
|
||||
public MyItemDetail(int adapterPosition, Long selectionKey) {
|
||||
Log.i(Helper.TAG, "MyItemDetail");
|
||||
this.adapterPosition = adapterPosition;
|
||||
this.selectionKey = selectionKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPosition() {
|
||||
Log.i(Helper.TAG, "MyItemDetail.getPosition=" + adapterPosition);
|
||||
return adapterPosition;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Long getSelectionKey() {
|
||||
Log.i(Helper.TAG, "MyItemDetail.getSelectionKey=" + selectionKey);
|
||||
return selectionKey;
|
||||
}
|
||||
}
|
37
app/src/main/java/eu/faircode/email/MyItemKeyProvider.java
Normal file
37
app/src/main/java/eu/faircode/email/MyItemKeyProvider.java
Normal file
|
@ -0,0 +1,37 @@
|
|||
package eu.faircode.email;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.paging.PagedList;
|
||||
import androidx.recyclerview.selection.ItemKeyProvider;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class MyItemKeyProvider extends ItemKeyProvider<Long> {
|
||||
private final PagedList<TupleMessageEx> messages;
|
||||
|
||||
public MyItemKeyProvider(PagedList<TupleMessageEx> messages) {
|
||||
super(ItemKeyProvider.SCOPE_MAPPED);
|
||||
this.messages = messages;
|
||||
Log.i(Helper.TAG, "MyItemKeyProvider");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Long getKey(int position) {
|
||||
Log.i(Helper.TAG, "MyItemKeyProvider.getKey pos=" + position + " key=" + messages.get(position).id);
|
||||
return messages.get(position).id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPosition(@NonNull Long key) {
|
||||
Log.i(Helper.TAG, "MyItemKeyProvider.getPosition key=" + key);
|
||||
int pos = RecyclerView.NO_POSITION;
|
||||
for (int i = 0; i < messages.size(); i++)
|
||||
if (messages.get(i).id.equals(key))
|
||||
pos = i;
|
||||
Log.i(Helper.TAG, "MyItemKeyProvider.getPosition key=" + key + " pos=" + pos);
|
||||
return pos;
|
||||
}
|
||||
}
|
35
app/src/main/java/eu/faircode/email/MyItemLookup.java
Normal file
35
app/src/main/java/eu/faircode/email/MyItemLookup.java
Normal file
|
@ -0,0 +1,35 @@
|
|||
package eu.faircode.email;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.selection.ItemDetailsLookup;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class MyItemLookup extends ItemDetailsLookup<Long> {
|
||||
|
||||
private final RecyclerView recyclerView;
|
||||
|
||||
public MyItemLookup(RecyclerView recyclerView) {
|
||||
Log.i(Helper.TAG, "MyItemLookup");
|
||||
this.recyclerView = recyclerView;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ItemDetails<Long> getItemDetails(@NonNull MotionEvent e) {
|
||||
Log.i(Helper.TAG, "MyItemLookup.getItemDetails");
|
||||
View view = recyclerView.findChildViewUnder(e.getX(), e.getY());
|
||||
if (view != null) {
|
||||
RecyclerView.ViewHolder viewHolder = recyclerView.getChildViewHolder(view);
|
||||
if (viewHolder instanceof AdapterMessage.ViewHolder) {
|
||||
return ((AdapterMessage.ViewHolder) viewHolder).getItemDetails();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue