diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressEvents.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressEvents.kt index a37774f1c5..69b51ce1c6 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressEvents.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressEvents.kt @@ -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 } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressNode.kt index 88299775cd..fbbfee203f 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressNode.kt @@ -29,6 +29,7 @@ class EditRoomAddressNode @AssistedInject constructor( val state = presenter.present() EditRoomAddressView( state = state, + onBackClick = ::navigateUp, modifier = modifier ) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressPresenter.kt index 384a1244f8..a2417e308a 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressPresenter.kt @@ -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 { +class EditRoomAddressPresenter @Inject constructor( + private val client: MatrixClient, + private val room: MatrixRoom, + private val roomAliasHelper: RoomAliasHelper, +) : Presenter { @Composable override fun present(): EditRoomAddressState { + val homeserverName = remember { client.userIdServerName() } + val roomAddressValidity = remember { + mutableStateOf(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) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressState.kt index 6709d41024..a4d6dbe5a0 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressState.kt @@ -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 +} diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressStateProvider.kt index 0f610f1714..48d6615615 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressStateProvider.kt @@ -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 { override val values: Sequence @@ -17,6 +18,14 @@ open class EditRoomAddressStateProvider : PreviewParameterProvider Unit = {} +) = EditRoomAddressState( + roomAddress = roomAddress, + roomAddressValidity = roomAddressValidity, + homeserverName = homeserverName, + eventSink = eventSink ) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressView.kt index 3a4ca3eaaa..c6059dce0c 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressView.kt @@ -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 = {}, ) }