feature(security&privacy): working SpaceMember selection
This commit is contained in:
parent
4e9d5c533f
commit
0d11c43a9a
9 changed files with 37 additions and 54 deletions
|
|
@ -66,7 +66,7 @@ class SecurityAndPrivacyFlowNode(
|
|||
data object EditRoomAddress : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data class ManageAuthorizedSpaces(val initialSelection: List<RoomId>) : NavTarget
|
||||
data object ManageAuthorizedSpaces: NavTarget
|
||||
}
|
||||
|
||||
private val callback: SecurityAndPrivacyEntryPoint.Callback = callback()
|
||||
|
|
@ -95,7 +95,7 @@ class SecurityAndPrivacyFlowNode(
|
|||
val authorizedSpacesData = securityAndPrivacyNode.getAuthorizedSpacesData()
|
||||
val selectedSpaces = manageAuthorizedSpacesNode.waitForCompletion(authorizedSpacesData)
|
||||
withContext(NonCancellable) {
|
||||
backstack.pop()
|
||||
navigator.closeManageAuthorizedSpaces()
|
||||
securityAndPrivacyNode.onAuthorizedSpacesSelected(selectedSpaces)
|
||||
}
|
||||
}
|
||||
|
|
@ -110,7 +110,7 @@ class SecurityAndPrivacyFlowNode(
|
|||
NavTarget.EditRoomAddress -> {
|
||||
createNode<EditRoomAddressNode>(buildContext, plugins = listOf(navigator))
|
||||
}
|
||||
is NavTarget.ManageAuthorizedSpaces -> {
|
||||
NavTarget.ManageAuthorizedSpaces -> {
|
||||
createNode<ManageAuthorizedSpacesNode>(buildContext, plugins = listOf(navigator))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,12 @@ import com.bumble.appyx.navmodel.backstack.BackStack
|
|||
import com.bumble.appyx.navmodel.backstack.operation.pop
|
||||
import com.bumble.appyx.navmodel.backstack.operation.push
|
||||
import io.element.android.features.securityandprivacy.api.SecurityAndPrivacyEntryPoint
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
interface SecurityAndPrivacyNavigator : Plugin {
|
||||
fun onDone()
|
||||
fun openEditRoomAddress()
|
||||
fun closeEditRoomAddress()
|
||||
fun openManageAuthorizedSpaces(initialSelection: List<RoomId>)
|
||||
fun openManageAuthorizedSpaces()
|
||||
fun closeManageAuthorizedSpaces()
|
||||
}
|
||||
|
||||
|
|
@ -39,8 +38,8 @@ class BackstackSecurityAndPrivacyNavigator(
|
|||
backStack.pop()
|
||||
}
|
||||
|
||||
override fun openManageAuthorizedSpaces(initialSelection: List<RoomId>) {
|
||||
backStack.push(SecurityAndPrivacyFlowNode.NavTarget.ManageAuthorizedSpaces(initialSelection))
|
||||
override fun openManageAuthorizedSpaces() {
|
||||
backStack.push(SecurityAndPrivacyFlowNode.NavTarget.ManageAuthorizedSpaces)
|
||||
}
|
||||
|
||||
override fun closeManageAuthorizedSpaces() {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import dev.zacsweers.metro.Assisted
|
|||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.features.securityandprivacy.impl.SecurityAndPrivacyNavigator
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.appyx.launchMolecule
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
|
@ -32,16 +31,10 @@ import kotlinx.coroutines.flow.first
|
|||
class ManageAuthorizedSpacesNode(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
presenterFactory: ManageAuthorizedSpacesPresenter.Factory,
|
||||
presenter: ManageAuthorizedSpacesPresenter,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
|
||||
data class Params(
|
||||
val initialSelection: List<RoomId>
|
||||
) : NodeInputs
|
||||
|
||||
private val navigator = plugins<SecurityAndPrivacyNavigator>().first()
|
||||
private val presenter = presenterFactory.create(navigator)
|
||||
|
||||
private val stateFlow = launchMolecule { presenter.present() }
|
||||
|
||||
suspend fun waitForCompletion(data: AuthorizedSpacesSelection): ImmutableList<RoomId> {
|
||||
|
|
@ -54,7 +47,7 @@ class ManageAuthorizedSpacesNode(
|
|||
val state by stateFlow.collectAsState()
|
||||
ManageAuthorizedSpacesView(
|
||||
state = state,
|
||||
onBackClick = ::navigateUp,
|
||||
onBackClick = { navigator.closeManageAuthorizedSpaces() },
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,57 +13,42 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.features.securityandprivacy.impl.SecurityAndPrivacyNavigator
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
@AssistedInject
|
||||
class ManageAuthorizedSpacesPresenter(
|
||||
@Assisted private val navigator: SecurityAndPrivacyNavigator,
|
||||
private val client: MatrixClient,
|
||||
private val room: JoinedRoom,
|
||||
) : Presenter<ManageAuthorizedSpacesState> {
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(navigator: SecurityAndPrivacyNavigator): ManageAuthorizedSpacesPresenter
|
||||
}
|
||||
@Inject
|
||||
class ManageAuthorizedSpacesPresenter() : Presenter<ManageAuthorizedSpacesState> {
|
||||
|
||||
@Composable
|
||||
override fun present(): ManageAuthorizedSpacesState {
|
||||
var currentSelection: ImmutableList<RoomId> by remember { mutableStateOf(persistentListOf()) }
|
||||
var spacesData by remember { mutableStateOf(AuthorizedSpacesSelection()) }
|
||||
var selectedIds: ImmutableList<RoomId> by remember { mutableStateOf(persistentListOf()) }
|
||||
var spacesSelection by remember { mutableStateOf(AuthorizedSpacesSelection()) }
|
||||
var isSelectionComplete by remember { mutableStateOf(false) }
|
||||
|
||||
fun handleEvent(event: ManageAuthorizedSpacesEvent) {
|
||||
when (event) {
|
||||
ManageAuthorizedSpacesEvent.Done -> {
|
||||
isSelectionComplete = true
|
||||
}
|
||||
ManageAuthorizedSpacesEvent.Done ->isSelectionComplete = true
|
||||
is ManageAuthorizedSpacesEvent.ToggleSpace -> {
|
||||
currentSelection = if (currentSelection.contains(event.roomId)) {
|
||||
currentSelection.minus(event.roomId).toPersistentList()
|
||||
selectedIds = if (selectedIds.contains(event.roomId)) {
|
||||
selectedIds.minus(event.roomId).toPersistentList()
|
||||
} else {
|
||||
currentSelection.plus(event.roomId).toPersistentList()
|
||||
selectedIds.plus(event.roomId).toPersistentList()
|
||||
}
|
||||
}
|
||||
is ManageAuthorizedSpacesEvent.SetData -> {
|
||||
spacesData = event.data
|
||||
currentSelection = event.data.initialSelectedIds
|
||||
spacesSelection = event.data
|
||||
selectedIds = event.data.initialSelectedIds
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ManageAuthorizedSpacesState(
|
||||
selection = spacesData,
|
||||
selectedIds = currentSelection,
|
||||
selection = spacesSelection,
|
||||
selectedIds = selectedIds,
|
||||
isSelectionComplete = isSelectionComplete,
|
||||
eventSink = ::handleEvent,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ data class ManageAuthorizedSpacesState(
|
|||
val selectedIds: ImmutableList<RoomId>,
|
||||
val isSelectionComplete: Boolean,
|
||||
val eventSink: (ManageAuthorizedSpacesEvent) -> Unit
|
||||
)
|
||||
) {
|
||||
val isDoneButtonEnabled = selectedIds.isNotEmpty()
|
||||
}
|
||||
|
||||
data class AuthorizedSpacesSelection(
|
||||
val joinedSpaces: ImmutableList<SpaceRoom> = persistentListOf(),
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ fun ManageAuthorizedSpacesView(
|
|||
onDoneClick = {
|
||||
state.eventSink(ManageAuthorizedSpacesEvent.Done)
|
||||
},
|
||||
isDoneButtonEnabled = state.isDoneButtonEnabled
|
||||
)
|
||||
}
|
||||
) { padding ->
|
||||
|
|
@ -160,6 +161,7 @@ private fun CheckableSpaceListItem(
|
|||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ManageAuthorizedSpacesTopBar(
|
||||
isDoneButtonEnabled: Boolean,
|
||||
onBackClick: () -> Unit,
|
||||
onDoneClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -170,6 +172,7 @@ private fun ManageAuthorizedSpacesTopBar(
|
|||
navigationIcon = { BackButton(onClick = onBackClick) },
|
||||
actions = {
|
||||
TextButton(
|
||||
enabled = isDoneButtonEnabled,
|
||||
text = stringResource(CommonStrings.action_done),
|
||||
onClick = onDoneClick,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class SecurityAndPrivacyNode(
|
|||
}
|
||||
|
||||
fun getAuthorizedSpacesData(): AuthorizedSpacesSelection{
|
||||
return stateFlow.value.getAuthorizedSpaceData()
|
||||
return stateFlow.value.getAuthorizedSpacesSelection()
|
||||
}
|
||||
|
||||
fun onAuthorizedSpacesSelected(selectedSpaces: ImmutableList<RoomId>) {
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ class SecurityAndPrivacyPresenter(
|
|||
address = savedSettings.address,
|
||||
)
|
||||
|
||||
val selectableJoinedSpaces by produceState(persistentSetOf()) {
|
||||
val selectableJoinedSpaces by produceState(initialValue = persistentSetOf(), key1 = savedSettings.roomAccess.spaceIds()) {
|
||||
val joinedParentSpaces = matrixClient
|
||||
.spaceService
|
||||
.joinedParents(room.roomId)
|
||||
|
|
@ -193,7 +193,7 @@ class SecurityAndPrivacyPresenter(
|
|||
saveAction.value = AsyncAction.Uninitialized
|
||||
}
|
||||
SecurityAndPrivacyEvent.ManageAuthorizedSpaces -> {
|
||||
navigator.openManageAuthorizedSpaces(editedSettings.roomAccess.spaceIds())
|
||||
navigator.openManageAuthorizedSpaces()
|
||||
}
|
||||
SecurityAndPrivacyEvent.SelectSpaceMemberAccess -> handleSpaceMemberAccessSelection(
|
||||
spaceSelectionMode = spaceSelectionMode,
|
||||
|
|
@ -254,9 +254,7 @@ class SecurityAndPrivacyPresenter(
|
|||
}
|
||||
when (spaceSelectionMode) {
|
||||
is SpaceSelectionMode.None -> Unit
|
||||
is SpaceSelectionMode.Multiple -> navigator.openManageAuthorizedSpaces(
|
||||
initialSelection = spaceIds ,
|
||||
)
|
||||
is SpaceSelectionMode.Multiple -> navigator.openManageAuthorizedSpaces()
|
||||
is SpaceSelectionMode.Single -> {
|
||||
val newRoomAccess = SecurityAndPrivacyRoomAccess.SpaceMember(
|
||||
spaceIds = persistentListOf(spaceSelectionMode.spaceId)
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ data class SecurityAndPrivacyState(
|
|||
val isSpaceMemberSelectable = isSpaceSettingsEnabled && spaceSelectionMode != SpaceSelectionMode.None
|
||||
|
||||
// Show SpaceMember option in two cases:
|
||||
// - the SpaceSettings FF is enabled
|
||||
// - SpaceMember is the current saved value
|
||||
// - SpaceMember option is selectable (ie. the FF is enabled and there is at least one space to select)
|
||||
val showSpaceMemberOption = savedSettings.roomAccess is SecurityAndPrivacyRoomAccess.SpaceMember || isSpaceMemberSelectable
|
||||
|
||||
val showManageSpaceAction = spaceSelectionMode is SpaceSelectionMode.Multiple && editedSettings.roomAccess is SecurityAndPrivacyRoomAccess.SpaceMember
|
||||
|
|
@ -94,13 +94,16 @@ data class SecurityAndPrivacyState(
|
|||
}
|
||||
}
|
||||
|
||||
fun getAuthorizedSpaceData(): AuthorizedSpacesSelection {
|
||||
fun getAuthorizedSpacesSelection(): AuthorizedSpacesSelection {
|
||||
return AuthorizedSpacesSelection(
|
||||
joinedSpaces = selectableJoinedSpaces.toImmutableList(),
|
||||
unknownSpaceIds = savedSettings.roomAccess.spaceIds().filter { spaceId ->
|
||||
selectableJoinedSpaces.none { it.roomId == spaceId }
|
||||
}.toImmutableList(),
|
||||
initialSelectedIds = editedSettings.roomAccess.spaceIds().toImmutableList()
|
||||
initialSelectedIds = when (editedSettings.roomAccess) {
|
||||
is SecurityAndPrivacyRoomAccess.SpaceMember -> editedSettings.roomAccess.spaceIds
|
||||
else -> savedSettings.roomAccess.spaceIds()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue