diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt index a7c0bef7c3..53ec9efccc 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt @@ -38,7 +38,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.getAndUpdate +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach @@ -80,7 +80,6 @@ class RustMatrixTimeline( lastLoginTimestamp = lastLoginTimestamp, isRoomEncrypted = matrixRoom.isEncrypted, isKeyBackupEnabled = isKeyBackupEnabled, - paginationStateFlow = _paginationState, dispatcher = dispatcher, ) @@ -115,9 +114,9 @@ class RustMatrixTimeline( postDiffs(diffs) }.launchIn(this) - innerTimeline.backPaginationStatusFlow() + paginationStateFlow() .onEach { - postPaginationStatus(it) + _paginationState.value = it } .launchIn(this) @@ -125,6 +124,44 @@ class RustMatrixTimeline( } } + private fun paginationStateFlow(): Flow { + return combine( + innerTimeline.backPaginationStatusFlow(), + timelineItems, + ) { paginationStatus, filteredItems -> + if (filteredItems.hasEncryptionHistoryBanner()) { + return@combine MatrixTimeline.PaginationState( + isBackPaginating = false, + hasMoreToLoadBackwards = false, + beginningOfRoomReached = false, + ) + } + when (paginationStatus) { + BackPaginationStatus.IDLE -> { + MatrixTimeline.PaginationState( + isBackPaginating = false, + hasMoreToLoadBackwards = true, + beginningOfRoomReached = false, + ) + } + BackPaginationStatus.PAGINATING -> { + MatrixTimeline.PaginationState( + isBackPaginating = true, + hasMoreToLoadBackwards = true, + beginningOfRoomReached = false, + ) + } + BackPaginationStatus.TIMELINE_START_REACHED -> { + MatrixTimeline.PaginationState( + isBackPaginating = false, + hasMoreToLoadBackwards = false, + beginningOfRoomReached = true, + ) + } + } + } + } + private suspend fun fetchMembers() = withContext(dispatcher) { initLatch.await() try { @@ -154,39 +191,6 @@ class RustMatrixTimeline( timelineDiffProcessor.postDiffs(diffs) } - private fun postPaginationStatus(status: BackPaginationStatus) { - _paginationState.getAndUpdate { currentPaginationState -> - if (hasEncryptionHistoryBanner()) { - return@getAndUpdate currentPaginationState.copy( - isBackPaginating = false, - hasMoreToLoadBackwards = false, - beginningOfRoomReached = false, - ) - } - when (status) { - BackPaginationStatus.IDLE -> { - currentPaginationState.copy( - isBackPaginating = false, - hasMoreToLoadBackwards = true - ) - } - BackPaginationStatus.PAGINATING -> { - currentPaginationState.copy( - isBackPaginating = true, - hasMoreToLoadBackwards = true - ) - } - BackPaginationStatus.TIMELINE_START_REACHED -> { - currentPaginationState.copy( - isBackPaginating = false, - hasMoreToLoadBackwards = false, - beginningOfRoomReached = true, - ) - } - } - } - } - override suspend fun fetchDetailsForEvent(eventId: EventId): Result = withContext(dispatcher) { runCatching { innerTimeline.fetchDetailsForEvent(eventId.value) @@ -251,8 +255,8 @@ class RustMatrixTimeline( return _timelineItems.value.firstOrNull { (it as? MatrixTimelineItem.Event)?.eventId == eventId } as? MatrixTimelineItem.Event } - private fun hasEncryptionHistoryBanner(): Boolean { - val firstItem = _timelineItems.value.firstOrNull() + private fun List.hasEncryptionHistoryBanner(): Boolean { + val firstItem = firstOrNull() return firstItem is MatrixTimelineItem.Virtual && firstItem.virtual is VirtualTimelineItem.EncryptedHistoryBanner } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessor.kt index 1a6b27203e..9c0fbfd115 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessor.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessor.kt @@ -16,12 +16,9 @@ package io.element.android.libraries.matrix.impl.timeline.postprocessor -import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.getAndUpdate import kotlinx.coroutines.withContext import timber.log.Timber import java.util.Date @@ -31,26 +28,12 @@ class TimelineEncryptedHistoryPostProcessor( private val lastLoginTimestamp: Date?, private val isRoomEncrypted: Boolean, private val isKeyBackupEnabled: Boolean, - private val paginationStateFlow: MutableStateFlow, ) { suspend fun process(items: List): List = withContext(dispatcher) { Timber.d("Process on Thread=${Thread.currentThread()}") if (!isRoomEncrypted || isKeyBackupEnabled || lastLoginTimestamp == null) return@withContext items - - val filteredItems = replaceWithEncryptionHistoryBannerIfNeeded(items) - // Disable back pagination - val wasFiltered = filteredItems !== items - if (wasFiltered) { - paginationStateFlow.getAndUpdate { - it.copy( - isBackPaginating = false, - hasMoreToLoadBackwards = false, - beginningOfRoomReached = false, - ) - } - } - filteredItems + replaceWithEncryptionHistoryBannerIfNeeded(items) } private fun replaceWithEncryptionHistoryBannerIfNeeded(list: List): List { diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt index ccfddba40a..29c8eca051 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt @@ -17,11 +17,9 @@ package io.element.android.libraries.matrix.impl.timeline.postprocessor import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest @@ -97,15 +95,8 @@ class TimelineEncryptedHistoryPostProcessorTest { } @Test - fun `given a list with several with lower or equal timestamps than lastLoginTimestamp, they're replaced and the user can't back paginate`() = runTest { - val paginationStateFlow = MutableStateFlow( - MatrixTimeline.PaginationState( - hasMoreToLoadBackwards = true, - isBackPaginating = false, - beginningOfRoomReached = false, - ) - ) - val processor = createPostProcessor(paginationStateFlow = paginationStateFlow) + fun `given a list with several with lower or equal timestamps than lastLoginTimestamp, then they're replaced`() = runTest { + val processor = createPostProcessor() val items = listOf( MatrixTimelineItem.Event("0L", anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time - 1)), MatrixTimelineItem.Event("0L", anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time)), @@ -117,32 +108,16 @@ class TimelineEncryptedHistoryPostProcessorTest { MatrixTimelineItem.Event("0L", anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time + 1)) ) ) - assertThat(paginationStateFlow.value).isEqualTo( - MatrixTimeline.PaginationState( - hasMoreToLoadBackwards = false, - isBackPaginating = false, - beginningOfRoomReached = false, - ) - ) } private fun TestScope.createPostProcessor( lastLoginTimestamp: Date? = defaultLastLoginTimestamp, isRoomEncrypted: Boolean = true, isKeyBackupEnabled: Boolean = false, - paginationStateFlow: MutableStateFlow = - MutableStateFlow( - MatrixTimeline.PaginationState( - hasMoreToLoadBackwards = true, - isBackPaginating = false, - beginningOfRoomReached = false, - ) - ) ) = TimelineEncryptedHistoryPostProcessor( lastLoginTimestamp = lastLoginTimestamp, isRoomEncrypted = isRoomEncrypted, isKeyBackupEnabled = isKeyBackupEnabled, - paginationStateFlow = paginationStateFlow, dispatcher = StandardTestDispatcher(testScheduler) ) }