[Room member list] Display room member list (#276)
* Implement room member list * Move timeline initialization back to `TimelinePresenter`. * Fix crash when the `innerRoom` inside a `RustMatrixRoom` is destroyed but `syncUpdateFlow` is still running. * Address review comments
This commit is contained in:
parent
f0b95d30be
commit
d7a6779343
62 changed files with 1159 additions and 157 deletions
|
|
@ -31,9 +31,11 @@ interface MatrixRoom: Closeable {
|
|||
val alternativeAliases: List<String>
|
||||
val topic: String?
|
||||
val avatarUrl: String?
|
||||
val members: List<RoomMember>
|
||||
val isEncrypted: Boolean
|
||||
|
||||
suspend fun members() : List<RoomMember>
|
||||
suspend fun memberCount(): Int
|
||||
|
||||
fun syncUpdateFlow(): Flow<Long>
|
||||
|
||||
fun timeline(): MatrixTimeline
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package io.element.android.libraries.matrix.impl.room
|
||||
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
|
|
@ -24,10 +25,12 @@ import io.element.android.libraries.matrix.api.room.RoomMember
|
|||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||
import io.element.android.libraries.matrix.impl.timeline.RustMatrixTimeline
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.Room
|
||||
import org.matrix.rustcomponents.sdk.SlidingSyncRoom
|
||||
|
|
@ -43,10 +46,32 @@ class RustMatrixRoom(
|
|||
private val coroutineDispatchers: CoroutineDispatchers,
|
||||
) : MatrixRoom {
|
||||
|
||||
private var loadMembersJob: Job? = null
|
||||
private var cachedMembers: List<RoomMember> = emptyList()
|
||||
|
||||
override suspend fun members(): List<RoomMember> {
|
||||
return cachedMembers.ifEmpty {
|
||||
if (loadMembersJob == null) {
|
||||
loadMembersJob = coroutineScope.launch(coroutineDispatchers.io) {
|
||||
cachedMembers = tryOrNull {
|
||||
innerRoom.members().map(RoomMemberMapper::map)
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
loadMembersJob?.join()
|
||||
loadMembersJob = null
|
||||
cachedMembers
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun memberCount(): Int {
|
||||
return members().size
|
||||
}
|
||||
|
||||
override fun syncUpdateFlow(): Flow<Long> {
|
||||
return slidingSyncUpdateFlow
|
||||
.filter {
|
||||
it.rooms.contains(innerRoom.id())
|
||||
it.rooms.contains(roomId.value)
|
||||
}
|
||||
.map {
|
||||
System.currentTimeMillis()
|
||||
|
|
@ -95,9 +120,6 @@ class RustMatrixRoom(
|
|||
return innerRoom.avatarUrl()
|
||||
}
|
||||
|
||||
override val members: List<RoomMember>
|
||||
get() = innerRoom.members().map(RoomMemberMapper::map)
|
||||
|
||||
override val isEncrypted: Boolean
|
||||
get() = innerRoom.isEncrypted()
|
||||
|
||||
|
|
|
|||
|
|
@ -87,14 +87,6 @@ class RustMatrixTimeline(
|
|||
|
||||
override fun initialize() {
|
||||
Timber.v("Init timeline for room ${matrixRoom.roomId}")
|
||||
coroutineScope.launch {
|
||||
matrixRoom.fetchMembers()
|
||||
.onFailure {
|
||||
Timber.e(it, "Fail to fetch members for room ${matrixRoom.roomId}")
|
||||
}.onSuccess {
|
||||
Timber.v("Success fetching members for room ${matrixRoom.roomId}")
|
||||
}
|
||||
}
|
||||
coroutineScope.launch {
|
||||
val result = addListener(innerTimelineListener)
|
||||
result
|
||||
|
|
|
|||
|
|
@ -34,13 +34,18 @@ class FakeMatrixRoom(
|
|||
override val displayName: String = "",
|
||||
override val topic: String? = null,
|
||||
override val avatarUrl: String? = null,
|
||||
override val members: List<RoomMember> = emptyList(),
|
||||
override val isEncrypted: Boolean = false,
|
||||
override val alias: String? = null,
|
||||
override val alternativeAliases: List<String> = emptyList(),
|
||||
private val members: List<RoomMember> = emptyList(),
|
||||
private val matrixTimeline: MatrixTimeline = FakeMatrixTimeline(),
|
||||
) : MatrixRoom {
|
||||
|
||||
private var fetchMemberResult: Result<Unit> = Result.success(Unit)
|
||||
|
||||
var areMembersFetched: Boolean = false
|
||||
private set
|
||||
|
||||
override fun syncUpdateFlow(): Flow<Long> {
|
||||
return emptyFlow()
|
||||
}
|
||||
|
|
@ -50,7 +55,11 @@ class FakeMatrixRoom(
|
|||
}
|
||||
|
||||
override suspend fun fetchMembers(): Result<Unit> {
|
||||
return Result.success(Unit)
|
||||
return fetchMemberResult.also { result ->
|
||||
if (result.isSuccess) {
|
||||
areMembersFetched = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun userDisplayName(userId: String): Result<String?> {
|
||||
|
|
@ -61,6 +70,18 @@ class FakeMatrixRoom(
|
|||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun members(): List<RoomMember> {
|
||||
return members
|
||||
}
|
||||
|
||||
override suspend fun memberCount(): Int {
|
||||
if (fetchMemberResult.isSuccess) {
|
||||
return members.count()
|
||||
} else {
|
||||
throw fetchMemberResult.exceptionOrNull()!!
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun sendMessage(message: String): Result<Unit> {
|
||||
delay(100)
|
||||
return Result.success(Unit)
|
||||
|
|
@ -94,4 +115,8 @@ class FakeMatrixRoom(
|
|||
}
|
||||
|
||||
override fun close() = Unit
|
||||
|
||||
fun givenFetchMemberResult(result: Result<Unit>) {
|
||||
fetchMemberResult = result
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue