Split MatrixRoom into BaseRoom and JoinedRoom (#4561)
`JoinedRoom` will now contain both a mandatory live timeline reference and all the functionality associated to it. `BaseRoom` on the other hand will contain only functionality that's shared for both joined and not joined rooms. `NotJoinedRoom` is a wrapper around `RoomPreviewInfo` data and a possible local `BaseRoom`, if it exists. The `RustRoomFactory` cache is now gone since the persistent event cache should have the same effect.
This commit is contained in:
parent
91cb84ce8d
commit
619aa6f2de
193 changed files with 2921 additions and 2567 deletions
|
|
@ -9,9 +9,9 @@ package io.element.android.libraries.matrix.ui.model
|
|||
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
|
||||
fun MatrixRoomInfo.getAvatarData(size: AvatarSize) = AvatarData(
|
||||
fun RoomInfo.getAvatarData(size: AvatarSize) = AvatarData(
|
||||
id = id.value,
|
||||
name = name,
|
||||
url = avatarUrl,
|
||||
|
|
|
|||
|
|
@ -14,19 +14,19 @@ import androidx.compose.runtime.derivedStateOf
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.roomMembers
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.getRoomMemberAsState(userId: UserId): State<RoomMember?> {
|
||||
fun BaseRoom.getRoomMemberAsState(userId: UserId): State<RoomMember?> {
|
||||
val roomMembersState by membersStateFlow.collectAsState()
|
||||
return getRoomMemberAsState(roomMembersState = roomMembersState, userId = userId)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun getRoomMemberAsState(roomMembersState: MatrixRoomMembersState, userId: UserId): State<RoomMember?> {
|
||||
fun getRoomMemberAsState(roomMembersState: RoomMembersState, userId: UserId): State<RoomMember?> {
|
||||
val roomMembers = roomMembersState.roomMembers()
|
||||
return remember(roomMembers) {
|
||||
derivedStateOf {
|
||||
|
|
@ -38,7 +38,7 @@ fun getRoomMemberAsState(roomMembersState: MatrixRoomMembersState, userId: UserI
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.getDirectRoomMember(roomMembersState: MatrixRoomMembersState): State<RoomMember?> {
|
||||
fun BaseRoom.getDirectRoomMember(roomMembersState: RoomMembersState): State<RoomMember?> {
|
||||
val roomMembers = roomMembersState.roomMembers()
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return remember(roomMembersState, roomInfo.isDirect) {
|
||||
|
|
@ -52,6 +52,6 @@ fun MatrixRoom.getDirectRoomMember(roomMembersState: MatrixRoomMembersState): St
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.getCurrentRoomMember(roomMembersState: MatrixRoomMembersState): State<RoomMember?> {
|
||||
fun BaseRoom.getCurrentRoomMember(roomMembersState: RoomMembersState): State<RoomMember?> {
|
||||
return getRoomMemberAsState(roomMembersState = roomMembersState, userId = sessionId)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import androidx.compose.runtime.State
|
|||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.produceState
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.isDm
|
||||
|
|
@ -25,77 +25,77 @@ import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
|||
import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canSendMessageAsState(type: MessageEventType, updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canSendMessageAsState(type: MessageEventType, updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = true, key1 = updateKey) {
|
||||
value = canSendMessage(type).getOrElse { true }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canInviteAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canInviteAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canInvite().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canRedactOwnAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canRedactOwnAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canRedactOwn().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canRedactOtherAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canRedactOtherAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canRedactOther().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canCall(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canCall(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canUserJoinCall(sessionId).getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canPinUnpin(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canPinUnpin(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canUserPinUnpin(sessionId).getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.isDmAsState(): State<Boolean> {
|
||||
fun BaseRoom.isDmAsState(): State<Boolean> {
|
||||
return produceState(initialValue = false) {
|
||||
roomInfoFlow.collect { value = it.isDm }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canKickAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canKickAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canKick().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canBanAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canBanAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canBan().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canHandleKnockRequestsAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canHandleKnockRequestsAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canHandleKnockRequests().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.userPowerLevelAsState(updateKey: Long): State<Long> {
|
||||
fun BaseRoom.userPowerLevelAsState(updateKey: Long): State<Long> {
|
||||
return produceState(initialValue = 0, key1 = updateKey) {
|
||||
value = userRole(sessionId)
|
||||
.getOrDefault(RoomMember.Role.USER)
|
||||
|
|
@ -104,26 +104,26 @@ fun MatrixRoom.userPowerLevelAsState(updateKey: Long): State<Long> {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.isOwnUserAdmin(): Boolean {
|
||||
fun BaseRoom.isOwnUserAdmin(): Boolean {
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
val powerLevel = roomInfo.userPowerLevels[sessionId] ?: 0L
|
||||
return RoomMember.Role.forPowerLevel(powerLevel) == RoomMember.Role.ADMIN
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.rawName(): String? {
|
||||
fun BaseRoom.rawName(): String? {
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return roomInfo.rawName
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.topic(): String? {
|
||||
fun BaseRoom.topic(): String? {
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return roomInfo.topic
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.avatarUrl(): String? {
|
||||
fun BaseRoom.avatarUrl(): String? {
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return roomInfo.avatarUrl
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
|||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.roomMembers
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
|
|
@ -29,7 +29,7 @@ import kotlinx.coroutines.flow.launchIn
|
|||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun MatrixRoom.roomMemberIdentityStateChange(): Flow<ImmutableList<RoomMemberIdentityStateChange>> {
|
||||
fun JoinedRoom.roomMemberIdentityStateChange(): Flow<ImmutableList<RoomMemberIdentityStateChange>> {
|
||||
return roomInfoFlow
|
||||
.filter {
|
||||
// Room cannot become unencrypted, so we can just apply a filter here.
|
||||
|
|
@ -52,7 +52,7 @@ fun MatrixRoom.roomMemberIdentityStateChange(): Flow<ImmutableList<RoomMemberIde
|
|||
}
|
||||
}
|
||||
|
||||
fun ProduceStateScope<PersistentList<RoomMemberIdentityStateChange>>.observeRoomMemberIdentityStateChange(room: MatrixRoom) {
|
||||
fun ProduceStateScope<PersistentList<RoomMemberIdentityStateChange>>.observeRoomMemberIdentityStateChange(room: JoinedRoom) {
|
||||
room.roomMemberIdentityStateChange()
|
||||
.onEach { roomMemberIdentityStateChanges ->
|
||||
value = roomMemberIdentityStateChanges.toPersistentList()
|
||||
|
|
|
|||
|
|
@ -11,26 +11,26 @@ import app.cash.molecule.RecompositionMode
|
|||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipState
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID_3
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class MatrixRoomMembersTest {
|
||||
class RoomMembersTest {
|
||||
private val roomMember1 = aRoomMember(A_USER_ID)
|
||||
private val roomMember2 = aRoomMember(A_USER_ID_2)
|
||||
private val roomMember3 = aRoomMember(A_USER_ID_3)
|
||||
|
||||
@Test
|
||||
fun `getDirectRoomMember emits other member for encrypted DM with 2 joined members`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(
|
||||
isDirect = true,
|
||||
|
|
@ -38,8 +38,8 @@ class MatrixRoomMembersTest {
|
|||
)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
)
|
||||
}.test {
|
||||
assertThat(awaitItem().value).isEqualTo(roomMember2)
|
||||
|
|
@ -48,13 +48,13 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emit null if the room is not a dm`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(isDirect = false)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
)
|
||||
}.test {
|
||||
assertThat(awaitItem().value).isNull()
|
||||
|
|
@ -63,7 +63,7 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emits other member even if the room is not encrypted`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(
|
||||
isDirect = true,
|
||||
|
|
@ -71,8 +71,8 @@ class MatrixRoomMembersTest {
|
|||
)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
)
|
||||
}.test {
|
||||
assertThat(awaitItem().value).isEqualTo(roomMember2)
|
||||
|
|
@ -81,13 +81,13 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emit null if the room has only 1 member`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(isDirect = true)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(persistentListOf(roomMember1))
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(persistentListOf(roomMember1))
|
||||
)
|
||||
}.test {
|
||||
assertThat(awaitItem().value).isNull()
|
||||
|
|
@ -96,14 +96,14 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emit null if the room has only 3 members`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
).apply {
|
||||
givenRoomInfo(aRoomInfo(isDirect = true))
|
||||
}
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2, roomMember3))
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2, roomMember3))
|
||||
)
|
||||
}.test {
|
||||
assertThat(awaitItem().value).isNull()
|
||||
|
|
@ -112,13 +112,13 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emit null if the other member is not active`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(isDirect = true),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(
|
||||
persistentListOf(
|
||||
roomMember1,
|
||||
roomMember2.copy(membership = RoomMembershipState.BAN),
|
||||
|
|
@ -132,7 +132,7 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emit the other member if there are 2 active members`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(
|
||||
isDirect = true,
|
||||
|
|
@ -140,8 +140,8 @@ class MatrixRoomMembersTest {
|
|||
)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(
|
||||
persistentListOf(
|
||||
roomMember1,
|
||||
roomMember2,
|
||||
|
|
@ -156,10 +156,10 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getCurrentRoomMember returns the current user`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(sessionId = A_USER_ID)
|
||||
val joinedRoom = FakeBaseRoom(sessionId = A_USER_ID)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getCurrentRoomMember(
|
||||
MatrixRoomMembersState.Ready(
|
||||
joinedRoom.getCurrentRoomMember(
|
||||
RoomMembersState.Ready(
|
||||
persistentListOf(
|
||||
roomMember1,
|
||||
roomMember2,
|
||||
|
|
@ -174,10 +174,10 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getCurrentRoomMember returns null if the member is not found`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(sessionId = A_USER_ID)
|
||||
val joinedRoom = FakeBaseRoom(sessionId = A_USER_ID)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getCurrentRoomMember(
|
||||
MatrixRoomMembersState.Ready(
|
||||
joinedRoom.getCurrentRoomMember(
|
||||
RoomMembersState.Ready(
|
||||
persistentListOf(
|
||||
roomMember2,
|
||||
roomMember3,
|
||||
Loading…
Add table
Add a link
Reference in a new issue