Skip to content

Commit 454f29d

Browse files
committed
Introduces ScreenViewFactoryFinder
Fixes #594, which was about how impractical it is to wrap the `ViewRegistry` interface, by introducing a higher level interface that's easy to wrap. The problem is that the fundamental method is `getFactoryFor(KClass)`, but lots of crucial behavior (e.g. `AndroidViewRendering` / `AndroidScreenRendering`) is in the `getFactoryForRendering` extension method. But if we change the fundamental method to be instance based instead of type based, we bring back a lot of potential complexity to `ViewRegistry` that the original type-based choice very intentionally restricted. To have our cake and eat it too, we move the extension method to a new `ViewEnvironment` service interface, `ScreenViewFactoryFinder`. Ta da, totally customizable, with the defaults totally built in.
1 parent 6099c59 commit 454f29d

File tree

4 files changed

+69
-33
lines changed

4 files changed

+69
-33
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,20 @@ public final class com/squareup/workflow1/ui/ScreenViewFactory$DefaultImpls {
9595
public static synthetic fun buildView$default (Lcom/squareup/workflow1/ui/ScreenViewFactory;Lcom/squareup/workflow1/ui/Screen;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;Landroid/view/ViewGroup;ILjava/lang/Object;)Landroid/view/View;
9696
}
9797

98+
public abstract interface class com/squareup/workflow1/ui/ScreenViewFactoryFinder {
99+
public static final field Companion Lcom/squareup/workflow1/ui/ScreenViewFactoryFinder$Companion;
100+
public abstract fun getViewFactoryForRendering (Lcom/squareup/workflow1/ui/ViewEnvironment;Lcom/squareup/workflow1/ui/Screen;)Lcom/squareup/workflow1/ui/ScreenViewFactory;
101+
}
102+
103+
public final class com/squareup/workflow1/ui/ScreenViewFactoryFinder$Companion : com/squareup/workflow1/ui/ViewEnvironmentKey {
104+
public fun getDefault ()Lcom/squareup/workflow1/ui/ScreenViewFactoryFinder;
105+
public synthetic fun getDefault ()Ljava/lang/Object;
106+
}
107+
108+
public final class com/squareup/workflow1/ui/ScreenViewFactoryFinder$DefaultImpls {
109+
public static fun getViewFactoryForRendering (Lcom/squareup/workflow1/ui/ScreenViewFactoryFinder;Lcom/squareup/workflow1/ui/ViewEnvironment;Lcom/squareup/workflow1/ui/Screen;)Lcom/squareup/workflow1/ui/ScreenViewFactory;
110+
}
111+
98112
public final class com/squareup/workflow1/ui/ScreenViewFactoryKt {
99113
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;
100114
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;

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

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@ package com.squareup.workflow1.ui
33
import android.content.Context
44
import android.view.View
55
import android.view.ViewGroup
6-
import com.squareup.workflow1.ui.container.BackStackScreen
7-
import com.squareup.workflow1.ui.container.BackStackScreenViewFactory
8-
import com.squareup.workflow1.ui.container.BodyAndModalsContainer
9-
import com.squareup.workflow1.ui.container.BodyAndModalsScreen
10-
import com.squareup.workflow1.ui.container.EnvironmentScreen
11-
import com.squareup.workflow1.ui.container.EnvironmentScreenViewFactory
126

137
/**
148
* Factory for [View] instances that can show renderings of type [RenderingT] : [Screen].
@@ -63,7 +57,9 @@ public fun <ScreenT : Screen> ScreenT.buildView(
6357
container: ViewGroup? = null,
6458
viewStarter: ViewStarter? = null,
6559
): View {
66-
val viewFactory = viewEnvironment.getViewFactoryForRendering(this)
60+
val viewFactory = viewEnvironment[ScreenViewFactoryFinder].getViewFactoryForRendering(
61+
viewEnvironment, this
62+
)
6763

6864
return viewFactory.buildView(this, viewEnvironment, contextForNewView, container).also { view ->
6965
checkNotNull(view.workflowViewStateOrNull) {
@@ -97,28 +93,3 @@ public fun interface ViewStarter {
9793
doStart: () -> Unit
9894
)
9995
}
100-
101-
@WorkflowUiExperimentalApi
102-
internal fun <ScreenT : Screen>
103-
ViewEnvironment.getViewFactoryForRendering(rendering: ScreenT): ScreenViewFactory<ScreenT> {
104-
val entry = get(ViewRegistry).getEntryFor(rendering::class)
105-
106-
@Suppress("UNCHECKED_CAST", "DEPRECATION")
107-
return (entry as? ScreenViewFactory<ScreenT>)
108-
?: (rendering as? AndroidScreen<*>)?.viewFactory as? ScreenViewFactory<ScreenT>
109-
?: (rendering as? AsScreen<*>)?.let { AsScreenViewFactory as ScreenViewFactory<ScreenT> }
110-
?: (rendering as? BackStackScreen<*>)?.let {
111-
BackStackScreenViewFactory as ScreenViewFactory<ScreenT>
112-
}
113-
?: (rendering as? BodyAndModalsScreen<*, *>)?.let {
114-
BodyAndModalsContainer as ScreenViewFactory<ScreenT>
115-
}
116-
?: (rendering as? NamedScreen<*>)?.let { NamedScreenViewFactory as ScreenViewFactory<ScreenT> }
117-
?: (rendering as? EnvironmentScreen<*>)?.let {
118-
EnvironmentScreenViewFactory as ScreenViewFactory<ScreenT>
119-
}
120-
?: throw IllegalArgumentException(
121-
"A ScreenViewFactory should have been registered to display $rendering, " +
122-
"or that class should implement AndroidScreen. Instead found $entry."
123-
)
124-
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.squareup.workflow1.ui
2+
3+
import com.squareup.workflow1.ui.container.BackStackScreen
4+
import com.squareup.workflow1.ui.container.BackStackScreenViewFactory
5+
import com.squareup.workflow1.ui.container.BodyAndModalsContainer
6+
import com.squareup.workflow1.ui.container.BodyAndModalsScreen
7+
import com.squareup.workflow1.ui.container.EnvironmentScreen
8+
import com.squareup.workflow1.ui.container.EnvironmentScreenViewFactory
9+
10+
/**
11+
* [ViewEnvironment] service object used by [Screen.buildView] to find the right
12+
* [ScreenViewFactory]. The default implementation is why [AndroidScreen], etc. work.
13+
* Can be customized like any other [ViewEnvironment] entry, e.g. via [EnvironmentScreen].
14+
*/
15+
@WorkflowUiExperimentalApi
16+
public interface ScreenViewFactoryFinder {
17+
public fun <ScreenT : Screen> getViewFactoryForRendering(
18+
environment: ViewEnvironment,
19+
rendering: ScreenT
20+
): ScreenViewFactory<ScreenT> {
21+
val entry = environment[ViewRegistry].getEntryFor(rendering::class)
22+
23+
@Suppress("UNCHECKED_CAST", "DEPRECATION")
24+
return (entry as? ScreenViewFactory<ScreenT>)
25+
?: (rendering as? AndroidScreen<*>)?.viewFactory as? ScreenViewFactory<ScreenT>
26+
?: (rendering as? AsScreen<*>)?.let { AsScreenViewFactory as ScreenViewFactory<ScreenT> }
27+
?: (rendering as? BackStackScreen<*>)?.let {
28+
BackStackScreenViewFactory as ScreenViewFactory<ScreenT>
29+
}
30+
?: (rendering as? BodyAndModalsScreen<*, *>)?.let {
31+
BodyAndModalsContainer as ScreenViewFactory<ScreenT>
32+
}
33+
?: (rendering as? NamedScreen<*>)?.let {
34+
NamedScreenViewFactory as ScreenViewFactory<ScreenT>
35+
}
36+
?: (rendering as? EnvironmentScreen<*>)?.let {
37+
EnvironmentScreenViewFactory as ScreenViewFactory<ScreenT>
38+
}
39+
?: throw IllegalArgumentException(
40+
"A ScreenViewFactory should have been registered to display $rendering, " +
41+
"or that class should implement AndroidScreen. Instead found $entry."
42+
)
43+
}
44+
45+
public companion object : ViewEnvironmentKey<ScreenViewFactoryFinder>(
46+
ScreenViewFactoryFinder::class
47+
) {
48+
override val default: ScreenViewFactoryFinder
49+
get() = object : ScreenViewFactoryFinder {}
50+
}
51+
}

workflow-ui/core-android/src/test/java/com/squareup/workflow1/ui/ScreenViewFactoryTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ internal class ScreenViewFactoryTest {
7474

7575
return mock {
7676
on {
77-
getTag(eq(com.squareup.workflow1.ui.R.id.workflow_ui_view_state))
77+
getTag(eq(R.id.workflow_ui_view_state))
7878
} doReturn (WorkflowViewState.New(initialRendering, initialViewEnvironment, { _, _ -> }))
7979
}
8080
}

0 commit comments

Comments
 (0)