diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsPresenter.kt index 659dc6c255..3f7224602d 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsPresenter.kt @@ -29,9 +29,11 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runUpdatingState import io.element.android.libraries.core.coroutine.CoroutineDispatchers +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.MatrixRoomInfo import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.joinedRoomMembers import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange import io.element.android.services.analytics.api.AnalyticsService import kotlinx.coroutines.CoroutineScope @@ -47,14 +49,22 @@ class RolesAndPermissionsPresenter @Inject constructor( override fun present(): RolesAndPermissionsState { val coroutineScope = rememberCoroutineScope() val roomInfo by room.roomInfoFlow.collectAsState(initial = null) + val roomMembers by room.membersStateFlow.collectAsState() + // Get the list of joined room members, in order to filter members present in the power + // level state Event, but not member of the room anymore. + val joinedRoomMemberIds by remember { + derivedStateOf { + roomMembers.joinedRoomMembers().map { it.userId } + } + } val moderatorCount by remember { derivedStateOf { - roomInfo.userCountWithRole(RoomMember.Role.MODERATOR) + roomInfo.userCountWithRole(joinedRoomMemberIds, RoomMember.Role.MODERATOR) } } val adminCount by remember { derivedStateOf { - roomInfo.userCountWithRole(RoomMember.Role.ADMIN) + roomInfo.userCountWithRole(joinedRoomMemberIds, RoomMember.Role.ADMIN) } } val changeOwnRoleAction = remember { mutableStateOf>(AsyncAction.Uninitialized) } @@ -108,11 +118,9 @@ class RolesAndPermissionsPresenter @Inject constructor( } } - private fun MatrixRoomInfo?.userCountWithRole(role: RoomMember.Role): Int { - return if (this != null) { - userPowerLevels.count { (_, level) -> RoomMember.Role.forPowerLevel(level) == role } - } else { - 0 + private fun MatrixRoomInfo?.userCountWithRole(joinedRoomMemberIds: List, role: RoomMember.Role): Int { + return this?.userPowerLevels.orEmpty().count { (userId, level) -> + RoomMember.Role.forPowerLevel(level) == role && userId in joinedRoomMemberIds } } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesEvent.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesEvent.kt index afb12a2e50..4176f5f9ce 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesEvent.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesEvent.kt @@ -16,12 +16,12 @@ package io.element.android.features.roomdetails.impl.rolesandpermissions.changeroles -import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.user.MatrixUser sealed interface ChangeRolesEvent { data object ToggleSearchActive : ChangeRolesEvent data class QueryChanged(val query: String?) : ChangeRolesEvent - data class UserSelectionToggled(val roomMember: RoomMember) : ChangeRolesEvent + data class UserSelectionToggled(val matrixUser: MatrixUser) : ChangeRolesEvent data object Save : ChangeRolesEvent data object Exit : ChangeRolesEvent data object CancelExit : ChangeRolesEvent diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenter.kt index dc1c2ef70e..403b3f3e5d 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenter.kt @@ -42,6 +42,8 @@ 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.RoomMember import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange +import io.element.android.libraries.matrix.api.room.powerlevels.usersWithRole +import io.element.android.libraries.matrix.api.room.toMatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.services.analytics.api.AnalyticsService import kotlinx.collections.immutable.ImmutableList @@ -129,11 +131,11 @@ class ChangeRolesPresenter @AssistedInject constructor( } is ChangeRolesEvent.UserSelectionToggled -> { val newList = selectedUsers.value.toMutableList() - val index = newList.indexOfFirst { it.userId == event.roomMember.userId } + val index = newList.indexOfFirst { it.userId == event.matrixUser.userId } if (index >= 0) { newList.removeAt(index) } else { - newList.add(event.roomMember.toMatrixUser()) + newList.add(event.matrixUser) } selectedUsers.value = newList.toImmutableList() } @@ -183,12 +185,6 @@ class ChangeRolesPresenter @AssistedInject constructor( return sortedWith(PowerLevelRoomMemberComparator()).toImmutableList() } - private fun RoomMember.toMatrixUser() = MatrixUser( - userId = userId, - displayName = displayName, - avatarUrl = avatarUrl, - ) - private fun CoroutineScope.save( usersWithRole: ImmutableList, selectedUsers: MutableState>, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesStateProvider.kt index 69e8d72be6..8cd5db01d6 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesStateProvider.kt @@ -62,6 +62,7 @@ internal fun aChangeRolesState( exitState: AsyncAction = AsyncAction.Uninitialized, savingState: AsyncAction = AsyncAction.Uninitialized, canRemoveMember: (UserId) -> Boolean = { true }, + eventSink: (ChangeRolesEvent) -> Unit = {}, ) = ChangeRolesState( role = role, query = query, @@ -72,7 +73,7 @@ internal fun aChangeRolesState( exitState = exitState, savingState = savingState, canChangeMemberRole = canRemoveMember, - eventSink = {}, + eventSink = eventSink, ) internal fun aChangeRolesStateWithSelectedUsers() = aChangeRolesState( diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesView.kt index 9510ca4272..f24ee3b0f1 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesView.kt @@ -46,7 +46,6 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.features.roomdetails.impl.R -import io.element.android.features.roomdetails.impl.members.aRoomMember import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.designsystem.components.ProgressDialog import io.element.android.libraries.designsystem.components.async.AsyncActionView @@ -68,6 +67,7 @@ import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.toMatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.ui.components.MatrixUserRow import io.element.android.libraries.matrix.ui.components.SelectedUsersRowList @@ -83,12 +83,8 @@ fun ChangeRolesView( modifier: Modifier = Modifier, ) { val updatedOnBackPressed by rememberUpdatedState(newValue = onBackPressed) - BackHandler { - if (state.isSearchActive) { - state.eventSink(ChangeRolesEvent.ToggleSearchActive) - } else { - state.eventSink(ChangeRolesEvent.Exit) - } + BackHandler(enabled = !state.isSearchActive) { + state.eventSink(ChangeRolesEvent.Exit) } Box(modifier = modifier) { @@ -129,7 +125,9 @@ fun ChangeRolesView( ) { val lazyListState = rememberLazyListState() SearchBar( - modifier = Modifier.padding(bottom = 16.dp), + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 16.dp), placeHolderTitle = stringResource(CommonStrings.common_search_for_someone), query = state.query.orEmpty(), onQueryChange = { state.eventSink(ChangeRolesEvent.QueryChanged(it)) }, @@ -143,7 +141,7 @@ fun ChangeRolesView( searchResults = members, selectedUsers = state.selectedUsers, canRemoveMember = state.canChangeMemberRole, - onSelectionToggled = { state.eventSink(ChangeRolesEvent.UserSelectionToggled(it)) }, + onSelectionToggled = { state.eventSink(ChangeRolesEvent.UserSelectionToggled(it.toMatrixUser())) }, selectedUsersList = {}, ) } @@ -159,13 +157,13 @@ fun ChangeRolesView( searchResults = (state.searchResults as? SearchBarResultState.Results)?.results ?: persistentListOf(), selectedUsers = state.selectedUsers, canRemoveMember = state.canChangeMemberRole, - onSelectionToggled = { state.eventSink(ChangeRolesEvent.UserSelectionToggled(it)) }, + onSelectionToggled = { state.eventSink(ChangeRolesEvent.UserSelectionToggled(it.toMatrixUser())) }, selectedUsersList = { users -> SelectedUsersRowList( contentPadding = PaddingValues(start = 16.dp, end = 16.dp, bottom = 16.dp), selectedUsers = users, onUserRemoved = { - state.eventSink(ChangeRolesEvent.UserSelectionToggled(aRoomMember(it.userId))) + state.eventSink(ChangeRolesEvent.UserSelectionToggled(it)) }, canDeselect = { state.canChangeMemberRole(it.userId) }, ) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsView.kt index 1d57545a0b..c9e09c7c68 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsView.kt @@ -17,8 +17,9 @@ package io.element.android.features.roomdetails.impl.rolesandpermissions.permissions import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -80,29 +81,35 @@ fun ChangeRoomPermissionsView( ) } ) { padding -> - Column(modifier = Modifier.padding(padding)) { + LazyColumn( + modifier = Modifier + .padding(padding) + .fillMaxSize() + ) { for ((index, permissionItem) in state.items.withIndex()) { - ListSectionHeader(titleForSection(item = permissionItem), hasDivider = index > 0) - SelectRoleItem( - permissionsItem = permissionItem, - role = RoomMember.Role.ADMIN, - currentPermissions = state.currentPermissions - ) { item, role -> - state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(item, role)) - } - SelectRoleItem( - permissionsItem = permissionItem, - role = RoomMember.Role.MODERATOR, - currentPermissions = state.currentPermissions - ) { item, role -> - state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(item, role)) - } - SelectRoleItem( - permissionsItem = permissionItem, - role = RoomMember.Role.USER, - currentPermissions = state.currentPermissions - ) { item, role -> - state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(item, role)) + item { + ListSectionHeader(titleForSection(item = permissionItem), hasDivider = index > 0) + SelectRoleItem( + permissionsItem = permissionItem, + role = RoomMember.Role.ADMIN, + currentPermissions = state.currentPermissions + ) { item, role -> + state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(item, role)) + } + SelectRoleItem( + permissionsItem = permissionItem, + role = RoomMember.Role.MODERATOR, + currentPermissions = state.currentPermissions + ) { item, role -> + state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(item, role)) + } + SelectRoleItem( + permissionsItem = permissionItem, + role = RoomMember.Role.USER, + currentPermissions = state.currentPermissions + ) { item, role -> + state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(item, role)) + } } } } diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/rolesandpermissions/changeroles/ChangeRolesPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/rolesandpermissions/changeroles/ChangeRolesPresenterTests.kt index ff5e185bbd..1dbce1fc53 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/rolesandpermissions/changeroles/ChangeRolesPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/rolesandpermissions/changeroles/ChangeRolesPresenterTests.kt @@ -21,7 +21,6 @@ import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.RoomModeration -import io.element.android.features.roomdetails.impl.members.aRoomMember import io.element.android.features.roomdetails.impl.members.aRoomMemberList import io.element.android.features.roomdetails.impl.rolesandpermissions.changeroles.ChangeRolesEvent import io.element.android.features.roomdetails.impl.rolesandpermissions.changeroles.ChangeRolesPresenter @@ -30,6 +29,7 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.user.MatrixUser 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.room.FakeMatrixRoom @@ -154,10 +154,10 @@ class ChangeRolesPresenterTests { val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) - initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(aRoomMember(A_USER_ID_2))) + initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) assertThat(awaitItem().selectedUsers).hasSize(2) - initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(aRoomMember(A_USER_ID_2))) + initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) assertThat(awaitItem().selectedUsers).hasSize(1) } } @@ -177,13 +177,13 @@ class ChangeRolesPresenterTests { assertThat(initialState.hasPendingChanges).isFalse() assertThat(initialState.selectedUsers).hasSize(1) - initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(aRoomMember(A_USER_ID_2))) + initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) with(awaitItem()) { assertThat(selectedUsers).hasSize(2) assertThat(hasPendingChanges).isTrue() } - initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(aRoomMember(A_USER_ID_2))) + initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) with(awaitItem()) { assertThat(selectedUsers).hasSize(1) assertThat(hasPendingChanges).isFalse() @@ -226,7 +226,7 @@ class ChangeRolesPresenterTests { assertThat(initialState.hasPendingChanges).isFalse() assertThat(initialState.exitState).isEqualTo(AsyncAction.Uninitialized) - initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(aRoomMember(A_USER_ID_2))) + initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) awaitItem().eventSink(ChangeRolesEvent.Exit) val confirmingState = awaitItem() @@ -252,7 +252,7 @@ class ChangeRolesPresenterTests { assertThat(initialState.hasPendingChanges).isFalse() assertThat(initialState.exitState).isEqualTo(AsyncAction.Uninitialized) - initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(aRoomMember(A_USER_ID_2))) + initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) val updatedState = awaitItem() assertThat(updatedState.hasPendingChanges).isTrue() skipItems(1) @@ -279,8 +279,7 @@ class ChangeRolesPresenterTests { val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) - initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(aRoomMember(A_USER_ID_2))) - + initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) awaitItem().eventSink(ChangeRolesEvent.Save) val confirmingState = awaitItem() assertThat(confirmingState.savingState).isEqualTo(AsyncAction.Confirming) @@ -304,7 +303,7 @@ class ChangeRolesPresenterTests { val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) - initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(aRoomMember(A_USER_ID_2))) + initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) awaitItem().eventSink(ChangeRolesEvent.Save) val confirmingState = awaitItem() @@ -334,7 +333,7 @@ class ChangeRolesPresenterTests { val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) - initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(aRoomMember(A_USER_ID_2))) + initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) awaitItem().eventSink(ChangeRolesEvent.Save) assertThat(awaitItem().savingState).isEqualTo(AsyncAction.Success(Unit)) @@ -357,7 +356,7 @@ class ChangeRolesPresenterTests { val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) - initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(aRoomMember(A_USER_ID_2))) + initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) awaitItem().eventSink(ChangeRolesEvent.Save) val failedState = awaitItem() diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/rolesandpermissions/changeroles/ChangeRolesViewTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/rolesandpermissions/changeroles/ChangeRolesViewTest.kt new file mode 100644 index 0000000000..037223327e --- /dev/null +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/rolesandpermissions/changeroles/ChangeRolesViewTest.kt @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.roomdetails.rolesandpermissions.changeroles + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onAllNodesWithText +import androidx.compose.ui.test.onNodeWithContentDescription +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import io.element.android.features.roomdetails.impl.rolesandpermissions.changeroles.ChangeRolesEvent +import io.element.android.features.roomdetails.impl.rolesandpermissions.changeroles.ChangeRolesState +import io.element.android.features.roomdetails.impl.rolesandpermissions.changeroles.ChangeRolesView +import io.element.android.features.roomdetails.impl.rolesandpermissions.changeroles.aChangeRolesState +import io.element.android.features.roomdetails.impl.rolesandpermissions.changeroles.aChangeRolesStateWithSelectedUsers +import io.element.android.libraries.architecture.AsyncAction +import io.element.android.libraries.designsystem.theme.components.SearchBarResultState +import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.toMatrixUser +import io.element.android.libraries.matrix.ui.components.aMatrixUserList +import io.element.android.libraries.ui.strings.CommonStrings +import io.element.android.tests.testutils.EnsureNeverCalled +import io.element.android.tests.testutils.EventsRecorder +import io.element.android.tests.testutils.clickOn +import io.element.android.tests.testutils.pressBack +import kotlinx.collections.immutable.toImmutableList +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestRule +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ChangeRolesViewTest { + @get:Rule val rule = createAndroidComposeRule() + + @Test + fun `click on back icon search not active emits the expected event`() { + val eventsRecorder = EventsRecorder() + rule.setChangeRolesView( + state = aChangeRolesState( + eventSink = eventsRecorder, + ), + ) + rule.pressBack() + eventsRecorder.assertList( + listOf( + ChangeRolesEvent.QueryChanged(""), + ChangeRolesEvent.Exit, + ) + ) + } + + @Test + fun `click on back icon search active emits the expected event`() { + val eventsRecorder = EventsRecorder() + rule.setChangeRolesView( + state = aChangeRolesState( + isSearchActive = true, + eventSink = eventsRecorder, + ), + ) + rule.pressBack() + // This event should be there, maybe a problem with the SearchBar + // It's working fine in the app, so let's ignore it for now + // eventsRecorder.assertSingle(ChangeRolesEvent.ToggleSearchActive) + } + + @Test + fun `click on search bar emits the expected event`() { + val eventsRecorder = EventsRecorder() + rule.setChangeRolesView( + state = aChangeRolesState( + eventSink = eventsRecorder, + ), + ) + rule.clickOn(CommonStrings.common_search_for_someone) + eventsRecorder.assertList( + listOf( + ChangeRolesEvent.QueryChanged(""), + // This event should be there, maybe a problem with the SearchBar + // It's working fine in the app, so let's ignore it for now + // ChangeRolesEvent.ToggleSearchActive, + ) + ) + } + + @Test + fun `click on save button emits the expected event`() { + val eventsRecorder = EventsRecorder() + rule.setChangeRolesView( + state = aChangeRolesState( + hasPendingChanges = true, + eventSink = eventsRecorder, + ), + ) + rule.clickOn(CommonStrings.action_save) + eventsRecorder.assertList( + listOf( + ChangeRolesEvent.QueryChanged(""), + ChangeRolesEvent.Save, + ) + ) + } + + @Test + fun `testing exit confirmation dialog ok emits the expected event`() { + val eventsRecorder = EventsRecorder() + rule.setChangeRolesView( + state = aChangeRolesState( + exitState = AsyncAction.Confirming, + eventSink = eventsRecorder, + ), + ) + rule.clickOn(CommonStrings.action_ok) + eventsRecorder.assertList( + listOf( + ChangeRolesEvent.QueryChanged(""), + ChangeRolesEvent.Exit, + ) + ) + } + + @Test + fun `testing exit confirmation dialog cancel emits the expected event`() { + val eventsRecorder = EventsRecorder() + rule.setChangeRolesView( + state = aChangeRolesState( + exitState = AsyncAction.Confirming, + eventSink = eventsRecorder, + ), + ) + rule.clickOn(CommonStrings.action_cancel) + eventsRecorder.assertList( + listOf( + ChangeRolesEvent.QueryChanged(""), + ChangeRolesEvent.CancelExit + ) + ) + } + + @Test + fun `testing saving dialog failure OK emits the expected event`() { + val eventsRecorder = EventsRecorder() + rule.setChangeRolesView( + state = aChangeRolesState( + savingState = AsyncAction.Failure(Exception("boom")), + eventSink = eventsRecorder, + ), + ) + rule.clickOn(CommonStrings.action_ok) + eventsRecorder.assertList( + listOf( + ChangeRolesEvent.QueryChanged(""), + ChangeRolesEvent.ClearError, + ) + ) + } + + @Test + fun `testing saving confirmation dialog for admin OK emits the expected event`() { + val eventsRecorder = EventsRecorder() + rule.setChangeRolesView( + state = aChangeRolesState( + role = RoomMember.Role.ADMIN, + savingState = AsyncAction.Confirming, + eventSink = eventsRecorder, + ), + ) + rule.clickOn(CommonStrings.action_ok) + eventsRecorder.assertList( + listOf( + ChangeRolesEvent.QueryChanged(""), + ChangeRolesEvent.Save, + ) + ) + } + + @Test + fun `testing saving confirmation dialog for admin cancel emits the expected event`() { + val eventsRecorder = EventsRecorder() + rule.setChangeRolesView( + state = aChangeRolesState( + role = RoomMember.Role.ADMIN, + savingState = AsyncAction.Confirming, + eventSink = eventsRecorder, + ), + ) + rule.clickOn(CommonStrings.action_cancel) + eventsRecorder.assertList( + listOf( + ChangeRolesEvent.QueryChanged(""), + ChangeRolesEvent.ClearError, + ) + ) + } + + @Test + fun `testing removing user from selected list emits the expected event`() { + val eventsRecorder = EventsRecorder() + val selectedUsers = aMatrixUserList().take(2) + val userToDeselect = selectedUsers[1] + assertThat(userToDeselect.displayName).isEqualTo("Bob") + rule.setChangeRolesView( + state = aChangeRolesStateWithSelectedUsers().copy( + selectedUsers = selectedUsers.toImmutableList(), + eventSink = eventsRecorder, + ), + ) + // Unselect the user from the row list + val contentDescription = rule.activity.getString(CommonStrings.action_remove) + rule.onNodeWithContentDescription(contentDescription).performClick() + eventsRecorder.assertList( + listOf( + ChangeRolesEvent.QueryChanged(""), + ChangeRolesEvent.UserSelectionToggled(userToDeselect), + ) + ) + } + + @Test + fun `testing adding user to the selected list emits the expected event`() { + val eventsRecorder = EventsRecorder() + val selectedUsers = aMatrixUserList().take(2) + val state = aChangeRolesStateWithSelectedUsers().copy( + selectedUsers = selectedUsers.toImmutableList(), + eventSink = eventsRecorder, + ) + val userToSelect = (state.searchResults as SearchBarResultState.Results).results[2].toMatrixUser() + assertThat(userToSelect.displayName).isEqualTo("Carol") + rule.setChangeRolesView( + state = state, + ) + // Select the user from the rom list + rule.onNodeWithText("Carol").performClick() + eventsRecorder.assertList( + listOf( + ChangeRolesEvent.QueryChanged(""), + ChangeRolesEvent.UserSelectionToggled(userToSelect), + ) + ) + } + + @Test + fun `testing removing user to the selected list emits the expected event`() { + val eventsRecorder = EventsRecorder() + val selectedUsers = aMatrixUserList().take(2) + val state = aChangeRolesStateWithSelectedUsers().copy( + selectedUsers = selectedUsers.toImmutableList(), + eventSink = eventsRecorder, + ) + val userToSelect = (state.searchResults as SearchBarResultState.Results).results[1].toMatrixUser() + assertThat(userToSelect.displayName).isEqualTo("Bob") + rule.setChangeRolesView( + state = state, + ) + // Select the user from the rom list + rule.onAllNodesWithText("Bob")[1].performClick() + eventsRecorder.assertList( + listOf( + ChangeRolesEvent.QueryChanged(""), + ChangeRolesEvent.UserSelectionToggled(userToSelect), + ) + ) + } +} + +private fun AndroidComposeTestRule.setChangeRolesView( + state: ChangeRolesState, + onBackPressed: () -> Unit = EnsureNeverCalled(), +) { + setContent { + ChangeRolesView( + state = state, + onBackPressed = onBackPressed, + ) + } +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt index aa1f3fa025..fef657571c 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt @@ -35,13 +35,8 @@ import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.api.timeline.ReceiptType import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.map import java.io.Closeable import java.io.File @@ -183,18 +178,6 @@ interface MatrixRoom : Closeable { suspend fun canUserJoinCall(userId: UserId): Result = canUserSendState(userId, StateEventType.CALL_MEMBER) - fun usersWithRole(role: RoomMember.Role): Flow> { - return roomInfoFlow - .map { it.userPowerLevels.filter { (_, powerLevel) -> RoomMember.Role.forPowerLevel(powerLevel) == role } } - .distinctUntilChanged() - .combine(membersStateFlow) { powerLevels, membersState -> - membersState.roomMembers() - .orEmpty() - .filter { powerLevels.containsKey(it.userId) } - .toPersistentList() - } - } - suspend fun updateAvatar(mimeType: String, data: ByteArray): Result suspend fun removeAvatar(): Result diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomMembersState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomMembersState.kt index 759b0f46cb..13f19fe0e0 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomMembersState.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomMembersState.kt @@ -35,3 +35,7 @@ fun MatrixRoomMembersState.roomMembers(): List? { else -> null } } + +fun MatrixRoomMembersState.joinedRoomMembers(): List { + return roomMembers().orEmpty().filter { it.membership == RoomMembershipState.JOIN } +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt index f6609a2bce..4415e51327 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt @@ -17,6 +17,7 @@ package io.element.android.libraries.matrix.api.room import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.user.MatrixUser data class RoomMember( val userId: UserId, @@ -78,3 +79,9 @@ enum class RoomMembershipState { fun RoomMember.getBestName(): String { return displayName?.takeIf { it.isNotEmpty() } ?: userId.value } + +fun RoomMember.toMatrixUser() = MatrixUser( + userId = userId, + displayName = displayName, + avatarUrl = avatarUrl, +) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomMembersWithRole.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomMembersWithRole.kt new file mode 100644 index 0000000000..2c17718ccf --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomMembersWithRole.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.api.room.powerlevels + +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.joinedRoomMembers +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toPersistentList +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map + +/** + * Return a flow of the list of room members who are still in the room (with membership == RoomMembershipState.JOIN) + * and who have the given role. + */ +fun MatrixRoom.usersWithRole(role: RoomMember.Role): Flow> { + return roomInfoFlow + .map { it.userPowerLevels.filter { (_, powerLevel) -> RoomMember.Role.forPowerLevel(powerLevel) == role } } + .combine(membersStateFlow) { powerLevels, membersState -> + membersState.joinedRoomMembers() + .filter { powerLevels.containsKey(it.userId) } + .toPersistentList() + } + .distinctUntilChanged() +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt index f2577fcb6b..ef4e6f747e 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt @@ -42,7 +42,7 @@ suspend fun MatrixRoom.canInvite(): Result = canUserInvite(sessionId) suspend fun MatrixRoom.canKick(): Result = canUserKick(sessionId) /** - * Shortcut for calling [MatrixRoom.canBanUser] with our own user. + * Shortcut for calling [MatrixRoom.canUserBan] with our own user. */ suspend fun MatrixRoom.canBan(): Result = canUserBan(sessionId) diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt index 9851a8c7c2..b2c703fdb1 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt @@ -127,6 +127,7 @@ fun RoomSelectView( .consumeWindowInsets(paddingValues) ) { SearchBar( + modifier = Modifier.fillMaxWidth(), placeHolderTitle = stringResource(CommonStrings.action_search), query = state.query, onQueryChange = { state.eventSink(RoomSelectEvents.UpdateQuery(it)) }, diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_0,NEXUS_5,1.0,en].png index c1fa064495..25e2ed257b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cce394023e7c5bac40bcf234f9073196b1eb424893760f29d609eb329f62817f -size 42587 +oid sha256:491c4c2465dd79a98e0062a7dbae9dffb1dca66ac991cacae44bc31fbd415b1d +size 42557 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_2,NEXUS_5,1.0,en].png index 8428ee7714..0d7ebc9df2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d6818023d37493825ba7b929470152847c397b5f19a5bd8ee862fc900dee690 -size 40755 +oid sha256:373b21c8f450fcdde73431e55fad3b8f7f255ca3f5d954e9555b65ca9d891e4a +size 40720 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_3,NEXUS_5,1.0,en].png index 52135a6c75..ee3dc1981a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:86aa47d55841e5041bf56534852dd716b4546cc3657a30133b88c0c87998f16c -size 42464 +oid sha256:8b9b89615f55b7f33c4d16c2affaf0ad768c2dc940dc512c22a3376c7a70266c +size 42434 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_4,NEXUS_5,1.0,en].png index d7bdf55419..3c662c7fd9 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:237125629b6449d6898391235b625248b71629b4d96415b80fb7ef5e773e86b2 -size 40484 +oid sha256:a54f44acb3270d7822cbd3e1a4ff92dbc15e3efb01d84b4b86157820e68b8304 +size 40492 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_5,NEXUS_5,1.0,en].png index 6c7a7c2b33..bcbd74311f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:753eecb930bf0659671f2f1ecb2a64ae226aac96c5365ed549c635fd90c8c729 -size 40951 +oid sha256:592b7775769f8a51bd3a2a3a4d81fe5e2cc95de9d781b446a74cfb39bd53aa0b +size 40954 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_6,NEXUS_5,1.0,en].png index bca446759d..1e8a0d2813 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Day-10_11_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d0b37566f62e30fcb4f16364a9ac2c008a98a5429c3fa5724d7ef6455e79cf34 -size 47995 +oid sha256:eee33a3534c66fb6a6ecebfdfe3518a7446880905da5bb0aae11ff260f7470eb +size 47999 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_0,NEXUS_5,1.0,en].png index 35d6c4ad87..101d42b4bc 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dff4c4a80156b2977da007d6258d1cd6cefc93bc709ec33bff0e1b484604cf0a -size 38506 +oid sha256:be6fc53e78d78c117a1e166fdd3e618eb3e2a44ef3effb74f9aa0a2116a0fec3 +size 38484 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_2,NEXUS_5,1.0,en].png index 97de47b574..d8a11cb617 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af5a843cc9cd5a51d986ba7dae7d2c6a088f862f46bac961667a1fb1d62b8a20 -size 36966 +oid sha256:56c2f01102a7e2902981a4a71efaf838ffe0fd1efd0c4a1f42afbdac013c6f3c +size 36940 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_3,NEXUS_5,1.0,en].png index e7363aa84b..a031323cc9 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:059e598dc973e8c01dba4ef49accf47ea2bd74377dfbfb441c3c213fc77a1cee -size 38158 +oid sha256:540804fa0abf2754e55616fefc03991d692a464bb4679b110a0a7bfc99754338 +size 38135 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_4,NEXUS_5,1.0,en].png index 7f5fe9dbc4..d5c54c295e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c34415877b279b2018d02667cc98b4857f4ae5bfa68d169f3226a0c99ed4620b -size 36699 +oid sha256:9759cca46c3158225f780439f7da527b5a76c75a201b10f6ba50ccc2022a9f1b +size 36664 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_5,NEXUS_5,1.0,en].png index 17ca2569d6..e4539c272a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc02c16667b78ca5a9985da6816f17bbd0f7bb2307569aacaf3391ccd8431bd5 -size 36567 +oid sha256:2f4eb202f7cffe9eb5dd51ee32abccc5e97877c6d35df82b6d8632fea611370f +size 36530 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_6,NEXUS_5,1.0,en].png index 9d7aa5c1be..41b61c015c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_null_ChangeRoomPermissionsView-Night-10_12_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4faece23a4780f5465abe42587f56933ecded55bf3ae966a9e6b634e7df1e049 -size 42845 +oid sha256:2d332b41b0a566848e81376e335706e822a25cbd3c40233cedef3f21eba7dbf0 +size 42811