feat(security&privacy) : start handling edition of room address

This commit is contained in:
ganfra 2025-01-21 21:55:55 +01:00
parent 9faa305262
commit f8cd8b3cc2
6 changed files with 160 additions and 15 deletions

View file

@ -9,4 +9,5 @@ package io.element.android.features.roomdetails.impl.securityandprivacy.editroom
sealed interface EditRoomAddressEvents {
data object Save : EditRoomAddressEvents
data class RoomAddressChanged(val roomAddress: String) : EditRoomAddressEvents
}

View file

@ -29,6 +29,7 @@ class EditRoomAddressNode @AssistedInject constructor(
val state = presenter.present()
EditRoomAddressView(
state = state,
onBackClick = ::navigateUp,
modifier = modifier
)
}

View file

@ -8,22 +8,80 @@
package io.element.android.features.roomdetails.impl.securityandprivacy.editroomaddress
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper
import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity
import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidityEffect
import javax.inject.Inject
class EditRoomAddressPresenter @Inject constructor() : Presenter<EditRoomAddressState> {
class EditRoomAddressPresenter @Inject constructor(
private val client: MatrixClient,
private val room: MatrixRoom,
private val roomAliasHelper: RoomAliasHelper,
) : Presenter<EditRoomAddressState> {
@Composable
override fun present(): EditRoomAddressState {
val homeserverName = remember { client.userIdServerName() }
val roomAddressValidity = remember {
mutableStateOf<RoomAddressValidity>(RoomAddressValidity.Unknown)
}
val savedRoomAddress = remember {
room.firstAliasMatching(homeserverName)?.roomAddress()
}
var currentRoomAddress by remember {
mutableStateOf(
savedRoomAddress ?: roomAliasHelper.roomAliasNameFromRoomDisplayName(room.displayName)
)
}
fun handleEvents(event: EditRoomAddressEvents) {
when (event) {
EditRoomAddressEvents.Save -> Unit
is EditRoomAddressEvents.RoomAddressChanged -> {
currentRoomAddress = event.roomAddress
}
}
}
RoomAddressValidityEffect(
client = client,
roomAliasHelper = roomAliasHelper,
newRoomAddress = currentRoomAddress,
knownRoomAddress = savedRoomAddress
) { newRoomAddressValidity ->
roomAddressValidity.value = newRoomAddressValidity
}
return EditRoomAddressState(
homeserverName = homeserverName,
roomAddressValidity = roomAddressValidity.value,
roomAddress = currentRoomAddress,
eventSink = ::handleEvents
)
}
}
private fun MatrixRoom.firstAliasMatching(serverName: String): RoomAlias? {
// Check if the canonical alias matches the homeserver
if (this.alias?.matchesServer(serverName) == true) {
return this.alias
}
return this.alternativeAliases.firstOrNull { it.value.contains(serverName) }
}
private fun RoomAlias.roomAddress(): String {
return value.drop(1).split(":").first()
}
private fun RoomAlias.matchesServer(serverName: String): Boolean {
return value.contains(serverName)
}

View file

@ -7,6 +7,13 @@
package io.element.android.features.roomdetails.impl.securityandprivacy.editroomaddress
import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity
data class EditRoomAddressState(
val homeserverName: String,
val roomAddress: String,
val roomAddressValidity: RoomAddressValidity,
val eventSink: (EditRoomAddressEvents) -> Unit
)
) {
val canBeSaved = roomAddressValidity == RoomAddressValidity.Valid
}

View file

@ -8,6 +8,7 @@
package io.element.android.features.roomdetails.impl.securityandprivacy.editroomaddress
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity
open class EditRoomAddressStateProvider : PreviewParameterProvider<EditRoomAddressState> {
override val values: Sequence<EditRoomAddressState>
@ -17,6 +18,14 @@ open class EditRoomAddressStateProvider : PreviewParameterProvider<EditRoomAddre
)
}
fun aEditRoomAddressState() = EditRoomAddressState(
eventSink = {}
fun aEditRoomAddressState(
roomAddress: String = "therapy",
roomAddressValidity: RoomAddressValidity = RoomAddressValidity.Unknown,
homeserverName: String = ":myserver.org",
eventSink: (EditRoomAddressEvents) -> Unit = {}
) = EditRoomAddressState(
roomAddress = roomAddress,
roomAddressValidity = roomAddressValidity,
homeserverName = homeserverName,
eventSink = eventSink
)

View file

@ -8,32 +8,100 @@
package io.element.android.features.roomdetails.impl.securityandprivacy.editroomaddress
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
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.TextButton
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.matrix.ui.room.address.RoomAddressField
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun EditRoomAddressView(
state: EditRoomAddressState,
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Box(
modifier = modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
"EditRoomAddress feature view",
color = MaterialTheme.colorScheme.primary,
)
Scaffold(
modifier = modifier,
topBar = {
EditRoomAddressTopBar(
isSaveActionEnabled = state.canBeSaved,
onBackClick = onBackClick,
onSaveClick = {
state.eventSink(EditRoomAddressEvents.Save)
},
)
}
) { padding ->
Box(
modifier = Modifier
.padding(padding)
.imePadding()
.verticalScroll(rememberScrollState())
.consumeWindowInsets(padding)
) {
RoomAddressField(
address = state.roomAddress,
homeserverName = state.homeserverName,
addressValidity = state.roomAddressValidity,
onAddressChange = {
state.eventSink(EditRoomAddressEvents.RoomAddressChanged(it))
},
label = stringResource(CommonStrings.screen_edit_room_address_title),
supportingText = stringResource(CommonStrings.screen_edit_room_address_room_address_section_footer),
modifier = Modifier
.fillMaxWidth()
.padding(all = 16.dp)
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun EditRoomAddressTopBar(
isSaveActionEnabled: Boolean,
onBackClick: () -> Unit,
onSaveClick: () -> Unit,
modifier: Modifier = Modifier,
) {
TopAppBar(
modifier = modifier,
title = {
Text(
text = stringResource(CommonStrings.screen_edit_room_address_title),
style = ElementTheme.typography.aliasScreenTitle,
)
},
navigationIcon = { BackButton(onClick = onBackClick) },
actions = {
TextButton(
text = stringResource(CommonStrings.action_save),
enabled = isSaveActionEnabled,
onClick = onSaveClick,
)
}
)
}
@PreviewsDayNight
@Composable
internal fun EditRoomAddressViewPreview(
@ -41,5 +109,6 @@ internal fun EditRoomAddressViewPreview(
) = ElementPreview {
EditRoomAddressView(
state = state,
onBackClick = {},
)
}