Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotate StackNavigator#push as delicate API #747

Merged
merged 1 commit into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions decompose/api/android/decompose.api
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
}

Expand Down
3 changes: 3 additions & 0 deletions decompose/api/decompose.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -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 <get-onDecomposeError>(): kotlin/Function1<kotlin/Exception, kotlin/Unit> // com.arkivanov.decompose.errorhandler/onDecomposeError.<get-onDecomposeError>|<get-onDecomposeError>(){}[0]
final fun <set-onDecomposeError>(kotlin/Function1<kotlin/Exception, kotlin/Unit>) // com.arkivanov.decompose.errorhandler/onDecomposeError.<set-onDecomposeError>|<set-onDecomposeError>(kotlin.Function1<kotlin.Exception,kotlin.Unit>){}[0]
open annotation class com.arkivanov.decompose/DelicateDecomposeApi : kotlin/Annotation { // com.arkivanov.decompose/DelicateDecomposeApi|null[0]
constructor <init>() // com.arkivanov.decompose/DelicateDecomposeApi.<init>|<init>(){}[0]
}
open annotation class com.arkivanov.decompose/ExperimentalDecomposeApi : kotlin/Annotation { // com.arkivanov.decompose/ExperimentalDecomposeApi|null[0]
constructor <init>() // com.arkivanov.decompose/ExperimentalDecomposeApi.<init>|<init>(){}[0]
}
Expand Down
3 changes: 3 additions & 0 deletions decompose/api/jvm/decompose.api
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend marking the level as ERROR to force people to read the description. Otherwise the issue may persist

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I will keep it as warning for now, similar to DelicateCoroutinesApi.

@Retention(AnnotationRetention.BINARY)
annotation class DelicateDecomposeApi
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.arkivanov.decompose.router.stack

import com.arkivanov.decompose.DelicateDecomposeApi

/**
* A convenience method for [StackNavigator.navigate].
*/
Expand All @@ -11,12 +13,15 @@ fun <C : Any> StackNavigator<C>.navigate(transformer: (stack: List<C>) -> List<C
* 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] instead.
* You can also try enabling the experimental
* [Duplicate Configurations][com.arkivanov.decompose.DecomposeExperimentFlags.duplicateConfigurationsEnabled] feature
* to avoid the error.
* to avoid the error. But still, pushing duplicated components on top of the stack might be wrong.
*
* @param onComplete called when the navigation is finished (either synchronously or asynchronously).
*/
@DelicateDecomposeApi
inline fun <C : Any> StackNavigator<C>.push(configuration: C, crossinline onComplete: () -> Unit = {}) {
navigate(transformer = { it + configuration }, onComplete = { _, _ -> onComplete() })
}
Expand Down
2 changes: 1 addition & 1 deletion docs/navigation/stack/navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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())) },
)
}
)
Expand Down
Loading