diff --git a/changelog.d/3542.bugfix b/changelog.d/3542.bugfix new file mode 100644 index 0000000000..8e133e1e30 --- /dev/null +++ b/changelog.d/3542.bugfix @@ -0,0 +1 @@ +Fix some issues with timeline cache invalidation and visibility. \ No newline at end of file diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt index a0f87b9749..bbb1b7a06f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt @@ -39,13 +39,13 @@ import im.vector.app.features.home.room.detail.UnreadState import im.vector.app.features.home.room.detail.timeline.factory.MergedHeaderItemFactory import im.vector.app.features.home.room.detail.timeline.factory.ReadReceiptsItemFactory import im.vector.app.features.home.room.detail.timeline.factory.TimelineItemFactory +import im.vector.app.features.home.room.detail.timeline.factory.TimelineItemFactoryParams import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadStateTrackerBinder import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder import im.vector.app.features.home.room.detail.timeline.helper.TimelineControllerInterceptorHelper import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventDiffUtilCallback import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventVisibilityHelper import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventVisibilityStateChangedListener -import im.vector.app.features.home.room.detail.timeline.factory.TimelineItemFactoryParams import im.vector.app.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider import im.vector.app.features.home.room.detail.timeline.item.AbsMessageItem import im.vector.app.features.home.room.detail.timeline.item.BasedMergedItem @@ -163,10 +163,19 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec override fun onChanged(position: Int, count: Int, payload: Any?) { synchronized(modelCache) { assertUpdateCallbacksAllowed() - (position until (position + count)).forEach { + (position until position + count).forEach { // Invalidate cache modelCache[it] = null } + // Also invalidate the first previous displayable event if + // it's sent by the same user so we are sure we have up to date information. + val invalidatedSenderId: String? = currentSnapshot.getOrNull(position)?.senderInfo?.userId + val prevDisplayableEventIndex = currentSnapshot.subList(0, position).indexOfLast { + timelineEventVisibilityHelper.shouldShowEvent(it, eventIdToHighlight) + } + if (prevDisplayableEventIndex != -1 && currentSnapshot[prevDisplayableEventIndex].senderInfo.userId == invalidatedSenderId) { + modelCache[prevDisplayableEventIndex] = null + } requestModelBuild() } } @@ -209,6 +218,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec ) init { + isDebugLoggingEnabled = true addInterceptor(this) requestModelBuild() } @@ -340,10 +350,14 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec val event = currentSnapshot[position] val nextEvent = currentSnapshot.nextOrNull(position) val prevEvent = currentSnapshot.prevOrNull(position) + val nextDisplayableEvent = currentSnapshot.subList(position + 1, currentSnapshot.size).firstOrNull { + timelineEventVisibilityHelper.shouldShowEvent(it, eventIdToHighlight) + } val params = TimelineItemFactoryParams( event = event, prevEvent = prevEvent, nextEvent = nextEvent, + nextDisplayableEvent = nextDisplayableEvent, highlightedEventId = eventIdToHighlight, lastSentEventIdWithoutReadReceipts = lastSentEventWithoutReadReceipts, callback = callback diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactoryParams.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactoryParams.kt index f92cd2800a..0e595ba30e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactoryParams.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactoryParams.kt @@ -23,6 +23,7 @@ data class TimelineItemFactoryParams( val event: TimelineEvent, val prevEvent: TimelineEvent? = null, val nextEvent: TimelineEvent? = null, + val nextDisplayableEvent: TimelineEvent? = null, val highlightedEventId: String? = null, val lastSentEventIdWithoutReadReceipts: String? = null, val callback: TimelineEventController.Callback? = null diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index 124b196f72..221149aced 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -50,27 +50,28 @@ import javax.inject.Inject class MessageInformationDataFactory @Inject constructor(private val session: Session, private val roomSummariesHolder: RoomSummariesHolder, private val dateFormatter: VectorDateFormatter, + private val visibilityHelper: TimelineEventVisibilityHelper, private val vectorPreferences: VectorPreferences) { fun create(params: TimelineItemFactoryParams): MessageInformationData { val event = params.event - val nextEvent = params.nextEvent + val nextDisplayableEvent = params.nextDisplayableEvent val eventId = event.eventId val date = event.root.localDateTime() - val nextDate = nextEvent?.root?.localDateTime() + val nextDate = nextDisplayableEvent?.root?.localDateTime() val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate() val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60)) ?: false val showInformation = addDaySeparator - || event.senderInfo.avatarUrl != nextEvent?.senderInfo?.avatarUrl - || event.senderInfo.disambiguatedDisplayName != nextEvent?.senderInfo?.disambiguatedDisplayName - || nextEvent.root.getClearType() !in listOf(EventType.MESSAGE, EventType.STICKER, EventType.ENCRYPTED) + || event.senderInfo.avatarUrl != nextDisplayableEvent?.senderInfo?.avatarUrl + || event.senderInfo.disambiguatedDisplayName != nextDisplayableEvent?.senderInfo?.disambiguatedDisplayName + || nextDisplayableEvent.root.getClearType() !in listOf(EventType.MESSAGE, EventType.STICKER, EventType.ENCRYPTED) || isNextMessageReceivedMoreThanOneHourAgo - || isTileTypeMessage(nextEvent) - || nextEvent.isEdition() + || isTileTypeMessage(nextDisplayableEvent) + || nextDisplayableEvent.isEdition() val time = dateFormatter.format(event.root.originServerTs, DateFormatKind.MESSAGE_SIMPLE) val e2eDecoration = getE2EDecoration(event)