diff --git a/docs/extensions/compose.md b/docs/extensions/compose.md index ef9fd6db9..eacbd265e 100644 --- a/docs/extensions/compose.md +++ b/docs/extensions/compose.md @@ -78,7 +78,7 @@ fun main() { !!! note - You can find the `runOnUiThread` method [here]([Utils.kt](https://github.com/arkivanov/Decompose/blob/master/sample/app-desktop/src/jvmMain/kotlin/com/arkivanov/sample/app/Utils.kt)). + You can find the `runOnUiThread` method [here](https://github.com/arkivanov/Decompose/blob/master/sample/app-desktop/src/jvmMain/kotlin/com/arkivanov/sample/app/Utils.kt). ## Navigating between Composable components diff --git a/docs/navigation/pages/overview.md b/docs/navigation/pages/overview.md index bc3dafeb6..6f075d7d3 100644 --- a/docs/navigation/pages/overview.md +++ b/docs/navigation/pages/overview.md @@ -42,6 +42,8 @@ There are three steps to initialize `Child Pages`: Here is a very basic example of a pager-like navigation: ```kotlin title="PageComponent" +import com.arkivanov.decompose.ComponentContext + interface PageComponent { val data: String } @@ -55,6 +57,16 @@ class DefaultPageComponent( === "Before v2.2.0-alpha01" ```kotlin title="PagesComponent" + import com.arkivanov.decompose.ComponentContext + import com.arkivanov.decompose.router.pages.ChildPages + import com.arkivanov.decompose.router.pages.Pages + import com.arkivanov.decompose.router.pages.PagesNavigation + import com.arkivanov.decompose.router.pages.childPages + import com.arkivanov.decompose.router.pages.select + import com.arkivanov.decompose.value.Value + import com.arkivanov.essenty.parcelable.Parcelable + import com.arkivanov.essenty.parcelable.Parcelize + interface PagesComponent { val pages: Value> @@ -89,12 +101,21 @@ class DefaultPageComponent( @Parcelize // kotlin-parcelize plugin must be applied if you are targetting Android private data class Config(val data: String) : Parcelable - } + } ``` === "Since v2.2.0-alpha01" ```kotlin title="PagesComponent" + import com.arkivanov.decompose.ComponentContext + import com.arkivanov.decompose.router.pages.ChildPages + import com.arkivanov.decompose.router.pages.Pages + import com.arkivanov.decompose.router.pages.PagesNavigation + import com.arkivanov.decompose.router.pages.childPages + import com.arkivanov.decompose.router.pages.select + import com.arkivanov.decompose.value.Value + import kotlinx.serialization.Serializable + interface PagesComponent { val pages: Value> diff --git a/docs/navigation/slot/component-context.md b/docs/navigation/slot/component-context.md index 12d86aa10..4abe9f264 100644 --- a/docs/navigation/slot/component-context.md +++ b/docs/navigation/slot/component-context.md @@ -2,39 +2,93 @@ Custom `ComponentContext` allows passing extra data and functionality to every child component. See [Custom ComponentContext](../../component/custom-component-context.md) page for more information about creating custom `AppComponentContext`. -In order to pass custom component context (like `AppComponentContext`) to child slot components, make an extension function on your `AppComponentContext` interface. This custom extension function will initialize the `Child Slot` and provide every child an `AppComponentContext`. +In order to pass the custom `ComponentContext` (like `AppComponentContext`) to child slot components, make an extension function on your `AppComponentContext` interface. This custom extension function will initialize the `Child Slot` and provide every child an `AppComponentContext`. -```kotlin -inline fun AppComponentContext.appChildSlot( - source: SlotNavigationSource, - noinline initialConfiguration: () -> C? = { null }, - key: String = "DefaultSlot", - handleBackButton: Boolean = false, - persistent: Boolean = false, - noinline childFactory: (configuration: C, AppComponentContext) -> T -): Value> = - childSlot( - source = source, - key = key, - handleBackButton = handleBackButton, - initialConfiguration = initialConfiguration, - persistent = persistent - ) { configuration, componentContext -> - childFactory( - configuration, - DefaultAppComponentContext( - componentContext = componentContext, - // Additional dependencies here +=== "Before v2.2.0-alpha01" + + ```kotlin + import com.arkivanov.decompose.router.slot.ChildSlot + import com.arkivanov.decompose.router.slot.SlotNavigationSource + import com.arkivanov.decompose.router.slot.childSlot + import com.arkivanov.decompose.value.Value + import com.arkivanov.essenty.parcelable.Parcelable + + inline fun AppComponentContext.appChildSlot( + source: SlotNavigationSource, + noinline initialConfiguration: () -> C? = { null }, + key: String = "DefaultSlot", + handleBackButton: Boolean = false, + persistent: Boolean = false, + noinline childFactory: (configuration: C, AppComponentContext) -> T + ): Value> = + childSlot( + source = source, + key = key, + handleBackButton = handleBackButton, + initialConfiguration = initialConfiguration, + persistent = persistent + ) { configuration, componentContext -> + childFactory( + configuration, + DefaultAppComponentContext( + componentContext = componentContext, + // Additional dependencies here + ) ) - ) - } -``` + } + ``` + +=== "Since v2.2.0-alpha01" + + ```kotlin + import com.arkivanov.decompose.router.slot.ChildSlot + import com.arkivanov.decompose.router.slot.SlotNavigationSource + import com.arkivanov.decompose.router.slot.childSlot + import com.arkivanov.decompose.value.Value + import kotlinx.serialization.KSerializer + + interface AppComponentContext : ComponentContext + + class DefaultAppComponentContext(componentContext: ComponentContext) : AppComponentContext + + inline fun AppComponentContext.appChildSlot( + source: SlotNavigationSource, + serializer: KSerializer?, + noinline initialConfiguration: () -> C? = { null }, + key: String = "DefaultSlot", + handleBackButton: Boolean = false, + noinline childFactory: (configuration: C, AppComponentContext) -> T + ): Value> = + childSlot( + source = source, + serializer = serializer, + key = key, + handleBackButton = handleBackButton, + initialConfiguration = initialConfiguration, + ) { configuration, componentContext -> + childFactory( + configuration, + DefaultAppComponentContext( + componentContext = componentContext, + // Additional dependencies here + ) + ) + } + ``` Finally, in your components you can use the new extension function that will utilize the custom `AppComponentContext`. -=== "Before v3.0.0-alpha01" +=== "Before v2.2.0-alpha01" ```kotlin + import com.arkivanov.decompose.router.slot.ChildSlot + import com.arkivanov.decompose.router.slot.SlotNavigation + import com.arkivanov.decompose.router.slot.activate + import com.arkivanov.decompose.router.slot.dismiss + import com.arkivanov.decompose.value.Value + import com.arkivanov.essenty.parcelable.Parcelable + import com.arkivanov.essenty.parcelable.Parcelize + interface RootComponent { val dialog: Value> } @@ -67,9 +121,16 @@ Finally, in your components you can use the new extension function that will uti } ``` -=== "Since v3.0.0-alpha01" +=== "Since v2.2.0-alpha01" ```kotlin + import com.arkivanov.decompose.router.slot.ChildSlot + import com.arkivanov.decompose.router.slot.SlotNavigation + import com.arkivanov.decompose.router.slot.activate + import com.arkivanov.decompose.router.slot.dismiss + import com.arkivanov.decompose.value.Value + import kotlinx.serialization.Serializable + interface RootComponent { val dialog: Value> } diff --git a/docs/navigation/slot/overview.md b/docs/navigation/slot/overview.md index c699871c7..38f4a3f42 100644 --- a/docs/navigation/slot/overview.md +++ b/docs/navigation/slot/overview.md @@ -28,6 +28,8 @@ There are three steps to initialize the `Child Slot`: Here is a very basic example of a child slot: ```kotlin title="Dialog component" +import com.arkivanov.decompose.ComponentContext + interface DialogComponent { fun onDismissClicked() @@ -48,6 +50,16 @@ class DefaultDialogComponent( === "Before v2.2.0-alpha01" ```kotlin title="Root component" + import com.arkivanov.decompose.ComponentContext + import com.arkivanov.decompose.router.slot.ChildSlot + import com.arkivanov.decompose.router.slot.SlotNavigation + import com.arkivanov.decompose.router.slot.activate + import com.arkivanov.decompose.router.slot.childSlot + import com.arkivanov.decompose.router.slot.dismiss + import com.arkivanov.decompose.value.Value + import com.arkivanov.essenty.parcelable.Parcelable + import com.arkivanov.essenty.parcelable.Parcelize + interface RootComponent { val dialog: Value> @@ -76,7 +88,7 @@ class DefaultDialogComponent( dialogNavigation.activate(DialogConfig(message = message)) } - @Parcelize // kotlin-parcelize plugin must be applied if you are targetting Android + @Parcelize // kotlin-parcelize plugin must be applied if you are targeting Android private data class DialogConfig( val message: String, ) : Parcelable @@ -86,6 +98,15 @@ class DefaultDialogComponent( === "Since v2.2.0-alpha01" ```kotlin title="Root component" + import com.arkivanov.decompose.ComponentContext + import com.arkivanov.decompose.router.slot.ChildSlot + import com.arkivanov.decompose.router.slot.SlotNavigation + import com.arkivanov.decompose.router.slot.activate + import com.arkivanov.decompose.router.slot.childSlot + import com.arkivanov.decompose.router.slot.dismiss + import com.arkivanov.decompose.value.Value + import kotlinx.serialization.Serializable + interface RootComponent { val dialog: Value> @@ -126,12 +147,16 @@ class DefaultDialogComponent( When multiple `Child Slots` are used in one component, each such `Child Slot` must have a unique key associated. The keys are required to be unique only within the parent (hosting) component, so it is ok for different components to have `Child Slots` with same keys. An exception will be thrown if multiple `Child Slots` with the same key are detected in a component. ```kotlin title="Two Child Slots in one component" +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.router.slot.SlotNavigation +import com.arkivanov.decompose.router.slot.childSlot + class Root( componentContext: ComponentContext ) : ComponentContext by componentContext { private val topNavigation = SlotNavigation() - + private val topSlot = childSlot( source = topNavigation, @@ -140,7 +165,7 @@ class Root( ) private val bottomNavigation = SlotNavigation() - + private val bottomSlot = childSlot( source = bottomNavigation, diff --git a/docs/navigation/stack/component-context.md b/docs/navigation/stack/component-context.md index 04f4bc121..b3e08237e 100644 --- a/docs/navigation/stack/component-context.md +++ b/docs/navigation/stack/component-context.md @@ -4,42 +4,92 @@ Custom `ComponentContext` allows passing extra data and functionality to every c In order to pass custom component context (like `AppComponentContext`) to child stack components, make an extension function on your `AppComponentContext` interface. This custom extension function will initialize the `Child Stack` and provide every child an `AppComponentContext`. -```kotlin -inline fun AppComponentContext.appChildStack( - source: StackNavigationSource, - noinline initialStack: () -> List, - key: String = "DefaultStack", - handleBackButton: Boolean = false, - noinline childFactory: (configuration: C, AppComponentContext) -> T -): Value> = - childStack( - source = source, - initialStack = initialStack, - key = key, - handleBackButton = handleBackButton - ) { configuration, componentContext -> - childFactory( - configuration, - DefaultAppComponentContext( - componentContext = componentContext, - // Additional dependencies here +=== "Before v2.2.0-alpha01" + + ```kotlin + import com.arkivanov.decompose.router.stack.ChildStack + import com.arkivanov.decompose.router.stack.StackNavigationSource + import com.arkivanov.decompose.router.stack.childStack + import com.arkivanov.decompose.value.Value + import com.arkivanov.essenty.parcelable.Parcelable + + inline fun AppComponentContext.appChildStack( + source: StackNavigationSource, + noinline initialStack: () -> List, + key: String = "DefaultStack", + persistent: Boolean = true, + handleBackButton: Boolean = false, + noinline childFactory: (configuration: C, AppComponentContext) -> T + ): Value> = + childStack( + source = source, + initialStack = initialStack, + key = key, + persistent = persistent, + handleBackButton = handleBackButton + ) { configuration, componentContext -> + childFactory( + configuration, + DefaultAppComponentContext( + componentContext = componentContext, + // Additional dependencies here + ) ) - ) - } -``` + } + ``` + +=== "Since v2.2.0-alpha01" + + ```kotlin + import com.arkivanov.decompose.router.stack.ChildStack + import com.arkivanov.decompose.router.stack.StackNavigationSource + import com.arkivanov.decompose.router.stack.childStack + import com.arkivanov.decompose.value.Value + import kotlinx.serialization.KSerializer + + inline fun AppComponentContext.appChildStack( + source: StackNavigationSource, + serializer: KSerializer?, + noinline initialStack: () -> List, + key: String = "DefaultStack", + handleBackButton: Boolean = false, + noinline childFactory: (configuration: C, AppComponentContext) -> T + ): Value> = + childStack( + source = source, + serializer = serializer, + initialStack = initialStack, + key = key, + handleBackButton = handleBackButton + ) { configuration, componentContext -> + childFactory( + configuration, + DefaultAppComponentContext( + componentContext = componentContext, + // Additional dependencies here + ) + ) + } + ``` Finally, in your components you can use the new extension function that will utilize the custom `AppComponentContext`. -=== "Before v3.0.0-alpha01" +=== "Before v2.2.0-alpha01" ```kotlin + import com.arkivanov.decompose.router.stack.ChildStack + import com.arkivanov.decompose.router.stack.StackNavigation + import com.arkivanov.decompose.value.Value + import com.arkivanov.essenty.parcelable.Parcelable + import com.arkivanov.essenty.parcelable.Parcelize + interface RootComponent { val childStack: Value> sealed class Child { - class ListChild(val component: ItemList) : Child() - class DetailsChild(val component: ItemDetails) : Child() + class ListChild(val component: ItemListComponent) : Child() + class DetailsChild(val component: ItemDetailsComponent) : Child() } } @@ -52,19 +102,19 @@ Finally, in your components you can use the new extension function that will uti override val childStack: Value> = appChildStack( source = navigation, - initialConfiguration = Config.List, + initialStack = { listOf(Config.List) }, handleBackButton = true, // Pop the back stack on back button press childFactory = ::createChild, ) private fun createChild(config: Config, componentContext: AppComponentContext): RootComponent.Child = - TODO('Initialize child based on config with the custom component context') + TODO("Initialize child based on config with the custom component context") private fun itemList(componentContext: AppComponentContext): ItemListComponent = - TODO('Initialize ItemDetails with the custom component context') + TODO("Initialize ItemDetails with the custom component context") private fun itemDetails(componentContext: AppComponentContext, config: Config.Details): ItemDetailsComponent = - TODO('Initialize ItemDetails with the custom component context') + TODO("Initialize ItemDetails with the custom component context") private sealed class Config : Parcelable { @Parcelize @@ -76,16 +126,21 @@ Finally, in your components you can use the new extension function that will uti } ``` -=== "Since v3.0.0-alpha01" +=== "Since v2.2.0-alpha01" ```kotlin + import com.arkivanov.decompose.router.stack.ChildStack + import com.arkivanov.decompose.router.stack.StackNavigation + import com.arkivanov.decompose.value.Value + import kotlinx.serialization.Serializable + interface RootComponent { val childStack: Value> sealed class Child { - class ListChild(val component: ItemList) : Child() - class DetailsChild(val component: ItemDetails) : Child() + class ListChild(val component: ItemListComponent) : Child() + class DetailsChild(val component: ItemDetailsComponent) : Child() } } @@ -99,19 +154,19 @@ Finally, in your components you can use the new extension function that will uti appChildStack( source = navigation, serializer = Config.serializer(), - initialConfiguration = Config.List, + initialStack = { listOf(Config.List) }, handleBackButton = true, // Pop the back stack on back button press childFactory = ::createChild, ) private fun createChild(config: Config, componentContext: AppComponentContext): RootComponent.Child = - TODO('Initialize child based on config with the custom component context') + TODO("Initialize child based on config with the custom component context") private fun itemList(componentContext: AppComponentContext): ItemListComponent = - TODO('Initialize ItemDetails with the custom component context') + TODO("Initialize ItemDetails with the custom component context") private fun itemDetails(componentContext: AppComponentContext, config: Config.Details): ItemDetailsComponent = - TODO('Initialize ItemDetails with the custom component context') + TODO("Initialize ItemDetails with the custom component context") @Serializable private sealed class Config { diff --git a/docs/navigation/stack/deeplinking.md b/docs/navigation/stack/deeplinking.md index 7681bf882..ed10aed8a 100644 --- a/docs/navigation/stack/deeplinking.md +++ b/docs/navigation/stack/deeplinking.md @@ -15,13 +15,18 @@ item with the provided `id`. When the user closes the details screen, they shoul parsed data from the deep link to a component responsible for navigation, in our case it is the `Root` component. ```kotlin -class RootComponent( +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.router.stack.StackNavigation +import com.arkivanov.decompose.router.stack.childStack +import kotlinx.serialization.Serializable + +class DefaultRootComponent( componentContext: ComponentContext, initialItemId: Long? = null, // It can be any other type, e.g. a sealed class with all possible destinations -) : Root, ComponentContext by componentContext { +) : RootComponent, ComponentContext by componentContext { private val navigation = StackNavigation() - + private val stack = childStack( source = navigation, @@ -36,6 +41,15 @@ class RootComponent( ) // Omitted code + + @Serializable + private sealed class Config { + @Serializable + data object List : Config() + + @Serializable + data class Details(val itemId: Long) : Config() + } } ``` @@ -51,6 +65,13 @@ Once the app is configured, the deeplink `Intent` can arrive via one of the two #### Handling deep links since v3.0.0-alpha01 ```kotlin +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatActivity +import com.arkivanov.decompose.defaultComponentContext + class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -58,13 +79,12 @@ class MainActivity : AppCompatActivity() { val initialItemId = intent.data?.extractInitialItemId() - val root = - RootComponent( - componentContext = defaultComponentContext( - discardSavedState = initialItemId != null, // Discard any saved state if there is a deep link - ), - initialItemId = initialItemId, - ) + val root = DefaultRootComponent( + componentContext = defaultComponentContext( + discardSavedState = initialItemId != null, // Discard any saved state if there is a deep link + ), + initialItemId = initialItemId, + ) if (initialItemId != null) { intent = Intent(intent).setData(null) // The deep link has been handled, clear the Intent data @@ -84,14 +104,21 @@ class MainActivity : AppCompatActivity() { } } - private fun Uri.extractInitialItemId(): Long? = - TODO("Extract the initial item id from the deep link") + private fun Uri.extractInitialItemId(): Long = TODO("Extract the initial item id from the deep link") } ``` #### Alternative way ```kotlin +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatActivity +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.defaultComponentContext + class MainActivity : AppCompatActivity() { private lateinit var root: RootComponent @@ -102,7 +129,7 @@ class MainActivity : AppCompatActivity() { val initialItemId = intent.data?.extractInitialItemId() root = - RootComponent( + DefaultRootComponent( componentContext = defaultComponentContext(), initialItemId = initialItemId, ) @@ -127,17 +154,17 @@ class MainActivity : AppCompatActivity() { TODO("Extract the initial item id from the deep link") } -class RootComponent( +class DefaultRootComponent( componentContext: ComponentContext, initialItemId: Long? = null, -) { +) : RootComponent, ComponentContext by componentContext { // Omitted code fun onDeepLink(initialItemId: Long) { navigation.replaceAll(Config.List, Config.Details(itemId = initialItemId)) } - + // Omitted code } ``` diff --git a/docs/navigation/stack/overview.md b/docs/navigation/stack/overview.md index 63057e4ee..88820e106 100644 --- a/docs/navigation/stack/overview.md +++ b/docs/navigation/stack/overview.md @@ -34,6 +34,8 @@ There are three steps to initialize the `Child Stack`: Here is a very basic example of navigation between two child components: ```kotlin title="ItemList component" +import com.arkivanov.decompose.ComponentContext + interface ItemListComponent { // Omitted code @@ -55,6 +57,8 @@ class DefaultItemListComponent( ``` ```kotlin title="ItemDetails component" +import com.arkivanov.decompose.ComponentContext + interface ItemDetailsComponent { // Omitted code @@ -78,63 +82,86 @@ class DefaultItemDetailsComponent( === "Before v2.2.0-alpha01" - ```kotlin title="Root component" - interface RootComponent { - - val childStack: Value> - - sealed class Child { - class ListChild(val component: ItemListComponent) : Child() - class DetailsChild(val component: ItemDetailsComponent) : Child() - } - } - - class DefaultRootComponent( - componentContext: ComponentContext - ) : RootComponent, ComponentContext by componentContext { - - private val navigation = StackNavigation() - - override val childStack: Value> = - childStack( - source = navigation, - initialConfiguration = Config.List, - handleBackButton = true, // Pop the back stack on back button press - childFactory = ::createChild, - ) - - private fun createChild(config: Config, componentContext: ComponentContext): RootComponent.Child = - when (config) { - is Config.List -> ListChild(itemList(componentContext)) - is Config.Details -> DetailsChild(itemDetails(componentContext, config)) - } - - private fun itemList(componentContext: ComponentContext): ItemListComponent = - DefaultItemListComponent( - componentContext = componentContext, - onItemSelected = { navigation.push(Config.Details(itemId = it)) } - ) - - private fun itemDetails(componentContext: ComponentContext, config: Config.Details): ItemDetailsComponent = - DefaultItemDetailsComponent( - componentContext = componentContext, - itemId = config.itemId, - onFinished = { navigation.pop() } - ) - - private sealed class Config : Parcelable { - @Parcelize - data object List : Config() - - @Parcelize - data class Details(val itemId: Long) : Config() - } - } - ``` + ```kotlin title="Root component" + import com.arkivanov.decompose.ComponentContext + import com.arkivanov.decompose.router.stack.ChildStack + import com.arkivanov.decompose.router.stack.StackNavigation + import com.arkivanov.decompose.router.stack.childStack + import com.arkivanov.decompose.router.stack.pop + import com.arkivanov.decompose.router.stack.push + import com.arkivanov.decompose.value.Value + import com.arkivanov.essenty.parcelable.Parcelable + import com.arkivanov.essenty.parcelable.Parcelize + import com.arkivanov.sample.shared.RootComponent.Child.DetailsChild + import com.arkivanov.sample.shared.RootComponent.Child.ListChild + + interface RootComponent { + + val childStack: Value> + + sealed class Child { + class ListChild(val component: ItemListComponent) : Child() + class DetailsChild(val component: ItemDetailsComponent) : Child() + } + } + + class DefaultRootComponent( + componentContext: ComponentContext + ) : RootComponent, ComponentContext by componentContext { + + private val navigation = StackNavigation() + + override val childStack: Value> = + childStack( + source = navigation, + initialConfiguration = Config.List, + handleBackButton = true, // Pop the back stack on back button press + childFactory = ::createChild, + ) + + private fun createChild(config: Config, componentContext: ComponentContext): RootComponent.Child = + when (config) { + is Config.List -> ListChild(itemList(componentContext)) + is Config.Details -> DetailsChild(itemDetails(componentContext, config)) + } + + private fun itemList(componentContext: ComponentContext): ItemListComponent = + DefaultItemListComponent( + componentContext = componentContext, + onItemSelected = { navigation.push(Config.Details(itemId = it)) } + ) + + private fun itemDetails(componentContext: ComponentContext, config: Config.Details): ItemDetailsComponent = + DefaultItemDetailsComponent( + componentContext = componentContext, + itemId = config.itemId, + onFinished = navigation::pop, + ) + + private sealed class Config : Parcelable { + @Parcelize + data object List : Config() + + @Parcelize + data class Details(val itemId: Long) : Config() + } + } + ``` === "Since v2.2.0-alpha01" ```kotlin title="Root component" + import com.arkivanov.decompose.ComponentContext + import com.arkivanov.decompose.router.stack.ChildStack + import com.arkivanov.decompose.router.stack.StackNavigation + import com.arkivanov.decompose.router.stack.childStack + import com.arkivanov.decompose.router.stack.pop + import com.arkivanov.decompose.router.stack.push + import com.arkivanov.decompose.value.Value + import com.arkivanov.sample.shared.RootComponent.Child.DetailsChild + import com.arkivanov.sample.shared.RootComponent.Child.ListChild + import kotlinx.serialization.Serializable + interface RootComponent { val childStack: Value> @@ -212,7 +239,7 @@ To deliver a result from one component to another: - When the callback is invoked, perform the navigation, e.g. by using `navigation.pop { ... }`. - After the navigation is performed, call a method on the `first` component with the `result`. -```kotlin +```kotlin title="Child components" interface ItemListComponent { fun onItemClicked(id: Long) @@ -220,11 +247,6 @@ interface ItemListComponent { fun onItemDeleted(id: Long) } -interface ItemDetailsComponent { - - fun onDeleteClicked() -} - class DefaultItemListComponent( componentContext: ComponentContext, private val onItemSelected: (id: Long) -> Unit, @@ -239,6 +261,11 @@ class DefaultItemListComponent( } } +interface ItemDetailsComponent { + + fun onDeleteClicked() +} + class DefaultItemDetailsComponent( componentContext: ComponentContext, private val itemId: Long, @@ -247,9 +274,15 @@ class DefaultItemDetailsComponent( override fun onDeleteClicked() { // TODO: Delete the item - onDeleted(itemId = itemId) + onDeleted(itemId) } } +``` + +```kotlin title="Root component" +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.router.stack.pop +import com.arkivanov.decompose.router.stack.push class DefaultRootComponent( componentContext: ComponentContext