From cc07f86bf479cd3c667cc9e7e0135a1c457825de Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 27 Mar 2023 10:41:46 +0200 Subject: [PATCH] use occupantResource for sender name --- .../android/database/Converters.java | 1 + .../android/database/dao/ChatDao.java | 23 +++-- .../database/model/ChatOverviewItem.java | 83 ++++++++++++++----- .../database/model/MessageEmbedded.java | 19 +++++ .../database/model/MessageReaction.java | 17 ++++ .../android/database/model/MessageState.java | 18 ++++ .../model/MessageWithContentReactions.java | 82 ++++++++++++++++-- .../android/ui/adapter/MessageAdapter.java | 5 ++ .../android/ui/adapter/MessageComparator.java | 9 ++ .../main/res/layout/item_chat_overview.xml | 2 +- 10 files changed, 224 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/im/conversations/android/database/Converters.java b/app/src/main/java/im/conversations/android/database/Converters.java index 4988f6481..9b68e73e0 100644 --- a/app/src/main/java/im/conversations/android/database/Converters.java +++ b/app/src/main/java/im/conversations/android/database/Converters.java @@ -52,6 +52,7 @@ public final class Converters { return input == null ? null : JidCreate.fromOrThrowUnchecked(input); } + // TODO do we want to return null on null input? @TypeConverter public static Resourcepart toResourcePart(final String input) { return Strings.isNullOrEmpty(input) diff --git a/app/src/main/java/im/conversations/android/database/dao/ChatDao.java b/app/src/main/java/im/conversations/android/database/dao/ChatDao.java index 5e796c331..fbe058ae2 100644 --- a/app/src/main/java/im/conversations/android/database/dao/ChatDao.java +++ b/app/src/main/java/im/conversations/android/database/dao/ChatDao.java @@ -198,15 +198,20 @@ public abstract class ChatDao { "SELECT c.id,c.accountId,c.address,c.type,m.sentAt,m.senderIdentity as" + " sender,m.outgoing,m.latestVersion as" + " version,m.toBare,m.toResource,m.fromBare,m.fromResource,(SELECT count(id) FROM" - + " message WHERE chatId=c.id) as unread,(SELECT name FROM roster WHERE" - + " roster.accountId=c.accountId AND roster.address=c.address) as" - + " rosterName,(SELECT nick FROM nick WHERE nick.accountId=c.accountId AND" - + " nick.address=c.address) as nick,(SELECT identity.name FROM disco_item JOIN" - + " disco_identity identity ON disco_item.discoId=identity.discoId WHERE" - + " disco_item.accountId=c.accountId AND disco_item.address=c.address LIMIT 1) as" - + " discoIdentityName,(SELECT name FROM bookmark WHERE" - + " bookmark.accountId=c.accountId AND bookmark.address=c.address) as" - + " bookmarkName,(CASE WHEN c.type='MUC' THEN (SELECT vCardPhoto FROM presence" + + " message WHERE chatId=c.id) as unread,(CASE WHEN c.type = 'INDIVIDUAL' THEN" + + " (SELECT name FROM roster WHERE roster.accountId=c.accountId AND" + + " roster.address=c.address) ELSE NULL END) as rosterName,(CASE WHEN c.type =" + + " 'INDIVIDUAL' THEN (SELECT nick FROM nick WHERE nick.accountId=c.accountId AND" + + " nick.address=c.address) ELSE NULL END) as nick,(CASE WHEN c.type IN('MUC') THEN" + + " (SELECT name FROM roster WHERE roster.accountId=c.accountId AND" + + " roster.address=m.senderIdentity) ELSE NULL END) as senderRosterName,(CASE WHEN" + + " c.type IN ('MUC') THEN (SELECT nick FROM nick WHERE nick.accountId=c.accountId" + + " AND nick.address=m.senderIdentity) ELSE NULL END) as senderNick,(SELECT" + + " identity.name FROM disco_item JOIN disco_identity identity ON" + + " disco_item.discoId=identity.discoId WHERE disco_item.accountId=c.accountId AND" + + " disco_item.address=c.address LIMIT 1) as discoIdentityName,(SELECT name FROM" + + " bookmark WHERE bookmark.accountId=c.accountId AND bookmark.address=c.address)" + + " as bookmarkName,(CASE WHEN c.type='MUC' THEN (SELECT vCardPhoto FROM presence" + " WHERE presence.accountId=c.accountId AND address=c.address AND resource='')" + " WHEN c.type='INDIVIDUAL' THEN (SELECT vCardPhoto FROM presence WHERE" + " accountId=c.accountId AND address=c.address AND vCardPhoto NOT NULL LIMIT 1)" diff --git a/app/src/main/java/im/conversations/android/database/model/ChatOverviewItem.java b/app/src/main/java/im/conversations/android/database/model/ChatOverviewItem.java index 30b846b2a..4a048aa82 100644 --- a/app/src/main/java/im/conversations/android/database/model/ChatOverviewItem.java +++ b/app/src/main/java/im/conversations/android/database/model/ChatOverviewItem.java @@ -3,6 +3,7 @@ package im.conversations.android.database.model; import androidx.room.Relation; import com.google.common.base.Objects; import com.google.common.collect.Iterables; +import im.conversations.android.database.KnownSender; import im.conversations.android.database.entity.MessageContentEntity; import java.time.Instant; import java.util.List; @@ -10,7 +11,7 @@ import org.jxmpp.jid.BareJid; import org.jxmpp.jid.Jid; import org.jxmpp.jid.parts.Resourcepart; -public class ChatOverviewItem extends ChatInfo { +public class ChatOverviewItem extends ChatInfo implements KnownSender { public long id; @@ -24,6 +25,8 @@ public class ChatOverviewItem extends ChatInfo { public String fromResource; public BareJid sender; + public String senderNick; + public String senderRosterName; public long version; @@ -45,17 +48,63 @@ public class ChatOverviewItem extends ChatInfo { return firstMessageContent == null ? null : firstMessageContent.body; } - public Sender getSender() { + @Override + public ChatType getChatType() { + return this.type; + } + + @Override + public boolean isMembersOnlyNonAnonymous() { + return this.membersOnlyNonAnonymous; + } + + @Override + public BareJid getSender() { + return this.sender; + } + + public Sender getMessageSender() { if (outgoing) { return new SenderYou(); } else if (type == ChatType.MUC) { - if (fromResource != null) { - return new SenderName(fromResource); + if (isKnownSender()) { + return new SenderName(individualName()); } else { - return null; + if (occupantResource != null && occupantResource.length() > 0) { + return new SenderName(occupantResource.toString()); + } + if (fromResource != null && fromResource.length() > 0) { + return new SenderName(fromResource.toString()); + } } + } + return null; + } + + @Override + public String individualRosterName() { + if (type == ChatType.INDIVIDUAL) { + return super.individualRosterName(); } else { - return null; + return this.senderRosterName; + } + } + + @Override + public String individualNick() { + if (type == ChatType.INDIVIDUAL) { + return super.individualNick(); + } else { + return senderNick; + } + } + + @Override + public BareJid individualAddress() { + if (type == ChatType.INDIVIDUAL) { + return super.individualAddress(); + } else { + return this.sender; } } @@ -88,23 +137,20 @@ public class ChatOverviewItem extends ChatInfo { if (o == null || getClass() != o.getClass()) return false; ChatOverviewItem that = (ChatOverviewItem) o; return id == that.id - && accountId == that.accountId && outgoing == that.outgoing && version == that.version && unread == that.unread - && Objects.equal(address, that.address) - && type == that.type && Objects.equal(sentAt, that.sentAt) && Objects.equal(toBare, that.toBare) && Objects.equal(toResource, that.toResource) && Objects.equal(fromBare, that.fromBare) && Objects.equal(fromResource, that.fromResource) - && Objects.equal(rosterName, that.rosterName) - && Objects.equal(nick, that.nick) - && Objects.equal(discoIdentityName, that.discoIdentityName) - && Objects.equal(bookmarkName, that.bookmarkName) + && Objects.equal(sender, that.sender) + && Objects.equal(senderNick, that.senderNick) + && Objects.equal(senderRosterName, that.senderRosterName) && Objects.equal(vCardPhoto, that.vCardPhoto) && Objects.equal(avatar, that.avatar) + && Objects.equal(occupantResource, that.occupantResource) && Objects.equal(contents, that.contents); } @@ -112,22 +158,19 @@ public class ChatOverviewItem extends ChatInfo { public int hashCode() { return Objects.hashCode( id, - accountId, - address, - type, sentAt, outgoing, toBare, toResource, fromBare, fromResource, + sender, + senderNick, + senderRosterName, version, - rosterName, - nick, - discoIdentityName, - bookmarkName, vCardPhoto, avatar, + occupantResource, unread, contents); } diff --git a/app/src/main/java/im/conversations/android/database/model/MessageEmbedded.java b/app/src/main/java/im/conversations/android/database/model/MessageEmbedded.java index 45f11a9db..ade15e5f2 100644 --- a/app/src/main/java/im/conversations/android/database/model/MessageEmbedded.java +++ b/app/src/main/java/im/conversations/android/database/model/MessageEmbedded.java @@ -1,6 +1,7 @@ package im.conversations.android.database.model; import androidx.room.Relation; +import com.google.common.base.Objects; import im.conversations.android.database.entity.MessageContentEntity; import java.time.Instant; import java.util.List; @@ -20,4 +21,22 @@ public class MessageEmbedded { parentColumn = "latestVersion", entityColumn = "messageVersionId") public List contents; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MessageEmbedded that = (MessageEmbedded) o; + return id == that.id + && Objects.equal(fromBare, that.fromBare) + && Objects.equal(fromResource, that.fromResource) + && Objects.equal(sentAt, that.sentAt) + && Objects.equal(latestVersion, that.latestVersion) + && Objects.equal(contents, that.contents); + } + + @Override + public int hashCode() { + return Objects.hashCode(id, fromBare, fromResource, sentAt, latestVersion, contents); + } } diff --git a/app/src/main/java/im/conversations/android/database/model/MessageReaction.java b/app/src/main/java/im/conversations/android/database/model/MessageReaction.java index 00f31eca7..13ac7dd3b 100644 --- a/app/src/main/java/im/conversations/android/database/model/MessageReaction.java +++ b/app/src/main/java/im/conversations/android/database/model/MessageReaction.java @@ -1,5 +1,6 @@ package im.conversations.android.database.model; +import com.google.common.base.Objects; import org.jxmpp.jid.Jid; public class MessageReaction { @@ -17,4 +18,20 @@ public class MessageReaction { this.occupantId = occupantId; this.reaction = reaction; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MessageReaction that = (MessageReaction) o; + return Objects.equal(reactionBy, that.reactionBy) + && Objects.equal(reactionByResource, that.reactionByResource) + && Objects.equal(occupantId, that.occupantId) + && Objects.equal(reaction, that.reaction); + } + + @Override + public int hashCode() { + return Objects.hashCode(reactionBy, reactionByResource, occupantId, reaction); + } } diff --git a/app/src/main/java/im/conversations/android/database/model/MessageState.java b/app/src/main/java/im/conversations/android/database/model/MessageState.java index 24ff41293..2269ed28f 100644 --- a/app/src/main/java/im/conversations/android/database/model/MessageState.java +++ b/app/src/main/java/im/conversations/android/database/model/MessageState.java @@ -1,5 +1,6 @@ package im.conversations.android.database.model; +import com.google.common.base.Objects; import com.google.common.base.Preconditions; import im.conversations.android.transformer.MessageTransformation; import im.conversations.android.xmpp.model.error.Condition; @@ -64,4 +65,21 @@ public class MessageState { null, null); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MessageState that = (MessageState) o; + return Objects.equal(fromBare, that.fromBare) + && Objects.equal(fromResource, that.fromResource) + && type == that.type + && Objects.equal(errorCondition, that.errorCondition) + && Objects.equal(errorText, that.errorText); + } + + @Override + public int hashCode() { + return Objects.hashCode(fromBare, fromResource, type, errorCondition, errorText); + } } diff --git a/app/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java b/app/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java index a784b72a3..854845276 100644 --- a/app/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java +++ b/app/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java @@ -1,6 +1,7 @@ package im.conversations.android.database.model; import androidx.room.Relation; +import com.google.common.base.Objects; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; @@ -48,7 +49,7 @@ public class MessageWithContentReactions implements IndividualName, KnownSender public String senderNick; public String occupantVcardPhoto; - public String occupantResource; + public Resourcepart occupantResource; public Modification modification; public long version; @@ -101,9 +102,13 @@ public class MessageWithContentReactions implements IndividualName, KnownSender if (isKnownSender()) { return new AddressWithName(individualAddress(), individualName()); } else { - final Jid address = JidCreate.fullFrom(fromBare, fromResource); - final String name = fromResource.toString(); - return new AddressWithName(address, name); + final Jid address; + if (occupantResource != null && occupantResource.length() != 0) { + address = JidCreate.fullFrom(fromBare, occupantResource); + } else { + address = JidCreate.fullFrom(fromBare, fromResource); + } + return new AddressWithName(address, address.getResourceOrEmpty().toString()); } } @@ -159,7 +164,8 @@ public class MessageWithContentReactions implements IndividualName, KnownSender } public String getSenderName() { - return this.fromResource == null ? null : fromResource.toString(); + final var addressWithName = getAddressWithName(); + return addressWithName.name; } public boolean isGroupChat() { @@ -170,6 +176,72 @@ public class MessageWithContentReactions implements IndividualName, KnownSender return new EncryptionTuple(this.encryption, this.trust); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MessageWithContentReactions that = (MessageWithContentReactions) o; + return accountId == that.accountId + && id == that.id + && membersOnlyNonAnonymous == that.membersOnlyNonAnonymous + && outgoing == that.outgoing + && version == that.version + && chatType == that.chatType + && Objects.equal(sentAt, that.sentAt) + && Objects.equal(toBare, that.toBare) + && Objects.equal(toResource, that.toResource) + && Objects.equal(fromBare, that.fromBare) + && Objects.equal(fromResource, that.fromResource) + && Objects.equal(sender, that.sender) + && Objects.equal(senderVcardPhoto, that.senderVcardPhoto) + && Objects.equal(senderAvatar, that.senderAvatar) + && Objects.equal(senderRosterName, that.senderRosterName) + && Objects.equal(senderNick, that.senderNick) + && Objects.equal(occupantVcardPhoto, that.occupantVcardPhoto) + && Objects.equal(occupantResource, that.occupantResource) + && modification == that.modification + && Objects.equal(inReplyToMessageEntityId, that.inReplyToMessageEntityId) + && encryption == that.encryption + && Objects.equal(identityKey, that.identityKey) + && trust == that.trust + && Objects.equal(inReplyTo, that.inReplyTo) + && Objects.equal(contents, that.contents) + && Objects.equal(reactions, that.reactions) + && Objects.equal(states, that.states); + } + + @Override + public int hashCode() { + return Objects.hashCode( + accountId, + id, + chatType, + membersOnlyNonAnonymous, + sentAt, + outgoing, + toBare, + toResource, + fromBare, + fromResource, + sender, + senderVcardPhoto, + senderAvatar, + senderRosterName, + senderNick, + occupantVcardPhoto, + occupantResource, + modification, + version, + inReplyToMessageEntityId, + encryption, + identityKey, + trust, + inReplyTo, + contents, + reactions, + states); + } + public static class EncryptionTuple { public final Encryption encryption; public final Trust trust; diff --git a/app/src/main/java/im/conversations/android/ui/adapter/MessageAdapter.java b/app/src/main/java/im/conversations/android/ui/adapter/MessageAdapter.java index 4d3451ab4..a450cb75b 100644 --- a/app/src/main/java/im/conversations/android/ui/adapter/MessageAdapter.java +++ b/app/src/main/java/im/conversations/android/ui/adapter/MessageAdapter.java @@ -12,11 +12,15 @@ import im.conversations.android.R; import im.conversations.android.database.model.MessageWithContentReactions; import im.conversations.android.databinding.ItemMessageReceivedBinding; import im.conversations.android.ui.AvatarFetcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class MessageAdapter extends PagingDataAdapter< MessageWithContentReactions, MessageAdapter.AbstractMessageViewHolder> { + private static final Logger LOGGER = LoggerFactory.getLogger(MessageAdapter.class); + public MessageAdapter( @NonNull DiffUtil.ItemCallback diffCallback) { super(diffCallback); @@ -41,6 +45,7 @@ public class MessageAdapter if (message == null) { holder.setMessage(null); } + LOGGER.info("onBindViewHolder({})", message == null ? null : message.id); holder.setMessage(message); if (holder instanceof MessageReceivedViewHolder messageReceivedViewHolder) { final var addressWithName = message == null ? null : message.getAddressWithName(); diff --git a/app/src/main/java/im/conversations/android/ui/adapter/MessageComparator.java b/app/src/main/java/im/conversations/android/ui/adapter/MessageComparator.java index 96bce1709..6ed115f92 100644 --- a/app/src/main/java/im/conversations/android/ui/adapter/MessageComparator.java +++ b/app/src/main/java/im/conversations/android/ui/adapter/MessageComparator.java @@ -3,8 +3,13 @@ package im.conversations.android.ui.adapter; import androidx.annotation.NonNull; import androidx.recyclerview.widget.DiffUtil; import im.conversations.android.database.model.MessageWithContentReactions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class MessageComparator extends DiffUtil.ItemCallback { + + private static final Logger LOGGER = LoggerFactory.getLogger(MessageComparator.class); + @Override public boolean areItemsTheSame( @NonNull MessageWithContentReactions oldItem, @@ -16,6 +21,10 @@ public class MessageComparator extends DiffUtil.ItemCallback