diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleStateProvider.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleStateProvider.kt index a1c0e6bdf2..6f1679e252 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleStateProvider.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleStateProvider.kt @@ -18,8 +18,8 @@ package io.element.android.features.createroom.impl.addpeople import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.selectusers.api.SelectionMode +import io.element.android.features.selectusers.api.aListOfSelectedUsers import io.element.android.features.selectusers.api.aSelectUsersState -import io.element.android.features.selectusers.api.aSetOfSelectedUsers open class AddPeopleStateProvider : PreviewParameterProvider { override val values: Sequence @@ -27,13 +27,13 @@ open class AddPeopleStateProvider : PreviewParameterProvider { aAddPeopleState(), aAddPeopleState().copy( selectUsersState = aSelectUsersState().copy( - selectedUsers = aSetOfSelectedUsers(), + selectedUsers = aListOfSelectedUsers(), selectionMode = SelectionMode.Multiple, ) ), aAddPeopleState().copy( selectUsersState = aSelectUsersState().copy( - selectedUsers = aSetOfSelectedUsers(), + selectedUsers = aListOfSelectedUsers(), isSearchActive = true, selectionMode = SelectionMode.Multiple, ) diff --git a/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersState.kt b/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersState.kt index a858703350..2a1a2c48e3 100644 --- a/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersState.kt +++ b/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersState.kt @@ -19,12 +19,11 @@ package io.element.android.features.selectusers.api import androidx.compose.foundation.lazy.LazyListState import io.element.android.libraries.matrix.ui.model.MatrixUser import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.ImmutableSet data class SelectUsersState( val searchQuery: String, val searchResults: ImmutableList, - val selectedUsers: ImmutableSet, + val selectedUsers: ImmutableList, val selectedUsersListState: LazyListState, val isSearchActive: Boolean, val selectionMode: SelectionMode, diff --git a/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersStateProvider.kt b/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersStateProvider.kt index 790bd010c0..93209a632c 100644 --- a/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersStateProvider.kt +++ b/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersStateProvider.kt @@ -21,7 +21,6 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.ui.model.MatrixUser import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.persistentSetOf open class SelectUsersStateProvider : PreviewParameterProvider { override val values: Sequence @@ -29,7 +28,7 @@ open class SelectUsersStateProvider : PreviewParameterProvider aSelectUsersState(), aSelectUsersState().copy( isSearchActive = false, - selectedUsers = aSetOfSelectedUsers(), + selectedUsers = aListOfSelectedUsers(), selectionMode = SelectionMode.Multiple, ), aSelectUsersState().copy(isSearchActive = true), @@ -38,14 +37,14 @@ open class SelectUsersStateProvider : PreviewParameterProvider aSelectUsersState().copy( isSearchActive = true, searchQuery = "@someone:matrix.org", - selectedUsers = aSetOfSelectedUsers(), + selectedUsers = aListOfSelectedUsers(), searchResults = aListOfResults(), ), aSelectUsersState().copy( isSearchActive = true, searchQuery = "@someone:matrix.org", selectionMode = SelectionMode.Multiple, - selectedUsers = aSetOfSelectedUsers(), + selectedUsers = aListOfSelectedUsers(), searchResults = aListOfResults(), ) ) @@ -55,7 +54,7 @@ fun aSelectUsersState() = SelectUsersState( isSearchActive = false, searchQuery = "", searchResults = persistentListOf(), - selectedUsers = persistentSetOf(), + selectedUsers = persistentListOf(), selectedUsersListState = LazyListState( firstVisibleItemIndex = 0, firstVisibleItemScrollOffset = 0, @@ -64,7 +63,7 @@ fun aSelectUsersState() = SelectUsersState( eventSink = {} ) -fun aSetOfSelectedUsers() = persistentSetOf( +fun aListOfSelectedUsers() = persistentListOf( MatrixUser(id = UserId("@someone:matrix.org")), MatrixUser(id = UserId("@other:matrix.org"), username = "other"), ) diff --git a/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersView.kt b/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersView.kt index b4e97b5bd1..6703aacac6 100644 --- a/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersView.kt +++ b/features/selectusers/api/src/main/kotlin/io/element/android/features/selectusers/api/SelectUsersView.kt @@ -61,7 +61,6 @@ import io.element.android.libraries.matrix.ui.components.MatrixUserRow import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.ui.model.getBestName import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.ImmutableSet import io.element.android.libraries.ui.strings.R as StringR @Composable @@ -113,7 +112,7 @@ fun SelectUsersView( fun SearchUserBar( query: String, results: ImmutableList, - selectedUsers: ImmutableSet, + selectedUsers: ImmutableList, selectedUsersListState: LazyListState, active: Boolean, isMultiSelectionEnabled: Boolean, @@ -243,7 +242,7 @@ fun SearchSingleUserResultItem( @Composable fun SelectedUsersList( listState: LazyListState, - selectedUsers: ImmutableSet, + selectedUsers: ImmutableList, modifier: Modifier = Modifier, onUserRemoved: (MatrixUser) -> Unit = {}, ) { diff --git a/features/selectusers/impl/src/main/kotlin/io/element/android/features/selectusers/impl/DefaultSelectUsersPresenter.kt b/features/selectusers/impl/src/main/kotlin/io/element/android/features/selectusers/impl/DefaultSelectUsersPresenter.kt index 2176317aba..e1135cd1a2 100644 --- a/features/selectusers/impl/src/main/kotlin/io/element/android/features/selectusers/impl/DefaultSelectUsersPresenter.kt +++ b/features/selectusers/impl/src/main/kotlin/io/element/android/features/selectusers/impl/DefaultSelectUsersPresenter.kt @@ -40,11 +40,8 @@ import io.element.android.libraries.matrix.api.core.MatrixPatterns import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.ui.model.MatrixUser import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toImmutableList -import kotlinx.collections.immutable.toImmutableSet import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -62,8 +59,8 @@ class DefaultSelectUsersPresenter @AssistedInject constructor( override fun present(): SelectUsersState { val localCoroutineScope = rememberCoroutineScope() var isSearchActive by rememberSaveable { mutableStateOf(false) } - val selectedUsers: MutableState> = remember { - mutableStateOf(persistentSetOf()) + val selectedUsers: MutableState> = remember { + mutableStateOf(persistentListOf()) } val selectedUsersListState = rememberLazyListState() var searchQuery by rememberSaveable { mutableStateOf("") } @@ -76,10 +73,12 @@ class DefaultSelectUsersPresenter @AssistedInject constructor( is SelectUsersEvents.OnSearchActiveChanged -> isSearchActive = event.active is SelectUsersEvents.UpdateSearchQuery -> searchQuery = event.query is SelectUsersEvents.AddToSelection -> { - selectedUsers.value = selectedUsers.value.plus(event.matrixUser).toImmutableSet() + if (event.matrixUser !in selectedUsers.value) { + selectedUsers.value = selectedUsers.value.plus(event.matrixUser).toImmutableList() + } localCoroutineScope.scrollToFirstSelectedUser(selectedUsersListState) } - is SelectUsersEvents.RemoveFromSelection -> selectedUsers.value = selectedUsers.value.minus(event.matrixUser).toImmutableSet() + is SelectUsersEvents.RemoveFromSelection -> selectedUsers.value = selectedUsers.value.minus(event.matrixUser).toImmutableList() } } @@ -99,7 +98,7 @@ class DefaultSelectUsersPresenter @AssistedInject constructor( return SelectUsersState( searchQuery = searchQuery, searchResults = searchResults.value, - selectedUsers = selectedUsers.value.reversed().toImmutableSet(), + selectedUsers = selectedUsers.value.reversed().toImmutableList(), selectedUsersListState = selectedUsersListState, isSearchActive = isSearchActive, selectionMode = args.selectionMode, diff --git a/features/selectusers/impl/src/test/kotlin/io/element/android/features/selectusers/impl/DefaultSelectUsersPresenterTests.kt b/features/selectusers/impl/src/test/kotlin/io/element/android/features/selectusers/impl/DefaultSelectUsersPresenterTests.kt index 0df0ec88ec..f5b0b43d0e 100644 --- a/features/selectusers/impl/src/test/kotlin/io/element/android/features/selectusers/impl/DefaultSelectUsersPresenterTests.kt +++ b/features/selectusers/impl/src/test/kotlin/io/element/android/features/selectusers/impl/DefaultSelectUsersPresenterTests.kt @@ -105,27 +105,27 @@ class DefaultSelectUsersPresenterTests { val userA = aMatrixUser("userA", "A") val userB = aMatrixUser("userB", "B") + val userABis = aMatrixUser("userA", "A") + val userC = aMatrixUser("userC", "C") + initialState.eventSink(SelectUsersEvents.AddToSelection(userA)) - val selectionAfterAddingA = awaitItem().selectedUsers - assertThat(selectionAfterAddingA).hasSize(1) - assertThat(selectionAfterAddingA).contains(userA) + assertThat(awaitItem().selectedUsers).containsExactly(userA) initialState.eventSink(SelectUsersEvents.AddToSelection(userB)) - val selectionAfterAddingB = awaitItem().selectedUsers - assertThat(selectionAfterAddingB).hasSize(2) - assertThat(selectionAfterAddingB).contains(userA) - assertThat(selectionAfterAddingB).contains(userB) // the last added user should be presented first - assertThat(selectionAfterAddingB.first()).isEqualTo(userB) + assertThat(awaitItem().selectedUsers).containsExactly(userB, userA) + + initialState.eventSink(SelectUsersEvents.AddToSelection(userABis)) + initialState.eventSink(SelectUsersEvents.AddToSelection(userC)) + // duplicated users should be ignored + assertThat(awaitItem().selectedUsers).containsExactly(userC, userB, userA) initialState.eventSink(SelectUsersEvents.RemoveFromSelection(userB)) - val selectionAfterRemovingB = awaitItem().selectedUsers - assertThat(selectionAfterRemovingB).hasSize(1) - assertThat(selectionAfterRemovingB).contains(userA) - + assertThat(awaitItem().selectedUsers).containsExactly(userC, userA) initialState.eventSink(SelectUsersEvents.RemoveFromSelection(userA)) - val selectionAfterRemovingA = awaitItem().selectedUsers - assertThat(selectionAfterRemovingA).isEmpty() + assertThat(awaitItem().selectedUsers).containsExactly(userC) + initialState.eventSink(SelectUsersEvents.RemoveFromSelection(userC)) + assertThat(awaitItem().selectedUsers).isEmpty() } } }