Detailed changes
@@ -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)) {
@@ -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<Element> 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<Element> getCommands() {
if (this.payloads == null) return null;
@@ -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;
}
@@ -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() {
@@ -719,6 +719,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
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);
@@ -60,10 +60,10 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- android:layout_alignParentLeft="true"
android:layout_toStartOf="@+id/textSendButton"
android:layout_toLeftOf="@+id/textSendButton"
+ android:layout_toEndOf="@+id/thread_identicon"
+ android:layout_toRightOf="@+id/thread_identicon"
android:orientation="vertical">
<TextView
@@ -109,6 +109,17 @@
</LinearLayout>
+ <com.lelloman.identicon.view.GithubIdenticonView
+ android:id="@+id/thread_identicon"
+ android:alpha="0"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginLeft="8dp"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:contentDescription="Thread Marker" />
+
<ImageButton
android:id="@+id/textSendButton"
android:layout_width="48dp"
@@ -10,29 +10,33 @@
android:paddingRight="8dp"
android:paddingBottom="3dp">
-
- <LinearLayout
+ <RelativeLayout
android:id="@+id/message_photo_box"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
- android:layout_alignParentBottom="true"
- android:orientation="vertical">
-
- <com.makeramen.roundedimageview.RoundedImageView
- android:id="@+id/message_photo"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:scaleType="fitXY"
- app:riv_corner_radius="2dp" />
-
- <View
- android:id="@+id/placeholder"
- android:layout_width="48dp"
- android:layout_height="3dp" />
- </LinearLayout>
+ android:layout_alignParentBottom="true">
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <com.makeramen.roundedimageview.RoundedImageView
+ android:id="@+id/message_photo"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="fitXY"
+ app:riv_corner_radius="2dp" />
+
+ <View
+ android:id="@+id/placeholder"
+ android:layout_width="match_parent"
+ android:layout_height="3dp" />
+ </LinearLayout>
+
+ </RelativeLayout>
<LinearLayout
android:id="@+id/message_box"
@@ -44,7 +48,6 @@
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:layout_toLeftOf="@+id/message_photo_box"
- android:translationY="-2dp"
android:elevation="3dp"
android:background="@drawable/message_bubble_sent"
android:longClickable="true"
@@ -93,6 +96,15 @@
android:text="@string/sending"
android:textAppearance="@style/TextAppearance.Conversations.Caption" />
+ <com.lelloman.identicon.view.GithubIdenticonView
+ android:id="@+id/thread_identicon"
+ android:visibility="gone"
+ android:layout_width="9dp"
+ android:layout_height="9dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="4sp"
+ android:layout_marginBottom="-1dp" />
+
<ImageView
android:id="@+id/security_indicator"
android:layout_width="?attr/TextSizeCaption"