From 16d5be3ed556cfdea79b0c844a4d943de32ab580 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Mon, 23 Sep 2024 15:19:29 +0200 Subject: [PATCH] Fix pinned events banner reappearing when loading (#3519) * Fix pinned events banner reappearing when loading. Make the `RustTimelineItem.timelineItems` property a `SharedFlow` so we don't always incorrectly load an empty state by default. --- .../pinned/banner/PinnedMessagesBannerPresenter.kt | 3 +-- .../impl/pinned/list/PinnedMessagesListPresenter.kt | 2 -- .../impl/timeline/MatrixTimelineDiffProcessor.kt | 12 ++++++++---- .../libraries/matrix/impl/timeline/RustTimeline.kt | 8 +++++--- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt index 457e96c5b8..8a066d48d4 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt @@ -24,7 +24,6 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn @@ -106,7 +105,7 @@ class PinnedMessagesBannerPresenter @Inject constructor( } } - @OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class) + @OptIn(ExperimentalCoroutinesApi::class) @Composable private fun PinnedMessagesBannerItemsEffect( onItemsChange: (AsyncData>) -> Unit, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt index 9937d71097..38639644f4 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt @@ -41,7 +41,6 @@ import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn @@ -161,7 +160,6 @@ class PinnedMessagesListPresenter @AssistedInject constructor( } } - @OptIn(FlowPreview::class) @Composable private fun PinnedMessagesListEffect(onItemsChange: (AsyncData>) -> Unit) { val updatedOnItemsChange by rememberUpdatedState(onItemsChange) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessor.kt index a48817efa5..3ef330b309 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessor.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessor.kt @@ -11,7 +11,7 @@ import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import org.matrix.rustcomponents.sdk.TimelineChange @@ -20,7 +20,7 @@ import org.matrix.rustcomponents.sdk.TimelineItem import timber.log.Timber internal class MatrixTimelineDiffProcessor( - private val timelineItems: MutableStateFlow>, + private val timelineItems: MutableSharedFlow>, private val timelineItemFactory: MatrixTimelineItemMapper, ) { private val mutex = Mutex() @@ -47,9 +47,13 @@ internal class MatrixTimelineDiffProcessor( private suspend fun updateTimelineItems(block: MutableList.() -> Unit) = mutex.withLock { - val mutableTimelineItems = timelineItems.value.toMutableList() + val mutableTimelineItems = if (timelineItems.replayCache.isNotEmpty()) { + timelineItems.first().toMutableList() + } else { + mutableListOf() + } block(mutableTimelineItems) - timelineItems.value = mutableTimelineItems + timelineItems.tryEmit(mutableTimelineItems) } private fun MutableList.applyDiff(diff: TimelineDiff) { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt index 1fa43c4e7c..ea6b93b7fa 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt @@ -49,10 +49,12 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.getAndUpdate import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map @@ -88,8 +90,8 @@ class RustTimeline( private val initLatch = CompletableDeferred() private val isTimelineInitialized = MutableStateFlow(false) - private val _timelineItems: MutableStateFlow> = - MutableStateFlow(emptyList()) + private val _timelineItems: MutableSharedFlow> = + MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE) private val timelineEventContentMapper = TimelineEventContentMapper() private val inReplyToMapper = InReplyToMapper(timelineEventContentMapper) @@ -522,7 +524,7 @@ class RustTimeline( } override suspend fun loadReplyDetails(eventId: EventId): InReplyTo = withContext(dispatcher) { - val timelineItem = _timelineItems.value.firstOrNull { timelineItem -> + val timelineItem = _timelineItems.first().firstOrNull { timelineItem -> timelineItem is MatrixTimelineItem.Event && timelineItem.eventId == eventId } as? MatrixTimelineItem.Event