diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt index 43c1544ffd..ac3e2dea43 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt @@ -62,15 +62,18 @@ data class TimelineEvent( } fun getDisambiguatedDisplayName(): String { - return if (isUniqueDisplayName) { + val disambiguated = if (isUniqueDisplayName) { senderName } else { senderName?.let { name -> "$name (${root.senderId})" } } - ?: root.senderId - ?: "" + return if (disambiguated.isNullOrBlank()) { + root.senderId ?: "" + } else { + disambiguated + } } /** @@ -113,7 +116,8 @@ fun TimelineEvent.getLastMessageBody(): String? { val lastMessageContent = getLastMessageContent() if (lastMessageContent != null) { - return lastMessageContent.newContent?.toModel()?.body ?: lastMessageContent.body + return lastMessageContent.newContent?.toModel()?.body + ?: lastMessageContent.body } return null diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt index 24765c120d..daee1fadec 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt @@ -16,6 +16,7 @@ package im.vector.matrix.android.internal.database.helper +import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.RoomMember @@ -39,14 +40,17 @@ internal fun TimelineEventEntity.updateSenderData() { val isUnlinked = chunkEntity.isUnlinked() var senderMembershipEvent: EventEntity? var senderRoomMemberContent: String? + var senderRoomMemberPrevContent: String? when { stateIndex <= 0 -> { senderMembershipEvent = chunkEntity.timelineEvents.buildQuery(senderId, isUnlinked).next(from = stateIndex)?.root senderRoomMemberContent = senderMembershipEvent?.prevContent + senderRoomMemberPrevContent = senderMembershipEvent?.content } else -> { senderMembershipEvent = chunkEntity.timelineEvents.buildQuery(senderId, isUnlinked).prev(since = stateIndex)?.root senderRoomMemberContent = senderMembershipEvent?.content + senderRoomMemberPrevContent = senderMembershipEvent?.prevContent } } @@ -58,11 +62,27 @@ internal fun TimelineEventEntity.updateSenderData() { .equalTo(EventEntityFields.TYPE, EventType.STATE_ROOM_MEMBER) .prev(since = stateIndex) senderRoomMemberContent = senderMembershipEvent?.content + senderRoomMemberPrevContent = senderMembershipEvent?.prevContent + } + + ContentMapper.map(senderRoomMemberContent).toModel()?.also { + this.senderAvatar = it.avatarUrl + this.senderName = it.displayName + this.isUniqueDisplayName = RoomMembers(realm, roomId).isUniqueDisplayName(it.displayName) + } + + // We try to fallback on prev content if we got a room member state events with null fields + if (root?.type == EventType.STATE_ROOM_MEMBER) { + ContentMapper.map(senderRoomMemberPrevContent).toModel()?.also { + if (this.senderAvatar == null && it.avatarUrl != null) { + this.senderAvatar = it.avatarUrl + } + if (this.senderName == null && it.displayName != null) { + this.senderName = it.displayName + this.isUniqueDisplayName = RoomMembers(realm, roomId).isUniqueDisplayName(it.displayName) + } + } } - val senderRoomMember: RoomMember? = ContentMapper.map(senderRoomMemberContent).toModel() - this.senderAvatar = senderRoomMember?.avatarUrl - this.senderName = senderRoomMember?.displayName - this.isUniqueDisplayName = RoomMembers(realm, roomId).isUniqueDisplayName(senderRoomMember?.displayName) this.senderMembershipEvent = senderMembershipEvent } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt index 49c813ece6..dae1b043ba 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt @@ -119,7 +119,7 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use permalink, stringProvider.getString(R.string.message_reply_to_prefix), userLink, - originalEvent.senderName ?: originalEvent.root.senderId, + originalEvent.getDisambiguatedDisplayName(), body.takeFormatted(), createTextContent(newBodyText, newBodyAutoMarkdown).takeFormatted() ) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 7c4437d6f0..35bcd388fd 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -409,7 +409,7 @@ class RoomDetailFragment : composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), iconRes)) composerLayout.sendButton.setContentDescription(getString(descriptionRes)) - avatarRenderer.render(event.senderAvatar, event.root.senderId ?: "", event.senderName, composerLayout.composerRelatedMessageAvatar) + avatarRenderer.render(event.senderAvatar, event.root.senderId ?: "", event.getDisambiguatedDisplayName(), composerLayout.composerRelatedMessageAvatar) composerLayout.expand { // need to do it here also when not using quick reply focusComposerAndShowKeyboard() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt index 12f49c2e74..3f234fcd3e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt @@ -27,8 +27,6 @@ import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController import im.vector.riotx.features.home.room.detail.timeline.helper.AvatarSizeProvider -import im.vector.riotx.features.home.room.detail.timeline.helper.senderAvatar -import im.vector.riotx.features.home.room.detail.timeline.helper.senderName import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem_ @@ -41,13 +39,13 @@ class EncryptionItemFactory @Inject constructor(private val stringProvider: Stri fun create(event: TimelineEvent, highlight: Boolean, callback: TimelineEventController.Callback?): NoticeItem? { - val text = buildNoticeText(event.root, event.senderName) ?: return null + val text = buildNoticeText(event.root, event.getDisambiguatedDisplayName()) ?: return null val informationData = MessageInformationData( eventId = event.root.eventId ?: "?", senderId = event.root.senderId ?: "", sendState = event.root.sendState, - avatarUrl = event.senderAvatar(), - memberName = event.senderName(), + avatarUrl = event.senderAvatar, + memberName = event.getDisambiguatedDisplayName(), showInformation = false ) val attributes = NoticeItem.Attributes( diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt index 1df885cd35..1d98595c4d 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt @@ -64,12 +64,12 @@ class MergedHeaderItemFactory @Inject constructor(private val sessionHolder: Act if (!showReadMarker && mergedEvent.hasReadMarker && readMarkerVisible) { showReadMarker = true } - val senderAvatar = mergedEvent.senderAvatar() - val senderName = mergedEvent.senderName() + val senderAvatar = mergedEvent.senderAvatar + val senderName = mergedEvent.getDisambiguatedDisplayName() val data = MergedHeaderItem.Data( userId = mergedEvent.root.senderId ?: "", avatarUrl = senderAvatar, - memberName = senderName ?: "", + memberName = senderName , localId = mergedEvent.localId, eventId = mergedEvent.root.eventId ?: "" ) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt index 2d116e4a90..9a86420277 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt @@ -19,13 +19,17 @@ package im.vector.riotx.features.home.room.detail.timeline.format import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel -import im.vector.matrix.android.api.session.room.model.* +import im.vector.matrix.android.api.session.room.model.Membership +import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility +import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibilityContent +import im.vector.matrix.android.api.session.room.model.RoomMember +import im.vector.matrix.android.api.session.room.model.RoomNameContent +import im.vector.matrix.android.api.session.room.model.RoomTopicContent import im.vector.matrix.android.api.session.room.model.call.CallInviteContent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotx.R import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.resources.StringProvider -import im.vector.riotx.features.home.room.detail.timeline.helper.senderName import timber.log.Timber import javax.inject.Inject @@ -36,7 +40,7 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active return when (val type = timelineEvent.root.getClearType()) { EventType.STATE_ROOM_NAME -> formatRoomNameEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName()) EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName()) - EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(timelineEvent.root, timelineEvent.senderName()) + EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName()) EventType.STATE_HISTORY_VISIBILITY -> formatRoomHistoryVisibilityEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName()) EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(timelineEvent.getDisambiguatedDisplayName()) EventType.CALL_INVITE, @@ -96,7 +100,8 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active } private fun formatRoomHistoryVisibilityEvent(event: Event, senderName: String?): CharSequence? { - val historyVisibility = event.getClearContent().toModel()?.historyVisibility ?: return null + val historyVisibility = event.getClearContent().toModel()?.historyVisibility + ?: return null val formattedVisibility = when (historyVisibility) { RoomHistoryVisibility.SHARED -> stringProvider.getString(R.string.notice_room_visibility_shared) @@ -135,7 +140,7 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active } } - private fun buildProfileNotice(event: Event, senderName: String?, eventContent: RoomMember?, prevEventContent: RoomMember?): String? { + private fun buildProfileNotice(event: Event, senderName: String?, eventContent: RoomMember?, prevEventContent: RoomMember?): String { val displayText = StringBuilder() // Check display name has been changed if (eventContent?.displayName != prevEventContent?.displayName) { @@ -146,7 +151,7 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active stringProvider.getString(R.string.notice_display_name_removed, event.senderId, prevEventContent?.displayName) else -> stringProvider.getString(R.string.notice_display_name_changed_from, - event.senderId, prevEventContent?.displayName, eventContent?.displayName) + event.senderId, prevEventContent?.displayName, eventContent?.displayName) } displayText.append(displayNameText) } @@ -160,6 +165,11 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active } displayText.append(displayAvatarText) } + if (displayText.isEmpty()) { + displayText.append( + stringProvider.getString(R.string.notice_member_no_changes, senderName) + ) + } return displayText.toString() } @@ -171,9 +181,10 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active val selfUserId = sessionHolder.getSafeActiveSession()?.myUserId when { eventContent.thirdPartyInvite != null -> { - val userWhoHasAccepted = eventContent.thirdPartyInvite?.signed?.mxid ?: event.stateKey + val userWhoHasAccepted = eventContent.thirdPartyInvite?.signed?.mxid + ?: event.stateKey stringProvider.getString(R.string.notice_room_third_party_registered_invite, - userWhoHasAccepted, eventContent.thirdPartyInvite?.displayName) + userWhoHasAccepted, eventContent.thirdPartyInvite?.displayName) } event.stateKey == selfUserId -> stringProvider.getString(R.string.notice_room_invite_you, senderDisplayName) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt index a75ac86c1b..0b2a111e7e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt @@ -47,25 +47,6 @@ object TimelineDisplayableEvents { ) } -fun TimelineEvent.senderAvatar(): String? { - // We might have no avatar when user leave, so we try to get it from prevContent - return senderAvatar - ?: if (root.type == EventType.STATE_ROOM_MEMBER) { - root.prevContent.toModel()?.avatarUrl - } else { - null - } -} - -fun TimelineEvent.senderName(): String? { - // We might have no senderName when user leave, so we try to get it from prevContent - return when { - senderName != null -> getDisambiguatedDisplayName() - root.type == EventType.STATE_ROOM_MEMBER -> root.prevContent.toModel()?.displayName - else -> null - } -} - fun TimelineEvent.canBeMerged(): Boolean { return root.getClearType() == EventType.STATE_ROOM_MEMBER } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItemFactory.kt index 0ad3b10159..1e5067923b 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItemFactory.kt @@ -30,7 +30,6 @@ import im.vector.riotx.core.resources.DateProvider import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.room.detail.timeline.format.NoticeEventFormatter -import im.vector.riotx.features.home.room.detail.timeline.helper.senderName import me.gujun.android.span.span import javax.inject.Inject @@ -97,10 +96,10 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte && latestEvent.root.mxDecryptionResult == null) { stringProvider.getString(R.string.encrypted_message) } else if (latestEvent.root.getClearType() == EventType.MESSAGE) { - val senderName = latestEvent.senderName() ?: latestEvent.root.senderId + val senderName = latestEvent.getDisambiguatedDisplayName() val content = latestEvent.root.getClearContent()?.toModel() val message = content?.body ?: "" - if (roomSummary.isDirect.not() && senderName != null) { + if (roomSummary.isDirect.not()) { span { text = senderName textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_primary) diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt index 06108e07fe..fc555b5735 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt @@ -94,7 +94,7 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St event.getLastMessageBody() ?: stringProvider.getString(R.string.notification_unknown_new_event) val roomName = stringProvider.getString(R.string.notification_unknown_room_name) - val senderDisplayName = event.senderName ?: event.root.senderId + val senderDisplayName = event.getDisambiguatedDisplayName() val notifiableEvent = NotifiableMessageEvent( eventId = event.root.eventId!!, @@ -128,7 +128,7 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St val body = event.getLastMessageBody() ?: stringProvider.getString(R.string.notification_unknown_new_event) val roomName = room.roomSummary()?.displayName ?: "" - val senderDisplayName = event.senderName ?: event.root.senderId + val senderDisplayName = event.getDisambiguatedDisplayName() val notifiableEvent = NotifiableMessageEvent( eventId = event.root.eventId!!, diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index 71fbc22acf..20fc234fc8 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -2,6 +2,6 @@ - + "%1$s made no changes"