WIP create room screen

This commit is contained in:
Florian Renaud 2023-04-03 15:02:33 +02:00
parent 0a926bd05a
commit ac5f50d264
6 changed files with 207 additions and 6 deletions

View file

@ -49,6 +49,7 @@ dependencies {
implementation(projects.libraries.uiStrings) implementation(projects.libraries.uiStrings)
implementation(projects.features.userlist.api) implementation(projects.features.userlist.api)
api(projects.features.createroom.api) api(projects.features.createroom.api)
implementation(libs.coil.compose) // FIXME temp
testImplementation(libs.test.junit) testImplementation(libs.test.junit)
testImplementation(libs.coroutines.test) testImplementation(libs.coroutines.test)

View file

@ -21,6 +21,7 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import kotlinx.collections.immutable.toImmutableList
class ConfigureRoomPresenter @AssistedInject constructor( class ConfigureRoomPresenter @AssistedInject constructor(
@Assisted val args: ConfigureRoomPresenterArgs, @Assisted val args: ConfigureRoomPresenterArgs,
@ -41,7 +42,8 @@ class ConfigureRoomPresenter @AssistedInject constructor(
} }
return ConfigureRoomState( return ConfigureRoomState(
selectedUsers = args.selectedUsers, selectedUsers = args.selectedUsers.toImmutableList(),
avatarUri = null,
eventSink = ::handleEvents, eventSink = ::handleEvents,
) )
} }

View file

@ -16,9 +16,12 @@
package io.element.android.features.createroom.impl.configureroom package io.element.android.features.createroom.impl.configureroom
import android.net.Uri
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.collections.immutable.ImmutableList
data class ConfigureRoomState( data class ConfigureRoomState(
val selectedUsers: List<MatrixUser>, val selectedUsers: ImmutableList<MatrixUser>,
val avatarUri: Uri?,
val eventSink: (ConfigureRoomEvents) -> Unit val eventSink: (ConfigureRoomEvents) -> Unit
) )

View file

@ -17,6 +17,8 @@
package io.element.android.features.createroom.impl.configureroom package io.element.android.features.createroom.impl.configureroom
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.matrix.ui.components.aMatrixUser
import kotlinx.collections.immutable.persistentListOf
open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomState> { open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomState> {
override val values: Sequence<ConfigureRoomState> override val values: Sequence<ConfigureRoomState>
@ -27,6 +29,7 @@ open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomSt
} }
fun aConfigureRoomState() = ConfigureRoomState( fun aConfigureRoomState() = ConfigureRoomState(
selectedUsers = emptyList(), selectedUsers = persistentListOf(aMatrixUser(), aMatrixUser(), aMatrixUser(), aMatrixUser(), aMatrixUser(), aMatrixUser()),
avatarUri = null,
eventSink = {} eventSink = {}
) )

View file

@ -16,26 +16,215 @@
package io.element.android.features.createroom.impl.configureroom package io.element.android.features.createroom.impl.configureroom
import android.net.Uri
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
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.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.AddAPhoto
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment 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.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
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.sp
import coil.compose.AsyncImage
import coil.request.ImageRequest
import io.element.android.features.selectusers.api.SelectedUsersList
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.LocalColors
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.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.TextField
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ConfigureRoomView( fun ConfigureRoomView(
state: ConfigureRoomState, state: ConfigureRoomState,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onBackPressed: () -> Unit = {},
onCreatePressed: () -> Unit = {},
) { ) {
Box(modifier, contentAlignment = Alignment.Center) { Scaffold(
modifier = modifier,
topBar = {
ConfigureRoomToolbar(
isNextActionEnabled = false,
onBackPressed = onBackPressed,
onNextPressed = onCreatePressed,
)
}
) { padding ->
Column(
modifier = Modifier.padding(padding),
verticalArrangement = Arrangement.spacedBy(24.dp),
) {
RoomNameWithAvatar(
modifier = Modifier.padding(horizontal = 16.dp),
)
RoomTopic(
modifier = Modifier.padding(horizontal = 16.dp),
)
SelectedUsersList(
listState = LazyListState(), // FIXME
contentPadding = PaddingValues(horizontal = 24.dp),
selectedUsers = state.selectedUsers,
onUserRemoved = {
// TODO
},
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ConfigureRoomToolbar(
isNextActionEnabled: Boolean,
modifier: Modifier = Modifier,
onBackPressed: () -> Unit = {},
onNextPressed: () -> Unit = {},
) {
CenterAlignedTopAppBar(
modifier = modifier,
title = {
Text(
text = "Create a room",
fontSize = 16.sp,
fontWeight = FontWeight.SemiBold,
)
},
navigationIcon = { BackButton(onClick = onBackPressed) },
actions = {
TextButton(
modifier = Modifier.padding(horizontal = 8.dp),
enabled = isNextActionEnabled,
onClick = onNextPressed,
) {
Text(
text = "Create",
fontSize = 16.sp,
)
}
}
)
}
@Composable
fun RoomNameWithAvatar(
modifier: Modifier = Modifier,
avatarUri: Uri? = null,
roomName: String = "",
onAvatarClick: () -> Unit = {},
onRoomNameChanged: (String) -> Unit = {},
) {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Avatar(
avatarUri = avatarUri,
onClick = onAvatarClick,
)
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(
modifier = Modifier.padding(horizontal = 16.dp),
text = "Room name"
)
TextField(
modifier = Modifier.fillMaxWidth(),
value = roomName,
placeholder = { Text("e.g. Product Sprint") },
onValueChange = onRoomNameChanged,
maxLines = 1,
)
}
}
}
@Composable
fun Avatar(
modifier: Modifier = Modifier,
avatarUri: Uri? = null,
onClick: () -> Unit = {},
) {
val commonModifier = modifier
.size(70.dp)
.clip(CircleShape)
.clickable(onClick = onClick)
if (avatarUri != null) {
val context = LocalContext.current
val model = ImageRequest.Builder(context)
.data(avatarUri)
.build()
AsyncImage(
model = model,
contentDescription = null,
modifier = commonModifier,
)
} else {
Box(
modifier = commonModifier
.background(LocalColors.current.quinary)
) {
Icon(
imageVector = Icons.Outlined.AddAPhoto,
contentDescription = "",
modifier = modifier
.align(Alignment.Center)
.size(40.dp),
tint = MaterialTheme.colorScheme.secondary,
)
}
}
}
@Composable
fun RoomTopic(
modifier: Modifier = Modifier,
topic: String = "",
onTopicChanged: (String) -> Unit = {},
) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text( Text(
"ConfigureRoom feature view", modifier = Modifier.padding(horizontal = 16.dp),
color = MaterialTheme.colorScheme.primary, text = "Topic (optional)",
)
TextField(
modifier = Modifier.fillMaxWidth(),
value = topic,
placeholder = { Text("What is this room about?") },
onValueChange = onTopicChanged,
maxLines = 3,
) )
} }
} }

View file

@ -21,6 +21,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement 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.Column
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.layout.size import androidx.compose.foundation.layout.size
@ -244,11 +245,13 @@ fun SelectedUsersList(
listState: LazyListState, listState: LazyListState,
selectedUsers: ImmutableList<MatrixUser>, selectedUsers: ImmutableList<MatrixUser>,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
onUserRemoved: (MatrixUser) -> Unit = {}, onUserRemoved: (MatrixUser) -> Unit = {},
) { ) {
LazyRow( LazyRow(
state = listState, state = listState,
modifier = modifier, modifier = modifier,
contentPadding = contentPadding,
horizontalArrangement = Arrangement.spacedBy(24.dp), horizontalArrangement = Arrangement.spacedBy(24.dp),
) { ) {
items(selectedUsers.toList()) { matrixUser -> items(selectedUsers.toList()) { matrixUser ->