diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index 6daafb51..60f6ead3 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -1289,8 +1289,9 @@ public class AdapterMessage extends PagedListAdapter( "messages-selection", rvMessage, new ItemKeyProviderMessage(rvMessage), new ItemDetailsLookupMessage(rvMessage), StorageStrategy.createLongStorage()) - .withSelectionPredicate(new SelectionPredicateMessage()) + .withSelectionPredicate(new SelectionPredicateMessage(rvMessage)) .build(); adapter.setSelectionTracker(selectionTracker); selectionTracker.addObserver(new SelectionTracker.SelectionObserver() { @Override public void onSelectionChanged() { - multiple.setVisibility(selectionTracker.hasSelection() ? View.VISIBLE : View.GONE); + if (selectionTracker.hasSelection()) + fabMove.show(); + else + fabMove.hide(); } }); } @@ -520,14 +531,129 @@ public class FragmentMessages extends FragmentEx { } }); + fabMove.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Bundle args = new Bundle(); + args.putLong("folder", folder); + + new SimpleTask>() { + @Override + protected List onLoad(Context context, Bundle args) { + long folder = args.getLong("folder"); + DB db = DB.getInstance(context); + + EntityFolder source = db.folder().getFolder(folder); + List folders = db.folder().getFolders(source.account); + List targets = new ArrayList<>(); + for (EntityFolder f : folders) + if (!f.id.equals(folder) && !EntityFolder.DRAFTS.equals(f.type)) + targets.add(f); + + final Collator collator = Collator.getInstance(Locale.getDefault()); + collator.setStrength(Collator.SECONDARY); // Case insensitive, process accents etc + + Collections.sort(targets, new Comparator() { + @Override + public int compare(EntityFolder f1, EntityFolder f2) { + int s = Integer.compare( + EntityFolder.FOLDER_SORT_ORDER.indexOf(f1.type), + EntityFolder.FOLDER_SORT_ORDER.indexOf(f2.type)); + if (s != 0) + return s; + return collator.compare( + f1.name == null ? "" : f1.name, + f2.name == null ? "" : f2.name); + } + }); + + return targets; + } + + @Override + protected void onLoaded(final Bundle args, List folders) { + PopupMenu popupMenu = new PopupMenu(getContext(), popupAnchor); + + int order = 0; + for (EntityFolder folder : folders) { + String name = (folder.display == null + ? Helper.localizeFolderName(getContext(), folder.name) + : folder.display); + popupMenu.getMenu().add(Menu.NONE, folder.id.intValue(), order++, name); + } + + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(final MenuItem target) { + MutableSelection selection = new MutableSelection<>(); + selectionTracker.copySelection(selection); + + long[] ids = new long[selection.size()]; + int i = 0; + for (Long id : selection) + ids[i++] = id; + + selectionTracker.clearSelection(); + + args.putLongArray("ids", ids); + args.putLong("target", target.getItemId()); + + new SimpleTask() { + @Override + protected Void onLoad(Context context, Bundle args) { + long[] ids = args.getLongArray("ids"); + long target = args.getLong("target"); + + DB db = DB.getInstance(context); + try { + db.beginTransaction(); + + for (long id : ids) { + db.message().setMessageUiHide(id, true); + + EntityMessage message = db.message().getMessage(id); + EntityOperation.queue(db, message, EntityOperation.MOVE, target); + } + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + EntityOperation.process(context); + + return null; + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Helper.unexpectedError(getContext(), ex); + } + }.load(FragmentMessages.this, args); + + return true; + } + }); + + popupMenu.show(); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Helper.unexpectedError(getContext(), ex); + } + }.load(FragmentMessages.this, args); + } + }); + // Initialize tvNoEmail.setVisibility(View.GONE); - multiple.setVisibility(View.GONE); bottom_navigation.setVisibility(View.GONE); grpReady.setVisibility(View.GONE); pbWait.setVisibility(View.VISIBLE); fab.hide(); + fabMove.hide(); return view; } @@ -644,7 +770,10 @@ public class FragmentMessages extends FragmentEx { } }); - multiple.setVisibility(selectionTracker != null && selectionTracker.hasSelection() ? View.VISIBLE : View.GONE); + if (selectionTracker != null && selectionTracker.hasSelection()) + fabMove.show(); + else + fabMove.hide(); if (viewType == AdapterMessage.ViewType.THREAD) { // Navigation diff --git a/app/src/main/java/eu/faircode/email/SelectionPredicateMessage.java b/app/src/main/java/eu/faircode/email/SelectionPredicateMessage.java index 987feeed..5d351b1c 100644 --- a/app/src/main/java/eu/faircode/email/SelectionPredicateMessage.java +++ b/app/src/main/java/eu/faircode/email/SelectionPredicateMessage.java @@ -1,18 +1,35 @@ package eu.faircode.email; import androidx.annotation.NonNull; +import androidx.paging.PagedList; import androidx.recyclerview.selection.SelectionTracker; +import androidx.recyclerview.widget.RecyclerView; public class SelectionPredicateMessage extends SelectionTracker.SelectionPredicate { + private RecyclerView recyclerView; + + SelectionPredicateMessage(RecyclerView recyclerView) { + this.recyclerView = recyclerView; + } + @Override public boolean canSetStateForKey(@NonNull Long key, boolean nextState) { - return true; + AdapterMessage adapter = (AdapterMessage) recyclerView.getAdapter(); + PagedList 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 (message.uid != null); + } + return false; } @Override public boolean canSetStateAtPosition(int position, boolean nextState) { - return true; + AdapterMessage adapter = (AdapterMessage) recyclerView.getAdapter(); + return (adapter.getCurrentList().get(position).uid != null); } @Override diff --git a/app/src/main/res/layout/fragment_messages.xml b/app/src/main/res/layout/fragment_messages.xml index eae9d135..98d41ebe 100644 --- a/app/src/main/res/layout/fragment_messages.xml +++ b/app/src/main/res/layout/fragment_messages.xml @@ -10,6 +10,13 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + + + - - diff --git a/app/src/main/res/menu/action_multiple.xml b/app/src/main/res/menu/action_multiple.xml deleted file mode 100644 index 902c31c0..00000000 --- a/app/src/main/res/menu/action_multiple.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - -