Browse Source

Timeline: use val instead of fun for flows

jonny/proxy
ganfra 1 year ago
parent
commit
3aa5cce8dc
  1. 16
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt
  2. 11
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt
  3. 4
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt
  4. 17
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt
  5. 17
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeMatrixTimeline.kt
  6. 6
      samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt

16
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt

@ -59,13 +59,8 @@ class TimelinePresenter @Inject constructor( @@ -59,13 +59,8 @@ class TimelinePresenter @Inject constructor(
var lastReadMarkerIndex by rememberSaveable { mutableStateOf(Int.MAX_VALUE) }
var lastReadMarkerId by rememberSaveable { mutableStateOf<EventId?>(null) }
val timelineItems = timelineItemsFactory
.flow()
.collectAsState()
val paginationState = timeline
.paginationState()
.collectAsState()
val timelineItems = timelineItemsFactory.collectItemsAsState()
val paginationState = timeline.paginationState.collectAsState()
fun handleEvents(event: TimelineEvents) {
when (event) {
@ -85,13 +80,8 @@ class TimelinePresenter @Inject constructor( @@ -85,13 +80,8 @@ class TimelinePresenter @Inject constructor(
LaunchedEffect(Unit) {
timeline
.timelineItems()
.timelineItems
.onEach(timelineItemsFactory::replaceWith)
.onEach { timelineItems ->
if (timelineItems.isEmpty()) {
loadMore(paginationState.value)
}
}
.launchIn(this)
}

11
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt

@ -16,6 +16,9 @@ @@ -16,6 +16,9 @@
package io.element.android.features.messages.impl.timeline.factories
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.recyclerview.widget.DiffUtil
import io.element.android.features.messages.impl.timeline.diff.CacheInvalidator
import io.element.android.features.messages.impl.timeline.diff.MatrixTimelineItemsDiffCallback
@ -27,11 +30,8 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers @@ -27,11 +30,8 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
@ -55,7 +55,10 @@ class TimelineItemsFactory @Inject constructor( @@ -55,7 +55,10 @@ class TimelineItemsFactory @Inject constructor(
private val lock = Mutex()
private val cacheInvalidator = CacheInvalidator(timelineItemsCache)
fun flow(): StateFlow<ImmutableList<TimelineItem>> = timelineItems.asStateFlow()
@Composable
fun collectItemsAsState(): State<ImmutableList<TimelineItem>> {
return timelineItems.collectAsState()
}
suspend fun replaceWith(
timelineItems: List<MatrixTimelineItem>,

4
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt

@ -27,8 +27,8 @@ interface MatrixTimeline { @@ -27,8 +27,8 @@ interface MatrixTimeline {
val canBackPaginate: Boolean
)
fun paginationState(): StateFlow<PaginationState>
fun timelineItems(): Flow<List<MatrixTimelineItem>>
val paginationState: StateFlow<PaginationState>
val timelineItems: Flow<List<MatrixTimelineItem>>
suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result<Unit>
suspend fun fetchDetailsForEvent(eventId: EventId): Result<Unit>

17
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt

@ -30,6 +30,7 @@ import kotlinx.coroutines.FlowPreview @@ -30,6 +30,7 @@ import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.PaginationOptions
@ -45,10 +46,10 @@ class RustMatrixTimeline( @@ -45,10 +46,10 @@ class RustMatrixTimeline(
private val coroutineDispatchers: CoroutineDispatchers,
) : MatrixTimeline {
private val timelineItems: MutableStateFlow<List<MatrixTimelineItem>> =
private val _timelineItems: MutableStateFlow<List<MatrixTimelineItem>> =
MutableStateFlow(emptyList())
private val paginationState = MutableStateFlow(
private val _paginationState = MutableStateFlow(
MatrixTimeline.PaginationState(canBackPaginate = true, isBackPaginating = false)
)
@ -64,19 +65,15 @@ class RustMatrixTimeline( @@ -64,19 +65,15 @@ class RustMatrixTimeline(
)
private val timelineDiffProcessor = MatrixTimelineDiffProcessor(
paginationState = paginationState,
timelineItems = timelineItems,
paginationState = _paginationState,
timelineItems = _timelineItems,
timelineItemFactory = timelineItemFactory,
)
override fun paginationState(): StateFlow<MatrixTimeline.PaginationState> {
return paginationState
}
override val paginationState: StateFlow<MatrixTimeline.PaginationState> = _paginationState.asStateFlow()
@OptIn(FlowPreview::class)
override fun timelineItems(): Flow<List<MatrixTimelineItem>> {
return timelineItems.sample(50)
}
override val timelineItems: Flow<List<MatrixTimelineItem>> = _timelineItems.sample(50)
internal suspend fun postItems(items: List<TimelineItem>) {
timelineDiffProcessor.postItems(items)

17
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeMatrixTimeline.kt

@ -23,33 +23,30 @@ import kotlinx.coroutines.delay @@ -23,33 +23,30 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.getAndUpdate
class FakeMatrixTimeline(
initialTimelineItems: List<MatrixTimelineItem> = emptyList(),
initialPaginationState: MatrixTimeline.PaginationState = MatrixTimeline.PaginationState(canBackPaginate = true, isBackPaginating = false)
) : MatrixTimeline {
private val paginationState: MutableStateFlow<MatrixTimeline.PaginationState> = MutableStateFlow(initialPaginationState)
private val timelineItems: MutableStateFlow<List<MatrixTimelineItem>> = MutableStateFlow(initialTimelineItems)
private val _paginationState: MutableStateFlow<MatrixTimeline.PaginationState> = MutableStateFlow(initialPaginationState)
private val _timelineItems: MutableStateFlow<List<MatrixTimelineItem>> = MutableStateFlow(initialTimelineItems)
var sendReadReceiptCount = 0
private set
fun updatePaginationState(update: (MatrixTimeline.PaginationState.() -> MatrixTimeline.PaginationState)) {
paginationState.value = update(paginationState.value)
_paginationState.getAndUpdate(update)
}
fun updateTimelineItems(update: (items: List<MatrixTimelineItem>) -> List<MatrixTimelineItem>) {
timelineItems.value = update(timelineItems.value)
_timelineItems.getAndUpdate(update)
}
override fun paginationState(): StateFlow<MatrixTimeline.PaginationState> {
return paginationState
}
override val paginationState: StateFlow<MatrixTimeline.PaginationState> = _paginationState
override fun timelineItems(): Flow<List<MatrixTimelineItem>> {
return timelineItems
}
override val timelineItems: Flow<List<MatrixTimelineItem>> = _timelineItems
override suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result<Unit> {
updatePaginationState {

6
samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt

@ -82,11 +82,7 @@ class RoomListScreen( @@ -82,11 +82,7 @@ class RoomListScreen(
withContext(coroutineDispatchers.io) {
matrixClient.getRoom(roomId)!!.use { room ->
room.open()
val timeline = room.timeline
timeline.apply {
// TODO This doesn't work reliably as initialize is asynchronous, and the timeline can't be used until it's finished
paginateBackwards(20, 50)
}
room.timeline.paginateBackwards(20, 50)
}
}
}

Loading…
Cancel
Save