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