From 577c7607cae7a01023b0b48cf1472a8ec5178034 Mon Sep 17 00:00:00 2001 From: M66B Date: Fri, 23 Nov 2018 08:53:18 +0100 Subject: [PATCH] Allow multiple select for same account in unified inbox --- .../eu/faircode/email/AdapterMessage.java | 177 +--------------- .../eu/faircode/email/FragmentMessages.java | 194 +++++++++++++----- .../email/SelectionPredicateMessage.java | 25 ++- app/src/main/res/layout/fragment_messages.xml | 23 +-- 4 files changed, 172 insertions(+), 247 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index e7f02ed1e0..f76131d51a 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -132,7 +132,7 @@ public class AdapterMessage extends PagedListAdapter() { - @Override - protected Void onLoad(Context context, Bundle args) throws Throwable { - long account = args.getLong("account"); - String thread = args.getString("thread"); - boolean found = args.getBoolean("found"); - boolean seen = args.getBoolean("seen"); - - DB db = DB.getInstance(context); - try { - db.beginTransaction(); - - List messages = db.message().getMessageByThread(account, thread, found); - for (EntityMessage message : messages) { - db.message().setMessageUiSeen(message.id, seen); - db.message().setMessageUiIgnored(message.id, true); - EntityOperation.queue(db, message, EntityOperation.SEEN, seen); - } - - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - - EntityOperation.process(context); - - return null; - } - }.load(context, owner, args); - } - - private void onActionMove() { - Bundle args = new Bundle(); - args.putSerializable("message", message); - - new SimpleTask>() { - @Override - protected List onLoad(Context context, Bundle args) { - TupleMessageEx message = (TupleMessageEx) args.getSerializable("message"); - - DB db = DB.getInstance(context); - - List folders = db.folder().getFolders(message.account); - List targets = new ArrayList<>(); - for (EntityFolder f : folders) - if (!f.unified && !EntityFolder.DRAFTS.equals(f.type)) - targets.add(f); - - EntityFolder.sort(targets); - - return targets; - } - - @Override - protected void onLoaded(final Bundle args, List folders) { - PopupMenu popupMenu = new PopupMenu(context, itemView); - - int order = 0; - for (EntityFolder folder : folders) { - String name = (folder.display == null - ? Helper.localizeFolderName(context, 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) { - args.putLong("target", target.getItemId()); - - new SimpleTask() { - @Override - protected Void onLoad(Context context, Bundle args) { - long target = args.getLong("target"); - TupleMessageEx message = (TupleMessageEx) args.getSerializable("message"); - - DB db = DB.getInstance(context); - try { - db.beginTransaction(); - - List messages = db.message().getMessageByThread( - message.account, message.thread, message.ui_found); - for (EntityMessage threaded : messages) { - db.message().setMessageUiHide(threaded.id, true); - EntityOperation.queue(db, threaded, EntityOperation.MOVE, target); - } - - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - - EntityOperation.process(context); - - return null; - } - - @Override - protected void onException(Bundle args, Throwable ex) { - Helper.unexpectedError(context, ex); - } - }.load(context, owner, args); - - return true; - } - }); - - popupMenu.show(); - } - - @Override - protected void onException(Bundle args, Throwable ex) { - Helper.unexpectedError(context, ex); - } - }.load(context, owner, args); - } - }); - - popupMenu.show(); - - return false; - } - private void onAddContact(TupleMessageEx message) { for (Address address : message.from) { InternetAddress ia = (InternetAddress) address; diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index 8d8f08567f..20a3516efa 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -87,8 +87,7 @@ public class FragmentMessages extends FragmentEx { private Group grpHintSelect; private Group grpReady; private FloatingActionButton fab; - private FloatingActionButton fabMove; - private FloatingActionButton fabDelete; + private FloatingActionButton fabMore; private long folder = -1; private long account = -1; @@ -175,8 +174,7 @@ public class FragmentMessages extends FragmentEx { grpHintSelect = view.findViewById(R.id.grpHintSelect); grpReady = view.findViewById(R.id.grpReady); fab = view.findViewById(R.id.fab); - fabMove = view.findViewById(R.id.fabMove); - fabDelete = view.findViewById(R.id.fabDelete); + fabMore = view.findViewById(R.id.fabMore); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); @@ -327,26 +325,27 @@ public class FragmentMessages extends FragmentEx { rvMessage.setAdapter(adapter); - if (viewType == AdapterMessage.ViewType.FOLDER) { + if (viewType != AdapterMessage.ViewType.THREAD) { + final SelectionPredicateMessage predicate = new SelectionPredicateMessage(rvMessage); + selectionTracker = new SelectionTracker.Builder<>( "messages-selection", rvMessage, new ItemKeyProviderMessage(rvMessage), new ItemDetailsLookupMessage(rvMessage), StorageStrategy.createLongStorage()) - .withSelectionPredicate(new SelectionPredicateMessage(rvMessage)) + .withSelectionPredicate(predicate) .build(); adapter.setSelectionTracker(selectionTracker); selectionTracker.addObserver(new SelectionTracker.SelectionObserver() { @Override public void onSelectionChanged() { - if (selectionTracker.hasSelection()) { - fabMove.show(); - fabDelete.show(); - } else { - fabMove.hide(); - fabDelete.hide(); + if (selectionTracker.hasSelection()) + fabMore.show(); + else { + fabMore.hide(); + predicate.clearAccount(); } } }); @@ -548,24 +547,148 @@ public class FragmentMessages extends FragmentEx { } }); - fabMove.setOnClickListener(new View.OnClickListener() { + fabMore.setOnClickListener(new View.OnClickListener() { + private final int action_seen = 1; + private final int action_unseen = 2; + private final int action_move = 3; + private final int action_trash = 4; + @Override public void onClick(View v) { Bundle args = new Bundle(); + args.putLongArray("ids", getSelection()); + + new SimpleTask() { + @Override + protected Integer[] onLoad(Context context, Bundle args) { + long[] ids = args.getLongArray("ids"); + + Integer[] result = new Integer[2]; + result[0] = 0; + result[1] = 0; + + DB db = DB.getInstance(context); + + for (Long id : ids) { + EntityMessage message = db.message().getMessage(id); + result[message.ui_seen ? 1 : 0]++; + } + + return result; + } + + @Override + protected void onLoaded(Bundle args, Integer[] result) { + PopupMenu popupMenu = new PopupMenu(getContext(), fabMore); + + if (result[0] > 0) + popupMenu.getMenu().add(Menu.NONE, action_seen, 1, R.string.title_seen); + if (result[1] > 0) + popupMenu.getMenu().add(Menu.NONE, action_unseen, 2, R.string.title_unseen); + popupMenu.getMenu().add(Menu.NONE, action_move, 3, R.string.title_move); + popupMenu.getMenu().add(Menu.NONE, action_trash, 4, R.string.title_trash); + + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem target) { + switch (target.getItemId()) { + case action_seen: + onActionSeen(true); + return true; + case action_unseen: + onActionSeen(false); + return true; + case action_move: + onActionMove(); + return true; + case action_trash: + onActionDelete(); + return true; + default: + return false; + } + } + }); + + popupMenu.show(); + } + }.load(FragmentMessages.this, args); + } + + private long[] getSelection() { + MutableSelection selection = new MutableSelection<>(); + selectionTracker.copySelection(selection); + + long[] ids = new long[selection.size()]; + int i = 0; + for (Long id : selection) + ids[i++] = id; + + return ids; + } + + private void onActionSeen(boolean seen) { + Bundle args = new Bundle(); + args.putLongArray("ids", getSelection()); + args.putBoolean("seen", seen); + + selectionTracker.clearSelection(); + + new SimpleTask() { + @Override + protected Void onLoad(Context context, Bundle args) { + long[] ids = args.getLongArray("ids"); + boolean seen = args.getBoolean("seen"); + + DB db = DB.getInstance(context); + try { + db.beginTransaction(); + + for (long id : ids) { + EntityMessage message = db.message().getMessage(id); + db.message().setMessageUiSeen(message.id, seen); + db.message().setMessageUiIgnored(message.id, true); + EntityOperation.queue(db, message, EntityOperation.SEEN, seen); + } + + 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); + } + + private void onActionMove() { + Bundle args = new Bundle(); + args.putLongArray("ids", getSelection()); args.putLong("folder", folder); new SimpleTask>() { @Override protected List onLoad(Context context, Bundle args) { - long folder = args.getLong("folder"); + long[] ids = args.getLongArray("ids"); + long fid = args.getLong("folder"); + DB db = DB.getInstance(context); - EntityFolder source = db.folder().getFolder(folder); - List folders = db.folder().getFolders(source.account); + EntityMessage message = db.message().getMessage(ids[0]); + List folders = db.folder().getFolders(message.account); + List targets = new ArrayList<>(); - for (EntityFolder f : folders) - if (!f.id.equals(folder) && !EntityFolder.DRAFTS.equals(f.type)) - targets.add(f); + for (EntityFolder folder : folders) + if (!EntityFolder.DRAFTS.equals(folder.type)) + if (fid < 0 ? !folder.unified : !folder.id.equals(fid)) + targets.add(folder); EntityFolder.sort(targets); @@ -587,19 +710,10 @@ public class FragmentMessages extends FragmentEx { 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; + args.putLong("target", target.getItemId()); selectionTracker.clearSelection(); - args.putLongArray("ids", ids); - args.putLong("target", target.getItemId()); - new SimpleTask() { @Override protected Void onLoad(Context context, Bundle args) { @@ -651,29 +765,18 @@ public class FragmentMessages extends FragmentEx { } }.load(FragmentMessages.this, args); } - }); - fabDelete.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { + private void onActionDelete() { new DialogBuilderLifecycle(getContext(), getViewLifecycleOwner()) .setMessage(R.string.title_ask_delete_selected) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Bundle args = new Bundle(); - MutableSelection selection = new MutableSelection<>(); - selectionTracker.copySelection(selection); - - long[] ids = new long[selection.size()]; - int i = 0; - for (Long id : selection) - ids[i++] = id; + args.putLongArray("ids", getSelection()); selectionTracker.clearSelection(); - args.putLongArray("ids", ids); - new SimpleTask() { @Override protected Void onLoad(Context context, Bundle args) { @@ -724,8 +827,7 @@ public class FragmentMessages extends FragmentEx { pbWait.setVisibility(View.VISIBLE); fab.hide(); - fabMove.hide(); - fabDelete.hide(); + fabMore.hide(); return view; } @@ -850,9 +952,9 @@ public class FragmentMessages extends FragmentEx { }); if (selectionTracker != null && selectionTracker.hasSelection()) - fabMove.show(); + fabMore.show(); else - fabMove.hide(); + fabMore.hide(); if (viewType == AdapterMessage.ViewType.THREAD) db.folder().liveSystemFolders(account).observe(getViewLifecycleOwner(), new Observer>() { diff --git a/app/src/main/java/eu/faircode/email/SelectionPredicateMessage.java b/app/src/main/java/eu/faircode/email/SelectionPredicateMessage.java index bf311758cf..2bcd55f812 100644 --- a/app/src/main/java/eu/faircode/email/SelectionPredicateMessage.java +++ b/app/src/main/java/eu/faircode/email/SelectionPredicateMessage.java @@ -25,13 +25,17 @@ import androidx.recyclerview.selection.SelectionTracker; import androidx.recyclerview.widget.RecyclerView; public class SelectionPredicateMessage extends SelectionTracker.SelectionPredicate { - private RecyclerView recyclerView; + private long account = -1; SelectionPredicateMessage(RecyclerView recyclerView) { this.recyclerView = recyclerView; } + void clearAccount() { + account = -1; + } + @Override public boolean canSetStateForKey(@NonNull Long key, boolean nextState) { AdapterMessage adapter = (AdapterMessage) recyclerView.getAdapter(); @@ -39,8 +43,13 @@ public class SelectionPredicateMessage extends SelectionTracker.SelectionPredica 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); + if (message != null && message.id.equals(key)) { + if (message.uid != null && (account < 0 || account == message.account)) { + account = message.account; + return true; + } else + return false; + } } return false; } @@ -48,7 +57,15 @@ public class SelectionPredicateMessage extends SelectionTracker.SelectionPredica @Override public boolean canSetStateAtPosition(int position, boolean nextState) { AdapterMessage adapter = (AdapterMessage) recyclerView.getAdapter(); - return (adapter.getCurrentList().get(position).uid != null); + PagedList messages = adapter.getCurrentList(); + if (messages != null) { + TupleMessageEx message = messages.get(position); + if (message.uid != null && (account < 0 || account == message.account)) { + account = message.account; + return true; + } + } + return false; } @Override diff --git a/app/src/main/res/layout/fragment_messages.xml b/app/src/main/res/layout/fragment_messages.xml index 5647f7f863..93266ac8be 100644 --- a/app/src/main/res/layout/fragment_messages.xml +++ b/app/src/main/res/layout/fragment_messages.xml @@ -209,34 +209,15 @@ - - - -