Reply to message instead of just quote

Stephen Paul Weber created

If you want an editable quote you can still copy to clipboard + paste as quote.
This commit works at a protocol level, but there is no UI to show that you are
replying or to let you cancel a reply.

Change summary

src/main/java/eu/siacs/conversations/entities/Conversation.java   |  9 
src/main/java/eu/siacs/conversations/entities/Message.java        | 24 +
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java | 10 
3 files changed, 41 insertions(+), 2 deletions(-)

Detailed changes

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

@@ -170,6 +170,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
     protected Element thread = null;
     protected boolean lockThread = false;
     protected boolean userSelectedThread = false;
+    protected Message replyTo = null;
 
     public Conversation(final String name, final Account account, final Jid contactJid,
                         final int mode) {
@@ -671,6 +672,14 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
         return this.userSelectedThread;
     }
 
+    public void setReplyTo(Message m) {
+        this.replyTo = m;
+    }
+
+    public Message getReplyTo() {
+        return this.replyTo;
+    }
+
     public boolean isRead() {
         synchronized (this.messages) {
             for(final Message message : Lists.reverse(this.messages)) {

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

@@ -47,6 +47,7 @@ import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
 import eu.siacs.conversations.http.URL;
 import eu.siacs.conversations.services.AvatarService;
 import eu.siacs.conversations.ui.util.PresenceSelector;
+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;
@@ -379,6 +380,22 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
         return values;
     }
 
+    public Message reply() {
+        Message m = new Message(conversation, QuoteHelper.quote(getBody()) + "\n", ENCRYPTION_NONE);
+        m.setThread(getThread());
+        m.addPayload(
+            new Element("reply", "urn:xmpp:reply:0")
+                .setAttribute("to", getCounterpart())
+                .setAttribute("id", conversation.getMode() == Conversation.MODE_MULTI ? getServerMsgId() : getRemoteMsgId())
+        );
+        final Element fallback = new Element("fallback", "urn:xmpp:fallback:0").setAttribute("for", "urn:xmpp:reply:0");
+        fallback.addChild("body", "urn:xmpp:fallback:0")
+                .setAttribute("start", "0")
+                .setAttribute("end", "" + m.body.length());
+        m.addPayload(fallback);
+        return m;
+    }
+
     public String getConversationUuid() {
         return conversationUuid;
     }
@@ -450,6 +467,13 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
         this.treatAsDownloadable = null;
     }
 
+    public synchronized void appendBody(String append) {
+        this.body += append;
+        this.isGeoUri = null;
+        this.isEmojisOnly = null;
+        this.treatAsDownloadable = null;
+    }
+
     public String getSubject() {
         return subject;
     }

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

@@ -893,7 +893,13 @@ public class ConversationFragment extends XmppFragment
         }
         final Message message;
         if (conversation.getCorrectingMessage() == null) {
-            message = new Message(conversation, body, conversation.getNextEncryption());
+            if (conversation.getReplyTo() != null) {
+                message = conversation.getReplyTo().reply();
+                message.appendBody(body);
+                message.setEncryption(conversation.getNextEncryption());
+            } else {
+                message = new Message(conversation, body, conversation.getNextEncryption());
+            }
             message.setThread(conversation.getThread());
             Message.configurePrivateMessage(message);
         } else {
@@ -1358,7 +1364,7 @@ public class ConversationFragment extends XmppFragment
     private void quoteMessage(Message message) {
         setThread(message.getThread());
         conversation.setUserSelectedThread(true);
-        quoteText(MessageUtils.prepareQuote(message));
+        conversation.setReplyTo(message);
     }
 
     private void setThread(Element thread) {