Merge pull request #863 from vector-im/feature/fga/timeline_pagination
Feature/fga/timeline pagination
This commit is contained in:
commit
732a4eb5fa
9 changed files with 61 additions and 30 deletions
|
|
@ -17,7 +17,6 @@
|
|||
package io.element.android.libraries.matrix.impl.timeline
|
||||
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
|
@ -30,20 +29,16 @@ internal class MatrixTimelineDiffProcessor(
|
|||
private val timelineItemFactory: MatrixTimelineItemMapper,
|
||||
) {
|
||||
|
||||
private val initLatch = CompletableDeferred<Unit>()
|
||||
private val mutex = Mutex()
|
||||
|
||||
suspend fun postItems(items: List<TimelineItem>) {
|
||||
updateTimelineItems {
|
||||
val mappedItems = items.map { it.asMatrixTimelineItem() }
|
||||
addAll(mappedItems)
|
||||
addAll(0, mappedItems)
|
||||
}
|
||||
initLatch.complete(Unit)
|
||||
}
|
||||
|
||||
suspend fun postDiff(diff: TimelineDiff) {
|
||||
// Makes sure to process first items before diff.
|
||||
initLatch.await()
|
||||
updateTimelineItems {
|
||||
applyDiff(diff)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,12 @@ import io.element.android.libraries.matrix.api.core.EventId
|
|||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
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.TimelineException
|
||||
import io.element.android.libraries.matrix.impl.timeline.item.event.EventMessageMapper
|
||||
import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper
|
||||
import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper
|
||||
import io.element.android.libraries.matrix.impl.timeline.item.virtual.VirtualTimelineItemMapper
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
|
|
@ -40,6 +42,9 @@ import org.matrix.rustcomponents.sdk.Room
|
|||
import org.matrix.rustcomponents.sdk.TimelineDiff
|
||||
import org.matrix.rustcomponents.sdk.TimelineItem
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
private const val INITIAL_MAX_SIZE = 50
|
||||
|
||||
class RustMatrixTimeline(
|
||||
roomCoroutineScope: CoroutineScope,
|
||||
|
|
@ -48,11 +53,14 @@ class RustMatrixTimeline(
|
|||
private val dispatcher: CoroutineDispatcher,
|
||||
) : MatrixTimeline {
|
||||
|
||||
private val initLatch = CompletableDeferred<Unit>()
|
||||
private val isInit = AtomicBoolean(false)
|
||||
|
||||
private val _timelineItems: MutableStateFlow<List<MatrixTimelineItem>> =
|
||||
MutableStateFlow(emptyList())
|
||||
|
||||
private val _paginationState = MutableStateFlow(
|
||||
MatrixTimeline.PaginationState(canBackPaginate = true, isBackPaginating = false)
|
||||
MatrixTimeline.PaginationState(hasMoreToLoadBackwards = true, isBackPaginating = false)
|
||||
)
|
||||
|
||||
private val timelineItemFactory = MatrixTimelineItemMapper(
|
||||
|
|
@ -77,10 +85,16 @@ class RustMatrixTimeline(
|
|||
override val timelineItems: Flow<List<MatrixTimelineItem>> = _timelineItems.sample(50)
|
||||
|
||||
internal suspend fun postItems(items: List<TimelineItem>) {
|
||||
timelineDiffProcessor.postItems(items)
|
||||
// Split the initial items in multiple list as there is no pagination in the cached data, so we can post timelineItems asap.
|
||||
items.chunked(INITIAL_MAX_SIZE).reversed().forEach {
|
||||
timelineDiffProcessor.postItems(it)
|
||||
}
|
||||
isInit.set(true)
|
||||
initLatch.complete(Unit)
|
||||
}
|
||||
|
||||
internal suspend fun postDiff(timelineDiff: TimelineDiff) {
|
||||
initLatch.await()
|
||||
timelineDiffProcessor.postDiff(timelineDiff)
|
||||
}
|
||||
|
||||
|
|
@ -90,19 +104,19 @@ class RustMatrixTimeline(
|
|||
BackPaginationStatus.IDLE -> {
|
||||
currentPaginationState.copy(
|
||||
isBackPaginating = false,
|
||||
canBackPaginate = true
|
||||
hasMoreToLoadBackwards = true
|
||||
)
|
||||
}
|
||||
BackPaginationStatus.PAGINATING -> {
|
||||
currentPaginationState.copy(
|
||||
isBackPaginating = true,
|
||||
canBackPaginate = true
|
||||
hasMoreToLoadBackwards = true
|
||||
)
|
||||
}
|
||||
BackPaginationStatus.TIMELINE_START_REACHED -> {
|
||||
currentPaginationState.copy(
|
||||
isBackPaginating = false,
|
||||
canBackPaginate = false
|
||||
hasMoreToLoadBackwards = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -117,6 +131,7 @@ class RustMatrixTimeline(
|
|||
|
||||
override suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result<Unit> = withContext(dispatcher) {
|
||||
runCatching {
|
||||
if (!canBackPaginate()) throw TimelineException.CannotPaginate
|
||||
Timber.v("Start back paginating for room ${matrixRoom.roomId} ")
|
||||
val paginationOptions = PaginationOptions.UntilNumItems(
|
||||
eventLimit = requestSize.toUShort(),
|
||||
|
|
@ -125,12 +140,16 @@ class RustMatrixTimeline(
|
|||
)
|
||||
innerRoom.paginateBackwards(paginationOptions)
|
||||
}.onFailure {
|
||||
Timber.e(it, "Fail to paginate for room ${matrixRoom.roomId}")
|
||||
Timber.d(it, "Fail to paginate for room ${matrixRoom.roomId}")
|
||||
}.onSuccess {
|
||||
Timber.v("Success back paginating for room ${matrixRoom.roomId}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun canBackPaginate(): Boolean {
|
||||
return isInit.get() && paginationState.value.canBackPaginate
|
||||
}
|
||||
|
||||
override suspend fun sendReadReceipt(eventId: EventId) = withContext(dispatcher) {
|
||||
runCatching {
|
||||
innerRoom.sendReadReceipt(eventId = eventId.value)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue