Space List
Extract InviteButtonsRowMolecule Take into account seenSpaceInvites
This commit is contained in:
parent
1836ae0ae0
commit
81d82fb0de
24 changed files with 811 additions and 40 deletions
|
|
@ -42,6 +42,7 @@ import io.element.android.libraries.matrix.api.room.join.JoinRule
|
|||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceService
|
||||
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||
|
|
@ -71,6 +72,7 @@ import io.element.android.libraries.matrix.impl.roomdirectory.map
|
|||
import io.element.android.libraries.matrix.impl.roomlist.RoomListFactory
|
||||
import io.element.android.libraries.matrix.impl.roomlist.RustRoomListService
|
||||
import io.element.android.libraries.matrix.impl.roomlist.roomOrNull
|
||||
import io.element.android.libraries.matrix.impl.spaces.RustSpaceService
|
||||
import io.element.android.libraries.matrix.impl.sync.RustSyncService
|
||||
import io.element.android.libraries.matrix.impl.sync.map
|
||||
import io.element.android.libraries.matrix.impl.usersearch.UserProfileMapper
|
||||
|
|
@ -143,6 +145,7 @@ class RustMatrixClient(
|
|||
private val sessionDispatcher = dispatchers.io.limitedParallelism(64)
|
||||
|
||||
private val innerRoomListService = innerSyncService.roomListService()
|
||||
private val innerSpaceService = innerClient.spaceService()
|
||||
|
||||
private val rustSyncService = RustSyncService(
|
||||
inner = innerSyncService,
|
||||
|
|
@ -184,6 +187,17 @@ class RustMatrixClient(
|
|||
roomSyncSubscriber = roomSyncSubscriber,
|
||||
)
|
||||
|
||||
override val spaceService: SpaceService = RustSpaceService(
|
||||
innerSpaceService = innerSpaceService,
|
||||
sessionCoroutineScope = sessionCoroutineScope,
|
||||
sessionDispatcher = sessionDispatcher,
|
||||
//roomListFactory = RoomListFactory(
|
||||
// innerRoomListService = innerRoomListService,
|
||||
// sessionCoroutineScope = sessionCoroutineScope,
|
||||
//),
|
||||
//roomSyncSubscriber = roomSyncSubscriber,
|
||||
)
|
||||
|
||||
private val verificationService = RustSessionVerificationService(
|
||||
client = innerClient,
|
||||
isSyncServiceReady = rustSyncService.syncState.map { it == SyncState.Running },
|
||||
|
|
@ -540,6 +554,7 @@ class RustMatrixClient(
|
|||
|
||||
sessionDelegate.clearCurrentClient()
|
||||
innerRoomListService.close()
|
||||
innerSpaceService.close()
|
||||
notificationService.close()
|
||||
encryptionService.close()
|
||||
innerClient.close()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceService
|
||||
import io.element.android.libraries.matrix.impl.util.cancelAndDestroy
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.channels.trySendBlocking
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.buffer
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.SpaceListUpdate
|
||||
import org.matrix.rustcomponents.sdk.SpaceServiceInterface
|
||||
import org.matrix.rustcomponents.sdk.SpaceServiceJoinedSpacesListener
|
||||
import timber.log.Timber
|
||||
import org.matrix.rustcomponents.sdk.SpaceService as ClientSpaceService
|
||||
|
||||
class RustSpaceService(
|
||||
private val innerSpaceService: ClientSpaceService,
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
private val sessionDispatcher: CoroutineDispatcher,
|
||||
) : SpaceService {
|
||||
private val mapper = SpaceRoomMapper()
|
||||
private val mutex = Mutex()
|
||||
|
||||
override val spaceRooms = MutableSharedFlow<List<SpaceRoom>>(replay = 1, extraBufferCapacity = 1)
|
||||
|
||||
override suspend fun joinedSpaces(): Result<List<SpaceRoom>> = withContext(sessionDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerSpaceService.joinedSpaces()
|
||||
.map {
|
||||
it.let(mapper::map)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// override suspend fun spaceRoomList(spaceId: SpaceId): Result<List<SpaceRoom>> = withContext(sessionDispatcher) {
|
||||
// runCatchingExceptions {
|
||||
// innerSpaceService.spaceRoomList(spaceId.value)
|
||||
// }
|
||||
// }
|
||||
|
||||
init {
|
||||
innerSpaceService
|
||||
.spaceDiffFlow()
|
||||
.onEach {
|
||||
handeUpdate(it)
|
||||
}
|
||||
.launchIn(sessionCoroutineScope)
|
||||
}
|
||||
|
||||
private suspend fun handeUpdate(spaceListUpdates: List<SpaceListUpdate>) {
|
||||
mutex.withLock {
|
||||
val current = if (spaceRooms.replayCache.isNotEmpty()) {
|
||||
spaceRooms.first().toMutableList()
|
||||
} else {
|
||||
mutableListOf()
|
||||
}
|
||||
spaceListUpdates.forEach { update ->
|
||||
current.applyUpdate(update)
|
||||
}
|
||||
spaceRooms.emit(current)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<SpaceRoom>.applyUpdate(update: SpaceListUpdate) {
|
||||
when (update) {
|
||||
is SpaceListUpdate.Append -> {
|
||||
val newSpaces = update.values.map { it ->
|
||||
it.let(mapper::map)
|
||||
}
|
||||
addAll(newSpaces)
|
||||
}
|
||||
SpaceListUpdate.Clear -> clear()
|
||||
is SpaceListUpdate.Insert -> {
|
||||
val newSpace = mapper.map(update.value)
|
||||
add(update.index.toInt(), newSpace)
|
||||
}
|
||||
SpaceListUpdate.PopBack -> {
|
||||
removeAt(lastIndex)
|
||||
}
|
||||
SpaceListUpdate.PopFront -> {
|
||||
removeAt(0)
|
||||
}
|
||||
is SpaceListUpdate.PushBack -> {
|
||||
val newSpace = mapper.map(update.value)
|
||||
add(newSpace)
|
||||
}
|
||||
is SpaceListUpdate.PushFront -> {
|
||||
val newSpace = mapper.map(update.value)
|
||||
add(0, newSpace)
|
||||
}
|
||||
is SpaceListUpdate.Remove -> {
|
||||
removeAt(update.index.toInt())
|
||||
}
|
||||
is SpaceListUpdate.Reset -> {
|
||||
clear()
|
||||
val newSpaces = update.values.map(mapper::map)
|
||||
addAll(newSpaces)
|
||||
}
|
||||
is SpaceListUpdate.Set -> {
|
||||
val newSpace = mapper.map(update.value)
|
||||
this[update.index.toInt()] = newSpace
|
||||
}
|
||||
is SpaceListUpdate.Truncate -> {
|
||||
subList(update.length.toInt(), size).clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun SpaceServiceInterface.spaceDiffFlow(): Flow<List<SpaceListUpdate>> =
|
||||
callbackFlow {
|
||||
val listener = object : SpaceServiceJoinedSpacesListener {
|
||||
override fun onUpdate(roomUpdates: List<SpaceListUpdate>) {
|
||||
trySendBlocking(roomUpdates)
|
||||
}
|
||||
}
|
||||
Timber.d("Open spaceDiffFlow for SpaceServiceInterface ${this@spaceDiffFlow}")
|
||||
val taskHandle = subscribeToJoinedSpaces(listener)
|
||||
awaitClose {
|
||||
Timber.d("Close spaceDiffFlow for SpaceServiceInterface ${this@spaceDiffFlow}")
|
||||
taskHandle.cancelAndDestroy()
|
||||
}
|
||||
}.catch {
|
||||
Timber.d(it, "spaceDiffFlow() failed")
|
||||
}.buffer(Channel.UNLIMITED)
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.bool.orFalse
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.SpaceId
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
|
||||
import io.element.android.libraries.matrix.impl.room.join.map
|
||||
import io.element.android.libraries.matrix.impl.room.map
|
||||
import org.matrix.rustcomponents.sdk.SpaceRoom as RustSpaceRoom
|
||||
|
||||
class SpaceRoomMapper {
|
||||
fun map(spaceRoom: RustSpaceRoom): SpaceRoom {
|
||||
return SpaceRoom(
|
||||
avatarUrl = spaceRoom.avatarUrl,
|
||||
canonicalAlias = spaceRoom.canonicalAlias?.let(::RoomAlias),
|
||||
childrenCount = spaceRoom.childrenCount.toInt(),
|
||||
guestCanJoin = spaceRoom.guestCanJoin,
|
||||
heroes = spaceRoom.heroes.orEmpty().map { it.map() },
|
||||
joinRule = spaceRoom.joinRule?.map(),
|
||||
name = spaceRoom.name,
|
||||
numJoinedMembers = spaceRoom.numJoinedMembers.toInt(),
|
||||
spaceId = spaceRoom.roomId.let(::SpaceId),
|
||||
roomType = spaceRoom.roomType.map(),
|
||||
state = spaceRoom.state?.map(),
|
||||
topic = spaceRoom.topic,
|
||||
worldReadable = spaceRoom.worldReadable.orFalse(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue