Room visibility

This commit is contained in:
Florian Renaud 2023-04-05 16:28:09 +02:00
parent 5e88b23372
commit bb48f5f378
7 changed files with 209 additions and 7 deletions

View file

@ -22,4 +22,5 @@ sealed interface ConfigureRoomEvents {
data class RoomNameChanged(val name: String) : ConfigureRoomEvents data class RoomNameChanged(val name: String) : ConfigureRoomEvents
data class TopicChanged(val topic: String) : ConfigureRoomEvents data class TopicChanged(val topic: String) : ConfigureRoomEvents
data class AvatarUriChanged(val uri: Uri?) : ConfigureRoomEvents data class AvatarUriChanged(val uri: Uri?) : ConfigureRoomEvents
data class RoomPrivacyChanged(val privacy: RoomPrivacy?) : ConfigureRoomEvents
} }

View file

@ -42,12 +42,14 @@ class ConfigureRoomPresenter @AssistedInject constructor(
var roomName by rememberSaveable { mutableStateOf("") } var roomName by rememberSaveable { mutableStateOf("") }
var topic by rememberSaveable { mutableStateOf("") } var topic by rememberSaveable { mutableStateOf("") }
var avatarUri by rememberSaveable { mutableStateOf<Uri?>(null) } var avatarUri by rememberSaveable { mutableStateOf<Uri?>(null) }
var privacy by rememberSaveable { mutableStateOf<RoomPrivacy?>(null) }
fun handleEvents(event: ConfigureRoomEvents) { fun handleEvents(event: ConfigureRoomEvents) {
when (event) { when (event) {
is ConfigureRoomEvents.AvatarUriChanged -> avatarUri = event.uri is ConfigureRoomEvents.AvatarUriChanged -> avatarUri = event.uri
is ConfigureRoomEvents.RoomNameChanged -> roomName = event.name is ConfigureRoomEvents.RoomNameChanged -> roomName = event.name
is ConfigureRoomEvents.TopicChanged -> topic = event.topic is ConfigureRoomEvents.TopicChanged -> topic = event.topic
is ConfigureRoomEvents.RoomPrivacyChanged -> privacy = event.privacy
} }
} }
@ -56,6 +58,7 @@ class ConfigureRoomPresenter @AssistedInject constructor(
roomName = roomName, roomName = roomName,
topic = topic, topic = topic,
avatarUri = avatarUri, avatarUri = avatarUri,
privacy = privacy,
eventSink = ::handleEvents, eventSink = ::handleEvents,
) )
} }

View file

@ -25,5 +25,6 @@ data class ConfigureRoomState(
val roomName: String, val roomName: String,
val topic: String, val topic: String,
val avatarUri: Uri?, val avatarUri: Uri?,
val privacy: RoomPrivacy?,
val eventSink: (ConfigureRoomEvents) -> Unit val eventSink: (ConfigureRoomEvents) -> Unit
) )

View file

@ -33,5 +33,6 @@ fun aConfigureRoomState() = ConfigureRoomState(
roomName = "", roomName = "",
topic = "", topic = "",
avatarUri = null, avatarUri = null,
privacy = null,
eventSink = {} eventSink = {}
) )

View file

@ -24,20 +24,27 @@ 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.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
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.LazyListState import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.AddAPhoto import androidx.compose.material.icons.outlined.AddAPhoto
import androidx.compose.material.icons.outlined.Lock
import androidx.compose.material.icons.outlined.Public
import androidx.compose.material3.ExperimentalMaterial3Api 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.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight 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
@ -45,13 +52,14 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import coil.compose.AsyncImage import coil.compose.AsyncImage
import coil.request.ImageRequest import coil.request.ImageRequest
import io.element.android.features.selectusers.api.SelectedUsersList import io.element.android.features.userlist.api.SelectedUsersList
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.LocalColors 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.CenterAlignedTopAppBar
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.RadioButton
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
@ -98,6 +106,12 @@ fun ConfigureRoomView(
// TODO // TODO
}, },
) )
Spacer(Modifier.weight(1f))
RoomPrivacyOptions(
modifier = Modifier.padding(bottom = 40.dp),
selected = state.privacy,
onOptionSelected = { state.eventSink(ConfigureRoomEvents.RoomPrivacyChanged(it)) },
)
} }
} }
} }
@ -189,15 +203,12 @@ fun Avatar(
.data(avatarUri) .data(avatarUri)
.build() .build()
AsyncImage( AsyncImage(
modifier = commonModifier,
model = model, model = model,
contentDescription = null, contentDescription = null,
modifier = commonModifier,
) )
} else { } else {
Box( Box(modifier = commonModifier.background(LocalColors.current.quinary)) {
modifier = commonModifier
.background(LocalColors.current.quinary)
) {
Icon( Icon(
imageVector = Icons.Outlined.AddAPhoto, imageVector = Icons.Outlined.AddAPhoto,
contentDescription = "", contentDescription = "",
@ -212,8 +223,8 @@ fun Avatar(
@Composable @Composable
fun RoomTopic( fun RoomTopic(
modifier: Modifier = Modifier,
topic: String, topic: String,
modifier: Modifier = Modifier,
onTopicChanged: (String) -> Unit = {}, onTopicChanged: (String) -> Unit = {},
) { ) {
Column( Column(
@ -234,6 +245,106 @@ fun RoomTopic(
} }
} }
@Composable
fun RoomPrivacyOptions(
selected: RoomPrivacy?,
modifier: Modifier = Modifier,
onOptionSelected: (RoomPrivacy) -> Unit = {},
) {
data class RoomPrivacyItem(
val privacy: RoomPrivacy,
val icon: ImageVector,
val title: String,
val description: String,
)
val items = RoomPrivacy.values().map {
when (it) {
RoomPrivacy.Public -> RoomPrivacyItem(
privacy = it,
icon = Icons.Outlined.Lock,
title = "Private room (invite only)",
description = "Messages in this room are encrypted. Encryption cant be disabled afterwards.",
)
RoomPrivacy.Private -> RoomPrivacyItem(
privacy = it,
icon = Icons.Outlined.Public,
title = "Public room (anyone)",
description = "Messages are not encrypted and anyone can read them. You can enable encryption at a later date.",
)
}
}
Column(modifier = modifier.selectableGroup()) {
items.forEach { item ->
RoomPrivacyOption(
privacy = RoomPrivacy.Private,
icon = item.icon,
title = item.title,
description = item.description,
isSelected = selected == item.privacy,
onOptionSelected = { onOptionSelected(item.privacy) }
)
}
}
}
@Composable
fun RoomPrivacyOption(
privacy: RoomPrivacy,
icon: ImageVector,
title: String,
description: String,
modifier: Modifier = Modifier,
isSelected: Boolean = false,
onOptionSelected: (RoomPrivacy) -> Unit = {},
) {
Row(
modifier
.fillMaxWidth()
.selectable(
selected = isSelected,
onClick = { onOptionSelected(privacy) },
role = Role.RadioButton,
)
.padding(8.dp),
) {
Icon(
modifier = Modifier.padding(horizontal = 8.dp),
imageVector = icon,
contentDescription = "",
tint = MaterialTheme.colorScheme.secondary,
)
Column(
Modifier
.weight(1f)
.padding(horizontal = 8.dp)
) {
Text(
text = title,
fontSize = 16.sp,
color = MaterialTheme.colorScheme.primary,
)
Spacer(Modifier.size(3.dp))
Text(
text = description,
fontSize = 12.sp,
lineHeight = 17.sp,
color = MaterialTheme.colorScheme.tertiary,
)
}
RadioButton(
modifier = Modifier
.align(Alignment.CenterVertically)
.size(48.dp),
selected = isSelected,
onClick = null // null recommended for accessibility with screenreaders
)
}
}
@Preview @Preview
@Composable @Composable
fun ConfigureRoomViewLightPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) = fun ConfigureRoomViewLightPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) =

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.createroom.impl.configureroom
enum class RoomPrivacy {
Public,
Private,
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.RadioButtonColors
import androidx.compose.material3.RadioButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
@Composable
fun RadioButton(
selected: Boolean,
onClick: (() -> Unit)?,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: RadioButtonColors = RadioButtonDefaults.colors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
) {
androidx.compose.material3.RadioButton(
selected = selected,
onClick = onClick,
modifier = modifier,
enabled = enabled,
colors = colors,
interactionSource = interactionSource,
)
}
@Preview
@Composable
internal fun RadioButtonLightPreview() = ElementPreviewLight { ContentToPreview() }
@Preview
@Composable
internal fun RadioButtonDarkPreview() = ElementPreviewDark { ContentToPreview() }
@Composable
private fun ContentToPreview() {
Column {
RadioButton(selected = false, onClick = {})
RadioButton(selected = true, onClick = {})
}
}