RoomList: more rework on RoomSummaryDataSource
This commit is contained in:
parent
e392f15872
commit
e5c86675a4
11 changed files with 152 additions and 98 deletions
|
|
@ -179,7 +179,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
combine(
|
combine(
|
||||||
syncService.syncState.debounce(100),
|
syncService.syncState,
|
||||||
networkMonitor.connectivity
|
networkMonitor.connectivity
|
||||||
) { syncState, networkStatus ->
|
) { syncState, networkStatus ->
|
||||||
syncState == SyncState.InError && networkStatus == NetworkStatus.Online
|
syncState == SyncState.InError && networkStatus == NetworkStatus.Online
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ class InviteListPresenter @Inject constructor(
|
||||||
override fun present(): InviteListState {
|
override fun present(): InviteListState {
|
||||||
val invites by client
|
val invites by client
|
||||||
.roomSummaryDataSource
|
.roomSummaryDataSource
|
||||||
.inviteList()
|
.inviteRooms()
|
||||||
.collectAsState()
|
.collectAsState()
|
||||||
|
|
||||||
var seenInvites by remember { mutableStateOf<Set<RoomId>>(emptySet()) }
|
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.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
|
|
@ -67,7 +66,7 @@ class ForwardMessagesPresenter @AssistedInject constructor(
|
||||||
var results: SearchBarResultState<ImmutableList<RoomSummaryDetails>> by remember { mutableStateOf(SearchBarResultState.NotSearching()) }
|
var results: SearchBarResultState<ImmutableList<RoomSummaryDetails>> by remember { mutableStateOf(SearchBarResultState.NotSearching()) }
|
||||||
val forwardingActionState: MutableState<Async<ImmutableList<RoomId>>> = remember { mutableStateOf(Async.Uninitialized) }
|
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) {
|
LaunchedEffect(query, summaries) {
|
||||||
val filteredSummaries = summaries.filterIsInstance<RoomSummary.Filled>()
|
val filteredSummaries = summaries.filterIsInstance<RoomSummary.Filled>()
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ class DefaultInviteStateDataSource @Inject constructor(
|
||||||
override fun inviteState(): InvitesState {
|
override fun inviteState(): InvitesState {
|
||||||
val invites by client
|
val invites by client
|
||||||
.roomSummaryDataSource
|
.roomSummaryDataSource
|
||||||
.inviteList()
|
.inviteRooms()
|
||||||
.collectAsState()
|
.collectAsState()
|
||||||
|
|
||||||
val seenInvites by seenInvitesStore
|
val seenInvites by seenInvitesStore
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ class RoomListPresenter @Inject constructor(
|
||||||
var filter by rememberSaveable { mutableStateOf("") }
|
var filter by rememberSaveable { mutableStateOf("") }
|
||||||
val roomSummaries by client
|
val roomSummaries by client
|
||||||
.roomSummaryDataSource
|
.roomSummaryDataSource
|
||||||
.roomList()
|
.allRooms()
|
||||||
.collectAsState()
|
.collectAsState()
|
||||||
|
|
||||||
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
|
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ interface RoomSummaryDataSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadingState(): StateFlow<LoadingState>
|
fun loadingState(): StateFlow<LoadingState>
|
||||||
fun roomList(): StateFlow<List<RoomSummary>>
|
fun allRooms(): StateFlow<List<RoomSummary>>
|
||||||
fun inviteList(): StateFlow<List<RoomSummary>>
|
fun inviteRooms(): StateFlow<List<RoomSummary>>
|
||||||
fun updateRoomListVisibleRange(range: IntRange)
|
fun updateRoomListVisibleRange(range: IntRange)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,6 @@ class RustMatrixClient constructor(
|
||||||
onSlidingSyncUpdate()
|
onSlidingSyncUpdate()
|
||||||
}
|
}
|
||||||
}.launchIn(sessionCoroutineScope)
|
}.launchIn(sessionCoroutineScope)
|
||||||
rustRoomSummaryDataSource.init()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRoom(roomId: RoomId): MatrixRoom? {
|
override fun getRoom(roomId: RoomId): MatrixRoom? {
|
||||||
|
|
@ -180,7 +179,7 @@ class RustMatrixClient constructor(
|
||||||
|
|
||||||
// Wait to receive the room back from the sync
|
// Wait to receive the room back from the sync
|
||||||
withTimeout(30_000L) {
|
withTimeout(30_000L) {
|
||||||
roomSummaryDataSource.roomList()
|
roomSummaryDataSource.allRooms()
|
||||||
.filter { roomSummaries ->
|
.filter { roomSummaries ->
|
||||||
roomSummaries.map { it.identifier() }.contains(roomId.value)
|
roomSummaries.map { it.identifier() }.contains(roomId.value)
|
||||||
}.first()
|
}.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.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.getAndUpdate
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
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.RoomListException
|
||||||
import org.matrix.rustcomponents.sdk.RoomListInput
|
import org.matrix.rustcomponents.sdk.RoomListInput
|
||||||
import org.matrix.rustcomponents.sdk.RoomListRange
|
import org.matrix.rustcomponents.sdk.RoomListRange
|
||||||
import org.matrix.rustcomponents.sdk.RoomListService
|
import org.matrix.rustcomponents.sdk.RoomListService
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
internal class RustRoomSummaryDataSource(
|
internal class RustRoomSummaryDataSource(
|
||||||
private val roomListService: RoomListService,
|
private val roomListService: RoomListService,
|
||||||
private val sessionCoroutineScope: CoroutineScope,
|
private val sessionCoroutineScope: CoroutineScope,
|
||||||
private val coroutineDispatchers: CoroutineDispatchers,
|
coroutineDispatchers: CoroutineDispatchers,
|
||||||
private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory(),
|
roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory(),
|
||||||
) : RoomSummaryDataSource {
|
) : RoomSummaryDataSource {
|
||||||
|
|
||||||
private val roomList = MutableStateFlow<List<RoomSummary>>(emptyList())
|
private val allRooms = MutableStateFlow<List<RoomSummary>>(emptyList())
|
||||||
private val inviteList = MutableStateFlow<List<RoomSummary>>(emptyList())
|
private val inviteRooms = MutableStateFlow<List<RoomSummary>>(emptyList())
|
||||||
private val loadingState = MutableStateFlow(RoomSummaryDataSource.LoadingState.NotLoaded)
|
|
||||||
|
|
||||||
fun init() {
|
private val loadingState = MutableStateFlow(RoomSummaryDataSource.LoadingState.NotLoaded)
|
||||||
|
private val allRoomsListProcessor = RoomSummaryListProcessor(allRooms, roomListService, roomSummaryDetailsFactory)
|
||||||
|
|
||||||
|
init {
|
||||||
sessionCoroutineScope.launch(coroutineDispatchers.computation) {
|
sessionCoroutineScope.launch(coroutineDispatchers.computation) {
|
||||||
roomListService.allRooms().entriesFlow { roomListEntries ->
|
roomListService.allRooms().entriesFlow { roomListEntries ->
|
||||||
roomList.value = roomListEntries.map(::buildSummaryForRoomListEntry)
|
allRoomsListProcessor.postEntries(roomListEntries)
|
||||||
}.onEach { update ->
|
}.onEach { update ->
|
||||||
roomList.getAndUpdate {
|
allRoomsListProcessor.postUpdate(update)
|
||||||
it.applyUpdate(update)
|
|
||||||
}
|
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun roomList(): StateFlow<List<RoomSummary>> {
|
override fun allRooms(): StateFlow<List<RoomSummary>> {
|
||||||
return roomList
|
return allRooms
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun inviteList(): StateFlow<List<RoomSummary>> {
|
override fun inviteRooms(): StateFlow<List<RoomSummary>> {
|
||||||
return inviteList
|
return inviteRooms
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadingState(): StateFlow<RoomSummaryDataSource.LoadingState> {
|
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(
|
class RustSyncService(
|
||||||
private val roomListService: RoomListService,
|
private val roomListService: RoomListService,
|
||||||
private val sessionCoroutineScope: CoroutineScope
|
sessionCoroutineScope: CoroutineScope
|
||||||
) : SyncService {
|
) : SyncService {
|
||||||
|
|
||||||
override fun startSync() {
|
override fun startSync() {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class FakeRoomSummaryDataSource : RoomSummaryDataSource {
|
||||||
roomSummariesFlow.emit(roomSummaries)
|
roomSummariesFlow.emit(roomSummaries)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun roomList(): StateFlow<List<RoomSummary>> {
|
override fun allRooms(): StateFlow<List<RoomSummary>> {
|
||||||
return roomSummariesFlow
|
return roomSummariesFlow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue