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.
This commit is contained in:
Jorge Martin Espinosa 2024-09-23 15:19:29 +02:00 committed by GitHub
parent 60db5fb8e7
commit 103627d6ad
4 changed files with 14 additions and 11 deletions

View file

@ -24,7 +24,6 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -106,7 +105,7 @@ class PinnedMessagesBannerPresenter @Inject constructor(
} }
} }
@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@Composable @Composable
private fun PinnedMessagesBannerItemsEffect( private fun PinnedMessagesBannerItemsEffect(
onItemsChange: (AsyncData<ImmutableList<PinnedMessagesBannerItem>>) -> Unit, onItemsChange: (AsyncData<ImmutableList<PinnedMessagesBannerItem>>) -> Unit,

View file

@ -41,7 +41,6 @@ import io.element.android.libraries.matrix.api.room.roomMembers
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -161,7 +160,6 @@ class PinnedMessagesListPresenter @AssistedInject constructor(
} }
} }
@OptIn(FlowPreview::class)
@Composable @Composable
private fun PinnedMessagesListEffect(onItemsChange: (AsyncData<ImmutableList<TimelineItem>>) -> Unit) { private fun PinnedMessagesListEffect(onItemsChange: (AsyncData<ImmutableList<TimelineItem>>) -> Unit) {
val updatedOnItemsChange by rememberUpdatedState(onItemsChange) val updatedOnItemsChange by rememberUpdatedState(onItemsChange)

View file

@ -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 io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import org.matrix.rustcomponents.sdk.TimelineChange import org.matrix.rustcomponents.sdk.TimelineChange
@ -20,7 +20,7 @@ import org.matrix.rustcomponents.sdk.TimelineItem
import timber.log.Timber import timber.log.Timber
internal class MatrixTimelineDiffProcessor( internal class MatrixTimelineDiffProcessor(
private val timelineItems: MutableStateFlow<List<MatrixTimelineItem>>, private val timelineItems: MutableSharedFlow<List<MatrixTimelineItem>>,
private val timelineItemFactory: MatrixTimelineItemMapper, private val timelineItemFactory: MatrixTimelineItemMapper,
) { ) {
private val mutex = Mutex() private val mutex = Mutex()
@ -47,9 +47,13 @@ internal class MatrixTimelineDiffProcessor(
private suspend fun updateTimelineItems(block: MutableList<MatrixTimelineItem>.() -> Unit) = private suspend fun updateTimelineItems(block: MutableList<MatrixTimelineItem>.() -> Unit) =
mutex.withLock { mutex.withLock {
val mutableTimelineItems = timelineItems.value.toMutableList() val mutableTimelineItems = if (timelineItems.replayCache.isNotEmpty()) {
timelineItems.first().toMutableList()
} else {
mutableListOf()
}
block(mutableTimelineItems) block(mutableTimelineItems)
timelineItems.value = mutableTimelineItems timelineItems.tryEmit(mutableTimelineItems)
} }
private fun MutableList<MatrixTimelineItem>.applyDiff(diff: TimelineDiff) { private fun MutableList<MatrixTimelineItem>.applyDiff(diff: TimelineDiff) {

View file

@ -49,10 +49,12 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.getAndUpdate import kotlinx.coroutines.flow.getAndUpdate
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
@ -88,8 +90,8 @@ class RustTimeline(
private val initLatch = CompletableDeferred<Unit>() private val initLatch = CompletableDeferred<Unit>()
private val isTimelineInitialized = MutableStateFlow(false) private val isTimelineInitialized = MutableStateFlow(false)
private val _timelineItems: MutableStateFlow<List<MatrixTimelineItem>> = private val _timelineItems: MutableSharedFlow<List<MatrixTimelineItem>> =
MutableStateFlow(emptyList()) MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
private val timelineEventContentMapper = TimelineEventContentMapper() private val timelineEventContentMapper = TimelineEventContentMapper()
private val inReplyToMapper = InReplyToMapper(timelineEventContentMapper) private val inReplyToMapper = InReplyToMapper(timelineEventContentMapper)
@ -522,7 +524,7 @@ class RustTimeline(
} }
override suspend fun loadReplyDetails(eventId: EventId): InReplyTo = withContext(dispatcher) { 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 timelineItem is MatrixTimelineItem.Event && timelineItem.eventId == eventId
} as? MatrixTimelineItem.Event } as? MatrixTimelineItem.Event