feat(security&privacy) : clean code

This commit is contained in:
ganfra 2025-01-28 14:39:27 +01:00
parent 76bc87275c
commit 3c18c1f06a
17 changed files with 35 additions and 46 deletions

View file

@ -11,9 +11,9 @@ sealed interface SecurityAndPrivacyEvents {
data object EditRoomAddress : SecurityAndPrivacyEvents data object EditRoomAddress : SecurityAndPrivacyEvents
data object Save : SecurityAndPrivacyEvents data object Save : SecurityAndPrivacyEvents
data class ChangeRoomAccess(val roomAccess: SecurityAndPrivacyRoomAccess) : SecurityAndPrivacyEvents data class ChangeRoomAccess(val roomAccess: SecurityAndPrivacyRoomAccess) : SecurityAndPrivacyEvents
data object ToggleEncryptionState: SecurityAndPrivacyEvents data object ToggleEncryptionState : SecurityAndPrivacyEvents
data object CancelEnableEncryption : SecurityAndPrivacyEvents data object CancelEnableEncryption : SecurityAndPrivacyEvents
data object ConfirmEnableEncryption: SecurityAndPrivacyEvents data object ConfirmEnableEncryption : SecurityAndPrivacyEvents
data class ChangeHistoryVisibility(val historyVisibility: SecurityAndPrivacyHistoryVisibility) : SecurityAndPrivacyEvents data class ChangeHistoryVisibility(val historyVisibility: SecurityAndPrivacyHistoryVisibility) : SecurityAndPrivacyEvents
data object ToggleRoomVisibility : SecurityAndPrivacyEvents data object ToggleRoomVisibility : SecurityAndPrivacyEvents
data object DismissSaveError : SecurityAndPrivacyEvents data object DismissSaveError : SecurityAndPrivacyEvents

View file

@ -36,7 +36,6 @@ class SecurityAndPrivacyFlowNode @AssistedInject constructor(
buildContext = buildContext, buildContext = buildContext,
plugins = plugins, plugins = plugins,
) { ) {
sealed interface NavTarget : Parcelable { sealed interface NavTarget : Parcelable {
@Parcelize @Parcelize
data object SecurityAndPrivacy : NavTarget data object SecurityAndPrivacy : NavTarget

View file

@ -24,7 +24,6 @@ class SecurityAndPrivacyNode @AssistedInject constructor(
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
presenterFactory: SecurityAndPrivacyPresenter.Factory, presenterFactory: SecurityAndPrivacyPresenter.Factory,
) : Node(buildContext, plugins = plugins) { ) : Node(buildContext, plugins = plugins) {
private val navigator = plugins<SecurityAndPrivacyNavigator>().first() private val navigator = plugins<SecurityAndPrivacyNavigator>().first()
private val presenter = presenterFactory.create(navigator) private val presenter = presenterFactory.create(navigator)

View file

@ -60,7 +60,9 @@ class SecurityAndPrivacyPresenter @AssistedInject constructor(
val roomInfo by room.roomInfoFlow.collectAsState(null) val roomInfo by room.roomInfoFlow.collectAsState(null)
val savedIsVisibleInRoomDirectory = remember { mutableStateOf<AsyncData<Boolean>>(AsyncData.Uninitialized) } val savedIsVisibleInRoomDirectory = remember { mutableStateOf<AsyncData<Boolean>>(AsyncData.Uninitialized) }
IsRoomVisibleInRoomDirectoryEffect(savedIsVisibleInRoomDirectory) LaunchedEffect(Unit) {
isRoomVisibleInRoomDirectory(savedIsVisibleInRoomDirectory)
}
val savedSettings by remember { val savedSettings by remember {
derivedStateOf { derivedStateOf {
@ -159,12 +161,9 @@ class SecurityAndPrivacyPresenter @AssistedInject constructor(
return state return state
} }
@Composable private fun CoroutineScope.isRoomVisibleInRoomDirectory(isRoomVisible: MutableState<AsyncData<Boolean>>) = launch {
private fun IsRoomVisibleInRoomDirectoryEffect(isRoomVisible: MutableState<AsyncData<Boolean>>) { isRoomVisible.runUpdatingState {
LaunchedEffect(Unit) { room.getRoomVisibility().map { it == RoomVisibility.Public }
isRoomVisible.runUpdatingState {
room.getRoomVisibility().map { it == RoomVisibility.Public }
}
} }
} }
@ -264,7 +263,6 @@ private fun RoomHistoryVisibility?.map(): SecurityAndPrivacyHistoryVisibility {
RoomHistoryVisibility.Shared, RoomHistoryVisibility.Shared,
is RoomHistoryVisibility.Custom, is RoomHistoryVisibility.Custom,
null -> SecurityAndPrivacyHistoryVisibility.SinceSelection null -> SecurityAndPrivacyHistoryVisibility.SinceSelection
} }
} }
@ -279,4 +277,3 @@ private fun SecurityAndPrivacyHistoryVisibility.map(): RoomHistoryVisibility {
private fun MatrixRoomInfo.firstDisplayableAlias(serverName: String): RoomAlias? { private fun MatrixRoomInfo.firstDisplayableAlias(serverName: String): RoomAlias? {
return aliases.firstOrNull { it.matchesServer(serverName) } ?: aliases.firstOrNull() return aliases.firstOrNull { it.matchesServer(serverName) } ?: aliases.firstOrNull()
} }

View file

@ -10,6 +10,7 @@ package io.element.android.features.roomdetails.impl.securityandprivacy
import io.element.android.features.roomdetails.impl.securityandprivacy.permissions.SecurityAndPrivacyPermissions import io.element.android.features.roomdetails.impl.securityandprivacy.permissions.SecurityAndPrivacyPermissions
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import kotlinx.collections.immutable.toImmutableSet
data class SecurityAndPrivacyState( data class SecurityAndPrivacyState(
// the settings that are currently applied on the room. // the settings that are currently applied on the room.
@ -22,9 +23,6 @@ data class SecurityAndPrivacyState(
private val permissions: SecurityAndPrivacyPermissions, private val permissions: SecurityAndPrivacyPermissions,
val eventSink: (SecurityAndPrivacyEvents) -> Unit val eventSink: (SecurityAndPrivacyEvents) -> Unit
) { ) {
val canBeSaved = savedSettings != editedSettings val canBeSaved = savedSettings != editedSettings
val availableHistoryVisibilities = buildSet { val availableHistoryVisibilities = buildSet {
@ -34,15 +32,12 @@ data class SecurityAndPrivacyState(
} else { } else {
add(SecurityAndPrivacyHistoryVisibility.SinceInvite) add(SecurityAndPrivacyHistoryVisibility.SinceInvite)
} }
} }.toImmutableSet()
val showRoomAccessSection = permissions.canChangeRoomAccess val showRoomAccessSection = permissions.canChangeRoomAccess
val showRoomVisibilitySections = permissions.canChangeRoomVisibility && editedSettings.roomAccess != SecurityAndPrivacyRoomAccess.InviteOnly val showRoomVisibilitySections = permissions.canChangeRoomVisibility && editedSettings.roomAccess != SecurityAndPrivacyRoomAccess.InviteOnly
val showHistoryVisibilitySection = permissions.canChangeHistoryVisibility val showHistoryVisibilitySection = permissions.canChangeHistoryVisibility
val showEncryptionSection = permissions.canChangeEncryption val showEncryptionSection = permissions.canChangeEncryption
override fun toString(): String {
return "SecurityAndPrivacyState(savedSettings=$savedSettings, editedSettings=$editedSettings, homeserverName='$homeserverName', showEncryptionConfirmation=$showEncryptionConfirmation, saveAction=$saveAction, canBeSaved=$canBeSaved)"
}
} }
data class SecurityAndPrivacySettings( data class SecurityAndPrivacySettings(
@ -54,7 +49,9 @@ data class SecurityAndPrivacySettings(
) )
enum class SecurityAndPrivacyHistoryVisibility { enum class SecurityAndPrivacyHistoryVisibility {
SinceSelection, SinceInvite, Anyone; SinceSelection,
SinceInvite,
Anyone;
/** /**
* Returns the fallback visibility when the current visibility is not available. * Returns the fallback visibility when the current visibility is not available.
@ -69,7 +66,10 @@ enum class SecurityAndPrivacyHistoryVisibility {
} }
enum class SecurityAndPrivacyRoomAccess { enum class SecurityAndPrivacyRoomAccess {
InviteOnly, AskToJoin, Anyone, SpaceMember InviteOnly,
AskToJoin,
Anyone,
SpaceMember
} }
sealed class SecurityAndPrivacyFailures : Exception() { sealed class SecurityAndPrivacyFailures : Exception() {

View file

@ -49,6 +49,7 @@ 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.TextButton
import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.ImmutableSet
@Composable @Composable
fun SecurityAndPrivacyView( fun SecurityAndPrivacyView(
@ -81,7 +82,7 @@ fun SecurityAndPrivacyView(
modifier = Modifier.padding(top = 24.dp), modifier = Modifier.padding(top = 24.dp),
edited = state.editedSettings.roomAccess, edited = state.editedSettings.roomAccess,
saved = state.savedSettings.roomAccess, saved = state.savedSettings.roomAccess,
onSelected = { state.eventSink(SecurityAndPrivacyEvents.ChangeRoomAccess(it)) }, onSelectOption = { state.eventSink(SecurityAndPrivacyEvents.ChangeRoomAccess(it)) },
) )
} }
if (state.showRoomVisibilitySections) { if (state.showRoomVisibilitySections) {
@ -111,7 +112,7 @@ fun SecurityAndPrivacyView(
editedOption = state.editedSettings.historyVisibility, editedOption = state.editedSettings.historyVisibility,
savedOptions = state.savedSettings.historyVisibility, savedOptions = state.savedSettings.historyVisibility,
availableOptions = state.availableHistoryVisibilities, availableOptions = state.availableHistoryVisibilities,
onSelected = { state.eventSink(SecurityAndPrivacyEvents.ChangeHistoryVisibility(it)) }, onSelectOption = { state.eventSink(SecurityAndPrivacyEvents.ChangeHistoryVisibility(it)) },
) )
} }
} }
@ -180,7 +181,7 @@ private fun SecurityAndPrivacySection(
private fun RoomAccessSection( private fun RoomAccessSection(
edited: SecurityAndPrivacyRoomAccess, edited: SecurityAndPrivacyRoomAccess,
saved: SecurityAndPrivacyRoomAccess, saved: SecurityAndPrivacyRoomAccess,
onSelected: (SecurityAndPrivacyRoomAccess) -> Unit, onSelectOption: (SecurityAndPrivacyRoomAccess) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
SecurityAndPrivacySection( SecurityAndPrivacySection(
@ -191,19 +192,19 @@ private fun RoomAccessSection(
headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_invite_only_option_title)) }, headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_invite_only_option_title)) },
supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_invite_only_option_description)) }, supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_invite_only_option_description)) },
trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.InviteOnly), trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.InviteOnly),
onClick = { onSelected(SecurityAndPrivacyRoomAccess.InviteOnly) }, onClick = { onSelectOption(SecurityAndPrivacyRoomAccess.InviteOnly) },
) )
ListItem( ListItem(
headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_ask_to_join_option_title)) }, headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_ask_to_join_option_title)) },
supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_ask_to_join_option_description)) }, supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_ask_to_join_option_description)) },
trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.AskToJoin), trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.AskToJoin),
onClick = { onSelected(SecurityAndPrivacyRoomAccess.AskToJoin) }, onClick = { onSelectOption(SecurityAndPrivacyRoomAccess.AskToJoin) },
) )
ListItem( ListItem(
headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_anyone_option_title)) }, headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_anyone_option_title)) },
supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_anyone_option_description)) }, supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_anyone_option_description)) },
trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.Anyone), trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.Anyone),
onClick = { onSelected(SecurityAndPrivacyRoomAccess.Anyone) }, onClick = { onSelectOption(SecurityAndPrivacyRoomAccess.Anyone) },
) )
if (saved == SecurityAndPrivacyRoomAccess.SpaceMember) { if (saved == SecurityAndPrivacyRoomAccess.SpaceMember) {
ListItem( ListItem(
@ -333,8 +334,8 @@ private fun EncryptionSection(
private fun HistoryVisibilitySection( private fun HistoryVisibilitySection(
editedOption: SecurityAndPrivacyHistoryVisibility?, editedOption: SecurityAndPrivacyHistoryVisibility?,
savedOptions: SecurityAndPrivacyHistoryVisibility?, savedOptions: SecurityAndPrivacyHistoryVisibility?,
availableOptions: Set<SecurityAndPrivacyHistoryVisibility>, availableOptions: ImmutableSet<SecurityAndPrivacyHistoryVisibility>,
onSelected: (SecurityAndPrivacyHistoryVisibility) -> Unit, onSelectOption: (SecurityAndPrivacyHistoryVisibility) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
SecurityAndPrivacySection( SecurityAndPrivacySection(
@ -347,7 +348,7 @@ private fun HistoryVisibilitySection(
HistoryVisibilityItem( HistoryVisibilityItem(
option = availableOption, option = availableOption,
isSelected = isSelected, isSelected = isSelected,
onSelected = onSelected, onSelectOption = onSelectOption,
) )
} }
if (savedOptions != null && !availableOptions.contains(savedOptions)) { if (savedOptions != null && !availableOptions.contains(savedOptions)) {
@ -355,7 +356,7 @@ private fun HistoryVisibilitySection(
option = savedOptions, option = savedOptions,
isSelected = true, isSelected = true,
isEnabled = false, isEnabled = false,
onSelected = {}, onSelectOption = {},
) )
} }
} }
@ -365,7 +366,7 @@ private fun HistoryVisibilitySection(
private fun HistoryVisibilityItem( private fun HistoryVisibilityItem(
option: SecurityAndPrivacyHistoryVisibility, option: SecurityAndPrivacyHistoryVisibility,
isSelected: Boolean, isSelected: Boolean,
onSelected: (SecurityAndPrivacyHistoryVisibility) -> Unit, onSelectOption: (SecurityAndPrivacyHistoryVisibility) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
isEnabled: Boolean = true, isEnabled: Boolean = true,
) { ) {
@ -377,7 +378,7 @@ private fun HistoryVisibilityItem(
ListItem( ListItem(
headlineContent = { Text(text = headlineText) }, headlineContent = { Text(text = headlineText) },
trailingContent = ListItemContent.RadioButton(selected = isSelected, enabled = isEnabled), trailingContent = ListItemContent.RadioButton(selected = isSelected, enabled = isEnabled),
onClick = { onSelected(option) }, onClick = { onSelectOption(option) },
enabled = isEnabled, enabled = isEnabled,
modifier = modifier, modifier = modifier,
) )
@ -401,4 +402,3 @@ private fun ContentToPreview(state: SecurityAndPrivacyState) {
onBackClick = {}, onBackClick = {},
) )
} }

View file

@ -25,7 +25,6 @@ class EditRoomAddressNode @AssistedInject constructor(
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
presenterFactory: EditRoomAddressPresenter.Factory, presenterFactory: EditRoomAddressPresenter.Factory,
) : Node(buildContext, plugins = plugins) { ) : Node(buildContext, plugins = plugins) {
private val navigator = plugins<SecurityAndPrivacyNavigator>().first() private val navigator = plugins<SecurityAndPrivacyNavigator>().first()
private val presenter = presenterFactory.create(navigator) private val presenter = presenterFactory.create(navigator)

View file

@ -86,7 +86,6 @@ fun EditRoomAddressView(
onRetry = { state.eventSink(EditRoomAddressEvents.Save) }, onRetry = { state.eventSink(EditRoomAddressEvents.Save) },
onErrorDismiss = { state.eventSink(EditRoomAddressEvents.DismissError) }, onErrorDismiss = { state.eventSink(EditRoomAddressEvents.DismissError) },
) )
} }
} }

View file

@ -47,4 +47,3 @@ fun MatrixRoom.securityAndPrivacyPermissionsAsState(updateKey: Long): State<Secu
) )
} }
} }

View file

@ -30,7 +30,6 @@ import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
class SecurityAndPrivacyPresenterTest { class SecurityAndPrivacyPresenterTest {
@Test @Test
fun `present - initial states`() = runTest { fun `present - initial states`() = runTest {
val presenter = createSecurityAndPrivacyPresenter() val presenter = createSecurityAndPrivacyPresenter()

View file

@ -31,7 +31,6 @@ import org.junit.Test
import java.util.Optional import java.util.Optional
class EditRoomAddressPresenterTest { class EditRoomAddressPresenterTest {
@Test @Test
fun `present - initial state no address`() = runTest { fun `present - initial state no address`() = runTest {
val presenter = createEditRoomAddressPresenter() val presenter = createEditRoomAddressPresenter()

View file

@ -10,7 +10,6 @@ package io.element.android.features.roomdetails.securityandprivacy.editroomaddre
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.performTextInput
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
@ -104,8 +103,6 @@ class EditRoomAddressViewTest {
rule.clickOn(CommonStrings.action_retry) rule.clickOn(CommonStrings.action_retry)
recorder.assertSingle(EditRoomAddressEvents.Save) recorder.assertSingle(EditRoomAddressEvents.Save)
} }
} }
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setEditRoomAddressView( private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setEditRoomAddressView(

View file

@ -433,6 +433,7 @@ interface MatrixRoom : Closeable {
* directory and can be found using it. * directory and can be found using it.
*/ */
suspend fun getRoomVisibility(): Result<RoomVisibility> suspend fun getRoomVisibility(): Result<RoomVisibility>
/** /**
* Publish a new room alias for this room in the room directory. * Publish a new room alias for this room in the room directory.
* *
@ -442,6 +443,7 @@ interface MatrixRoom : Closeable {
* published. * published.
*/ */
suspend fun publishRoomAliasInRoomDirectory(roomAlias: RoomAlias): Result<Boolean> suspend fun publishRoomAliasInRoomDirectory(roomAlias: RoomAlias): Result<Boolean>
/** /**
* Remove an existing room alias for this room in the room directory. * Remove an existing room alias for this room in the room directory.
* *

View file

@ -104,6 +104,7 @@ import org.matrix.rustcomponents.sdk.KnockRequest as InnerKnockRequest
import org.matrix.rustcomponents.sdk.Room as InnerRoom import org.matrix.rustcomponents.sdk.Room as InnerRoom
import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline
@Suppress("LargeClass")
class RustMatrixRoom( class RustMatrixRoom(
override val sessionId: SessionId, override val sessionId: SessionId,
private val deviceId: DeviceId, private val deviceId: DeviceId,

View file

@ -34,8 +34,8 @@ import kotlinx.collections.immutable.toPersistentList
import org.junit.Test import org.junit.Test
import org.matrix.rustcomponents.sdk.Membership import org.matrix.rustcomponents.sdk.Membership
import org.matrix.rustcomponents.sdk.JoinRule as RustJoinRule import org.matrix.rustcomponents.sdk.JoinRule as RustJoinRule
import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode
import org.matrix.rustcomponents.sdk.RoomHistoryVisibility as RustRoomHistoryVisibility import org.matrix.rustcomponents.sdk.RoomHistoryVisibility as RustRoomHistoryVisibility
import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode
class MatrixRoomInfoMapperTest { class MatrixRoomInfoMapperTest {
@Test @Test

View file

@ -64,7 +64,7 @@ fun RoomAddressField(
@PreviewsDayNight @PreviewsDayNight
@Composable @Composable
fun RoomAddressFieldPreview() = ElementPreview { internal fun RoomAddressFieldPreview() = ElementPreview {
RoomAddressField( RoomAddressField(
address = "room", address = "room",
homeserverName = "element.io", homeserverName = "element.io",

View file

@ -117,5 +117,4 @@ object TestTags {
* *
*/ */
val roomAddressField = TestTag("room_address_field") val roomAddressField = TestTag("room_address_field")
} }