Skip to content

Commit 0b455cf

Browse files
authored
Merge pull request #957 from arkivanov/child-key-3
Change Child#key type from Any to String and promote it to stable
2 parents f6d4b8d + 56b4128 commit 0b455cf

File tree

27 files changed

+561
-319
lines changed

27 files changed

+561
-319
lines changed

decompose-test-utils/src/commonMain/kotlin/com/arkivanov/decompose/testutils/TestUtils.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package com.arkivanov.decompose.testutils
22

3+
import com.arkivanov.decompose.Child
34
import com.arkivanov.decompose.value.Value
45
import com.arkivanov.essenty.statekeeper.StateKeeper
56
import com.arkivanov.essenty.statekeeper.StateKeeperDispatcher
6-
import kotlin.reflect.KProperty
77
import kotlinx.serialization.json.Json
88
import kotlinx.serialization.serializer
9+
import kotlin.reflect.KProperty
910

1011
@PublishedApi
1112
internal val json =
@@ -32,3 +33,5 @@ fun StateKeeperDispatcher.recreate(isConfigurationChange: Boolean = false): Stat
3233
)
3334

3435
operator fun <T : Any> Value<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
36+
37+
val List<Child<*, *>>.keys: List<String> get() = map { it.key }

decompose/api/android/decompose.api

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,41 @@ public abstract interface class com/arkivanov/decompose/Cancellation {
55
public abstract class com/arkivanov/decompose/Child {
66
public abstract fun getConfiguration ()Ljava/lang/Object;
77
public abstract fun getInstance ()Ljava/lang/Object;
8-
public abstract fun getKey ()Ljava/lang/Object;
8+
public abstract fun getKey ()Ljava/lang/String;
99
}
1010

1111
public final class com/arkivanov/decompose/Child$Created : com/arkivanov/decompose/Child {
1212
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
13-
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
13+
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)V
1414
public final fun component1 ()Ljava/lang/Object;
1515
public final fun component2 ()Ljava/lang/Object;
16-
public final fun component3 ()Ljava/lang/Object;
16+
public final fun component3 ()Ljava/lang/String;
1717
public final synthetic fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child;
18-
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
19-
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Created;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
18+
public final synthetic fun copy (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
19+
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)Lcom/arkivanov/decompose/Child$Created;
20+
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Created;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
2021
public fun equals (Ljava/lang/Object;)Z
2122
public fun getConfiguration ()Ljava/lang/Object;
2223
public fun getInstance ()Ljava/lang/Object;
23-
public fun getKey ()Ljava/lang/Object;
24+
public fun getKey ()Ljava/lang/String;
2425
public fun hashCode ()I
2526
public fun toString ()Ljava/lang/String;
2627
}
2728

2829
public final class com/arkivanov/decompose/Child$Destroyed : com/arkivanov/decompose/Child {
2930
public fun <init> (Ljava/lang/Object;)V
30-
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
31+
public fun <init> (Ljava/lang/Object;Ljava/lang/String;)V
3132
public final fun component1 ()Ljava/lang/Object;
32-
public final fun component2 ()Ljava/lang/Object;
33+
public final fun component2 ()Ljava/lang/String;
3334
public final synthetic fun copy (Ljava/lang/Object;)Lcom/arkivanov/decompose/Child;
34-
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
35-
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Destroyed;Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
35+
public final synthetic fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
36+
public final fun copy (Ljava/lang/Object;Ljava/lang/String;)Lcom/arkivanov/decompose/Child$Destroyed;
37+
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Destroyed;Ljava/lang/Object;Ljava/lang/String;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
3638
public fun equals (Ljava/lang/Object;)Z
3739
public fun getConfiguration ()Ljava/lang/Object;
3840
public synthetic fun getInstance ()Ljava/lang/Object;
3941
public fun getInstance ()Ljava/lang/Void;
40-
public fun getKey ()Ljava/lang/Object;
42+
public fun getKey ()Ljava/lang/String;
4143
public fun hashCode ()I
4244
public fun toString ()Ljava/lang/String;
4345
}
@@ -567,7 +569,7 @@ public final class com/arkivanov/decompose/router/stack/ChildStack {
567569
public fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)V
568570
public synthetic fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
569571
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
570-
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
572+
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)V
571573
public final fun component1 ()Lcom/arkivanov/decompose/Child$Created;
572574
public final fun component2 ()Ljava/util/List;
573575
public final fun copy (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)Lcom/arkivanov/decompose/router/stack/ChildStack;

decompose/api/decompose.klib.api

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ final class <#A: out kotlin/Any, #B: out kotlin/Any> com.arkivanov.decompose.rou
410410

411411
final class <#A: out kotlin/Any, #B: out kotlin/Any> com.arkivanov.decompose.router.stack/ChildStack { // com.arkivanov.decompose.router.stack/ChildStack|null[0]
412412
constructor <init>(#A, #B) // com.arkivanov.decompose.router.stack/ChildStack.<init>|<init>(1:0;1:1){}[0]
413-
constructor <init>(#A, #B, kotlin/Any) // com.arkivanov.decompose.router.stack/ChildStack.<init>|<init>(1:0;1:1;kotlin.Any){}[0]
413+
constructor <init>(#A, #B, kotlin/String) // com.arkivanov.decompose.router.stack/ChildStack.<init>|<init>(1:0;1:1;kotlin.String){}[0]
414414
constructor <init>(com.arkivanov.decompose/Child.Created<#A, #B>, kotlin.collections/List<com.arkivanov.decompose/Child.Created<#A, #B>> = ...) // com.arkivanov.decompose.router.stack/ChildStack.<init>|<init>(com.arkivanov.decompose.Child.Created<1:0,1:1>;kotlin.collections.List<com.arkivanov.decompose.Child.Created<1:0,1:1>>){}[0]
415415

416416
final val active // com.arkivanov.decompose.router.stack/ChildStack.active|{}active[0]
@@ -523,44 +523,46 @@ sealed class <#A: out kotlin/Any, #B: out kotlin/Any> com.arkivanov.decompose/Ch
523523
abstract val instance // com.arkivanov.decompose/Child.instance|{}instance[0]
524524
abstract fun <get-instance>(): #B? // com.arkivanov.decompose/Child.instance.<get-instance>|<get-instance>(){}[0]
525525
abstract val key // com.arkivanov.decompose/Child.key|{}key[0]
526-
abstract fun <get-key>(): kotlin/Any // com.arkivanov.decompose/Child.key.<get-key>|<get-key>(){}[0]
526+
abstract fun <get-key>(): kotlin/String // com.arkivanov.decompose/Child.key.<get-key>|<get-key>(){}[0]
527527

528528
final class <#A1: out kotlin/Any, #B1: out kotlin/Any> Created : com.arkivanov.decompose/Child<#A1, #B1> { // com.arkivanov.decompose/Child.Created|null[0]
529529
constructor <init>(#A1, #B1) // com.arkivanov.decompose/Child.Created.<init>|<init>(1:0;1:1){}[0]
530-
constructor <init>(#A1, #B1, kotlin/Any) // com.arkivanov.decompose/Child.Created.<init>|<init>(1:0;1:1;kotlin.Any){}[0]
530+
constructor <init>(#A1, #B1, kotlin/String) // com.arkivanov.decompose/Child.Created.<init>|<init>(1:0;1:1;kotlin.String){}[0]
531531

532532
final val configuration // com.arkivanov.decompose/Child.Created.configuration|{}configuration[0]
533533
final fun <get-configuration>(): #A1 // com.arkivanov.decompose/Child.Created.configuration.<get-configuration>|<get-configuration>(){}[0]
534534
final val instance // com.arkivanov.decompose/Child.Created.instance|{}instance[0]
535535
final fun <get-instance>(): #B1 // com.arkivanov.decompose/Child.Created.instance.<get-instance>|<get-instance>(){}[0]
536536
final val key // com.arkivanov.decompose/Child.Created.key|{}key[0]
537-
final fun <get-key>(): kotlin/Any // com.arkivanov.decompose/Child.Created.key.<get-key>|<get-key>(){}[0]
537+
final fun <get-key>(): kotlin/String // com.arkivanov.decompose/Child.Created.key.<get-key>|<get-key>(){}[0]
538538

539539
final fun component1(): #A1 // com.arkivanov.decompose/Child.Created.component1|component1(){}[0]
540540
final fun component2(): #B1 // com.arkivanov.decompose/Child.Created.component2|component2(){}[0]
541-
final fun component3(): kotlin/Any // com.arkivanov.decompose/Child.Created.component3|component3(){}[0]
542-
final fun copy(#A1 = ..., #B1 = ..., kotlin/Any = ...): com.arkivanov.decompose/Child.Created<#A1, #B1> // com.arkivanov.decompose/Child.Created.copy|copy(1:0;1:1;kotlin.Any){}[0]
541+
final fun component3(): kotlin/String // com.arkivanov.decompose/Child.Created.component3|component3(){}[0]
542+
final fun copy(#A1 = ..., #B1 = ..., kotlin/String = ...): com.arkivanov.decompose/Child.Created<#A1, #B1> // com.arkivanov.decompose/Child.Created.copy|copy(1:0;1:1;kotlin.String){}[0]
543543
final fun copy(#A1, #B1): com.arkivanov.decompose/Child<#A1, #B1> // com.arkivanov.decompose/Child.Created.copy|copy(1:0;1:1){}[0]
544+
final fun copy(#A1, #B1, kotlin/Any): com.arkivanov.decompose/Child.Created<#A1, #B1> // com.arkivanov.decompose/Child.Created.copy|copy(1:0;1:1;kotlin.Any){}[0]
544545
final fun equals(kotlin/Any?): kotlin/Boolean // com.arkivanov.decompose/Child.Created.equals|equals(kotlin.Any?){}[0]
545546
final fun hashCode(): kotlin/Int // com.arkivanov.decompose/Child.Created.hashCode|hashCode(){}[0]
546547
final fun toString(): kotlin/String // com.arkivanov.decompose/Child.Created.toString|toString(){}[0]
547548
}
548549

549550
final class <#A1: out kotlin/Any> Destroyed : com.arkivanov.decompose/Child<#A1, kotlin/Nothing> { // com.arkivanov.decompose/Child.Destroyed|null[0]
550551
constructor <init>(#A1) // com.arkivanov.decompose/Child.Destroyed.<init>|<init>(1:0){}[0]
551-
constructor <init>(#A1, kotlin/Any) // com.arkivanov.decompose/Child.Destroyed.<init>|<init>(1:0;kotlin.Any){}[0]
552+
constructor <init>(#A1, kotlin/String) // com.arkivanov.decompose/Child.Destroyed.<init>|<init>(1:0;kotlin.String){}[0]
552553

553554
final val configuration // com.arkivanov.decompose/Child.Destroyed.configuration|{}configuration[0]
554555
final fun <get-configuration>(): #A1 // com.arkivanov.decompose/Child.Destroyed.configuration.<get-configuration>|<get-configuration>(){}[0]
555556
final val instance // com.arkivanov.decompose/Child.Destroyed.instance|{}instance[0]
556557
final fun <get-instance>(): kotlin/Nothing? // com.arkivanov.decompose/Child.Destroyed.instance.<get-instance>|<get-instance>(){}[0]
557558
final val key // com.arkivanov.decompose/Child.Destroyed.key|{}key[0]
558-
final fun <get-key>(): kotlin/Any // com.arkivanov.decompose/Child.Destroyed.key.<get-key>|<get-key>(){}[0]
559+
final fun <get-key>(): kotlin/String // com.arkivanov.decompose/Child.Destroyed.key.<get-key>|<get-key>(){}[0]
559560

560561
final fun component1(): #A1 // com.arkivanov.decompose/Child.Destroyed.component1|component1(){}[0]
561-
final fun component2(): kotlin/Any // com.arkivanov.decompose/Child.Destroyed.component2|component2(){}[0]
562-
final fun copy(#A1 = ..., kotlin/Any = ...): com.arkivanov.decompose/Child.Destroyed<#A1> // com.arkivanov.decompose/Child.Destroyed.copy|copy(1:0;kotlin.Any){}[0]
562+
final fun component2(): kotlin/String // com.arkivanov.decompose/Child.Destroyed.component2|component2(){}[0]
563+
final fun copy(#A1 = ..., kotlin/String = ...): com.arkivanov.decompose/Child.Destroyed<#A1> // com.arkivanov.decompose/Child.Destroyed.copy|copy(1:0;kotlin.String){}[0]
563564
final fun copy(#A1): com.arkivanov.decompose/Child<#A1, kotlin/Nothing> // com.arkivanov.decompose/Child.Destroyed.copy|copy(1:0){}[0]
565+
final fun copy(#A1, kotlin/Any): com.arkivanov.decompose/Child.Destroyed<#A1> // com.arkivanov.decompose/Child.Destroyed.copy|copy(1:0;kotlin.Any){}[0]
564566
final fun equals(kotlin/Any?): kotlin/Boolean // com.arkivanov.decompose/Child.Destroyed.equals|equals(kotlin.Any?){}[0]
565567
final fun hashCode(): kotlin/Int // com.arkivanov.decompose/Child.Destroyed.hashCode|hashCode(){}[0]
566568
final fun toString(): kotlin/String // com.arkivanov.decompose/Child.Destroyed.toString|toString(){}[0]

decompose/api/jvm/decompose.api

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,41 @@ public abstract interface class com/arkivanov/decompose/Cancellation {
55
public abstract class com/arkivanov/decompose/Child {
66
public abstract fun getConfiguration ()Ljava/lang/Object;
77
public abstract fun getInstance ()Ljava/lang/Object;
8-
public abstract fun getKey ()Ljava/lang/Object;
8+
public abstract fun getKey ()Ljava/lang/String;
99
}
1010

1111
public final class com/arkivanov/decompose/Child$Created : com/arkivanov/decompose/Child {
1212
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
13-
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
13+
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)V
1414
public final fun component1 ()Ljava/lang/Object;
1515
public final fun component2 ()Ljava/lang/Object;
16-
public final fun component3 ()Ljava/lang/Object;
16+
public final fun component3 ()Ljava/lang/String;
1717
public final synthetic fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child;
18-
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
19-
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Created;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
18+
public final synthetic fun copy (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
19+
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)Lcom/arkivanov/decompose/Child$Created;
20+
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Created;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
2021
public fun equals (Ljava/lang/Object;)Z
2122
public fun getConfiguration ()Ljava/lang/Object;
2223
public fun getInstance ()Ljava/lang/Object;
23-
public fun getKey ()Ljava/lang/Object;
24+
public fun getKey ()Ljava/lang/String;
2425
public fun hashCode ()I
2526
public fun toString ()Ljava/lang/String;
2627
}
2728

2829
public final class com/arkivanov/decompose/Child$Destroyed : com/arkivanov/decompose/Child {
2930
public fun <init> (Ljava/lang/Object;)V
30-
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
31+
public fun <init> (Ljava/lang/Object;Ljava/lang/String;)V
3132
public final fun component1 ()Ljava/lang/Object;
32-
public final fun component2 ()Ljava/lang/Object;
33+
public final fun component2 ()Ljava/lang/String;
3334
public final synthetic fun copy (Ljava/lang/Object;)Lcom/arkivanov/decompose/Child;
34-
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
35-
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Destroyed;Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
35+
public final synthetic fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
36+
public final fun copy (Ljava/lang/Object;Ljava/lang/String;)Lcom/arkivanov/decompose/Child$Destroyed;
37+
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Destroyed;Ljava/lang/Object;Ljava/lang/String;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
3638
public fun equals (Ljava/lang/Object;)Z
3739
public fun getConfiguration ()Ljava/lang/Object;
3840
public synthetic fun getInstance ()Ljava/lang/Object;
3941
public fun getInstance ()Ljava/lang/Void;
40-
public fun getKey ()Ljava/lang/Object;
42+
public fun getKey ()Ljava/lang/String;
4143
public fun hashCode ()I
4244
public fun toString ()Ljava/lang/String;
4345
}
@@ -547,7 +549,7 @@ public final class com/arkivanov/decompose/router/stack/ChildStack {
547549
public fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)V
548550
public synthetic fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
549551
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
550-
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
552+
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)V
551553
public final fun component1 ()Lcom/arkivanov/decompose/Child$Created;
552554
public final fun component2 ()Ljava/util/List;
553555
public final fun copy (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)Lcom/arkivanov/decompose/router/stack/ChildStack;
Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,64 @@
11
package com.arkivanov.decompose
22

3+
/**
4+
* A holder class for child [configuration], [instance] and [key].
5+
*/
36
sealed class Child<out C : Any, out T : Any> {
47

8+
/**
9+
* A configuration object the child was originally created with.
10+
*/
511
abstract val configuration: C
12+
13+
/**
14+
* The actual child instance.
15+
*/
616
abstract val instance: T?
717

8-
@ExperimentalDecomposeApi
9-
abstract val key: Any
18+
/**
19+
* A key of the child, unique within the navigation model managing the child.
20+
*/
21+
abstract val key: String
1022

11-
data class Created<out C : Any, out T : Any> @ExperimentalDecomposeApi constructor(
23+
data class Created<out C : Any, out T : Any>(
1224
override val configuration: C,
1325
override val instance: T,
14-
15-
@property:ExperimentalDecomposeApi
16-
override val key: Any,
26+
override val key: String,
1727
) : Child<C, T>() {
28+
// TODO: Annotate with @VisibleForTesting in version 4.0
1829
constructor(configuration: C, instance: T) : this(
1930
configuration = configuration,
2031
instance = instance,
21-
key = configuration,
32+
key = configuration.hashString(),
2233
)
2334

2435
@Deprecated(message = "For binary compatibility", level = DeprecationLevel.HIDDEN)
2536
fun copy(configuration: @UnsafeVariance C, instance: @UnsafeVariance T): Child<C, T> =
2637
copy(configuration = configuration, instance = instance)
38+
39+
@Deprecated(message = "For binary compatibility", level = DeprecationLevel.HIDDEN)
40+
fun copy(configuration: @UnsafeVariance C, instance: @UnsafeVariance T, key: Any): Created<C, T> =
41+
copy(configuration = configuration, instance = instance, key = key.toString())
2742
}
2843

2944
data class Destroyed<out C : Any> @ExperimentalDecomposeApi constructor(
3045
override val configuration: C,
31-
32-
@property:ExperimentalDecomposeApi
33-
override val key: Any,
46+
override val key: String,
3447
) : Child<C, Nothing>() {
48+
// TODO: Annotate with @VisibleForTesting in version 4.0
3549
constructor(configuration: C) : this(
3650
configuration = configuration,
37-
key = configuration,
51+
key = configuration.hashString(),
3852
)
3953

4054
override val instance: Nothing? = null
4155

4256
@Deprecated(message = "For binary compatibility", level = DeprecationLevel.HIDDEN)
4357
fun copy(configuration: @UnsafeVariance C): Child<C, Nothing> =
4458
copy(configuration = configuration)
59+
60+
@Deprecated(message = "For binary compatibility", level = DeprecationLevel.HIDDEN)
61+
fun copy(configuration: @UnsafeVariance C, key: Any): Destroyed<C> =
62+
copy(configuration = configuration, key = key.toString())
4563
}
4664
}

0 commit comments

Comments
 (0)