From 06f4a036149b66ef6fcc619a1de9d874208ddf29 Mon Sep 17 00:00:00 2001 From: Arkadii Ivanov Date: Sun, 28 Jul 2024 00:22:01 +0100 Subject: [PATCH] Annotate StackNavigator#push as delicate API --- decompose/api/android/decompose.api | 3 +++ decompose/api/decompose.klib.api | 3 +++ decompose/api/jvm/decompose.api | 3 +++ .../kotlin/com/arkivanov/decompose/Annotations.kt | 8 ++++++++ .../arkivanov/decompose/router/stack/StackNavigatorExt.kt | 7 ++++++- docs/navigation/stack/navigation.md | 2 +- .../sample/shared/cards/DefaultCardsComponent.kt | 4 ++-- .../sample/shared/counters/DefaultCountersComponent.kt | 4 ++-- .../dynamicfeatures/DefaultDynamicFeaturesComponent.kt | 4 ++-- 9 files changed, 30 insertions(+), 8 deletions(-) diff --git a/decompose/api/android/decompose.api b/decompose/api/android/decompose.api index 0120a5109..0e49fac26 100644 --- a/decompose/api/android/decompose.api +++ b/decompose/api/android/decompose.api @@ -88,6 +88,9 @@ public final class com/arkivanov/decompose/DefaultComponentContextBuilderKt { public static synthetic fun defaultComponentContext$default (Landroidx/savedstate/SavedStateRegistryOwner;ZLkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/arkivanov/decompose/DefaultComponentContext; } +public abstract interface annotation class com/arkivanov/decompose/DelicateDecomposeApi : java/lang/annotation/Annotation { +} + public abstract interface annotation class com/arkivanov/decompose/ExperimentalDecomposeApi : java/lang/annotation/Annotation { } diff --git a/decompose/api/decompose.klib.api b/decompose/api/decompose.klib.api index d0ff66aa7..f09c3344b 100644 --- a/decompose/api/decompose.klib.api +++ b/decompose/api/decompose.klib.api @@ -250,6 +250,9 @@ final val com.arkivanov.decompose.router.stack/items // com.arkivanov.decompose. final var com.arkivanov.decompose.errorhandler/onDecomposeError // com.arkivanov.decompose.errorhandler/onDecomposeError|{}onDecomposeError[0] final fun (): kotlin/Function1 // com.arkivanov.decompose.errorhandler/onDecomposeError.|(){}[0] final fun (kotlin/Function1) // com.arkivanov.decompose.errorhandler/onDecomposeError.|(kotlin.Function1){}[0] +open annotation class com.arkivanov.decompose/DelicateDecomposeApi : kotlin/Annotation { // com.arkivanov.decompose/DelicateDecomposeApi|null[0] + constructor () // com.arkivanov.decompose/DelicateDecomposeApi.|(){}[0] +} open annotation class com.arkivanov.decompose/ExperimentalDecomposeApi : kotlin/Annotation { // com.arkivanov.decompose/ExperimentalDecomposeApi|null[0] constructor () // com.arkivanov.decompose/ExperimentalDecomposeApi.|(){}[0] } diff --git a/decompose/api/jvm/decompose.api b/decompose/api/jvm/decompose.api index 9280659b0..9361550d2 100644 --- a/decompose/api/jvm/decompose.api +++ b/decompose/api/jvm/decompose.api @@ -75,6 +75,9 @@ public final class com/arkivanov/decompose/DefaultComponentContext : com/arkivan public fun getStateKeeper ()Lcom/arkivanov/essenty/statekeeper/StateKeeper; } +public abstract interface annotation class com/arkivanov/decompose/DelicateDecomposeApi : java/lang/annotation/Annotation { +} + public abstract interface annotation class com/arkivanov/decompose/ExperimentalDecomposeApi : java/lang/annotation/Annotation { } diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Annotations.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Annotations.kt index 33cf52357..36fb6c04e 100644 --- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Annotations.kt +++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Annotations.kt @@ -22,3 +22,11 @@ annotation class ExperimentalDecomposeApi @RequiresOptIn(level = RequiresOptIn.Level.WARNING) @Retention(AnnotationRetention.BINARY) annotation class FaultyDecomposeApi + +/** + * Marks delicate Decompose API that requires special attention when used. + * See the docs of the annotated API for more information. + */ +@RequiresOptIn(level = RequiresOptIn.Level.WARNING) +@Retention(AnnotationRetention.BINARY) +annotation class DelicateDecomposeApi diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackNavigatorExt.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackNavigatorExt.kt index b21de000c..bd8b85b56 100644 --- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackNavigatorExt.kt +++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackNavigatorExt.kt @@ -1,5 +1,7 @@ package com.arkivanov.decompose.router.stack +import com.arkivanov.decompose.DelicateDecomposeApi + /** * A convenience method for [StackNavigator.navigate]. */ @@ -11,12 +13,15 @@ fun StackNavigator.navigate(transformer: (stack: List) -> List StackNavigator.push(configuration: C, crossinline onComplete: () -> Unit = {}) { navigate(transformer = { it + configuration }, onComplete = { _, _ -> onComplete() }) } diff --git a/docs/navigation/stack/navigation.md b/docs/navigation/stack/navigation.md index 646aaf927..3ca13c639 100644 --- a/docs/navigation/stack/navigation.md +++ b/docs/navigation/stack/navigation.md @@ -30,7 +30,7 @@ There are `StackNavigator` [extension functions](https://github.com/arkivanov/De ### push(configuration) -Pushes the provided `Configuration` at the top of the stack. Decompose will throw an exception if the provided `Configuration` is already present in the stack. +Pushes the provided `Configuration` at the top of the stack. Decompose will throw an exception if the provided `Configuration` is already present in the stack. This usually happens when a component is pushed on user interaction (e.g. a button click). Consider using [pushNew](#pushnewconfiguration) instead. !!! note "Illustration" diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/cards/DefaultCardsComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/cards/DefaultCardsComponent.kt index b3230cdff..61c13de2f 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/cards/DefaultCardsComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/cards/DefaultCardsComponent.kt @@ -7,7 +7,7 @@ import com.arkivanov.decompose.router.stack.childStack import com.arkivanov.decompose.router.stack.items import com.arkivanov.decompose.router.stack.navigate import com.arkivanov.decompose.router.stack.pop -import com.arkivanov.decompose.router.stack.push +import com.arkivanov.decompose.router.stack.pushNew import com.arkivanov.decompose.value.Value import com.arkivanov.sample.shared.cards.card.CardComponent import com.arkivanov.sample.shared.cards.card.DefaultCardComponent @@ -54,7 +54,7 @@ class DefaultCardsComponent( val maxNumber = _stack.items.maxOf { it.configuration.number } - navigation.push( + navigation.pushNew( Config( color = COLORS[maxNumber % COLORS.size], number = maxNumber + 1, diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/DefaultCountersComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/DefaultCountersComponent.kt index e61e9039f..cc033cafb 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/DefaultCountersComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/DefaultCountersComponent.kt @@ -6,7 +6,7 @@ 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.popTo -import com.arkivanov.decompose.router.stack.push +import com.arkivanov.decompose.router.stack.pushNew import com.arkivanov.decompose.value.Value import com.arkivanov.sample.shared.counters.counter.CounterComponent import com.arkivanov.sample.shared.counters.counter.DefaultCounterComponent @@ -36,7 +36,7 @@ internal class DefaultCountersComponent( componentContext = componentContext, title = "Counter ${config.index}", isBackEnabled = config.isBackEnabled, - onNext = { navigation.push(Config(index = config.index + 1, isBackEnabled = true)) }, + onNext = { navigation.pushNew(Config(index = config.index + 1, isBackEnabled = true)) }, onPrev = navigation::pop, ) diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DefaultDynamicFeaturesComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DefaultDynamicFeaturesComponent.kt index 33bdd905e..e2f5352be 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DefaultDynamicFeaturesComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DefaultDynamicFeaturesComponent.kt @@ -5,7 +5,7 @@ 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.router.stack.pushNew import com.arkivanov.decompose.value.Value import com.arkivanov.sample.shared.dynamicfeatures.DynamicFeaturesComponent.Child import com.arkivanov.sample.shared.dynamicfeatures.DynamicFeaturesComponent.Child.Feature1Child @@ -51,7 +51,7 @@ internal class DefaultDynamicFeaturesComponent( factory = { featureComponentContext -> Feature1( componentContext = featureComponentContext, - onFeature2 = { navigation.push(Config.Feature2(magicNumber = Random.nextInt())) }, + onFeature2 = { navigation.pushNew(Config.Feature2(magicNumber = Random.nextInt())) }, ) } )