From bcef5f0f1e4e3bf3862728e10620b202e8a777e8 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Fri, 18 Aug 2023 21:20:58 -0500 Subject: [PATCH] Re-use existing forked thread when exists When replying to or mentioning a null-thread message, re-use the thread id of any existing forked thread from a previous reply to that message if there is one, so that not everyone replying to a null thread message ends up generating a new thread when most of the time they mean to all end up in the same new thread. Of course user may tap thread icon at any time if they actually want a second fork. Mentions still do not generate a new thread since their association is not tracked, but will follow the forked thread if it exists. --- .../conversations/entities/Conversation.java | 17 +++++++++++++++ .../ui/ConversationFragment.java | 21 +++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index aadf4c4b62d9192ad8081bc1bd2c79365eca0303..b27d15ab85d708dc517f852725497e8598c9d8b9 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -599,6 +599,23 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl return reactionEmoji; } + public Set findReplies(String id) { + Set replies = new HashSet<>(); + + synchronized (this.messages) { + for (int i = this.messages.size() - 1; i >= 0; --i) { + final Message message = messages.get(i); + if (id.equals(message.getServerMsgId())) break; + if (id.equals(message.getUuid())) break; + final Element r = message.getReply(); + if (r != null && r.getAttribute("id") != null && id.equals(r.getAttribute("id"))) { + replies.add(message); + } + } + } + return replies; + } + public long loadMoreTimestamp() { if (messages.size() < 1) return 0; if (getLockThread() && messages.size() > 5000) return 0; diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 3a857b4f394df7e667e08de85648e7c71cb5fed2..993509a4cf7e74d988f4bb4141e38a9ba4333452 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -1500,10 +1500,23 @@ public class ConversationFragment extends XmppFragment if (message.isPrivateMessage()) privateMessageWith(message.getCounterpart()); setThread(message.getThread()); conversation.setUserSelectedThread(true); - if (message.getThread() == null && conversation.getMode() == Conversation.MODE_MULTI) newThread(); + if (!forkNullThread(message)) newThread(); setupReply(message); } + private boolean forkNullThread(Message message) { + if (message.getThread() != null || conversation.getMode() != Conversation.MODE_MULTI) return true; + for (final Message m : conversation.findReplies(message.getServerMsgId())) { + final Element thread = m.getThread(); + if (thread != null) { + setThread(thread); + return true; + } + } + + return false; + } + private void setupReply(Message message) { conversation.setReplyTo(message); if (message == null) { @@ -4188,8 +4201,12 @@ public class ConversationFragment extends XmppFragment @Override public void onContactPictureClicked(Message message) { - if (message.isPrivateMessage()) privateMessageWith(message.getCounterpart()); setThread(message.getThread()); + if (message.isPrivateMessage()) { + privateMessageWith(message.getCounterpart()); + return; + } + forkNullThread(message); conversation.setUserSelectedThread(true); final boolean received = message.getStatus() <= Message.STATUS_RECEIVED;