diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyEvents.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyEvents.kt index 72af1449a9..f87aff2f31 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyEvents.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyEvents.kt @@ -12,5 +12,5 @@ sealed interface SecurityAndPrivacyEvents { data class ChangeRoomAccess(val roomAccess: SecurityAndPrivacyRoomAccess) : SecurityAndPrivacyEvents data object EnableEncryption: SecurityAndPrivacyEvents data class ChangeHistoryVisibility(val historyVisibility: SecurityAndPrivacyHistoryVisibility) : SecurityAndPrivacyEvents - data class ChangeVisibleInRoomDirectory(val isVisibleInRoomDirectory: Boolean) : SecurityAndPrivacyEvents + data class ChangeRoomVisibility(val isVisibleInRoomDirectory: Boolean) : SecurityAndPrivacyEvents } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt index 6568704d9c..901a3b4a4b 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt @@ -8,47 +8,129 @@ package io.element.android.features.roomdetails.impl.securityandprivacy import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.derivedStateOf 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.AsyncData import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility +import io.element.android.libraries.matrix.api.room.join.JoinRule import java.util.Optional import javax.inject.Inject class SecurityAndPrivacyPresenter @Inject constructor() : Presenter { + private val matrixClient: MatrixClient, + private val room: MatrixRoom, +) : Presenter { @Composable override fun present(): SecurityAndPrivacyState { + val homeserverName = remember { matrixClient.userIdServerName() } + val roomInfo by room.roomInfoFlow.collectAsState(initial = null) - val savedSettings by remember { - mutableStateOf( - SecurityAndPrivacySettings( - roomAccess = SecurityAndPrivacyRoomAccess.InviteOnly, - isEncrypted = true, - isVisibleInRoomDirectory = Optional.empty(), - historyVisibility = Optional.empty(), - formattedAddress = Optional.empty(), - ) - ) + val isVisibleInRoomDirectory = remember { + mutableStateOf>(AsyncData.Uninitialized) } - fun handleEvents(event: SecurityAndPrivacyEvents) { - when (event) { - SecurityAndPrivacyEvents.Save -> {} - is SecurityAndPrivacyEvents.ChangeRoomAccess -> {} - is SecurityAndPrivacyEvents.EnableEncryption -> {} - is SecurityAndPrivacyEvents.ChangeHistoryVisibility -> {} - is SecurityAndPrivacyEvents.ChangeVisibleInRoomDirectory -> {} + val savedSettings by remember { + derivedStateOf { + SecurityAndPrivacySettings( + roomAccess = roomInfo?.joinRule.map(), + isEncrypted = room.isEncrypted, + isVisibleInRoomDirectory = Optional.ofNullable(isVisibleInRoomDirectory.value), + historyVisibility = Optional.ofNullable(roomInfo?.historyVisibility?.map()), + formattedAddress = Optional.ofNullable(roomInfo?.canonicalAlias?.value), + ) } } + var currentRoomAccess by remember(savedSettings.roomAccess) { + mutableStateOf(savedSettings.roomAccess) + } + var currentHistoryVisibility by remember(savedSettings.historyVisibility) { + mutableStateOf(savedSettings.historyVisibility) + } + var currentVisibleInRoomDirectory by remember(savedSettings.isVisibleInRoomDirectory) { + mutableStateOf(savedSettings.isVisibleInRoomDirectory) + } + var currentIsEncrypted by remember(savedSettings.isEncrypted) { + mutableStateOf(savedSettings.isEncrypted) + } + val currentSettings = SecurityAndPrivacySettings( + roomAccess = currentRoomAccess, + isEncrypted = currentIsEncrypted, + isVisibleInRoomDirectory = currentVisibleInRoomDirectory, + historyVisibility = currentHistoryVisibility, + formattedAddress = savedSettings.formattedAddress, + ) + + fun handleEvents(event: SecurityAndPrivacyEvents) { + when (event) { + SecurityAndPrivacyEvents.Save -> { + } + is SecurityAndPrivacyEvents.ChangeRoomAccess -> { + currentRoomAccess = event.roomAccess + } + is SecurityAndPrivacyEvents.EnableEncryption -> { + currentIsEncrypted = true + } + is SecurityAndPrivacyEvents.ChangeHistoryVisibility -> { + currentHistoryVisibility = Optional.of(event.historyVisibility) + } + is SecurityAndPrivacyEvents.ChangeRoomVisibility -> { + currentVisibleInRoomDirectory = Optional.of(AsyncData.Success(event.isVisibleInRoomDirectory)) + } + } + } return SecurityAndPrivacyState( savedSettings = savedSettings, - currentSettings = savedSettings, - homeserverName = "", - canBeSaved = true, + currentSettings = currentSettings, + homeserverName = homeserverName, eventSink = ::handleEvents ) } } + +private fun JoinRule?.map(): SecurityAndPrivacyRoomAccess { + return when (this) { + JoinRule.Public -> SecurityAndPrivacyRoomAccess.Anyone + JoinRule.Knock, is JoinRule.KnockRestricted -> SecurityAndPrivacyRoomAccess.AskToJoin + is JoinRule.Restricted -> SecurityAndPrivacyRoomAccess.SpaceMember + is JoinRule.Custom, + JoinRule.Invite, + JoinRule.Private, + null -> SecurityAndPrivacyRoomAccess.InviteOnly + } +} + +private fun SecurityAndPrivacyRoomAccess.map(): JoinRule { + return when (this) { + SecurityAndPrivacyRoomAccess.Anyone -> JoinRule.Public + SecurityAndPrivacyRoomAccess.AskToJoin -> JoinRule.Knock + SecurityAndPrivacyRoomAccess.InviteOnly -> JoinRule.Private + SecurityAndPrivacyRoomAccess.SpaceMember -> error("Unsupported") + } +} + +private fun RoomHistoryVisibility.map(): SecurityAndPrivacyHistoryVisibility { + return when (this) { + RoomHistoryVisibility.Joined, + RoomHistoryVisibility.Invited -> SecurityAndPrivacyHistoryVisibility.SinceInvite + RoomHistoryVisibility.Shared, + is RoomHistoryVisibility.Custom -> SecurityAndPrivacyHistoryVisibility.SinceSelection + RoomHistoryVisibility.WorldReadable -> SecurityAndPrivacyHistoryVisibility.Anyone + } +} + +private fun SecurityAndPrivacyHistoryVisibility.map(): RoomHistoryVisibility { + return when (this) { + SecurityAndPrivacyHistoryVisibility.SinceSelection -> RoomHistoryVisibility.Shared + SecurityAndPrivacyHistoryVisibility.SinceInvite -> RoomHistoryVisibility.Invited + SecurityAndPrivacyHistoryVisibility.Anyone -> RoomHistoryVisibility.WorldReadable + } +} diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyState.kt index 5d598f4c53..9208135985 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyState.kt @@ -15,9 +15,11 @@ data class SecurityAndPrivacyState( val savedSettings: SecurityAndPrivacySettings, val currentSettings: SecurityAndPrivacySettings, val homeserverName: String, - val canBeSaved: Boolean, val eventSink: (SecurityAndPrivacyEvents) -> Unit ) { + + val canBeSaved = savedSettings != currentSettings + val showRoomVisibilitySections = currentSettings.roomAccess != SecurityAndPrivacyRoomAccess.InviteOnly && currentSettings.historyVisibility.isPresent val availableHistoryVisibilities = buildSet { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyStateProvider.kt index 2807763c6e..6955008914 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyStateProvider.kt @@ -41,7 +41,6 @@ open class SecurityAndPrivacyStateProvider : PreviewParameterProvider Unit = {} ) = SecurityAndPrivacyState( currentSettings = currentSettings, savedSettings = savedSettings, homeserverName = homeserverName, - canBeSaved = canBeSaved, eventSink = eventSink ) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyView.kt index 2ad61f2e18..540f81a80e 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyView.kt @@ -69,10 +69,10 @@ fun SecurityAndPrivacyView( ) { padding -> Column( modifier = Modifier - .padding(padding) - .imePadding() - .verticalScroll(rememberScrollState()) - .consumeWindowInsets(padding), + .padding(padding) + .imePadding() + .verticalScroll(rememberScrollState()) + .consumeWindowInsets(padding), verticalArrangement = Arrangement.spacedBy(32.dp), ) { RoomAccessSection( @@ -87,11 +87,14 @@ fun SecurityAndPrivacyView( homeserverName = state.homeserverName, onRoomAddressClick = { }, isVisibleInPublicDirectory = state.currentSettings.isVisibleInRoomDirectory, - onVisibilityChange = { }, + onVisibilityChange = { isVisible -> + state.eventSink(SecurityAndPrivacyEvents.ChangeRoomVisibility(isVisible)) + }, ) } EncryptionSection( isEncryptionEnabled = state.currentSettings.isEncrypted, + isSectionEnabled = !state.savedSettings.isEncrypted, onEnableEncryption = { state.eventSink(SecurityAndPrivacyEvents.EnableEncryption) }, ) if (state.showRoomHistoryVisibilitySection) { @@ -243,8 +246,8 @@ private fun RoomAddressSection( ListItemContent.Custom { CircularProgressIndicator( modifier = Modifier - .progressSemantics() - .size(20.dp), + .progressSemantics() + .size(20.dp), strokeWidth = 2.dp ) } @@ -270,6 +273,7 @@ private fun RoomAddressSection( @Composable private fun EncryptionSection( isEncryptionEnabled: Boolean, + isSectionEnabled: Boolean, onEnableEncryption: () -> Unit, modifier: Modifier = Modifier, ) { @@ -282,7 +286,7 @@ private fun EncryptionSection( supportingContent = { Text(text = stringResource(CommonStrings.screen_security_and_privacy_encryption_section_footer)) }, trailingContent = ListItemContent.Switch( checked = isEncryptionEnabled, - enabled = !isEncryptionEnabled, + enabled = isSectionEnabled, onChange = { onEnableEncryption() } ), )