feat(security&privacy) : get data from sdk

This commit is contained in:
ganfra 2025-01-21 20:38:29 +01:00
parent 6e4bcedc4c
commit 6e43c2d659
5 changed files with 118 additions and 33 deletions

View file

@ -12,5 +12,5 @@ sealed interface SecurityAndPrivacyEvents {
data class ChangeRoomAccess(val roomAccess: SecurityAndPrivacyRoomAccess) : SecurityAndPrivacyEvents data class ChangeRoomAccess(val roomAccess: SecurityAndPrivacyRoomAccess) : SecurityAndPrivacyEvents
data object EnableEncryption: SecurityAndPrivacyEvents data object EnableEncryption: SecurityAndPrivacyEvents
data class ChangeHistoryVisibility(val historyVisibility: SecurityAndPrivacyHistoryVisibility) : SecurityAndPrivacyEvents data class ChangeHistoryVisibility(val historyVisibility: SecurityAndPrivacyHistoryVisibility) : SecurityAndPrivacyEvents
data class ChangeVisibleInRoomDirectory(val isVisibleInRoomDirectory: Boolean) : SecurityAndPrivacyEvents data class ChangeRoomVisibility(val isVisibleInRoomDirectory: Boolean) : SecurityAndPrivacyEvents
} }

View file

@ -8,47 +8,129 @@
package io.element.android.features.roomdetails.impl.securityandprivacy package io.element.android.features.roomdetails.impl.securityandprivacy
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter 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 java.util.Optional
import javax.inject.Inject import javax.inject.Inject
class SecurityAndPrivacyPresenter @Inject constructor() : Presenter<SecurityAndPrivacyState> { class SecurityAndPrivacyPresenter @Inject constructor() : Presenter<SecurityAndPrivacyState> {
private val matrixClient: MatrixClient,
private val room: MatrixRoom,
) : Presenter<SecurityAndPrivacyState> {
@Composable @Composable
override fun present(): SecurityAndPrivacyState { override fun present(): SecurityAndPrivacyState {
val homeserverName = remember { matrixClient.userIdServerName() }
val roomInfo by room.roomInfoFlow.collectAsState(initial = null)
val savedSettings by remember { val isVisibleInRoomDirectory = remember {
mutableStateOf( mutableStateOf<AsyncData<Boolean>>(AsyncData.Uninitialized)
SecurityAndPrivacySettings(
roomAccess = SecurityAndPrivacyRoomAccess.InviteOnly,
isEncrypted = true,
isVisibleInRoomDirectory = Optional.empty(),
historyVisibility = Optional.empty(),
formattedAddress = Optional.empty(),
)
)
} }
fun handleEvents(event: SecurityAndPrivacyEvents) { val savedSettings by remember {
when (event) { derivedStateOf {
SecurityAndPrivacyEvents.Save -> {} SecurityAndPrivacySettings(
is SecurityAndPrivacyEvents.ChangeRoomAccess -> {} roomAccess = roomInfo?.joinRule.map(),
is SecurityAndPrivacyEvents.EnableEncryption -> {} isEncrypted = room.isEncrypted,
is SecurityAndPrivacyEvents.ChangeHistoryVisibility -> {} isVisibleInRoomDirectory = Optional.ofNullable(isVisibleInRoomDirectory.value),
is SecurityAndPrivacyEvents.ChangeVisibleInRoomDirectory -> {} 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( return SecurityAndPrivacyState(
savedSettings = savedSettings, savedSettings = savedSettings,
currentSettings = savedSettings, currentSettings = currentSettings,
homeserverName = "", homeserverName = homeserverName,
canBeSaved = true,
eventSink = ::handleEvents 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
}
}

View file

@ -15,9 +15,11 @@ data class SecurityAndPrivacyState(
val savedSettings: SecurityAndPrivacySettings, val savedSettings: SecurityAndPrivacySettings,
val currentSettings: SecurityAndPrivacySettings, val currentSettings: SecurityAndPrivacySettings,
val homeserverName: String, val homeserverName: String,
val canBeSaved: Boolean,
val eventSink: (SecurityAndPrivacyEvents) -> Unit val eventSink: (SecurityAndPrivacyEvents) -> Unit
) { ) {
val canBeSaved = savedSettings != currentSettings
val showRoomVisibilitySections = currentSettings.roomAccess != SecurityAndPrivacyRoomAccess.InviteOnly && currentSettings.historyVisibility.isPresent val showRoomVisibilitySections = currentSettings.roomAccess != SecurityAndPrivacyRoomAccess.InviteOnly && currentSettings.historyVisibility.isPresent
val availableHistoryVisibilities = buildSet { val availableHistoryVisibilities = buildSet {

View file

@ -41,7 +41,6 @@ open class SecurityAndPrivacyStateProvider : PreviewParameterProvider<SecurityAn
isVisibleInRoomDirectory = Optional.of(AsyncData.Success(true)) isVisibleInRoomDirectory = Optional.of(AsyncData.Success(true))
) )
), ),
aSecurityAndPrivacyState(canBeSaved = false)
) )
} }
@ -62,13 +61,11 @@ fun aSecurityAndPrivacySettings(
fun aSecurityAndPrivacyState( fun aSecurityAndPrivacyState(
currentSettings: SecurityAndPrivacySettings = aSecurityAndPrivacySettings(), currentSettings: SecurityAndPrivacySettings = aSecurityAndPrivacySettings(),
savedSettings: SecurityAndPrivacySettings = currentSettings, savedSettings: SecurityAndPrivacySettings = currentSettings,
canBeSaved: Boolean = true,
homeserverName: String = "myserver.xyz", homeserverName: String = "myserver.xyz",
eventSink: (SecurityAndPrivacyEvents) -> Unit = {} eventSink: (SecurityAndPrivacyEvents) -> Unit = {}
) = SecurityAndPrivacyState( ) = SecurityAndPrivacyState(
currentSettings = currentSettings, currentSettings = currentSettings,
savedSettings = savedSettings, savedSettings = savedSettings,
homeserverName = homeserverName, homeserverName = homeserverName,
canBeSaved = canBeSaved,
eventSink = eventSink eventSink = eventSink
) )

View file

@ -69,10 +69,10 @@ fun SecurityAndPrivacyView(
) { padding -> ) { padding ->
Column( Column(
modifier = Modifier modifier = Modifier
.padding(padding) .padding(padding)
.imePadding() .imePadding()
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
.consumeWindowInsets(padding), .consumeWindowInsets(padding),
verticalArrangement = Arrangement.spacedBy(32.dp), verticalArrangement = Arrangement.spacedBy(32.dp),
) { ) {
RoomAccessSection( RoomAccessSection(
@ -87,11 +87,14 @@ fun SecurityAndPrivacyView(
homeserverName = state.homeserverName, homeserverName = state.homeserverName,
onRoomAddressClick = { }, onRoomAddressClick = { },
isVisibleInPublicDirectory = state.currentSettings.isVisibleInRoomDirectory, isVisibleInPublicDirectory = state.currentSettings.isVisibleInRoomDirectory,
onVisibilityChange = { }, onVisibilityChange = { isVisible ->
state.eventSink(SecurityAndPrivacyEvents.ChangeRoomVisibility(isVisible))
},
) )
} }
EncryptionSection( EncryptionSection(
isEncryptionEnabled = state.currentSettings.isEncrypted, isEncryptionEnabled = state.currentSettings.isEncrypted,
isSectionEnabled = !state.savedSettings.isEncrypted,
onEnableEncryption = { state.eventSink(SecurityAndPrivacyEvents.EnableEncryption) }, onEnableEncryption = { state.eventSink(SecurityAndPrivacyEvents.EnableEncryption) },
) )
if (state.showRoomHistoryVisibilitySection) { if (state.showRoomHistoryVisibilitySection) {
@ -243,8 +246,8 @@ private fun RoomAddressSection(
ListItemContent.Custom { ListItemContent.Custom {
CircularProgressIndicator( CircularProgressIndicator(
modifier = Modifier modifier = Modifier
.progressSemantics() .progressSemantics()
.size(20.dp), .size(20.dp),
strokeWidth = 2.dp strokeWidth = 2.dp
) )
} }
@ -270,6 +273,7 @@ private fun RoomAddressSection(
@Composable @Composable
private fun EncryptionSection( private fun EncryptionSection(
isEncryptionEnabled: Boolean, isEncryptionEnabled: Boolean,
isSectionEnabled: Boolean,
onEnableEncryption: () -> Unit, onEnableEncryption: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@ -282,7 +286,7 @@ private fun EncryptionSection(
supportingContent = { Text(text = stringResource(CommonStrings.screen_security_and_privacy_encryption_section_footer)) }, supportingContent = { Text(text = stringResource(CommonStrings.screen_security_and_privacy_encryption_section_footer)) },
trailingContent = ListItemContent.Switch( trailingContent = ListItemContent.Switch(
checked = isEncryptionEnabled, checked = isEncryptionEnabled,
enabled = !isEncryptionEnabled, enabled = isSectionEnabled,
onChange = { onEnableEncryption() } onChange = { onEnableEncryption() }
), ),
) )