Skip to content

Commit 66d377d

Browse files
authored
Merge pull request #737 from square/ray/vek-merge
Introduces ViewEnvironmentKey.combine, makes ViewRegistry use it.
2 parents a6fa11c + 85b3449 commit 66d377d

File tree

13 files changed

+100
-111
lines changed

13 files changed

+100
-111
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ android.useAndroidX=true
88
systemProp.org.gradle.internal.publish.checksums.insecure=true
99

1010
GROUP=com.squareup.workflow1
11-
VERSION_NAME=1.8.0-uiUpdate03-SNAPSHOT
11+
VERSION_NAME=1.8.0-uiUpdate04-SNAPSHOT
1212

1313
POM_DESCRIPTION=Square Workflow
1414

workflow-ui/core-android/api/core-android.api

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,12 @@ public abstract interface class com/squareup/workflow1/ui/ScreenViewHolder {
199199
}
200200

201201
public final class com/squareup/workflow1/ui/ScreenViewHolder$Companion {
202-
public final fun getShowing ()Lcom/squareup/workflow1/ui/ViewEnvironmentKey;
202+
}
203+
204+
public final class com/squareup/workflow1/ui/ScreenViewHolder$Companion$Showing : com/squareup/workflow1/ui/ViewEnvironmentKey {
205+
public static final field INSTANCE Lcom/squareup/workflow1/ui/ScreenViewHolder$Companion$Showing;
206+
public fun getDefault ()Lcom/squareup/workflow1/ui/Screen;
207+
public synthetic fun getDefault ()Ljava/lang/Object;
203208
}
204209

205210
public final class com/squareup/workflow1/ui/ScreenViewHolder$Companion$ShowingNothing : com/squareup/workflow1/ui/Screen {

workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/ScreenViewHolder.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ public interface ScreenViewHolder<in ScreenT : Screen> {
4444
* Provides access to the [Screen] instance most recently shown in a [ScreenViewHolder]'s
4545
* [view] via [show]. Call [showing] for more convenient access.
4646
*/
47-
public val Showing: ViewEnvironmentKey<Screen> = ViewEnvironmentKey { ShowingNothing }
47+
public object Showing : ViewEnvironmentKey<Screen>(Screen::class) {
48+
override val default: Screen = ShowingNothing
49+
}
4850
}
4951
}
5052

workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/BackStackContainer.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.squareup.workflow1.ui.Compatible.Companion.keyFor
2020
import com.squareup.workflow1.ui.NamedScreen
2121
import com.squareup.workflow1.ui.R
2222
import com.squareup.workflow1.ui.ScreenViewHolder
23+
import com.squareup.workflow1.ui.ScreenViewHolder.Companion.Showing
2324
import com.squareup.workflow1.ui.ViewEnvironment
2425
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
2526
import com.squareup.workflow1.ui.androidx.WorkflowAndroidXSupport.stateRegistryOwnerFromViewTreeOrContext
@@ -65,7 +66,7 @@ public open class BackStackContainer @JvmOverloads constructor(
6566
newRendering: BackStackScreen<*>,
6667
newViewEnvironment: ViewEnvironment
6768
) {
68-
savedStateParentKey = keyFor(newViewEnvironment[ScreenViewHolder.Showing])
69+
savedStateParentKey = keyFor(newViewEnvironment[Showing])
6970

7071
val config = if (newRendering.backStack.isEmpty()) First else Other
7172
val environment = newViewEnvironment + config

workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/BodyAndModalsContainer.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.squareup.workflow1.ui.Compatible.Companion.keyFor
1717
import com.squareup.workflow1.ui.R
1818
import com.squareup.workflow1.ui.ScreenViewFactory
1919
import com.squareup.workflow1.ui.ScreenViewHolder
20+
import com.squareup.workflow1.ui.ScreenViewHolder.Companion.Showing
2021
import com.squareup.workflow1.ui.ViewEnvironment
2122
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
2223
import com.squareup.workflow1.ui.WorkflowViewStub
@@ -82,7 +83,7 @@ internal class BodyAndModalsContainer @JvmOverloads constructor(
8283
newScreen: BodyAndModalsScreen<*, *>,
8384
viewEnvironment: ViewEnvironment
8485
) {
85-
savedStateParentKey = keyFor(viewEnvironment[ScreenViewHolder.Showing])
86+
savedStateParentKey = keyFor(viewEnvironment[Showing])
8687

8788
val showingModals = newScreen.modals.isNotEmpty()
8889

workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/EnvironmentScreenLegacyViewFactory.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@ package com.squareup.workflow1.ui.container
55
import com.squareup.workflow1.ui.DecorativeViewFactory
66
import com.squareup.workflow1.ui.ViewFactory
77
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
8-
import com.squareup.workflow1.ui.merge
98

109
@Suppress("DEPRECATION")
1110
@WorkflowUiExperimentalApi
1211
internal object EnvironmentScreenLegacyViewFactory : ViewFactory<EnvironmentScreen<*>>
1312
by DecorativeViewFactory(
1413
type = EnvironmentScreen::class,
1514
map = { environmentScreen, inheritedEnvironment ->
16-
Pair(environmentScreen.wrapped, environmentScreen.environment merge inheritedEnvironment)
15+
Pair(environmentScreen.wrapped, environmentScreen.environment + inheritedEnvironment)
1716
}
1817
)

workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/EnvironmentScreenViewFactory.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,20 @@ import com.squareup.workflow1.ui.Screen
44
import com.squareup.workflow1.ui.ScreenViewFactory
55
import com.squareup.workflow1.ui.ScreenViewFactory.Companion.fromCode
66
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
7-
import com.squareup.workflow1.ui.merge
87
import com.squareup.workflow1.ui.toUnwrappingViewFactory
98
import com.squareup.workflow1.ui.toViewFactory
109

1110
@WorkflowUiExperimentalApi
1211
internal fun <WrappedT : Screen> EnvironmentScreenViewFactory():
1312
ScreenViewFactory<EnvironmentScreen<WrappedT>> {
1413
return fromCode { initialEnvScreen, initialEnvironment, context, container ->
15-
val mergedInitialEnvironment = initialEnvironment merge initialEnvScreen.environment
14+
val mergedInitialEnvironment = initialEnvironment + initialEnvScreen.environment
1615

1716
initialEnvScreen.wrapped.toViewFactory(mergedInitialEnvironment)
1817
.toUnwrappingViewFactory<EnvironmentScreen<WrappedT>, WrappedT>(
1918
unwrap = { it.wrapped },
2019
showWrapperScreen = { _, envScreen, environment, showUnwrapped ->
21-
showUnwrapped(envScreen.wrapped, environment merge envScreen.environment)
20+
showUnwrapped(envScreen.wrapped, environment + envScreen.environment)
2221
}
2322
)
2423
.buildView(initialEnvScreen, mergedInitialEnvironment, context, container)

workflow-ui/core-common/api/core-common.api

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,11 @@ public final class com/squareup/workflow1/ui/ViewEnvironment$Companion {
102102

103103
public abstract class com/squareup/workflow1/ui/ViewEnvironmentKey {
104104
public fun <init> (Lkotlin/reflect/KClass;)V
105+
public fun combine (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
105106
public final fun equals (Ljava/lang/Object;)Z
106107
public abstract fun getDefault ()Ljava/lang/Object;
107108
public final fun hashCode ()I
108-
public fun toString ()Ljava/lang/String;
109-
}
110-
111-
public final class com/squareup/workflow1/ui/ViewEnvironmentKt {
112-
public static final synthetic fun ViewEnvironmentKey (Lkotlin/jvm/functions/Function0;)Lcom/squareup/workflow1/ui/ViewEnvironmentKey;
109+
public final fun toString ()Ljava/lang/String;
113110
}
114111

115112
public abstract interface class com/squareup/workflow1/ui/ViewRegistry {
@@ -119,6 +116,8 @@ public abstract interface class com/squareup/workflow1/ui/ViewRegistry {
119116
}
120117

121118
public final class com/squareup/workflow1/ui/ViewRegistry$Companion : com/squareup/workflow1/ui/ViewEnvironmentKey {
119+
public fun combine (Lcom/squareup/workflow1/ui/ViewRegistry;Lcom/squareup/workflow1/ui/ViewRegistry;)Lcom/squareup/workflow1/ui/ViewRegistry;
120+
public synthetic fun combine (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
122121
public fun getDefault ()Lcom/squareup/workflow1/ui/ViewRegistry;
123122
public synthetic fun getDefault ()Ljava/lang/Object;
124123
}
@@ -131,8 +130,6 @@ public final class com/squareup/workflow1/ui/ViewRegistryKt {
131130
public static final fun ViewRegistry ()Lcom/squareup/workflow1/ui/ViewRegistry;
132131
public static final fun ViewRegistry ([Lcom/squareup/workflow1/ui/ViewRegistry$Entry;)Lcom/squareup/workflow1/ui/ViewRegistry;
133132
public static final synthetic fun get (Lcom/squareup/workflow1/ui/ViewRegistry;Lkotlin/reflect/KClass;)Lcom/squareup/workflow1/ui/ViewRegistry$Entry;
134-
public static final fun merge (Lcom/squareup/workflow1/ui/ViewEnvironment;Lcom/squareup/workflow1/ui/ViewEnvironment;)Lcom/squareup/workflow1/ui/ViewEnvironment;
135-
public static final fun merge (Lcom/squareup/workflow1/ui/ViewEnvironment;Lcom/squareup/workflow1/ui/ViewRegistry;)Lcom/squareup/workflow1/ui/ViewEnvironment;
136133
public static final fun merge (Lcom/squareup/workflow1/ui/ViewRegistry;Lcom/squareup/workflow1/ui/ViewRegistry;)Lcom/squareup/workflow1/ui/ViewRegistry;
137134
public static final fun plus (Lcom/squareup/workflow1/ui/ViewEnvironment;Lcom/squareup/workflow1/ui/ViewRegistry;)Lcom/squareup/workflow1/ui/ViewEnvironment;
138135
public static final fun plus (Lcom/squareup/workflow1/ui/ViewRegistry;Lcom/squareup/workflow1/ui/ViewRegistry$Entry;)Lcom/squareup/workflow1/ui/ViewRegistry;

workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/ViewEnvironment.kt

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,30 @@ public class ViewEnvironment
1919
constructor(
2020
public val map: Map<ViewEnvironmentKey<*>, Any> = emptyMap()
2121
) {
22-
@Suppress("UNCHECKED_CAST")
23-
public operator fun <T : Any> get(key: ViewEnvironmentKey<T>): T = map[key] as? T ?: key.default
22+
public operator fun <T : Any> get(key: ViewEnvironmentKey<T>): T = getOrNull(key) ?: key.default
2423

25-
@Suppress("DEPRECATION")
26-
public operator fun <T : Any> plus(pair: Pair<ViewEnvironmentKey<T>, T>): ViewEnvironment =
27-
ViewEnvironment(map + pair)
24+
public operator fun <T : Any> plus(pair: Pair<ViewEnvironmentKey<T>, T>): ViewEnvironment {
25+
val (newKey, newValue) = pair
26+
val newPair = getOrNull(newKey)
27+
?.let { oldValue -> newKey to newKey.combine(oldValue, newValue) }
28+
?: pair
29+
@Suppress("DEPRECATION")
30+
return ViewEnvironment(map + newPair)
31+
}
2832

2933
@Suppress("DEPRECATION")
3034
public operator fun plus(other: ViewEnvironment): ViewEnvironment {
3135
if (this == other) return this
3236
if (other.map.isEmpty()) return this
33-
if (this.map.isEmpty()) return other
34-
return ViewEnvironment(map + other.map)
37+
if (map.isEmpty()) return other
38+
val newMap = map.toMutableMap()
39+
other.map.entries.forEach { (key, value) ->
40+
@Suppress("UNCHECKED_CAST")
41+
newMap[key] = getOrNull(key as ViewEnvironmentKey<Any>)
42+
?.let { oldValue -> key.combine(oldValue, value) }
43+
?: value
44+
}
45+
return ViewEnvironment(newMap)
3546
}
3647

3748
override fun toString(): String = "ViewEnvironment($map)"
@@ -41,6 +52,9 @@ constructor(
4152

4253
override fun hashCode(): Int = map.hashCode()
4354

55+
@Suppress("UNCHECKED_CAST")
56+
private fun <T : Any> getOrNull(key: ViewEnvironmentKey<T>): T? = map[key] as? T
57+
4458
public companion object {
4559
@Suppress("DEPRECATION")
4660
public val EMPTY: ViewEnvironment = ViewEnvironment()
@@ -57,6 +71,15 @@ public abstract class ViewEnvironmentKey<T : Any>(
5771
) {
5872
public abstract val default: T
5973

74+
/**
75+
* Applied from [ViewEnvironment.plus] when the receiving environment already contains
76+
* a value for this key. The default implementation replaces [left] with [right].
77+
*/
78+
public open fun combine(
79+
left: T,
80+
right: T
81+
): T = right
82+
6083
final override fun equals(other: Any?): Boolean = when {
6184
this === other -> true
6285
other != null && this::class != other::class -> false
@@ -65,17 +88,7 @@ public abstract class ViewEnvironmentKey<T : Any>(
6588

6689
final override fun hashCode(): Int = type.hashCode()
6790

68-
override fun toString(): String {
91+
final override fun toString(): String {
6992
return "${this::class.simpleName}(${type.simpleName})"
7093
}
7194
}
72-
73-
@WorkflowUiExperimentalApi
74-
public inline fun <reified T : Any> ViewEnvironmentKey(
75-
crossinline produceDefault: () -> T,
76-
): ViewEnvironmentKey<T> {
77-
return object : ViewEnvironmentKey<T>(T::class) {
78-
override val default: T
79-
get() = produceDefault()
80-
}
81-
}

workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/ViewRegistry.kt

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ public interface ViewRegistry {
8383

8484
public companion object : ViewEnvironmentKey<ViewRegistry>(ViewRegistry::class) {
8585
override val default: ViewRegistry get() = ViewRegistry()
86+
override fun combine(
87+
left: ViewRegistry,
88+
right: ViewRegistry
89+
): ViewRegistry = left.merge(right)
8690
}
8791
}
8892

@@ -103,24 +107,24 @@ public fun ViewRegistry(vararg bindings: Entry<*>): ViewRegistry =
103107
public fun ViewRegistry(): ViewRegistry = TypedViewRegistry()
104108

105109
/**
106-
* @throws IllegalArgumentException if the receiver already has a matching [entry].
110+
* Transforms the receiver to add [entry], throwing [IllegalArgumentException] if the receiver
111+
* already has a matching [entry]. Use [merge] to replace an existing entry with a new one.
107112
*/
108113
@WorkflowUiExperimentalApi
109114
public operator fun ViewRegistry.plus(entry: Entry<*>): ViewRegistry =
110115
this + ViewRegistry(entry)
111116

112-
/** @throws IllegalArgumentException if other has redundant entries. */
117+
/**
118+
* Transforms the receiver to add all entries from [other], throwing [IllegalArgumentException]
119+
* if the receiver already has any matching [entry]. Use [merge] to replace existing entries.
120+
*/
113121
@WorkflowUiExperimentalApi
114122
public operator fun ViewRegistry.plus(other: ViewRegistry): ViewRegistry {
115123
if (other.keys.isEmpty()) return this
116124
if (this.keys.isEmpty()) return other
117125
return CompositeViewRegistry(this, other)
118126
}
119127

120-
/**
121-
* Replaces the existing [ViewRegistry] of the receiver with [registry]. Use
122-
* [ViewEnvironment.merge] to combine them instead.
123-
*/
124128
@WorkflowUiExperimentalApi
125129
public operator fun ViewEnvironment.plus(registry: ViewRegistry): ViewEnvironment {
126130
if (this[ViewRegistry] === registry) return this
@@ -144,32 +148,3 @@ public infix fun ViewRegistry.merge(other: ViewRegistry): ViewRegistry {
144148
.toTypedArray()
145149
.let { ViewRegistry(*it) }
146150
}
147-
148-
/**
149-
* Merges the [ViewRegistry] of the receiver with [registry]. If there are conflicting entries,
150-
* those in [registry] are preferred.
151-
*/
152-
@WorkflowUiExperimentalApi
153-
public infix fun ViewEnvironment.merge(registry: ViewRegistry): ViewEnvironment {
154-
if (this[ViewRegistry] === registry) return this
155-
if (registry.keys.isEmpty()) return this
156-
157-
val merged = this[ViewRegistry] merge registry
158-
return this + merged
159-
}
160-
161-
/**
162-
* Combines the receiving [ViewEnvironment] with [other], taking care to merge
163-
* their [ViewRegistry] entries. Any other conflicting values in [other] replace those
164-
* in the receiver.
165-
*/
166-
@WorkflowUiExperimentalApi
167-
public infix fun ViewEnvironment.merge(other: ViewEnvironment): ViewEnvironment {
168-
if (this == other) return this
169-
if (other.map.isEmpty()) return this
170-
if (this.map.isEmpty()) return other
171-
172-
val oldReg = this[ViewRegistry]
173-
val newReg = other[ViewRegistry]
174-
return this + other + (ViewRegistry to oldReg.merge(newReg))
175-
}

0 commit comments

Comments
 (0)