RoomList: introduce incremental loading to improve performances.
This commit is contained in:
parent
656fcbd5e4
commit
fda114d648
7 changed files with 99 additions and 56 deletions
|
|
@ -65,7 +65,6 @@ fun RoomListInterface.loadingStateFlow(): Flow<RoomListLoadingState> =
|
|||
|
||||
internal fun RoomListInterface.entriesFlow(
|
||||
pageSize: Int,
|
||||
numberOfPages: Int,
|
||||
roomListDynamicEvents: Flow<RoomListDynamicEvents>,
|
||||
initialFilterKind: RoomListEntriesDynamicFilterKind
|
||||
): Flow<List<RoomListEntriesUpdate>> =
|
||||
|
|
@ -84,9 +83,7 @@ internal fun RoomListInterface.entriesFlow(
|
|||
controller.setFilter(controllerEvents.filter)
|
||||
}
|
||||
is RoomListDynamicEvents.LoadMore -> {
|
||||
repeat(numberOfPages) {
|
||||
controller.addOnePage()
|
||||
}
|
||||
controller.addOnePage()
|
||||
}
|
||||
is RoomListDynamicEvents.Reset -> {
|
||||
controller.resetToOnePage()
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import kotlinx.coroutines.CoroutineDispatcher
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.getAndUpdate
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
|
@ -39,57 +40,28 @@ internal class RoomListFactory(
|
|||
private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory(),
|
||||
) {
|
||||
|
||||
/**
|
||||
* Creates a room list that will load all rooms in a single page.
|
||||
* It mimics the usage of the old api.
|
||||
*/
|
||||
fun createRoomList(
|
||||
innerProvider: suspend () -> InnerRoomList,
|
||||
): RoomList {
|
||||
return createRustRoomList(
|
||||
pageSize = Int.MAX_VALUE,
|
||||
numberOfPages = 1,
|
||||
initialFilterKind = RoomListEntriesDynamicFilterKind.AllNonLeft,
|
||||
innerRoomListProvider = innerProvider
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a room list that can be used to load more rooms and filter them dynamically.
|
||||
*/
|
||||
fun createDynamicRoomList(
|
||||
pageSize: Int = DynamicRoomList.DEFAULT_PAGE_SIZE,
|
||||
pagesToLoad: Int = DynamicRoomList.DEFAULT_PAGES_TO_LOAD,
|
||||
initialFilter: DynamicRoomList.Filter = DynamicRoomList.Filter.None,
|
||||
fun createRoomList(
|
||||
pageSize: Int,
|
||||
initialFilter: DynamicRoomList.Filter = DynamicRoomList.Filter.All,
|
||||
innerProvider: suspend () -> InnerRoomList
|
||||
): DynamicRoomList {
|
||||
return createRustRoomList(
|
||||
pageSize = pageSize,
|
||||
numberOfPages = pagesToLoad,
|
||||
initialFilterKind = initialFilter.toRustFilter(),
|
||||
innerRoomListProvider = innerProvider
|
||||
)
|
||||
}
|
||||
|
||||
private fun createRustRoomList(
|
||||
pageSize: Int,
|
||||
numberOfPages: Int,
|
||||
initialFilterKind: RoomListEntriesDynamicFilterKind,
|
||||
innerRoomListProvider: suspend () -> InnerRoomList
|
||||
): RustDynamicRoomList {
|
||||
val loadingStateFlow: MutableStateFlow<RoomList.LoadingState> = MutableStateFlow(RoomList.LoadingState.NotLoaded)
|
||||
val summariesFlow = MutableStateFlow<List<RoomSummary>>(emptyList())
|
||||
val processor = RoomSummaryListProcessor(summariesFlow, innerRoomListService, dispatcher, roomSummaryDetailsFactory)
|
||||
val dynamicEvents = MutableSharedFlow<RoomListDynamicEvents>()
|
||||
|
||||
// Makes sure we don't miss any events
|
||||
val dynamicEvents = MutableSharedFlow<RoomListDynamicEvents>(replay = 100)
|
||||
val currentFilter = MutableStateFlow(initialFilter)
|
||||
val loadedPages = MutableStateFlow(1)
|
||||
var innerRoomList: InnerRoomList? = null
|
||||
coroutineScope.launch(dispatcher) {
|
||||
innerRoomList = innerRoomListProvider()
|
||||
innerRoomList = innerProvider()
|
||||
innerRoomList?.let { innerRoomList ->
|
||||
innerRoomList.entriesFlow(
|
||||
pageSize = pageSize,
|
||||
numberOfPages = numberOfPages,
|
||||
initialFilterKind = initialFilterKind,
|
||||
initialFilterKind = initialFilter.toRustFilter(),
|
||||
roomListDynamicEvents = dynamicEvents
|
||||
).onEach { update ->
|
||||
processor.postUpdate(update)
|
||||
|
|
@ -105,15 +77,26 @@ internal class RoomListFactory(
|
|||
}.invokeOnCompletion {
|
||||
innerRoomList?.destroy()
|
||||
}
|
||||
return RustDynamicRoomList(summariesFlow, loadingStateFlow, dynamicEvents, processor)
|
||||
return RustDynamicRoomList(
|
||||
summaries = summariesFlow,
|
||||
loadingState = loadingStateFlow,
|
||||
currentFilter = currentFilter,
|
||||
loadedPages = loadedPages,
|
||||
dynamicEvents = dynamicEvents,
|
||||
processor = processor,
|
||||
pageSize = pageSize,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class RustDynamicRoomList(
|
||||
override val summaries: MutableStateFlow<List<RoomSummary>>,
|
||||
override val loadingState: MutableStateFlow<RoomList.LoadingState>,
|
||||
override val currentFilter: MutableStateFlow<DynamicRoomList.Filter>,
|
||||
override val loadedPages: MutableStateFlow<Int>,
|
||||
private val dynamicEvents: MutableSharedFlow<RoomListDynamicEvents>,
|
||||
private val processor: RoomSummaryListProcessor,
|
||||
override val pageSize: Int,
|
||||
) : DynamicRoomList {
|
||||
|
||||
override suspend fun rebuildSummaries() {
|
||||
|
|
@ -121,16 +104,19 @@ private class RustDynamicRoomList(
|
|||
}
|
||||
|
||||
override suspend fun updateFilter(filter: DynamicRoomList.Filter) {
|
||||
currentFilter.emit(filter)
|
||||
val filterEvent = RoomListDynamicEvents.SetFilter(filter.toRustFilter())
|
||||
dynamicEvents.emit(filterEvent)
|
||||
}
|
||||
|
||||
override suspend fun loadMore() {
|
||||
dynamicEvents.emit(RoomListDynamicEvents.LoadMore)
|
||||
loadedPages.getAndUpdate { it + 1 }
|
||||
}
|
||||
|
||||
override suspend fun reset() {
|
||||
dynamicEvents.emit(RoomListDynamicEvents.Reset)
|
||||
loadedPages.emit(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -146,6 +132,7 @@ private fun DynamicRoomList.Filter.toRustFilter(): RoomListEntriesDynamicFilterK
|
|||
DynamicRoomList.Filter.All -> RoomListEntriesDynamicFilterKind.All
|
||||
is DynamicRoomList.Filter.NormalizedMatchRoomName -> RoomListEntriesDynamicFilterKind.NormalizedMatchRoomName(this.pattern)
|
||||
DynamicRoomList.Filter.None -> RoomListEntriesDynamicFilterKind.None
|
||||
DynamicRoomList.Filter.AllNonLeft -> RoomListEntriesDynamicFilterKind.AllNonLeft
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
package io.element.android.libraries.matrix.impl.roomlist
|
||||
|
||||
import io.element.android.libraries.matrix.api.roomlist.DynamicRoomList
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.roomlist.loadAllIncrementally
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
|
@ -34,20 +36,31 @@ import org.matrix.rustcomponents.sdk.RoomListServiceSyncIndicator
|
|||
import timber.log.Timber
|
||||
import org.matrix.rustcomponents.sdk.RoomListService as InnerRustRoomListService
|
||||
|
||||
private const val DEFAULT_PAGE_SIZE = 20
|
||||
|
||||
internal class RustRoomListService(
|
||||
private val innerRoomListService: InnerRustRoomListService,
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
roomListFactory: RoomListFactory,
|
||||
) : RoomListService {
|
||||
|
||||
override val allRooms: RoomList = roomListFactory.createRoomList {
|
||||
override val allRooms: DynamicRoomList = roomListFactory.createRoomList(
|
||||
pageSize = DEFAULT_PAGE_SIZE,
|
||||
initialFilter = DynamicRoomList.Filter.AllNonLeft,
|
||||
) {
|
||||
innerRoomListService.allRooms()
|
||||
}
|
||||
|
||||
override val invites: RoomList = roomListFactory.createRoomList {
|
||||
override val invites: RoomList = roomListFactory.createRoomList(
|
||||
pageSize = Int.MAX_VALUE,
|
||||
) {
|
||||
innerRoomListService.invites()
|
||||
}
|
||||
|
||||
init {
|
||||
allRooms.loadAllIncrementally(sessionCoroutineScope)
|
||||
}
|
||||
|
||||
override fun updateAllRoomsVisibleRange(range: IntRange) {
|
||||
Timber.v("setVisibleRange=$range")
|
||||
sessionCoroutineScope.launch {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue