Browse Source

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.
pull/3525/head
Jorge Martin Espinosa 4 weeks ago committed by GitHub
parent
commit
16d5be3ed5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt
  2. 2
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt
  3. 12
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessor.kt
  4. 8
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt

3
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.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,

2
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 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)

12
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 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) {

8
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.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

Loading…
Cancel
Save