do not reverse selected user list ordering & add autoscroll when selecting user

This commit is contained in:
Florian Renaud 2023-04-13 15:44:00 +02:00
parent a7d273432d
commit f3b64e0ca5
7 changed files with 24 additions and 35 deletions

View file

@ -29,7 +29,6 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.selection.selectableGroup import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
@ -77,7 +76,6 @@ fun ConfigureRoomView(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onBackPressed: () -> Unit = {}, onBackPressed: () -> Unit = {},
) { ) {
val selectedUsersListState = rememberLazyListState()
val context = LocalContext.current val context = LocalContext.current
Scaffold( Scaffold(
modifier = modifier, modifier = modifier,
@ -106,7 +104,6 @@ fun ConfigureRoomView(
onTopicChanged = { state.eventSink(ConfigureRoomEvents.TopicChanged(it)) }, onTopicChanged = { state.eventSink(ConfigureRoomEvents.TopicChanged(it)) },
) )
SelectedUsersList( SelectedUsersList(
listState = selectedUsersListState,
contentPadding = PaddingValues(horizontal = 24.dp), contentPadding = PaddingValues(horizontal = 24.dp),
selectedUsers = state.config.invites, selectedUsers = state.config.invites,
onUserRemoved = { state.eventSink(ConfigureRoomEvents.RemoveFromSelection(it)) }, onUserRemoved = { state.eventSink(ConfigureRoomEvents.RemoveFromSelection(it)) },

View file

@ -16,7 +16,6 @@
package io.element.android.features.userlist.api package io.element.android.features.userlist.api
import androidx.compose.foundation.lazy.LazyListState
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
@ -24,7 +23,6 @@ data class UserListState(
val searchQuery: String, val searchQuery: String,
val searchResults: ImmutableList<MatrixUser>, val searchResults: ImmutableList<MatrixUser>,
val selectedUsers: ImmutableList<MatrixUser>, val selectedUsers: ImmutableList<MatrixUser>,
val selectedUsersListState: LazyListState,
val isSearchActive: Boolean, val isSearchActive: Boolean,
val selectionMode: SelectionMode, val selectionMode: SelectionMode,
val eventSink: (UserListEvents) -> Unit, val eventSink: (UserListEvents) -> Unit,

View file

@ -16,7 +16,6 @@
package io.element.android.features.userlist.api package io.element.android.features.userlist.api
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.matrix.ui.components.aMatrixUserList import io.element.android.libraries.matrix.ui.components.aMatrixUserList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@ -55,10 +54,6 @@ fun aUserListState() = UserListState(
searchQuery = "", searchQuery = "",
searchResults = persistentListOf(), searchResults = persistentListOf(),
selectedUsers = persistentListOf(), selectedUsers = persistentListOf(),
selectedUsersListState = LazyListState(
firstVisibleItemIndex = 0,
firstVisibleItemScrollOffset = 0,
),
selectionMode = SelectionMode.Single, selectionMode = SelectionMode.Single,
eventSink = {} eventSink = {}
) )

View file

@ -20,7 +20,6 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Close
@ -49,7 +48,6 @@ fun SearchUserBar(
query: String, query: String,
results: ImmutableList<MatrixUser>, results: ImmutableList<MatrixUser>,
selectedUsers: ImmutableList<MatrixUser>, selectedUsers: ImmutableList<MatrixUser>,
selectedUsersListState: LazyListState,
active: Boolean, active: Boolean,
isMultiSelectionEnabled: Boolean, isMultiSelectionEnabled: Boolean,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -108,9 +106,9 @@ fun SearchUserBar(
content = { content = {
if (isMultiSelectionEnabled && active && selectedUsers.isNotEmpty()) { if (isMultiSelectionEnabled && active && selectedUsers.isNotEmpty()) {
SelectedUsersList( SelectedUsersList(
listState = selectedUsersListState,
contentPadding = PaddingValues(16.dp), contentPadding = PaddingValues(16.dp),
selectedUsers = selectedUsers, selectedUsers = selectedUsers,
autoScroll = true,
onUserRemoved = onUserDeselected, onUserRemoved = onUserDeselected,
) )
} }

View file

@ -18,10 +18,15 @@ package io.element.android.features.userlist.api.components
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -29,18 +34,29 @@ import io.element.android.features.userlist.api.aListOfSelectedUsers
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.collections.immutable.ImmutableList
@Composable @Composable
fun SelectedUsersList( fun SelectedUsersList(
listState: LazyListState, selectedUsers: List<MatrixUser>,
selectedUsers: ImmutableList<MatrixUser>,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
autoScroll: Boolean = false,
contentPadding: PaddingValues = PaddingValues(0.dp), contentPadding: PaddingValues = PaddingValues(0.dp),
onUserRemoved: (MatrixUser) -> Unit = {}, onUserRemoved: (MatrixUser) -> Unit = {},
) { ) {
val lazyListState = rememberLazyListState()
if (autoScroll) {
var currentSize by rememberSaveable { mutableStateOf(selectedUsers.size) }
LaunchedEffect(selectedUsers.size) {
val isItemAdded = selectedUsers.size > currentSize
if (isItemAdded) {
lazyListState.animateScrollToItem(selectedUsers.lastIndex)
}
currentSize = selectedUsers.size
}
}
LazyRow( LazyRow(
state = listState, state = lazyListState,
modifier = modifier, modifier = modifier,
contentPadding = contentPadding, contentPadding = contentPadding,
horizontalArrangement = Arrangement.spacedBy(24.dp), horizontalArrangement = Arrangement.spacedBy(24.dp),
@ -65,7 +81,6 @@ internal fun SelectedUsersListDarkPreview() = ElementPreviewDark { ContentToPrev
@Composable @Composable
private fun ContentToPreview() { private fun ContentToPreview() {
SelectedUsersList( SelectedUsersList(
listState = LazyListState(),
selectedUsers = aListOfSelectedUsers(), selectedUsers = aListOfSelectedUsers(),
) )
} }

View file

@ -46,7 +46,6 @@ fun UserListView(
query = state.searchQuery, query = state.searchQuery,
results = state.searchResults, results = state.searchResults,
selectedUsers = state.selectedUsers, selectedUsers = state.selectedUsers,
selectedUsersListState = state.selectedUsersListState,
active = state.isSearchActive, active = state.isSearchActive,
isMultiSelectionEnabled = state.isMultiSelectionEnabled, isMultiSelectionEnabled = state.isMultiSelectionEnabled,
onActiveChanged = { state.eventSink(UserListEvents.OnSearchActiveChanged(it)) }, onActiveChanged = { state.eventSink(UserListEvents.OnSearchActiveChanged(it)) },
@ -63,9 +62,9 @@ fun UserListView(
if (state.isMultiSelectionEnabled && !state.isSearchActive && state.selectedUsers.isNotEmpty()) { if (state.isMultiSelectionEnabled && !state.isSearchActive && state.selectedUsers.isNotEmpty()) {
SelectedUsersList( SelectedUsersList(
listState = state.selectedUsersListState,
contentPadding = PaddingValues(16.dp), contentPadding = PaddingValues(16.dp),
selectedUsers = state.selectedUsers, selectedUsers = state.selectedUsers,
autoScroll = true,
onUserRemoved = { onUserRemoved = {
state.eventSink(UserListEvents.RemoveFromSelection(it)) state.eventSink(UserListEvents.RemoveFromSelection(it))
onUserDeselected(it) onUserDeselected(it)

View file

@ -16,8 +16,6 @@
package io.element.android.features.userlist.impl package io.element.android.features.userlist.impl
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable 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
@ -25,7 +23,6 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import com.squareup.anvil.annotations.ContributesBinding import com.squareup.anvil.annotations.ContributesBinding
@ -45,8 +42,6 @@ import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
class DefaultUserListPresenter @AssistedInject constructor( class DefaultUserListPresenter @AssistedInject constructor(
@Assisted val args: UserListPresenterArgs, @Assisted val args: UserListPresenterArgs,
@ -66,10 +61,8 @@ class DefaultUserListPresenter @AssistedInject constructor(
@Composable @Composable
override fun present(): UserListState { override fun present(): UserListState {
val localCoroutineScope = rememberCoroutineScope()
var isSearchActive by rememberSaveable { mutableStateOf(false) } var isSearchActive by rememberSaveable { mutableStateOf(false) }
val selectedUsers = userListDataStore.selectedUsers().collectAsState(emptyList()) val selectedUsers = userListDataStore.selectedUsers().collectAsState(emptyList())
val selectedUsersListState = rememberLazyListState()
var searchQuery by rememberSaveable { mutableStateOf("") } var searchQuery by rememberSaveable { mutableStateOf("") }
val searchResults: MutableState<ImmutableList<MatrixUser>> = remember { val searchResults: MutableState<ImmutableList<MatrixUser>> = remember {
mutableStateOf(persistentListOf()) mutableStateOf(persistentListOf())
@ -83,7 +76,6 @@ class DefaultUserListPresenter @AssistedInject constructor(
if (event.matrixUser !in selectedUsers.value) { if (event.matrixUser !in selectedUsers.value) {
userListDataStore.selectUser(event.matrixUser) userListDataStore.selectUser(event.matrixUser)
} }
localCoroutineScope.scrollToFirstSelectedUser(selectedUsersListState)
} }
is UserListEvents.RemoveFromSelection -> userListDataStore.removeUserFromSelection(event.matrixUser) is UserListEvents.RemoveFromSelection -> userListDataStore.removeUserFromSelection(event.matrixUser)
} }
@ -105,8 +97,7 @@ class DefaultUserListPresenter @AssistedInject constructor(
return UserListState( return UserListState(
searchQuery = searchQuery, searchQuery = searchQuery,
searchResults = searchResults.value, searchResults = searchResults.value,
selectedUsers = selectedUsers.value.reversed().toImmutableList(), selectedUsers = selectedUsers.value.toImmutableList(),
selectedUsersListState = selectedUsersListState,
isSearchActive = isSearchActive, isSearchActive = isSearchActive,
selectionMode = args.selectionMode, selectionMode = args.selectionMode,
eventSink = ::handleEvents, eventSink = ::handleEvents,
@ -123,8 +114,4 @@ class DefaultUserListPresenter @AssistedInject constructor(
} }
return results.toImmutableList() return results.toImmutableList()
} }
private fun CoroutineScope.scrollToFirstSelectedUser(listState: LazyListState) = launch {
listState.scrollToItem(index = 0)
}
} }