diff --git a/app/src/main/java/eu/faircode/email/EntityMessage.java b/app/src/main/java/eu/faircode/email/EntityMessage.java index 2193f17420..6617e3b81c 100644 --- a/app/src/main/java/eu/faircode/email/EntityMessage.java +++ b/app/src/main/java/eu/faircode/email/EntityMessage.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.text.TextUtils; +import android.util.Pair; import androidx.annotation.NonNull; import androidx.preference.PreferenceManager; @@ -326,6 +327,42 @@ public class EntityMessage implements Serializable { return null; } + static String collapsePrefixes(Context context, String language, String subject, boolean forward) { + List> prefixes = new ArrayList<>(); + for (String re : Helper.getStrings(context, language, R.string.title_subject_reply, "")) + prefixes.add(new Pair<>(re.trim().toLowerCase(), false)); + for (String re : Helper.getStrings(context, language, R.string.title_subject_reply_alt, "")) + prefixes.add(new Pair<>(re.trim().toLowerCase(), false)); + for (String fwd : Helper.getStrings(context, language, R.string.title_subject_forward, "")) + prefixes.add(new Pair<>(fwd.trim().toLowerCase(), true)); + for (String fwd : Helper.getStrings(context, language, R.string.title_subject_forward_alt, "")) + prefixes.add(new Pair<>(fwd.trim().toLowerCase(), true)); + + List scanned = new ArrayList<>(); + subject = subject.trim(); + while (true) { + boolean found = false; + for (Pair prefix : prefixes) + if (subject.toLowerCase().startsWith(prefix.first)) { + found = true; + int count = scanned.size(); + if (!prefix.second.equals(count == 0 ? forward : scanned.get(count - 1))) + scanned.add(prefix.second); + subject = subject.substring(prefix.first.length()).trim(); + break; + } + if (!found) + break; + } + + StringBuilder result = new StringBuilder(); + for (int i = 0; i < scanned.size(); i++) + result.append(context.getString(scanned.get(i) ? R.string.title_subject_forward : R.string.title_subject_reply, "")); + result.append(subject); + + return result.toString(); + } + Element getReplyHeader(Context context, Document document, boolean separate, boolean extended) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); boolean language_detection = prefs.getBoolean("language_detection", false); diff --git a/app/src/main/java/eu/faircode/email/EntityRule.java b/app/src/main/java/eu/faircode/email/EntityRule.java index a03418e55d..c66365b1d4 100644 --- a/app/src/main/java/eu/faircode/email/EntityRule.java +++ b/app/src/main/java/eu/faircode/email/EntityRule.java @@ -550,6 +550,15 @@ public class EntityRule { boolean cc = jargs.optBoolean("cc"); boolean attachments = jargs.optBoolean("attachments"); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + boolean prefix_once = prefs.getBoolean("prefix_once", true); + boolean alt_re = prefs.getBoolean("alt_re", true); + boolean alt_fwd = prefs.getBoolean("alt_fwd", true); + boolean separate_reply = prefs.getBoolean("separate_reply", false); + boolean extended_reply = prefs.getBoolean("extended_reply", false); + boolean quote_reply = prefs.getBoolean("quote_reply", true); + boolean quote = (quote_reply && TextUtils.isEmpty(to)); + EntityIdentity identity = db.identity().getIdentity(iid); if (identity == null) throw new IllegalArgumentException("Rule identity not found name=" + rule.name); @@ -609,9 +618,17 @@ public class EntityRule { reply.cc = message.cc; reply.unsubscribe = "mailto:" + identity.email; reply.auto_submitted = true; + + String subject = (message.subject == null ? "" : message.subject); + if (prefix_once) + EntityMessage.collapsePrefixes(context, message.language, subject, !TextUtils.isEmpty(to)); + reply.subject = context.getString( - TextUtils.isEmpty(to) ? R.string.title_subject_reply : R.string.title_subject_forward, - message.subject == null ? "" : message.subject); + TextUtils.isEmpty(to) + ? (alt_re ? R.string.title_subject_reply_alt : R.string.title_subject_reply) + : (alt_fwd ? R.string.title_subject_forward_alt : R.string.title_subject_forward), + subject); + reply.received = new Date().getTime(); reply.sender = MessageHelper.getSortKey(reply.from); @@ -620,12 +637,6 @@ public class EntityRule { reply.id = db.message().insertMessage(reply); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean separate_reply = prefs.getBoolean("separate_reply", false); - boolean extended_reply = prefs.getBoolean("extended_reply", false); - boolean quote_reply = prefs.getBoolean("quote_reply", true); - boolean quote = (quote_reply && TextUtils.isEmpty(to)); - String body = answer.getText(message.from); Document msg = JsoupEx.parse(body); diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index da3b8da0de..49cc653847 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -264,6 +264,8 @@ public class FragmentCompose extends FragmentBase { private AdapterAttachment adapter; private boolean prefix_once = false; + private boolean alt_re = false; + private boolean alt_fwd = false; private boolean monospaced = false; private String compose_font; private Integer encrypt = null; @@ -320,6 +322,8 @@ public class FragmentCompose extends FragmentBase { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); prefix_once = prefs.getBoolean("prefix_once", true); + alt_re = prefs.getBoolean("alt_re", true); + alt_fwd = prefs.getBoolean("alt_fwd", true); monospaced = prefs.getBoolean("monospaced", false); compose_font = prefs.getString("compose_font", monospaced ? "monospace" : "sans-serif"); media = prefs.getBoolean("compose_media", true); @@ -4110,8 +4114,11 @@ public class FragmentCompose extends FragmentBase { String subject = (ref.subject == null ? "" : ref.subject); if ("reply".equals(action) || "reply_all".equals(action)) { if (prefix_once) - subject = collapsePrefixes(context, ref.language, subject, false); - data.draft.subject = Helper.getString(context, ref.language, R.string.title_subject_reply, subject); + subject = EntityMessage.collapsePrefixes(context, ref.language, subject, false); + data.draft.subject = Helper.getString(context, + ref.language, + alt_re ? R.string.title_subject_reply_alt : R.string.title_subject_reply, + subject); String t = args.getString("text"); if (t != null) { @@ -4126,8 +4133,11 @@ public class FragmentCompose extends FragmentBase { } } else if ("forward".equals(action)) { if (prefix_once) - subject = collapsePrefixes(context, ref.language, subject, true); - data.draft.subject = Helper.getString(context, ref.language, R.string.title_subject_forward, subject); + subject = EntityMessage.collapsePrefixes(context, ref.language, subject, true); + data.draft.subject = Helper.getString(context, + ref.language, + alt_fwd ? R.string.title_subject_forward_alt : R.string.title_subject_forward, + subject); } else if ("editasnew".equals(action)) { if (ref.from != null && ref.from.length == 1) { String from = ((InternetAddress) ref.from[0]).getAddress(); @@ -5611,42 +5621,6 @@ public class FragmentCompose extends FragmentBase { getActivity().invalidateOptionsMenu(); } - private static String collapsePrefixes(Context context, String language, String subject, boolean forward) { - List> prefixes = new ArrayList<>(); - for (String re : Helper.getStrings(context, language, R.string.title_subject_reply, "")) - prefixes.add(new Pair<>(re.trim().toLowerCase(), false)); - for (String re : Helper.getStrings(context, language, R.string.title_subject_reply_alt, "")) - prefixes.add(new Pair<>(re.trim().toLowerCase(), false)); - for (String fwd : Helper.getStrings(context, language, R.string.title_subject_forward, "")) - prefixes.add(new Pair<>(fwd.trim().toLowerCase(), true)); - for (String fwd : Helper.getStrings(context, language, R.string.title_subject_forward_alt, "")) - prefixes.add(new Pair<>(fwd.trim().toLowerCase(), true)); - - List scanned = new ArrayList<>(); - subject = subject.trim(); - while (true) { - boolean found = false; - for (Pair prefix : prefixes) - if (subject.toLowerCase().startsWith(prefix.first)) { - found = true; - int count = scanned.size(); - if (!prefix.second.equals(count == 0 ? forward : scanned.get(count - 1))) - scanned.add(prefix.second); - subject = subject.substring(prefix.first.length()).trim(); - break; - } - if (!found) - break; - } - - StringBuilder result = new StringBuilder(); - for (int i = 0; i < scanned.size(); i++) - result.append(context.getString(scanned.get(i) ? R.string.title_subject_forward : R.string.title_subject_reply, "")); - result.append(subject); - - return result.toString(); - } - private static void addSignature(Context context, Document document, EntityMessage message, EntityIdentity identity) { if (!message.signature || identity == null || TextUtils.isEmpty(identity.signature)) diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java b/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java index eff241a759..f16a79adf7 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java @@ -35,6 +35,8 @@ import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CompoundButton; +import android.widget.RadioButton; +import android.widget.RadioGroup; import android.widget.Spinner; import androidx.annotation.NonNull; @@ -47,6 +49,7 @@ import androidx.preference.PreferenceManager; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class FragmentOptionsSend extends FragmentBase implements SharedPreferences.OnSharedPreferenceChangeListener { private SwitchCompat swKeyboard; @@ -56,6 +59,8 @@ public class FragmentOptionsSend extends FragmentBase implements SharedPreferenc private SwitchCompat swSuggestReceived; private SwitchCompat swSuggestFrequently; private Button btnLocalContacts; + private RadioGroup rgRe; + private RadioGroup rgFwd; private SwitchCompat swSendReminders; private Spinner spSendDelayed; private SwitchCompat swSendPending; @@ -87,6 +92,7 @@ public class FragmentOptionsSend extends FragmentBase implements SharedPreferenc private final static String[] RESET_OPTIONS = new String[]{ "keyboard", "keyboard_no_fullscreen", "suggest_names", "suggest_sent", "suggested_received", "suggest_frequently", + "alt_re", "alt_fwd", "send_reminders", "send_delayed", "send_pending", "compose_font", "prefix_once", "separate_reply", "extended_reply", "write_below", "quote_reply", "quote_limit", "resize_reply", "signature_location", "signature_reply", "signature_forward", @@ -112,6 +118,8 @@ public class FragmentOptionsSend extends FragmentBase implements SharedPreferenc swSuggestReceived = view.findViewById(R.id.swSuggestReceived); swSuggestFrequently = view.findViewById(R.id.swSuggestFrequently); btnLocalContacts = view.findViewById(R.id.btnLocalContacts); + rgRe = view.findViewById(R.id.rgRe); + rgFwd = view.findViewById(R.id.rgFwd); swSendReminders = view.findViewById(R.id.swSendReminders); spSendDelayed = view.findViewById(R.id.spSendDelayed); swSendPending = view.findViewById(R.id.swSendPending); @@ -212,6 +220,20 @@ public class FragmentOptionsSend extends FragmentBase implements SharedPreferenc } }); + rgRe.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + prefs.edit().putBoolean("alt_re", checkedId == R.id.rbRe2).apply(); + } + }); + + rgFwd.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + prefs.edit().putBoolean("alt_fwd", checkedId == R.id.rbFwd2).apply(); + } + }); + swSendReminders.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { @@ -429,6 +451,18 @@ public class FragmentOptionsSend extends FragmentBase implements SharedPreferenc : R.color.lightColorBackground_cards)); } + String re1 = getString(R.string.title_subject_reply, ""); + String re2 = getString(R.string.title_subject_reply_alt, ""); + ((RadioButton) view.findViewById(R.id.rbRe1)).setText(re1); + ((RadioButton) view.findViewById(R.id.rbRe2)).setText(re2); + rgRe.setVisibility(Objects.equals(re1, re2) ? View.GONE : View.VISIBLE); + + String fwd1 = getString(R.string.title_subject_forward, ""); + String fwd2 = getString(R.string.title_subject_forward_alt, ""); + ((RadioButton) view.findViewById(R.id.rbFwd1)).setText(fwd1); + ((RadioButton) view.findViewById(R.id.rbFwd2)).setText(fwd2); + rgFwd.setVisibility(Objects.equals(fwd1, fwd2) ? View.GONE : View.VISIBLE); + PreferenceManager.getDefaultSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this); return view; @@ -471,6 +505,10 @@ public class FragmentOptionsSend extends FragmentBase implements SharedPreferenc swSuggestReceived.setChecked(prefs.getBoolean("suggest_received", false)); swSuggestFrequently.setChecked(prefs.getBoolean("suggest_frequently", false)); swSuggestFrequently.setEnabled(swSuggestSent.isChecked() || swSuggestReceived.isChecked()); + + rgRe.check(prefs.getBoolean("alt_re", false) ? R.id.rbRe2 : R.id.rbRe1); + rgFwd.check(prefs.getBoolean("alt_fwd", false) ? R.id.rbFwd2 : R.id.rbFwd1); + swSendReminders.setChecked(prefs.getBoolean("send_reminders", true)); int send_delayed = prefs.getInt("send_delayed", 0); diff --git a/app/src/main/java/eu/faircode/email/ServiceUI.java b/app/src/main/java/eu/faircode/email/ServiceUI.java index 15848775b7..7fd222221e 100644 --- a/app/src/main/java/eu/faircode/email/ServiceUI.java +++ b/app/src/main/java/eu/faircode/email/ServiceUI.java @@ -292,10 +292,8 @@ public class ServiceUI extends IntentService { throw new IllegalArgumentException("outbox not found"); String subject = (ref.subject == null ? "" : ref.subject); - if (prefix_once) { - String re = getString(R.string.title_subject_reply, ""); - subject = subject.replaceAll("(?i)" + Pattern.quote(re.trim()), "").trim(); - } + if (prefix_once) + subject = EntityMessage.collapsePrefixes(this, ref.language, subject, false); Bundle results = RemoteInput.getResultsFromIntent(intent); String body = results.getString("text"); diff --git a/app/src/main/res/layout/fragment_options_send.xml b/app/src/main/res/layout/fragment_options_send.xml index fbd1eed5d3..067ed6927a 100644 --- a/app/src/main/res/layout/fragment_options_send.xml +++ b/app/src/main/res/layout/fragment_options_send.xml @@ -181,6 +181,64 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/swSuggestFrequently" /> + + + + + + + + + + + + + +