Skip to content

Commit 3ea87d8

Browse files
committed
Promoted duplicate configurations feature to stable
1 parent f5b6b39 commit 3ea87d8

22 files changed

+261
-221
lines changed

decompose/api/android/decompose.api

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,25 @@ public final class com/arkivanov/decompose/DecomposeExperimentFlags {
6666
public final fun setDuplicateConfigurationsEnabled (Z)V
6767
}
6868

69+
public final class com/arkivanov/decompose/DecomposeSettings {
70+
public static final field Companion Lcom/arkivanov/decompose/DecomposeSettings$Companion;
71+
public fun <init> ()V
72+
public fun <init> (Z)V
73+
public synthetic fun <init> (ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
74+
public final fun component1 ()Z
75+
public final fun copy (Z)Lcom/arkivanov/decompose/DecomposeSettings;
76+
public static synthetic fun copy$default (Lcom/arkivanov/decompose/DecomposeSettings;ZILjava/lang/Object;)Lcom/arkivanov/decompose/DecomposeSettings;
77+
public fun equals (Ljava/lang/Object;)Z
78+
public final fun getDuplicateConfigurationsEnabled ()Z
79+
public fun hashCode ()I
80+
public fun toString ()Ljava/lang/String;
81+
}
82+
83+
public final class com/arkivanov/decompose/DecomposeSettings$Companion {
84+
public final fun getSettings ()Lcom/arkivanov/decompose/DecomposeSettings;
85+
public final fun setSettings (Lcom/arkivanov/decompose/DecomposeSettings;)V
86+
}
87+
6988
public final class com/arkivanov/decompose/DeeplinkUtilsKt {
7089
public static final fun handleDeepLink (Landroid/app/Activity;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
7190
}

decompose/api/decompose.klib.api

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,25 @@ final class <#A: out kotlin/Any> com.arkivanov.decompose.router.pages/Pages { //
482482
}
483483
}
484484

485+
final class com.arkivanov.decompose/DecomposeSettings { // com.arkivanov.decompose/DecomposeSettings|null[0]
486+
constructor <init>(kotlin/Boolean = ...) // com.arkivanov.decompose/DecomposeSettings.<init>|<init>(kotlin.Boolean){}[0]
487+
488+
final val duplicateConfigurationsEnabled // com.arkivanov.decompose/DecomposeSettings.duplicateConfigurationsEnabled|{}duplicateConfigurationsEnabled[0]
489+
final fun <get-duplicateConfigurationsEnabled>(): kotlin/Boolean // com.arkivanov.decompose/DecomposeSettings.duplicateConfigurationsEnabled.<get-duplicateConfigurationsEnabled>|<get-duplicateConfigurationsEnabled>(){}[0]
490+
491+
final fun component1(): kotlin/Boolean // com.arkivanov.decompose/DecomposeSettings.component1|component1(){}[0]
492+
final fun copy(kotlin/Boolean = ...): com.arkivanov.decompose/DecomposeSettings // com.arkivanov.decompose/DecomposeSettings.copy|copy(kotlin.Boolean){}[0]
493+
final fun equals(kotlin/Any?): kotlin/Boolean // com.arkivanov.decompose/DecomposeSettings.equals|equals(kotlin.Any?){}[0]
494+
final fun hashCode(): kotlin/Int // com.arkivanov.decompose/DecomposeSettings.hashCode|hashCode(){}[0]
495+
final fun toString(): kotlin/String // com.arkivanov.decompose/DecomposeSettings.toString|toString(){}[0]
496+
497+
final object Companion { // com.arkivanov.decompose/DecomposeSettings.Companion|null[0]
498+
final var settings // com.arkivanov.decompose/DecomposeSettings.Companion.settings|{}settings[0]
499+
final fun <get-settings>(): com.arkivanov.decompose/DecomposeSettings // com.arkivanov.decompose/DecomposeSettings.Companion.settings.<get-settings>|<get-settings>(){}[0]
500+
final fun <set-settings>(com.arkivanov.decompose/DecomposeSettings) // com.arkivanov.decompose/DecomposeSettings.Companion.settings.<set-settings>|<set-settings>(com.arkivanov.decompose.DecomposeSettings){}[0]
501+
}
502+
}
503+
485504
final class com.arkivanov.decompose/DefaultComponentContext : com.arkivanov.decompose/ComponentContext { // com.arkivanov.decompose/DefaultComponentContext|null[0]
486505
constructor <init>(com.arkivanov.essenty.lifecycle/Lifecycle) // com.arkivanov.decompose/DefaultComponentContext.<init>|<init>(com.arkivanov.essenty.lifecycle.Lifecycle){}[0]
487506
constructor <init>(com.arkivanov.essenty.lifecycle/Lifecycle, com.arkivanov.essenty.statekeeper/StateKeeper? = ..., com.arkivanov.essenty.instancekeeper/InstanceKeeper? = ..., com.arkivanov.essenty.backhandler/BackHandler? = ...) // com.arkivanov.decompose/DefaultComponentContext.<init>|<init>(com.arkivanov.essenty.lifecycle.Lifecycle;com.arkivanov.essenty.statekeeper.StateKeeper?;com.arkivanov.essenty.instancekeeper.InstanceKeeper?;com.arkivanov.essenty.backhandler.BackHandler?){}[0]

decompose/api/jvm/decompose.api

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,25 @@ public final class com/arkivanov/decompose/DecomposeExperimentFlags {
6666
public final fun setDuplicateConfigurationsEnabled (Z)V
6767
}
6868

69+
public final class com/arkivanov/decompose/DecomposeSettings {
70+
public static final field Companion Lcom/arkivanov/decompose/DecomposeSettings$Companion;
71+
public fun <init> ()V
72+
public fun <init> (Z)V
73+
public synthetic fun <init> (ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
74+
public final fun component1 ()Z
75+
public final fun copy (Z)Lcom/arkivanov/decompose/DecomposeSettings;
76+
public static synthetic fun copy$default (Lcom/arkivanov/decompose/DecomposeSettings;ZILjava/lang/Object;)Lcom/arkivanov/decompose/DecomposeSettings;
77+
public fun equals (Ljava/lang/Object;)Z
78+
public final fun getDuplicateConfigurationsEnabled ()Z
79+
public fun hashCode ()I
80+
public fun toString ()Ljava/lang/String;
81+
}
82+
83+
public final class com/arkivanov/decompose/DecomposeSettings$Companion {
84+
public final fun getSettings ()Lcom/arkivanov/decompose/DecomposeSettings;
85+
public final fun setSettings (Lcom/arkivanov/decompose/DecomposeSettings;)V
86+
}
87+
6988
public final class com/arkivanov/decompose/DefaultComponentContext : com/arkivanov/decompose/ComponentContext {
7089
public fun <init> (Lcom/arkivanov/essenty/lifecycle/Lifecycle;)V
7190
public fun <init> (Lcom/arkivanov/essenty/lifecycle/Lifecycle;Lcom/arkivanov/essenty/statekeeper/StateKeeper;Lcom/arkivanov/essenty/instancekeeper/InstanceKeeper;Lcom/arkivanov/essenty/backhandler/BackHandler;)V

decompose/src/commonMain/kotlin/com/arkivanov/decompose/DecomposeExperimentFlags.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,12 @@ package com.arkivanov.decompose
33
@ExperimentalDecomposeApi
44
object DecomposeExperimentFlags {
55

6-
var duplicateConfigurationsEnabled: Boolean = false
6+
@Deprecated(
7+
message = "The feature has been promoted to stable. Please use DecomposeSettings.duplicateConfigurationsEnabled instead.",
8+
)
9+
var duplicateConfigurationsEnabled: Boolean
10+
get() = DecomposeSettings.settings.duplicateConfigurationsEnabled
11+
set(value) {
12+
DecomposeSettings.settings = DecomposeSettings.settings.copy(duplicateConfigurationsEnabled = value)
13+
}
714
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.arkivanov.decompose
2+
3+
import kotlin.concurrent.Volatile
4+
5+
/**
6+
* Global Decompose settings. Use [DecomposeSettings.settings] property to change the settings.
7+
*
8+
* @param duplicateConfigurationsEnabled controls whether duplicate configurations are enabled or not. Default value is `false`.
9+
* Excludes the `Child Items` navigation model, which doesn't support duplicate configurations.
10+
*/
11+
data class DecomposeSettings(
12+
val duplicateConfigurationsEnabled: Boolean = false,
13+
) {
14+
15+
companion object {
16+
@Volatile
17+
var settings: DecomposeSettings = DecomposeSettings()
18+
}
19+
}

decompose/src/commonMain/kotlin/com/arkivanov/decompose/Utils.kt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,22 @@ internal expect val KClass<*>.uniqueName: String?
1515

1616
internal val Lifecycle.isDestroyed: Boolean get() = state == Lifecycle.State.DESTROYED
1717

18-
internal fun <T : Any, C : Any> List<T>.keyed(configuration: (T) -> C): Map<Any, T> {
19-
val numbers = HashMap<C, Int>()
18+
internal fun <T : Any, C : Any> List<T>.keyed(configuration: (T) -> C): Map<ItemKey, T> {
19+
val indices = HashMap<C, Int>()
2020

2121
return associateBy { item ->
2222
val config = configuration(item)
23-
val number = (numbers[config] ?: 0) + 1
24-
numbers[config] = number
25-
config to number
23+
val index = indices[config]?.plus(1) ?: 0
24+
indices[config] = index
25+
ItemKey(config, index)
2626
}
2727
}
2828

29+
internal data class ItemKey(
30+
private val value: Any,
31+
private val index: Int,
32+
)
33+
2934
internal fun <T : Any> Iterable<T>.findFirstDuplicate(set: Set<T>): Pair<Int, T>? {
3035
val iter1 = iterator()
3136
val iter2 = set.iterator()

decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/children/ChildItem.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,28 @@ internal sealed interface ChildItem<out C : Any, out T : Any> {
1010

1111
val configuration: C
1212
val instance: T?
13+
val lifecycleRegistry: LifecycleRegistry?
14+
val stateKeeperDispatcher: StateKeeperDispatcher?
15+
val instanceKeeperDispatcher: InstanceKeeperDispatcher?
16+
val backHandler: ChildBackHandler?
1317

1418
data class Created<out C : Any, out T : Any>(
1519
override val configuration: C,
1620
override val instance: T,
17-
val lifecycleRegistry: LifecycleRegistry,
18-
val stateKeeperDispatcher: StateKeeperDispatcher,
19-
val instanceKeeperDispatcher: InstanceKeeperDispatcher,
20-
val backHandler: ChildBackHandler,
21+
override val lifecycleRegistry: LifecycleRegistry,
22+
override val stateKeeperDispatcher: StateKeeperDispatcher,
23+
override val instanceKeeperDispatcher: InstanceKeeperDispatcher,
24+
override val backHandler: ChildBackHandler,
2125
) : ChildItem<C, T>
2226

2327
data class Destroyed<out C : Any>(
2428
override val configuration: C,
2529
val savedState: SerializableContainer? = null
2630
) : ChildItem<C, Nothing> {
2731
override val instance: Nothing? = null
32+
override val lifecycleRegistry: LifecycleRegistry? = null
33+
override val stateKeeperDispatcher: StateKeeperDispatcher? = null
34+
override val instanceKeeperDispatcher: InstanceKeeperDispatcher? = null
35+
override val backHandler: ChildBackHandler? = null
2836
}
2937
}

decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/children/ChildrenFactory.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,12 @@ fun <Ctx : GenericComponentContext<Ctx>, C : Any, T : Any, E : Any, N : NavState
6969
* The API is based around [NavState] and [ChildNavState] interfaces that should be implemented by
7070
* clients. [NavState] represents a persistent state of the navigation. It also holds a navigation
7171
* state for each child - [ChildNavState]. Both [NavState] and [ChildNavState] must be immutable, and
72-
* correctly implement `equals` and `hashCode` methods (or just be data classes). There must be no
73-
* duplicated (by equality) [ChildNavState.configuration] within a [NavState].
72+
* correctly implement `equals` and `hashCode` methods (or just be data classes).
73+
*
74+
* By default, having duplicate (by equality) configurations ([ChildNavState.configuration]) within
75+
* a [NavState] is prohibited. Decompose will throw an exception when detected. However, duplicate
76+
* configurations can be enabled by setting the
77+
* [com.arkivanov.decompose.DecomposeSettings.duplicateConfigurationsEnabled] flag to `true`.
7478
*
7579
* The navigation is performed by transforming the current [NavState] to a new one. The implementation
7680
* calculates diffs between the old list of [ChildNavState] and the new one, and manipulates child

0 commit comments

Comments
 (0)