From 91863e252915081859d8e7fca19975c527d012ff Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 2 Mar 2023 17:55:26 +0100 Subject: [PATCH] [Architecture] introduce BackstackNode --- .../android/x/node/LoggedInFlowNode.kt | 33 ++++---------- .../android/x/node/NotLoggedInFlowNode.kt | 31 ++++--------- .../io/element/android/x/node/RoomFlowNode.kt | 26 ++++------- .../io/element/android/x/node/RootFlowNode.kt | 44 +++++-------------- features/login/build.gradle.kts | 2 +- .../features/login/impl/LoginFlowNode.kt | 25 ++++------- features/logout/build.gradle.kts | 2 +- features/messages/build.gradle.kts | 2 +- features/onboarding/build.gradle.kts | 2 +- features/preferences/build.gradle.kts | 2 +- .../preferences/impl/PreferencesFlowNode.kt | 26 ++++------- features/rageshake/build.gradle.kts | 2 +- features/roomlist/build.gradle.kts | 2 +- features/template/build.gradle.kts | 2 +- .../libraries/architecture/BackstackNode.kt | 38 ++++++++++++++++ 15 files changed, 103 insertions(+), 136 deletions(-) create mode 100644 libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BackstackNode.kt diff --git a/app/src/main/kotlin/io/element/android/x/node/LoggedInFlowNode.kt b/app/src/main/kotlin/io/element/android/x/node/LoggedInFlowNode.kt index a86daa5380..e627f0d448 100644 --- a/app/src/main/kotlin/io/element/android/x/node/LoggedInFlowNode.kt +++ b/app/src/main/kotlin/io/element/android/x/node/LoggedInFlowNode.kt @@ -27,7 +27,6 @@ import com.bumble.appyx.core.composable.Children import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.node.ParentNode import com.bumble.appyx.core.node.node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins @@ -38,6 +37,7 @@ import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.preferences.api.PreferencesEntryPoint import io.element.android.features.roomlist.api.RoomListEntryPoint +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.bindings @@ -54,35 +54,20 @@ import io.element.android.x.di.SessionComponent import kotlinx.parcelize.Parcelize @ContributesNode(AppScope::class) -class LoggedInFlowNode( - buildContext: BuildContext, - plugins: List, - private val backstack: BackStack, +class LoggedInFlowNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, private val roomListEntryPoint: RoomListEntryPoint, private val preferencesEntryPoint: PreferencesEntryPoint, -) : ParentNode( - navModel = backstack, +) : BackstackNode( + backstack = BackStack( + initialElement = NavTarget.RoomList, + savedStateMap = buildContext.savedStateMap, + ), buildContext = buildContext, plugins = plugins ), DaggerComponentOwner { - @AssistedInject - constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, - roomListEntryPoint: RoomListEntryPoint, - preferencesEntryPoint: PreferencesEntryPoint, - ) : this( - buildContext = buildContext, - plugins = plugins, - roomListEntryPoint = roomListEntryPoint, - preferencesEntryPoint = preferencesEntryPoint, - backstack = BackStack( - initialElement = NavTarget.RoomList, - savedStateMap = buildContext.savedStateMap, - ) - ) - interface Callback : Plugin { fun onOpenBugReport() } diff --git a/app/src/main/kotlin/io/element/android/x/node/NotLoggedInFlowNode.kt b/app/src/main/kotlin/io/element/android/x/node/NotLoggedInFlowNode.kt index 6a8b66c7f9..4b4c4be66c 100644 --- a/app/src/main/kotlin/io/element/android/x/node/NotLoggedInFlowNode.kt +++ b/app/src/main/kotlin/io/element/android/x/node/NotLoggedInFlowNode.kt @@ -23,7 +23,6 @@ import com.bumble.appyx.core.composable.Children import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.node.ParentNode import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.operation.push @@ -32,38 +31,26 @@ import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.login.api.LoginEntryPoint import io.element.android.features.onboarding.api.OnBoardingEntryPoint +import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.di.AppScope import kotlinx.parcelize.Parcelize import timber.log.Timber @ContributesNode(AppScope::class) -class NotLoggedInFlowNode private constructor( - buildContext: BuildContext, - plugins: List, +class NotLoggedInFlowNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, private val onBoardingEntryPoint: OnBoardingEntryPoint, private val loginEntryPoint: LoginEntryPoint, - private val backstack: BackStack, -) : ParentNode( - navModel = backstack, +) : BackstackNode( + backstack = BackStack( + initialElement = NavTarget.OnBoarding, + savedStateMap = buildContext.savedStateMap + ), buildContext = buildContext, plugins = plugins, ) { - @AssistedInject - constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, - onBoardingEntryPoint: OnBoardingEntryPoint, - loginEntryPoint: LoginEntryPoint, - ) - : this( - buildContext = buildContext, - plugins = plugins, - onBoardingEntryPoint = onBoardingEntryPoint, - loginEntryPoint = loginEntryPoint, - backstack = BackStack(initialElement = NavTarget.OnBoarding, savedStateMap = buildContext.savedStateMap), - ) - init { lifecycle.subscribe( onCreate = { Timber.v("OnCreate") }, diff --git a/app/src/main/kotlin/io/element/android/x/node/RoomFlowNode.kt b/app/src/main/kotlin/io/element/android/x/node/RoomFlowNode.kt index 4d5c120958..d00b2e2414 100644 --- a/app/src/main/kotlin/io/element/android/x/node/RoomFlowNode.kt +++ b/app/src/main/kotlin/io/element/android/x/node/RoomFlowNode.kt @@ -23,13 +23,13 @@ import com.bumble.appyx.core.composable.Children import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.node.ParentNode import com.bumble.appyx.core.plugin.Plugin 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.messages.MessagesNode +import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.bindings import io.element.android.libraries.architecture.createNode @@ -42,12 +42,14 @@ import kotlinx.parcelize.Parcelize import timber.log.Timber @ContributesNode(SessionScope::class) -class RoomFlowNode private constructor( - buildContext: BuildContext, - plugins: List, - private val backstack: BackStack, -) : ParentNode( - navModel = backstack, +class RoomFlowNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, +) : BackstackNode( + backstack = BackStack( + initialElement = NavTarget.Messages, + savedStateMap = buildContext.savedStateMap, + ), buildContext = buildContext, plugins = plugins, ), DaggerComponentOwner { @@ -56,16 +58,6 @@ class RoomFlowNode private constructor( val room: MatrixRoom, ) : NodeInputs - @AssistedInject - constructor(@Assisted buildContext: BuildContext, @Assisted plugins: List) : this( - buildContext = buildContext, - plugins = plugins, - backstack = BackStack( - initialElement = NavTarget.Messages, - savedStateMap = buildContext.savedStateMap, - ), - ) - private val inputs: Inputs by nodeInputs() override val daggerComponent: Any by lazy { diff --git a/app/src/main/kotlin/io/element/android/x/node/RootFlowNode.kt b/app/src/main/kotlin/io/element/android/x/node/RootFlowNode.kt index b35ddba736..6120833e15 100644 --- a/app/src/main/kotlin/io/element/android/x/node/RootFlowNode.kt +++ b/app/src/main/kotlin/io/element/android/x/node/RootFlowNode.kt @@ -27,7 +27,6 @@ import androidx.lifecycle.lifecycleScope import com.bumble.appyx.core.composable.Children import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.node.ParentNode import com.bumble.appyx.core.node.node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.navmodel.backstack.BackStack @@ -38,6 +37,8 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.rageshake.bugreport.BugReportEntryPoint +import io.element.android.features.rageshake.bugreport.BugReportNode +import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.nodeInputsProvider @@ -57,46 +58,25 @@ import kotlinx.parcelize.Parcelize import timber.log.Timber @ContributesNode(AppScope::class) -class RootFlowNode private constructor( - private val buildContext: BuildContext, - private val backstack: BackStack = BackStack( - initialElement = NavTarget.SplashScreen, - savedStateMap = buildContext.savedStateMap, - ), - private val appComponentOwner: DaggerComponentOwner, +class RootFlowNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + @ApplicationContext context: Context, private val authenticationService: MatrixAuthenticationService, private val matrixClientsHolder: MatrixClientsHolder, private val presenter: RootPresenter, private val bugReportEntryPoint: BugReportEntryPoint, ) : - ParentNode( - navModel = backstack, - buildContext = buildContext - ), - - DaggerComponentOwner by appComponentOwner { - - @AssistedInject - constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, - @ApplicationContext context: Context, - authenticationService: MatrixAuthenticationService, - matrixClientsHolder: MatrixClientsHolder, - presenter: RootPresenter, - bugReportEntryPoint: BugReportEntryPoint, - ) : this( - buildContext = buildContext, + BackstackNode( backstack = BackStack( initialElement = NavTarget.SplashScreen, savedStateMap = buildContext.savedStateMap, ), - appComponentOwner = context.applicationContext as DaggerComponentOwner, - authenticationService = authenticationService, - matrixClientsHolder = matrixClientsHolder, - presenter = presenter, - bugReportEntryPoint = bugReportEntryPoint, - ) + buildContext = buildContext, + plugins = plugins + ), + + DaggerComponentOwner by (context as DaggerComponentOwner) { override fun onBuilt() { super.onBuilt() diff --git a/features/login/build.gradle.kts b/features/login/build.gradle.kts index f4f8ca4844..29ddbec57d 100644 --- a/features/login/build.gradle.kts +++ b/features/login/build.gradle.kts @@ -18,8 +18,8 @@ @Suppress("DSL_SCOPE_VIOLATION") plugins { id("io.element.android-compose-library") - alias(libs.plugins.ksp) alias(libs.plugins.anvil) + alias(libs.plugins.ksp) id("kotlin-parcelize") } diff --git a/features/login/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt b/features/login/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt index a9061a2ef4..75735f698f 100644 --- a/features/login/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt +++ b/features/login/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt @@ -31,32 +31,25 @@ import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.login.impl.changeserver.ChangeServerNode import io.element.android.features.login.impl.root.LoginRootNode +import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.AppScope import kotlinx.parcelize.Parcelize @ContributesNode(AppScope::class) -class LoginFlowNode( - buildContext: BuildContext, - plugins: List, - private val backstack: BackStack, -) : ParentNode( - navModel = backstack, +class LoginFlowNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, +) : BackstackNode( + backstack = BackStack( + initialElement = NavTarget.Root, + savedStateMap = buildContext.savedStateMap, + ), buildContext = buildContext, plugins = plugins, ) { - @AssistedInject - constructor(@Assisted buildContext: BuildContext, @Assisted plugins: List) : this( - buildContext = buildContext, - plugins = plugins, - backstack = BackStack( - initialElement = NavTarget.Root, - savedStateMap = buildContext.savedStateMap, - ), - ) - sealed interface NavTarget : Parcelable { @Parcelize object Root : NavTarget diff --git a/features/logout/build.gradle.kts b/features/logout/build.gradle.kts index 2935965b80..16581ba58a 100644 --- a/features/logout/build.gradle.kts +++ b/features/logout/build.gradle.kts @@ -18,8 +18,8 @@ @Suppress("DSL_SCOPE_VIOLATION") plugins { id("io.element.android-compose-library") - alias(libs.plugins.ksp) alias(libs.plugins.anvil) + alias(libs.plugins.ksp) } android { diff --git a/features/messages/build.gradle.kts b/features/messages/build.gradle.kts index 1eb054d3d0..a6ecc71a80 100644 --- a/features/messages/build.gradle.kts +++ b/features/messages/build.gradle.kts @@ -18,8 +18,8 @@ @Suppress("DSL_SCOPE_VIOLATION") plugins { id("io.element.android-compose-library") - alias(libs.plugins.ksp) alias(libs.plugins.anvil) + alias(libs.plugins.ksp) } android { diff --git a/features/onboarding/build.gradle.kts b/features/onboarding/build.gradle.kts index d9636304aa..61e5371095 100644 --- a/features/onboarding/build.gradle.kts +++ b/features/onboarding/build.gradle.kts @@ -18,8 +18,8 @@ @Suppress("DSL_SCOPE_VIOLATION") plugins { id("io.element.android-compose-library") - alias(libs.plugins.ksp) alias(libs.plugins.anvil) + alias(libs.plugins.ksp) } android { diff --git a/features/preferences/build.gradle.kts b/features/preferences/build.gradle.kts index ba069e6333..fadd8a7e05 100644 --- a/features/preferences/build.gradle.kts +++ b/features/preferences/build.gradle.kts @@ -18,8 +18,8 @@ @Suppress("DSL_SCOPE_VIOLATION") plugins { id("io.element.android-compose-library") - alias(libs.plugins.ksp) alias(libs.plugins.anvil) + alias(libs.plugins.ksp) id("kotlin-parcelize") } diff --git a/features/preferences/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt b/features/preferences/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt index fa76f5b3e7..30b4d0a65c 100644 --- a/features/preferences/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt +++ b/features/preferences/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt @@ -22,7 +22,6 @@ import androidx.compose.ui.Modifier import com.bumble.appyx.core.composable.Children import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.node.ParentNode import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack @@ -31,32 +30,25 @@ import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.preferences.api.PreferencesEntryPoint import io.element.android.features.preferences.impl.root.PreferencesRootNode +import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope import kotlinx.parcelize.Parcelize @ContributesNode(SessionScope::class) -class PreferencesFlowNode( - buildContext: BuildContext, - plugins: List, - private val backstack: BackStack, -) : ParentNode( - navModel = backstack, +class PreferencesFlowNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, +) : BackstackNode( + backstack = BackStack( + initialElement = NavTarget.Root, + savedStateMap = buildContext.savedStateMap, + ), buildContext = buildContext, plugins = plugins ) { - @AssistedInject - constructor(@Assisted buildContext: BuildContext, @Assisted plugins: List) : this( - buildContext = buildContext, - plugins = plugins, - backstack = BackStack( - initialElement = NavTarget.Root, - savedStateMap = buildContext.savedStateMap, - ) - ) - sealed interface NavTarget : Parcelable { @Parcelize object Root : NavTarget diff --git a/features/rageshake/build.gradle.kts b/features/rageshake/build.gradle.kts index 45cc9cdd64..37fb8e1d3f 100644 --- a/features/rageshake/build.gradle.kts +++ b/features/rageshake/build.gradle.kts @@ -18,8 +18,8 @@ @Suppress("DSL_SCOPE_VIOLATION") plugins { id("io.element.android-compose-library") - alias(libs.plugins.ksp) alias(libs.plugins.anvil) + alias(libs.plugins.ksp) id("kotlin-parcelize") } diff --git a/features/roomlist/build.gradle.kts b/features/roomlist/build.gradle.kts index fe8112fb81..60f8c83b3c 100644 --- a/features/roomlist/build.gradle.kts +++ b/features/roomlist/build.gradle.kts @@ -18,8 +18,8 @@ @Suppress("DSL_SCOPE_VIOLATION") plugins { id("io.element.android-compose-library") - alias(libs.plugins.ksp) alias(libs.plugins.anvil) + alias(libs.plugins.ksp) } android { diff --git a/features/template/build.gradle.kts b/features/template/build.gradle.kts index 47cf8f490c..5dd2946f96 100644 --- a/features/template/build.gradle.kts +++ b/features/template/build.gradle.kts @@ -18,8 +18,8 @@ @Suppress("DSL_SCOPE_VIOLATION") plugins { id("io.element.android-compose-library") - alias(libs.plugins.ksp) alias(libs.plugins.anvil) + alias(libs.plugins.ksp) } android { diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BackstackNode.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BackstackNode.kt new file mode 100644 index 0000000000..c59a4a4483 --- /dev/null +++ b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BackstackNode.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.architecture + +import androidx.compose.runtime.Stable +import com.bumble.appyx.Appyx +import com.bumble.appyx.core.children.ChildEntry +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.ParentNode +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.navmodel.backstack.BackStack + +@Stable +abstract class BackstackNode( + val backstack: BackStack, + buildContext: BuildContext, + childKeepMode: ChildEntry.KeepMode = Appyx.defaultChildKeepMode, + plugins: List +) : ParentNode( + navModel = backstack, + buildContext = buildContext, + plugins = plugins, + childKeepMode = childKeepMode, +)