From 8972319a85672f2608019c76c5f9f43562241a17 Mon Sep 17 00:00:00 2001 From: ganfra Date: Sat, 27 Jun 2020 18:26:14 +0200 Subject: [PATCH 1/3] Handle typing through RoomSummaryMapper + fix room summary binding called too many times --- .../api/session/room/model/RoomSummary.kt | 2 + .../api/session/typing/TypingUsersTracker.kt | 5 -- .../database/mapper/RoomSummaryMapper.kt | 7 ++- .../internal/session/sync/job/SyncThread.kt | 4 -- .../typing/DefaultTypingUsersTracker.kt | 20 -------- .../room/breadcrumbs/BreadcrumbsController.kt | 4 +- .../home/room/breadcrumbs/BreadcrumbsItem.kt | 15 +++--- .../home/room/detail/RoomDetailViewModel.kt | 18 ++----- .../home/room/list/RoomSummaryItem.kt | 27 +++++----- .../home/room/list/RoomSummaryItemFactory.kt | 5 +- .../features/home/room/typing/TypingHelper.kt | 50 ++++++------------- 11 files changed, 57 insertions(+), 100 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt index 6f21b9eeae..d26ca2dcc4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt @@ -19,6 +19,7 @@ package im.vector.matrix.android.api.session.room.model import im.vector.matrix.android.api.crypto.RoomEncryptionTrustLevel import im.vector.matrix.android.api.session.room.model.tag.RoomTag import im.vector.matrix.android.api.session.room.send.UserDraft +import im.vector.matrix.android.api.session.room.sender.SenderInfo import im.vector.matrix.android.api.session.room.timeline.TimelineEvent /** @@ -47,6 +48,7 @@ data class RoomSummary constructor( val userDrafts: List = emptyList(), val isEncrypted: Boolean, val encryptionEventTs: Long?, + val typingUsers: List, val inviterId: String? = null, val breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS, val roomEncryptionTrustLevel: RoomEncryptionTrustLevel? = null diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/typing/TypingUsersTracker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/typing/TypingUsersTracker.kt index 642541fd2f..c85b3354d9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/typing/TypingUsersTracker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/typing/TypingUsersTracker.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.api.session.typing -import androidx.lifecycle.LiveData import im.vector.matrix.android.api.session.room.sender.SenderInfo /** @@ -30,8 +29,4 @@ interface TypingUsersTracker { */ fun getTypingUsers(roomId: String): List - /** - * Returns a LiveData of the sender information of all currently typing users in a room, excluding yourself. - */ - fun getTypingUsersLive(roomId: String): LiveData> } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt index d7bc0a17ae..d266570432 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt @@ -19,9 +19,11 @@ package im.vector.matrix.android.internal.database.mapper import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.tag.RoomTag import im.vector.matrix.android.internal.database.model.RoomSummaryEntity +import im.vector.matrix.android.internal.session.typing.DefaultTypingUsersTracker import javax.inject.Inject -internal class RoomSummaryMapper @Inject constructor(private val timelineEventMapper: TimelineEventMapper) { +internal class RoomSummaryMapper @Inject constructor(private val timelineEventMapper: TimelineEventMapper, + private val typingUsersTracker: DefaultTypingUsersTracker) { fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary { val tags = roomSummaryEntity.tags.map { @@ -31,6 +33,8 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa val latestEvent = roomSummaryEntity.latestPreviewableEvent?.let { timelineEventMapper.map(it, buildReadReceipts = false) } + // typings are updated through the sync where room summary entity gets updated no matter what, so it's ok get there + val typingUsers = typingUsersTracker.getTypingUsers(roomSummaryEntity.roomId) return RoomSummary( roomId = roomSummaryEntity.roomId, @@ -46,6 +50,7 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa notificationCount = roomSummaryEntity.notificationCount, hasUnreadMessages = roomSummaryEntity.hasUnreadMessages, tags = tags, + typingUsers = typingUsers, membership = roomSummaryEntity.membership, versioningState = roomSummaryEntity.versioningState, readMarkerId = roomSummaryEntity.readMarkerId, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt index b1dc9c07f1..d17294a967 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt @@ -202,10 +202,6 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, return } state = newState - // We clear typing users if the sync is not running - if (newState !is SyncState.Running) { - typingUsersTracker.clear() - } debouncer.debounce("post_state", Runnable { liveState.value = newState }, 150) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/typing/DefaultTypingUsersTracker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/typing/DefaultTypingUsersTracker.kt index 1aab39b412..a2df64e910 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/typing/DefaultTypingUsersTracker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/typing/DefaultTypingUsersTracker.kt @@ -16,8 +16,6 @@ package im.vector.matrix.android.internal.session.typing -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import im.vector.matrix.android.api.session.room.sender.SenderInfo import im.vector.matrix.android.api.session.typing.TypingUsersTracker import im.vector.matrix.android.internal.session.SessionScope @@ -27,7 +25,6 @@ import javax.inject.Inject internal class DefaultTypingUsersTracker @Inject constructor() : TypingUsersTracker { private val typingUsers = mutableMapOf>() - private val typingUsersLiveData = mutableMapOf>>() /** * Set all currently typing users for a room (excluding yourself) @@ -36,27 +33,10 @@ internal class DefaultTypingUsersTracker @Inject constructor() : TypingUsersTrac val hasNewValue = typingUsers[roomId] != senderInfoList if (hasNewValue) { typingUsers[roomId] = senderInfoList - typingUsersLiveData[roomId]?.postValue(senderInfoList) - } - } - - /** - * Can be called when there is no sync so you don't get stuck with ephemeral data - */ - fun clear() { - val roomIds = typingUsers.keys - roomIds.forEach { - setTypingUsersFromRoom(it, emptyList()) } } override fun getTypingUsers(roomId: String): List { return typingUsers[roomId] ?: emptyList() } - - override fun getTypingUsersLive(roomId: String): LiveData> { - return typingUsersLiveData.getOrPut(roomId) { - MutableLiveData(getTypingUsers(roomId)) - } - } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt index 3a7dfd0033..df0f0845b5 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt @@ -22,11 +22,9 @@ import im.vector.matrix.android.api.util.toMatrixItem import im.vector.riotx.core.epoxy.zeroItem import im.vector.riotx.core.utils.DebouncedClickListener import im.vector.riotx.features.home.AvatarRenderer -import im.vector.riotx.features.home.room.typing.TypingHelper import javax.inject.Inject class BreadcrumbsController @Inject constructor( - private val typingHelper: TypingHelper, private val avatarRenderer: AvatarRenderer ) : EpoxyController() { @@ -59,12 +57,12 @@ class BreadcrumbsController @Inject constructor( ?.forEach { breadcrumbsItem { id(it.roomId) + hasTypingUsers(it.typingUsers.isNotEmpty()) avatarRenderer(avatarRenderer) matrixItem(it.toMatrixItem()) unreadNotificationCount(it.notificationCount) showHighlighted(it.highlightCount > 0) hasUnreadMessage(it.hasUnreadMessages) - typingHelper(typingHelper) hasDraft(it.userDrafts.isNotEmpty()) itemClickListener( DebouncedClickListener(View.OnClickListener { _ -> diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsItem.kt index ef75ac8de9..3e97c6103c 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsItem.kt @@ -26,22 +26,20 @@ import im.vector.matrix.android.api.util.MatrixItem import im.vector.riotx.R import im.vector.riotx.core.epoxy.VectorEpoxyHolder import im.vector.riotx.core.epoxy.VectorEpoxyModel -import im.vector.riotx.core.extensions.observeNotNull import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.room.list.UnreadCounterBadgeView -import im.vector.riotx.features.home.room.typing.TypingHelper @EpoxyModelClass(layout = R.layout.item_breadcrumbs) abstract class BreadcrumbsItem : VectorEpoxyModel() { - @EpoxyAttribute lateinit var typingHelper: TypingHelper + @EpoxyAttribute var hasTypingUsers: Boolean = false @EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer @EpoxyAttribute lateinit var matrixItem: MatrixItem @EpoxyAttribute var unreadNotificationCount: Int = 0 @EpoxyAttribute var showHighlighted: Boolean = false @EpoxyAttribute var hasUnreadMessage: Boolean = false @EpoxyAttribute var hasDraft: Boolean = false - @EpoxyAttribute var itemClickListener: View.OnClickListener? = null + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemClickListener: View.OnClickListener? = null override fun bind(holder: Holder) { super.bind(holder) @@ -50,9 +48,12 @@ abstract class BreadcrumbsItem : VectorEpoxyModel() { avatarRenderer.render(matrixItem, holder.avatarImageView) holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted)) holder.draftIndentIndicator.isVisible = hasDraft - typingHelper.hasTypingUsers(matrixItem.id).observeNotNull(this) { hasTypingUsers -> - holder.typingIndicator.isVisible = hasTypingUsers - } + holder.typingIndicator.isVisible = hasTypingUsers + } + + override fun unbind(holder: Holder) { + holder.rootView.setOnClickListener(null) + super.unbind(holder) } class Holder : VectorEpoxyHolder() { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 3e8949e94c..941dfb370a 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -58,7 +58,6 @@ import im.vector.matrix.android.api.session.room.timeline.getTextEditableContent import im.vector.matrix.android.api.util.toOptional import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent -import im.vector.matrix.rx.asObservable import im.vector.matrix.rx.rx import im.vector.matrix.rx.unwrap import im.vector.riotx.R @@ -97,12 +96,12 @@ class RoomDetailViewModel @AssistedInject constructor( userPreferencesProvider: UserPreferencesProvider, private val vectorPreferences: VectorPreferences, private val stringProvider: StringProvider, - private val typingHelper: TypingHelper, private val rainbowGenerator: RainbowGenerator, private val session: Session, private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider, private val stickerPickerActionHandler: StickerPickerActionHandler, private val roomSummaryHolder: RoomSummaryHolder, + private val typingHelper: TypingHelper, private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager ) : VectorViewModel(initialState), Timeline.Listener { @@ -166,7 +165,6 @@ class RoomDetailViewModel @AssistedInject constructor( observeSummaryState() getUnreadState() observeSyncState() - observeTypings() observeEventDisplayedActions() observeDrafts() observeUnreadState() @@ -1043,15 +1041,6 @@ class RoomDetailViewModel @AssistedInject constructor( } } - private fun observeTypings() { - typingHelper.getTypingMessage(initialState.roomId) - .asObservable() - .subscribe { - setState { copy(typingMessage = it) } - } - .disposeOnClear() - } - private fun getUnreadState() { Observable .combineLatest, RoomSummary, UnreadState>( @@ -1109,8 +1098,11 @@ class RoomDetailViewModel @AssistedInject constructor( private fun observeSummaryState() { asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary -> - roomSummaryHolder.set(summary) + setState { + val typingMessage = typingHelper.getTypingMessage(summary.typingUsers) + copy(typingMessage = typingMessage) + } if (summary.membership == Membership.INVITE) { summary.inviterId?.let { inviterId -> session.getUser(inviterId) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItem.kt index f918b81d3e..04193dba0d 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItem.kt @@ -32,28 +32,28 @@ import im.vector.matrix.android.api.util.MatrixItem import im.vector.riotx.R import im.vector.riotx.core.epoxy.VectorEpoxyHolder import im.vector.riotx.core.epoxy.VectorEpoxyModel -import im.vector.riotx.core.extensions.observeK import im.vector.riotx.core.extensions.setTextOrHide import im.vector.riotx.features.crypto.util.toImageRes import im.vector.riotx.features.home.AvatarRenderer -import im.vector.riotx.features.home.room.typing.TypingHelper -import timber.log.Timber @EpoxyModelClass(layout = R.layout.item_room) abstract class RoomSummaryItem : VectorEpoxyModel() { - @EpoxyAttribute lateinit var typingHelper: TypingHelper + @EpoxyAttribute lateinit var typingMessage: CharSequence @EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer @EpoxyAttribute lateinit var matrixItem: MatrixItem - @EpoxyAttribute lateinit var lastFormattedEvent: CharSequence + // Used only for diff calculation + @EpoxyAttribute lateinit var lastEvent: String + // We use DoNotHash here as Spans are not implementing equals/hashcode + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) lateinit var lastFormattedEvent: CharSequence @EpoxyAttribute lateinit var lastEventTime: CharSequence @EpoxyAttribute var encryptionTrustLevel: RoomEncryptionTrustLevel? = null @EpoxyAttribute var unreadNotificationCount: Int = 0 @EpoxyAttribute var hasUnreadMessage: Boolean = false @EpoxyAttribute var hasDraft: Boolean = false @EpoxyAttribute var showHighlighted: Boolean = false - @EpoxyAttribute var itemLongClickListener: View.OnLongClickListener? = null - @EpoxyAttribute var itemClickListener: View.OnClickListener? = null + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemLongClickListener: View.OnLongClickListener? = null + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemClickListener: View.OnClickListener? = null @EpoxyAttribute var showSelected: Boolean = false override fun bind(holder: Holder) { @@ -73,11 +73,14 @@ abstract class RoomSummaryItem : VectorEpoxyModel() { holder.roomAvatarDecorationImageView.isVisible = encryptionTrustLevel != null holder.roomAvatarDecorationImageView.setImageResource(encryptionTrustLevel.toImageRes()) renderSelection(holder, showSelected) - typingHelper.getTypingMessage(matrixItem.id).observeK(this) { - Timber.v("Observe typing for room ${matrixItem.id}: $it") - holder.typingView.setTextOrHide(it) - holder.lastEventView.isInvisible = holder.typingView.isVisible - } + holder.typingView.setTextOrHide(typingMessage) + holder.lastEventView.isInvisible = holder.typingView.isVisible + } + + override fun unbind(holder: Holder) { + holder.rootView.setOnClickListener(null) + holder.rootView.setOnLongClickListener(null) + super.unbind(holder) } private fun renderSelection(holder: Holder, isSelected: Boolean) { 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 1cd798d3a3..d9381b6546 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,6 +30,7 @@ import im.vector.riotx.core.utils.DebouncedClickListener import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.room.detail.timeline.format.DisplayableEventFormatter import im.vector.riotx.features.home.room.typing.TypingHelper +import timber.log.Timber import javax.inject.Inject class RoomSummaryItemFactory @Inject constructor(private val displayableEventFormatter: DisplayableEventFormatter, @@ -102,13 +103,15 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor dateFormatter.formatMessageDay(date) } } + val typingMessage = typingHelper.getTypingMessage(roomSummary.typingUsers) return RoomSummaryItem_() .id(roomSummary.roomId) .avatarRenderer(avatarRenderer) .encryptionTrustLevel(roomSummary.roomEncryptionTrustLevel) .matrixItem(roomSummary.toMatrixItem()) .lastEventTime(latestEventTime) - .typingHelper(typingHelper) + .typingMessage(typingMessage) + .lastEvent(latestFormattedEvent.toString()) .lastFormattedEvent(latestFormattedEvent) .showHighlighted(showHighlighted) .showSelected(showSelected) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/typing/TypingHelper.kt b/vector/src/main/java/im/vector/riotx/features/home/room/typing/TypingHelper.kt index 0c6960551c..b47a0a471e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/typing/TypingHelper.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/typing/TypingHelper.kt @@ -16,48 +16,30 @@ package im.vector.riotx.features.home.room.typing -import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations -import im.vector.matrix.android.api.session.Session +import im.vector.matrix.android.api.session.room.sender.SenderInfo import im.vector.riotx.R import im.vector.riotx.core.resources.StringProvider import javax.inject.Inject -class TypingHelper @Inject constructor( - private val session: Session, - private val stringProvider: StringProvider -) { - - /** - * Return true if some users are currently typing in the room (excluding yourself). - */ - fun hasTypingUsers(roomId: String): LiveData { - val liveData = session.typingUsersTracker().getTypingUsersLive(roomId) - return Transformations.map(liveData) { - it.isNotEmpty() - } - } +class TypingHelper @Inject constructor(private val stringProvider: StringProvider) { /** * Returns a human readable String of currently typing users in the room (excluding yourself). */ - fun getTypingMessage(roomId: String): LiveData { - val liveData = session.typingUsersTracker().getTypingUsersLive(roomId) - return Transformations.map(liveData) { typingUsers -> - when { - typingUsers.isEmpty() -> - "" - typingUsers.size == 1 -> - stringProvider.getString(R.string.room_one_user_is_typing, typingUsers[0].disambiguatedDisplayName) - typingUsers.size == 2 -> - stringProvider.getString(R.string.room_two_users_are_typing, - typingUsers[0].disambiguatedDisplayName, - typingUsers[1].disambiguatedDisplayName) - else -> - stringProvider.getString(R.string.room_many_users_are_typing, - typingUsers[0].disambiguatedDisplayName, - typingUsers[1].disambiguatedDisplayName) - } + fun getTypingMessage(typingUsers: List): String { + return when { + typingUsers.isEmpty() -> + "" + typingUsers.size == 1 -> + stringProvider.getString(R.string.room_one_user_is_typing, typingUsers[0].disambiguatedDisplayName) + typingUsers.size == 2 -> + stringProvider.getString(R.string.room_two_users_are_typing, + typingUsers[0].disambiguatedDisplayName, + typingUsers[1].disambiguatedDisplayName) + else -> + stringProvider.getString(R.string.room_many_users_are_typing, + typingUsers[0].disambiguatedDisplayName, + typingUsers[1].disambiguatedDisplayName) } } } From 7e703e47885c4c6573e049bd0ee0c21cd757b278 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 29 Jun 2020 15:05:21 +0200 Subject: [PATCH 2/3] Epoxy: optimize some hashcode in timeline --- .../detail/timeline/MessageColorProvider.kt | 6 ++++ .../helper/MessageInformationDataFactory.kt | 7 ++-- .../timeline/item/AbsBaseMessageItem.kt | 1 + .../detail/timeline/item/AbsMessageItem.kt | 33 ++++++++++++++++++- .../detail/timeline/item/BaseEventItem.kt | 4 ++- .../detail/timeline/item/MessageFileItem.kt | 2 +- .../timeline/item/MessageImageVideoItem.kt | 4 ++- .../detail/timeline/item/MessageTextItem.kt | 2 +- 8 files changed, 49 insertions(+), 10 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/MessageColorProvider.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/MessageColorProvider.kt index c6ab5b024f..96f7885e5d 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/MessageColorProvider.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/MessageColorProvider.kt @@ -20,6 +20,7 @@ import androidx.annotation.ColorInt import im.vector.matrix.android.api.session.room.send.SendState import im.vector.riotx.R import im.vector.riotx.core.resources.ColorProvider +import im.vector.riotx.core.utils.getColorFromUserId import im.vector.riotx.features.settings.VectorPreferences import javax.inject.Inject @@ -27,6 +28,11 @@ class MessageColorProvider @Inject constructor( private val colorProvider: ColorProvider, private val vectorPreferences: VectorPreferences) { + @ColorInt + fun getMemberNameTextColor(userId: String): Int { + return colorProvider.getColor(getColorFromUserId(userId)) + } + @ColorInt fun getMessageTextColor(sendState: SendState): Int { return if (vectorPreferences.developerMode()) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index 06c9544881..b976cd4140 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -71,11 +71,8 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses || isTileTypeMessage(nextEvent) val time = dateFormatter.formatMessageHour(date) - val formattedMemberName = span(event.senderInfo.disambiguatedDisplayName) { - textColor = colorProvider.getColor(getColorFromUserId(event.root.senderId)) - } - val e2eDecoration = getE2EDecoration(event) + return MessageInformationData( eventId = eventId, senderId = event.root.senderId ?: "", @@ -83,7 +80,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses time = time, ageLocalTS = event.root.ageLocalTs, avatarUrl = event.senderInfo.avatarUrl, - memberName = formattedMemberName, + memberName = event.senderInfo.disambiguatedDisplayName, showInformation = showInformation, orderedReactionList = event.annotations?.reactionsSummary // ?.filter { isSingleEmoji(it.key) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsBaseMessageItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsBaseMessageItem.kt index e62de05518..0845b9059c 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsBaseMessageItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsBaseMessageItem.kt @@ -109,6 +109,7 @@ abstract class AbsBaseMessageItem : BaseEventItem } override fun unbind(holder: H) { + holder.reactionsContainer.setOnLongClickListener(null) holder.readReceiptsView.unbind() super.unbind(holder) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt index 2b01e915df..4f7828ddaf 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt @@ -61,6 +61,7 @@ abstract class AbsMessageItem : AbsBaseMessageItem holder.timeView.visibility = View.VISIBLE holder.timeView.text = attributes.informationData.time holder.memberNameView.text = attributes.informationData.memberName + holder.memberNameView.setTextColor(attributes.getMemberNameColor()) attributes.avatarRenderer.render(attributes.informationData.matrixItem, holder.avatarImageView) holder.avatarImageView.setOnLongClickListener(attributes.itemLongClickListener) holder.memberNameView.setOnLongClickListener(attributes.itemLongClickListener) @@ -75,6 +76,16 @@ abstract class AbsMessageItem : AbsBaseMessageItem } } + override fun unbind(holder: H) { + holder.avatarImageView.setOnClickListener(null) + holder.avatarImageView.setOnLongClickListener(null) + holder.memberNameView.setOnClickListener(null) + holder.memberNameView.setOnLongClickListener(null) + super.unbind(holder) + } + + private fun Attributes.getMemberNameColor() = messageColorProvider.getMemberNameTextColor(informationData.senderId) + abstract class Holder(@IdRes stubId: Int) : AbsBaseMessageItem.Holder(stubId) { val avatarImageView by bind(R.id.messageAvatarImageView) val memberNameView by bind(R.id.messageMemberNameView) @@ -96,5 +107,25 @@ abstract class AbsMessageItem : AbsBaseMessageItem val avatarCallback: TimelineEventController.AvatarCallback? = null, override val readReceiptsCallback: TimelineEventController.ReadReceiptsCallback? = null, val emojiTypeFace: Typeface? = null - ) : AbsBaseMessageItem.Attributes + ) : AbsBaseMessageItem.Attributes { + + // Have to override as it's used to diff epoxy items + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Attributes + + if (avatarSize != other.avatarSize) return false + if (informationData != other.informationData) return false + + return true + } + + override fun hashCode(): Int { + var result = avatarSize + result = 31 * result + informationData.hashCode() + return result + } + } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt index f674cfa0f4..6eacb034ac 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt @@ -28,6 +28,7 @@ import im.vector.riotx.core.epoxy.VectorEpoxyModel import im.vector.riotx.core.platform.CheckableView import im.vector.riotx.core.ui.views.ReadReceiptsView import im.vector.riotx.core.utils.DimensionConverter +import timber.log.Timber /** * Children must override getViewType() @@ -40,12 +41,13 @@ abstract class BaseEventItem : VectorEpoxyModel @EpoxyAttribute open var leftGuideline: Int = 0 - @EpoxyAttribute + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) lateinit var dimensionConverter: DimensionConverter @CallSuper override fun bind(holder: H) { super.bind(holder) + Timber.v("Bind event item with ids: ${getEventIds()}") holder.leftGuideline.updateLayoutParams { this.marginStart = leftGuideline } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageFileItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageFileItem.kt index 24a783a6d6..ea52df2bfb 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageFileItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageFileItem.kt @@ -36,7 +36,7 @@ abstract class MessageFileItem : AbsMessageItem() { @EpoxyAttribute @DrawableRes var iconRes: Int = 0 - @EpoxyAttribute + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var clickListener: View.OnClickListener? = null @EpoxyAttribute var izLocalFile = false diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageImageVideoItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageImageVideoItem.kt index 2fd46ddf12..779b132f2d 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageImageVideoItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageImageVideoItem.kt @@ -37,7 +37,7 @@ abstract class MessageImageVideoItem : AbsMessageItem() { var message: CharSequence? = null @EpoxyAttribute var useBigFont: Boolean = false - @EpoxyAttribute + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var movementMethod: MovementMethod? = null override fun bind(holder: Holder) { From 84c8f9d35100d9a7313e116d5acc407908945180 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 29 Jun 2020 16:08:45 +0200 Subject: [PATCH 3/3] Clean code --- .../matrix/android/api/session/typing/TypingUsersTracker.kt | 1 - .../detail/timeline/helper/MessageInformationDataFactory.kt | 4 +--- .../features/home/room/detail/timeline/item/BaseEventItem.kt | 2 -- .../riotx/features/home/room/list/RoomSummaryItemFactory.kt | 1 - 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/typing/TypingUsersTracker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/typing/TypingUsersTracker.kt index c85b3354d9..4d1f1a9c45 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/typing/TypingUsersTracker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/typing/TypingUsersTracker.kt @@ -28,5 +28,4 @@ interface TypingUsersTracker { * Returns the sender information of all currently typing users in a room, excluding yourself. */ fun getTypingUsers(roomId: String): List - } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index b976cd4140..44644fb942 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -33,14 +33,12 @@ import im.vector.matrix.android.internal.session.room.VerificationState import im.vector.riotx.core.date.VectorDateFormatter import im.vector.riotx.core.extensions.localDateTime import im.vector.riotx.core.resources.ColorProvider -import im.vector.riotx.core.utils.getColorFromUserId import im.vector.riotx.features.home.room.detail.timeline.item.E2EDecoration import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData import im.vector.riotx.features.home.room.detail.timeline.item.PollResponseData import im.vector.riotx.features.home.room.detail.timeline.item.ReactionInfoData import im.vector.riotx.features.home.room.detail.timeline.item.ReadReceiptData import im.vector.riotx.features.home.room.detail.timeline.item.ReferencesInfoData -import me.gujun.android.span.span import javax.inject.Inject /** @@ -72,7 +70,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses val time = dateFormatter.formatMessageHour(date) val e2eDecoration = getE2EDecoration(event) - + return MessageInformationData( eventId = eventId, senderId = event.root.senderId ?: "", diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt index 6eacb034ac..a8d465d8e0 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt @@ -28,7 +28,6 @@ import im.vector.riotx.core.epoxy.VectorEpoxyModel import im.vector.riotx.core.platform.CheckableView import im.vector.riotx.core.ui.views.ReadReceiptsView import im.vector.riotx.core.utils.DimensionConverter -import timber.log.Timber /** * Children must override getViewType() @@ -47,7 +46,6 @@ abstract class BaseEventItem : VectorEpoxyModel @CallSuper override fun bind(holder: H) { super.bind(holder) - Timber.v("Bind event item with ids: ${getEventIds()}") holder.leftGuideline.updateLayoutParams { this.marginStart = leftGuideline } 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 d9381b6546..1830899d80 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.utils.DebouncedClickListener import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.room.detail.timeline.format.DisplayableEventFormatter import im.vector.riotx.features.home.room.typing.TypingHelper -import timber.log.Timber import javax.inject.Inject class RoomSummaryItemFactory @Inject constructor(private val displayableEventFormatter: DisplayableEventFormatter,