From fd03d6de8e9161131dae631f2b0ac98d2ad5ae3a Mon Sep 17 00:00:00 2001 From: andreykovalev Date: Tue, 16 Jul 2024 12:37:44 +0100 Subject: [PATCH 1/4] Update documentation structure --- .../{ => 2.x}/components/backstack.md | 0 .../{ => 2.x}/components/experimental.md | 0 documentation/{ => 2.x}/components/index.md | 0 .../{ => 2.x}/components/spotlight.md | 0 documentation/{ => 2.x}/faq.md | 0 documentation/{ => 2.x}/index_2.x.md | 4 +- .../{ => 2.x}/interactions/appyxcomponent.md | 0 .../{ => 2.x}/interactions/gestures.md | 0 documentation/{ => 2.x}/interactions/index.md | 0 documentation/{ => 2.x}/interactions/ksp.md | 0 .../{ => 2.x}/interactions/operations.md | 0 .../{ => 2.x}/interactions/transitionmodel.md | 0 .../interactions/ui-representation.md | 0 documentation/{ => 2.x}/interactions/usage.md | 0 documentation/2.x/migrationguide.md | 4 +- .../concepts/composable-navigation.md | 176 ++++---- .../concepts/explicit-navigation.md | 426 +++++++++--------- .../concepts/implicit-navigation.md | 0 .../concepts/model-driven-navigation.md | 0 .../navigation/features/childaware.md | 0 .../navigation/features/deep-linking.md | 0 .../navigation/features/lifecycle.md | 0 .../navigation/features/material3.md | 0 .../{ => 2.x}/navigation/features/plugins.md | 0 .../navigation/features/scoped-di.md | 0 .../surviving-configuration-changes.md | 0 documentation/{ => 2.x}/navigation/index.md | 0 .../integrations/compose-navigation.md | 0 .../navigation/integrations/di-frameworks.md | 0 .../{ => 2.x}/navigation/integrations/ribs.md | 0 .../{ => 2.x}/navigation/integrations/rx.md | 0 .../navigation/integrations/viewmodel.md | 0 .../{ => 2.x}/navigation/multiplatform.md | 0 .../{ => 2.x}/navigation/quick-start.md | 0 .../{ => 2.x}/navigation/sample-app.md | 0 .../{ => 2.x}/releases/2.0.0-alpha10.md | 0 documentation/{ => 2.x}/releases/2.0.0.md | 0 documentation/{ => 2.x}/releases/changelog.md | 0 documentation/{ => 2.x}/releases/downloads.md | 0 39 files changed, 305 insertions(+), 305 deletions(-) rename documentation/{ => 2.x}/components/backstack.md (100%) rename documentation/{ => 2.x}/components/experimental.md (100%) rename documentation/{ => 2.x}/components/index.md (100%) rename documentation/{ => 2.x}/components/spotlight.md (100%) rename documentation/{ => 2.x}/faq.md (100%) rename documentation/{ => 2.x}/index_2.x.md (97%) rename documentation/{ => 2.x}/interactions/appyxcomponent.md (100%) rename documentation/{ => 2.x}/interactions/gestures.md (100%) rename documentation/{ => 2.x}/interactions/index.md (100%) rename documentation/{ => 2.x}/interactions/ksp.md (100%) rename documentation/{ => 2.x}/interactions/operations.md (100%) rename documentation/{ => 2.x}/interactions/transitionmodel.md (100%) rename documentation/{ => 2.x}/interactions/ui-representation.md (100%) rename documentation/{ => 2.x}/interactions/usage.md (100%) rename documentation/{ => 2.x}/navigation/concepts/composable-navigation.md (97%) rename documentation/{ => 2.x}/navigation/concepts/explicit-navigation.md (96%) rename documentation/{ => 2.x}/navigation/concepts/implicit-navigation.md (100%) rename documentation/{ => 2.x}/navigation/concepts/model-driven-navigation.md (100%) rename documentation/{ => 2.x}/navigation/features/childaware.md (100%) rename documentation/{ => 2.x}/navigation/features/deep-linking.md (100%) rename documentation/{ => 2.x}/navigation/features/lifecycle.md (100%) rename documentation/{ => 2.x}/navigation/features/material3.md (100%) rename documentation/{ => 2.x}/navigation/features/plugins.md (100%) rename documentation/{ => 2.x}/navigation/features/scoped-di.md (100%) rename documentation/{ => 2.x}/navigation/features/surviving-configuration-changes.md (100%) rename documentation/{ => 2.x}/navigation/index.md (100%) rename documentation/{ => 2.x}/navigation/integrations/compose-navigation.md (100%) rename documentation/{ => 2.x}/navigation/integrations/di-frameworks.md (100%) rename documentation/{ => 2.x}/navigation/integrations/ribs.md (100%) rename documentation/{ => 2.x}/navigation/integrations/rx.md (100%) rename documentation/{ => 2.x}/navigation/integrations/viewmodel.md (100%) rename documentation/{ => 2.x}/navigation/multiplatform.md (100%) rename documentation/{ => 2.x}/navigation/quick-start.md (100%) rename documentation/{ => 2.x}/navigation/sample-app.md (100%) rename documentation/{ => 2.x}/releases/2.0.0-alpha10.md (100%) rename documentation/{ => 2.x}/releases/2.0.0.md (100%) rename documentation/{ => 2.x}/releases/changelog.md (100%) rename documentation/{ => 2.x}/releases/downloads.md (100%) diff --git a/documentation/components/backstack.md b/documentation/2.x/components/backstack.md similarity index 100% rename from documentation/components/backstack.md rename to documentation/2.x/components/backstack.md diff --git a/documentation/components/experimental.md b/documentation/2.x/components/experimental.md similarity index 100% rename from documentation/components/experimental.md rename to documentation/2.x/components/experimental.md diff --git a/documentation/components/index.md b/documentation/2.x/components/index.md similarity index 100% rename from documentation/components/index.md rename to documentation/2.x/components/index.md diff --git a/documentation/components/spotlight.md b/documentation/2.x/components/spotlight.md similarity index 100% rename from documentation/components/spotlight.md rename to documentation/2.x/components/spotlight.md diff --git a/documentation/faq.md b/documentation/2.x/faq.md similarity index 100% rename from documentation/faq.md rename to documentation/2.x/faq.md diff --git a/documentation/index_2.x.md b/documentation/2.x/index_2.x.md similarity index 97% rename from documentation/index_2.x.md rename to documentation/2.x/index_2.x.md index 51b9733fb..47a423dd2 100644 --- a/documentation/index_2.x.md +++ b/documentation/2.x/index_2.x.md @@ -119,12 +119,12 @@ Stacks, custom pagers, custom UI components – whether for navigation, or stand ## 2.x migration guide -If you used Appyx `1.x` before, you can find a [summary of differences](2.x/migrationguide.md) here. +If you used Appyx `1.x` before, you can find a [summary of differences](migrationguide.md) here. ## 1.x documentation This page is about Appyx `2.x` (alpha). -You can find `1.x` related documentation [here](1.x/index.md). +You can find `1.x` related documentation [here](../1.x/index.md). diff --git a/documentation/interactions/appyxcomponent.md b/documentation/2.x/interactions/appyxcomponent.md similarity index 100% rename from documentation/interactions/appyxcomponent.md rename to documentation/2.x/interactions/appyxcomponent.md diff --git a/documentation/interactions/gestures.md b/documentation/2.x/interactions/gestures.md similarity index 100% rename from documentation/interactions/gestures.md rename to documentation/2.x/interactions/gestures.md diff --git a/documentation/interactions/index.md b/documentation/2.x/interactions/index.md similarity index 100% rename from documentation/interactions/index.md rename to documentation/2.x/interactions/index.md diff --git a/documentation/interactions/ksp.md b/documentation/2.x/interactions/ksp.md similarity index 100% rename from documentation/interactions/ksp.md rename to documentation/2.x/interactions/ksp.md diff --git a/documentation/interactions/operations.md b/documentation/2.x/interactions/operations.md similarity index 100% rename from documentation/interactions/operations.md rename to documentation/2.x/interactions/operations.md diff --git a/documentation/interactions/transitionmodel.md b/documentation/2.x/interactions/transitionmodel.md similarity index 100% rename from documentation/interactions/transitionmodel.md rename to documentation/2.x/interactions/transitionmodel.md diff --git a/documentation/interactions/ui-representation.md b/documentation/2.x/interactions/ui-representation.md similarity index 100% rename from documentation/interactions/ui-representation.md rename to documentation/2.x/interactions/ui-representation.md diff --git a/documentation/interactions/usage.md b/documentation/2.x/interactions/usage.md similarity index 100% rename from documentation/interactions/usage.md rename to documentation/2.x/interactions/usage.md diff --git a/documentation/2.x/migrationguide.md b/documentation/2.x/migrationguide.md index 3501b1a5c..90b99c728 100644 --- a/documentation/2.x/migrationguide.md +++ b/documentation/2.x/migrationguide.md @@ -21,7 +21,7 @@ The library is packaged as multiple artifacts. - Android library - Compose Multiplatform. -Check also [Multiplatform](../navigation/multiplatform.md) documentation and the `:demos:appyx-navigation` module for code examples. +Check also [Multiplatform](navigation/multiplatform.md) documentation and the `:demos:appyx-navigation` module for code examples. #### :appyx-interactions @@ -52,7 +52,7 @@ Check also [Multiplatform](../navigation/multiplatform.md) documentation and the #### Core -Note that [BackStack](../components/backstack.md) and [Spotlight](../components/spotlight.md) are now standalone artifacts. Check your usage, you might only need `backstack`: +Note that [BackStack](components/backstack.md) and [Spotlight](components/spotlight.md) are now standalone artifacts. Check your usage, you might only need `backstack`: ```diff -implementation("com.bumble.appyx:core:1.x.x") diff --git a/documentation/navigation/concepts/composable-navigation.md b/documentation/2.x/navigation/concepts/composable-navigation.md similarity index 97% rename from documentation/navigation/concepts/composable-navigation.md rename to documentation/2.x/navigation/concepts/composable-navigation.md index 1f99e7869..0f4e562dc 100644 --- a/documentation/navigation/concepts/composable-navigation.md +++ b/documentation/2.x/navigation/concepts/composable-navigation.md @@ -1,88 +1,88 @@ ---- -title: Appyx Navigation – Composable navigation ---- - -# Composable navigation - -[AppyxComponents](../../components/index.md) in Appyx are composable. - -As a single `AppyxComponent` won't be enough for the whole of your whole app, you can use many in a composable way. That is, any managed element of a `AppyxComponent` can also host its own `AppyxComponent`. - - -## Nodes – structural elements for composing navigation - -```Nodes``` are the main structural element in Appyx. They can form a tree. - -You can think of a `Node` as a standalone unit of your app with: - -- Its own `AppyxComponent` -- Its own [Lifecycle](../features/lifecycle.md) -- State restoration -- A `@Composable` view -- Business logic that's kept alive even when the view isn't added to the composition -- The ability to host generic [Plugins](../features/plugins.md) to extract extra concerns without enforcing any particular architectural pattern - -This allows you to make your app's business logic also composable by leveraging `Nodes` as lifecycled components. - - -## Parent nodes, child nodes - -`Nodes` can have other `Nodes` as children. This means you can represent your whole application as a tree of Appyx nodes. - - - -You can go as granular or as high-level as it fits you. This allows to keep the complexity low in individual `Nodes` by extracting responsibilities to children, as well as composing other components to build more complex functionality. - - -## ChildAware API - -A `Node` can react to dynamically added child `Nodes` in the tree: [ChildAware API](../features/childaware.md) - - -## Navigation in the tree - - - -Once you've structured your navigation in a composable way, you can add an `AppyxComponent` to a `Node` of this tree and make it dynamic: - -- Some parts in this tree are active while others ore not -- The active parts define what state the application is in, and what the user sees on the screen -- We can change what's active by using an `AppyxComponent` on each level of the tree -- Changes will feel like navigation to the user - -See [Implicit navigation](implicit-navigation.md) and [Explicit navigation](explicit-navigation.md) for building complex navigation behaviours with this approach. - - - -## How AppyxComponents affect Nodes - -`AppyxComponent` operations will typically result in: - -- Adding or removing child `Nodes` of a `Node` -- Move them on and off the screen -- Change their states - -As an illustration: - - - -Here: - -- `Back stack` illustrates adding and removing child `Nodes` -- `Tiles` illustrates changing the state of children and removing them from the `Node` - -These are just two examples, you're of course not limited to using them. - - - -## Summary - -A summary of Appyx's approach to structuring applications: - -- Compose your app out of `Nodes` with their own lifecycles and state -- Navigation is local, composed of individual pieces of `AppyxComponents` -- Navigation is stateful -- Navigation is unit-testable -- Nested navigation and multi-module navigation works as a default -- You're free to implement your own navigable components by utilising `AppyxComponents` -- Avoid global navigation concerns, like shared modules needing to know about the application, or the application needing to know about all its possible modules +--- +title: Appyx Navigation – Composable navigation +--- + +# Composable navigation + +[AppyxComponents](../../components/index.md) in Appyx are composable. + +As a single `AppyxComponent` won't be enough for the whole of your whole app, you can use many in a composable way. That is, any managed element of a `AppyxComponent` can also host its own `AppyxComponent`. + + +## Nodes – structural elements for composing navigation + +```Nodes``` are the main structural element in Appyx. They can form a tree. + +You can think of a `Node` as a standalone unit of your app with: + +- Its own `AppyxComponent` +- Its own [Lifecycle](../features/lifecycle.md) +- State restoration +- A `@Composable` view +- Business logic that's kept alive even when the view isn't added to the composition +- The ability to host generic [Plugins](../features/plugins.md) to extract extra concerns without enforcing any particular architectural pattern + +This allows you to make your app's business logic also composable by leveraging `Nodes` as lifecycled components. + + +## Parent nodes, child nodes + +`Nodes` can have other `Nodes` as children. This means you can represent your whole application as a tree of Appyx nodes. + + + +You can go as granular or as high-level as it fits you. This allows to keep the complexity low in individual `Nodes` by extracting responsibilities to children, as well as composing other components to build more complex functionality. + + +## ChildAware API + +A `Node` can react to dynamically added child `Nodes` in the tree: [ChildAware API](../features/childaware.md) + + +## Navigation in the tree + + + +Once you've structured your navigation in a composable way, you can add an `AppyxComponent` to a `Node` of this tree and make it dynamic: + +- Some parts in this tree are active while others ore not +- The active parts define what state the application is in, and what the user sees on the screen +- We can change what's active by using an `AppyxComponent` on each level of the tree +- Changes will feel like navigation to the user + +See [Implicit navigation](implicit-navigation.md) and [Explicit navigation](explicit-navigation.md) for building complex navigation behaviours with this approach. + + + +## How AppyxComponents affect Nodes + +`AppyxComponent` operations will typically result in: + +- Adding or removing child `Nodes` of a `Node` +- Move them on and off the screen +- Change their states + +As an illustration: + + + +Here: + +- `Back stack` illustrates adding and removing child `Nodes` +- `Tiles` illustrates changing the state of children and removing them from the `Node` + +These are just two examples, you're of course not limited to using them. + + + +## Summary + +A summary of Appyx's approach to structuring applications: + +- Compose your app out of `Nodes` with their own lifecycles and state +- Navigation is local, composed of individual pieces of `AppyxComponents` +- Navigation is stateful +- Navigation is unit-testable +- Nested navigation and multi-module navigation works as a default +- You're free to implement your own navigable components by utilising `AppyxComponents` +- Avoid global navigation concerns, like shared modules needing to know about the application, or the application needing to know about all its possible modules diff --git a/documentation/navigation/concepts/explicit-navigation.md b/documentation/2.x/navigation/concepts/explicit-navigation.md similarity index 96% rename from documentation/navigation/concepts/explicit-navigation.md rename to documentation/2.x/navigation/concepts/explicit-navigation.md index 7b1bb8edf..b9ef884a9 100644 --- a/documentation/navigation/concepts/explicit-navigation.md +++ b/documentation/2.x/navigation/concepts/explicit-navigation.md @@ -1,213 +1,213 @@ ---- -title: Appyx Navigation – Explicit navigation ---- - -# Explicit navigation - -When [Implicit navigation](implicit-navigation.md) doesn't fit your use case, you can try an explicit approach. - -!!! info "Relevant methods" - - - Node.attachChild() - - Node.waitForChildAttached() - -Using these methods we can chain together a path which leads from the root of the tree to a specific `Node`. - -## Use case - -We want to navigate from `Chat` - - - -to onboarding's first screen `O1`: - - - -This time we'll want to do this explicitly by calling a function. - - -## The plan - -1. Create a public method on `Root` that attaches `Onboarding` -2. Create a public method on `Onboarding` that attaches the first onboarding screen -3. Create a `Navigator`, that starting from an instance of `Root`, can chain these public methods together into a single action: `navigateToO1()` -4. Capture an instance of `Root` to use with `Navigator` -5. Call `navigateToO1()` on our `Navigator` instance - - -## Step 1 – `Root` → `Onboarding` - -First, we need to define how to programmatically attach `Onboarding` to the `Root`: - -```kotlin -class RootNode( - nodeContext: NodeContext, - backStack: BackStack -) : Node( - nodeContext = nodeContext, - appyxComponent = backStack, -) { - - suspend fun attachOnboarding(): OnboardingNode { - return attachChild { - backStack.replace(NavTarget.Onboarding) - } - } -} -``` - -Let's break down what happens here: - -1. Since `attachChild` has a generic `` return type, it will conform to the defined `OnboardingNode` type -2. However, `attachChild` doesn't know how to create navigation to `OnboardingNode` – that's something only we can do with the provided lambda -3. We replace `NavTarget.Onboarding` into the back stack -4. Doing this _should_ result in `OnboardingNode` being created and added to `RootNode` as a child -5. `attachChild` expects an instance of `OnboardingNode` to appear as a child of `Root` as a consequence of executing our lambda -6. Once it appears, `attachChild` returns it - - -!!! info "Important" - - It's our responsibility to make sure that the provided lambda actually results in the expected child being added. If we accidentally do something else instead, for example: - - ```kotlin - suspend fun attachOnboarding(): OnboardingNode { - return attachChild { - backStack.replace(NavTarget.Main) // Wrong NavTarget - } - } - ``` - - Then an exception will be thrown after a timeout. - - -## Step 2 – `Onboarding` → `O1` - -Unlike `Root`, `Onboarding` uses [Spotlight](../../components/spotlight.md) instead of [BackStack](../../components/backstack.md) as an `AppyxComponent`, so navigation to the first screen is slightly different: - -```kotlin -class OnboardingNode( - nodeContext: NodeContext, - spotlight: Spotlight -) : Node( - nodeContext = nodeContext, - appyxComponent = spotlight, -) { - - suspend fun attachO1(): O1Node { - return attachChild { - spotlight.activate(index = 0) - } - } -} -``` - - -## Step 3 – Our `Navigator` - -```kotlin -interface Navigator { - fun navigateToO1() -} -``` - -In this case we'll implement it directly with our activity: - -```kotlin -class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { - - lateinit var rootNode: RootNode // See the next step - - override fun navigateToO1() { - lifecycleScope.launch { - rootNode - .attachOnboarding() - .attachO1() - } - } -} -``` - -## Step 4 – An instance of `RootNode` - -As the last piece of the puzzle, we'll also need to capture the instance of `RootNode` to make it all work. We can do that by a `NodeReadyObserver` plugin when setting up our tree: - - -```kotlin -class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { - - lateinit var rootNode: RootNode - - override fun navigateToO1() { /*...*/ } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContent { - NodeHost(integrationPoint = appyxIntegrationPoint) { - RootNode( - nodeContext = it, - navigator = this@ExplicitNavigationExampleActivity, - plugins = listOf(object : NodeReadyObserver { - override fun init(node: RootNode) { - rootNode = node - } - }) - ) - } - } - } -} -``` - -## Step 5 – Using the `Navigator` - -See how in the previous snippet `RootNode` receives a `navigator` dependency. - -It can pass it further down the tree as a dependency to other nodes. Those nodes can call the methods of the `Navigator`, which will change the global navigation state directly. - - ---- - -## Bonus: Wait for a child to be attached - -There might be cases when we want to wait for a certain action to be _performed by the user_, rather than us, to result in a child being attached. - -In these cases we can use `Node.waitForChildAttached()` instead. - - -### Use case – Wait for login - -A typical case building an explicit navigation chain that relies on `Logged in` being attached. Most probably `Logged in` has a dependency on some kind of a `User` object. Here we want to wait for the user to authenticate themselves, rather than creating a dummy user object ourselves. - - -```kotlin -class RootNode( - nodeContext: NodeContext, -) : Node( - nodeContext = nodeContext -) { - - suspend fun waitForLoggedIn(): LoggedInNode = - waitForChildAttached() -} -``` - -This method will wait for `LoggedInNode` to appear in the child list of `RootNode` and return with it. If it's already there, it returns immediately. - -A navigation chain using it could look like: - -```kotlin -class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { - - override fun navigateToProfile() { - lifecycleScope.launch { - rootNode - .waitForLoggedIn() - .attachMain() - .attachProfile() - } - } -} -``` - -You can find related code examples in `ExplicitNavigationExampleActivity` in our samples. +--- +title: Appyx Navigation – Explicit navigation +--- + +# Explicit navigation + +When [Implicit navigation](implicit-navigation.md) doesn't fit your use case, you can try an explicit approach. + +!!! info "Relevant methods" + + - Node.attachChild() + - Node.waitForChildAttached() + +Using these methods we can chain together a path which leads from the root of the tree to a specific `Node`. + +## Use case + +We want to navigate from `Chat` + + + +to onboarding's first screen `O1`: + + + +This time we'll want to do this explicitly by calling a function. + + +## The plan + +1. Create a public method on `Root` that attaches `Onboarding` +2. Create a public method on `Onboarding` that attaches the first onboarding screen +3. Create a `Navigator`, that starting from an instance of `Root`, can chain these public methods together into a single action: `navigateToO1()` +4. Capture an instance of `Root` to use with `Navigator` +5. Call `navigateToO1()` on our `Navigator` instance + + +## Step 1 – `Root` → `Onboarding` + +First, we need to define how to programmatically attach `Onboarding` to the `Root`: + +```kotlin +class RootNode( + nodeContext: NodeContext, + backStack: BackStack +) : Node( + nodeContext = nodeContext, + appyxComponent = backStack, +) { + + suspend fun attachOnboarding(): OnboardingNode { + return attachChild { + backStack.replace(NavTarget.Onboarding) + } + } +} +``` + +Let's break down what happens here: + +1. Since `attachChild` has a generic `` return type, it will conform to the defined `OnboardingNode` type +2. However, `attachChild` doesn't know how to create navigation to `OnboardingNode` – that's something only we can do with the provided lambda +3. We replace `NavTarget.Onboarding` into the back stack +4. Doing this _should_ result in `OnboardingNode` being created and added to `RootNode` as a child +5. `attachChild` expects an instance of `OnboardingNode` to appear as a child of `Root` as a consequence of executing our lambda +6. Once it appears, `attachChild` returns it + + +!!! info "Important" + + It's our responsibility to make sure that the provided lambda actually results in the expected child being added. If we accidentally do something else instead, for example: + + ```kotlin + suspend fun attachOnboarding(): OnboardingNode { + return attachChild { + backStack.replace(NavTarget.Main) // Wrong NavTarget + } + } + ``` + + Then an exception will be thrown after a timeout. + + +## Step 2 – `Onboarding` → `O1` + +Unlike `Root`, `Onboarding` uses [Spotlight](../../components/spotlight.md) instead of [BackStack](../../components/backstack.md) as an `AppyxComponent`, so navigation to the first screen is slightly different: + +```kotlin +class OnboardingNode( + nodeContext: NodeContext, + spotlight: Spotlight +) : Node( + nodeContext = nodeContext, + appyxComponent = spotlight, +) { + + suspend fun attachO1(): O1Node { + return attachChild { + spotlight.activate(index = 0) + } + } +} +``` + + +## Step 3 – Our `Navigator` + +```kotlin +interface Navigator { + fun navigateToO1() +} +``` + +In this case we'll implement it directly with our activity: + +```kotlin +class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { + + lateinit var rootNode: RootNode // See the next step + + override fun navigateToO1() { + lifecycleScope.launch { + rootNode + .attachOnboarding() + .attachO1() + } + } +} +``` + +## Step 4 – An instance of `RootNode` + +As the last piece of the puzzle, we'll also need to capture the instance of `RootNode` to make it all work. We can do that by a `NodeReadyObserver` plugin when setting up our tree: + + +```kotlin +class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { + + lateinit var rootNode: RootNode + + override fun navigateToO1() { /*...*/ } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + NodeHost(integrationPoint = appyxIntegrationPoint) { + RootNode( + nodeContext = it, + navigator = this@ExplicitNavigationExampleActivity, + plugins = listOf(object : NodeReadyObserver { + override fun init(node: RootNode) { + rootNode = node + } + }) + ) + } + } + } +} +``` + +## Step 5 – Using the `Navigator` + +See how in the previous snippet `RootNode` receives a `navigator` dependency. + +It can pass it further down the tree as a dependency to other nodes. Those nodes can call the methods of the `Navigator`, which will change the global navigation state directly. + + +--- + +## Bonus: Wait for a child to be attached + +There might be cases when we want to wait for a certain action to be _performed by the user_, rather than us, to result in a child being attached. + +In these cases we can use `Node.waitForChildAttached()` instead. + + +### Use case – Wait for login + +A typical case building an explicit navigation chain that relies on `Logged in` being attached. Most probably `Logged in` has a dependency on some kind of a `User` object. Here we want to wait for the user to authenticate themselves, rather than creating a dummy user object ourselves. + + +```kotlin +class RootNode( + nodeContext: NodeContext, +) : Node( + nodeContext = nodeContext +) { + + suspend fun waitForLoggedIn(): LoggedInNode = + waitForChildAttached() +} +``` + +This method will wait for `LoggedInNode` to appear in the child list of `RootNode` and return with it. If it's already there, it returns immediately. + +A navigation chain using it could look like: + +```kotlin +class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { + + override fun navigateToProfile() { + lifecycleScope.launch { + rootNode + .waitForLoggedIn() + .attachMain() + .attachProfile() + } + } +} +``` + +You can find related code examples in `ExplicitNavigationExampleActivity` in our samples. diff --git a/documentation/navigation/concepts/implicit-navigation.md b/documentation/2.x/navigation/concepts/implicit-navigation.md similarity index 100% rename from documentation/navigation/concepts/implicit-navigation.md rename to documentation/2.x/navigation/concepts/implicit-navigation.md diff --git a/documentation/navigation/concepts/model-driven-navigation.md b/documentation/2.x/navigation/concepts/model-driven-navigation.md similarity index 100% rename from documentation/navigation/concepts/model-driven-navigation.md rename to documentation/2.x/navigation/concepts/model-driven-navigation.md diff --git a/documentation/navigation/features/childaware.md b/documentation/2.x/navigation/features/childaware.md similarity index 100% rename from documentation/navigation/features/childaware.md rename to documentation/2.x/navigation/features/childaware.md diff --git a/documentation/navigation/features/deep-linking.md b/documentation/2.x/navigation/features/deep-linking.md similarity index 100% rename from documentation/navigation/features/deep-linking.md rename to documentation/2.x/navigation/features/deep-linking.md diff --git a/documentation/navigation/features/lifecycle.md b/documentation/2.x/navigation/features/lifecycle.md similarity index 100% rename from documentation/navigation/features/lifecycle.md rename to documentation/2.x/navigation/features/lifecycle.md diff --git a/documentation/navigation/features/material3.md b/documentation/2.x/navigation/features/material3.md similarity index 100% rename from documentation/navigation/features/material3.md rename to documentation/2.x/navigation/features/material3.md diff --git a/documentation/navigation/features/plugins.md b/documentation/2.x/navigation/features/plugins.md similarity index 100% rename from documentation/navigation/features/plugins.md rename to documentation/2.x/navigation/features/plugins.md diff --git a/documentation/navigation/features/scoped-di.md b/documentation/2.x/navigation/features/scoped-di.md similarity index 100% rename from documentation/navigation/features/scoped-di.md rename to documentation/2.x/navigation/features/scoped-di.md diff --git a/documentation/navigation/features/surviving-configuration-changes.md b/documentation/2.x/navigation/features/surviving-configuration-changes.md similarity index 100% rename from documentation/navigation/features/surviving-configuration-changes.md rename to documentation/2.x/navigation/features/surviving-configuration-changes.md diff --git a/documentation/navigation/index.md b/documentation/2.x/navigation/index.md similarity index 100% rename from documentation/navigation/index.md rename to documentation/2.x/navigation/index.md diff --git a/documentation/navigation/integrations/compose-navigation.md b/documentation/2.x/navigation/integrations/compose-navigation.md similarity index 100% rename from documentation/navigation/integrations/compose-navigation.md rename to documentation/2.x/navigation/integrations/compose-navigation.md diff --git a/documentation/navigation/integrations/di-frameworks.md b/documentation/2.x/navigation/integrations/di-frameworks.md similarity index 100% rename from documentation/navigation/integrations/di-frameworks.md rename to documentation/2.x/navigation/integrations/di-frameworks.md diff --git a/documentation/navigation/integrations/ribs.md b/documentation/2.x/navigation/integrations/ribs.md similarity index 100% rename from documentation/navigation/integrations/ribs.md rename to documentation/2.x/navigation/integrations/ribs.md diff --git a/documentation/navigation/integrations/rx.md b/documentation/2.x/navigation/integrations/rx.md similarity index 100% rename from documentation/navigation/integrations/rx.md rename to documentation/2.x/navigation/integrations/rx.md diff --git a/documentation/navigation/integrations/viewmodel.md b/documentation/2.x/navigation/integrations/viewmodel.md similarity index 100% rename from documentation/navigation/integrations/viewmodel.md rename to documentation/2.x/navigation/integrations/viewmodel.md diff --git a/documentation/navigation/multiplatform.md b/documentation/2.x/navigation/multiplatform.md similarity index 100% rename from documentation/navigation/multiplatform.md rename to documentation/2.x/navigation/multiplatform.md diff --git a/documentation/navigation/quick-start.md b/documentation/2.x/navigation/quick-start.md similarity index 100% rename from documentation/navigation/quick-start.md rename to documentation/2.x/navigation/quick-start.md diff --git a/documentation/navigation/sample-app.md b/documentation/2.x/navigation/sample-app.md similarity index 100% rename from documentation/navigation/sample-app.md rename to documentation/2.x/navigation/sample-app.md diff --git a/documentation/releases/2.0.0-alpha10.md b/documentation/2.x/releases/2.0.0-alpha10.md similarity index 100% rename from documentation/releases/2.0.0-alpha10.md rename to documentation/2.x/releases/2.0.0-alpha10.md diff --git a/documentation/releases/2.0.0.md b/documentation/2.x/releases/2.0.0.md similarity index 100% rename from documentation/releases/2.0.0.md rename to documentation/2.x/releases/2.0.0.md diff --git a/documentation/releases/changelog.md b/documentation/2.x/releases/changelog.md similarity index 100% rename from documentation/releases/changelog.md rename to documentation/2.x/releases/changelog.md diff --git a/documentation/releases/downloads.md b/documentation/2.x/releases/downloads.md similarity index 100% rename from documentation/releases/downloads.md rename to documentation/2.x/releases/downloads.md From 1d3393941d1b1b1bec67eff94569d0a515fe6a78 Mon Sep 17 00:00:00 2001 From: andreykovalev Date: Tue, 16 Jul 2024 13:46:12 +0100 Subject: [PATCH 2/4] Update documentation paths --- .../deprecation.md => 2.x/experimental.md} | 2 +- documentation/2.x/{index_2.x.md => index.md} | 6 +- documentation/{1.x => }/apps/childaware.md | 2 +- documentation/{1.x => }/apps/configuration.md | 2 +- documentation/{1.x => }/apps/lifecycle.md | 2 +- documentation/{1.x => }/apps/plugins.md | 2 +- documentation/{1.x => }/apps/structure.md | 6 +- documentation/{1.x => }/faq.md | 0 .../{1.x => }/how-to-use-appyx/codelabs.md | 2 +- .../how-to-use-appyx/coding-challenges.md | 2 +- .../{1.x => }/how-to-use-appyx/quick-start.md | 2 +- .../{1.x => }/how-to-use-appyx/sample-apps.md | 2 +- documentation/{1.x => }/index.md | 2 - .../navigation/composable-navigation.md | 102 ++--- .../{1.x => }/navigation/deep-linking.md | 2 +- .../navigation/explicit-navigation.md | 422 +++++++++--------- .../navigation/implicit-navigation.md | 2 +- .../navigation/model-driven-navigation.md | 2 +- documentation/{1.x => }/navmodel/backstack.md | 2 +- documentation/{1.x => }/navmodel/cards.md | 2 +- documentation/{1.x => }/navmodel/custom.md | 2 +- documentation/{1.x => }/navmodel/index.md | 2 +- documentation/{1.x => }/navmodel/promoter.md | 2 +- documentation/{1.x => }/navmodel/spotlight.md | 2 +- documentation/{1.x => }/navmodel/tiles.md | 2 +- documentation/{1.x => }/releases/changelog.md | 2 +- documentation/{1.x => }/releases/downloads.md | 2 +- documentation/{1.x => }/ui/children-view.md | 2 +- documentation/{1.x => }/ui/transitions.md | 2 +- mkdocs.yml | 126 +++--- 30 files changed, 352 insertions(+), 358 deletions(-) rename documentation/{1.x/deprecation.md => 2.x/experimental.md} (86%) rename documentation/2.x/{index_2.x.md => index.md} (92%) rename documentation/{1.x => }/apps/childaware.md (98%) rename documentation/{1.x => }/apps/configuration.md (97%) rename documentation/{1.x => }/apps/lifecycle.md (97%) rename documentation/{1.x => }/apps/plugins.md (98%) rename documentation/{1.x => }/apps/structure.md (90%) rename documentation/{1.x => }/faq.md (100%) rename documentation/{1.x => }/how-to-use-appyx/codelabs.md (94%) rename documentation/{1.x => }/how-to-use-appyx/coding-challenges.md (94%) rename documentation/{1.x => }/how-to-use-appyx/quick-start.md (99%) rename documentation/{1.x => }/how-to-use-appyx/sample-apps.md (96%) rename documentation/{1.x => }/index.md (98%) rename documentation/{1.x => }/navigation/composable-navigation.md (95%) rename documentation/{1.x => }/navigation/deep-linking.md (96%) rename documentation/{1.x => }/navigation/explicit-navigation.md (96%) rename documentation/{1.x => }/navigation/implicit-navigation.md (98%) rename documentation/{1.x => }/navigation/model-driven-navigation.md (97%) rename documentation/{1.x => }/navmodel/backstack.md (99%) rename documentation/{1.x => }/navmodel/cards.md (98%) rename documentation/{1.x => }/navmodel/custom.md (99%) rename documentation/{1.x => }/navmodel/index.md (96%) rename documentation/{1.x => }/navmodel/promoter.md (96%) rename documentation/{1.x => }/navmodel/spotlight.md (98%) rename documentation/{1.x => }/navmodel/tiles.md (97%) rename documentation/{1.x => }/releases/changelog.md (99%) rename documentation/{1.x => }/releases/downloads.md (97%) rename documentation/{1.x => }/ui/children-view.md (98%) rename documentation/{1.x => }/ui/transitions.md (98%) diff --git a/documentation/1.x/deprecation.md b/documentation/2.x/experimental.md similarity index 86% rename from documentation/1.x/deprecation.md rename to documentation/2.x/experimental.md index d564e5dce..707f239ea 100644 --- a/documentation/1.x/deprecation.md +++ b/documentation/2.x/experimental.md @@ -1,4 +1,4 @@ -!!! failure "Deprecation warning" +!!! failure "Experimental warning" This page in the documentation is about Appyx `1.x`. diff --git a/documentation/2.x/index_2.x.md b/documentation/2.x/index.md similarity index 92% rename from documentation/2.x/index_2.x.md rename to documentation/2.x/index.md index 47a423dd2..fc30f9919 100644 --- a/documentation/2.x/index_2.x.md +++ b/documentation/2.x/index.md @@ -2,10 +2,6 @@ title: Appyx 2.x (experimental) – Overview --- -# Disclaimer - -We’re stopping the development of Appyx 2.x until further notice. We’re fully committed to maintaining and developing new features for the stable 1.x version of Appyx. We recommend you use that version instead - # Appyx ![badge-android](https://img.shields.io/badge/platform-android-brightgreen) @@ -126,5 +122,5 @@ If you used Appyx `1.x` before, you can find a [summary of differences](migratio This page is about Appyx `2.x` (alpha). -You can find `1.x` related documentation [here](../1.x/index.md). +You can find `1.x` related documentation [here](../index.md). diff --git a/documentation/1.x/apps/childaware.md b/documentation/apps/childaware.md similarity index 98% rename from documentation/1.x/apps/childaware.md rename to documentation/apps/childaware.md index 31b1dede6..52695fcac 100644 --- a/documentation/1.x/apps/childaware.md +++ b/documentation/apps/childaware.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # ChildAware API diff --git a/documentation/1.x/apps/configuration.md b/documentation/apps/configuration.md similarity index 97% rename from documentation/1.x/apps/configuration.md rename to documentation/apps/configuration.md index 07112d1e4..1855dc470 100644 --- a/documentation/1.x/apps/configuration.md +++ b/documentation/apps/configuration.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Configuration change diff --git a/documentation/1.x/apps/lifecycle.md b/documentation/apps/lifecycle.md similarity index 97% rename from documentation/1.x/apps/lifecycle.md rename to documentation/apps/lifecycle.md index 9a5e77721..365206f14 100644 --- a/documentation/1.x/apps/lifecycle.md +++ b/documentation/apps/lifecycle.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Lifecycle diff --git a/documentation/1.x/apps/plugins.md b/documentation/apps/plugins.md similarity index 98% rename from documentation/1.x/apps/plugins.md rename to documentation/apps/plugins.md index 5c17863a9..4d7beab0b 100644 --- a/documentation/1.x/apps/plugins.md +++ b/documentation/apps/plugins.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Plugins diff --git a/documentation/1.x/apps/structure.md b/documentation/apps/structure.md similarity index 90% rename from documentation/1.x/apps/structure.md rename to documentation/apps/structure.md index 842722700..557f7089c 100644 --- a/documentation/1.x/apps/structure.md +++ b/documentation/apps/structure.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Structuring your app navigation @@ -24,7 +24,7 @@ You can think of a `Node` as a standalone component with: - State restoration - A `@Composable` view - Business logic that's kept alive even when the view isn't added to the composition -- The ability to host generic [Plugins](../apps/plugins.md) to extract extra concerns without enforcing any particular architectural pattern +- The ability to host generic [Plugins](.md) to extract extra concerns without enforcing any particular architectural pattern ## Parent nodes, child nodes @@ -49,7 +49,7 @@ Read more in [Composable navigation](../navigation/composable-navigation.md) Nodes have their own lifecycles, directly using the related classes of `androidx.lifecycle`. -Read more in [Lifecycle](../apps/lifecycle.md) +Read more in [Lifecycle](le.md) ## ChildAware API diff --git a/documentation/1.x/faq.md b/documentation/faq.md similarity index 100% rename from documentation/1.x/faq.md rename to documentation/faq.md diff --git a/documentation/1.x/how-to-use-appyx/codelabs.md b/documentation/how-to-use-appyx/codelabs.md similarity index 94% rename from documentation/1.x/how-to-use-appyx/codelabs.md rename to documentation/how-to-use-appyx/codelabs.md index 5db19dfe9..3a96d8aaa 100644 --- a/documentation/1.x/how-to-use-appyx/codelabs.md +++ b/documentation/how-to-use-appyx/codelabs.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Appyx codelabs diff --git a/documentation/1.x/how-to-use-appyx/coding-challenges.md b/documentation/how-to-use-appyx/coding-challenges.md similarity index 94% rename from documentation/1.x/how-to-use-appyx/coding-challenges.md rename to documentation/how-to-use-appyx/coding-challenges.md index 207d4afe2..a6846bb01 100644 --- a/documentation/1.x/how-to-use-appyx/coding-challenges.md +++ b/documentation/how-to-use-appyx/coding-challenges.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Appyx coding challenges diff --git a/documentation/1.x/how-to-use-appyx/quick-start.md b/documentation/how-to-use-appyx/quick-start.md similarity index 99% rename from documentation/1.x/how-to-use-appyx/quick-start.md rename to documentation/how-to-use-appyx/quick-start.md index 2bdcdd52d..abd0c20a9 100644 --- a/documentation/1.x/how-to-use-appyx/quick-start.md +++ b/documentation/how-to-use-appyx/quick-start.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Quick start guide diff --git a/documentation/1.x/how-to-use-appyx/sample-apps.md b/documentation/how-to-use-appyx/sample-apps.md similarity index 96% rename from documentation/1.x/how-to-use-appyx/sample-apps.md rename to documentation/how-to-use-appyx/sample-apps.md index e6ed660df..9ee9fefc4 100644 --- a/documentation/1.x/how-to-use-appyx/sample-apps.md +++ b/documentation/how-to-use-appyx/sample-apps.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Appyx sample apps diff --git a/documentation/1.x/index.md b/documentation/index.md similarity index 98% rename from documentation/1.x/index.md rename to documentation/index.md index d26b3dd91..81126abc9 100644 --- a/documentation/1.x/index.md +++ b/documentation/index.md @@ -1,5 +1,3 @@ -{% include-markdown "./deprecation.md" %} - # Appyx diff --git a/documentation/1.x/navigation/composable-navigation.md b/documentation/navigation/composable-navigation.md similarity index 95% rename from documentation/1.x/navigation/composable-navigation.md rename to documentation/navigation/composable-navigation.md index 1a0dc6973..b0d1bd52e 100644 --- a/documentation/1.x/navigation/composable-navigation.md +++ b/documentation/navigation/composable-navigation.md @@ -1,51 +1,51 @@ -{% include-markdown "../deprecation.md" %} - -# Composable navigation - -[NavModels](../navmodel/index.md) in Appyx are composable. - -As a single `NavModel` won't be enough for the whole of your whole app, you can use many in a composable way. That is, any navigation target of a `NavModel` can also host its own `NavModel`. - - -## Structural element for composing navigation - -```Nodes``` are the main structural element in Appyx. They can host `NavModels`, and they form a tree. - -This allows you to make your app's business logic also composable by leveraging `Nodes` as lifecycled components. - -Read more in [Structuring your app navigation](../apps/structure.md) - - -## Navigation in the tree - - - -Once you've structured your navigation in a composable way, you can add `NavModels` to `Node` of this tree and make it dynamic: - -- Some parts in this tree are active while others ore not -- The active parts define what state the application is in, and what the user sees on the screen -- We can change what's active by using `NavModels` on each level of the tree -- Changes will feel like navigation to the user - -See [Implicit navigation](implicit-navigation.md) and [Explicit navigation](explicit-navigation.md) for building complex navigation behaviours with this approach. - - - -## How NavModels affect Nodes - -NavModel operations will typically result in: - -- Adding or removing child `Nodes` of a `ParentNode` -- Move them on and off the screen -- Change their states - -As an illustration: - - - -Here: - -- `Back stack` illustrates adding and removing child `Nodes` -- `Tiles` illustrates changing the state of children and removing them from the `ParentNode` - -These are just two examples, you're of course not limited to using them. + + +# Composable navigation + +[NavModels](../navmodel/index.md) in Appyx are composable. + +As a single `NavModel` won't be enough for the whole of your whole app, you can use many in a composable way. That is, any navigation target of a `NavModel` can also host its own `NavModel`. + + +## Structural element for composing navigation + +```Nodes``` are the main structural element in Appyx. They can host `NavModels`, and they form a tree. + +This allows you to make your app's business logic also composable by leveraging `Nodes` as lifecycled components. + +Read more in [Structuring your app navigation](../apps/structure.md) + + +## Navigation in the tree + + + +Once you've structured your navigation in a composable way, you can add `NavModels` to `Node` of this tree and make it dynamic: + +- Some parts in this tree are active while others ore not +- The active parts define what state the application is in, and what the user sees on the screen +- We can change what's active by using `NavModels` on each level of the tree +- Changes will feel like navigation to the user + +See [Implicit navigation](implicit-navigation.md) and [Explicit navigation](explicit-navigation.md) for building complex navigation behaviours with this approach. + + + +## How NavModels affect Nodes + +NavModel operations will typically result in: + +- Adding or removing child `Nodes` of a `ParentNode` +- Move them on and off the screen +- Change their states + +As an illustration: + + + +Here: + +- `Back stack` illustrates adding and removing child `Nodes` +- `Tiles` illustrates changing the state of children and removing them from the `ParentNode` + +These are just two examples, you're of course not limited to using them. diff --git a/documentation/1.x/navigation/deep-linking.md b/documentation/navigation/deep-linking.md similarity index 96% rename from documentation/1.x/navigation/deep-linking.md rename to documentation/navigation/deep-linking.md index 8fc37cf0e..ae194a90d 100644 --- a/documentation/1.x/navigation/deep-linking.md +++ b/documentation/navigation/deep-linking.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Deep linking diff --git a/documentation/1.x/navigation/explicit-navigation.md b/documentation/navigation/explicit-navigation.md similarity index 96% rename from documentation/1.x/navigation/explicit-navigation.md rename to documentation/navigation/explicit-navigation.md index a9a0d3957..acfa21415 100644 --- a/documentation/1.x/navigation/explicit-navigation.md +++ b/documentation/navigation/explicit-navigation.md @@ -1,211 +1,211 @@ -{% include-markdown "../deprecation.md" %} - -# Explicit navigation - -When [Implicit navigation](implicit-navigation.md) doesn't fit your use case, you can try an explicit approach. - -!!! info "Relevant methods" - - - ParentNode.attachChild() - - ParentNode.waitForChildAttached() - -Using these methods we can chain together a path which leads from the root of the tree to a specific `Node`. - -## Use case - -We want to navigate from `Chat` - - - -to onboarding's first screen `O1`: - - - -This time we'll want to do this explicitly by calling a function. - - -## The plan - -1. Create a public method on `Root` that attaches `Onboarding` -2. Create a public method on `Onboarding` that attaches the first onboarding screen -3. Create a `Navigator`, that starting from an instance of `Root`, can chain these public methods together into a single action: `navigateToO1()` -4. Capture an instance of `Root` to use with `Navigator` -5. Call `navigateToO1()` on our `Navigator` instance - - -## Step 1 – `Root` → `Onboarding` - -First, we need to define how to programmatically attach `Onboarding` to the `Root`: - -```kotlin -class RootNode( - buildContext: BuildContext, - backStack: BackStack -) : ParentNode( - buildContext = buildContext, - navModel = backStack, -) { - - suspend fun attachOnboarding(): OnboardingNode { - return attachChild { - backStack.replace(NavTarget.Onboarding) - } - } -} -``` - -Let's break down what happens here: - -1. Since `attachChild` has a generic `` return type, it will conform to the defined `OnboardingNode` type -2. However, `attachChild` doesn't know how to create navigation to `OnboardingNode` – that's something only we can do with the provided lambda -3. We replace `NavTarget.Onboarding` into the back stack -4. Doing this _should_ result in `OnboardingNode` being created and added to `RootNode` as a child -5. `attachChild` expects an instance of `OnboardingNode` to appear as a child of `Root` as a consequence of executing our lambda -6. Once it appears, `attachChild` returns it - - -!!! info "Important" - - It's our responsibility to make sure that the provided lambda actually results in the expected child being added. If we accidentally do something else instead, for example: - - ```kotlin - suspend fun attachOnboarding(): OnboardingNode { - return attachChild { - backStack.replace(NavTarget.Main) // Wrong NavTarget - } - } - ``` - - Then an exception will be thrown after a timeout. - - -## Step 2 – `Onboarding` → `O1` - -Unlike `Root`, `Onboarding` uses [Spotlight](../navmodel/spotlight.md) instead of [BackStack](../navmodel/backstack.md) as a `NavModel`, so navigation to the first screen is slightly different: - -```kotlin -class OnboardingNode( - buildContext: BuildContext, - spotlight: Spotlight -) : ParentNode( - buildContext = buildContext, - navModel = spotlight, -) { - - suspend fun attachO1(): O1Node { - return attachChild { - spotlight.activate(index = 0) - } - } -} -``` - - -## Step 3 – Our `Navigator` - -```kotlin -interface Navigator { - fun navigateToO1() -} -``` - -In this case we'll implement it directly with our activity: - -```kotlin -class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { - - lateinit var rootNode: RootNode // See the next step - - override fun navigateToO1() { - lifecycleScope.launch { - rootNode - .attachOnboarding() - .attachO1() - } - } -} -``` - -## Step 4 – An instance of `RootNode` - -As the last piece of the puzzle, we'll also need to capture the instance of `RootNode` to make it all work. We can do that by a `NodeReadyObserver` plugin when setting up our tree: - - -```kotlin -class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { - - lateinit var rootNode: RootNode - - override fun navigateToO1() { /*...*/ } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContent { - NodeHost(integrationPoint = appyxIntegrationPoint) { - RootNode( - buildContext = it, - navigator = this@ExplicitNavigationExampleActivity, - plugins = listOf(object : NodeReadyObserver { - override fun init(node: RootNode) { - rootNode = node - } - }) - ) - } - } - } -} -``` - -## Step 5 – Using the `Navigator` - -See how in the previous snippet `RootNode` receives a `navigator` dependency. - -It can pass it further down the tree as a dependency to other nodes. Those nodes can call the methods of the `Navigator`, which will change the global navigation state directly. - - ---- - -## Bonus: Wait for a child to be attached - -There might be cases when we want to wait for a certain action to be _performed by the user_, rather than us, to result in a child being attached. - -In these cases we can use `ParentNode.waitForChildAttached()` instead. - - -### Use case – Wait for login - -A typical case building an explicit navigation chain that relies on `Logged in` being attached. Most probably `Logged in` has a dependency on some kind of a `User` object. Here we want to wait for the user to authenticate themselves, rather than creating a dummy user object ourselves. - - -```kotlin -class RootNode( - buildContext: BuildContext, -) : ParentNode( - buildContext = buildContext -) { - - suspend fun waitForLoggedIn(): LoggedInNode = - waitForChildAttached() -} -``` - -This method will wait for `LoggedInNode` to appear in the child list of `RootNode` and return with it. If it's already there, it returns immediately. - -A navigation chain using it could look like: - -```kotlin -class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { - - override fun navigateToProfile() { - lifecycleScope.launch { - rootNode - .waitForLoggedIn() - .attachMain() - .attachProfile() - } - } -} -``` - -You can find related code examples in `ExplicitNavigationExampleActivity` in our samples. + + +# Explicit navigation + +When [Implicit navigation](implicit-navigation.md) doesn't fit your use case, you can try an explicit approach. + +!!! info "Relevant methods" + + - ParentNode.attachChild() + - ParentNode.waitForChildAttached() + +Using these methods we can chain together a path which leads from the root of the tree to a specific `Node`. + +## Use case + +We want to navigate from `Chat` + + + +to onboarding's first screen `O1`: + + + +This time we'll want to do this explicitly by calling a function. + + +## The plan + +1. Create a public method on `Root` that attaches `Onboarding` +2. Create a public method on `Onboarding` that attaches the first onboarding screen +3. Create a `Navigator`, that starting from an instance of `Root`, can chain these public methods together into a single action: `navigateToO1()` +4. Capture an instance of `Root` to use with `Navigator` +5. Call `navigateToO1()` on our `Navigator` instance + + +## Step 1 – `Root` → `Onboarding` + +First, we need to define how to programmatically attach `Onboarding` to the `Root`: + +```kotlin +class RootNode( + buildContext: BuildContext, + backStack: BackStack +) : ParentNode( + buildContext = buildContext, + navModel = backStack, +) { + + suspend fun attachOnboarding(): OnboardingNode { + return attachChild { + backStack.replace(NavTarget.Onboarding) + } + } +} +``` + +Let's break down what happens here: + +1. Since `attachChild` has a generic `` return type, it will conform to the defined `OnboardingNode` type +2. However, `attachChild` doesn't know how to create navigation to `OnboardingNode` – that's something only we can do with the provided lambda +3. We replace `NavTarget.Onboarding` into the back stack +4. Doing this _should_ result in `OnboardingNode` being created and added to `RootNode` as a child +5. `attachChild` expects an instance of `OnboardingNode` to appear as a child of `Root` as a consequence of executing our lambda +6. Once it appears, `attachChild` returns it + + +!!! info "Important" + + It's our responsibility to make sure that the provided lambda actually results in the expected child being added. If we accidentally do something else instead, for example: + + ```kotlin + suspend fun attachOnboarding(): OnboardingNode { + return attachChild { + backStack.replace(NavTarget.Main) // Wrong NavTarget + } + } + ``` + + Then an exception will be thrown after a timeout. + + +## Step 2 – `Onboarding` → `O1` + +Unlike `Root`, `Onboarding` uses [Spotlight](../navmodel/spotlight.md) instead of [BackStack](../navmodel/backstack.md) as a `NavModel`, so navigation to the first screen is slightly different: + +```kotlin +class OnboardingNode( + buildContext: BuildContext, + spotlight: Spotlight +) : ParentNode( + buildContext = buildContext, + navModel = spotlight, +) { + + suspend fun attachO1(): O1Node { + return attachChild { + spotlight.activate(index = 0) + } + } +} +``` + + +## Step 3 – Our `Navigator` + +```kotlin +interface Navigator { + fun navigateToO1() +} +``` + +In this case we'll implement it directly with our activity: + +```kotlin +class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { + + lateinit var rootNode: RootNode // See the next step + + override fun navigateToO1() { + lifecycleScope.launch { + rootNode + .attachOnboarding() + .attachO1() + } + } +} +``` + +## Step 4 – An instance of `RootNode` + +As the last piece of the puzzle, we'll also need to capture the instance of `RootNode` to make it all work. We can do that by a `NodeReadyObserver` plugin when setting up our tree: + + +```kotlin +class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { + + lateinit var rootNode: RootNode + + override fun navigateToO1() { /*...*/ } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + NodeHost(integrationPoint = appyxIntegrationPoint) { + RootNode( + buildContext = it, + navigator = this@ExplicitNavigationExampleActivity, + plugins = listOf(object : NodeReadyObserver { + override fun init(node: RootNode) { + rootNode = node + } + }) + ) + } + } + } +} +``` + +## Step 5 – Using the `Navigator` + +See how in the previous snippet `RootNode` receives a `navigator` dependency. + +It can pass it further down the tree as a dependency to other nodes. Those nodes can call the methods of the `Navigator`, which will change the global navigation state directly. + + +--- + +## Bonus: Wait for a child to be attached + +There might be cases when we want to wait for a certain action to be _performed by the user_, rather than us, to result in a child being attached. + +In these cases we can use `ParentNode.waitForChildAttached()` instead. + + +### Use case – Wait for login + +A typical case building an explicit navigation chain that relies on `Logged in` being attached. Most probably `Logged in` has a dependency on some kind of a `User` object. Here we want to wait for the user to authenticate themselves, rather than creating a dummy user object ourselves. + + +```kotlin +class RootNode( + buildContext: BuildContext, +) : ParentNode( + buildContext = buildContext +) { + + suspend fun waitForLoggedIn(): LoggedInNode = + waitForChildAttached() +} +``` + +This method will wait for `LoggedInNode` to appear in the child list of `RootNode` and return with it. If it's already there, it returns immediately. + +A navigation chain using it could look like: + +```kotlin +class ExplicitNavigationExampleActivity : NodeActivity(), Navigator { + + override fun navigateToProfile() { + lifecycleScope.launch { + rootNode + .waitForLoggedIn() + .attachMain() + .attachProfile() + } + } +} +``` + +You can find related code examples in `ExplicitNavigationExampleActivity` in our samples. diff --git a/documentation/1.x/navigation/implicit-navigation.md b/documentation/navigation/implicit-navigation.md similarity index 98% rename from documentation/1.x/navigation/implicit-navigation.md rename to documentation/navigation/implicit-navigation.md index 30f00b2a8..f03e61eab 100644 --- a/documentation/1.x/navigation/implicit-navigation.md +++ b/documentation/navigation/implicit-navigation.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Implicit navigation diff --git a/documentation/1.x/navigation/model-driven-navigation.md b/documentation/navigation/model-driven-navigation.md similarity index 97% rename from documentation/1.x/navigation/model-driven-navigation.md rename to documentation/navigation/model-driven-navigation.md index 499a414e4..bdd8399df 100644 --- a/documentation/1.x/navigation/model-driven-navigation.md +++ b/documentation/navigation/model-driven-navigation.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Model-driven navigation diff --git a/documentation/1.x/navmodel/backstack.md b/documentation/navmodel/backstack.md similarity index 99% rename from documentation/1.x/navmodel/backstack.md rename to documentation/navmodel/backstack.md index b70b54e15..47c70be8c 100644 --- a/documentation/1.x/navmodel/backstack.md +++ b/documentation/navmodel/backstack.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Back stack diff --git a/documentation/1.x/navmodel/cards.md b/documentation/navmodel/cards.md similarity index 98% rename from documentation/1.x/navmodel/cards.md rename to documentation/navmodel/cards.md index 102d9deca..e797f53cd 100644 --- a/documentation/1.x/navmodel/cards.md +++ b/documentation/navmodel/cards.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Cards diff --git a/documentation/1.x/navmodel/custom.md b/documentation/navmodel/custom.md similarity index 99% rename from documentation/1.x/navmodel/custom.md rename to documentation/navmodel/custom.md index f7d7a14a6..ff3499ea8 100644 --- a/documentation/1.x/navmodel/custom.md +++ b/documentation/navmodel/custom.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Implementing your own navigation models diff --git a/documentation/1.x/navmodel/index.md b/documentation/navmodel/index.md similarity index 96% rename from documentation/1.x/navmodel/index.md rename to documentation/navmodel/index.md index 76eaf3629..3d0c00cc0 100644 --- a/documentation/1.x/navmodel/index.md +++ b/documentation/navmodel/index.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Navigation models diff --git a/documentation/1.x/navmodel/promoter.md b/documentation/navmodel/promoter.md similarity index 96% rename from documentation/1.x/navmodel/promoter.md rename to documentation/navmodel/promoter.md index c28c71e18..7c3b956b6 100644 --- a/documentation/1.x/navmodel/promoter.md +++ b/documentation/navmodel/promoter.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Promoter carousel diff --git a/documentation/1.x/navmodel/spotlight.md b/documentation/navmodel/spotlight.md similarity index 98% rename from documentation/1.x/navmodel/spotlight.md rename to documentation/navmodel/spotlight.md index 8552f4030..4d2b1d6f5 100644 --- a/documentation/1.x/navmodel/spotlight.md +++ b/documentation/navmodel/spotlight.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Spotlight diff --git a/documentation/1.x/navmodel/tiles.md b/documentation/navmodel/tiles.md similarity index 97% rename from documentation/1.x/navmodel/tiles.md rename to documentation/navmodel/tiles.md index 4ad864706..da81e1d1a 100644 --- a/documentation/1.x/navmodel/tiles.md +++ b/documentation/navmodel/tiles.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Tiles diff --git a/documentation/1.x/releases/changelog.md b/documentation/releases/changelog.md similarity index 99% rename from documentation/1.x/releases/changelog.md rename to documentation/releases/changelog.md index de4c27ffd..1dd05de4b 100644 --- a/documentation/1.x/releases/changelog.md +++ b/documentation/releases/changelog.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Changelog diff --git a/documentation/1.x/releases/downloads.md b/documentation/releases/downloads.md similarity index 97% rename from documentation/1.x/releases/downloads.md rename to documentation/releases/downloads.md index bd8713d96..27a60c9bd 100644 --- a/documentation/1.x/releases/downloads.md +++ b/documentation/releases/downloads.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Downloads diff --git a/documentation/1.x/ui/children-view.md b/documentation/ui/children-view.md similarity index 98% rename from documentation/1.x/ui/children-view.md rename to documentation/ui/children-view.md index c4ee95244..c3abf5b76 100644 --- a/documentation/1.x/ui/children-view.md +++ b/documentation/ui/children-view.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Adding children to the view diff --git a/documentation/1.x/ui/transitions.md b/documentation/ui/transitions.md similarity index 98% rename from documentation/1.x/ui/transitions.md rename to documentation/ui/transitions.md index d04d9b996..9ca6a9507 100644 --- a/documentation/1.x/ui/transitions.md +++ b/documentation/ui/transitions.md @@ -1,4 +1,4 @@ -{% include-markdown "../deprecation.md" %} + # Transitions diff --git a/mkdocs.yml b/mkdocs.yml index 061c006d7..c3d69fc47 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -16,84 +16,84 @@ copyright: Copyright © 2022 - 2023 Bumble docs_dir: documentation nav: - - Home: 1.x/index.md + - Home: index.md - Using Appyx: - - Quick start guide: 1.x/how-to-use-appyx/quick-start.md - - Codelabs: 1.x/how-to-use-appyx/codelabs.md - - Coding challenges: 1.x/how-to-use-appyx/coding-challenges.md - - Sample apps: 1.x/how-to-use-appyx/sample-apps.md + - Quick start guide: how-to-use-appyx/quick-start.md + - Codelabs: how-to-use-appyx/codelabs.md + - Coding challenges: how-to-use-appyx/coding-challenges.md + - Sample apps: how-to-use-appyx/sample-apps.md - Navigation: - - Model-driven navigation: 1.x/navigation/model-driven-navigation.md + - Model-driven navigation: navigation/model-driven-navigation.md - NavModel: - - Overview: 1.x/navmodel/index.md - - Back stack: 1.x/navmodel/backstack.md - - Spotlight: 1.x/navmodel/spotlight.md - - Cards: 1.x/navmodel/cards.md - - Tiles: 1.x/navmodel/tiles.md - - Promoter: 1.x/navmodel/promoter.md - - Writing your own: 1.x/navmodel/custom.md - - Composable navigation: 1.x/navigation/composable-navigation.md - - Implicit navigation: 1.x/navigation/implicit-navigation.md - - Explicit navigation: 1.x/navigation/explicit-navigation.md - - Deep linking: 1.x/navigation/deep-linking.md + - Overview: navmodel/index.md + - Back stack: navmodel/backstack.md + - Spotlight: navmodel/spotlight.md + - Cards: navmodel/cards.md + - Tiles: navmodel/tiles.md + - Promoter: navmodel/promoter.md + - Writing your own: navmodel/custom.md + - Composable navigation: navigation/composable-navigation.md + - Implicit navigation: navigation/implicit-navigation.md + - Explicit navigation: navigation/explicit-navigation.md + - Deep linking: navigation/deep-linking.md - UI: - - Children: 1.x/ui/children-view.md - - Transitions: 1.x/ui/transitions.md + - Children: ui/children-view.md + - Transitions: ui/transitions.md - App: - - Structuring your app navigation: 1.x/apps/structure.md - - Lifecycle: 1.x/apps/lifecycle.md - - Plugins: 1.x/apps/plugins.md - - ChildAware API: 1.x/apps/childaware.md - - Configuration changes: 1.x/apps/configuration.md + - Structuring your app navigation: apps/structure.md + - Lifecycle: apps/lifecycle.md + - Plugins: apps/plugins.md + - ChildAware API: apps/childaware.md + - Configuration changes: apps/configuration.md - Releases: - - Downloads: 1.x/releases/downloads.md - - Changelog: 1.x/releases/changelog.md - - FAQ: 1.x/faq.md + - Downloads: releases/downloads.md + - Changelog: releases/changelog.md + - FAQ: faq.md - Appyx 2.x (experimental): - - Home: index.md + - Home: 2.x/index.md - Appyx Navigation: - - Overview: navigation/index_2.x.md - - Sample app: navigation/sample-app.md - - Quick start guide: navigation/quick-start.md + - Overview: 2.x/navigation/index.md + - Sample app: 2.x/navigation/sample-app.md + - Quick start guide: 2.x/navigation/quick-start.md - Concepts: - - Model-driven navigation: navigation/concepts/model-driven-navigation.md - - Composable navigation: navigation/concepts/composable-navigation.md - - Implicit navigation: navigation/concepts/implicit-navigation.md - - Explicit navigation: navigation/concepts/explicit-navigation.md + - Model-driven navigation: 2.x/navigation/concepts/model-driven-navigation.md + - Composable navigation: 2.x/navigation/concepts/composable-navigation.md + - Implicit navigation: 2.x/navigation/concepts/implicit-navigation.md + - Explicit navigation: 2.x/navigation/concepts/explicit-navigation.md - Features: - - Deep linking: navigation/features/deep-linking.md - - Scoped DI: navigation/features/scoped-di.md - - Lifecycle: navigation/features/lifecycle.md - - Material 3 support: navigation/features/material3.md - - Plugins: navigation/features/plugins.md - - ChildAware API: navigation/features/childaware.md - - Surviving configuration changes: navigation/features/surviving-configuration-changes.md + - Deep linking: 2.x/navigation/features/deep-linking.md + - Scoped DI: 2.x/navigation/features/scoped-di.md + - Lifecycle: 2.x/navigation/features/lifecycle.md + - Material 3 support: 2.x/navigation/features/material3.md + - Plugins: 2.x/navigation/features/plugins.md + - ChildAware API: 2.x/navigation/features/childaware.md + - Surviving configuration changes: 2.x/navigation/features/surviving-configuration-changes.md - Integrations: - - Compose Navigation: navigation/integrations/compose-navigation.md - - DI frameworks: navigation/integrations/di-frameworks.md - - RIBs: navigation/integrations/ribs.md - - RxJava: navigation/integrations/rx.md - - ViewModel: navigation/integrations/viewmodel.md - - Multiplatform: navigation/multiplatform.md + - Compose Navigation: 2.x/navigation/integrations/compose-navigation.md + - DI frameworks: 2.x/navigation/integrations/di-frameworks.md + - RIBs: 2.x/navigation/integrations/ribs.md + - RxJava: 2.x/navigation/integrations/rx.md + - ViewModel: 2.x/navigation/integrations/viewmodel.md + - Multiplatform: 2.x/navigation/multiplatform.md - Appyx Interactions: - - Overview: interactions/index.md - - Using components: interactions/usage.md + - Overview: 2.x/interactions/index.md + - Using components: 2.x/interactions/usage.md - Creating your own: - - Component overview: interactions/appyxcomponent.md - - Transition model: interactions/transitionmodel.md - - Operations: interactions/operations.md - - UI representation: interactions/ui-representation.md - - KSP setup: interactions/ksp.md - - Gestures: interactions/gestures.md + - Component overview: 2.x/interactions/appyxcomponent.md + - Transition model: 2.x/interactions/transitionmodel.md + - Operations: 2.x/interactions/operations.md + - UI representation: 2.x/interactions/ui-representation.md + - KSP setup: 2.x/interactions/ksp.md + - Gestures: 2.x/interactions/gestures.md - Appyx Components: - - Overview: components/index.md - - Back stack: components/backstack.md - - Spotlight: components/spotlight.md - - Experimental: components/experimental.md + - Overview: 2.x/components/index.md + - Back stack: 2.x/components/backstack.md + - Spotlight: 2.x/components/spotlight.md + - Experimental: 2.x/components/experimental.md - Releases: - - Downloads: releases/downloads.md - - Changelog: releases/changelog.md - - FAQ: faq.md + - Downloads: 2.x/releases/downloads.md + - Changelog: 2.x/releases/changelog.md + - FAQ: 2.x/faq.md - Migration guide: 2.x/migrationguide.md From f36aa1606626b1ecff01b08b8c33a11398877e0a Mon Sep 17 00:00:00 2001 From: andreykovalev Date: Tue, 16 Jul 2024 13:55:47 +0100 Subject: [PATCH 3/4] Update documentation --- documentation/2.x/experimental.md | 6 +++--- documentation/faq.md | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/documentation/2.x/experimental.md b/documentation/2.x/experimental.md index 707f239ea..86af41a05 100644 --- a/documentation/2.x/experimental.md +++ b/documentation/2.x/experimental.md @@ -1,10 +1,10 @@ !!! failure "Experimental warning" - This page in the documentation is about Appyx `1.x`. + We’re stopping the development of Appyx 2.x until further notice. - Appyx is now in its `2.x` iteration. + We’re fully committed to maintaining and developing new features for the stable 1.x version of Appyx. - To access the `2.x`-related pages please check the sidebar or go to: + We recommend you use that version instead. The code for 2.x you can find in the `2.x` branch of the repository. **[Documentation root](../index.md)** diff --git a/documentation/faq.md b/documentation/faq.md index 6f8c0d9e2..265806d5b 100644 --- a/documentation/faq.md +++ b/documentation/faq.md @@ -1,5 +1,3 @@ -{% include-markdown "./deprecation.md" %} - # FAQ From 78c17651b68000d5e0a4150e0e25a7e616ce4a59 Mon Sep 17 00:00:00 2001 From: andreykovalev Date: Tue, 16 Jul 2024 14:05:06 +0100 Subject: [PATCH 4/4] Fix missing file --- documentation/2.x/releases/changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 120000 => 100644 documentation/2.x/releases/changelog.md diff --git a/documentation/2.x/releases/changelog.md b/documentation/2.x/releases/changelog.md deleted file mode 120000 index 699cc9e7b..000000000 --- a/documentation/2.x/releases/changelog.md +++ /dev/null @@ -1 +0,0 @@ -../../CHANGELOG.md \ No newline at end of file diff --git a/documentation/2.x/releases/changelog.md b/documentation/2.x/releases/changelog.md new file mode 100644 index 000000000..03cb73106 --- /dev/null +++ b/documentation/2.x/releases/changelog.md @@ -0,0 +1 @@ +../../CHANGELOG.md