Selected users: if scrollable, make last one peek
If there are enough selected users that they can't all be displayed, add extra padding in between the users to ensure that the last visible one is half visible to provide some scroll affordance.
This commit is contained in:
parent
37d1a3b394
commit
a5849ca0bc
1 changed files with 79 additions and 10 deletions
|
|
@ -16,18 +16,26 @@
|
|||
|
||||
package io.element.android.libraries.matrix.ui.components
|
||||
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
|
|
@ -35,6 +43,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
|||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlin.math.floor
|
||||
|
||||
@Composable
|
||||
fun SelectedUsersList(
|
||||
|
|
@ -56,16 +65,60 @@ fun SelectedUsersList(
|
|||
}
|
||||
}
|
||||
|
||||
val rowWidth by remember {
|
||||
derivedStateOf {
|
||||
lazyListState.layoutInfo.viewportSize.width - lazyListState.layoutInfo.beforeContentPadding
|
||||
}
|
||||
}
|
||||
|
||||
LazyRow(
|
||||
state = lazyListState,
|
||||
modifier = modifier,
|
||||
modifier = modifier
|
||||
.fillMaxWidth(),
|
||||
contentPadding = contentPadding,
|
||||
horizontalArrangement = Arrangement.spacedBy(24.dp),
|
||||
) {
|
||||
items(selectedUsers.toList()) { matrixUser ->
|
||||
SelectedUser(
|
||||
matrixUser = matrixUser,
|
||||
onUserRemoved = onUserRemoved,
|
||||
itemsIndexed(selectedUsers.toList()) { index, matrixUser ->
|
||||
Layout(
|
||||
content = {
|
||||
SelectedUser(
|
||||
matrixUser = matrixUser,
|
||||
onUserRemoved = onUserRemoved,
|
||||
)
|
||||
},
|
||||
measurePolicy = { measurables, constraints ->
|
||||
// Measures out extra space between each user to ensure that the last visible user is exactly half visible, giving an affordance that
|
||||
// the user can scroll to see more.
|
||||
|
||||
val placeable = measurables.first().measure(constraints)
|
||||
val isLastItem = index == selectedUsers.lastIndex
|
||||
val width = if (isLastItem) {
|
||||
// Don't add any padding on the final item
|
||||
placeable.width
|
||||
} else {
|
||||
val minimumSpacing = 24.dp.toPx()
|
||||
val userWidth = placeable.width + minimumSpacing
|
||||
val maxVisibleUsers = rowWidth / userWidth
|
||||
if (maxVisibleUsers >= selectedUsers.size) {
|
||||
// If we can fit all the users in, don't do anything fancy
|
||||
(placeable.width + minimumSpacing).toInt()
|
||||
} else {
|
||||
// Round down the number of visible users to end with a state where one is half visible
|
||||
val targetFraction = (placeable.width / 2) / userWidth
|
||||
val targetUsers = floor(maxVisibleUsers - targetFraction) + targetFraction
|
||||
|
||||
// Work out how much extra spacing we need to reduce the number of users that much, then split it evenly amongst the visible users
|
||||
val extraSpacing = (maxVisibleUsers - targetUsers) * userWidth
|
||||
val extraSpacingPerUser = (extraSpacing) / floor(targetUsers)
|
||||
|
||||
(placeable.width + minimumSpacing + extraSpacingPerUser).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
layout(width, placeable.height) {
|
||||
placeable.place(0, 0)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -81,7 +134,23 @@ internal fun SelectedUsersListDarkPreview() = ElementPreviewDark { ContentToPrev
|
|||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
SelectedUsersList(
|
||||
selectedUsers = aMatrixUserList().take(6).toImmutableList(),
|
||||
)
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
// Two users that will be visible with no scrolling
|
||||
SelectedUsersList(
|
||||
selectedUsers = aMatrixUserList().take(2).toImmutableList(),
|
||||
modifier = Modifier
|
||||
.width(200.dp)
|
||||
.border(1.dp, Color.Red)
|
||||
)
|
||||
|
||||
// Multiple users that don't fit, so will be spaced out per the measure policy
|
||||
for (i in 0..5) {
|
||||
SelectedUsersList(
|
||||
selectedUsers = aMatrixUserList().take(6).toImmutableList(),
|
||||
modifier = Modifier
|
||||
.width((200 + (i * 20)).dp)
|
||||
.border(1.dp, Color.Red)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue