From 099bf5a016b9a445331b402f8ea0723dacb79c62 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Fri, 29 Apr 2022 15:30:14 +0200 Subject: [PATCH] Fix stuck timeline for new messages Change-Id: Id560898844438d88194a7211cac6d4db9853bceb --- .../session/room/timeline/DefaultTimeline.kt | 21 +++++++++++++++++++ .../room/timeline/LoadTimelineStrategy.kt | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt index b7527f16bc..08d5c1a135 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt @@ -108,6 +108,7 @@ internal class DefaultTimeline(private val roomId: String, lightweightSettingsStorage = lightweightSettingsStorage, onEventsUpdated = this::sendSignalToPostSnapshot, onLimitedTimeline = this::onLimitedTimeline, + onLastForwardDeleted = this::onLastForwardDeleted, onNewTimelineEvents = this::onNewTimelineEvents ) @@ -317,12 +318,32 @@ internal class DefaultTimeline(private val roomId: String, private fun onLimitedTimeline() { timelineScope.launch { + Timber.i("onLimitedTimeline: load more backwards") initPaginationStates(null) loadMore(settings.initialSize, Timeline.Direction.BACKWARDS, false) postSnapshot() } } + private fun onLastForwardDeleted() { + timelineScope.launch { + // If we noticed before we don't have more to load, we want to re-try now. + // Since the last forward chunk got deleted, more may be available now using pagination. + if (hasMoreToLoad(Timeline.Direction.FORWARDS)) { + Timber.i("onLastForwardDeleted: no action necessary") + return@launch + } + Timber.i("onLastForwardDeleted: load more forwards") + //initPaginationStates(null) + updateState(Timeline.Direction.FORWARDS) { + it.copy(hasMoreToLoad = true) + } + loadMore(settings.initialSize, Timeline.Direction.FORWARDS, true) + postSnapshot() + } + } + + private suspend fun postSnapshot() { val snapshot = strategy.buildSnapshot() Timber.v("Post snapshot of ${snapshot.size} events") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt index a2056b9afd..380278a7f6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt @@ -104,6 +104,7 @@ internal class LoadTimelineStrategy( val lightweightSettingsStorage: LightweightSettingsStorage, val onEventsUpdated: (Boolean) -> Unit, val onLimitedTimeline: () -> Unit, + val onLastForwardDeleted: () -> Unit, val onNewTimelineEvents: (List) -> Unit ) @@ -111,6 +112,7 @@ internal class LoadTimelineStrategy( private var chunkEntity: RealmResults? = null private var timelineChunk: TimelineChunk? = null private var sendingEventCount: Int = 0 + private var lastForwardChunkEntity: RealmResults? = null private val chunkEntityListener = OrderedRealmCollectionChangeListener { _: RealmResults, changeSet: OrderedCollectionChangeSet -> // Can be call either when you open a permalink on an unknown event @@ -128,6 +130,14 @@ internal class LoadTimelineStrategy( } } + private val lastForwardChunkEntityListener = OrderedRealmCollectionChangeListener { _: RealmResults, changeSet: OrderedCollectionChangeSet -> + // When the last forward chunk changes and we had previously reached that, load forward again to avoid a stuck timeline + val shouldRebuildChunk = changeSet.deletions.isNotEmpty() + if (shouldRebuildChunk) { + dependencies.onLastForwardDeleted() + } + } + private val uiEchoManagerListener = object : UIEchoManager.Listener { override fun rebuildEvent(eventId: String, builder: (TimelineEvent) -> TimelineEvent?): Boolean { return timelineChunk?.rebuildEvent(eventId, builder, searchInNext = true, searchInPrev = true).orFalse() @@ -180,12 +190,16 @@ internal class LoadTimelineStrategy( it.addChangeListener(chunkEntityListener) timelineChunk = it.createTimelineChunk() } + lastForwardChunkEntity = getLastForwardChunkEntity(realm).also { + it.addChangeListener(lastForwardChunkEntityListener) + } } fun onStop() { dependencies.eventDecryptor.destroy() dependencies.timelineInput.listeners.remove(timelineInputListener) chunkEntity?.removeChangeListener(chunkEntityListener) + lastForwardChunkEntity?.removeChangeListener(lastForwardChunkEntityListener) sendingEventsDataSource.stop() timelineChunk?.close(closeNext = true, closePrev = true) getContextLatch?.cancel() @@ -194,6 +208,7 @@ internal class LoadTimelineStrategy( if (mode is Mode.Thread) { clearThreadChunkEntity(dependencies.realm.get(), mode.rootThreadEventId) } + lastForwardChunkEntity = null } suspend fun loadMore(count: Int, direction: Timeline.Direction, fetchOnServerIfNeeded: Boolean = true): LoadMoreResult { @@ -293,6 +308,12 @@ internal class LoadTimelineStrategy( } } + private fun getLastForwardChunkEntity(realm: Realm): RealmResults { + return ChunkEntity.where(realm, roomId) + .equalTo(ChunkEntityFields.IS_LAST_FORWARD, true) + .findAll() + } + private fun hasReachedLastForward(): Boolean { return timelineChunk?.hasReachedLastForward().orFalse() }