Repository: arkivanov/Decompose
Pull request #300 (2023-01-10 21:09:23)

Added not parcelable overloads for childStack and childOverlay


Patch:
diff --git a/decompose/api/android/decompose.api b/decompose/api/android/decompose.api
index 976f37d3..21f5257a 100644
--- a/decompose/api/android/decompose.api
+++ b/decompose/api/android/decompose.api
@@ -141,7 +141,9 @@ public final class com/arkivanov/decompose/router/overlay/ChildOverlay {
 }
 
 public final class com/arkivanov/decompose/router/overlay/ChildOverlayFactoryKt {
+	public static final fun childOverlay (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/overlay/OverlayNavigationSource;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/value/Value;
 	public static final fun childOverlay (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/overlay/OverlayNavigationSource;Lkotlin/reflect/KClass;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ZZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/value/Value;
+	public static synthetic fun childOverlay$default (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/overlay/OverlayNavigationSource;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/value/Value;
 	public static synthetic fun childOverlay$default (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/overlay/OverlayNavigationSource;Lkotlin/reflect/KClass;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ZZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/value/Value;
 }
 
@@ -195,7 +197,9 @@ public final class com/arkivanov/decompose/router/stack/ChildStack {
 }
 
 public final class com/arkivanov/decompose/router/stack/ChildStackFactoryKt {
+	public static final fun childStack (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/stack/StackNavigationSource;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Ljava/lang/String;IZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/value/Value;
 	public static final fun childStack (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/stack/StackNavigationSource;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZIZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/value/Value;
+	public static synthetic fun childStack$default (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/stack/StackNavigationSource;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Ljava/lang/String;IZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/value/Value;
 	public static synthetic fun childStack$default (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/stack/StackNavigationSource;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZIZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/value/Value;
 }
 
diff --git a/decompose/api/jvm/decompose.api b/decompose/api/jvm/decompose.api
index 7feeac7e..61b7006e 100644
--- a/decompose/api/jvm/decompose.api
+++ b/decompose/api/jvm/decompose.api
@@ -120,7 +120,9 @@ public final class com/arkivanov/decompose/router/overlay/ChildOverlay {
 }
 
 public final class com/arkivanov/decompose/router/overlay/ChildOverlayFactoryKt {
+	public static final fun childOverlay (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/overlay/OverlayNavigationSource;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/value/Value;
 	public static final fun childOverlay (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/overlay/OverlayNavigationSource;Lkotlin/reflect/KClass;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ZZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/value/Value;
+	public static synthetic fun childOverlay$default (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/overlay/OverlayNavigationSource;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/value/Value;
 	public static synthetic fun childOverlay$default (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/overlay/OverlayNavigationSource;Lkotlin/reflect/KClass;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ZZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/value/Value;
 }
 
@@ -174,7 +176,9 @@ public final class com/arkivanov/decompose/router/stack/ChildStack {
 }
 
 public final class com/arkivanov/decompose/router/stack/ChildStackFactoryKt {
+	public static final fun childStack (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/stack/StackNavigationSource;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Ljava/lang/String;IZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/value/Value;
 	public static final fun childStack (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/stack/StackNavigationSource;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZIZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/value/Value;
+	public static synthetic fun childStack$default (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/stack/StackNavigationSource;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Ljava/lang/String;IZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/value/Value;
 	public static synthetic fun childStack$default (Lcom/arkivanov/decompose/ComponentContext;Lcom/arkivanov/decompose/router/stack/StackNavigationSource;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZIZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/value/Value;
 }
 
diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/children/ChildrenFactory.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/children/ChildrenFactory.kt
index bc686be0..6ad7056a 100644
--- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/children/ChildrenFactory.kt
+++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/children/ChildrenFactory.kt
@@ -41,7 +41,9 @@ import com.arkivanov.essenty.statekeeper.consume
  * `children` used in the same component.
  * @param initialNavState an initial navigation state that should be used if there is no previously saved state.
  * @param saveNavState a function that saves the provided navigation state into [ParcelableContainer].
+ * The navigation state is not saved if `null` is returned.
  * @param restoreNavState a function that restores the navigation state from the provided [ParcelableContainer].
+ * If `null` is returned then [initialNavState] is used instead.
  * The restored navigation state must have the same amount of child configurations and in the same order.
  * The restored child [Statuses][ChildNavState.Status] can be any, e.g. a previously active child may become
  * destroyed, etc.
@@ -61,7 +63,7 @@ fun <C : Any, T : Any, E : Any, N : NavState<C>, S : Any> ComponentContext.child
     key: String,
     initialNavState: () -> N,
     saveNavState: (navState: N) -> ParcelableContainer?,
-    restoreNavState: (container: ParcelableContainer) -> N,
+    restoreNavState: (container: ParcelableContainer) -> N?,
     navTransformer: (navState: N, event: E) -> N,
     onEventComplete: (event: E, newNavState: N, oldNavState: N) -> Unit,
     backTransformer: (navState: N) -> (() -> N)?,
@@ -70,20 +72,20 @@ fun <C : Any, T : Any, E : Any, N : NavState<C>, S : Any> ComponentContext.child
 ): Value<S> {
     val mainBackHandler = backHandler.child()
 
-    val savedState = stateKeeper.consume<SavedState>(key = key)
-
     val navigator =
-        ChildrenNavigator(
-            lifecycle = lifecycle,
-            retainedInstanceSupplier = { factory -> instanceKeeper.getOrCreate(key = key, factory = factory) },
-            childItemFactory = DefaultChildItemFactory(
+        stateKeeper.consume<SavedState>(key = key).let { savedState ->
+            ChildrenNavigator(
                 lifecycle = lifecycle,
-                backHandler = backHandler.child(),
-                childFactory = childFactory,
-            ),
-            navState = savedState?.navState?.let(restoreNavState) ?: initialNavState(),
-            savedChildState = savedState?.childState,
-        )
+                retainedInstanceSupplier = { factory -> instanceKeeper.getOrCreate(key = key, factory = factory) },
+                childItemFactory = DefaultChildItemFactory(
+                    lifecycle = lifecycle,
+                    backHandler = backHandler.child(),
+                    childFactory = childFactory,
+                ),
+                navState = savedState?.navState?.let(restoreNavState) ?: initialNavState(),
+                savedChildState = savedState?.childState,
+            )
+        }
 
     stateKeeper.register(key = key) {
         saveNavState(navigator.navState)?.let { savedNavState ->
diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/overlay/ChildOverlayFactory.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/overlay/ChildOverlayFactory.kt
index 0d2a59a0..21ccaa4c 100644
--- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/overlay/ChildOverlayFactory.kt
+++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/overlay/ChildOverlayFactory.kt
@@ -36,13 +36,47 @@ fun <C : Parcelable, T : Any> ComponentContext.childOverlay(
     persistent: Boolean = true,
     handleBackButton: Boolean = false,
     childFactory: (configuration: C, ComponentContext) -> T,
+): Value<ChildOverlay<C, T>> =
+    childOverlay(
+        source = source,
+        saveConfiguration = { if (persistent) ParcelableContainer(it) else null },
+        restoreConfiguration = { it.consume(configurationClass) },
+        key = key,
+        initialConfiguration = initialConfiguration,
+        handleBackButton = handleBackButton,
+        childFactory = childFactory,
+    )
+
+/**
+ * Initializes and manages component overlay. An overlay component can be either active or dismissed (destroyed).
+ *
+ * @param source a source of navigation events.
+ * @param key a key of the overlay, must be unique within the parent (hosting) component.
+ * @param saveConfiguration a function that saves the provided configuration into [ParcelableContainer].
+ * @param restoreConfiguration a function that restores the configuration from the provided [ParcelableContainer].
+ * @param initialConfiguration a component configuration that should be shown if there is
+ * no saved state, return `null` to show nothing.
+ * @param handleBackButton determines whether the overlay should be automatically dismissed
+ * on back button press or not, default is `false`.
+ * @param childFactory a factory function that creates new child instances.
+ * @return an observable [Value] of [ChildOverlay].
+ */
+@ExperimentalDecomposeApi
+fun <C : Any, T : Any> ComponentContext.childOverlay(
+    source: OverlayNavigationSource<C>,
+    saveConfiguration: (C?) -> ParcelableContainer?,
+    restoreConfiguration: (ParcelableContainer) -> C?,
+    key: String = "DefaultChildOverlay",
+    initialConfiguration: () -> C? = { null },
+    handleBackButton: Boolean = false,
+    childFactory: (configuration: C, ComponentContext) -> T,
 ): Value<ChildOverlay<C, T>> =
     children(
         source = source,
         key = key,
         initialNavState = { OverlayNavState(configuration = initialConfiguration()) },
-        saveNavState = { navState -> if (persistent) ParcelableContainer(navState.configuration) else null },
-        restoreNavState = { container -> OverlayNavState(container.consume(configurationClass)) },
+        saveNavState = { saveConfiguration(it.configuration) },
+        restoreNavState = { OverlayNavState(restoreConfiguration(it)) },
         navTransformer = { navState, event -> OverlayNavState(configuration = event.transformer(navState.configuration)) },
         onEventComplete = { event, newNavState, oldNavState -> event.onComplete(newNavState.configuration, oldNavState.configuration) },
         backTransformer = { navState ->
@@ -56,19 +90,6 @@ fun <C : Parcelable, T : Any> ComponentContext.childOverlay(
         childFactory = childFactory,
     )
 
-@OptIn(ExperimentalDecomposeApi::class)
-private data class OverlayNavState<out C : Any>(
-    val configuration: C?,
-) : NavState<C> {
-
-    override val children: List<SimpleChildNavState<C>> =
-        if (configuration == null) {
-            emptyList()
-        } else {
-            listOf(SimpleChildNavState(configuration = configuration, status = Status.ACTIVE))
-        }
-}
-
 /**
  * A convenience extension function for [ComponentContext.childOverlay].
  */
@@ -89,3 +110,16 @@ inline fun <reified C : Parcelable, T : Any> ComponentContext.childOverlay(
         handleBackButton = handleBackButton,
         childFactory = childFactory,
     )
+
+@OptIn(ExperimentalDecomposeApi::class)
+private data class OverlayNavState<out C : Any>(
+    val configuration: C?,
+) : NavState<C> {
+
+    override val children: List<SimpleChildNavState<C>> =
+        if (configuration == null) {
+            emptyList()
+        } else {
+            listOf(SimpleChildNavState(configuration = configuration, status = Status.ACTIVE))
+        }
+}
diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/ChildStackFactory.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/ChildStackFactory.kt
index 9699d09c..c200d23c 100644
--- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/ChildStackFactory.kt
+++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/ChildStackFactory.kt
@@ -36,7 +36,6 @@ import kotlin.reflect.KClass
  * @param childFactory a factory function that creates new child instances.
  * @return an observable [Value] of [ChildStack].
  */
-@OptIn(ExperimentalDecomposeApi::class)
 fun <C : Parcelable, T : Any> ComponentContext.childStack(
     source: StackNavigationSource<C>,
     initialStack: () -> List<C>,
@@ -47,46 +46,79 @@ fun <C : Parcelable, T : Any> ComponentContext.childStack(
     handleBackButton: Boolean = false,
     childFactory: (configuration: C, ComponentContext) -> T,
 ): Value<ChildStack<C, T>> =
-    children(
+    childStack(
         source = source,
-        key = key,
-        initialNavState = {
-            val stack = initialStack()
-            check(stack.isNotEmpty()) { "Configuration stack must not be empty" }
-
-            StackNavState(
-                active = stack.last(),
-                backStack = stack
-                    .dropLast(1)
-                    .map { configuration -> SimpleChildNavState(configuration = configuration, status = Status.DESTROYED) }
-                    .withCreateDepth(createDepth = backStackCreateDepth),
-            )
-        },
-        saveNavState = { navState ->
+        initialStack = initialStack,
+        saveStack = { stack ->
             if (persistent) {
                 ParcelableContainer(
                     StackSavedNavState(
-                        activeConfiguration = ParcelableContainer(navState.active),
-                        backStackConfigurations = navState.backStack.map { ParcelableContainer(it.configuration) },
+                        configurations = stack.map { ParcelableContainer(it) },
                     )
                 )
             } else {
                 null
             }
         },
-        restoreNavState = { container ->
-            val state = container.consumeRequired<StackSavedNavState>()
+        restoreStack = { container ->
+            container
+                .consumeRequired<StackSavedNavState>()
+                .configurations
+                .map { it.consumeRequired(configurationClass) }
+        },
+        key = key,
+        backStackCreateDepth = backStackCreateDepth,
+        handleBackButton = handleBackButton,
+        childFactory = childFactory,
+    )
 
+/**
+ * Initializes and manages a stack of components.
+ *
+ * @param source a source of navigation events.
+ * @param initialStack a stack of component configurations (ordered from tail to head) that should be set
+ * if there is no saved state, must be not empty and unique.
+ * @param saveStack a function that saves the provided stack of configurations into [ParcelableContainer].
+ * The navigation state is not saved if `null` is returned.
+ * @param restoreStack a function that restores the stack of configuration from the provided [ParcelableContainer].
+ * If `null` is returned then [initialStack] is used instead.
+ * The restored stack must have the same amount of configurations and in the same order.
+ * @param key a key of the stack, must be unique if there are multiple stacks in the same component.
+ * @param backStackCreateDepth automatically creates the specified amount of components
+ * in the back stack, e.g. when initialized, during navigation or after process death.
+ * Default value is `0`, which means that a component is only created when it becomes active.
+ * Use `1` to always create the previous component in the stack. Use [Int.MAX_VALUE] to
+ * create all components in the stack.
+ * @param handleBackButton determines whether the overlay should be automatically dismissed
+ * on back button press or not, default is `false`.
+ * @param childFactory a factory function that creates new child instances.
+ * @return an observable [Value] of [ChildStack].
+ */
+@OptIn(ExperimentalDecomposeApi::class)
+fun <C : Any, T : Any> ComponentContext.childStack(
+    source: StackNavigationSource<C>,
+    initialStack: () -> List<C>,
+    saveStack: (List<C>) -> ParcelableContainer?,
+    restoreStack: (ParcelableContainer) -> List<C>?,
+    key: String = "DefaultChildStack",
+    backStackCreateDepth: Int = 0,
+    handleBackButton: Boolean = false,
+    childFactory: (configuration: C, ComponentContext) -> T,
+): Value<ChildStack<C, T>> =
+    children(
+        source = source,
+        key = key,
+        initialNavState = {
             StackNavState(
-                active = state.activeConfiguration.consumeRequired(configurationClass),
-                backStack = state.backStackConfigurations
-                    .map {
-                        SimpleChildNavState(
-                            configuration = it.consumeRequired(configurationClass),
-                            status = Status.DESTROYED,
-                        )
-                    }
-                    .withCreateDepth(createDepth = backStackCreateDepth)
+                configurations = initialStack(),
+                backStackCreateDepth = backStackCreateDepth,
+            )
+        },
+        saveNavState = { saveStack(it.configurations) },
+        restoreNavState = { container ->
+            StackNavState(
+                configurations = restoreStack(container) ?: initialStack(),
+                backStackCreateDepth = backStackCreateDepth,
             )
         },
         navTransformer = { navState, event ->
@@ -137,6 +169,52 @@ fun <C : Parcelable, T : Any> ComponentContext.childStack(
         childFactory = childFactory,
     )
 
+/**
+ * A convenience extension function for [ComponentContext.childStack].
+ */
+inline fun <reified C : Parcelable, T : Any> ComponentContext.childStack(
+    source: StackNavigationSource<C>,
+    noinline initialStack: () -> List<C>,
+    key: String = "DefaultChildStack",
+    persistent: Boolean = true,
+    backStackCreateDepth: Int = 0,
+    handleBackButton: Boolean = false,
+    noinline childFactory: (configuration: C, ComponentContext) -> T
+): Value<ChildStack<C, T>> =
+    childStack(
+        source = source,
+        initialStack = initialStack,
+        configurationClass = C::class,
+        key = key,
+        persistent = persistent,
+        handleBackButton = handleBackButton,
+        backStackCreateDepth = backStackCreateDepth,
+        childFactory = childFactory,
+    )
+
+/**
+ * A convenience extension function for [ComponentContext.childStack].
+ */
+inline fun <reified C : Parcelable, T : Any> ComponentContext.childStack(
+    source: StackNavigationSource<C>,
+    initialConfiguration: C,
+    key: String = "DefaultChildStack",
+    persistent: Boolean = true,
+    backStackCreateDepth: Int = 0,
+    handleBackButton: Boolean = false,
+    noinline childFactory: (configuration: C, ComponentContext) -> T
+): Value<ChildStack<C, T>> =
+    childStack(
+        source = source,
+        initialStack = { listOf(initialConfiguration) },
+        configurationClass = C::class,
+        key = key,
+        persistent = persistent,
+        handleBackButton = handleBackButton,
+        backStackCreateDepth = backStackCreateDepth,
+        childFactory = childFactory,
+    )
+
 @ExperimentalDecomposeApi
 private fun <C : Any> List<SimpleChildNavState<C>>.withCreateDepth(createDepth: Int): List<SimpleChildNavState<C>> =
     if (isCreateRequired(createDepth = createDepth)) {
@@ -181,54 +259,20 @@ private data class StackNavState<out C : Any>(
         }
 }
 
-@Parcelize
-private class StackSavedNavState(
-    val activeConfiguration: ParcelableContainer,
-    val backStackConfigurations: List<ParcelableContainer>,
-) : Parcelable
+@ExperimentalDecomposeApi
+private fun <C : Any> StackNavState(configurations: List<C>, backStackCreateDepth: Int): StackNavState<C> {
+    require(configurations.isNotEmpty()) { "Configuration stack must not be empty" }
 
-/**
- * A convenience extension function for [ComponentContext.childStack].
- */
-inline fun <reified C : Parcelable, T : Any> ComponentContext.childStack(
-    source: StackNavigationSource<C>,
-    noinline initialStack: () -> List<C>,
-    key: String = "DefaultChildStack",
-    persistent: Boolean = true,
-    backStackCreateDepth: Int = 0,
-    handleBackButton: Boolean = false,
-    noinline childFactory: (configuration: C, ComponentContext) -> T
-): Value<ChildStack<C, T>> =
-    childStack(
-        source = source,
-        initialStack = initialStack,
-        configurationClass = C::class,
-        key = key,
-        persistent = persistent,
-        handleBackButton = handleBackButton,
-        backStackCreateDepth = backStackCreateDepth,
-        childFactory = childFactory,
+    return StackNavState(
+        active = configurations.last(),
+        backStack = configurations
+            .dropLast(1)
+            .map { SimpleChildNavState(configuration = it, status = Status.DESTROYED) }
+            .withCreateDepth(createDepth = backStackCreateDepth),
     )
+}
 
-/**
- * A convenience extension function for [ComponentContext.childStack].
- */
-inline fun <reified C : Parcelable, T : Any> ComponentContext.childStack(
-    source: StackNavigationSource<C>,
-    initialConfiguration: C,
-    key: String = "DefaultChildStack",
-    persistent: Boolean = true,
-    backStackCreateDepth: Int = 0,
-    handleBackButton: Boolean = false,
-    noinline childFactory: (configuration: C, ComponentContext) -> T
-): Value<ChildStack<C, T>> =
-    childStack(
-        source = source,
-        initialStack = { listOf(initialConfiguration) },
-        configurationClass = C::class,
-        key = key,
-        persistent = persistent,
-        handleBackButton = handleBackButton,
-        backStackCreateDepth = backStackCreateDepth,
-        childFactory = childFactory,
-    )
+@Parcelize
+private class StackSavedNavState(
+    val configurations: List<ParcelableContainer>,
+) : Parcelable


Test patch:
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenSavedStateTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenSavedStateTest.kt
index 334a0734..078bb286 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenSavedStateTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenSavedStateTest.kt
@@ -1,6 +1,7 @@
 package com.arkivanov.decompose.router.children
 
 import com.arkivanov.decompose.DefaultComponentContext
+import com.arkivanov.decompose.ExperimentalDecomposeApi
 import com.arkivanov.decompose.router.children.ChildNavState.Status.ACTIVE
 import com.arkivanov.decompose.router.children.ChildNavState.Status.DESTROYED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.INACTIVE
@@ -15,6 +16,7 @@ import kotlin.test.assertFalse
 import kotlin.test.assertNull
 import kotlin.test.assertTrue
 
+@OptIn(ExperimentalDecomposeApi::class)
 @Suppress("TestFunctionName")
 internal class ChildrenSavedStateTest : ChildrenTestBase() {
 
@@ -164,6 +166,20 @@ internal class ChildrenSavedStateTest : ChildrenTestBase() {
         newChildren.assertChildren(1 to 1)
     }
 
+    @Test
+    fun GIVEN_not_restoring_state_WHEN_recreated_THEN_navigation_state_not_restored() {
+        val oldStateKeeper = TestStateKeeperDispatcher()
+        val oldContext = DefaultComponentContext(lifecycle = lifecycle, stateKeeper = oldStateKeeper)
+        oldContext.children(initialNavState = listOf(1 by DESTROYED, 2 by INACTIVE, 3 by ACTIVE))
+
+        val savedState = oldStateKeeper.save()
+        val newStateKeeper = TestStateKeeperDispatcher(savedState)
+        val newContext = DefaultComponentContext(lifecycle = lifecycle, stateKeeper = newStateKeeper)
+        val newChildren by newContext.children(initialNavState = listOf(1 by ACTIVE), restoreNavState = { null })
+
+        newChildren.assertChildren(1 to 1)
+    }
+
     @Test
     fun GIVEN_saving_state_WHEN_recreated_THEN_child_states_restored() {
         val oldStateKeeper = TestStateKeeperDispatcher()
@@ -196,6 +212,22 @@ internal class ChildrenSavedStateTest : ChildrenTestBase() {
         assertNull(restoredState3)
     }
 
+    @Test
+    fun GIVEN_not_restoring_state_WHEN_recreated_THEN_child_states_not_restored() {
+        val oldStateKeeper = TestStateKeeperDispatcher()
+        val oldContext = DefaultComponentContext(lifecycle = lifecycle, stateKeeper = oldStateKeeper)
+        val oldChildren by oldContext.children(initialNavState = listOf(1 by ACTIVE), saveNavState = { null })
+        oldChildren.getById(id = 1).requireInstance().stateKeeper.register(key = "key") { Config(id = 30) }
+
+        val savedState = oldStateKeeper.save()
+        val newStateKeeper = TestStateKeeperDispatcher(savedState)
+        val newContext = DefaultComponentContext(lifecycle = lifecycle, stateKeeper = newStateKeeper)
+        val newChildren by newContext.children(initialNavState = listOf(1 by ACTIVE), restoreNavState = { null })
+        val restoredState3 = newChildren.getById(id = 1).requireInstance().stateKeeper.consume<Config>(key = "key")
+
+        assertNull(restoredState3)
+    }
+
     @Test
     fun GIVEN_recreated_and_child_restored_as_destroyed_WHEN_child_switched_to_inactive_THEN_state_restored() {
         val oldStateKeeper = TestStateKeeperDispatcher()
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenTestBase.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenTestBase.kt
index 16341d4f..c4bf74e1 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenTestBase.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenTestBase.kt
@@ -48,7 +48,7 @@ internal open class ChildrenTestBase {
                 )
             )
         },
-        restoreNavState: (container: ParcelableContainer) -> List<SimpleChildNavState<Config>> = { container ->
+        restoreNavState: (container: ParcelableContainer) -> List<SimpleChildNavState<Config>>? = { container ->
             val savedState = container.consumeRequired<SavedNavState>()
             savedState.configurations.zip(savedState.statuses).map { (configuration, status) ->
                 SimpleChildNavState(
@@ -65,7 +65,7 @@ internal open class ChildrenTestBase {
             key = "Key",
             initialNavState = { TestNavState(children = initialNavState) },
             saveNavState = { navState -> saveNavState(navState.children) },
-            restoreNavState = { container -> TestNavState(children = restoreNavState(container)) },
+            restoreNavState = { container -> restoreNavState(container)?.let(::TestNavState) },
             navTransformer = { navState, event -> event.transformer(navState) },
             onEventComplete = { event, newNavState, oldNavState -> event.onComplete(newNavState, oldNavState) },
             backTransformer = {