diff --git a/app/src/main/java/eu/faircode/email/EntityFolder.java b/app/src/main/java/eu/faircode/email/EntityFolder.java index 724fcef37a..f54cafd6c6 100644 --- a/app/src/main/java/eu/faircode/email/EntityFolder.java +++ b/app/src/main/java/eu/faircode/email/EntityFolder.java @@ -198,6 +198,8 @@ public class EntityFolder extends EntityOrder implements Serializable { } static int getIcon(String type) { + if (type == null) + return R.drawable.baseline_list_24; if (EntityFolder.INBOX.equals(type)) return R.drawable.baseline_inbox_24; if (EntityFolder.DRAFTS.equals(type)) diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index 64d8cc55e9..821a1622f5 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -49,6 +49,7 @@ import android.text.TextUtils; import android.text.format.DateUtils; import android.util.LongSparseArray; import android.util.TypedValue; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -1111,14 +1112,17 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. if (message == null) return 0; + if (EntityFolder.OUTBOX.equals(message.folderType)) + return 0; + TupleAccountSwipes swipes = accountSwipes.get(message.account); if (swipes == null) return 0; int flags = 0; - if (swipes.swipe_left != null && !swipes.swipe_left.equals(message.folder)) + if (swipes.swipe_left == null || !swipes.swipe_left.equals(message.folder)) flags |= ItemTouchHelper.LEFT; - if (swipes.swipe_right != null && !swipes.swipe_right.equals(message.folder)) + if (swipes.swipe_right == null || !swipes.swipe_right.equals(message.folder)) flags |= ItemTouchHelper.RIGHT; return makeMovementFlags(0, flags); @@ -1195,74 +1199,147 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. @Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { - TupleMessageEx message = getMessage(viewHolder); + final TupleMessageEx message = getMessage(viewHolder); if (message == null) { - super.clearView(rvMessage, viewHolder); + adapter.notifyItemChanged(viewHolder.getAdapterPosition()); return; } TupleAccountSwipes swipes = accountSwipes.get(message.account); if (swipes == null) { - super.clearView(rvMessage, viewHolder); + adapter.notifyItemChanged(viewHolder.getAdapterPosition()); return; } Log.i("Swiped dir=" + direction + " message=" + message.id); - Bundle args = new Bundle(); - args.putLong("id", message.id); - args.putBoolean("thread", viewType != AdapterMessage.ViewType.THREAD); - args.putLong("target", direction == ItemTouchHelper.LEFT ? swipes.swipe_left : swipes.swipe_right); + if (direction == ItemTouchHelper.LEFT ? swipes.swipe_left == null : swipes.swipe_right == null) { + adapter.notifyItemChanged(viewHolder.getAdapterPosition()); - new SimpleTask>() { - @Override - protected ArrayList onExecute(Context context, Bundle args) { - long id = args.getLong("id"); - boolean thread = args.getBoolean("thread"); - long tid = args.getLong("target"); + PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(getContext(), getViewLifecycleOwner(), viewHolder.itemView); + popupMenu.setGravity(Gravity.RIGHT); - ArrayList result = new ArrayList<>(); + if (message.ui_seen) + popupMenu.getMenu().add(Menu.NONE, R.string.title_unseen, 2, R.string.title_unseen); + else + popupMenu.getMenu().add(Menu.NONE, R.string.title_seen, 1, R.string.title_seen); - // Get target folder and hide message - DB db = DB.getInstance(context); - try { - db.beginTransaction(); + popupMenu.getMenu().add(Menu.NONE, R.string.title_snooze, 3, R.string.title_snooze); + popupMenu.getMenu().add(Menu.NONE, R.string.title_flag_color, 3, R.string.title_flag_color); + popupMenu.getMenu().add(Menu.NONE, R.string.title_move, 3, R.string.title_move); + + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem target) { + switch (target.getItemId()) { + case R.string.title_seen: + onActionSeenSelection(true, message.id); + return true; + case R.string.title_unseen: + onActionSeenSelection(false, message.id); + return true; + case R.string.title_snooze: + onActionSnoozeSelection(message.id); + return true; + case R.string.title_flag_color: + onActionFlagColorSelection(message.color == null ? Color.TRANSPARENT : message.color, message.id); + return true; + case R.string.title_move: + onMenuMove(); + return true; + default: + return false; + } + } - EntityFolder target = db.folder().getFolder(tid); - if (target == null) - throw new IllegalArgumentException(context.getString(R.string.title_no_folder)); + private void onMenuMove() { + Bundle args = new Bundle(); + args.putLong("account", message.account); - EntityAccount account = db.account().getAccount(target.account); - EntityMessage message = db.message().getMessage(id); - if (message != null) { - List messages = db.message().getMessageByThread( - message.account, message.thread, threading && thread ? null : id, message.folder); - for (EntityMessage threaded : messages) { - result.add(new MessageTarget(threaded, account, target)); - db.message().setMessageUiHide(threaded.id, new Date().getTime()); - // Prevent new message notification on undo - db.message().setMessageUiIgnored(threaded.id, true); + new SimpleTask>() { + @Override + protected List onExecute(Context context, Bundle args) { + long account = args.getLong("account"); + + DB db = DB.getInstance(context); + return db.folder().getFoldersEx(account); } - } - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); + @Override + protected void onExecuted(Bundle args, List folders) { + onActionMoveSelectionAccount( + message.account, + folders, + Arrays.asList(new Long[]{message.folder}), + message.id); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex); + } + }.execute(getContext(), getViewLifecycleOwner(), args, "message:move"); } + }); - return result; - } + popupMenu.show(); - @Override - protected void onExecuted(Bundle args, ArrayList result) { - moveUndo(result); - } + } else { + Bundle args = new Bundle(); + args.putLong("id", message.id); + args.putBoolean("thread", viewType != AdapterMessage.ViewType.THREAD); + args.putLong("target", direction == ItemTouchHelper.LEFT ? swipes.swipe_left : swipes.swipe_right); - @Override - protected void onException(Bundle args, Throwable ex) { - Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex); - } - }.execute(FragmentMessages.this, args, "messages:swipe"); + new SimpleTask>() { + @Override + protected ArrayList onExecute(Context context, Bundle args) { + long id = args.getLong("id"); + boolean thread = args.getBoolean("thread"); + long tid = args.getLong("target"); + + ArrayList result = new ArrayList<>(); + + // Get target folder and hide message + DB db = DB.getInstance(context); + try { + db.beginTransaction(); + + EntityFolder target = db.folder().getFolder(tid); + if (target == null) + throw new IllegalArgumentException(context.getString(R.string.title_no_folder)); + + EntityAccount account = db.account().getAccount(target.account); + EntityMessage message = db.message().getMessage(id); + if (message != null) { + List messages = db.message().getMessageByThread( + message.account, message.thread, threading && thread ? null : id, message.folder); + for (EntityMessage threaded : messages) { + result.add(new MessageTarget(threaded, account, target)); + db.message().setMessageUiHide(threaded.id, new Date().getTime()); + // Prevent new message notification on undo + db.message().setMessageUiIgnored(threaded.id, true); + } + } + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + return result; + } + + @Override + protected void onExecuted(Bundle args, ArrayList result) { + moveUndo(result); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex); + } + }.execute(FragmentMessages.this, args, "messages:swipe"); + } } private TupleMessageEx getMessage(RecyclerView.ViewHolder viewHolder) { @@ -1527,22 +1604,22 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. public boolean onMenuItemClick(MenuItem target) { switch (target.getItemId()) { case R.string.title_seen: - onActionSeenSelection(true); + onActionSeenSelection(true, null); return true; case R.string.title_unseen: - onActionSeenSelection(false); + onActionSeenSelection(false, null); return true; case R.string.title_snooze: - onActionSnoozeSelection(); + onActionSnoozeSelection(null); return true; case R.string.title_flag: - onActionFlagSelection(true, null); + onActionFlagSelection(true, null, null); return true; case R.string.title_unflag: - onActionFlagSelection(false, null); + onActionFlagSelection(false, null, null); return true; case R.string.title_flag_color: - onActionFlagColorSelection(); + onActionFlagColorSelection(Color.TRANSPARENT, null); return true; case R.string.title_archive: onActionMoveSelection(EntityFolder.ARCHIVE); @@ -1558,7 +1635,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. return true; case R.string.title_move_to_account: long account = target.getIntent().getLongExtra("account", -1); - onActionMoveSelectionAccount(account, result.targets.get(account), result.folders); + onActionMoveSelectionAccount(account, result.targets.get(account), result.folders, null); return true; default: return false; @@ -1587,9 +1664,9 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. return ids; } - private void onActionSeenSelection(boolean seen) { + private void onActionSeenSelection(boolean seen, Long id) { Bundle args = new Bundle(); - args.putLongArray("ids", getSelection()); + args.putLongArray("ids", id == null ? getSelection() : new long[]{id}); args.putBoolean("seen", seen); selectionTracker.clearSelection(); @@ -1629,7 +1706,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. }.execute(FragmentMessages.this, args, "messages:seen"); } - private void onActionSnoozeSelection() { + private void onActionSnoozeSelection(final Long id) { DialogDuration.show(getContext(), getViewLifecycleOwner(), R.string.title_snooze, new DialogDuration.IDialogDuration() { @Override @@ -1641,7 +1718,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. } Bundle args = new Bundle(); - args.putLongArray("ids", getSelection()); + args.putLongArray("ids", id == null ? getSelection() : new long[]{id}); args.putLong("wakeup", duration == 0 ? -1 : time); selectionTracker.clearSelection(); @@ -1692,9 +1769,9 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. }); } - private void onActionFlagSelection(boolean flagged, Integer color) { + private void onActionFlagSelection(boolean flagged, Integer color, Long id) { Bundle args = new Bundle(); - args.putLongArray("ids", getSelection()); + args.putLongArray("ids", id == null ? getSelection() : new long[]{id}); args.putBoolean("flagged", flagged); if (color != null) args.putInt("color", color); @@ -1737,10 +1814,10 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. }.execute(FragmentMessages.this, args, "messages:flag"); } - private void onActionFlagColorSelection() { + private void onActionFlagColorSelection(int color, final Long id) { int[] colors = getResources().getIntArray(R.array.colorPicker); ColorPickerDialog colorPickerDialog = new ColorPickerDialog(); - colorPickerDialog.initialize(R.string.title_flag_color, colors, Color.TRANSPARENT, 4, colors.length); + colorPickerDialog.initialize(R.string.title_flag_color, colors, color, 4, colors.length); colorPickerDialog.setOnColorSelectedListener(new ColorPickerSwatch.OnColorSelectedListener() { @Override public void onColorSelected(int color) { @@ -1750,7 +1827,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. return; } - onActionFlagSelection(true, color); + onActionFlagSelection(true, color, id); } }); colorPickerDialog.show(getFragmentManager(), "colorpicker"); @@ -1908,7 +1985,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. }.execute(FragmentMessages.this, args, "messages:move"); } - private void onActionMoveSelectionAccount(long account, List folders, List disabled) { + private void onActionMoveSelectionAccount(long account, List folders, List disabled, final Long id) { final View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_folder_select, null); final RecyclerView rvFolder = dview.findViewById(R.id.rvFolder); final ContentLoadingProgressBar pbWait = dview.findViewById(R.id.pbWait); @@ -1927,7 +2004,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. @Override public void onFolderSelected(TupleFolderEx folder) { dialog.dismiss(); - onActionMoveSelection(folder.id); + onActionMoveSelection(folder.id, id); } }); @@ -1941,9 +2018,9 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. dialog.show(); } - private void onActionMoveSelection(long target) { + private void onActionMoveSelection(long target, Long id) { Bundle args = new Bundle(); - args.putLongArray("ids", getSelection()); + args.putLongArray("ids", id == null ? getSelection() : new long[]{id}); args.putLong("target", target); new SimpleTask>() { diff --git a/app/src/main/res/drawable/baseline_list_24.xml b/app/src/main/res/drawable/baseline_list_24.xml new file mode 100644 index 0000000000..555080bae4 --- /dev/null +++ b/app/src/main/res/drawable/baseline_list_24.xml @@ -0,0 +1,10 @@ + + +