Skip to content

Commit

Permalink
Brings ViewStarter to the UI update.
Browse files Browse the repository at this point in the history
Propagates changes from #602 -- replace `initializeView`
with `viewStarter` to fix #597.
  • Loading branch information
rjrjr committed Jan 5, 2022
1 parent a691e8e commit 847de16
Show file tree
Hide file tree
Showing 11 changed files with 222 additions and 113 deletions.
82 changes: 53 additions & 29 deletions workflow-ui/core-android/api/core-android.api
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public abstract interface class com/squareup/workflow1/ui/AndroidScreen : com/sq
}

public final class com/squareup/workflow1/ui/AndroidViewRegistryKt {
public static final fun buildView (Lcom/squareup/workflow1/ui/ViewRegistry;Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;Landroid/view/ViewGroup;Lkotlin/jvm/functions/Function1;)Landroid/view/View;
public static synthetic fun buildView$default (Lcom/squareup/workflow1/ui/ViewRegistry;Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;Landroid/view/ViewGroup;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Landroid/view/View;
public static final fun buildView (Lcom/squareup/workflow1/ui/ViewRegistry;Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;Landroid/view/ViewGroup;Lcom/squareup/workflow1/ui/ViewStarter;)Landroid/view/View;
public static synthetic fun buildView$default (Lcom/squareup/workflow1/ui/ViewRegistry;Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;Landroid/view/ViewGroup;Lcom/squareup/workflow1/ui/ViewStarter;ILjava/lang/Object;)Landroid/view/View;
public static final fun getFactoryFor (Lcom/squareup/workflow1/ui/ViewRegistry;Lkotlin/reflect/KClass;)Lcom/squareup/workflow1/ui/ViewFactory;
public static final fun getFactoryForRendering (Lcom/squareup/workflow1/ui/ViewRegistry;Ljava/lang/Object;)Lcom/squareup/workflow1/ui/ViewFactory;
}
Expand All @@ -39,19 +39,19 @@ public final class com/squareup/workflow1/ui/BuilderViewFactory : com/squareup/w
}

public final class com/squareup/workflow1/ui/DecorativeScreenViewFactory : com/squareup/workflow1/ui/ScreenViewFactory {
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)V
public synthetic fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)V
public synthetic fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/ui/ViewStarter;Lkotlin/jvm/functions/Function4;)V
public synthetic fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/ui/ViewStarter;Lkotlin/jvm/functions/Function4;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function2;Lcom/squareup/workflow1/ui/ViewStarter;Lkotlin/jvm/functions/Function4;)V
public synthetic fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function2;Lcom/squareup/workflow1/ui/ViewStarter;Lkotlin/jvm/functions/Function4;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun buildView (Lcom/squareup/workflow1/ui/Screen;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;Landroid/view/ViewGroup;)Landroid/view/View;
public fun getType ()Lkotlin/reflect/KClass;
}

public final class com/squareup/workflow1/ui/DecorativeViewFactory : com/squareup/workflow1/ui/ViewFactory {
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)V
public synthetic fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)V
public synthetic fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/ui/ViewStarter;Lkotlin/jvm/functions/Function4;)V
public synthetic fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/ui/ViewStarter;Lkotlin/jvm/functions/Function4;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function2;Lcom/squareup/workflow1/ui/ViewStarter;Lkotlin/jvm/functions/Function4;)V
public synthetic fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function2;Lcom/squareup/workflow1/ui/ViewStarter;Lkotlin/jvm/functions/Function4;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun buildView (Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;Landroid/view/ViewGroup;)Landroid/view/View;
public fun getType ()Lkotlin/reflect/KClass;
}
Expand Down Expand Up @@ -96,9 +96,8 @@ public final class com/squareup/workflow1/ui/ScreenViewFactory$DefaultImpls {
}

public final class com/squareup/workflow1/ui/ScreenViewFactoryKt {
public static final fun buildView (Lcom/squareup/workflow1/ui/Screen;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;Landroid/view/ViewGroup;Lkotlin/jvm/functions/Function1;)Landroid/view/View;
public static synthetic fun buildView$default (Lcom/squareup/workflow1/ui/Screen;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;Landroid/view/ViewGroup;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Landroid/view/View;
public static final fun showFirstRendering (Landroid/view/View;)V
public static final fun buildView (Lcom/squareup/workflow1/ui/Screen;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;Landroid/view/ViewGroup;Lcom/squareup/workflow1/ui/ViewStarter;)Landroid/view/View;
public static synthetic fun buildView$default (Lcom/squareup/workflow1/ui/Screen;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;Landroid/view/ViewGroup;Lcom/squareup/workflow1/ui/ViewStarter;ILjava/lang/Object;)Landroid/view/View;
}

public abstract interface class com/squareup/workflow1/ui/ScreenViewRunner {
Expand All @@ -109,21 +108,6 @@ public abstract interface class com/squareup/workflow1/ui/ScreenViewRunner {
public final class com/squareup/workflow1/ui/ScreenViewRunner$Companion {
}

public final class com/squareup/workflow1/ui/ShowRenderingTag {
public fun <init> (Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function2;)V
public final fun component1 ()Ljava/lang/Object;
public final fun component2 ()Lcom/squareup/workflow1/ui/ViewEnvironment;
public final fun component3 ()Lkotlin/jvm/functions/Function2;
public final fun copy (Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function2;)Lcom/squareup/workflow1/ui/ShowRenderingTag;
public static synthetic fun copy$default (Lcom/squareup/workflow1/ui/ShowRenderingTag;Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/squareup/workflow1/ui/ShowRenderingTag;
public fun equals (Ljava/lang/Object;)Z
public final fun getEnvironment ()Lcom/squareup/workflow1/ui/ViewEnvironment;
public final fun getShowRendering ()Lkotlin/jvm/functions/Function2;
public final fun getShowing ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/squareup/workflow1/ui/SnapshotParcelsKt {
public static final fun toSnapshot (Landroid/os/Parcelable;)Lcom/squareup/workflow1/Snapshot;
}
Expand Down Expand Up @@ -156,9 +140,13 @@ public final class com/squareup/workflow1/ui/ViewShowRenderingKt {
public static final fun bindShowRendering (Landroid/view/View;Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function2;)V
public static final fun canShowRendering (Landroid/view/View;Ljava/lang/Object;)Z
public static final fun getEnvironment (Landroid/view/View;)Lcom/squareup/workflow1/ui/ViewEnvironment;
public static final fun getRendering (Landroid/view/View;)Ljava/lang/Object;
public static final fun getShowRendering (Landroid/view/View;)Lkotlin/jvm/functions/Function2;
public static final fun showRendering (Landroid/view/View;Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;)V
public static final fun start (Landroid/view/View;)V
}

public abstract interface class com/squareup/workflow1/ui/ViewStarter {
public abstract fun startView (Landroid/view/View;Lkotlin/jvm/functions/Function0;)V
}

public final class com/squareup/workflow1/ui/WorkflowLayout : android/widget/FrameLayout {
Expand All @@ -170,6 +158,42 @@ public final class com/squareup/workflow1/ui/WorkflowLayout : android/widget/Fra
public final fun take (Lkotlinx/coroutines/flow/Flow;)V
}

public abstract class com/squareup/workflow1/ui/WorkflowViewState {
public abstract fun getEnvironment ()Lcom/squareup/workflow1/ui/ViewEnvironment;
public abstract fun getShowRendering ()Lkotlin/jvm/functions/Function2;
}

public final class com/squareup/workflow1/ui/WorkflowViewState$New : com/squareup/workflow1/ui/WorkflowViewState {
public fun <init> (Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component2 ()Lcom/squareup/workflow1/ui/ViewEnvironment;
public final fun component3 ()Lkotlin/jvm/functions/Function2;
public final fun component4 ()Lkotlin/jvm/functions/Function1;
public final fun copy (Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lcom/squareup/workflow1/ui/WorkflowViewState$New;
public static synthetic fun copy$default (Lcom/squareup/workflow1/ui/WorkflowViewState$New;Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/squareup/workflow1/ui/WorkflowViewState$New;
public fun equals (Ljava/lang/Object;)Z
public fun getEnvironment ()Lcom/squareup/workflow1/ui/ViewEnvironment;
public fun getShowRendering ()Lkotlin/jvm/functions/Function2;
public synthetic fun getShowing ()Ljava/lang/Object;
public final fun getStarter ()Lkotlin/jvm/functions/Function1;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/squareup/workflow1/ui/WorkflowViewState$Started : com/squareup/workflow1/ui/WorkflowViewState {
public fun <init> (Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function2;)V
public final fun component2 ()Lcom/squareup/workflow1/ui/ViewEnvironment;
public final fun component3 ()Lkotlin/jvm/functions/Function2;
public final fun copy (Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function2;)Lcom/squareup/workflow1/ui/WorkflowViewState$Started;
public static synthetic fun copy$default (Lcom/squareup/workflow1/ui/WorkflowViewState$Started;Ljava/lang/Object;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/squareup/workflow1/ui/WorkflowViewState$Started;
public fun equals (Ljava/lang/Object;)Z
public fun getEnvironment ()Lcom/squareup/workflow1/ui/ViewEnvironment;
public fun getShowRendering ()Lkotlin/jvm/functions/Function2;
public synthetic fun getShowing ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/squareup/workflow1/ui/WorkflowViewStub : android/view/View {
public fun <init> (Landroid/content/Context;)V
public fun <init> (Landroid/content/Context;Landroid/util/AttributeSet;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.junit.Test
internal class DecorativeScreenViewFactoryTest {
private val instrumentation = InstrumentationRegistry.getInstrumentation()

@Test fun initializeView_is_only_call_to_showRendering() {
@Test fun viewStarter_is_only_call_to_showRendering() {
val events = mutableListOf<String>()

val innerViewFactory = object : ScreenViewFactory<InnerRendering> {
Expand All @@ -38,27 +38,25 @@ internal class DecorativeScreenViewFactoryTest {
val enhancedEnv = env + (envString to "Updated environment")
Pair(outer.wrapped, enhancedEnv)
},
initializeView = {
val outerRendering = getRendering<OuterRendering>()
events += "initializeView $outerRendering ${environment!![envString]}"
showFirstRendering()
events += "exit initializeView"
viewStarter = { view, doStart ->
events += "viewStarter ${view.getRendering<Any>()} ${view.environment!![envString]}"
doStart()
events += "exit viewStarter"
}
)
val viewRegistry = ViewRegistry(innerViewFactory)
val viewRegistry = ViewRegistry(innerViewFactory, outerViewFactory)
val viewEnvironment = ViewEnvironment(mapOf(ViewRegistry to viewRegistry))

outerViewFactory.buildView(
OuterRendering("outer", InnerRendering("inner")),
OuterRendering("outer", InnerRendering("inner")).buildView(
viewEnvironment,
instrumentation.context
)
).start()

assertThat(events).containsExactly(
"initializeView OuterRendering(outerData=outer, wrapped=InnerRendering(innerData=inner)) " +
"viewStarter OuterRendering(outerData=outer, wrapped=InnerRendering(innerData=inner)) " +
"Updated environment",
"inner showRendering InnerRendering(innerData=inner)",
"exit initializeView"
"exit viewStarter"
)
}

Expand Down Expand Up @@ -86,21 +84,97 @@ internal class DecorativeScreenViewFactoryTest {
innerShowRendering(outerRendering.wrapped, env)
}
)
val viewRegistry = ViewRegistry(innerViewFactory)
val viewRegistry = ViewRegistry(innerViewFactory, outerViewFactory)
val viewEnvironment = ViewEnvironment(mapOf(ViewRegistry to viewRegistry))

outerViewFactory.buildView(
OuterRendering("outer", InnerRendering("inner")),
OuterRendering("outer", InnerRendering("inner")).buildView(
viewEnvironment,
instrumentation.context
)
).start()

assertThat(events).containsExactly(
"doShowRendering OuterRendering(outerData=outer, wrapped=InnerRendering(innerData=inner))",
"inner showRendering InnerRendering(innerData=inner)"
)
}

// https://github.com/square/workflow-kotlin/issues/597
@Test fun double_wrapping_only_calls_showRendering_once() {
val events = mutableListOf<String>()

val innerViewFactory = object : ScreenViewFactory<InnerRendering> {
override val type = InnerRendering::class
override fun buildView(
initialRendering: InnerRendering,
initialViewEnvironment: ViewEnvironment,
contextForNewView: Context,
container: ViewGroup?
): View = InnerView(contextForNewView).apply {
bindShowRendering(initialRendering, initialViewEnvironment) { rendering, _ ->
events += "inner showRendering $rendering"
}
}
}

val envString = object : ViewEnvironmentKey<String>(String::class) {
override val default: String get() = "Not set"
}

val outerViewFactory = DecorativeScreenViewFactory(
type = OuterRendering::class,
map = { outer, env ->
val enhancedEnv = env + (envString to "Outer Updated environment" +
" SHOULD NOT SEE THIS! It will be clobbered by WayOutRendering")
Pair(outer.wrapped, enhancedEnv)
},
viewStarter = { view, doStart ->
events += "outer viewStarter ${view.getRendering<Any>()} ${view.environment!![envString]}"
doStart()
events += "exit outer viewStarter"
}
)

val wayOutViewFactory = DecorativeScreenViewFactory(
type = WayOutRendering::class,
map = { wayOut, env ->
val enhancedEnv = env + (envString to "Way Out Updated environment triumphs over all")
Pair(wayOut.wrapped, enhancedEnv)
},
viewStarter = { view, doStart ->
events += "way out viewStarter ${view.getRendering<Any>()} ${view.environment!![envString]}"
doStart()
events += "exit way out viewStarter"
}
)
val viewRegistry = ViewRegistry(innerViewFactory, outerViewFactory, wayOutViewFactory)
val viewEnvironment = ViewEnvironment(mapOf(ViewRegistry to viewRegistry))

WayOutRendering("way out", OuterRendering("outer", InnerRendering("inner"))).buildView(
viewEnvironment,
instrumentation.context
).start()

assertThat(events).containsExactly(
"way out viewStarter " +
"WayOutRendering(wayOutData=way out, wrapped=" +
"OuterRendering(outerData=outer, wrapped=" +
"InnerRendering(innerData=inner))) " +
"Way Out Updated environment triumphs over all",
"outer viewStarter " +
// Notice that both the initial rendering and the ViewEnvironment are stomped by
// the outermost wrapper before inners are invoked. Could try to give
// the inner wrapper access to the rendering it expected, but there are no
// use cases and it trashes the API.
"WayOutRendering(wayOutData=way out, wrapped=" +
"OuterRendering(outerData=outer, wrapped=" +
"InnerRendering(innerData=inner))) " +
"Way Out Updated environment triumphs over all",
"inner showRendering InnerRendering(innerData=inner)",
"exit outer viewStarter",
"exit way out viewStarter"
)
}

@Test fun subsequent_showRendering_calls_wrapped_showRendering() {
val events = mutableListOf<String>()

Expand All @@ -125,14 +199,13 @@ internal class DecorativeScreenViewFactoryTest {
innerShowRendering(outerRendering.wrapped, env)
}
)
val viewRegistry = ViewRegistry(innerViewFactory)
val viewRegistry = ViewRegistry(innerViewFactory, outerViewFactory)
val viewEnvironment = ViewEnvironment(mapOf(ViewRegistry to viewRegistry))

val view = outerViewFactory.buildView(
OuterRendering("out1", InnerRendering("in1")),
val view = OuterRendering("out1", InnerRendering("in1")).buildView(
viewEnvironment,
instrumentation.context
)
).apply { start() }
events.clear()

view.showRendering(OuterRendering("out2", InnerRendering("in2")), viewEnvironment)
Expand All @@ -149,5 +222,10 @@ internal class DecorativeScreenViewFactoryTest {
val wrapped: InnerRendering
) : Screen

private data class WayOutRendering(
val wayOutData: String,
val wrapped: OuterRendering
) : Screen

private class InnerView(context: Context) : View(context)
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,27 @@ public fun <RenderingT : Any> ViewRegistry.getFactoryFor(
}

@Suppress("DEPRECATION")
@Deprecated("Use ViewEnvironment.buildview")
@Deprecated("Use Screen.buildview")
@WorkflowUiExperimentalApi
public fun <RenderingT : Any> ViewRegistry.buildView(
initialRendering: RenderingT,
initialViewEnvironment: ViewEnvironment,
contextForNewView: Context,
container: ViewGroup? = null,
initializeView: View.() -> Unit = { showFirstRendering() }
viewStarter: ViewStarter? = null,
): View {
return getFactoryForRendering(initialRendering).buildView(
initialRendering, initialViewEnvironment, contextForNewView, container
).also { view ->
checkNotNull(view.showRenderingTag) {
checkNotNull(view.workflowViewStateOrNull) {
"View.bindShowRendering should have been called for $view, typically by the " +
"${ViewFactory::class.java.name} that created it."
"ViewFactory that created it."
}
viewStarter?.let { givenStarter ->
val doStart = view.starter
view.starter = { newView ->
givenStarter.startView(newView) { doStart.invoke(newView) }
}
}
initializeView.invoke(view)
}
}

0 comments on commit 847de16

Please sign in to comment.