mirror of https://github.com/M66B/FairEmail.git
Added multiple selection
This commit is contained in:
parent
1fdb9c70a8
commit
61441c3c8a
|
@ -94,6 +94,8 @@ import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.lifecycle.Observer;
|
import androidx.lifecycle.Observer;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
import androidx.paging.PagedListAdapter;
|
import androidx.paging.PagedListAdapter;
|
||||||
|
import androidx.recyclerview.selection.ItemDetailsLookup;
|
||||||
|
import androidx.recyclerview.selection.SelectionTracker;
|
||||||
import androidx.recyclerview.widget.DiffUtil;
|
import androidx.recyclerview.widget.DiffUtil;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
@ -109,6 +111,8 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
|
||||||
private boolean compact;
|
private boolean compact;
|
||||||
private boolean debug;
|
private boolean debug;
|
||||||
|
|
||||||
|
private SelectionTracker<Long> selectionTracker = null;
|
||||||
|
|
||||||
private DateFormat df = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.LONG, SimpleDateFormat.LONG);
|
private DateFormat df = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.LONG, SimpleDateFormat.LONG);
|
||||||
|
|
||||||
enum ViewType {UNIFIED, FOLDER, THREAD, SEARCH}
|
enum ViewType {UNIFIED, FOLDER, THREAD, SEARCH}
|
||||||
|
@ -159,6 +163,8 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
|
||||||
private Group grpAttachments;
|
private Group grpAttachments;
|
||||||
private Group grpExpanded;
|
private Group grpExpanded;
|
||||||
|
|
||||||
|
private ItemDetailsMessage itemDetails = null;
|
||||||
|
|
||||||
ViewHolder(View itemView) {
|
ViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
|
||||||
|
@ -251,7 +257,7 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
|
||||||
grpExpanded.setVisibility(View.GONE);
|
grpExpanded.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindTo(final TupleMessageEx message) {
|
private void bindTo(int position, final TupleMessageEx message) {
|
||||||
final DB db = DB.getInstance(context);
|
final DB db = DB.getInstance(context);
|
||||||
final boolean show_expanded = properties.isExpanded(message.id);
|
final boolean show_expanded = properties.isExpanded(message.id);
|
||||||
boolean show_headers = properties.showHeaders(message.id);
|
boolean show_headers = properties.showHeaders(message.id);
|
||||||
|
@ -458,6 +464,9 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itemDetails = new ItemDetailsMessage(position, message.id);
|
||||||
|
itemView.setActivated(selectionTracker != null && selectionTracker.isSelected(message.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1329,6 +1338,10 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
|
||||||
.putExtra("action", "reply")
|
.putExtra("action", "reply")
|
||||||
.putExtra("reference", data.message.id));
|
.putExtra("reference", data.message.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ItemDetailsLookup.ItemDetails<Long> getItemDetails(@NonNull MotionEvent motionEvent) {
|
||||||
|
return itemDetails;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AdapterMessage(Context context, LifecycleOwner owner, ViewType viewType, IProperties properties) {
|
AdapterMessage(Context context, LifecycleOwner owner, ViewType viewType, IProperties properties) {
|
||||||
|
@ -1380,11 +1393,15 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
|
||||||
if (message == null)
|
if (message == null)
|
||||||
holder.clear();
|
holder.clear();
|
||||||
else {
|
else {
|
||||||
holder.bindTo(message);
|
holder.bindTo(position, message);
|
||||||
holder.wire();
|
holder.wire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setSelectionTracker(SelectionTracker<Long> selectionTracker) {
|
||||||
|
this.selectionTracker = selectionTracker;
|
||||||
|
}
|
||||||
|
|
||||||
interface IProperties {
|
interface IProperties {
|
||||||
void setExpanded(long id, boolean expand);
|
void setExpanded(long id, boolean expand);
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,8 @@ import androidx.lifecycle.ViewModelProviders;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
import androidx.paging.LivePagedListBuilder;
|
import androidx.paging.LivePagedListBuilder;
|
||||||
import androidx.paging.PagedList;
|
import androidx.paging.PagedList;
|
||||||
|
import androidx.recyclerview.selection.SelectionTracker;
|
||||||
|
import androidx.recyclerview.selection.StorageStrategy;
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
@ -95,6 +97,8 @@ public class FragmentMessages extends FragmentEx {
|
||||||
private AdapterMessage.ViewType viewType;
|
private AdapterMessage.ViewType viewType;
|
||||||
private LiveData<PagedList<TupleMessageEx>> messages = null;
|
private LiveData<PagedList<TupleMessageEx>> messages = null;
|
||||||
|
|
||||||
|
private SelectionTracker<Long> selectionTracker;
|
||||||
|
|
||||||
private int autoCount = 0;
|
private int autoCount = 0;
|
||||||
private boolean autoExpand = true;
|
private boolean autoExpand = true;
|
||||||
private List<Long> expanded = new ArrayList<>();
|
private List<Long> expanded = new ArrayList<>();
|
||||||
|
@ -229,6 +233,22 @@ public class FragmentMessages extends FragmentEx {
|
||||||
});
|
});
|
||||||
rvMessage.setAdapter(adapter);
|
rvMessage.setAdapter(adapter);
|
||||||
|
|
||||||
|
selectionTracker = new SelectionTracker.Builder<>(
|
||||||
|
"messages-selection",
|
||||||
|
rvMessage,
|
||||||
|
new ItemKeyProviderMessage(rvMessage),
|
||||||
|
new ItemDetailsLookupMessage(rvMessage),
|
||||||
|
StorageStrategy.createLongStorage())
|
||||||
|
.withSelectionPredicate(new SelectionPredicateMessage())
|
||||||
|
.build();
|
||||||
|
adapter.setSelectionTracker(selectionTracker);
|
||||||
|
|
||||||
|
selectionTracker.addObserver(new SelectionTracker.SelectionObserver() {
|
||||||
|
@Override
|
||||||
|
public void onSelectionChanged() {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
new ItemTouchHelper(new ItemTouchHelper.Callback() {
|
new ItemTouchHelper(new ItemTouchHelper.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||||
|
@ -515,6 +535,7 @@ public class FragmentMessages extends FragmentEx {
|
||||||
outState.putLongArray("expanded", Helper.toLongArray(expanded));
|
outState.putLongArray("expanded", Helper.toLongArray(expanded));
|
||||||
outState.putLongArray("headers", Helper.toLongArray(headers));
|
outState.putLongArray("headers", Helper.toLongArray(headers));
|
||||||
outState.putLongArray("images", Helper.toLongArray(images));
|
outState.putLongArray("images", Helper.toLongArray(images));
|
||||||
|
selectionTracker.onSaveInstanceState(outState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -527,6 +548,7 @@ public class FragmentMessages extends FragmentEx {
|
||||||
expanded = Helper.fromLongArray(savedInstanceState.getLongArray("expanded"));
|
expanded = Helper.fromLongArray(savedInstanceState.getLongArray("expanded"));
|
||||||
headers = Helper.fromLongArray(savedInstanceState.getLongArray("headers"));
|
headers = Helper.fromLongArray(savedInstanceState.getLongArray("headers"));
|
||||||
images = Helper.fromLongArray(savedInstanceState.getLongArray("images"));
|
images = Helper.fromLongArray(savedInstanceState.getLongArray("images"));
|
||||||
|
selectionTracker.onRestoreInstanceState(savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package eu.faircode.email;
|
||||||
|
|
||||||
|
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 ItemDetailsLookupMessage extends ItemDetailsLookup<Long> {
|
||||||
|
private RecyclerView recyclerView;
|
||||||
|
|
||||||
|
ItemDetailsLookupMessage(RecyclerView recyclerView) {
|
||||||
|
this.recyclerView = recyclerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public ItemDetails<Long> getItemDetails(@NonNull MotionEvent motionEvent) {
|
||||||
|
View view = recyclerView.findChildViewUnder(motionEvent.getX(), motionEvent.getY());
|
||||||
|
if (view != null) {
|
||||||
|
RecyclerView.ViewHolder viewHolder = recyclerView.getChildViewHolder(view);
|
||||||
|
if (viewHolder instanceof AdapterMessage.ViewHolder)
|
||||||
|
return ((AdapterMessage.ViewHolder) viewHolder).getItemDetails(motionEvent);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package eu.faircode.email;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.recyclerview.selection.ItemDetailsLookup;
|
||||||
|
|
||||||
|
public class ItemDetailsMessage extends ItemDetailsLookup.ItemDetails<Long> {
|
||||||
|
private int pos;
|
||||||
|
private Long key;
|
||||||
|
|
||||||
|
ItemDetailsMessage(int pos, Long id) {
|
||||||
|
this.pos = pos;
|
||||||
|
this.key = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPosition() {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Long getSelectionKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package eu.faircode.email;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.paging.PagedList;
|
||||||
|
import androidx.recyclerview.selection.ItemKeyProvider;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
public class ItemKeyProviderMessage extends ItemKeyProvider<Long> {
|
||||||
|
private RecyclerView recyclerView;
|
||||||
|
|
||||||
|
ItemKeyProviderMessage(RecyclerView recyclerView) {
|
||||||
|
super(ItemKeyProvider.SCOPE_CACHED);
|
||||||
|
this.recyclerView = recyclerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Long getKey(int pos) {
|
||||||
|
AdapterMessage adapter = (AdapterMessage) recyclerView.getAdapter();
|
||||||
|
return adapter.getCurrentList().get(pos).id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPosition(@NonNull Long key) {
|
||||||
|
AdapterMessage adapter = (AdapterMessage) recyclerView.getAdapter();
|
||||||
|
PagedList<TupleMessageEx> messages = adapter.getCurrentList();
|
||||||
|
if (messages != null)
|
||||||
|
for (int i = 0; i < messages.size(); i++) {
|
||||||
|
TupleMessageEx message = messages.get(i);
|
||||||
|
if (message != null && message.id.equals(key))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return RecyclerView.NO_POSITION;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package eu.faircode.email;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.selection.SelectionTracker;
|
||||||
|
|
||||||
|
public class SelectionPredicateMessage extends SelectionTracker.SelectionPredicate<Long> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSetStateForKey(@NonNull Long key, boolean nextState) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSetStateAtPosition(int position, boolean nextState) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSelectMultiple() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue