If whole mesage is a known URI with an icon, make button

Stephen Paul Weber created

Change summary

src/main/java/eu/siacs/conversations/entities/Message.java          | 15 
src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java | 28 
2 files changed, 42 insertions(+), 1 deletion(-)

Detailed changes

src/main/java/eu/siacs/conversations/entities/Message.java 🔗

@@ -4,6 +4,7 @@ import android.content.ContentValues;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
 import android.graphics.Color;
+import android.net.Uri;
 import android.os.Build;
 import android.text.Html;
 import android.text.SpannableStringBuilder;
@@ -58,6 +59,7 @@ import eu.siacs.conversations.ui.util.QuoteHelper;
 import eu.siacs.conversations.utils.CryptoHelper;
 import eu.siacs.conversations.utils.Emoticons;
 import eu.siacs.conversations.utils.GeoHelper;
+import eu.siacs.conversations.utils.Patterns;
 import eu.siacs.conversations.utils.MessageUtils;
 import eu.siacs.conversations.utils.MimeUtils;
 import eu.siacs.conversations.utils.StringUtils;
@@ -163,6 +165,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
     private Collection<Reaction> reactions = Collections.emptyList();
 
     private Boolean isGeoUri = null;
+    private Uri wholeIsKnownURI = null;
     private Boolean isEmojisOnly = null;
     private Boolean treatAsDownloadable = null;
     private FileParams fileParams = null;
@@ -631,6 +634,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
     private synchronized void setBodyPreserveXHTML(String body) {
         this.body = body;
         this.isGeoUri = null;
+        this.wholeIsKnownURI = null;
         this.isEmojisOnly = null;
         this.treatAsDownloadable = null;
     }
@@ -651,6 +655,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
     public synchronized void appendBody(String append) {
         this.body += append;
         this.isGeoUri = null;
+        this.wholeIsKnownURI = null;
         this.isEmojisOnly = null;
         this.treatAsDownloadable = null;
     }
@@ -1421,6 +1426,16 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
         return isGeoUri;
     }
 
+    public synchronized Uri wholeIsKnownURI() {
+        if (wholeIsKnownURI != null) return wholeIsKnownURI;
+
+        if (Patterns.BITCOIN_URI.matcher(body).matches() ||Patterns.BITCOINCASH_URI.matcher(body).matches() || Patterns.MONERO_URI.matcher(body).matches()) {
+            wholeIsKnownURI = Uri.parse(body.replace(":", "://")); // hack to make query parser work
+        }
+
+        return wholeIsKnownURI;
+    }
+
     protected List<Element> getSims() {
         return payloads.stream().filter(el ->
             el.getName().equals("reference") && el.getNamespace().equals("urn:xmpp:reference:0") &&

src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java 🔗

@@ -925,9 +925,33 @@ public class MessageAdapter extends ArrayAdapter<Message> {
         viewHolder.download_button.setOnClickListener(v -> openDownloadable(message));
     }
 
+    private void displayURIMessage(
+            ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor, final int type) {
+        displayTextMessage(viewHolder, message, bubbleColor, type);
+        viewHolder.messageBody.setVisibility(View.GONE);
+        viewHolder.image.setVisibility(View.GONE);
+        viewHolder.audioPlayer.setVisibility(View.GONE);
+        viewHolder.download_button.setVisibility(View.VISIBLE);
+        final var uri = message.wholeIsKnownURI();
+        final var amount = uri.getQueryParameter("amount");
+        final var formattedAmount = amount == null || amount.equals("") ? "" : amount + " ";
+        if ("bitcoin".equals(uri.getScheme())) {
+            viewHolder.download_button.setIconResource(R.drawable.bitcoin_24dp);
+            viewHolder.download_button.setText("Send " + formattedAmount + "Bitcoin");
+        } else if ("bitcoincash".equals(uri.getScheme())) {
+            viewHolder.download_button.setIconResource(R.drawable.bitcoin_cash_24dp);
+            viewHolder.download_button.setText("Send " + formattedAmount + "Bitcoin Cash");
+        } else if ("monero".equals(uri.getScheme())) {
+            viewHolder.download_button.setIconResource(R.drawable.monero_24dp);
+            viewHolder.download_button.setText("Send " + formattedAmount + "Monero");
+        }
+        viewHolder.download_button.setOnClickListener(v -> new FixedURLSpan(message.getRawBody()).onClick(v));
+    }
+
     private void displayLocationMessage(
             ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor, final int type) {
         displayTextMessage(viewHolder, message, bubbleColor, type);
+        viewHolder.messageBody.setVisibility(View.GONE);
         viewHolder.image.setVisibility(View.GONE);
         viewHolder.audioPlayer.setVisibility(View.GONE);
         viewHolder.download_button.setVisibility(View.VISIBLE);
@@ -1446,7 +1470,9 @@ public class MessageAdapter extends ArrayAdapter<Message> {
             displayInfoMessage(
                     viewHolder, activity.getString(R.string.omemo_decryption_failed), bubbleColor);
         } else {
-            if (message.isGeoUri()) {
+            if (message.wholeIsKnownURI() != null) {
+                displayURIMessage(viewHolder, message, bubbleColor, type);
+            } else if (message.isGeoUri()) {
                 displayLocationMessage(viewHolder, message, bubbleColor, type);
             } else if (message.treatAsDownloadable()) {
                 try {