Allow selecting text and quoting the selection

Stephen Paul Weber created

Change summary

src/cheogram/java/com/cheogram/android/MessageTextActionModeCallback.java | 49 
src/cheogram/res/menu/message_text_actions.xml                            |  9 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java         |  4 
src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java       | 14 
src/main/res/layout/message_content.xml                                   |  1 
src/main/res/menu/message_context.xml                                     |  2 
src/main/res/values/strings.xml                                           |  2 
7 files changed, 78 insertions(+), 3 deletions(-)

Detailed changes

src/cheogram/java/com/cheogram/android/MessageTextActionModeCallback.java 🔗

@@ -0,0 +1,49 @@
+package com.cheogram.android;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.TextView;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.ui.adapter.MessageAdapter;
+
+public class MessageTextActionModeCallback implements ActionMode.Callback {
+	final MessageAdapter adapter;
+	final TextView text;
+
+	public MessageTextActionModeCallback(MessageAdapter adapter, TextView text) {
+		this.adapter = adapter;
+		this.text = text;
+	}
+
+	@Override
+	public boolean onCreateActionMode(final ActionMode mode, final Menu menu) {
+		final MenuInflater inflater = mode.getMenuInflater();
+		inflater.inflate(R.menu.message_text_actions, menu);
+		return true;
+	}
+
+	@Override
+	public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+		return false;
+	}
+
+	@Override
+	public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
+		if (item.getItemId() == R.id.quote) {
+            int start = text.getSelectionStart();
+            int end = text.getSelectionEnd();
+            if (start < 0 || end < 0) return false;
+            adapter.quoteText(text.getText().subSequence(start, end).toString());
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	public void onDestroyActionMode(ActionMode mode) {}
+}

src/cheogram/res/menu/message_text_actions.xml 🔗

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:id="@+id/quote"
+        android:title="@string/quote"
+        android:orderInCategory="1"/>
+
+</menu>

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -1358,6 +1358,7 @@ public class ConversationFragment extends XmppFragment
         messageListAdapter.setOnContactPictureClicked(this);
         messageListAdapter.setOnContactPictureLongClicked(this);
         messageListAdapter.setOnInlineImageLongClicked(this);
+        messageListAdapter.setConversationFragment(this);
         binding.messagesView.setAdapter(messageListAdapter);
 
         registerForContextMenu(binding.messagesView);
@@ -1483,11 +1484,12 @@ public class ConversationFragment extends XmppFragment
         messageListAdapter.setOnContactPictureClicked(null);
         messageListAdapter.setOnContactPictureLongClicked(null);
         messageListAdapter.setOnInlineImageLongClicked(null);
+        messageListAdapter.setConversationFragment(null);
         binding.conversationViewPager.setAdapter(null);
         if (conversation != null) conversation.setupViewPager(null, null, false, null);
     }
 
-    private void quoteText(String text) {
+    public void quoteText(String text) {
         if (binding.textinput.isEnabled()) {
             binding.textinput.insertAsQuote(text);
             binding.textinput.requestFocus();

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

@@ -43,6 +43,7 @@ import androidx.core.content.ContextCompat;
 import androidx.core.content.res.ResourcesCompat;
 
 import com.cheogram.android.BobTransfer;
+import com.cheogram.android.MessageTextActionModeCallback;
 import com.cheogram.android.SwipeDetector;
 import com.cheogram.android.WebxdcPage;
 import com.cheogram.android.WebxdcUpdate;
@@ -117,6 +118,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
     private final AudioPlayer audioPlayer;
     private List<String> highlightedTerm = null;
     private final DisplayMetrics metrics;
+    private ConversationFragment mConversationFragment = null;
     private OnContactPictureClicked mOnContactPictureClickedListener;
     private OnContactPictureClicked mOnMessageBoxClickedListener;
     private OnContactPictureClicked mOnMessageBoxSwipedListener;
@@ -169,6 +171,14 @@ public class MessageAdapter extends ArrayAdapter<Message> {
         this.mOnMessageBoxSwipedListener = listener;
     }
 
+    public void setConversationFragment(ConversationFragment frag) {
+        mConversationFragment = frag;
+    }
+
+    public void quoteText(String text) {
+        if (mConversationFragment != null) mConversationFragment.quoteText(text);
+    }
+
     public Activity getActivity() {
         return activity;
     }
@@ -910,6 +920,10 @@ public class MessageAdapter extends ArrayAdapter<Message> {
             }
         }
 
+        if (viewHolder.messageBody != null) {
+            viewHolder.messageBody.setCustomSelectionActionModeCallback(new MessageTextActionModeCallback(this, viewHolder.messageBody));
+        }
+
         if (viewHolder.thread_identicon != null) {
             viewHolder.thread_identicon.setVisibility(View.GONE);
             final Element thread = message.getThread();

src/main/res/layout/message_content.xml 🔗

@@ -7,6 +7,7 @@
         android:layout_height="wrap_content"
         android:autoLink="web"
         android:longClickable="false"
+        android:textIsSelectable="true"
         android:textAppearance="@style/TextAppearance.Conversations.Body1"/>
 
     <ImageView

src/main/res/values/strings.xml 🔗

@@ -311,7 +311,7 @@
     <string name="check_x_filesize">Check %s size</string>
     <string name="check_x_filesize_on_host">Check %1$s size on %2$s</string>
     <string name="message_options">Message options</string>
-    <string name="quote">Reply</string>
+    <string name="quote">Quote</string>
     <string name="paste_as_quote">Paste as quote</string>
     <string name="copy_original_url">Copy original URL</string>
     <string name="send_again">Send again</string>