Merge pull request #5786 from element-hq/feature/bma/addAdminConfirmation
Ensure confirmation dialog is displayed when an admin add other admin to a room
This commit is contained in:
commit
80d799c4db
16 changed files with 260 additions and 124 deletions
|
|
@ -12,6 +12,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
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.produceState
|
import androidx.compose.runtime.produceState
|
||||||
|
|
@ -104,7 +105,11 @@ class ChangeRolesPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasPendingChanges = usersWithRole.value != selectedUsers.value
|
val hasPendingChanges by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
usersWithRole.value.toSet() != selectedUsers.value.toSet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val roomInfo by room.roomInfoFlow.collectAsState()
|
val roomInfo by room.roomInfoFlow.collectAsState()
|
||||||
fun canChangeMemberRole(userId: UserId): Boolean {
|
fun canChangeMemberRole(userId: UserId): Boolean {
|
||||||
|
|
@ -134,16 +139,20 @@ class ChangeRolesPresenter(
|
||||||
is ChangeRolesEvent.Save -> {
|
is ChangeRolesEvent.Save -> {
|
||||||
val currentUserIsAdmin = roomInfo.roleOf(room.sessionId) == RoomMember.Role.Admin
|
val currentUserIsAdmin = roomInfo.roleOf(room.sessionId) == RoomMember.Role.Admin
|
||||||
val isModifyingAdmins = role == RoomMember.Role.Admin
|
val isModifyingAdmins = role == RoomMember.Role.Admin
|
||||||
val hasChanges = selectedUsers != usersWithRole
|
|
||||||
val isConfirming = saveState.value.isConfirming()
|
val isConfirming = saveState.value.isConfirming()
|
||||||
val modifyingOwners = role is RoomMember.Role.Owner
|
val modifyingOwners = role is RoomMember.Role.Owner
|
||||||
|
val confirmationValue = if (hasPendingChanges && !isConfirming) {
|
||||||
val needsConfirmation = (modifyingOwners || currentUserIsAdmin && isModifyingAdmins) && hasChanges && !isConfirming
|
when {
|
||||||
|
modifyingOwners -> ConfirmingModifyingOwners
|
||||||
|
currentUserIsAdmin && isModifyingAdmins -> ConfirmingModifyingAdmins
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
when {
|
when {
|
||||||
needsConfirmation -> {
|
confirmationValue != null -> {
|
||||||
// Confirm modifying users
|
saveState.value = confirmationValue
|
||||||
saveState.value = AsyncAction.ConfirmingNoParams
|
|
||||||
}
|
}
|
||||||
!saveState.value.isLoading() -> {
|
!saveState.value.isLoading() -> {
|
||||||
roomCoroutineScope.save(usersWithRole.value, selectedUsers, saveState)
|
roomCoroutineScope.save(usersWithRole.value, selectedUsers, saveState)
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ class ChangeRolesStateProvider : PreviewParameterProvider<ChangeRolesState> {
|
||||||
selectedUsers = aMatrixUserList().take(1).toImmutableList(),
|
selectedUsers = aMatrixUserList().take(1).toImmutableList(),
|
||||||
),
|
),
|
||||||
aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.ConfirmingCancellation),
|
aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.ConfirmingCancellation),
|
||||||
aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.ConfirmingNoParams),
|
aChangeRolesStateWithSelectedUsers().copy(savingState = ConfirmingModifyingAdmins),
|
||||||
aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.Loading),
|
aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.Loading),
|
||||||
aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.Success(true)),
|
aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.Success(true)),
|
||||||
aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.Failure(Exception("boom"))),
|
aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.Failure(Exception("boom"))),
|
||||||
|
|
@ -58,6 +58,8 @@ class ChangeRolesStateProvider : PreviewParameterProvider<ChangeRolesState> {
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
aChangeRolesStateWithOwners(role = RoomMember.Role.Owner(isCreator = false)),
|
aChangeRolesStateWithOwners(role = RoomMember.Role.Owner(isCreator = false)),
|
||||||
|
aChangeRolesStateWithOwners(role = RoomMember.Role.Owner(isCreator = false))
|
||||||
|
.copy(savingState = ConfirmingModifyingOwners),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -178,29 +178,23 @@ fun ChangeRolesView(
|
||||||
onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) }
|
onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
is ConfirmingModifyingOwners -> {
|
||||||
when (state.role) {
|
ConfirmationDialog(
|
||||||
is RoomMember.Role.Owner -> {
|
title = stringResource(R.string.screen_room_change_role_confirm_change_owners_title),
|
||||||
ConfirmationDialog(
|
content = stringResource(R.string.screen_room_change_role_confirm_change_owners_description),
|
||||||
title = stringResource(R.string.screen_room_change_role_confirm_change_owners_title),
|
submitText = stringResource(CommonStrings.action_continue),
|
||||||
content = stringResource(R.string.screen_room_change_role_confirm_change_owners_description),
|
onSubmitClick = { state.eventSink(ChangeRolesEvent.Save) },
|
||||||
submitText = stringResource(CommonStrings.action_continue),
|
onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) },
|
||||||
onSubmitClick = { state.eventSink(ChangeRolesEvent.Save) },
|
destructiveSubmit = true,
|
||||||
onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) },
|
)
|
||||||
destructiveSubmit = true,
|
}
|
||||||
)
|
is ConfirmingModifyingAdmins -> {
|
||||||
}
|
ConfirmationDialog(
|
||||||
is RoomMember.Role.Admin -> {
|
title = stringResource(R.string.screen_room_change_role_confirm_add_admin_title),
|
||||||
ConfirmationDialog(
|
content = stringResource(R.string.screen_room_change_role_confirm_add_admin_description),
|
||||||
title = stringResource(R.string.screen_room_change_role_confirm_add_admin_title),
|
onSubmitClick = { state.eventSink(ChangeRolesEvent.Save) },
|
||||||
content = stringResource(R.string.screen_room_change_role_confirm_add_admin_description),
|
onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) }
|
||||||
onSubmitClick = { state.eventSink(ChangeRolesEvent.Save) },
|
)
|
||||||
onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// No confirmation needed for Moderator or User roles
|
|
||||||
else -> Unit
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations 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.features.rolesandpermissions.impl.roles
|
||||||
|
|
||||||
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
|
|
||||||
|
data object ConfirmingModifyingAdmins : AsyncAction.Confirming
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations 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.features.rolesandpermissions.impl.roles
|
||||||
|
|
||||||
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
|
|
||||||
|
data object ConfirmingModifyingOwners : AsyncAction.Confirming
|
||||||
|
|
@ -8,9 +8,6 @@
|
||||||
|
|
||||||
package io.element.android.features.rolesandpermissions.impl.roles
|
package io.element.android.features.rolesandpermissions.impl.roles
|
||||||
|
|
||||||
import app.cash.molecule.RecompositionMode
|
|
||||||
import app.cash.molecule.moleculeFlow
|
|
||||||
import app.cash.turbine.test
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import im.vector.app.features.analytics.plan.RoomModeration
|
import im.vector.app.features.analytics.plan.RoomModeration
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
|
|
@ -31,6 +28,7 @@ import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||||
import io.element.android.libraries.matrix.test.room.defaultRoomPowerLevelValues
|
import io.element.android.libraries.matrix.test.room.defaultRoomPowerLevelValues
|
||||||
import io.element.android.libraries.previewutils.room.aRoomMemberList
|
import io.element.android.libraries.previewutils.room.aRoomMemberList
|
||||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||||
|
import io.element.android.tests.testutils.test
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
@ -43,9 +41,7 @@ class ChangeRolesPresenterTest {
|
||||||
@Test
|
@Test
|
||||||
fun `present - initial state`() = runTest {
|
fun `present - initial state`() = runTest {
|
||||||
val presenter = createChangeRolesPresenter()
|
val presenter = createChangeRolesPresenter()
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
with(awaitItem()) {
|
with(awaitItem()) {
|
||||||
assertThat(role).isEqualTo(RoomMember.Role.Admin)
|
assertThat(role).isEqualTo(RoomMember.Role.Admin)
|
||||||
assertThat(query).isNull()
|
assertThat(query).isNull()
|
||||||
|
|
@ -65,16 +61,14 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList()))
|
givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList()))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(room = room)
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
assertThat(awaitItem().searchResults).isInstanceOf(SearchBarResultState.Results::class.java)
|
assertThat(awaitItem().searchResults).isInstanceOf(SearchBarResultState.Results::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - canChangeRole of users with lower power level unless they are owners`() = runTest {
|
fun `present - canChangeRole of users with lower power level unless they are owners - privilegedCreatorRole is true`() = runTest {
|
||||||
val creatorUserId = UserId("@creator:matrix.org")
|
val creatorUserId = UserId("@creator:matrix.org")
|
||||||
val superAdminUserId = UserId("@super_admin:matrix.org")
|
val superAdminUserId = UserId("@super_admin:matrix.org")
|
||||||
|
|
||||||
|
|
@ -82,6 +76,7 @@ class ChangeRolesPresenterTest {
|
||||||
// User is a creator, so they can change roles of other members. So is `creatorUserId`.
|
// User is a creator, so they can change roles of other members. So is `creatorUserId`.
|
||||||
givenRoomInfo(
|
givenRoomInfo(
|
||||||
aRoomInfo(
|
aRoomInfo(
|
||||||
|
privilegedCreatorRole = true,
|
||||||
roomCreators = listOf(sessionId, creatorUserId),
|
roomCreators = listOf(sessionId, creatorUserId),
|
||||||
roomPowerLevels = RoomPowerLevels(
|
roomPowerLevels = RoomPowerLevels(
|
||||||
defaultRoomPowerLevelValues(),
|
defaultRoomPowerLevelValues(),
|
||||||
|
|
@ -99,16 +94,14 @@ class ChangeRolesPresenterTest {
|
||||||
|
|
||||||
val roomMemberList = aRoomMemberList() + listOf(
|
val roomMemberList = aRoomMemberList() + listOf(
|
||||||
// Owner - superadmin
|
// Owner - superadmin
|
||||||
aRoomMember(userId = superAdminUserId, role = RoomMember.Role.Owner(isCreator = true)),
|
aRoomMember(userId = superAdminUserId, role = RoomMember.Role.Owner(isCreator = false)),
|
||||||
// Owner - creator
|
// Owner - creator
|
||||||
aRoomMember(userId = creatorUserId, role = RoomMember.Role.Owner(isCreator = true))
|
aRoomMember(userId = creatorUserId, role = RoomMember.Role.Owner(isCreator = true))
|
||||||
)
|
)
|
||||||
givenRoomMembersState(RoomMembersState.Ready(roomMemberList.toImmutableList()))
|
givenRoomMembersState(RoomMembersState.Ready(roomMemberList.toImmutableList()))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(room = room)
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
awaitItem().run {
|
awaitItem().run {
|
||||||
assertThat(canChangeMemberRole(A_USER_ID_2)).isTrue() // Admin
|
assertThat(canChangeMemberRole(A_USER_ID_2)).isTrue() // Admin
|
||||||
|
|
@ -118,6 +111,53 @@ class ChangeRolesPresenterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - canChangeRole of users with lower power level unless they are owners - privilegedCreatorRole is false`() = runTest {
|
||||||
|
val creatorUserId = UserId("@creator:matrix.org")
|
||||||
|
val superAdminUserId = UserId("@super_admin:matrix.org")
|
||||||
|
|
||||||
|
val room = FakeJoinedRoom().apply {
|
||||||
|
// User is a creator, so they can change roles of other members. So is `creatorUserId`.
|
||||||
|
givenRoomInfo(
|
||||||
|
aRoomInfo(
|
||||||
|
privilegedCreatorRole = false,
|
||||||
|
roomCreators = listOf(sessionId, creatorUserId),
|
||||||
|
roomPowerLevels = RoomPowerLevels(
|
||||||
|
defaultRoomPowerLevelValues(),
|
||||||
|
users = persistentMapOf(
|
||||||
|
// Creator is an admin
|
||||||
|
sessionId to RoomMember.Role.Admin.powerLevel,
|
||||||
|
creatorUserId to RoomMember.Role.Admin.powerLevel,
|
||||||
|
// bob is Admin
|
||||||
|
A_USER_ID_2 to RoomMember.Role.Admin.powerLevel,
|
||||||
|
// carol is Moderator
|
||||||
|
A_USER_ID_3 to RoomMember.Role.Moderator.powerLevel,
|
||||||
|
// super_admin is Owner - Superadmin
|
||||||
|
superAdminUserId to RoomMember.Role.Owner(isCreator = false).powerLevel,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val roomMemberList = aRoomMemberList() + listOf(
|
||||||
|
// Owner - superadmin
|
||||||
|
aRoomMember(userId = superAdminUserId, role = RoomMember.Role.Owner(isCreator = false)),
|
||||||
|
// Owner - creator
|
||||||
|
aRoomMember(userId = creatorUserId, role = RoomMember.Role.Owner(isCreator = true))
|
||||||
|
)
|
||||||
|
givenRoomMembersState(RoomMembersState.Ready(roomMemberList.toImmutableList()))
|
||||||
|
}
|
||||||
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
|
presenter.test {
|
||||||
|
skipItems(1)
|
||||||
|
awaitItem().run {
|
||||||
|
assertThat(canChangeMemberRole(A_USER_ID_2)).isFalse() // Creator cannot update Admin in this case
|
||||||
|
assertThat(canChangeMemberRole(A_USER_ID_3)).isTrue() // Moderator
|
||||||
|
assertThat(canChangeMemberRole(creatorUserId)).isFalse() // Owner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - when modifying admins, creators are displayed too`() = runTest {
|
fun `present - when modifying admins, creators are displayed too`() = runTest {
|
||||||
val room = FakeJoinedRoom().apply {
|
val room = FakeJoinedRoom().apply {
|
||||||
|
|
@ -129,9 +169,7 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomMembersState(RoomMembersState.Ready(memberList))
|
givenRoomMembersState(RoomMembersState.Ready(memberList))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(room = room)
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
awaitItem().searchResults.run {
|
awaitItem().searchResults.run {
|
||||||
assertThat(this).isInstanceOf(SearchBarResultState.Results::class.java)
|
assertThat(this).isInstanceOf(SearchBarResultState.Results::class.java)
|
||||||
|
|
@ -149,9 +187,7 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList()))
|
givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList()))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(room = room)
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
|
|
||||||
initialState.eventSink(ChangeRolesEvent.ToggleSearchActive)
|
initialState.eventSink(ChangeRolesEvent.ToggleSearchActive)
|
||||||
|
|
@ -168,9 +204,7 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList()))
|
givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList()))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(room = room)
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
val initialResults = (awaitItem().searchResults as? SearchBarResultState.Results)?.results
|
val initialResults = (awaitItem().searchResults as? SearchBarResultState.Results)?.results
|
||||||
assertThat(initialResults?.members).hasSize(8)
|
assertThat(initialResults?.members).hasSize(8)
|
||||||
|
|
@ -194,9 +228,7 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList()))
|
givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList()))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(room = room)
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val initialResults = (awaitItem().searchResults as? SearchBarResultState.Results)?.results
|
val initialResults = (awaitItem().searchResults as? SearchBarResultState.Results)?.results
|
||||||
assertThat(initialResults?.members).hasSize(8)
|
assertThat(initialResults?.members).hasSize(8)
|
||||||
|
|
@ -221,9 +253,7 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(room = room)
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.selectedUsers).hasSize(1)
|
assertThat(initialState.selectedUsers).hasSize(1)
|
||||||
|
|
@ -243,9 +273,7 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(room = room)
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.hasPendingChanges).isFalse()
|
assertThat(initialState.hasPendingChanges).isFalse()
|
||||||
|
|
@ -272,9 +300,7 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(room = room)
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.hasPendingChanges).isFalse()
|
assertThat(initialState.hasPendingChanges).isFalse()
|
||||||
|
|
@ -292,9 +318,7 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(room = room)
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.hasPendingChanges).isFalse()
|
assertThat(initialState.hasPendingChanges).isFalse()
|
||||||
|
|
@ -318,9 +342,7 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(room = room)
|
val presenter = createChangeRolesPresenter(room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.hasPendingChanges).isFalse()
|
assertThat(initialState.hasPendingChanges).isFalse()
|
||||||
|
|
@ -349,16 +371,14 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(role = RoomMember.Role.Admin, room = room)
|
val presenter = createChangeRolesPresenter(role = RoomMember.Role.Admin, room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(2)
|
skipItems(2)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.selectedUsers).hasSize(1)
|
assertThat(initialState.selectedUsers).hasSize(1)
|
||||||
initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2)))
|
initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2)))
|
||||||
awaitItem().eventSink(ChangeRolesEvent.Save)
|
awaitItem().eventSink(ChangeRolesEvent.Save)
|
||||||
val confirmingState = awaitItem()
|
val confirmingState = awaitItem()
|
||||||
assertThat(confirmingState.savingState).isEqualTo(AsyncAction.ConfirmingNoParams)
|
assertThat(confirmingState.savingState).isEqualTo(ConfirmingModifyingAdmins)
|
||||||
confirmingState.eventSink(ChangeRolesEvent.Save)
|
confirmingState.eventSink(ChangeRolesEvent.Save)
|
||||||
assertThat(awaitItem().savingState).isInstanceOf(AsyncAction.Loading::class.java)
|
assertThat(awaitItem().savingState).isInstanceOf(AsyncAction.Loading::class.java)
|
||||||
assertThat(awaitItem().savingState).isEqualTo(AsyncAction.Success(true))
|
assertThat(awaitItem().savingState).isEqualTo(AsyncAction.Success(true))
|
||||||
|
|
@ -372,9 +392,7 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin)))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(role = RoomMember.Role.Admin, room = room)
|
val presenter = createChangeRolesPresenter(role = RoomMember.Role.Admin, room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.selectedUsers).hasSize(1)
|
assertThat(initialState.selectedUsers).hasSize(1)
|
||||||
|
|
@ -383,7 +401,7 @@ class ChangeRolesPresenterTest {
|
||||||
|
|
||||||
awaitItem().eventSink(ChangeRolesEvent.Save)
|
awaitItem().eventSink(ChangeRolesEvent.Save)
|
||||||
val confirmingState = awaitItem()
|
val confirmingState = awaitItem()
|
||||||
assertThat(confirmingState.savingState).isEqualTo(AsyncAction.ConfirmingNoParams)
|
assertThat(confirmingState.savingState).isEqualTo(ConfirmingModifyingAdmins)
|
||||||
|
|
||||||
confirmingState.eventSink(ChangeRolesEvent.CloseDialog)
|
confirmingState.eventSink(ChangeRolesEvent.CloseDialog)
|
||||||
assertThat(awaitItem().savingState).isEqualTo(AsyncAction.Uninitialized)
|
assertThat(awaitItem().savingState).isEqualTo(AsyncAction.Uninitialized)
|
||||||
|
|
@ -405,9 +423,7 @@ class ChangeRolesPresenterTest {
|
||||||
room = room,
|
room = room,
|
||||||
analyticsService = analyticsService
|
analyticsService = analyticsService
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(2)
|
skipItems(2)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.selectedUsers).hasSize(1)
|
assertThat(initialState.selectedUsers).hasSize(1)
|
||||||
|
|
@ -442,9 +458,7 @@ class ChangeRolesPresenterTest {
|
||||||
room = room,
|
room = room,
|
||||||
analyticsService = analyticsService
|
analyticsService = analyticsService
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.selectedUsers).hasSize(1)
|
assertThat(initialState.selectedUsers).hasSize(1)
|
||||||
|
|
@ -477,9 +491,7 @@ class ChangeRolesPresenterTest {
|
||||||
room = room,
|
room = room,
|
||||||
analyticsService = analyticsService
|
analyticsService = analyticsService
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(2)
|
skipItems(2)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.selectedUsers).hasSize(1)
|
assertThat(initialState.selectedUsers).hasSize(1)
|
||||||
|
|
@ -504,9 +516,7 @@ class ChangeRolesPresenterTest {
|
||||||
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(role = RoomMember.Role.Moderator, userId = A_USER_ID)))
|
givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(role = RoomMember.Role.Moderator, userId = A_USER_ID)))
|
||||||
}
|
}
|
||||||
val presenter = createChangeRolesPresenter(role = RoomMember.Role.Moderator, room = room)
|
val presenter = createChangeRolesPresenter(role = RoomMember.Role.Moderator, room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(2)
|
skipItems(2)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.selectedUsers).hasSize(1)
|
assertThat(initialState.selectedUsers).hasSize(1)
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,6 @@ class ChangeRolesViewTest {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}.exceptionOrNull()
|
}.exceptionOrNull()
|
||||||
|
|
||||||
assertThat(exception).isNotNull()
|
assertThat(exception).isNotNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,9 +62,7 @@ class ChangeRolesViewTest {
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.pressBackKey()
|
rule.pressBackKey()
|
||||||
|
|
||||||
eventsRecorder.assertSingle(ChangeRolesEvent.ToggleSearchActive)
|
eventsRecorder.assertSingle(ChangeRolesEvent.ToggleSearchActive)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,9 +75,7 @@ class ChangeRolesViewTest {
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.pressBackKey()
|
rule.pressBackKey()
|
||||||
|
|
||||||
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Exit))
|
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Exit))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,9 +88,7 @@ class ChangeRolesViewTest {
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.pressBack()
|
rule.pressBack()
|
||||||
|
|
||||||
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Exit))
|
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Exit))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,9 +101,7 @@ class ChangeRolesViewTest {
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.clickOn(CommonStrings.action_save)
|
rule.clickOn(CommonStrings.action_save)
|
||||||
|
|
||||||
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Save))
|
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Save))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,9 +114,7 @@ class ChangeRolesViewTest {
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.clickOn(CommonStrings.action_save)
|
rule.clickOn(CommonStrings.action_save)
|
||||||
|
|
||||||
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged("")))
|
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged("")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,9 +128,7 @@ class ChangeRolesViewTest {
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.clickOn(CommonStrings.action_ok)
|
rule.clickOn(CommonStrings.action_ok)
|
||||||
|
|
||||||
eventsRecorder.assertSingle(ChangeRolesEvent.Exit)
|
eventsRecorder.assertSingle(ChangeRolesEvent.Exit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,26 +142,22 @@ class ChangeRolesViewTest {
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.clickOn(CommonStrings.action_cancel)
|
rule.clickOn(CommonStrings.action_cancel)
|
||||||
|
|
||||||
eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog)
|
eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `save confirmation dialog - submit saves the changes`() {
|
fun `save admins confirmation dialog - submit saves the changes`() {
|
||||||
val eventsRecorder = EventsRecorder<ChangeRolesEvent>()
|
val eventsRecorder = EventsRecorder<ChangeRolesEvent>()
|
||||||
rule.setChangeRolesContent(
|
rule.setChangeRolesContent(
|
||||||
state = aChangeRolesState(
|
state = aChangeRolesState(
|
||||||
role = RoomMember.Role.Admin,
|
role = RoomMember.Role.Admin,
|
||||||
isSearchActive = true,
|
isSearchActive = true,
|
||||||
savingState = AsyncAction.ConfirmingNoParams,
|
savingState = ConfirmingModifyingAdmins,
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.clickOn(CommonStrings.action_ok)
|
rule.clickOn(CommonStrings.action_ok)
|
||||||
|
|
||||||
eventsRecorder.assertSingle(ChangeRolesEvent.Save)
|
eventsRecorder.assertSingle(ChangeRolesEvent.Save)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,30 +168,41 @@ class ChangeRolesViewTest {
|
||||||
state = aChangeRolesState(
|
state = aChangeRolesState(
|
||||||
role = RoomMember.Role.Owner(isCreator = false),
|
role = RoomMember.Role.Owner(isCreator = false),
|
||||||
isSearchActive = true,
|
isSearchActive = true,
|
||||||
savingState = AsyncAction.ConfirmingNoParams,
|
savingState = ConfirmingModifyingOwners,
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.clickOn(CommonStrings.action_continue)
|
rule.clickOn(CommonStrings.action_continue)
|
||||||
|
|
||||||
eventsRecorder.assertSingle(ChangeRolesEvent.Save)
|
eventsRecorder.assertSingle(ChangeRolesEvent.Save)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `save confirmation dialog - cancel removes the dialog`() {
|
fun `save admins confirmation dialog - cancel removes the dialog`() {
|
||||||
val eventsRecorder = EventsRecorder<ChangeRolesEvent>()
|
val eventsRecorder = EventsRecorder<ChangeRolesEvent>()
|
||||||
rule.setChangeRolesContent(
|
rule.setChangeRolesContent(
|
||||||
state = aChangeRolesState(
|
state = aChangeRolesState(
|
||||||
role = RoomMember.Role.Admin,
|
role = RoomMember.Role.Admin,
|
||||||
isSearchActive = true,
|
isSearchActive = true,
|
||||||
savingState = AsyncAction.ConfirmingNoParams,
|
savingState = ConfirmingModifyingAdmins,
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.clickOn(CommonStrings.action_cancel)
|
rule.clickOn(CommonStrings.action_cancel)
|
||||||
|
eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `save owners confirmation dialog - cancel removes the dialog`() {
|
||||||
|
val eventsRecorder = EventsRecorder<ChangeRolesEvent>()
|
||||||
|
rule.setChangeRolesContent(
|
||||||
|
state = aChangeRolesState(
|
||||||
|
role = RoomMember.Role.Owner(isCreator = false),
|
||||||
|
isSearchActive = true,
|
||||||
|
savingState = ConfirmingModifyingOwners,
|
||||||
|
eventSink = eventsRecorder,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
rule.clickOn(CommonStrings.action_cancel)
|
||||||
eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog)
|
eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,9 +216,7 @@ class ChangeRolesViewTest {
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.clickOn(CommonStrings.action_ok)
|
rule.clickOn(CommonStrings.action_ok)
|
||||||
|
|
||||||
eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog)
|
eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,7 @@ class RoomDetailsPresenter(
|
||||||
canReportRoom = canReportRoom,
|
canReportRoom = canReportRoom,
|
||||||
isTombstoned = roomInfo.successorRoom != null,
|
isTombstoned = roomInfo.successorRoom != null,
|
||||||
showDebugInfo = isDeveloperModeEnabled,
|
showDebugInfo = isDeveloperModeEnabled,
|
||||||
|
roomVersion = roomInfo.roomVersion,
|
||||||
eventSink = ::handleEvent,
|
eventSink = ::handleEvent,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ data class RoomDetailsState(
|
||||||
val canReportRoom: Boolean,
|
val canReportRoom: Boolean,
|
||||||
val isTombstoned: Boolean,
|
val isTombstoned: Boolean,
|
||||||
val showDebugInfo: Boolean,
|
val showDebugInfo: Boolean,
|
||||||
|
val roomVersion: String?,
|
||||||
val eventSink: (RoomDetailsEvent) -> Unit
|
val eventSink: (RoomDetailsEvent) -> Unit
|
||||||
) {
|
) {
|
||||||
val roomBadges = buildList {
|
val roomBadges = buildList {
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ fun aRoomDetailsState(
|
||||||
canReportRoom = canReportRoom,
|
canReportRoom = canReportRoom,
|
||||||
isTombstoned = isTombstoned,
|
isTombstoned = isTombstoned,
|
||||||
showDebugInfo = showDebugInfo,
|
showDebugInfo = showDebugInfo,
|
||||||
|
roomVersion = "12",
|
||||||
eventSink = eventSink,
|
eventSink = eventSink,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -264,6 +264,7 @@ fun RoomDetailsView(
|
||||||
if (state.showDebugInfo) {
|
if (state.showDebugInfo) {
|
||||||
DebugInfoSection(
|
DebugInfoSection(
|
||||||
roomId = state.roomId,
|
roomId = state.roomId,
|
||||||
|
roomVersion = state.roomVersion,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -714,7 +715,10 @@ private fun OtherActionsSection(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DebugInfoSection(roomId: RoomId) {
|
private fun DebugInfoSection(
|
||||||
|
roomId: RoomId,
|
||||||
|
roomVersion: String?,
|
||||||
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
PreferenceCategory(showTopDivider = true) {
|
PreferenceCategory(showTopDivider = true) {
|
||||||
ListItem(
|
ListItem(
|
||||||
|
|
@ -737,6 +741,19 @@ private fun DebugInfoSection(roomId: RoomId) {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text("Room version")
|
||||||
|
},
|
||||||
|
supportingContent = {
|
||||||
|
Text(
|
||||||
|
text = roomVersion ?: "Unknown",
|
||||||
|
style = ElementTheme.typography.fontBodySmRegular,
|
||||||
|
color = ElementTheme.colors.textSecondary,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Info())),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ fun aRoomInfo(
|
||||||
notificationCount: Long = 0,
|
notificationCount: Long = 0,
|
||||||
userDefinedNotificationMode: RoomNotificationMode? = null,
|
userDefinedNotificationMode: RoomNotificationMode? = null,
|
||||||
hasRoomCall: Boolean = false,
|
hasRoomCall: Boolean = false,
|
||||||
roomPowerLevels: RoomPowerLevels = RoomPowerLevels(
|
roomPowerLevels: RoomPowerLevels? = RoomPowerLevels(
|
||||||
values = defaultRoomPowerLevelValues(),
|
values = defaultRoomPowerLevelValues(),
|
||||||
users = persistentMapOf(),
|
users = persistentMapOf(),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,12 @@ fun RoomInfo.getAvatarData(size: AvatarSize) = AvatarData(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the role of the user in the room.
|
* Returns the role of the user in the room.
|
||||||
* If the user is a creator, returns [RoomMember.Role.Owner].
|
* If the user is a creator and [RoomInfo.privilegedCreatorRole] is true, returns [RoomMember.Role.Owner].
|
||||||
* Otherwise, checks the power levels and returns the corresponding role.
|
* Otherwise, checks the power levels and returns the corresponding role.
|
||||||
* If no specific power level is set for the user, defaults to [RoomMember.Role.User].
|
* If no specific power level is set for the user, defaults to [RoomMember.Role.User].
|
||||||
*/
|
*/
|
||||||
fun RoomInfo.roleOf(userId: UserId): RoomMember.Role {
|
fun RoomInfo.roleOf(userId: UserId): RoomMember.Role {
|
||||||
return if (creators.contains(userId)) {
|
return if (privilegedCreatorRole && creators.contains(userId)) {
|
||||||
RoomMember.Role.Owner(isCreator = true)
|
RoomMember.Role.Owner(isCreator = true)
|
||||||
} else {
|
} else {
|
||||||
roomPowerLevels?.roleOf(userId) ?: RoomMember.Role.User
|
roomPowerLevels?.roleOf(userId) ?: RoomMember.Role.User
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations 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.ui.model
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||||
|
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||||
|
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.aRoomInfo
|
||||||
|
import io.element.android.libraries.matrix.test.room.defaultRoomPowerLevelValues
|
||||||
|
import kotlinx.collections.immutable.toImmutableMap
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class RoomInfoExtensionTest {
|
||||||
|
@Test
|
||||||
|
fun `roleOf returns Owner for creator with privilegedCreatorRole true`() {
|
||||||
|
val roomInfo = aRoomInfo(
|
||||||
|
privilegedCreatorRole = true,
|
||||||
|
roomCreators = listOf(A_USER_ID),
|
||||||
|
)
|
||||||
|
assertThat(roomInfo.roleOf(A_USER_ID)).isEqualTo(RoomMember.Role.Owner(isCreator = true))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `roleOf returns User for not creator with privilegedCreatorRole true`() {
|
||||||
|
val roomInfo = aRoomInfo(
|
||||||
|
privilegedCreatorRole = true,
|
||||||
|
roomCreators = listOf(A_USER_ID),
|
||||||
|
)
|
||||||
|
assertThat(roomInfo.roleOf(A_USER_ID_2)).isEqualTo(RoomMember.Role.User)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `roleOf returns User for creator with privilegedCreatorRole false`() {
|
||||||
|
val roomInfo = aRoomInfo(
|
||||||
|
privilegedCreatorRole = false,
|
||||||
|
roomCreators = listOf(A_USER_ID),
|
||||||
|
)
|
||||||
|
assertThat(roomInfo.roleOf(A_USER_ID)).isEqualTo(RoomMember.Role.User)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `roleOf returns role from the power level`() {
|
||||||
|
val roomInfo = aRoomInfo(
|
||||||
|
privilegedCreatorRole = false,
|
||||||
|
roomPowerLevels = RoomPowerLevels(
|
||||||
|
values = defaultRoomPowerLevelValues(),
|
||||||
|
users = mapOf(
|
||||||
|
A_USER_ID to 100L, // Admin
|
||||||
|
A_USER_ID_2 to 50L, // Moderator
|
||||||
|
A_USER_ID_3 to 0L, // User
|
||||||
|
).toImmutableMap(),
|
||||||
|
),
|
||||||
|
roomCreators = listOf(A_USER_ID),
|
||||||
|
)
|
||||||
|
assertThat(roomInfo.roleOf(A_USER_ID)).isEqualTo(RoomMember.Role.Admin)
|
||||||
|
assertThat(roomInfo.roleOf(A_USER_ID_2)).isEqualTo(RoomMember.Role.Moderator)
|
||||||
|
assertThat(roomInfo.roleOf(A_USER_ID_3)).isEqualTo(RoomMember.Role.User)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `roleOf returns User when the power level is null`() {
|
||||||
|
val roomInfo = aRoomInfo(
|
||||||
|
privilegedCreatorRole = false,
|
||||||
|
roomPowerLevels = null,
|
||||||
|
roomCreators = listOf(A_USER_ID),
|
||||||
|
)
|
||||||
|
assertThat(roomInfo.roleOf(A_USER_ID)).isEqualTo(RoomMember.Role.User)
|
||||||
|
assertThat(roomInfo.roleOf(A_USER_ID_2)).isEqualTo(RoomMember.Role.User)
|
||||||
|
assertThat(roomInfo.roleOf(A_USER_ID_3)).isEqualTo(RoomMember.Role.User)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:fbee2417fcd701fce6d3f4d20e677681de6d529e5a17f0bfffc1c1592d73398a
|
||||||
|
size 58939
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:41698290446bc0f2e58fac106cdef381c1b46f3655ff51fff574ff867cd70d10
|
||||||
|
size 57006
|
||||||
Loading…
Add table
Add a link
Reference in a new issue