Improve direct chat handling

We show less information in direct chats in dual chat bubble layout, as
we assume that the senders know themselves, and see the chat partner
from  the action bar at the top.

However, there are some limitations:
- A directChat might actually include more members, due to helper bots,
  multiple accounts, or misconfigurations
- Even if a direct chat has exactly two members, there might have been
  some membership changes in the past

To account for this, we do the following:
- Only enable the direct message layout if there are exactly two members
  in the room currently (in addition to the isDirect-flag being set)
- Before hiding sender information, check if the sender is actually the
  expected chat partner. If not, fallback to showing avatar and name for
  this message.

Possible improvement for the future: if we have a message in a direct
chat by a non-member, following messages by the dm chat partner might
benefit from showing member name either way.

Change-Id: Ie4a204510990301175339e60469048b06669d36b
This commit is contained in:
SpiritCroc 2020-11-02 10:55:39 +01:00
parent be2983053a
commit 44355109d7
3 changed files with 29 additions and 3 deletions

View File

@ -35,6 +35,8 @@ import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.send.SendState
@ -76,6 +78,27 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
val time = dateFormatter.format(event.root.originServerTs, DateFormatKind.MESSAGE_SIMPLE) val time = dateFormatter.format(event.root.originServerTs, DateFormatKind.MESSAGE_SIMPLE)
val e2eDecoration = getE2EDecoration(event) val e2eDecoration = getE2EDecoration(event)
var isEffectivelyDirect = false
var dmOtherMemberId: String? = null
if ((roomSummaryHolder.roomSummary?.isDirect == true) && event.root.roomId != null) {
val members = session.getRoom(event.root.roomId!!)
?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) })
?.map { it.userId }
.orEmpty()
.toSet()
if (members.size == 2) {
var foundSelf = false
for (member in members) {
if (member == session.myUserId) {
foundSelf = true
} else {
dmOtherMemberId = member
}
}
isEffectivelyDirect = foundSelf && (dmOtherMemberId != null)
}
}
return MessageInformationData( return MessageInformationData(
eventId = eventId, eventId = eventId,
senderId = event.root.senderId ?: "", senderId = event.root.senderId ?: "",
@ -127,7 +150,8 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
} else { } else {
AnonymousReadReceipt.PROCESSING AnonymousReadReceipt.PROCESSING
}, },
isDirect = roomSummaryHolder.roomSummary?.isDirect ?: false, isDirect = isEffectivelyDirect,
dmChatPartnerId = dmOtherMemberId,
e2eDecoration = e2eDecoration e2eDecoration = e2eDecoration
) )
} }

View File

@ -242,7 +242,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
} }
override fun ignoreMessageGuideline(context: Context): Boolean { override fun ignoreMessageGuideline(context: Context): Boolean {
return infoInBubbles(context) && (attributes.informationData.sentByMe || attributes.informationData.isDirect) return infoInBubbles(context) && canHideAvatars()
} }
open fun getViewStubMinimumWidth(holder: H, contentInBubble: Boolean, showInformation: Boolean): Int { open fun getViewStubMinimumWidth(holder: H, contentInBubble: Boolean, showInformation: Boolean): Int {
@ -303,7 +303,8 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
} }
open fun canHideAvatars(): Boolean { open fun canHideAvatars(): Boolean {
return attributes.informationData.sentByMe || attributes.informationData.isDirect return attributes.informationData.sentByMe ||
(attributes.informationData.isDirect && attributes.informationData.senderId == attributes.informationData.dmChatPartnerId)
} }
override fun setBubbleLayout(holder: H, bubbleStyle: String, bubbleStyleSetting: String, reverseBubble: Boolean) { override fun setBubbleLayout(holder: H, bubbleStyle: String, bubbleStyleSetting: String, reverseBubble: Boolean) {

View File

@ -44,6 +44,7 @@ data class MessageInformationData(
val sentByMe : Boolean, val sentByMe : Boolean,
val readReceiptAnonymous: AnonymousReadReceipt, val readReceiptAnonymous: AnonymousReadReceipt,
val isDirect: Boolean, val isDirect: Boolean,
val dmChatPartnerId: String?,
val e2eDecoration: E2EDecoration = E2EDecoration.NONE val e2eDecoration: E2EDecoration = E2EDecoration.NONE
) : Parcelable { ) : Parcelable {