UI for rich replies

Stephen Paul Weber created

Change summary

src/cheogram/res/values/themes.xml                                  |  2 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java   | 19 
src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java |  2 
src/main/res/layout/fragment_conversation.xml                       | 40 
4 files changed, 60 insertions(+), 3 deletions(-)

Detailed changes

src/cheogram/res/values/themes.xml ๐Ÿ”—

@@ -108,7 +108,7 @@
         <item name="icon_save" type="reference">@drawable/ic_save_black_24dp</item>
         <item name="icon_group" type="reference">@drawable/ic_group_white_24dp</item>
         <item name="icon_new" type="reference">@drawable/ic_add_white_24dp</item>
-        <item name="icon_quote" type="reference">@drawable/ic_reply_white_24dp</item>
+        <item name="icon_quote" type="reference">@drawable/ic_reply_black</item>
         <item name="icon_refresh" type="reference">@drawable/ic_refresh_black_24dp</item>
         <item name="icon_new_attachment" type="reference">@drawable/ic_attach_file_white_24dp</item>
         <item name="icon_not_secure" type="reference">@drawable/ic_lock_open_white_24dp</item>

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java ๐Ÿ”—

@@ -30,6 +30,7 @@ import android.os.SystemClock;
 import android.preference.PreferenceManager;
 import android.provider.MediaStore;
 import android.text.Editable;
+import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.ContextMenu;
@@ -916,6 +917,7 @@ public class ConversationFragment extends XmppFragment
             default:
                 sendMessage(message);
         }
+        setupReply(null);
     }
 
     private boolean trustKeysIfNeeded(final Conversation conversation, final int requestCode) {
@@ -1124,6 +1126,7 @@ public class ConversationFragment extends XmppFragment
         } else {
             activity.selectPresence(conversation, callback);
         }
+        setupReply(null);
     }
 
     private static boolean anyNeedsExternalStoragePermission(
@@ -1275,6 +1278,7 @@ public class ConversationFragment extends XmppFragment
         binding.textinput.setRichContentListener(new String[] {"image/*"}, mEditorContentListener);
 
         binding.textSendButton.setOnClickListener(this.mSendButtonListener);
+        binding.contextPreviewCancel.setOnClickListener((v) -> setupReply(null));
 
         binding.scrollToBottomButton.setOnClickListener(this.mScrollButtonListener);
         binding.messagesView.setOnScrollListener(mOnScrollListener);
@@ -1364,7 +1368,21 @@ public class ConversationFragment extends XmppFragment
     private void quoteMessage(Message message) {
         setThread(message.getThread());
         conversation.setUserSelectedThread(true);
+        if (message.getThread() == null) newThread();
+        setupReply(message);
+    }
+
+    private void setupReply(Message message) {
         conversation.setReplyTo(message);
+        if (message == null) {
+            binding.contextPreview.setVisibility(View.GONE);
+            return;
+        }
+
+        SpannableStringBuilder body = message.getSpannableBody(null, null);
+        messageListAdapter.handleTextQuotes(body, activity.isDarkTheme());
+        binding.contextPreviewText.setText(body);
+        binding.contextPreview.setVisibility(View.VISIBLE);
     }
 
     private void setThread(Element thread) {
@@ -2727,6 +2745,7 @@ public class ConversationFragment extends XmppFragment
         }
 
         setThread(conversation.getThread());
+        setupReply(conversation.getReplyTo());
 
         stopScrolling();
         Log.d(Config.LOGTAG, "reInit(hasExtras=" + hasExtras + ")");

src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java ๐Ÿ”—

@@ -415,7 +415,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
      * Applies QuoteSpan to group of lines which starts with > or ยป characters.
      * Appends likebreaks and applies DividerSpan to them to show a padding between quote and text.
      */
-    private boolean handleTextQuotes(SpannableStringBuilder body, boolean darkBackground) {
+    public boolean handleTextQuotes(SpannableStringBuilder body, boolean darkBackground) {
         boolean startsWithQuote = false;
         int quoteDepth = 1;
         while (QuoteHelper.bodyContainsQuoteStart(body) && quoteDepth <= Config.QUOTE_MAX_DEPTH) {

src/main/res/layout/fragment_conversation.xml ๐Ÿ”—

@@ -48,6 +48,44 @@
                     android:transcriptMode="normal"
                     tools:listitem="@layout/message_sent"></ListView>
 
+                <LinearLayout
+                    android:id="@+id/context_preview"
+                    android:visibility="gone"
+                    android:layout_alignParentStart="true"
+                    android:layout_alignParentLeft="true"
+                    android:layout_above="@+id/textsend"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:paddingTop="8dp"
+                    android:paddingLeft="8dp"
+                    android:paddingRight="20dp"
+                    android:orientation="horizontal"
+                    android:background="?attr/color_background_primary">
+
+                    <ImageView
+                        android:src="?attr/icon_quote"
+                        android:layout_width="20dp"
+                        android:layout_height="20dp"
+                        android:layout_marginRight="8dp"
+                        android:contentDescription="Reply to" />
+
+                    <TextView
+                        android:id="@+id/context_preview_text"
+                        android:layout_weight="1"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content" />
+
+                    <ImageButton
+                        android:id="@+id/context_preview_cancel"
+                        android:layout_width="20dp"
+                        android:layout_height="20dp"
+                        android:padding="0dp"
+                        android:layout_gravity="center_vertical"
+                        android:contentDescription="Cancel"
+                        android:background="?attr/color_background_primary"
+                        android:src="?attr/icon_cancel" />
+                </LinearLayout>
+
                 <RelativeLayout
                     android:id="@+id/textsend"
                     android:layout_width="fill_parent"
@@ -182,7 +220,7 @@
                     android:id="@+id/snackbar"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
-                    android:layout_above="@+id/textsend"
+                    android:layout_above="@+id/context_preview"
                     android:layout_marginLeft="8dp"
                     android:layout_marginRight="8dp"
                     android:layout_marginBottom="4dp"