From acb5cb609b257ae6dc380e9669f7177abc3d725a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 18 Sep 2025 17:27:53 +0200 Subject: [PATCH] Introduce BugReportFlowNode, and remove NavTarget.ViewLogs from RootFlowNode. --- appnav/build.gradle.kts | 1 - .../io/element/android/appnav/RootFlowNode.kt | 28 +----- .../api/bugreport/BugReportEntryPoint.kt | 3 +- features/rageshake/impl/build.gradle.kts | 1 + .../impl/bugreport/BugReportFlowNode.kt | 95 +++++++++++++++++++ .../rageshake/impl/bugreport/BugReportNode.kt | 16 ++-- .../bugreport/DefaultBugReportEntryPoint.kt | 2 +- .../DefaultBugReportEntryPointTest.kt | 18 ++-- 8 files changed, 121 insertions(+), 43 deletions(-) create mode 100644 features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportFlowNode.kt diff --git a/appnav/build.gradle.kts b/appnav/build.gradle.kts index ef97f92781..3ea6f9d1c9 100644 --- a/appnav/build.gradle.kts +++ b/appnav/build.gradle.kts @@ -43,7 +43,6 @@ dependencies { implementation(projects.features.ftue.api) implementation(projects.features.share.api) - implementation(projects.features.viewfolder.api) implementation(projects.services.apperror.impl) implementation(projects.services.appnavstate.api) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt index 818e670e46..c67496ef87 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -39,7 +39,6 @@ import io.element.android.features.login.api.accesscontrol.AccountProviderAccess import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint import io.element.android.features.rageshake.api.reporter.BugReporter import io.element.android.features.signedout.api.SignedOutEntryPoint -import io.element.android.features.viewfolder.api.ViewFolderEntryPoint import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode @@ -71,7 +70,6 @@ class RootFlowNode( private val matrixSessionCache: MatrixSessionCache, private val presenter: RootPresenter, private val bugReportEntryPoint: BugReportEntryPoint, - private val viewFolderEntryPoint: ViewFolderEntryPoint, private val signedOutEntryPoint: SignedOutEntryPoint, private val intentResolver: IntentResolver, private val oidcActionFlow: OidcActionFlow, @@ -200,11 +198,6 @@ class RootFlowNode( @Parcelize data object BugReport : NavTarget - - @Parcelize - data class ViewLogs( - val rootPath: String, - ) : NavTarget } override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { @@ -244,31 +237,12 @@ class RootFlowNode( NavTarget.SplashScreen -> splashNode(buildContext) NavTarget.BugReport -> { val callback = object : BugReportEntryPoint.Callback { - override fun onBugReportSent() { - backstack.pop() - } - - override fun onViewLogs(basePath: String) { - backstack.push(NavTarget.ViewLogs(rootPath = basePath)) - } - } - bugReportEntryPoint - .nodeBuilder(this, buildContext) - .callback(callback) - .build() - } - is NavTarget.ViewLogs -> { - val callback = object : ViewFolderEntryPoint.Callback { override fun onDone() { backstack.pop() } } - val params = ViewFolderEntryPoint.Params( - rootPath = navTarget.rootPath, - ) - viewFolderEntryPoint + bugReportEntryPoint .nodeBuilder(this, buildContext) - .params(params) .callback(callback) .build() } diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt index fbc7eb0dc8..0eb84b529b 100644 --- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt +++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/bugreport/BugReportEntryPoint.kt @@ -21,7 +21,6 @@ interface BugReportEntryPoint : FeatureEntryPoint { } interface Callback : Plugin { - fun onBugReportSent() - fun onViewLogs(basePath: String) + fun onDone() } } diff --git a/features/rageshake/impl/build.gradle.kts b/features/rageshake/impl/build.gradle.kts index 717da71e1f..b17d78f3aa 100644 --- a/features/rageshake/impl/build.gradle.kts +++ b/features/rageshake/impl/build.gradle.kts @@ -28,6 +28,7 @@ setupDependencyInjection() dependencies { implementation(projects.appconfig) implementation(projects.features.enterprise.api) + implementation(projects.features.viewfolder.api) implementation(projects.services.toolbox.api) implementation(projects.libraries.androidutils) implementation(projects.libraries.core) diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportFlowNode.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportFlowNode.kt new file mode 100644 index 0000000000..0dd4d4f518 --- /dev/null +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportFlowNode.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2025 New Vector 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.rageshake.impl.bugreport + +import android.os.Parcelable +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins +import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.pop +import com.bumble.appyx.navmodel.backstack.operation.push +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.Assisted +import dev.zacsweers.metro.Inject +import io.element.android.annotations.ContributesNode +import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint +import io.element.android.features.viewfolder.api.ViewFolderEntryPoint +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode +import io.element.android.libraries.architecture.createNode +import kotlinx.parcelize.Parcelize + +@ContributesNode(AppScope::class) +@Inject +class BugReportFlowNode( + @Assisted val buildContext: BuildContext, + @Assisted plugins: List, + private val viewFolderEntryPoint: ViewFolderEntryPoint, +) : BaseFlowNode( + backstack = BackStack( + initialElement = NavTarget.Root, + savedStateMap = buildContext.savedStateMap, + ), + buildContext = buildContext, + plugins = plugins +) { + private fun onDone() { + plugins().forEach { it.onDone() } + } + + sealed interface NavTarget : Parcelable { + @Parcelize + data object Root : NavTarget + + @Parcelize + data class ViewLogs( + val rootPath: String, + ) : NavTarget + } + + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { + return when (navTarget) { + NavTarget.Root -> { + val callback = object : BugReportNode.Callback { + override fun onDone() { + this@BugReportFlowNode.onDone() + } + + override fun onViewLogs(basePath: String) { + backstack.push(NavTarget.ViewLogs(rootPath = basePath)) + } + } + createNode(buildContext, listOf(callback)) + } + is NavTarget.ViewLogs -> { + val callback = object : ViewFolderEntryPoint.Callback { + override fun onDone() { + backstack.pop() + } + } + val params = ViewFolderEntryPoint.Params( + rootPath = navTarget.rootPath, + ) + viewFolderEntryPoint + .nodeBuilder(this, buildContext) + .params(params) + .callback(callback) + .build() + } + } + } + + @Composable + override fun View(modifier: Modifier) { + BackstackView() + } +} diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt index 3f507829e8..b6eb494589 100644 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportNode.kt @@ -18,7 +18,6 @@ import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.Inject import io.element.android.annotations.ContributesNode -import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint import io.element.android.features.rageshake.api.reporter.BugReporter import io.element.android.libraries.androidutils.system.toast import io.element.android.libraries.ui.strings.CommonStrings @@ -31,8 +30,17 @@ class BugReportNode( private val presenter: BugReportPresenter, private val bugReporter: BugReporter, ) : Node(buildContext, plugins = plugins) { + interface Callback : Plugin { + fun onDone() + fun onViewLogs(basePath: String) + } + private fun onViewLogs(basePath: String) { - plugins().forEach { it.onViewLogs(basePath) } + plugins().forEach { it.onViewLogs(basePath) } + } + + private fun onDone() { + plugins().forEach { it.onDone() } } @Composable @@ -54,8 +62,4 @@ class BugReportNode( } ) } - - private fun onDone() { - plugins().forEach { it.onBugReportSent() } - } } diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPoint.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPoint.kt index 0415d36e1d..6fa5772c17 100644 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPoint.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPoint.kt @@ -29,7 +29,7 @@ class DefaultBugReportEntryPoint : BugReportEntryPoint { } override fun build(): Node { - return parentNode.createNode(buildContext, plugins) + return parentNode.createNode(buildContext, plugins) } } } diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPointTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPointTest.kt index d76e8edb50..23d74f7247 100644 --- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPointTest.kt +++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/DefaultBugReportEntryPointTest.kt @@ -9,8 +9,11 @@ package io.element.android.features.rageshake.impl.bugreport import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.testing.junit4.util.MainDispatcherRule import com.google.common.truth.Truth.assertThat import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint +import io.element.android.features.viewfolder.api.ViewFolderEntryPoint import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.node.TestParentNode import kotlinx.coroutines.test.runTest @@ -21,25 +24,28 @@ class DefaultBugReportEntryPointTest { @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule() + @get:Rule + val mainDispatcherRule = MainDispatcherRule() + @Test fun `test node builder`() = runTest { val entryPoint = DefaultBugReportEntryPoint() val parentNode = TestParentNode.create { buildContext, plugins -> - BugReportNode( + BugReportFlowNode( buildContext = buildContext, plugins = plugins, - presenter = createPresenter(), - bugReporter = FakeBugReporter(), + viewFolderEntryPoint = object : ViewFolderEntryPoint { + override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError() + }, ) } val callback = object : BugReportEntryPoint.Callback { - override fun onBugReportSent() = lambdaError() - override fun onViewLogs(basePath: String) = lambdaError() + override fun onDone() = lambdaError() } val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null)) .callback(callback) .build() - assertThat(result).isInstanceOf(BugReportNode::class.java) + assertThat(result).isInstanceOf(BugReportFlowNode::class.java) assertThat(result.plugins).contains(callback) } }