From 1f84bef601b6213005156462451a3388ad2bb5ec Mon Sep 17 00:00:00 2001 From: Jenna Vassar Date: Mon, 8 Jun 2026 15:35:30 -0700 Subject: [PATCH] Add SecureBackupSetupEntryPoint extension seam Introduces a FeatureEntryPoint for the recovery-key setup screen so enterprise builds can vend a richer setup node. The FOSS default builds the standard auto-generated-key node; SecureBackupFlowNode now resolves the Setup and Change targets through this seam instead of creating SecureBackupSetupNode directly. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../api/SecureBackupSetupEntryPoint.kt | 30 ++++++++++++++++ .../DefaultSecureBackupSetupEntryPoint.kt | 34 +++++++++++++++++++ .../securebackup/impl/SecureBackupFlowNode.kt | 17 ++++++---- .../impl/DefaultSecureBackupEntryPointTest.kt | 1 + 4 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 features/securebackup/api/src/main/kotlin/io/element/android/features/securebackup/api/SecureBackupSetupEntryPoint.kt create mode 100644 features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupSetupEntryPoint.kt diff --git a/features/securebackup/api/src/main/kotlin/io/element/android/features/securebackup/api/SecureBackupSetupEntryPoint.kt b/features/securebackup/api/src/main/kotlin/io/element/android/features/securebackup/api/SecureBackupSetupEntryPoint.kt new file mode 100644 index 0000000000..ca837d9cf8 --- /dev/null +++ b/features/securebackup/api/src/main/kotlin/io/element/android/features/securebackup/api/SecureBackupSetupEntryPoint.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.securebackup.api + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import io.element.android.libraries.architecture.FeatureEntryPoint +import io.element.android.libraries.architecture.NodeInputs + +/** + * Entry point for the recovery-key setup screen. + * + * The default (FOSS) implementation builds the standard auto-generated-key setup node. Enterprise + * builds replace this binding to vend a richer setup node (e.g. a homeserver-advertised custom + * recovery passphrase) while falling back to the standard node when no custom spec applies. + */ +interface SecureBackupSetupEntryPoint : FeatureEntryPoint { + data class Inputs(val isChangeRecoveryKeyUserStory: Boolean) : NodeInputs + + fun createNode( + parentNode: Node, + buildContext: BuildContext, + inputs: Inputs, + ): Node +} diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupSetupEntryPoint.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupSetupEntryPoint.kt new file mode 100644 index 0000000000..29465b1be1 --- /dev/null +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupSetupEntryPoint.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.securebackup.impl + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.features.securebackup.api.SecureBackupSetupEntryPoint +import io.element.android.features.securebackup.impl.setup.SecureBackupSetupNode +import io.element.android.libraries.architecture.createNode + +@ContributesBinding(AppScope::class) +class DefaultSecureBackupSetupEntryPoint : SecureBackupSetupEntryPoint { + override fun createNode( + parentNode: Node, + buildContext: BuildContext, + inputs: SecureBackupSetupEntryPoint.Inputs, + ): Node { + return parentNode.createNode( + buildContext = buildContext, + plugins = listOf( + SecureBackupSetupNode.Inputs( + isChangeRecoveryKeyUserStory = inputs.isChangeRecoveryKeyUserStory, + ) + ), + ) + } +} diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt index d9fd8a1785..035e47d1c7 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt @@ -21,11 +21,11 @@ import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode import io.element.android.features.securebackup.api.SecureBackupEntryPoint +import io.element.android.features.securebackup.api.SecureBackupSetupEntryPoint import io.element.android.features.securebackup.impl.disable.SecureBackupDisableNode import io.element.android.features.securebackup.impl.enter.SecureBackupEnterRecoveryKeyNode import io.element.android.features.securebackup.impl.reset.ResetIdentityFlowNode import io.element.android.features.securebackup.impl.root.SecureBackupRootNode -import io.element.android.features.securebackup.impl.setup.SecureBackupSetupNode import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.appyx.canPop @@ -39,6 +39,7 @@ import kotlinx.parcelize.Parcelize class SecureBackupFlowNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, + private val secureBackupSetupEntryPoint: SecureBackupSetupEntryPoint, ) : BaseFlowNode( backstack = BackStack( initialElement = when (plugins.filterIsInstance().first().initialElement) { @@ -97,16 +98,18 @@ class SecureBackupFlowNode( createNode(buildContext, listOf(callback)) } NavTarget.Setup -> { - val inputs = SecureBackupSetupNode.Inputs( - isChangeRecoveryKeyUserStory = false, + secureBackupSetupEntryPoint.createNode( + parentNode = this, + buildContext = buildContext, + inputs = SecureBackupSetupEntryPoint.Inputs(isChangeRecoveryKeyUserStory = false), ) - createNode(buildContext, listOf(inputs)) } NavTarget.Change -> { - val inputs = SecureBackupSetupNode.Inputs( - isChangeRecoveryKeyUserStory = true, + secureBackupSetupEntryPoint.createNode( + parentNode = this, + buildContext = buildContext, + inputs = SecureBackupSetupEntryPoint.Inputs(isChangeRecoveryKeyUserStory = true), ) - createNode(buildContext, listOf(inputs)) } NavTarget.Disable -> { createNode(buildContext) diff --git a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPointTest.kt b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPointTest.kt index 9e984f1ec0..6c2cb9984f 100644 --- a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPointTest.kt +++ b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPointTest.kt @@ -32,6 +32,7 @@ class DefaultSecureBackupEntryPointTest { SecureBackupFlowNode( buildContext = buildContext, plugins = plugins, + secureBackupSetupEntryPoint = DefaultSecureBackupSetupEntryPoint(), ) } val callback = object : SecureBackupEntryPoint.Callback {