From a24784a12bb4d4ac3a71e13dcd8f30f910d23b4b Mon Sep 17 00:00:00 2001 From: M66B Date: Fri, 13 Aug 2021 09:52:10 +0200 Subject: [PATCH] Added send raw dialog --- .../eu/faircode/email/AdapterMessage.java | 41 ++-- .../email/FragmentDialogForwardRaw.java | 196 ++++++++++++++++++ .../eu/faircode/email/FragmentMessages.java | 108 +--------- .../main/res/layout/dialog_forward_raw.xml | 61 ++++++ app/src/main/res/menu/popup_message_more.xml | 15 +- app/src/main/res/values/strings.xml | 8 +- 6 files changed, 295 insertions(+), 134 deletions(-) create mode 100644 app/src/main/java/eu/faircode/email/FragmentDialogForwardRaw.java create mode 100644 app/src/main/res/layout/dialog_forward_raw.xml diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index e1e7edd3dc..e60dacb89e 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -1401,11 +1401,6 @@ public class AdapterMessage extends RecyclerView.Adapter. + + Copyright 2018-2021 by Marcel Bokhorst (M66B) +*/ + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.core.content.FileProvider; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.Observer; + +import java.io.File; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; + +public class FragmentDialogForwardRaw extends FragmentDialogBase { + private boolean enabled; + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + if (savedInstanceState != null) + enabled = savedInstanceState.getBoolean("fair:enabled"); + + View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_forward_raw, null); + TextView tvRemaining = dview.findViewById(R.id.tvRemaining); + TextView tvOption = dview.findViewById(R.id.tvOption); + + tvRemaining.setText(getString(R.string.title_eml_downloaded, "-")); + + tvOption.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity( + new Intent(getContext(), ActivitySetup.class) + .putExtra("tab", "connection")); + } + }); + + NumberFormat NF = NumberFormat.getNumberInstance(); + + new SimpleTask() { + @Override + protected long[] onExecute(Context context, Bundle args) { + long[] ids = args.getLongArray("ids"); + boolean threads = args.getBoolean("threads"); + + List result = new ArrayList<>(); + + DB db = DB.getInstance(context); + try { + db.beginTransaction(); + + List msgids = new ArrayList<>(); + + for (long id : ids) { + EntityMessage message = db.message().getMessage(id); + if (message == null) + continue; + + List messages = db.message().getMessagesByThread( + message.account, message.thread, threads ? null : id, null); + if (messages == null) + continue; + + for (EntityMessage thread : messages) { + if (msgids.contains(thread.msgid)) + continue; + msgids.add(thread.msgid); + + result.add(thread.id); + + if (thread.raw == null || !thread.raw) + EntityOperation.queue(context, thread, EntityOperation.RAW); + } + } + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + return Helper.toLongArray(result); + } + + @Override + protected void onExecuted(Bundle args, long[] ids) { + DB db = DB.getInstance(getContext()); + LiveData ld = db.message().liveRaw(ids); + ld.observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(Integer remaining) { + if (remaining == null) + return; + + String of = getString(R.string.title_of, + NF.format(ids.length - remaining), + NF.format(ids.length)); + tvRemaining.setText(getString(R.string.title_eml_downloaded, of)); + + if (remaining == 0) { + ld.removeObserver(this); + getArguments().putLongArray("ids", ids); + enabled = true; + setButtonEnabled(enabled); + } + } + }); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Log.unexpectedError(getParentFragmentManager(), ex); + } + }.execute(this, getArguments(), "messages:forward"); + + return new AlertDialog.Builder(getContext()) + .setView(dview) + .setPositiveButton(R.string.title_send, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + send(getArguments().getLongArray("ids")); + } + }) + .setNegativeButton(android.R.string.cancel, null) + .create(); + } + + @Override + public void onStart() { + super.onStart(); + setButtonEnabled(enabled); + } + + void setButtonEnabled(boolean enabled) { + ((AlertDialog) getDialog()) + .getButton(AlertDialog.BUTTON_POSITIVE) + .setEnabled(enabled); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + outState.putBoolean("fair:enabled", enabled); + super.onSaveInstanceState(outState); + } + + private void send(long[] ids) { + try { + ArrayList uris = new ArrayList<>(); + for (long id : ids) { + File file = EntityMessage.getRawFile(getContext(), id); + Uri uri = FileProvider.getUriForFile(getContext(), BuildConfig.APPLICATION_ID, file); + uris.add(uri); + } + + Intent send = new Intent(Intent.ACTION_SEND_MULTIPLE); + send.setPackage(BuildConfig.APPLICATION_ID); + send.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); + send.setType("message/rfc822"); + send.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + startActivity(send); + } catch (Throwable ex) { + // java.lang.IllegalArgumentException: Failed to resolve canonical path for ... + Log.unexpectedError(getParentFragmentManager(), ex); + } + } +} diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index a5e3f1d2da..8bffbe5bee 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -121,7 +121,6 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.PopupMenu; import androidx.constraintlayout.widget.Group; -import androidx.core.content.FileProvider; import androidx.core.graphics.ColorUtils; import androidx.core.view.MenuItemCompat; import androidx.fragment.app.FragmentActivity; @@ -130,7 +129,6 @@ import androidx.fragment.app.FragmentResultListener; import androidx.fragment.app.FragmentTransaction; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleOwner; -import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -379,8 +377,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. private static final int REQUEST_BOUNDARY_RETRY = 22; static final int REQUEST_PICK_CONTACT = 23; static final int REQUEST_BUTTONS = 24; - private static final int REQUEST_ASKED_RAW = 25; - private static final int REQUEST_ALL_READ = 26; + private static final int REQUEST_ALL_READ = 25; static final String ACTION_STORE_RAW = BuildConfig.APPLICATION_ID + ".STORE_RAW"; static final String ACTION_DECRYPT = BuildConfig.APPLICATION_ID + ".DECRYPT"; @@ -3573,106 +3570,15 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. } private void onActionRaw() { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); - boolean raw_asked = prefs.getBoolean("raw_asked", false); - - if (raw_asked) { - _onActionRaw(); - return; - } - - Bundle args = new Bundle(); - args.putString("question", getString(R.string.title_raw_send)); - args.putString("remark", getString(R.string.title_ask_raw)); - args.putString("notagain", "raw_asked"); - - FragmentDialogAsk ask = new FragmentDialogAsk(); - ask.setArguments(args); - ask.setTargetFragment(FragmentMessages.this, REQUEST_ASKED_RAW); - ask.show(getParentFragmentManager(), "messages:raw"); - } - - private void _onActionRaw() { Bundle args = new Bundle(); args.putLongArray("ids", getSelection()); + args.putBoolean("threads", false); selectionTracker.clearSelection(); - new SimpleTask() { - private Toast toast = null; - - @Override - protected Void onExecute(Context context, Bundle args) { - long[] ids = args.getLongArray("ids"); - - DB db = DB.getInstance(context); - for (long id : ids) { - EntityMessage message = db.message().getMessage(id); - if (message == null) - continue; - - if (message.raw == null || !message.raw) - EntityOperation.queue(context, message, EntityOperation.RAW); - } - - return null; - } - - @Override - protected void onExecuted(Bundle args, Void data) { - long[] ids = args.getLongArray("ids"); - - final Context context = getContext(); - - DB db = DB.getInstance(context); - final LiveData ld = db.message().liveRaw(ids); - ld.observe(getViewLifecycleOwner(), new Observer() { - private Integer last = null; - - @Override - public void onChanged(Integer remaining) { - if (remaining == null || remaining == 0) { - ld.removeObserver(this); - - try { - ArrayList uris = new ArrayList<>(); - for (long id : ids) { - File file = EntityMessage.getRawFile(context, id); - Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, file); - uris.add(uri); - } - - Intent send = new Intent(Intent.ACTION_SEND_MULTIPLE); - send.setPackage(BuildConfig.APPLICATION_ID); - send.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); - send.setType("message/rfc822"); - send.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - context.startActivity(send); - } catch (Throwable ex) { - // java.lang.IllegalArgumentException: Failed to resolve canonical path for ... - Log.unexpectedError(getParentFragmentManager(), ex); - } - } else { - if (!Objects.equals(last, remaining)) { - last = remaining; - - String msg = getString(R.string.title_raw_remaining, remaining); - if (toast != null) - toast.cancel(); - toast = ToastEx.makeText(context, msg, Toast.LENGTH_SHORT); - toast.show(); - } - } - } - }); - } - - @Override - protected void onException(Bundle args, Throwable ex) { - Log.unexpectedError(getParentFragmentManager(), ex); - } - }.execute(this, args, "messages:forward"); + FragmentDialogForwardRaw ask = new FragmentDialogForwardRaw(); + ask.setArguments(args); + ask.show(getParentFragmentManager(), "messages:raw"); } private void onActionMoveSelectionAccount(long account, boolean copy, List disabled) { @@ -6566,10 +6472,6 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. case REQUEST_BUTTONS: adapter.notifyDataSetChanged(); break; - case REQUEST_ASKED_RAW: - if (resultCode == RESULT_OK) - _onActionRaw(); - break; case REQUEST_ALL_READ: if (resultCode == RESULT_OK) markAllRead(); diff --git a/app/src/main/res/layout/dialog_forward_raw.xml b/app/src/main/res/layout/dialog_forward_raw.xml new file mode 100644 index 0000000000..7726af5a1b --- /dev/null +++ b/app/src/main/res/layout/dialog_forward_raw.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/popup_message_more.xml b/app/src/main/res/menu/popup_message_more.xml index 26db1f773f..d6b8e5cc9a 100644 --- a/app/src/main/res/menu/popup_message_more.xml +++ b/app/src/main/res/menu/popup_message_more.xml @@ -122,7 +122,18 @@ + android:title="@string/title_raw_send"> + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index be87718021..ca6779fa51 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -981,6 +981,8 @@ Share as HTML Save raw message Send as attachment + Message + Conversation Manage keywords Manage Gmail labels Add keyword @@ -988,8 +990,10 @@ Download all Save all Save raw message file - Raw messages to download: %1$d - To forward messages, the raw (original) messages need to be downloaded from the server. This requires an internet connection. + + To forward messages, the raw (original) messages need to be downloaded from the server. This requires an internet connection. + This can prevented by enabling always downloading raw message files in the connection settings + Raw messages downloaded: %1$s Select buttons The actual actions available depend on the account type and configuration