diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index b9bdd21b2d2ecc5721b15ce66b1dfcf492904389..49cbb720f31a4ad2d7abd7e31175953d92edc1de 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -148,6 +148,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl private String mFirstMamReference = null; protected int mCurrentTab = -1; protected ConversationPagerAdapter pagerAdapter = new ConversationPagerAdapter(); + protected Element thread = null; public Conversation(final String name, final Account account, final Jid contactJid, final int mode) { @@ -628,6 +629,14 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl this.draftMessage = draftMessage; } + public Element getThread() { + return this.thread; + } + + public void setThread(Element thread) { + this.thread = thread; + } + public boolean isRead() { synchronized (this.messages) { for(final Message message : Lists.reverse(this.messages)) { diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 7e89357f9d69f7d9cc900218688c894bba2a169c..47fde1f5051683508e46a1bc2394df2730acf528 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -430,6 +430,11 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable return null; } + public void setThread(Element thread) { + payloads.removeIf(el -> el.getName().equals("thread") && el.getNamespace().equals("jabber:client")); + addPayload(thread); + } + public void setMucUser(MucOptions.User user) { this.user = new WeakReference<>(user); } @@ -919,9 +924,15 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable } public void addPayload(Element el) { + if (el == null) return; + this.payloads.add(el); } + public List getPayloads() { + return new ArrayList<>(this.payloads); + } + public Element getHtml() { if (this.payloads == null) return null; @@ -932,7 +943,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable } return null; - } + } public List getCommands() { if (this.payloads == null) return null; diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index 4b055e15883131ab61afff17482c7b4dbdec13d3..90a312204094c58cc2bda1baf3e27ed4aa7f25bf 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -62,6 +62,9 @@ public class MessageGenerator extends AbstractGenerator { if (message.edited()) { packet.addChild("replace", "urn:xmpp:message-correct:0").setAttribute("id", message.getEditedIdWireFormat()); } + for (Element el : message.getPayloads()) { + packet.addChild(el); + } return packet; } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 42e095d786da861f10e8466c08803d036c699da1..746b1ae6b642a217497e3e85f424ca2016e7a478 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -870,6 +870,7 @@ public class ConversationFragment extends XmppFragment final Message message; if (conversation.getCorrectingMessage() == null) { message = new Message(conversation, body, conversation.getNextEncryption()); + message.setThread(conversation.getThread()); Message.configurePrivateMessage(message); } else { message = conversation.getCorrectingMessage(); @@ -953,6 +954,8 @@ public class ConversationFragment extends XmppFragment this.binding.textinput.setHint(UIHelper.getMessageHint(getActivity(), conversation)); getActivity().invalidateOptionsMenu(); } + + binding.messagesView.post(this::updateThreadFromLastMessage); } public void setupIme() { @@ -1248,6 +1251,8 @@ public class ConversationFragment extends XmppFragment new EditMessageActionModeCallback(this.binding.textinput)); } + binding.threadIdenticon.setOnClickListener(v -> newThread()); + return binding.getRoot(); } @@ -1275,9 +1280,23 @@ public class ConversationFragment extends XmppFragment } private void quoteMessage(Message message) { + setThread(message.getThread()); quoteText(MessageUtils.prepareQuote(message)); } + private void setThread(Element thread) { + this.conversation.setThread(thread); + binding.threadIdenticon.setAlpha(0f); + if (thread != null) { + final String threadId = thread.getContent(); + if (threadId != null) { + binding.threadIdenticon.setAlpha(1f); + binding.threadIdenticon.setColor(UIHelper.getColorForName(threadId)); + binding.threadIdenticon.setHash(UIHelper.identiconHash(threadId)); + } + } + } + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // This should cancel any remaining click events that would otherwise trigger links @@ -2116,7 +2135,29 @@ public class ConversationFragment extends XmppFragment } } + private void newThread() { + Element thread = new Element("thread", "jabber:client"); + thread.setContent(UUID.randomUUID().toString()); + setThread(thread); + } + + private void updateThreadFromLastMessage() { + if (activity != null && this.conversation != null && TextUtils.isEmpty(binding.textinput.getText())) { + Message message = getLastVisibleMessage(); + if (message == null) { + newThread(); + } else { + setThread(message.getThread()); + } + } + } + private String getLastVisibleMessageUuid() { + Message message = getLastVisibleMessage(); + return message == null ? null : message.getUuid(); + } + + private Message getLastVisibleMessage() { if (binding == null) { return null; } @@ -2140,7 +2181,7 @@ public class ConversationFragment extends XmppFragment while (message.next() != null && message.next().wasMergedIntoPrevious()) { message = message.next(); } - return message.getUuid(); + return message; } } } @@ -3684,13 +3725,7 @@ public class ConversationFragment extends XmppFragment @Override public void onContactPictureClicked(Message message) { - String fingerprint; - if (message.getEncryption() == Message.ENCRYPTION_PGP - || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { - fingerprint = "pgp"; - } else { - fingerprint = message.getFingerprint(); - } + setThread(message.getThread()); final boolean received = message.getStatus() <= Message.STATUS_RECEIVED; if (received) { if (message.getConversation() instanceof Conversation @@ -3724,15 +3759,8 @@ public class ConversationFragment extends XmppFragment .show(); } } - return; - } else { - if (!message.getContact().isSelf()) { - activity.switchToContactDetails(message.getContact(), fingerprint); - return; - } } } - activity.switchToAccount(message.getConversation().getAccount(), fingerprint); } private Activity requireActivity() { diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index daa170dbfaa736227bd46e5e362ff3099703d304..a5d6c900127c6ea7e4834bd4d62962b100e744ba 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -719,6 +719,7 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.subject = view.findViewById(R.id.message_subject); viewHolder.indicatorReceived = view.findViewById(R.id.indicator_received); viewHolder.audioPlayer = view.findViewById(R.id.audio_player); + viewHolder.thread_identicon = view.findViewById(R.id.thread_identicon); break; case RECEIVED: view = activity.getLayoutInflater().inflate(R.layout.message_received, parent, false); diff --git a/src/main/res/layout/fragment_conversation.xml b/src/main/res/layout/fragment_conversation.xml index 05915e0c7e88662368fdfdf60d2f635d6acae685..861e3a1e429b97d2beaf1a8a283c169967af7c50 100644 --- a/src/main/res/layout/fragment_conversation.xml +++ b/src/main/res/layout/fragment_conversation.xml @@ -60,10 +60,10 @@ + + - - - - - - - + android:layout_alignParentBottom="true"> + + + + + + + + + +