RoomList: more rework on RoomSummaryDataSource
This commit is contained in:
@@ -179,7 +179,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
combine(
|
||||
syncService.syncState.debounce(100),
|
||||
syncService.syncState,
|
||||
networkMonitor.connectivity
|
||||
) { syncState, networkStatus ->
|
||||
syncState == SyncState.InError && networkStatus == NetworkStatus.Online
|
||||
|
||||
@@ -50,7 +50,7 @@ class InviteListPresenter @Inject constructor(
|
||||
override fun present(): InviteListState {
|
||||
val invites by client
|
||||
.roomSummaryDataSource
|
||||
.inviteList()
|
||||
.inviteRooms()
|
||||
.collectAsState()
|
||||
|
||||
var seenInvites by remember { mutableStateOf<Set<RoomId>>(emptySet()) }
|
||||
|
||||
@@ -24,7 +24,6 @@ import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
@@ -67,7 +66,7 @@ class ForwardMessagesPresenter @AssistedInject constructor(
|
||||
var results: SearchBarResultState<ImmutableList<RoomSummaryDetails>> by remember { mutableStateOf(SearchBarResultState.NotSearching()) }
|
||||
val forwardingActionState: MutableState<Async<ImmutableList<RoomId>>> = remember { mutableStateOf(Async.Uninitialized) }
|
||||
|
||||
val summaries by client.roomSummaryDataSource.roomList().collectAsState()
|
||||
val summaries by client.roomSummaryDataSource.allRooms().collectAsState()
|
||||
|
||||
LaunchedEffect(query, summaries) {
|
||||
val filteredSummaries = summaries.filterIsInstance<RoomSummary.Filled>()
|
||||
|
||||
@@ -44,7 +44,7 @@ class DefaultInviteStateDataSource @Inject constructor(
|
||||
override fun inviteState(): InvitesState {
|
||||
val invites by client
|
||||
.roomSummaryDataSource
|
||||
.inviteList()
|
||||
.inviteRooms()
|
||||
.collectAsState()
|
||||
|
||||
val seenInvites by seenInvitesStore
|
||||
|
||||
@@ -77,7 +77,7 @@ class RoomListPresenter @Inject constructor(
|
||||
var filter by rememberSaveable { mutableStateOf("") }
|
||||
val roomSummaries by client
|
||||
.roomSummaryDataSource
|
||||
.roomList()
|
||||
.allRooms()
|
||||
.collectAsState()
|
||||
|
||||
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
|
||||
|
||||
@@ -28,7 +28,7 @@ interface RoomSummaryDataSource {
|
||||
}
|
||||
|
||||
fun loadingState(): StateFlow<LoadingState>
|
||||
fun roomList(): StateFlow<List<RoomSummary>>
|
||||
fun inviteList(): StateFlow<List<RoomSummary>>
|
||||
fun allRooms(): StateFlow<List<RoomSummary>>
|
||||
fun inviteRooms(): StateFlow<List<RoomSummary>>
|
||||
fun updateRoomListVisibleRange(range: IntRange)
|
||||
}
|
||||
|
||||
@@ -123,7 +123,6 @@ class RustMatrixClient constructor(
|
||||
onSlidingSyncUpdate()
|
||||
}
|
||||
}.launchIn(sessionCoroutineScope)
|
||||
rustRoomSummaryDataSource.init()
|
||||
}
|
||||
|
||||
override fun getRoom(roomId: RoomId): MatrixRoom? {
|
||||
@@ -180,7 +179,7 @@ class RustMatrixClient constructor(
|
||||
|
||||
// Wait to receive the room back from the sync
|
||||
withTimeout(30_000L) {
|
||||
roomSummaryDataSource.roomList()
|
||||
roomSummaryDataSource.allRooms()
|
||||
.filter { roomSummaries ->
|
||||
roomSummaries.map { it.identifier() }.contains(roomId.value)
|
||||
}.first()
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.room
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummary
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate
|
||||
import org.matrix.rustcomponents.sdk.RoomListEntry
|
||||
import org.matrix.rustcomponents.sdk.RoomListService
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
|
||||
class RoomSummaryListProcessor(
|
||||
private val roomSummaries: MutableStateFlow<List<RoomSummary>>,
|
||||
private val roomListService: RoomListService,
|
||||
private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory(),
|
||||
) {
|
||||
|
||||
private val roomSummariesByIdentifier = HashMap<String, RoomSummary>()
|
||||
private val mutex = Mutex()
|
||||
|
||||
suspend fun postEntries(entries: List<RoomListEntry>) {
|
||||
updateRoomSummaries {
|
||||
Timber.v("Update rooms from postEntries (with ${entries.size} items) on ${Thread.currentThread()}")
|
||||
addAll(entries.map(::buildSummaryForRoomListEntry))
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun postUpdate(update: RoomListEntriesUpdate) {
|
||||
updateRoomSummaries {
|
||||
Timber.v("Update rooms from postUpdate ($update) on ${Thread.currentThread()}")
|
||||
applyUpdate(update)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<RoomSummary>.applyUpdate(update: RoomListEntriesUpdate) {
|
||||
when (update) {
|
||||
is RoomListEntriesUpdate.Append -> {
|
||||
val roomSummaries = update.values.map {
|
||||
buildSummaryForRoomListEntry(it)
|
||||
}
|
||||
addAll(roomSummaries)
|
||||
}
|
||||
is RoomListEntriesUpdate.PushBack -> {
|
||||
val roomSummary = buildSummaryForRoomListEntry(update.value)
|
||||
add(roomSummary)
|
||||
}
|
||||
is RoomListEntriesUpdate.PushFront -> {
|
||||
val roomSummary = buildSummaryForRoomListEntry(update.value)
|
||||
add(0, roomSummary)
|
||||
}
|
||||
is RoomListEntriesUpdate.Set -> {
|
||||
val roomSummary = buildSummaryForRoomListEntry(update.value)
|
||||
this[update.index.toInt()] = roomSummary
|
||||
}
|
||||
is RoomListEntriesUpdate.Insert -> {
|
||||
val roomSummary = buildSummaryForRoomListEntry(update.value)
|
||||
add(update.index.toInt(), roomSummary)
|
||||
}
|
||||
is RoomListEntriesUpdate.Remove -> {
|
||||
removeAt(update.index.toInt())
|
||||
}
|
||||
is RoomListEntriesUpdate.Reset -> {
|
||||
Timber.v("Reset size: ${update.values.size}")
|
||||
clear()
|
||||
addAll(update.values.map { buildSummaryForRoomListEntry(it) })
|
||||
}
|
||||
RoomListEntriesUpdate.PopBack -> {
|
||||
removeFirstOrNull()
|
||||
}
|
||||
RoomListEntriesUpdate.PopFront -> {
|
||||
removeLastOrNull()
|
||||
}
|
||||
RoomListEntriesUpdate.Clear -> {
|
||||
clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildSummaryForRoomListEntry(entry: RoomListEntry): RoomSummary {
|
||||
return when (entry) {
|
||||
RoomListEntry.Empty -> buildEmptyRoomSummary()
|
||||
is RoomListEntry.Filled -> buildAndCacheRoomSummaryForIdentifier(entry.roomId)
|
||||
is RoomListEntry.Invalidated -> {
|
||||
roomSummariesByIdentifier[entry.roomId] ?: buildEmptyRoomSummary()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildEmptyRoomSummary(): RoomSummary {
|
||||
return RoomSummary.Empty(UUID.randomUUID().toString())
|
||||
}
|
||||
|
||||
private fun buildAndCacheRoomSummaryForIdentifier(identifier: String): RoomSummary {
|
||||
val builtRoomSummary = roomListService.roomOrNull(identifier)?.use { roomListItem ->
|
||||
roomListItem.fullRoom().use { fullRoom ->
|
||||
RoomSummary.Filled(
|
||||
details = roomSummaryDetailsFactory.create(roomListItem, fullRoom)
|
||||
)
|
||||
}
|
||||
} ?: buildEmptyRoomSummary()
|
||||
roomSummariesByIdentifier[builtRoomSummary.identifier()] = builtRoomSummary
|
||||
return builtRoomSummary
|
||||
}
|
||||
|
||||
private suspend fun updateRoomSummaries(block: MutableList<RoomSummary>.() -> Unit) =
|
||||
mutex.withLock {
|
||||
val mutableRoomSummaries = roomSummaries.value.toMutableList()
|
||||
block(mutableRoomSummaries)
|
||||
roomSummaries.value = mutableRoomSummaries
|
||||
}
|
||||
}
|
||||
@@ -22,48 +22,44 @@ import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.getAndUpdate
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate
|
||||
import org.matrix.rustcomponents.sdk.RoomListEntry
|
||||
import org.matrix.rustcomponents.sdk.RoomListException
|
||||
import org.matrix.rustcomponents.sdk.RoomListInput
|
||||
import org.matrix.rustcomponents.sdk.RoomListRange
|
||||
import org.matrix.rustcomponents.sdk.RoomListService
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
|
||||
internal class RustRoomSummaryDataSource(
|
||||
private val roomListService: RoomListService,
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
private val coroutineDispatchers: CoroutineDispatchers,
|
||||
private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory(),
|
||||
coroutineDispatchers: CoroutineDispatchers,
|
||||
roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory(),
|
||||
) : RoomSummaryDataSource {
|
||||
|
||||
private val roomList = MutableStateFlow<List<RoomSummary>>(emptyList())
|
||||
private val inviteList = MutableStateFlow<List<RoomSummary>>(emptyList())
|
||||
private val loadingState = MutableStateFlow(RoomSummaryDataSource.LoadingState.NotLoaded)
|
||||
private val allRooms = MutableStateFlow<List<RoomSummary>>(emptyList())
|
||||
private val inviteRooms = MutableStateFlow<List<RoomSummary>>(emptyList())
|
||||
|
||||
fun init() {
|
||||
private val loadingState = MutableStateFlow(RoomSummaryDataSource.LoadingState.NotLoaded)
|
||||
private val allRoomsListProcessor = RoomSummaryListProcessor(allRooms, roomListService, roomSummaryDetailsFactory)
|
||||
|
||||
init {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.computation) {
|
||||
roomListService.allRooms().entriesFlow { roomListEntries ->
|
||||
roomList.value = roomListEntries.map(::buildSummaryForRoomListEntry)
|
||||
allRoomsListProcessor.postEntries(roomListEntries)
|
||||
}.onEach { update ->
|
||||
roomList.getAndUpdate {
|
||||
it.applyUpdate(update)
|
||||
}
|
||||
allRoomsListProcessor.postUpdate(update)
|
||||
}.launchIn(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun roomList(): StateFlow<List<RoomSummary>> {
|
||||
return roomList
|
||||
override fun allRooms(): StateFlow<List<RoomSummary>> {
|
||||
return allRooms
|
||||
}
|
||||
|
||||
override fun inviteList(): StateFlow<List<RoomSummary>> {
|
||||
return inviteList
|
||||
override fun inviteRooms(): StateFlow<List<RoomSummary>> {
|
||||
return inviteRooms
|
||||
}
|
||||
|
||||
override fun loadingState(): StateFlow<RoomSummaryDataSource.LoadingState> {
|
||||
@@ -83,72 +79,4 @@ internal class RustRoomSummaryDataSource(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<RoomSummary>.applyUpdate(update: RoomListEntriesUpdate): List<RoomSummary> {
|
||||
val newList = toMutableList()
|
||||
when (update) {
|
||||
is RoomListEntriesUpdate.Append -> {
|
||||
val roomSummaries = update.values.map {
|
||||
buildSummaryForRoomListEntry(it)
|
||||
}
|
||||
newList.addAll(roomSummaries)
|
||||
}
|
||||
is RoomListEntriesUpdate.PushBack -> {
|
||||
val roomSummary = buildSummaryForRoomListEntry(update.value)
|
||||
newList.add(roomSummary)
|
||||
}
|
||||
is RoomListEntriesUpdate.PushFront -> {
|
||||
val roomSummary = buildSummaryForRoomListEntry(update.value)
|
||||
newList.add(0, roomSummary)
|
||||
}
|
||||
is RoomListEntriesUpdate.Set -> {
|
||||
val roomSummary = buildSummaryForRoomListEntry(update.value)
|
||||
newList[update.index.toInt()] = roomSummary
|
||||
}
|
||||
is RoomListEntriesUpdate.Insert -> {
|
||||
val roomSummary = buildSummaryForRoomListEntry(update.value)
|
||||
newList.add(update.index.toInt(), roomSummary)
|
||||
}
|
||||
is RoomListEntriesUpdate.Remove -> {
|
||||
newList.removeAt(update.index.toInt())
|
||||
}
|
||||
is RoomListEntriesUpdate.Reset -> {
|
||||
newList.clear()
|
||||
newList.addAll(update.values.map { buildSummaryForRoomListEntry(it) })
|
||||
}
|
||||
RoomListEntriesUpdate.PopBack -> {
|
||||
newList.removeFirstOrNull()
|
||||
}
|
||||
RoomListEntriesUpdate.PopFront -> {
|
||||
newList.removeLastOrNull()
|
||||
}
|
||||
RoomListEntriesUpdate.Clear -> {
|
||||
newList.clear()
|
||||
}
|
||||
}
|
||||
return newList
|
||||
}
|
||||
|
||||
private fun buildSummaryForRoomListEntry(entry: RoomListEntry): RoomSummary {
|
||||
return when (entry) {
|
||||
RoomListEntry.Empty -> buildEmptyRoomSummary()
|
||||
is RoomListEntry.Invalidated -> buildRoomSummaryForIdentifier(entry.roomId)
|
||||
is RoomListEntry.Filled -> buildRoomSummaryForIdentifier(entry.roomId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildEmptyRoomSummary(): RoomSummary {
|
||||
return RoomSummary.Empty(UUID.randomUUID().toString())
|
||||
}
|
||||
|
||||
private fun buildRoomSummaryForIdentifier(identifier: String): RoomSummary {
|
||||
val roomListItem = roomListService.roomOrNull(identifier) ?: return RoomSummary.Empty(identifier)
|
||||
return roomListItem.use {
|
||||
roomListItem.fullRoom().use { fullRoom ->
|
||||
RoomSummary.Filled(
|
||||
details = roomSummaryDetailsFactory.create(roomListItem, fullRoom)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.matrix.rustcomponents.sdk.RoomListServiceState
|
||||
|
||||
class RustSyncService(
|
||||
private val roomListService: RoomListService,
|
||||
private val sessionCoroutineScope: CoroutineScope
|
||||
sessionCoroutineScope: CoroutineScope
|
||||
) : SyncService {
|
||||
|
||||
override fun startSync() {
|
||||
|
||||
@@ -29,7 +29,7 @@ class FakeRoomSummaryDataSource : RoomSummaryDataSource {
|
||||
roomSummariesFlow.emit(roomSummaries)
|
||||
}
|
||||
|
||||
override fun roomList(): StateFlow<List<RoomSummary>> {
|
||||
override fun allRooms(): StateFlow<List<RoomSummary>> {
|
||||
return roomSummariesFlow
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user