diff --git a/app/src/main/java/eu/faircode/email/AdapterFolderSelect.java b/app/src/main/java/eu/faircode/email/AdapterFolderSelect.java
new file mode 100644
index 0000000000..7b694467d6
--- /dev/null
+++ b/app/src/main/java/eu/faircode/email/AdapterFolderSelect.java
@@ -0,0 +1,184 @@
+package eu.faircode.email;
+
+/*
+ This file is part of FairEmail.
+
+ FairEmail is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ FairEmail is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with FairEmail. If not, see .
+
+ Copyright 2018-2019 by Marcel Bokhorst (M66B)
+*/
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.ListUpdateCallback;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AdapterFolderSelect extends RecyclerView.Adapter {
+ private Context context;
+ private LifecycleOwner owner;
+ private IFolderSelectedListener listener;
+ private LayoutInflater inflater;
+
+ private List items = new ArrayList<>();
+
+ public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
+ private View view;
+ private ImageView ivType;
+ private TextView tvName;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+
+ view = itemView.findViewById(R.id.clItem);
+ ivType = itemView.findViewById(R.id.ivType);
+ tvName = itemView.findViewById(R.id.tvName);
+ }
+
+ private void wire() {
+ view.setOnClickListener(this);
+ }
+
+ private void unwire() {
+ view.setOnClickListener(null);
+ }
+
+ private void bindTo(EntityFolder folder) {
+ ivType.setImageResource(EntityFolder.getIcon(folder.type));
+ tvName.setText(folder.getDisplayName(context));
+ }
+
+ @Override
+ public void onClick(View v) {
+ int pos = getAdapterPosition();
+ if (pos == RecyclerView.NO_POSITION)
+ return;
+
+ EntityFolder folder = items.get(pos);
+ if (folder != null)
+ listener.onFolderSelected(folder);
+ }
+ }
+
+ AdapterFolderSelect(Context context, LifecycleOwner owner, IFolderSelectedListener listener) {
+ this.context = context;
+ this.owner = owner;
+ this.listener = listener;
+ this.inflater = LayoutInflater.from(context);
+ setHasStableIds(true);
+ }
+
+ public void set(@NonNull List folders) {
+ Log.i("Set folders=" + folders.size());
+
+ DiffUtil.DiffResult diff = DiffUtil.calculateDiff(new DiffCallback(items, folders), false);
+
+ items = folders;
+
+ diff.dispatchUpdatesTo(new ListUpdateCallback() {
+ @Override
+ public void onInserted(int position, int count) {
+ Log.i("Inserted @" + position + " #" + count);
+ }
+
+ @Override
+ public void onRemoved(int position, int count) {
+ Log.i("Removed @" + position + " #" + count);
+ }
+
+ @Override
+ public void onMoved(int fromPosition, int toPosition) {
+ Log.i("Moved " + fromPosition + ">" + toPosition);
+ }
+
+ @Override
+ public void onChanged(int position, int count, Object payload) {
+ Log.i("Changed @" + position + " #" + count);
+ }
+ });
+ diff.dispatchUpdatesTo(this);
+ }
+
+ private class DiffCallback extends DiffUtil.Callback {
+ private List prev = new ArrayList<>();
+ private List next = new ArrayList<>();
+
+ DiffCallback(List prev, List next) {
+ this.prev.addAll(prev);
+ this.next.addAll(next);
+ }
+
+ @Override
+ public int getOldListSize() {
+ return prev.size();
+ }
+
+ @Override
+ public int getNewListSize() {
+ return next.size();
+ }
+
+ @Override
+ public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
+ EntityFolder m1 = prev.get(oldItemPosition);
+ EntityFolder m2 = next.get(newItemPosition);
+ return m1.id.equals(m2.id);
+ }
+
+ @Override
+ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
+ EntityFolder m1 = prev.get(oldItemPosition);
+ EntityFolder m2 = next.get(newItemPosition);
+ return m1.id.equals(m2.id);
+ }
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return items.get(position).id;
+ }
+
+ @Override
+ public int getItemCount() {
+ return items.size();
+ }
+
+ @Override
+ @NonNull
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new ViewHolder(inflater.inflate(R.layout.item_folder_select, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ holder.unwire();
+ EntityFolder folder = items.get(position);
+ holder.bindTo(folder);
+ holder.wire();
+ }
+
+ interface IFolderSelectedListener {
+ void onFolderSelected(EntityFolder folder);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java
index 98050da2a6..63acbbfa3a 100644
--- a/app/src/main/java/eu/faircode/email/AdapterMessage.java
+++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java
@@ -2455,6 +2455,66 @@ public class AdapterMessage extends RecyclerView.Adapter() {
+ @Override
+ protected Void onExecute(Context context, Bundle args) {
+ long id = args.getLong("id");
+ long target = args.getLong("target");
+
+ DB db = DB.getInstance(context);
+ try {
+ db.beginTransaction();
+
+ EntityMessage message = db.message().getMessage(id);
+ if (message == null)
+ return null;
+
+ EntityOperation.queue(context, message, EntityOperation.COPY, target);
+
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onException(Bundle args, Throwable ex) {
+ Helper.unexpectedError(context, owner, ex);
+ }
+ }.execute(context, owner, args, "message:copy");
+ }
+ });
+
+ rvFolder.setAdapter(adapter);
+
+ rvFolder.setVisibility(View.GONE);
+ pbWait.setVisibility(View.VISIBLE);
+ dialog.show();
+
Bundle args = new Bundle();
args.putLong("id", data.message.id);
@@ -2471,10 +2531,15 @@ public class AdapterMessage extends RecyclerView.Adapter 0)
- Collections.sort(folders, folders.get(0).getComparator(context));
+ List targets = new ArrayList<>();
+ for (EntityFolder folder : folders)
+ if (!folder.isHidden(context) && !folder.id.equals(message.folder))
+ targets.add(folder);
- return folders;
+ if (targets.size() > 0)
+ Collections.sort(targets, targets.get(0).getComparator(context));
+
+ return targets;
}
@Override
@@ -2482,53 +2547,9 @@ public class AdapterMessage extends RecyclerView.Adapter() {
- @Override
- protected Void onExecute(Context context, Bundle args) {
- long id = args.getLong("id");
- long target = args.getLong("target");
-
- DB db = DB.getInstance(context);
- try {
- db.beginTransaction();
-
- EntityMessage message = db.message().getMessage(id);
- if (message == null)
- return null;
-
- EntityOperation.queue(context, message, EntityOperation.COPY, target);
-
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
-
- return null;
- }
-
- @Override
- protected void onException(Bundle args, Throwable ex) {
- Helper.unexpectedError(context, owner, ex);
- }
- }.execute(context, owner, args, "message:copy");
-
- return true;
- }
- });
-
- popupMenu.show();
+ adapter.set(folders);
+ pbWait.setVisibility(View.GONE);
+ rvFolder.setVisibility(View.VISIBLE);
}
@Override
@@ -3115,7 +3136,33 @@ public class AdapterMessage extends RecyclerView.Adapter() {
- @Override
- protected String onExecute(Context context, Bundle args) {
- long target = args.getLong("target");
- return DB.getInstance(context).folder().getFolder(target).name;
- }
-
- @Override
- protected void onExecuted(Bundle args, String folderName) {
- long id = args.getLong("id");
- properties.move(id, folderName, false);
- }
-
- @Override
- protected void onException(Bundle args, Throwable ex) {
- Helper.unexpectedError(context, owner, ex);
- }
- }.execute(context, owner, args, "message:move");
-
- return true;
- }
- });
-
- popupMenu.show();
+ adapter.set(folders);
+ pbWait.setVisibility(View.GONE);
+ rvFolder.setVisibility(View.VISIBLE);
}
@Override
diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java
index a091a5547b..7373488062 100644
--- a/app/src/main/java/eu/faircode/email/FragmentMessages.java
+++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java
@@ -20,6 +20,7 @@ package eu.faircode.email;
*/
import android.app.Activity;
+import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -1396,7 +1397,7 @@ public class FragmentMessages extends FragmentBase {
if (targets.size() > 0)
Collections.sort(targets, targets.get(0).getComparator(context));
- result.targets.put(account, targets);
+ result.targets.put(account.id, targets);
}
return result;
@@ -1423,25 +1424,22 @@ public class FragmentMessages extends FragmentBase {
if (result.hasArchive && !result.isArchive) // has archive and not is archive/drafts
popupMenu.getMenu().add(Menu.NONE, R.string.title_archive, 7, R.string.title_archive);
+ int order = 8;
+ for (EntityAccount account : result.accounts) {
+ MenuItem item = popupMenu.getMenu()
+ .add(Menu.NONE, R.string.title_move_to_account, order++,
+ getString(R.string.title_move_to_account, account.name));
+ item.setIntent(new Intent().putExtra("account", account.id));
+ }
+
if (result.isTrash) // is trash
- popupMenu.getMenu().add(Menu.NONE, R.string.title_delete, 8, R.string.title_delete);
+ popupMenu.getMenu().add(Menu.NONE, R.string.title_delete, order++, R.string.title_delete);
if (!result.isTrash && result.hasTrash) // not trash and has trash
- popupMenu.getMenu().add(Menu.NONE, R.string.title_trash, 9, R.string.title_trash);
+ popupMenu.getMenu().add(Menu.NONE, R.string.title_trash, order++, R.string.title_trash);
if (result.hasJunk && !result.isJunk && !result.isDrafts) // has junk and not junk/drafts
- popupMenu.getMenu().add(Menu.NONE, R.string.title_spam, 10, R.string.title_spam);
-
- int order = 11;
- for (EntityAccount account : result.accounts) {
- SubMenu smenu = popupMenu.getMenu()
- .addSubMenu(Menu.NONE, 0, order++, getString(R.string.title_move_to, account.name));
- int sorder = 1;
- for (EntityFolder target : result.targets.get(account)) {
- MenuItem item = smenu.add(Menu.NONE, R.string.title_move_to, sorder++, target.getDisplayName(getContext()));
- item.setIntent(new Intent().putExtra("target", target.id));
- }
- }
+ popupMenu.getMenu().add(Menu.NONE, R.string.title_spam, order++, R.string.title_spam);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
@@ -1477,8 +1475,9 @@ public class FragmentMessages extends FragmentBase {
case R.string.title_spam:
onActionJunkSelection();
return true;
- case R.string.title_move_to:
- onActionMoveSelection(target.getIntent().getLongExtra("target", -1));
+ case R.string.title_move_to_account:
+ long account = target.getIntent().getLongExtra("account", -1);
+ onActionMoveSelectionAccount(result.targets.get(account));
return true;
default:
return false;
@@ -1829,6 +1828,37 @@ public class FragmentMessages extends FragmentBase {
}.execute(FragmentMessages.this, args, "messages:move");
}
+ private void onActionMoveSelectionAccount(List folders) {
+ 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);
+
+ final Dialog dialog = new DialogBuilderLifecycle(getContext(), getViewLifecycleOwner())
+ .setTitle(R.string.title_move_to_folder)
+ .setView(dview)
+ .create();
+
+ rvFolder.setHasFixedSize(false);
+ LinearLayoutManager llm = new LinearLayoutManager(getContext());
+ rvFolder.setLayoutManager(llm);
+
+ final AdapterFolderSelect adapter = new AdapterFolderSelect(getContext(), getViewLifecycleOwner(),
+ new AdapterFolderSelect.IFolderSelectedListener() {
+ @Override
+ public void onFolderSelected(EntityFolder folder) {
+ dialog.dismiss();
+ onActionMoveSelection(folder.id);
+ }
+ });
+ adapter.set(folders);
+
+ rvFolder.setAdapter(adapter);
+
+ rvFolder.setVisibility(View.VISIBLE);
+ pbWait.setVisibility(View.GONE);
+ dialog.show();
+ }
+
private void onActionMoveSelection(long target) {
Bundle args = new Bundle();
args.putLongArray("ids", getSelection());
@@ -3273,7 +3303,7 @@ public class FragmentMessages extends FragmentBase {
Boolean isJunk;
Boolean isDrafts;
List accounts;
- Map> targets = new HashMap<>();
+ Map> targets = new HashMap<>();
}
private static class MessageTarget implements Parcelable {
diff --git a/app/src/main/res/layout/dialog_folder_select.xml b/app/src/main/res/layout/dialog_folder_select.xml
new file mode 100644
index 0000000000..9d82415598
--- /dev/null
+++ b/app/src/main/res/layout/dialog_folder_select.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_folder_select.xml b/app/src/main/res/layout/item_folder_select.xml
new file mode 100644
index 0000000000..2adabe76b5
--- /dev/null
+++ b/app/src/main/res/layout/item_folder_select.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a777a31419..faa1af218a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -404,12 +404,14 @@
Trash
Copy …
+ Copy to …
Subscribe
Delete
More
Spam
Move
- Move to %1$s
+ Move to …
+ Move to %1$s …
Snooze …
Archive
Reply