do not reverse selected user list ordering & add autoscroll when selecting user
This commit is contained in:
parent
a7d273432d
commit
f3b64e0ca5
7 changed files with 24 additions and 35 deletions
|
|
@ -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)) },
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 = {}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue