Fix some issues with timeline cache invalidation and visibility.

This commit is contained in:
ganfra 2021-06-24 12:41:23 +02:00
parent 43a1e283c5
commit 919ebaa82e
4 changed files with 26 additions and 9 deletions

1
changelog.d/3542.bugfix Normal file
View File

@ -0,0 +1 @@
Fix some issues with timeline cache invalidation and visibility.

View File

@ -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.MergedHeaderItemFactory
import im.vector.app.features.home.room.detail.timeline.factory.ReadReceiptsItemFactory 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.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.ContentDownloadStateTrackerBinder
import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder 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.TimelineControllerInterceptorHelper
import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventDiffUtilCallback 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.TimelineEventVisibilityHelper
import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventVisibilityStateChangedListener 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.helper.TimelineMediaSizeProvider
import im.vector.app.features.home.room.detail.timeline.item.AbsMessageItem import im.vector.app.features.home.room.detail.timeline.item.AbsMessageItem
import im.vector.app.features.home.room.detail.timeline.item.BasedMergedItem 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?) { override fun onChanged(position: Int, count: Int, payload: Any?) {
synchronized(modelCache) { synchronized(modelCache) {
assertUpdateCallbacksAllowed() assertUpdateCallbacksAllowed()
(position until (position + count)).forEach { (position until position + count).forEach {
// Invalidate cache // Invalidate cache
modelCache[it] = null 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() requestModelBuild()
} }
} }
@ -209,6 +218,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
) )
init { init {
isDebugLoggingEnabled = true
addInterceptor(this) addInterceptor(this)
requestModelBuild() requestModelBuild()
} }
@ -340,10 +350,14 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
val event = currentSnapshot[position] val event = currentSnapshot[position]
val nextEvent = currentSnapshot.nextOrNull(position) val nextEvent = currentSnapshot.nextOrNull(position)
val prevEvent = currentSnapshot.prevOrNull(position) val prevEvent = currentSnapshot.prevOrNull(position)
val nextDisplayableEvent = currentSnapshot.subList(position + 1, currentSnapshot.size).firstOrNull {
timelineEventVisibilityHelper.shouldShowEvent(it, eventIdToHighlight)
}
val params = TimelineItemFactoryParams( val params = TimelineItemFactoryParams(
event = event, event = event,
prevEvent = prevEvent, prevEvent = prevEvent,
nextEvent = nextEvent, nextEvent = nextEvent,
nextDisplayableEvent = nextDisplayableEvent,
highlightedEventId = eventIdToHighlight, highlightedEventId = eventIdToHighlight,
lastSentEventIdWithoutReadReceipts = lastSentEventWithoutReadReceipts, lastSentEventIdWithoutReadReceipts = lastSentEventWithoutReadReceipts,
callback = callback callback = callback

View File

@ -23,6 +23,7 @@ data class TimelineItemFactoryParams(
val event: TimelineEvent, val event: TimelineEvent,
val prevEvent: TimelineEvent? = null, val prevEvent: TimelineEvent? = null,
val nextEvent: TimelineEvent? = null, val nextEvent: TimelineEvent? = null,
val nextDisplayableEvent: TimelineEvent? = null,
val highlightedEventId: String? = null, val highlightedEventId: String? = null,
val lastSentEventIdWithoutReadReceipts: String? = null, val lastSentEventIdWithoutReadReceipts: String? = null,
val callback: TimelineEventController.Callback? = null val callback: TimelineEventController.Callback? = null

View File

@ -50,27 +50,28 @@ import javax.inject.Inject
class MessageInformationDataFactory @Inject constructor(private val session: Session, class MessageInformationDataFactory @Inject constructor(private val session: Session,
private val roomSummariesHolder: RoomSummariesHolder, private val roomSummariesHolder: RoomSummariesHolder,
private val dateFormatter: VectorDateFormatter, private val dateFormatter: VectorDateFormatter,
private val visibilityHelper: TimelineEventVisibilityHelper,
private val vectorPreferences: VectorPreferences) { private val vectorPreferences: VectorPreferences) {
fun create(params: TimelineItemFactoryParams): MessageInformationData { fun create(params: TimelineItemFactoryParams): MessageInformationData {
val event = params.event val event = params.event
val nextEvent = params.nextEvent val nextDisplayableEvent = params.nextDisplayableEvent
val eventId = event.eventId val eventId = event.eventId
val date = event.root.localDateTime() val date = event.root.localDateTime()
val nextDate = nextEvent?.root?.localDateTime() val nextDate = nextDisplayableEvent?.root?.localDateTime()
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate() val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60)) val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
?: false ?: false
val showInformation = val showInformation =
addDaySeparator addDaySeparator
|| event.senderInfo.avatarUrl != nextEvent?.senderInfo?.avatarUrl || event.senderInfo.avatarUrl != nextDisplayableEvent?.senderInfo?.avatarUrl
|| event.senderInfo.disambiguatedDisplayName != nextEvent?.senderInfo?.disambiguatedDisplayName || event.senderInfo.disambiguatedDisplayName != nextDisplayableEvent?.senderInfo?.disambiguatedDisplayName
|| nextEvent.root.getClearType() !in listOf(EventType.MESSAGE, EventType.STICKER, EventType.ENCRYPTED) || nextDisplayableEvent.root.getClearType() !in listOf(EventType.MESSAGE, EventType.STICKER, EventType.ENCRYPTED)
|| isNextMessageReceivedMoreThanOneHourAgo || isNextMessageReceivedMoreThanOneHourAgo
|| isTileTypeMessage(nextEvent) || isTileTypeMessage(nextDisplayableEvent)
|| nextEvent.isEdition() || nextDisplayableEvent.isEdition()
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)