diff --git a/app/build.gradle b/app/build.gradle index 56a4a09b7f..3e8915f22e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -241,6 +241,7 @@ dependencies { def work_version = "2.3.3" def exif_version = "1.3.0-alpha01" def biometric_version = "1.0.1" + def textclassifier_version = "1.0.0-alpha03" def billingclient_version = "2.1.0" def javamail_version = "1.6.5" def jsoup_version = "1.12.1" @@ -323,6 +324,10 @@ dependencies { // https://developer.android.com/jetpack/androidx/releases/biometric implementation "androidx.biometric:biometric:$biometric_version" + // https://mvnrepository.com/artifact/androidx.textclassifier/textclassifier + // https://developer.android.com/jetpack/androidx/releases/textclassifier + //implementation "androidx.textclassifier:textclassifier:$textclassifier_version" + // https://developer.android.com/google/play/billing/billing_library_releases_notes implementation "com.android.billingclient:billing:$billingclient_version" diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index 345b68b4d1..777b051111 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -27,6 +27,7 @@ import android.app.Dialog; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; +import android.app.RemoteAction; import android.content.ClipData; import android.content.ClipboardManager; import android.content.ContentResolver; @@ -88,6 +89,9 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.textclassifier.ConversationAction; +import android.view.textclassifier.ConversationActions; +import android.view.textclassifier.TextClassificationManager; import android.webkit.WebView; import android.widget.Button; import android.widget.CheckBox; @@ -95,12 +99,14 @@ import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.PopupMenu; import androidx.constraintlayout.widget.ConstraintLayout; @@ -142,6 +148,8 @@ import java.security.NoSuchAlgorithmException; import java.text.DateFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -167,6 +175,7 @@ import biweekly.property.Organizer; import biweekly.util.ICalDate; import static android.app.Activity.RESULT_OK; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; public class AdapterMessage extends RecyclerView.Adapter { private Fragment parentFragment; @@ -408,6 +417,7 @@ public class AdapterMessage extends RecyclerView.Adapter= Build.VERSION_CODES.Q) + args.putParcelable("actions", getConversationActions(message, document)); + return document.html(); } else { // Cleanup message document = HtmlHelper.sanitize(context, document, show_images, true, true); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) + args.putParcelable("actions", getConversationActions(message, document)); + // Collapse quotes if (!show_quotes) { for (Element quote : document.select("blockquote")) @@ -1912,6 +1931,47 @@ public class AdapterMessage extends RecyclerView.Adapter actions = cactions.getConversationActions(); + for (ConversationAction action : actions) { + String type = action.getType(); + if (ConversationAction.TYPE_OPEN_URL.equals(type) || + ConversationAction.TYPE_SEND_EMAIL.equals(type)) + continue; + + final RemoteAction raction = action.getAction(); + final CharSequence title = (raction == null ? action.getTextReply() : raction.getTitle()); + + Button button = new Button(context, null, android.R.attr.buttonStyleSmall); + button.setId(View.generateViewId()); + button.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + button.setText(title); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + if (raction == null) { + Intent reply = new Intent(context, ActivityCompose.class) + .putExtra("action", "reply") + .putExtra("reference", message.id) + .putExtra("text", title); + context.startActivity(reply); + } else + raction.getActionIntent().send(); + } catch (Throwable ex) { + Log.e(ex); + } + } + }); + llAction.addView(button); + } + if (llAction.getChildCount() > 0) + llAction.setVisibility(View.VISIBLE); + } + } + // Show attachments cowner.start(); @@ -1955,6 +2015,30 @@ public class AdapterMessage extends RecyclerView.Adapter= Build.VERSION_CODES.Q ? View.VISIBLE : View.GONE); swFts.setChecked(prefs.getBoolean("fts", false)); swEnglish.setChecked(prefs.getBoolean("english", false)); swWatchdog.setChecked(prefs.getBoolean("watchdog", true)); diff --git a/app/src/main/res/layout/include_message_body.xml b/app/src/main/res/layout/include_message_body.xml index 64a1e3dd90..00dd495f3a 100644 --- a/app/src/main/res/layout/include_message_body.xml +++ b/app/src/main/res/layout/include_message_body.xml @@ -101,6 +101,15 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tvBody" /> + + Max AES key size: %1$d Allow other apps to search in messages + Show conversation actions Build search index %1$d / %2$d messages indexed (%3$s) Force English language diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 43e1aed222..71e1814850 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -398,6 +398,8 @@