Lock settings : branch the flow
This commit is contained in:
@@ -48,11 +48,11 @@ import io.element.android.features.createroom.api.CreateRoomEntryPoint
|
||||
import io.element.android.features.ftue.api.FtueEntryPoint
|
||||
import io.element.android.features.ftue.api.state.FtueState
|
||||
import io.element.android.features.invitelist.api.InviteListEntryPoint
|
||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
||||
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
|
||||
import io.element.android.features.lockscreen.api.LockScreenState
|
||||
import io.element.android.features.lockscreen.api.LockScreenStateService
|
||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
||||
import io.element.android.features.preferences.api.PreferencesEntryPoint
|
||||
import io.element.android.features.roomlist.api.RoomListEntryPoint
|
||||
import io.element.android.features.verifysession.api.VerifySessionEntryPoint
|
||||
@@ -218,7 +218,9 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||
createNode<LoggedInNode>(buildContext)
|
||||
}
|
||||
NavTarget.LockPermanent -> {
|
||||
lockScreenEntryPoint.createNode(this, buildContext)
|
||||
lockScreenEntryPoint.nodeBuilder(this, buildContext)
|
||||
.target(LockScreenEntryPoint.Target.Unlock)
|
||||
.build()
|
||||
}
|
||||
NavTarget.RoomList -> {
|
||||
val callback = object : RoomListEntryPoint.Callback {
|
||||
|
||||
@@ -16,6 +16,22 @@
|
||||
|
||||
package io.element.android.features.lockscreen.api
|
||||
|
||||
import io.element.android.libraries.architecture.SimpleFeatureEntryPoint
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import io.element.android.libraries.architecture.FeatureEntryPoint
|
||||
|
||||
interface LockScreenEntryPoint : SimpleFeatureEntryPoint
|
||||
interface LockScreenEntryPoint : FeatureEntryPoint {
|
||||
|
||||
fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
|
||||
|
||||
interface NodeBuilder {
|
||||
fun target(target: Target): NodeBuilder
|
||||
fun build(): Node
|
||||
}
|
||||
|
||||
enum class Target {
|
||||
Settings,
|
||||
Setup,
|
||||
Unlock
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,26 @@ import javax.inject.Inject
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultLockScreenEntryPoint @Inject constructor() : LockScreenEntryPoint {
|
||||
|
||||
override fun createNode(parentNode: Node, buildContext: BuildContext): Node {
|
||||
return parentNode.createNode<LockScreenFlowNode>(buildContext)
|
||||
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): LockScreenEntryPoint.NodeBuilder {
|
||||
|
||||
var innerTarget: LockScreenEntryPoint.Target = LockScreenEntryPoint.Target.Unlock
|
||||
|
||||
return object : LockScreenEntryPoint.NodeBuilder {
|
||||
override fun target(target: LockScreenEntryPoint.Target): LockScreenEntryPoint.NodeBuilder {
|
||||
innerTarget = target
|
||||
return this
|
||||
}
|
||||
|
||||
override fun build(): Node {
|
||||
val inputs = LockScreenFlowNode.Inputs(
|
||||
when (innerTarget) {
|
||||
LockScreenEntryPoint.Target.Unlock -> LockScreenFlowNode.NavTarget.Unlock
|
||||
LockScreenEntryPoint.Target.Setup -> LockScreenFlowNode.NavTarget.Setup
|
||||
LockScreenEntryPoint.Target.Settings -> LockScreenFlowNode.NavTarget.Settings
|
||||
}
|
||||
)
|
||||
return parentNode.createNode<LockScreenFlowNode>(buildContext, listOf(inputs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,11 @@ import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.features.lockscreen.impl.settings.LockScreenSettingsNode
|
||||
import io.element.android.features.lockscreen.impl.setup.SetupPinNode
|
||||
import io.element.android.features.lockscreen.impl.unlock.PinUnlockNode
|
||||
import io.element.android.libraries.architecture.BackstackNode
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.di.AppScope
|
||||
@@ -41,19 +43,26 @@ class LockScreenFlowNode @AssistedInject constructor(
|
||||
@Assisted plugins: List<Plugin>,
|
||||
) : BackstackNode<LockScreenFlowNode.NavTarget>(
|
||||
backstack = BackStack(
|
||||
initialElement = NavTarget.Unlock,
|
||||
initialElement = plugins.filterIsInstance(Inputs::class.java).first().initialNavTarget,
|
||||
savedStateMap = buildContext.savedStateMap,
|
||||
),
|
||||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
) {
|
||||
|
||||
data class Inputs(
|
||||
val initialNavTarget: NavTarget = NavTarget.Unlock,
|
||||
) : NodeInputs
|
||||
|
||||
sealed interface NavTarget : Parcelable {
|
||||
@Parcelize
|
||||
data object Unlock : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data object Setup : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data object Settings : NavTarget
|
||||
}
|
||||
|
||||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||
@@ -64,6 +73,9 @@ class LockScreenFlowNode @AssistedInject constructor(
|
||||
NavTarget.Setup -> {
|
||||
createNode<SetupPinNode>(buildContext)
|
||||
}
|
||||
NavTarget.Settings -> {
|
||||
createNode<LockScreenSettingsNode>(buildContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import io.element.android.appconfig.LockScreenConfig
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -29,9 +30,6 @@ class LockScreenSettingsPresenter @Inject constructor() : Presenter<LockScreenSe
|
||||
@Composable
|
||||
override fun present(): LockScreenSettingsState {
|
||||
|
||||
var isLockMandatory by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
var isBiometricEnabled by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
@@ -50,7 +48,7 @@ class LockScreenSettingsPresenter @Inject constructor() : Presenter<LockScreenSe
|
||||
}
|
||||
|
||||
return LockScreenSettingsState(
|
||||
isLockMandatory = isLockMandatory,
|
||||
isPinMandatory = LockScreenConfig.IS_PIN_MANDATORY,
|
||||
isBiometricEnabled = isBiometricEnabled,
|
||||
showRemovePinConfirmation = showRemovePinConfirmation,
|
||||
eventSink = ::handleEvents
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package io.element.android.features.lockscreen.impl.settings
|
||||
|
||||
data class LockScreenSettingsState(
|
||||
val isLockMandatory: Boolean,
|
||||
val isPinMandatory: Boolean,
|
||||
val isBiometricEnabled: Boolean,
|
||||
val showRemovePinConfirmation: Boolean,
|
||||
val eventSink: (LockScreenSettingsEvents) -> Unit
|
||||
|
||||
@@ -32,7 +32,7 @@ fun aLockScreenSettingsState(
|
||||
isBiometricEnabled: Boolean = false,
|
||||
showRemovePinConfirmation: Boolean = false,
|
||||
) = LockScreenSettingsState(
|
||||
isLockMandatory = isLockMandatory,
|
||||
isPinMandatory = isLockMandatory,
|
||||
isBiometricEnabled = isBiometricEnabled,
|
||||
showRemovePinConfirmation = showRemovePinConfirmation,
|
||||
eventSink = {}
|
||||
|
||||
@@ -48,7 +48,7 @@ fun LockScreenSettingsView(
|
||||
}
|
||||
)
|
||||
PreferenceDivider()
|
||||
if (!state.isLockMandatory) {
|
||||
if (!state.isPinMandatory) {
|
||||
PreferenceText(
|
||||
title = stringResource(id = R.string.screen_app_lock_settings_remove_pin),
|
||||
tintColor = ElementTheme.colors.textCriticalPrimary,
|
||||
|
||||
@@ -50,6 +50,7 @@ dependencies {
|
||||
implementation(projects.libraries.mediaupload.api)
|
||||
implementation(projects.libraries.permissions.api)
|
||||
implementation(projects.features.rageshake.api)
|
||||
implementation(projects.features.lockscreen.api)
|
||||
implementation(projects.features.analytics.api)
|
||||
implementation(projects.features.ftue.api)
|
||||
implementation(projects.features.logout.api)
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.bumble.appyx.navmodel.backstack.operation.push
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
|
||||
import io.element.android.features.preferences.api.PreferencesEntryPoint
|
||||
import io.element.android.features.preferences.impl.about.AboutNode
|
||||
import io.element.android.features.preferences.impl.advanced.AdvancedSettingsNode
|
||||
@@ -50,6 +51,7 @@ import kotlinx.parcelize.Parcelize
|
||||
class PreferencesFlowNode @AssistedInject constructor(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val lockScreenEntryPoint: LockScreenEntryPoint,
|
||||
) : BackstackNode<PreferencesFlowNode.NavTarget>(
|
||||
backstack = BackStack(
|
||||
initialElement = NavTarget.Root,
|
||||
@@ -81,6 +83,9 @@ class PreferencesFlowNode @AssistedInject constructor(
|
||||
@Parcelize
|
||||
data object NotificationSettings : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data object LockScreenSettings : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data class EditDefaultNotificationSetting(val isOneToOne: Boolean) : NavTarget
|
||||
|
||||
@@ -116,6 +121,10 @@ class PreferencesFlowNode @AssistedInject constructor(
|
||||
backstack.push(NavTarget.NotificationSettings)
|
||||
}
|
||||
|
||||
override fun onOpenLockScreenSettings() {
|
||||
backstack.push(NavTarget.LockScreenSettings)
|
||||
}
|
||||
|
||||
override fun onOpenAdvancedSettings() {
|
||||
backstack.push(NavTarget.AdvancedSettings)
|
||||
}
|
||||
@@ -162,6 +171,11 @@ class PreferencesFlowNode @AssistedInject constructor(
|
||||
val inputs = EditUserProfileNode.Inputs(navTarget.matrixUser)
|
||||
createNode<EditUserProfileNode>(buildContext, listOf(inputs))
|
||||
}
|
||||
NavTarget.LockScreenSettings -> {
|
||||
lockScreenEntryPoint.nodeBuilder(this, buildContext)
|
||||
.target(LockScreenEntryPoint.Target.Settings)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ class PreferencesRootNode @AssistedInject constructor(
|
||||
fun onOpenAbout()
|
||||
fun onOpenDeveloperSettings()
|
||||
fun onOpenNotificationSettings()
|
||||
fun onOpenLockScreenSettings()
|
||||
fun onOpenAdvancedSettings()
|
||||
fun onOpenUserProfile(matrixUser: MatrixUser)
|
||||
}
|
||||
@@ -93,6 +94,10 @@ class PreferencesRootNode @AssistedInject constructor(
|
||||
plugins<Callback>().forEach { it.onOpenNotificationSettings() }
|
||||
}
|
||||
|
||||
private fun onOpenLockScreenSettings() {
|
||||
plugins<Callback>().forEach { it.onOpenLockScreenSettings() }
|
||||
}
|
||||
|
||||
private fun onOpenUserProfile(matrixUser: MatrixUser) {
|
||||
plugins<Callback>().forEach { it.onOpenUserProfile(matrixUser) }
|
||||
}
|
||||
@@ -115,6 +120,7 @@ class PreferencesRootNode @AssistedInject constructor(
|
||||
onSuccessLogout = { onSuccessLogout(activity, it) },
|
||||
onManageAccountClicked = { onManageAccountClicked(activity, it, isDark) },
|
||||
onOpenNotificationSettings = this::onOpenNotificationSettings,
|
||||
onOpenLockScreenSettings = this::onOpenLockScreenSettings,
|
||||
onOpenUserProfile = this::onOpenUserProfile,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -68,6 +68,10 @@ class PreferencesRootPresenter @Inject constructor(
|
||||
LaunchedEffect(Unit) {
|
||||
showNotificationSettings.value = featureFlagService.isFeatureEnabled(FeatureFlags.NotificationSettings)
|
||||
}
|
||||
val showLockScreenSettings = remember { mutableStateOf(false) }
|
||||
LaunchedEffect(Unit) {
|
||||
showLockScreenSettings.value = featureFlagService.isFeatureEnabled(FeatureFlags.PinUnlock)
|
||||
}
|
||||
|
||||
// We should display the 'complete verification' option if the current session can be verified
|
||||
val showCompleteVerification by sessionVerificationService.canVerifySessionFlow.collectAsState(false)
|
||||
@@ -95,6 +99,7 @@ class PreferencesRootPresenter @Inject constructor(
|
||||
showAnalyticsSettings = hasAnalyticsProviders,
|
||||
showDeveloperSettings = showDeveloperSettings,
|
||||
showNotificationSettings = showNotificationSettings.value,
|
||||
showLockScreenSettings = showLockScreenSettings.value,
|
||||
snackbarMessage = snackbarMessage,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ data class PreferencesRootState(
|
||||
val devicesManagementUrl: String?,
|
||||
val showAnalyticsSettings: Boolean,
|
||||
val showDeveloperSettings: Boolean,
|
||||
val showLockScreenSettings: Boolean,
|
||||
val showNotificationSettings: Boolean,
|
||||
val snackbarMessage: SnackbarMessage?,
|
||||
)
|
||||
|
||||
@@ -30,5 +30,6 @@ fun aPreferencesRootState() = PreferencesRootState(
|
||||
showAnalyticsSettings = true,
|
||||
showDeveloperSettings = true,
|
||||
showNotificationSettings = true,
|
||||
showLockScreenSettings = true,
|
||||
snackbarMessage = SnackbarMessage(CommonStrings.common_verification_complete),
|
||||
)
|
||||
|
||||
@@ -20,6 +20,7 @@ import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Lock
|
||||
import androidx.compose.material.icons.outlined.InsertChart
|
||||
import androidx.compose.material.icons.outlined.VerifiedUser
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -53,6 +54,7 @@ fun PreferencesRootView(
|
||||
onManageAccountClicked: (url: String) -> Unit,
|
||||
onOpenAnalytics: () -> Unit,
|
||||
onOpenRageShake: () -> Unit,
|
||||
onOpenLockScreenSettings: ()->Unit,
|
||||
onOpenAbout: () -> Unit,
|
||||
onOpenDeveloperSettings: () -> Unit,
|
||||
onOpenAdvancedSettings: () -> Unit,
|
||||
@@ -116,6 +118,13 @@ fun PreferencesRootView(
|
||||
iconResourceId = CommonDrawables.ic_compound_info,
|
||||
onClick = onOpenAbout,
|
||||
)
|
||||
if (state.showLockScreenSettings) {
|
||||
PreferenceText(
|
||||
title = stringResource(id = CommonStrings.common_screen_lock),
|
||||
icon = Icons.Default.Lock,
|
||||
onClick = onOpenLockScreenSettings,
|
||||
)
|
||||
}
|
||||
HorizontalDivider()
|
||||
if (state.devicesManagementUrl != null) {
|
||||
PreferenceText(
|
||||
@@ -183,6 +192,7 @@ private fun ContentToPreview(matrixUser: MatrixUser) {
|
||||
onSuccessLogout = {},
|
||||
onManageAccountClicked = {},
|
||||
onOpenNotificationSettings = {},
|
||||
onOpenLockScreenSettings = {},
|
||||
onOpenUserProfile = {},
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user