sdk (space) : use the new space/spaceUpdate api from space list
This commit is contained in:
@@ -94,9 +94,7 @@ class JoinRoomPresenter(
|
||||
val roomInfo by remember {
|
||||
matrixClient.getRoomInfoFlow(roomId)
|
||||
}.collectAsState(initial = Optional.empty())
|
||||
val spaceRoom by remember {
|
||||
spaceList.currentSpaceFlow()
|
||||
}.collectAsState()
|
||||
val spaceRoom by spaceList.currentSpaceFlow.collectAsState()
|
||||
val joinAction: MutableState<AsyncAction<Unit>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
|
||||
val knockAction: MutableState<AsyncAction<Unit>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
|
||||
val cancelKnockAction: MutableState<AsyncAction<Unit>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
|
||||
|
||||
@@ -29,7 +29,6 @@ import kotlinx.collections.immutable.toPersistentSet
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.Optional
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
@Inject
|
||||
@@ -66,7 +65,7 @@ class SpacePresenter(
|
||||
}
|
||||
}.collectAsState()
|
||||
|
||||
val currentSpace by remember { spaceRoomList.currentSpaceFlow() }.collectAsState(Optional.empty())
|
||||
val currentSpace by spaceRoomList.currentSpaceFlow.collectAsState()
|
||||
|
||||
fun handleEvents(event: SpaceEvents) {
|
||||
when (event) {
|
||||
|
||||
@@ -17,7 +17,7 @@ interface SpaceRoomList {
|
||||
data class Idle(val hasMoreToLoad: Boolean) : PaginationStatus
|
||||
}
|
||||
|
||||
fun currentSpaceFlow(): StateFlow<Optional<SpaceRoom>>
|
||||
val currentSpaceFlow: StateFlow<Optional<SpaceRoom>>
|
||||
|
||||
val spaceRoomsFlow: Flow<List<SpaceRoom>>
|
||||
val paginationStatusFlow: StateFlow<PaginationStatus>
|
||||
|
||||
@@ -8,15 +8,14 @@
|
||||
package io.element.android.libraries.matrix.impl.spaces
|
||||
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import uniffi.matrix_sdk_ui.SpaceRoomListPaginationState
|
||||
@@ -24,25 +23,21 @@ import java.util.Optional
|
||||
import org.matrix.rustcomponents.sdk.SpaceRoomList as InnerSpaceRoomList
|
||||
|
||||
class RustSpaceRoomList(
|
||||
private val roomId: RoomId,
|
||||
private val innerProvider: suspend () -> InnerSpaceRoomList,
|
||||
sessionCoroutineScope: CoroutineScope,
|
||||
spaceRoomMapper: SpaceRoomMapper,
|
||||
private val spaceRoomCache: SpaceRoomCache,
|
||||
) : SpaceRoomList {
|
||||
private val inner = CompletableDeferred<InnerSpaceRoomList>()
|
||||
|
||||
override fun currentSpaceFlow(): StateFlow<Optional<SpaceRoom>> {
|
||||
return spaceRoomCache.getSpaceRoomFlow(roomId)
|
||||
}
|
||||
override val currentSpaceFlow = MutableStateFlow<Optional<SpaceRoom>>(Optional.empty())
|
||||
|
||||
override val spaceRoomsFlow = MutableSharedFlow<List<SpaceRoom>>(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
|
||||
|
||||
override val paginationStatusFlow: MutableStateFlow<SpaceRoomList.PaginationStatus> =
|
||||
MutableStateFlow(SpaceRoomList.PaginationStatus.Idle(hasMoreToLoad = false))
|
||||
private val spaceListUpdateProcessor = SpaceListUpdateProcessor(
|
||||
spaceRoomsFlow = spaceRoomsFlow,
|
||||
mapper = spaceRoomMapper,
|
||||
spaceRoomCache = spaceRoomCache
|
||||
mapper = spaceRoomMapper
|
||||
)
|
||||
|
||||
init {
|
||||
@@ -64,6 +59,14 @@ class RustSpaceRoomList(
|
||||
}
|
||||
.collect()
|
||||
}
|
||||
sessionCoroutineScope.launch {
|
||||
inner.await().spaceUpdateFlow()
|
||||
.map { space -> space.map(spaceRoomMapper::map) }
|
||||
.onEach { space ->
|
||||
currentSpaceFlow.emit(space)
|
||||
}
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun paginate(): Result<Unit> {
|
||||
|
||||
@@ -38,12 +38,10 @@ class RustSpaceService(
|
||||
private val sessionDispatcher: CoroutineDispatcher,
|
||||
) : SpaceService {
|
||||
private val spaceRoomMapper = SpaceRoomMapper()
|
||||
private val spaceRoomCache = SpaceRoomCache()
|
||||
override val spaceRoomsFlow = MutableSharedFlow<List<SpaceRoom>>(replay = 1, extraBufferCapacity = 1)
|
||||
private val spaceListUpdateProcessor = SpaceListUpdateProcessor(
|
||||
spaceRoomsFlow = spaceRoomsFlow,
|
||||
mapper = spaceRoomMapper,
|
||||
spaceRoomCache = spaceRoomCache
|
||||
mapper = spaceRoomMapper
|
||||
)
|
||||
|
||||
override suspend fun joinedSpaces(): Result<List<SpaceRoom>> = withContext(sessionDispatcher) {
|
||||
@@ -57,11 +55,9 @@ class RustSpaceService(
|
||||
|
||||
override fun spaceRoomList(id: RoomId): SpaceRoomList {
|
||||
return RustSpaceRoomList(
|
||||
roomId = id,
|
||||
innerProvider = { innerSpaceService.spaceRoomList(id.value) },
|
||||
sessionCoroutineScope = sessionCoroutineScope,
|
||||
spaceRoomMapper = spaceRoomMapper,
|
||||
spaceRoomCache = spaceRoomCache,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ import timber.log.Timber
|
||||
internal class SpaceListUpdateProcessor(
|
||||
private val spaceRoomsFlow: MutableSharedFlow<List<SpaceRoom>>,
|
||||
private val mapper: SpaceRoomMapper,
|
||||
private val spaceRoomCache: SpaceRoomCache,
|
||||
) {
|
||||
private val mutex = Mutex()
|
||||
|
||||
@@ -37,7 +36,6 @@ internal class SpaceListUpdateProcessor(
|
||||
mutableListOf()
|
||||
}
|
||||
block(spaceRooms)
|
||||
spaceRoomCache.update(spaceRooms)
|
||||
spaceRoomsFlow.emit(spaceRooms)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.spaces
|
||||
|
||||
import io.element.android.libraries.core.coroutine.mapState
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* An in memory cache of space rooms.
|
||||
* Only caches Rooms with roomType [io.element.android.libraries.matrix.api.room.RoomType.Space].
|
||||
*/
|
||||
class SpaceRoomCache {
|
||||
private val inMemoryCache = MutableStateFlow<Map<RoomId, SpaceRoom?>>(emptyMap())
|
||||
fun getSpaceRoomFlow(roomId: RoomId): StateFlow<Optional<SpaceRoom>> {
|
||||
return inMemoryCache.mapState { Optional.ofNullable(it[roomId]) }
|
||||
}
|
||||
|
||||
fun update(spaceRooms: List<SpaceRoom>) {
|
||||
inMemoryCache.update { currentValues ->
|
||||
val newValues = spaceRooms
|
||||
.filter { it.isSpace }
|
||||
.associateBy { it.roomId }
|
||||
currentValues + newValues
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,14 @@ import kotlinx.coroutines.flow.buffer
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import org.matrix.rustcomponents.sdk.SpaceListUpdate
|
||||
import org.matrix.rustcomponents.sdk.SpaceRoom
|
||||
import org.matrix.rustcomponents.sdk.SpaceRoomListEntriesListener
|
||||
import org.matrix.rustcomponents.sdk.SpaceRoomListInterface
|
||||
import org.matrix.rustcomponents.sdk.SpaceRoomListPaginationStateListener
|
||||
import org.matrix.rustcomponents.sdk.SpaceRoomListSpaceListener
|
||||
import timber.log.Timber
|
||||
import uniffi.matrix_sdk_ui.SpaceRoomListPaginationState
|
||||
import java.util.Optional
|
||||
|
||||
internal fun SpaceRoomListInterface.paginationStateFlow(): Flow<SpaceRoomListPaginationState> = callbackFlow {
|
||||
val listener = object : SpaceRoomListPaginationStateListener {
|
||||
@@ -55,3 +58,21 @@ internal fun SpaceRoomListInterface.spaceListUpdateFlow(): Flow<List<SpaceListUp
|
||||
}.catch {
|
||||
Timber.d(it, "spaceListUpdateFlow() failed")
|
||||
}.buffer(Channel.UNLIMITED)
|
||||
|
||||
internal fun SpaceRoomListInterface.spaceUpdateFlow(): Flow<Optional<SpaceRoom>> =
|
||||
callbackFlow {
|
||||
val listener = object : SpaceRoomListSpaceListener {
|
||||
override fun onUpdate(space: SpaceRoom?) {
|
||||
trySendBlocking(Optional.ofNullable(space))
|
||||
}
|
||||
}
|
||||
Timber.d("Open spaceUpdateFlow for SpaceRoomListInterface ${this@spaceUpdateFlow}")
|
||||
trySendBlocking(Optional.ofNullable(space()))
|
||||
val taskHandle = subscribeToSpaceUpdates(listener)
|
||||
awaitClose {
|
||||
Timber.d("Close spaceUpdateFlow for SpaceRoomListInterface ${this@spaceUpdateFlow}")
|
||||
taskHandle.cancelAndDestroy()
|
||||
}
|
||||
}.catch {
|
||||
Timber.d(it, "spaceUpdateFlow() failed")
|
||||
}.buffer(Channel.UNLIMITED)
|
||||
|
||||
@@ -185,6 +185,5 @@ class RoomSummaryListProcessorTest {
|
||||
) = SpaceListUpdateProcessor(
|
||||
spaceRoomsFlow = spaceRoomsFlow,
|
||||
mapper = SpaceRoomMapper(),
|
||||
spaceRoomCache = SpaceRoomCache(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,13 +11,10 @@ package io.element.android.libraries.matrix.impl.spaces
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
|
||||
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustSpaceRoom
|
||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiSpaceRoomList
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
||||
import io.element.android.libraries.previewutils.room.aSpaceRoom
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
@@ -26,7 +23,6 @@ import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.matrix.rustcomponents.sdk.SpaceListUpdate
|
||||
import uniffi.matrix_sdk_ui.SpaceRoomListPaginationState
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import org.matrix.rustcomponents.sdk.SpaceRoomList as InnerSpaceRoomList
|
||||
|
||||
class RustSpaceRoomListTest {
|
||||
@@ -87,33 +83,15 @@ class RustSpaceRoomListTest {
|
||||
paginateResult.assertions().isCalledOnce()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `currentSpaceFlow reads value from the SpaceRoomCache`() = runTest {
|
||||
val spaceRoomCache = SpaceRoomCache()
|
||||
val sut = createRustSpaceRoomList(
|
||||
spaceRoomCache = spaceRoomCache,
|
||||
)
|
||||
sut.currentSpaceFlow().test {
|
||||
assertThat(awaitItem().getOrNull()).isNull()
|
||||
val spaceRoom = aSpaceRoom(roomId = A_ROOM_ID)
|
||||
spaceRoomCache.update(listOf(spaceRoom))
|
||||
assertThat(awaitItem().getOrNull()).isEqualTo(spaceRoom)
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestScope.createRustSpaceRoomList(
|
||||
roomId: RoomId = A_ROOM_ID,
|
||||
innerSpaceRoomList: InnerSpaceRoomList = FakeFfiSpaceRoomList(),
|
||||
innerProvider: suspend () -> InnerSpaceRoomList = { innerSpaceRoomList },
|
||||
spaceRoomMapper: SpaceRoomMapper = SpaceRoomMapper(),
|
||||
spaceRoomCache: SpaceRoomCache = SpaceRoomCache(),
|
||||
): RustSpaceRoomList {
|
||||
return RustSpaceRoomList(
|
||||
roomId = roomId,
|
||||
innerProvider = innerProvider,
|
||||
sessionCoroutineScope = backgroundScope,
|
||||
spaceRoomMapper = spaceRoomMapper,
|
||||
spaceRoomCache = spaceRoomCache,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.spaces
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.room.RoomType
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
||||
import io.element.android.libraries.previewutils.room.aSpaceRoom
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class SpaceRoomCacheTest {
|
||||
@Test
|
||||
fun `getSpaceRoomFlow emits items`() = runTest {
|
||||
val sut = SpaceRoomCache()
|
||||
sut.getSpaceRoomFlow(A_ROOM_ID).test {
|
||||
assertThat(awaitItem().isEmpty).isTrue()
|
||||
val room = aSpaceRoom(
|
||||
roomId = A_ROOM_ID,
|
||||
roomType = RoomType.Room,
|
||||
)
|
||||
sut.update(listOf(room))
|
||||
// Not a space, should not be cached
|
||||
expectNoEvents()
|
||||
val space = aSpaceRoom(
|
||||
roomId = A_ROOM_ID,
|
||||
roomType = RoomType.Space,
|
||||
)
|
||||
sut.update(listOf(space))
|
||||
assertThat(awaitItem().get()).isEqualTo(space)
|
||||
val spaceOther = aSpaceRoom(
|
||||
roomId = A_ROOM_ID_2,
|
||||
roomType = RoomType.Space,
|
||||
)
|
||||
sut.update(listOf(spaceOther))
|
||||
expectNoEvents()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ class FakeSpaceRoomList(
|
||||
private val paginateResult: () -> Result<Unit> = { lambdaError() },
|
||||
) : SpaceRoomList {
|
||||
private val currentSpaceMutableStateFlow: MutableStateFlow<Optional<SpaceRoom>> = MutableStateFlow(Optional.ofNullable(initialSpaceFlowValue))
|
||||
override fun currentSpaceFlow(): StateFlow<Optional<SpaceRoom>> = currentSpaceMutableStateFlow.asStateFlow()
|
||||
override val currentSpaceFlow: StateFlow<Optional<SpaceRoom>> = currentSpaceMutableStateFlow.asStateFlow()
|
||||
|
||||
fun emitCurrentSpace(value: SpaceRoom?) {
|
||||
currentSpaceMutableStateFlow.value = Optional.ofNullable(value)
|
||||
|
||||
Reference in New Issue
Block a user