Adding a view to list the selected users

This commit is contained in:
Maxime NATUREL 2023-03-13 16:17:55 +01:00 committed by Florian Renaud
parent a41b025f5b
commit 341dfb478e
3 changed files with 97 additions and 5 deletions

View file

@ -16,7 +16,9 @@
package io.element.android.features.createroom.impl.selectmembers package io.element.android.features.createroom.impl.selectmembers
import io.element.android.libraries.matrix.ui.model.MatrixUser
data class SelectMembersState( data class SelectMembersState(
val selectedUserIds: List<String> = emptyList(), val selectedUsers: List<MatrixUser> = emptyList(),
val eventSink: (SelectMembersEvents) -> Unit, val eventSink: (SelectMembersEvents) -> Unit,
) )

View file

@ -17,15 +17,28 @@
package io.element.android.features.createroom.impl.selectmembers package io.element.android.features.createroom.impl.selectmembers
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.ui.model.MatrixUser
open class SelectMembersStateProvider : PreviewParameterProvider<SelectMembersState> { open class SelectMembersStateProvider : PreviewParameterProvider<SelectMembersState> {
override val values: Sequence<SelectMembersState> override val values: Sequence<SelectMembersState>
get() = sequenceOf( get() = sequenceOf(
aSelectMembersState(), aSelectMembersState(),
aSelectMembersState().copy(selectedUserIds = listOf("someUserId")) aSelectMembersState().copy(
selectedUsers = listOf(
aMatrixUser(userName = "User"),
aMatrixUser(userName = "User with long name"),
)
)
) )
} }
fun aSelectMembersState() = SelectMembersState( fun aSelectMembersState() = SelectMembersState(
eventSink = {} eventSink = {}
) )
fun aMatrixUser(userName: String): MatrixUser {
return MatrixUser(id = UserId("@id"), username = userName, avatarData = AvatarData("@id", "U", size = AvatarSize.BIG))
}

View file

@ -16,25 +16,43 @@
package io.element.android.features.createroom.impl.selectmembers package io.element.android.features.createroom.impl.selectmembers
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
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.designsystem.theme.components.CenterAlignedTopAppBar import io.element.android.libraries.designsystem.theme.components.CenterAlignedTopAppBar
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.matrix.ui.model.MatrixUser
import io.element.android.libraries.ui.strings.R as StringR import io.element.android.libraries.ui.strings.R as StringR
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@ -50,18 +68,23 @@ fun SelectMembersView(
Scaffold( Scaffold(
topBar = { topBar = {
SelectMembersViewTopBar( SelectMembersViewTopBar(
hasSelectedUsers = state.selectedUserIds.isNotEmpty(), hasSelectedUsers = state.selectedUsers.isNotEmpty(),
onBackPressed = onBackPressed, onBackPressed = onBackPressed,
onNextPressed = onNextPressed, onNextPressed = onNextPressed,
) )
} }
) { padding -> ) { padding ->
Box( Column(
modifier = modifier modifier = modifier
.fillMaxSize() .fillMaxSize()
.padding(padding) .padding(padding)
) { ) {
SelectedMembersList(
modifier = Modifier.padding(horizontal = 16.dp),
selectedUsers = state.selectedUsers,
)
// TODO create ViewEvent to add/remove selected user
// TODO create a SearchUserView with multi selection option + callbacks
} }
} }
} }
@ -99,6 +122,60 @@ fun SelectMembersViewTopBar(
) )
} }
@Composable
fun SelectedMembersList(
selectedUsers: List<MatrixUser>,
modifier: Modifier = Modifier,
onUserRemoved: (MatrixUser) -> Unit = {},
) {
LazyRow(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(24.dp),
) {
items(selectedUsers) { matrixUser ->
SelectedMember(
matrixUser = matrixUser,
onUserRemoved = onUserRemoved,
)
}
}
}
@Composable
fun SelectedMember(
matrixUser: MatrixUser,
modifier: Modifier = Modifier,
onUserRemoved: (MatrixUser) -> Unit,
) {
Box(modifier = modifier.width(56.dp)) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Avatar(matrixUser.avatarData)
Text(
text = matrixUser.username.orEmpty(),
overflow = TextOverflow.Ellipsis,
maxLines = 1,
style = MaterialTheme.typography.bodyLarge,
)
}
IconButton(
modifier = Modifier
.clip(CircleShape)
.background(MaterialTheme.colorScheme.primary)
.size(20.dp)
.align(Alignment.TopEnd),
onClick = { onUserRemoved(matrixUser) }
) {
Icon(
imageVector = Icons.Default.Close,
contentDescription = stringResource(id = StringR.string.action_remove),
tint = MaterialTheme.colorScheme.onPrimary,
)
}
}
}
@Preview @Preview
@Composable @Composable
internal fun ChangeServerViewLightPreview(@PreviewParameter(SelectMembersStateProvider::class) state: SelectMembersState) = internal fun ChangeServerViewLightPreview(@PreviewParameter(SelectMembersStateProvider::class) state: SelectMembersState) =