From 648e885baf4c9fa2da58d3a35bd7dd4ec753c44d Mon Sep 17 00:00:00 2001 From: M66B Date: Tue, 10 Sep 2019 22:09:16 +0200 Subject: [PATCH] Added attachment reminder --- .../eu/faircode/email/FragmentCompose.java | 90 ++++++++++++++++++- .../faircode/email/FragmentOptionsSend.java | 13 ++- .../main/res/layout/fragment_options_send.xml | 14 ++- app/src/main/res/values/strings.xml | 1 + 4 files changed, 113 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index 448882de6d..d7cb86ae9e 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -50,8 +50,10 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.os.LocaleList; import android.os.Looper; import android.provider.ContactsContract; import android.provider.MediaStore; @@ -203,6 +205,7 @@ public class FragmentCompose extends FragmentBase { private long working = -1; private State state = State.NONE; private boolean show_images = false; + private boolean reminded = false; private boolean autosave = false; private boolean busy = false; @@ -234,6 +237,7 @@ public class FragmentCompose extends FragmentBase { private static final int REQUEST_LINK = 15; private static final int REQUEST_DISCARD = 16; private static final int REQUEST_SEND = 17; + private static final int REQUEST_REMIND = 18; @Override public void onCreate(Bundle savedInstanceState) { @@ -756,6 +760,7 @@ public class FragmentCompose extends FragmentBase { public void onSaveInstanceState(Bundle outState) { outState.putLong("fair:working", working); outState.putBoolean("fair:show_images", show_images); + outState.putBoolean("fair:reminded", reminded); outState.putParcelable("fair:photo", photoURI); super.onSaveInstanceState(outState); } @@ -804,6 +809,7 @@ public class FragmentCompose extends FragmentBase { } else { working = savedInstanceState.getLong("fair:working"); show_images = savedInstanceState.getBoolean("fair:show_images"); + reminded = savedInstanceState.getBoolean("fair:reminded"); photoURI = savedInstanceState.getParcelable("fair:photo"); Bundle args = new Bundle(); @@ -1218,6 +1224,11 @@ public class FragmentCompose extends FragmentBase { onAction(R.id.action_send); } + private void onActionReminded() { + reminded = true; + onAction(R.id.action_send); + } + private void onEncrypt() { if (pgpService.isBound()) try { @@ -1327,6 +1338,10 @@ public class FragmentCompose extends FragmentBase { if (resultCode == RESULT_OK) onActionSendConfirmed(); break; + case REQUEST_REMIND: + if (resultCode == RESULT_OK) + onActionReminded(); + break; } } catch (Throwable ex) { Log.e(ex); @@ -1932,6 +1947,7 @@ public class FragmentCompose extends FragmentBase { args.putBoolean("plain_only", plain_only); args.putBoolean("encrypt", encrypt); args.putBoolean("empty", isEmpty()); + args.putBoolean("reminded", reminded); Log.i("Run execute id=" + working); actionLoader.execute(this, args, "compose:action:" + action); @@ -2663,6 +2679,7 @@ public class FragmentCompose extends FragmentBase { boolean plain_only = args.getBoolean("plain_only"); boolean encrypt = args.getBoolean("encrypt"); boolean empty = args.getBoolean("empty"); + boolean reminded = args.getBoolean("reminded"); EntityMessage draft; @@ -2932,11 +2949,38 @@ public class FragmentCompose extends FragmentBase { if (draft.to == null && draft.cc == null && draft.bcc == null) throw new IllegalArgumentException(context.getString(R.string.title_to_missing)); - // Save attachments + // Check attachments for (EntityAttachment attachment : attachments) if (!attachment.available) throw new IllegalArgumentException(context.getString(R.string.title_attachments_missing)); + boolean check_attachments = prefs.getBoolean("check_attachments", true); + if (check_attachments && !reminded && attachments.size() == 0) { + List keywords = new ArrayList<>(); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + String[] k = context.getString(R.string.title_attachment_keywords).split(","); + keywords.addAll(Arrays.asList(k)); + } else { + Configuration config = context.getResources().getConfiguration(); + LocaleList ll = context.getResources().getConfiguration().getLocales(); + for (int i = 0; i < ll.size(); i++) { + Configuration lconf = new Configuration(config); + lconf.setLocale(ll.get(i)); + Context lcontext = context.createConfigurationContext(lconf); + String[] k = lcontext.getString(R.string.title_attachment_keywords).split(","); + keywords.addAll(Arrays.asList(k)); + } + } + + String plain = HtmlHelper.getText(body); + for (String keyword : keywords) + if (plain.matches("(?si).*\\b" + Pattern.quote(keyword.trim()) + "\\b.*")) { + args.putBoolean("remind", true); + return draft; + } + } + // Delete draft (cannot move to outbox) EntityOperation.queue(context, draft, EntityOperation.DELETE); @@ -3025,8 +3069,14 @@ public class FragmentCompose extends FragmentBase { onEncrypt(); } else if (action == R.id.action_send) { - autosave = false; - finish(); + if (args.getBoolean("remind", false)) { + FragmentDialogRemind remind = new FragmentDialogRemind(); + remind.setTargetFragment(FragmentCompose.this, FragmentCompose.REQUEST_REMIND); + remind.show(getFragmentManager(), "compose:remind"); + } else { + autosave = false; + finish(); + } } } @@ -3688,6 +3738,40 @@ public class FragmentCompose extends FragmentBase { } } + public static class FragmentDialogRemind extends FragmentDialogEx { + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_ask_again, null); + TextView tvMessage = dview.findViewById(R.id.tvMessage); + final CheckBox cbNotAgain = dview.findViewById(R.id.cbNotAgain); + + tvMessage.setText(R.string.title_attachment_reminder); + + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + + return new AlertDialog.Builder(getContext()) + .setView(dview) + .setPositiveButton(R.string.title_yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (cbNotAgain.isChecked()) + prefs.edit().putBoolean("check_attachments", false).apply(); + sendResult(Activity.RESULT_CANCELED); + } + }) + .setNegativeButton(R.string.title_no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (cbNotAgain.isChecked()) + prefs.edit().putBoolean("check_attachments", false).apply(); + sendResult(Activity.RESULT_OK); + } + }) + .create(); + } + } + private class DraftData { private EntityMessage draft; private List identities; diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java b/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java index ff37df5a7c..434546b892 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java @@ -50,10 +50,12 @@ public class FragmentOptionsSend extends FragmentBase implements SharedPreferenc private TextView tvAutoResize; private SwitchCompat swLookupMx; private SwitchCompat swAutoSend; + private SwitchCompat swCheckAttachments; private Spinner spSendDelayed; private final static String[] RESET_OPTIONS = new String[]{ - "keyboard", "suggest_local", "prefix_once", "plain_only", "usenet_signature", "autoresize", "resize", "lookup_mx", "autosend", "send_delayed" + "keyboard", "suggest_local", "prefix_once", "plain_only", "usenet_signature", + "autoresize", "resize", "lookup_mx", "autosend", "check_attachments", "send_delayed" }; @Override @@ -76,6 +78,7 @@ public class FragmentOptionsSend extends FragmentBase implements SharedPreferenc tvAutoResize = view.findViewById(R.id.tvAutoResize); swLookupMx = view.findViewById(R.id.swLookupMx); swAutoSend = view.findViewById(R.id.swAutoSend); + swCheckAttachments = view.findViewById(R.id.swCheckAttachments); spSendDelayed = view.findViewById(R.id.spSendDelayed); setOptions(); @@ -155,6 +158,13 @@ public class FragmentOptionsSend extends FragmentBase implements SharedPreferenc } }); + swCheckAttachments.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("check_attachments", checked).apply(); + } + }); + spSendDelayed.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView adapterView, View view, int position, long id) { @@ -234,6 +244,7 @@ public class FragmentOptionsSend extends FragmentBase implements SharedPreferenc swLookupMx.setChecked(prefs.getBoolean("lookup_mx", false)); swAutoSend.setChecked(!prefs.getBoolean("autosend", false)); + swCheckAttachments.setChecked(prefs.getBoolean("check_attachments", true)); int send_delayed = prefs.getInt("send_delayed", 0); int[] sendDelayedValues = getResources().getIntArray(R.array.sendDelayedValues); diff --git a/app/src/main/res/layout/fragment_options_send.xml b/app/src/main/res/layout/fragment_options_send.xml index 0420d46d78..4c48ca4f56 100644 --- a/app/src/main/res/layout/fragment_options_send.xml +++ b/app/src/main/res/layout/fragment_options_send.xml @@ -153,6 +153,18 @@ app:layout_constraintTop_toBottomOf="@id/tvLookupMxHint" app:switchPadding="12dp" /> + + + app:layout_constraintTop_toBottomOf="@id/swCheckAttachments" /> < %1$d pixels Check recipient email addresses before sending Confirm sending messages + Check for missing attachments Delay sending messages Use metered connections