feat(security&privacy) : improve and document code after PR review.

This commit is contained in:
ganfra 2025-01-29 14:16:57 +01:00
parent d6df09cf3d
commit e6549d725c
7 changed files with 32 additions and 30 deletions

View file

@ -96,7 +96,7 @@ class SecurityAndPrivacyPresenter @AssistedInject constructor(
address = savedSettings.address, address = savedSettings.address,
) )
var showEncryptionConfirmation by remember(savedSettings.isEncrypted) { mutableStateOf(false) } var showEnableEncryptionConfirmation by remember(savedSettings.isEncrypted) { mutableStateOf(false) }
val permissions by room.securityAndPrivacyPermissionsAsState(syncUpdateFlow.value) val permissions by room.securityAndPrivacyPermissionsAsState(syncUpdateFlow.value)
fun handleEvents(event: SecurityAndPrivacyEvents) { fun handleEvents(event: SecurityAndPrivacyEvents) {
@ -116,7 +116,7 @@ class SecurityAndPrivacyPresenter @AssistedInject constructor(
if (editedIsEncrypted) { if (editedIsEncrypted) {
editedIsEncrypted = false editedIsEncrypted = false
} else { } else {
showEncryptionConfirmation = true showEnableEncryptionConfirmation = true
} }
} }
is SecurityAndPrivacyEvents.ChangeHistoryVisibility -> { is SecurityAndPrivacyEvents.ChangeHistoryVisibility -> {
@ -130,10 +130,10 @@ class SecurityAndPrivacyPresenter @AssistedInject constructor(
} }
SecurityAndPrivacyEvents.EditRoomAddress -> navigator.openEditRoomAddress() SecurityAndPrivacyEvents.EditRoomAddress -> navigator.openEditRoomAddress()
SecurityAndPrivacyEvents.CancelEnableEncryption -> { SecurityAndPrivacyEvents.CancelEnableEncryption -> {
showEncryptionConfirmation = false showEnableEncryptionConfirmation = false
} }
SecurityAndPrivacyEvents.ConfirmEnableEncryption -> { SecurityAndPrivacyEvents.ConfirmEnableEncryption -> {
showEncryptionConfirmation = false showEnableEncryptionConfirmation = false
editedIsEncrypted = true editedIsEncrypted = true
} }
SecurityAndPrivacyEvents.DismissSaveError -> { SecurityAndPrivacyEvents.DismissSaveError -> {
@ -146,7 +146,7 @@ class SecurityAndPrivacyPresenter @AssistedInject constructor(
savedSettings = savedSettings, savedSettings = savedSettings,
editedSettings = editedSettings, editedSettings = editedSettings,
homeserverName = homeserverName, homeserverName = homeserverName,
showEncryptionConfirmation = showEncryptionConfirmation, showEnableEncryptionConfirmation = showEnableEncryptionConfirmation,
saveAction = saveAction.value, saveAction = saveAction.value,
permissions = permissions, permissions = permissions,
eventSink = ::handleEvents eventSink = ::handleEvents
@ -189,8 +189,9 @@ class SecurityAndPrivacyPresenter @AssistedInject constructor(
} }
} }
val updateJoinRule = async { val updateJoinRule = async {
if (editedSettings.roomAccess != savedSettings.roomAccess) { val joinRule = editedSettings.roomAccess.map()
room.updateJoinRule(editedSettings.roomAccess.map()) if (editedSettings.roomAccess != savedSettings.roomAccess && joinRule != null) {
room.updateJoinRule(joinRule)
} else { } else {
Result.success(Unit) Result.success(Unit)
} }
@ -239,19 +240,21 @@ private fun JoinRule?.map(): SecurityAndPrivacyRoomAccess {
JoinRule.Public -> SecurityAndPrivacyRoomAccess.Anyone JoinRule.Public -> SecurityAndPrivacyRoomAccess.Anyone
JoinRule.Knock, is JoinRule.KnockRestricted -> SecurityAndPrivacyRoomAccess.AskToJoin JoinRule.Knock, is JoinRule.KnockRestricted -> SecurityAndPrivacyRoomAccess.AskToJoin
is JoinRule.Restricted -> SecurityAndPrivacyRoomAccess.SpaceMember is JoinRule.Restricted -> SecurityAndPrivacyRoomAccess.SpaceMember
JoinRule.Invite -> SecurityAndPrivacyRoomAccess.InviteOnly
// All other cases are not supported so we default to InviteOnly
is JoinRule.Custom, is JoinRule.Custom,
JoinRule.Invite,
JoinRule.Private, JoinRule.Private,
null -> SecurityAndPrivacyRoomAccess.InviteOnly null -> SecurityAndPrivacyRoomAccess.InviteOnly
} }
} }
private fun SecurityAndPrivacyRoomAccess.map(): JoinRule { private fun SecurityAndPrivacyRoomAccess.map(): JoinRule? {
return when (this) { return when (this) {
SecurityAndPrivacyRoomAccess.Anyone -> JoinRule.Public SecurityAndPrivacyRoomAccess.Anyone -> JoinRule.Public
SecurityAndPrivacyRoomAccess.AskToJoin -> JoinRule.Knock SecurityAndPrivacyRoomAccess.AskToJoin -> JoinRule.Knock
SecurityAndPrivacyRoomAccess.InviteOnly -> JoinRule.Private SecurityAndPrivacyRoomAccess.InviteOnly -> JoinRule.Private
SecurityAndPrivacyRoomAccess.SpaceMember -> error("Unsupported") // SpaceMember can't be selected in the ui
SecurityAndPrivacyRoomAccess.SpaceMember -> null
} }
} }
@ -260,7 +263,8 @@ private fun RoomHistoryVisibility?.map(): SecurityAndPrivacyHistoryVisibility {
RoomHistoryVisibility.WorldReadable -> SecurityAndPrivacyHistoryVisibility.Anyone RoomHistoryVisibility.WorldReadable -> SecurityAndPrivacyHistoryVisibility.Anyone
RoomHistoryVisibility.Joined, RoomHistoryVisibility.Joined,
RoomHistoryVisibility.Invited -> SecurityAndPrivacyHistoryVisibility.SinceInvite RoomHistoryVisibility.Invited -> SecurityAndPrivacyHistoryVisibility.SinceInvite
RoomHistoryVisibility.Shared, RoomHistoryVisibility.Shared -> SecurityAndPrivacyHistoryVisibility.SinceSelection
// All other cases are not supported so we default to SinceSelection
is RoomHistoryVisibility.Custom, is RoomHistoryVisibility.Custom,
null -> SecurityAndPrivacyHistoryVisibility.SinceSelection null -> SecurityAndPrivacyHistoryVisibility.SinceSelection
} }

View file

@ -18,7 +18,7 @@ data class SecurityAndPrivacyState(
// the settings the user wants to apply. // the settings the user wants to apply.
val editedSettings: SecurityAndPrivacySettings, val editedSettings: SecurityAndPrivacySettings,
val homeserverName: String, val homeserverName: String,
val showEncryptionConfirmation: Boolean, val showEnableEncryptionConfirmation: Boolean,
val saveAction: AsyncAction<Unit>, val saveAction: AsyncAction<Unit>,
private val permissions: SecurityAndPrivacyPermissions, private val permissions: SecurityAndPrivacyPermissions,
val eventSink: (SecurityAndPrivacyEvents) -> Unit val eventSink: (SecurityAndPrivacyEvents) -> Unit

View file

@ -79,7 +79,7 @@ fun aSecurityAndPrivacyState(
editedSettings = editedSettings, editedSettings = editedSettings,
savedSettings = savedSettings, savedSettings = savedSettings,
homeserverName = homeserverName, homeserverName = homeserverName,
showEncryptionConfirmation = showEncryptionConfirmation, showEnableEncryptionConfirmation = showEncryptionConfirmation,
saveAction = saveAction, saveAction = saveAction,
permissions = permissions, permissions = permissions,
eventSink = eventSink eventSink = eventSink

View file

@ -100,9 +100,10 @@ fun SecurityAndPrivacyView(
if (state.showEncryptionSection) { if (state.showEncryptionSection) {
EncryptionSection( EncryptionSection(
isRoomEncrypted = state.editedSettings.isEncrypted, isRoomEncrypted = state.editedSettings.isEncrypted,
// encryption can't be disabled once enabled
canToggleEncryption = !state.savedSettings.isEncrypted, canToggleEncryption = !state.savedSettings.isEncrypted,
onToggleEncryption = { state.eventSink(SecurityAndPrivacyEvents.ToggleEncryptionState) }, onToggleEncryption = { state.eventSink(SecurityAndPrivacyEvents.ToggleEncryptionState) },
showConfirmation = state.showEncryptionConfirmation, showConfirmation = state.showEnableEncryptionConfirmation,
onDismissConfirmation = { state.eventSink(SecurityAndPrivacyEvents.CancelEnableEncryption) }, onDismissConfirmation = { state.eventSink(SecurityAndPrivacyEvents.CancelEnableEncryption) },
onConfirmEncryption = { state.eventSink(SecurityAndPrivacyEvents.ConfirmEnableEncryption) }, onConfirmEncryption = { state.eventSink(SecurityAndPrivacyEvents.ConfirmEnableEncryption) },
) )
@ -206,6 +207,7 @@ private fun RoomAccessSection(
trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.Anyone), trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.Anyone),
onClick = { onSelectOption(SecurityAndPrivacyRoomAccess.Anyone) }, onClick = { onSelectOption(SecurityAndPrivacyRoomAccess.Anyone) },
) )
// Show space member option, but disabled as we don't support this option for now.
if (saved == SecurityAndPrivacyRoomAccess.SpaceMember) { if (saved == SecurityAndPrivacyRoomAccess.SpaceMember) {
ListItem( ListItem(
headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_space_members_option_title)) }, headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_space_members_option_title)) },
@ -342,7 +344,6 @@ private fun HistoryVisibilitySection(
title = stringResource(R.string.screen_security_and_privacy_room_history_section_header), title = stringResource(R.string.screen_security_and_privacy_room_history_section_header),
modifier = modifier, modifier = modifier,
) { ) {
Spacer(Modifier.height(16.dp))
for (availableOption in availableOptions) { for (availableOption in availableOptions) {
val isSelected = availableOption == editedOption val isSelected = availableOption == editedOption
HistoryVisibilityItem( HistoryVisibilityItem(
@ -351,6 +352,7 @@ private fun HistoryVisibilitySection(
onSelectOption = onSelectOption, onSelectOption = onSelectOption,
) )
} }
// Also show the saved option if it's not in the available options, but disabled
if (savedOptions != null && !availableOptions.contains(savedOptions)) { if (savedOptions != null && !availableOptions.contains(savedOptions)) {
HistoryVisibilityItem( HistoryVisibilityItem(
option = savedOptions, option = savedOptions,

View file

@ -118,12 +118,10 @@ class EditRoomAddressPresenter @AssistedInject constructor(
// Otherwise, only update the alternative aliases and keep the current canonical alias // Otherwise, only update the alternative aliases and keep the current canonical alias
else -> { else -> {
val newAlternativeAliases = buildList { val newAlternativeAliases = buildList {
// New alias is added first, so we make sure we pick it first
add(newRoomAlias) add(newRoomAlias)
for (alias in room.alternativeAliases) { // Add all other aliases, except the one we just removed from the room directory
if (alias != savedAliasFromHomeserver) { addAll(room.alternativeAliases.filter { it != savedAliasFromHomeserver })
add(alias)
}
}
} }
room.updateCanonicalAlias(savedCanonicalAlias, newAlternativeAliases).getOrThrow() room.updateCanonicalAlias(savedCanonicalAlias, newAlternativeAliases).getOrThrow()
} }
@ -141,5 +139,5 @@ private fun MatrixRoom.firstAliasMatching(serverName: String): RoomAlias? {
if (canonicalAlias?.matchesServer(serverName) == true) { if (canonicalAlias?.matchesServer(serverName) == true) {
return canonicalAlias return canonicalAlias
} }
return alternativeAliases.firstOrNull { it.value.contains(serverName) } return alternativeAliases.firstOrNull { it.matchesServer(serverName) }
} }

View file

@ -37,7 +37,7 @@ class SecurityAndPrivacyPresenterTest {
with(awaitItem()) { with(awaitItem()) {
assertThat(editedSettings).isEqualTo(savedSettings) assertThat(editedSettings).isEqualTo(savedSettings)
assertThat(canBeSaved).isFalse() assertThat(canBeSaved).isFalse()
assertThat(showEncryptionConfirmation).isFalse() assertThat(showEnableEncryptionConfirmation).isFalse()
assertThat(saveAction).isEqualTo(AsyncAction.Uninitialized) assertThat(saveAction).isEqualTo(AsyncAction.Uninitialized)
assertThat(showRoomAccessSection).isFalse() assertThat(showRoomAccessSection).isFalse()
assertThat(showRoomVisibilitySections).isFalse() assertThat(showRoomVisibilitySections).isFalse()
@ -47,7 +47,7 @@ class SecurityAndPrivacyPresenterTest {
with(awaitItem()) { with(awaitItem()) {
assertThat(editedSettings).isEqualTo(savedSettings) assertThat(editedSettings).isEqualTo(savedSettings)
assertThat(canBeSaved).isFalse() assertThat(canBeSaved).isFalse()
assertThat(showEncryptionConfirmation).isFalse() assertThat(showEnableEncryptionConfirmation).isFalse()
assertThat(saveAction).isEqualTo(AsyncAction.Uninitialized) assertThat(saveAction).isEqualTo(AsyncAction.Uninitialized)
assertThat(showRoomAccessSection).isTrue() assertThat(showRoomAccessSection).isTrue()
assertThat(showRoomVisibilitySections).isFalse() assertThat(showRoomVisibilitySections).isFalse()
@ -138,21 +138,21 @@ class SecurityAndPrivacyPresenterTest {
eventSink(SecurityAndPrivacyEvents.ToggleEncryptionState) eventSink(SecurityAndPrivacyEvents.ToggleEncryptionState)
} }
with(awaitItem()) { with(awaitItem()) {
assertThat(showEncryptionConfirmation).isTrue() assertThat(showEnableEncryptionConfirmation).isTrue()
eventSink(SecurityAndPrivacyEvents.CancelEnableEncryption) eventSink(SecurityAndPrivacyEvents.CancelEnableEncryption)
} }
with(awaitItem()) { with(awaitItem()) {
assertThat(showEncryptionConfirmation).isFalse() assertThat(showEnableEncryptionConfirmation).isFalse()
eventSink(SecurityAndPrivacyEvents.ToggleEncryptionState) eventSink(SecurityAndPrivacyEvents.ToggleEncryptionState)
} }
with(awaitItem()) { with(awaitItem()) {
assertThat(showEncryptionConfirmation).isTrue() assertThat(showEnableEncryptionConfirmation).isTrue()
eventSink(SecurityAndPrivacyEvents.ConfirmEnableEncryption) eventSink(SecurityAndPrivacyEvents.ConfirmEnableEncryption)
} }
skipItems(1) skipItems(1)
with(awaitItem()) { with(awaitItem()) {
assertThat(editedSettings.isEncrypted).isTrue() assertThat(editedSettings.isEncrypted).isTrue()
assertThat(showEncryptionConfirmation).isFalse() assertThat(showEnableEncryptionConfirmation).isFalse()
assertThat(canBeSaved).isTrue() assertThat(canBeSaved).isTrue()
eventSink(SecurityAndPrivacyEvents.ToggleEncryptionState) eventSink(SecurityAndPrivacyEvents.ToggleEncryptionState)
} }

View file

@ -428,9 +428,7 @@ interface MatrixRoom : Closeable {
/** /**
* Returns the visibility for this room in the room directory. * Returns the visibility for this room in the room directory.
* * If the room is not published, the result will be [RoomVisibility.Private].
* [Public](`RoomVisibility::Public`) rooms are listed in the room
* directory and can be found using it.
*/ */
suspend fun getRoomVisibility(): Result<RoomVisibility> suspend fun getRoomVisibility(): Result<RoomVisibility>