feat(security&privacy) : use permissions and improve save
This commit is contained in:
parent
75fef6b325
commit
88fce64d2f
4 changed files with 150 additions and 113 deletions
|
|
@ -10,7 +10,6 @@ package io.element.android.features.roomdetails.impl.securityandprivacy
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.State
|
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -22,6 +21,7 @@ import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import io.element.android.features.roomdetails.impl.securityandprivacy.editroomaddress.matchesServer
|
import io.element.android.features.roomdetails.impl.securityandprivacy.editroomaddress.matchesServer
|
||||||
|
import io.element.android.features.roomdetails.impl.securityandprivacy.permissions.securityAndPrivacyPermissionsAsState
|
||||||
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 io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
|
|
@ -35,8 +35,10 @@ import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibilit
|
||||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
class SecurityAndPrivacyPresenter @AssistedInject constructor(
|
class SecurityAndPrivacyPresenter @AssistedInject constructor(
|
||||||
@Assisted private val navigator: SecurityAndPrivacyNavigator,
|
@Assisted private val navigator: SecurityAndPrivacyNavigator,
|
||||||
|
|
@ -51,17 +53,22 @@ class SecurityAndPrivacyPresenter @AssistedInject constructor(
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): SecurityAndPrivacyState {
|
override fun present(): SecurityAndPrivacyState {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
val saveAction = remember { mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized) }
|
||||||
val homeserverName = remember { matrixClient.userIdServerName() }
|
val homeserverName = remember { matrixClient.userIdServerName() }
|
||||||
val roomInfo by room.roomInfoFlow.collectAsState(initial = null)
|
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
|
||||||
val isVisibleInRoomDirectory by isRoomVisibleInRoomDirectory()
|
val roomInfo by room.roomInfoFlow.collectAsState(null)
|
||||||
|
|
||||||
|
val savedIsVisibleInRoomDirectory = remember { mutableStateOf<AsyncData<Boolean>>(AsyncData.Uninitialized) }
|
||||||
|
IsRoomVisibleInRoomDirectoryEffect(savedIsVisibleInRoomDirectory)
|
||||||
|
|
||||||
val savedSettings by remember {
|
val savedSettings by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
SecurityAndPrivacySettings(
|
SecurityAndPrivacySettings(
|
||||||
roomAccess = roomInfo?.joinRule.map(),
|
roomAccess = roomInfo?.joinRule.map(),
|
||||||
isEncrypted = room.isEncrypted,
|
isEncrypted = room.isEncrypted,
|
||||||
isVisibleInRoomDirectory = isVisibleInRoomDirectory,
|
isVisibleInRoomDirectory = savedIsVisibleInRoomDirectory.value,
|
||||||
historyVisibility = roomInfo?.historyVisibility?.map(),
|
historyVisibility = roomInfo?.historyVisibility.map(),
|
||||||
addressName = roomInfo?.firstDisplayableAlias(homeserverName)?.value
|
addressName = roomInfo?.firstDisplayableAlias(homeserverName)?.value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -73,15 +80,12 @@ class SecurityAndPrivacyPresenter @AssistedInject constructor(
|
||||||
var editedHistoryVisibility by remember(savedSettings.historyVisibility) {
|
var editedHistoryVisibility by remember(savedSettings.historyVisibility) {
|
||||||
mutableStateOf(savedSettings.historyVisibility)
|
mutableStateOf(savedSettings.historyVisibility)
|
||||||
}
|
}
|
||||||
var editedVisibleInRoomDirectory by remember(savedSettings.isVisibleInRoomDirectory) {
|
|
||||||
mutableStateOf(savedSettings.isVisibleInRoomDirectory)
|
|
||||||
}
|
|
||||||
var editedIsEncrypted by remember(savedSettings.isEncrypted) {
|
var editedIsEncrypted by remember(savedSettings.isEncrypted) {
|
||||||
mutableStateOf(savedSettings.isEncrypted)
|
mutableStateOf(savedSettings.isEncrypted)
|
||||||
}
|
}
|
||||||
|
var editedVisibleInRoomDirectory by remember(savedIsVisibleInRoomDirectory.value) {
|
||||||
var showEncryptionConfirmation by remember(savedSettings.isEncrypted) { mutableStateOf(false) }
|
mutableStateOf(savedIsVisibleInRoomDirectory.value)
|
||||||
|
}
|
||||||
val editedSettings = SecurityAndPrivacySettings(
|
val editedSettings = SecurityAndPrivacySettings(
|
||||||
roomAccess = editedRoomAccess,
|
roomAccess = editedRoomAccess,
|
||||||
isEncrypted = editedIsEncrypted,
|
isEncrypted = editedIsEncrypted,
|
||||||
|
|
@ -90,18 +94,24 @@ class SecurityAndPrivacyPresenter @AssistedInject constructor(
|
||||||
addressName = savedSettings.addressName,
|
addressName = savedSettings.addressName,
|
||||||
)
|
)
|
||||||
|
|
||||||
val saveAction = remember { mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized) }
|
var showEncryptionConfirmation by remember(savedSettings.isEncrypted) { mutableStateOf(false) }
|
||||||
|
val permissions by room.securityAndPrivacyPermissionsAsState(syncUpdateFlow.value)
|
||||||
|
|
||||||
fun handleEvents(event: SecurityAndPrivacyEvents) {
|
fun handleEvents(event: SecurityAndPrivacyEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
SecurityAndPrivacyEvents.Save -> {
|
SecurityAndPrivacyEvents.Save -> {
|
||||||
coroutineScope.save(saveAction, savedSettings, editedSettings)
|
coroutineScope.save(
|
||||||
|
saveAction = saveAction,
|
||||||
|
isVisibleInRoomDirectory = savedIsVisibleInRoomDirectory,
|
||||||
|
savedSettings = savedSettings,
|
||||||
|
editedSettings = editedSettings
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is SecurityAndPrivacyEvents.ChangeRoomAccess -> {
|
is SecurityAndPrivacyEvents.ChangeRoomAccess -> {
|
||||||
editedRoomAccess = event.roomAccess
|
editedRoomAccess = event.roomAccess
|
||||||
}
|
}
|
||||||
is SecurityAndPrivacyEvents.ToggleEncryptionState -> {
|
is SecurityAndPrivacyEvents.ToggleEncryptionState -> {
|
||||||
if (editedSettings.isEncrypted) {
|
if (editedIsEncrypted) {
|
||||||
editedIsEncrypted = false
|
editedIsEncrypted = false
|
||||||
} else {
|
} else {
|
||||||
showEncryptionConfirmation = true
|
showEncryptionConfirmation = true
|
||||||
|
|
@ -133,123 +143,137 @@ class SecurityAndPrivacyPresenter @AssistedInject constructor(
|
||||||
homeserverName = homeserverName,
|
homeserverName = homeserverName,
|
||||||
showEncryptionConfirmation = showEncryptionConfirmation,
|
showEncryptionConfirmation = showEncryptionConfirmation,
|
||||||
saveAction = saveAction.value,
|
saveAction = saveAction.value,
|
||||||
|
permissions = permissions,
|
||||||
eventSink = ::handleEvents
|
eventSink = ::handleEvents
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// If the history visibility is not available for the current access, use the fallback.
|
||||||
LaunchedEffect(state.availableHistoryVisibilities) {
|
LaunchedEffect(state.availableHistoryVisibilities) {
|
||||||
editedSettings.historyVisibility?.also {
|
if (editedSettings.historyVisibility !in state.availableHistoryVisibilities) {
|
||||||
if (it !in state.availableHistoryVisibilities) {
|
editedHistoryVisibility = editedSettings.historyVisibility.fallback()
|
||||||
editedHistoryVisibility = it.fallback()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun isRoomVisibleInRoomDirectory(): State<AsyncData<Boolean>> {
|
private fun IsRoomVisibleInRoomDirectoryEffect(isRoomVisible: MutableState<AsyncData<Boolean>>) {
|
||||||
val result = remember { mutableStateOf<AsyncData<Boolean>>(AsyncData.Uninitialized) }
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
result.runUpdatingState {
|
isRoomVisible.runUpdatingState {
|
||||||
room.getRoomVisibility().map { it == RoomVisibility.Public }
|
room.getRoomVisibility().map { it == RoomVisibility.Public }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.save(
|
private fun CoroutineScope.save(
|
||||||
saveAction: MutableState<AsyncAction<Unit>>,
|
saveAction: MutableState<AsyncAction<Unit>>,
|
||||||
|
isVisibleInRoomDirectory: MutableState<AsyncData<Boolean>>,
|
||||||
savedSettings: SecurityAndPrivacySettings,
|
savedSettings: SecurityAndPrivacySettings,
|
||||||
editedSettings: SecurityAndPrivacySettings,
|
editedSettings: SecurityAndPrivacySettings,
|
||||||
) = launch {
|
) = launch {
|
||||||
suspend {
|
suspend {
|
||||||
var somethingWentWrong = false
|
val enableEncryption = async {
|
||||||
if (editedSettings.isEncrypted && !savedSettings.isEncrypted) {
|
if (editedSettings.isEncrypted && !savedSettings.isEncrypted) {
|
||||||
room
|
room.enableEncryption()
|
||||||
.enableEncryption()
|
} else {
|
||||||
.onFailure {
|
Result.success(Unit)
|
||||||
Timber.d("Failed to enable encryption")
|
}
|
||||||
somethingWentWrong = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (editedSettings.historyVisibility != null && editedSettings.historyVisibility != savedSettings.historyVisibility) {
|
val updateHistoryVisibility = async {
|
||||||
room
|
if (editedSettings.historyVisibility != savedSettings.historyVisibility) {
|
||||||
.updateHistoryVisibility(editedSettings.historyVisibility.map())
|
room.updateHistoryVisibility(editedSettings.historyVisibility.map())
|
||||||
.onFailure {
|
} else {
|
||||||
Timber.d("Failed to update history visibility")
|
Result.success(Unit)
|
||||||
somethingWentWrong = true
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (editedSettings.roomAccess != savedSettings.roomAccess) {
|
val updateJoinRule = async {
|
||||||
room
|
if (editedSettings.roomAccess != savedSettings.roomAccess) {
|
||||||
.updateJoinRule(editedSettings.roomAccess.map())
|
room.updateJoinRule(editedSettings.roomAccess.map())
|
||||||
.onFailure {
|
} else {
|
||||||
Timber.d("Failed to update join rule")
|
Result.success(Unit)
|
||||||
somethingWentWrong = true
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
val updateRoomVisibility = async {
|
||||||
val editedIsVisibleInRoomDirectory = when (editedSettings.roomAccess) {
|
// When a user changes join rules to something other than knock or public,
|
||||||
SecurityAndPrivacyRoomAccess.AskToJoin,
|
// the room should be automatically made invisible (private) in the room directory.
|
||||||
SecurityAndPrivacyRoomAccess.Anyone -> editedSettings.isVisibleInRoomDirectory.dataOrNull()
|
val editedIsVisibleInRoomDirectory = when (editedSettings.roomAccess) {
|
||||||
else -> false
|
SecurityAndPrivacyRoomAccess.AskToJoin,
|
||||||
|
SecurityAndPrivacyRoomAccess.Anyone -> editedSettings.isVisibleInRoomDirectory.dataOrNull()
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
val savedIsVisibleInRoomDirectory = savedSettings.isVisibleInRoomDirectory.dataOrNull()
|
||||||
|
if (editedIsVisibleInRoomDirectory != null && editedIsVisibleInRoomDirectory != savedIsVisibleInRoomDirectory) {
|
||||||
|
val roomVisibility = if (editedIsVisibleInRoomDirectory) RoomVisibility.Public else RoomVisibility.Private
|
||||||
|
room
|
||||||
|
.updateRoomVisibility(roomVisibility)
|
||||||
|
.onSuccess {
|
||||||
|
isVisibleInRoomDirectory.value = AsyncData.Success(editedIsVisibleInRoomDirectory)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Result.success(Unit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val savedIsVisibleInRoomDirectory = savedSettings.isVisibleInRoomDirectory.dataOrNull()
|
val artificialDelay = async {
|
||||||
if (editedIsVisibleInRoomDirectory != null && editedIsVisibleInRoomDirectory != savedIsVisibleInRoomDirectory) {
|
// Artificial delay to make sure the user sees the loading state
|
||||||
val roomVisibility = if (editedIsVisibleInRoomDirectory) RoomVisibility.Public else RoomVisibility.Private
|
delay(500)
|
||||||
room
|
Result.success(Unit)
|
||||||
.updateRoomVisibility(roomVisibility)
|
|
||||||
.onFailure {
|
|
||||||
Timber.d("Failed to update room visibility")
|
|
||||||
somethingWentWrong = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (somethingWentWrong) {
|
val results = awaitAll(
|
||||||
error("")
|
enableEncryption,
|
||||||
|
updateHistoryVisibility,
|
||||||
|
updateJoinRule,
|
||||||
|
updateRoomVisibility,
|
||||||
|
artificialDelay
|
||||||
|
)
|
||||||
|
if (results.any { it.isFailure }) {
|
||||||
|
throw SecurityAndPrivacyFailures.SaveFailed
|
||||||
}
|
}
|
||||||
}.runCatchingUpdatingState(saveAction)
|
}.runCatchingUpdatingState(saveAction)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun JoinRule?.map(): SecurityAndPrivacyRoomAccess {
|
private fun JoinRule?.map(): SecurityAndPrivacyRoomAccess {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
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
|
||||||
is JoinRule.Custom,
|
is JoinRule.Custom,
|
||||||
JoinRule.Invite,
|
JoinRule.Invite,
|
||||||
JoinRule.Private,
|
JoinRule.Private,
|
||||||
null -> SecurityAndPrivacyRoomAccess.InviteOnly
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun MatrixRoomInfo.firstDisplayableAlias(serverName: String): RoomAlias? {
|
|
||||||
return aliases.firstOrNull { it.matchesServer(serverName) } ?: aliases.firstOrNull()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.WorldReadable -> SecurityAndPrivacyHistoryVisibility.Anyone
|
||||||
|
RoomHistoryVisibility.Joined,
|
||||||
|
RoomHistoryVisibility.Invited -> SecurityAndPrivacyHistoryVisibility.SinceInvite
|
||||||
|
RoomHistoryVisibility.Shared,
|
||||||
|
is RoomHistoryVisibility.Custom,
|
||||||
|
null -> SecurityAndPrivacyHistoryVisibility.SinceSelection
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SecurityAndPrivacyHistoryVisibility.map(): RoomHistoryVisibility {
|
||||||
|
return when (this) {
|
||||||
|
SecurityAndPrivacyHistoryVisibility.SinceSelection -> RoomHistoryVisibility.Shared
|
||||||
|
SecurityAndPrivacyHistoryVisibility.SinceInvite -> RoomHistoryVisibility.Invited
|
||||||
|
SecurityAndPrivacyHistoryVisibility.Anyone -> RoomHistoryVisibility.WorldReadable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MatrixRoomInfo.firstDisplayableAlias(serverName: String): RoomAlias? {
|
||||||
|
return aliases.firstOrNull { it.matchesServer(serverName) } ?: aliases.firstOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
package io.element.android.features.roomdetails.impl.securityandprivacy
|
package io.element.android.features.roomdetails.impl.securityandprivacy
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
@ -18,12 +19,12 @@ data class SecurityAndPrivacyState(
|
||||||
val homeserverName: String,
|
val homeserverName: String,
|
||||||
val showEncryptionConfirmation: Boolean,
|
val showEncryptionConfirmation: Boolean,
|
||||||
val saveAction: AsyncAction<Unit>,
|
val saveAction: AsyncAction<Unit>,
|
||||||
|
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 {
|
||||||
add(SecurityAndPrivacyHistoryVisibility.SinceSelection)
|
add(SecurityAndPrivacyHistoryVisibility.SinceSelection)
|
||||||
if (editedSettings.roomAccess == SecurityAndPrivacyRoomAccess.Anyone && !editedSettings.isEncrypted) {
|
if (editedSettings.roomAccess == SecurityAndPrivacyRoomAccess.Anyone && !editedSettings.isEncrypted) {
|
||||||
|
|
@ -32,16 +33,17 @@ data class SecurityAndPrivacyState(
|
||||||
add(SecurityAndPrivacyHistoryVisibility.SinceInvite)
|
add(SecurityAndPrivacyHistoryVisibility.SinceInvite)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val showRoomAccessSection: Boolean = true
|
|
||||||
val showRoomVisibilitySections = editedSettings.roomAccess != SecurityAndPrivacyRoomAccess.InviteOnly
|
val showRoomAccessSection = permissions.canChangeRoomAccess
|
||||||
val showHistoryVisibilitySection = editedSettings.historyVisibility != null
|
val showRoomVisibilitySections = permissions.canChangeRoomVisibility && editedSettings.roomAccess != SecurityAndPrivacyRoomAccess.InviteOnly
|
||||||
val showEncryptionSection = true
|
val showHistoryVisibilitySection = permissions.canChangeHistoryVisibility
|
||||||
|
val showEncryptionSection = permissions.canChangeEncryption
|
||||||
}
|
}
|
||||||
|
|
||||||
data class SecurityAndPrivacySettings(
|
data class SecurityAndPrivacySettings(
|
||||||
val roomAccess: SecurityAndPrivacyRoomAccess,
|
val roomAccess: SecurityAndPrivacyRoomAccess,
|
||||||
val isEncrypted: Boolean,
|
val isEncrypted: Boolean,
|
||||||
val historyVisibility: SecurityAndPrivacyHistoryVisibility?,
|
val historyVisibility: SecurityAndPrivacyHistoryVisibility,
|
||||||
val addressName: String?,
|
val addressName: String?,
|
||||||
val isVisibleInRoomDirectory: AsyncData<Boolean>
|
val isVisibleInRoomDirectory: AsyncData<Boolean>
|
||||||
)
|
)
|
||||||
|
|
@ -54,8 +56,8 @@ enum class SecurityAndPrivacyHistoryVisibility {
|
||||||
*/
|
*/
|
||||||
fun fallback(): SecurityAndPrivacyHistoryVisibility {
|
fun fallback(): SecurityAndPrivacyHistoryVisibility {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
SinceSelection -> SinceSelection
|
SinceSelection,
|
||||||
SinceInvite -> Anyone
|
SinceInvite -> SinceSelection
|
||||||
Anyone -> SinceInvite
|
Anyone -> SinceInvite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -64,3 +66,7 @@ enum class SecurityAndPrivacyHistoryVisibility {
|
||||||
enum class SecurityAndPrivacyRoomAccess {
|
enum class SecurityAndPrivacyRoomAccess {
|
||||||
InviteOnly, AskToJoin, Anyone, SpaceMember
|
InviteOnly, AskToJoin, Anyone, SpaceMember
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class SecurityAndPrivacyFailures : Exception() {
|
||||||
|
data object SaveFailed : SecurityAndPrivacyFailures()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package io.element.android.features.roomdetails.impl.securityandprivacy
|
package io.element.android.features.roomdetails.impl.securityandprivacy
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
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
|
||||||
|
|
||||||
|
|
@ -27,7 +28,7 @@ open class SecurityAndPrivacyStateProvider : PreviewParameterProvider<SecurityAn
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
aSecurityAndPrivacyState(
|
aSecurityAndPrivacyState(
|
||||||
editedSettings = aSecurityAndPrivacySettings(
|
savedSettings = aSecurityAndPrivacySettings(
|
||||||
roomAccess = SecurityAndPrivacyRoomAccess.SpaceMember
|
roomAccess = SecurityAndPrivacyRoomAccess.SpaceMember
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
@ -51,7 +52,7 @@ fun aSecurityAndPrivacySettings(
|
||||||
roomAccess: SecurityAndPrivacyRoomAccess = SecurityAndPrivacyRoomAccess.InviteOnly,
|
roomAccess: SecurityAndPrivacyRoomAccess = SecurityAndPrivacyRoomAccess.InviteOnly,
|
||||||
isEncrypted: Boolean = true,
|
isEncrypted: Boolean = true,
|
||||||
formattedAddress: String? = null,
|
formattedAddress: String? = null,
|
||||||
historyVisibility: SecurityAndPrivacyHistoryVisibility? = null,
|
historyVisibility: SecurityAndPrivacyHistoryVisibility = SecurityAndPrivacyHistoryVisibility.SinceSelection,
|
||||||
isVisibleInRoomDirectory: AsyncData<Boolean> = AsyncData.Uninitialized,
|
isVisibleInRoomDirectory: AsyncData<Boolean> = AsyncData.Uninitialized,
|
||||||
) = SecurityAndPrivacySettings(
|
) = SecurityAndPrivacySettings(
|
||||||
roomAccess = roomAccess,
|
roomAccess = roomAccess,
|
||||||
|
|
@ -67,6 +68,12 @@ fun aSecurityAndPrivacyState(
|
||||||
homeserverName: String = "myserver.xyz",
|
homeserverName: String = "myserver.xyz",
|
||||||
showEncryptionConfirmation: Boolean = false,
|
showEncryptionConfirmation: Boolean = false,
|
||||||
saveAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
saveAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||||
|
permissions: SecurityAndPrivacyPermissions = SecurityAndPrivacyPermissions(
|
||||||
|
canChangeRoomAccess = true,
|
||||||
|
canChangeHistoryVisibility = true,
|
||||||
|
canChangeEncryption = true,
|
||||||
|
canChangeRoomVisibility = true
|
||||||
|
),
|
||||||
eventSink: (SecurityAndPrivacyEvents) -> Unit = {}
|
eventSink: (SecurityAndPrivacyEvents) -> Unit = {}
|
||||||
) = SecurityAndPrivacyState(
|
) = SecurityAndPrivacyState(
|
||||||
editedSettings = editedSettings,
|
editedSettings = editedSettings,
|
||||||
|
|
@ -74,5 +81,6 @@ fun aSecurityAndPrivacyState(
|
||||||
homeserverName = homeserverName,
|
homeserverName = homeserverName,
|
||||||
showEncryptionConfirmation = showEncryptionConfirmation,
|
showEncryptionConfirmation = showEncryptionConfirmation,
|
||||||
saveAction = saveAction,
|
saveAction = saveAction,
|
||||||
|
permissions = permissions,
|
||||||
eventSink = eventSink
|
eventSink = eventSink
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,6 @@ private fun RoomAddressSection(
|
||||||
supportingContent = { Text(text = stringResource(CommonStrings.screen_security_and_privacy_room_address_section_footer)) },
|
supportingContent = { Text(text = stringResource(CommonStrings.screen_security_and_privacy_room_address_section_footer)) },
|
||||||
onClick = onRoomAddressClick,
|
onClick = onRoomAddressClick,
|
||||||
colors = ListItemDefaults.colors(trailingIconColor = ElementTheme.colors.iconAccentPrimary),
|
colors = ListItemDefaults.colors(trailingIconColor = ElementTheme.colors.iconAccentPrimary),
|
||||||
alwaysClickable = true
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ListItem(
|
ListItem(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue