@@ -139,107 +139,83 @@ public interface ScreenViewFactory<in ScreenT : Screen> : ViewRegistry.Entry<Scr
139139 }
140140
141141 /* *
142- * Creates a [ScreenViewFactory] for [WrapperT] that finds and delegates to the one for
143- * [WrappedT]. Allows [WrapperT] to wrap instances of [WrappedT] to add information or behavior,
144- * without requiring wasteful wrapping in the view system.
145- *
146- * One general note: when creating a wrapper rendering, you're very likely to want it to
147- * implement [Compatible], to ensure that checks made to update or replace a view are based on
148- * the wrapped item. Each wrapper example below illustrates this.
149- *
150- * This a simpler variant of the like named function that takes three arguments, for use when
151- * there is no need to manipulate the [ScreenViewHolder].
142+ * Creates a [ScreenViewFactory] for type [WrapperT] that finds and delegates to the one for
143+ * [WrappedT]. Allows [WrapperT] to add information or behavior, without requiring wasteful
144+ * parallel wrapping in the view system.
152145 *
153146 * ## Examples
154147 *
155- * To make one rendering type an "alias" for another -- that is, to use the same
156- * [ScreenViewFactory] to display it:
157- *
158- * class RealScreen(val data: String): AndroidScreen<RealScreen> { override val viewFactory =
159- * fromLayout<RealScreen>(...) }
160- *
161- * class AliasScreen(val similarData: String) : AndroidScreen<AliasScreen> {
162- * override val viewFactory = forWrapper<AliasScreen, RealScreen> { aliasScreen ->
163- * RealScreen(aliasScreen.similarData) } }
164- *
165148 * To make one [Screen] type a wrapper for others:
166149 *
167- * class Wrapper<W>(val wrapped: W: Screen) : AndroidScreen<Wrapper<W>>, Compatible {
168- * override val compatibilityKey = Compatible.keyFor(wrapped) override val viewFactory =
169- * ScreenViewFactory.forWrapper<Wrapper<W>, W> { it.wrapped } }
170- *
171- * To make a wrapper that adds information to the [ViewEnvironment]:
150+ * class MyWrapper<W : Screen>(
151+ * override val content: W
152+ * ) : AndroidScreen<Wrapper<W>>, Wrapper<Screen, W> {
153+ * override val viewFactory = forWrapper<MyWrapper<W>, W>()
172154 *
173- * class ReverseNeutronFlowPolarity : ViewEnvironmentKey<Boolean>(Boolean::class) { override val
174- * default = false }
155+ * override fun <U : Screen> map(transform: (W) -> U) =
156+ * MyWrapper(transform(content))
157+ * }
175158 *
176- * class ReversePolarityScreen<W : Screen>( val wrapped: W ) :
177- * AndroidScreen<ReversePolarityScreen<W>>, Compatible { override val compatibilityKey: String
178- * = Compatible.keyFor(wrapped) override val viewFactory = forWrapper<OverrideNeutronFlow<W>,
179- * Screen> { it.wrapped.withEnvironment( Environment.EMPTY + (ReverseNeutronFlowPolarity to
180- * true) ) } }
159+ * To make a wrapper that customizes [View] initialization:
181160 *
182- * @param unwrap a function to extract [WrappedT] instances from [WrapperT]s.
183- */
184- @WorkflowUiExperimentalApi
185- public inline fun <
186- reified WrapperT : Screen ,
187- WrappedT : Screen
188- > forWrapper (
189- crossinline unwrap : (wrapperScreen: WrapperT ) -> WrappedT ,
190- ): ScreenViewFactory <WrapperT > = forWrapper(
191- unwrap = unwrap,
192- beforeShowing = {}
193- ) { _, wrapper, e, showWrapper ->
194- showWrapper(unwrap(wrapper), e)
195- }
196-
197- /* *
198- * Creates a [ScreenViewFactory] for [WrapperT] that finds and delegates to the one for
199- * [WrappedT]. Allows [WrapperT] to wrap instances of [WrappedT] to add information or behavior,
200- * without requiring wasteful wrapping in the view system.
161+ * class WithTutorialTips<W : Screen>(
162+ * override val content: W
163+ * ) : AndroidScreen<WithTutorialTips<W>>, Wrapper<Screen, W> {
164+ * override val viewFactory = forWrapper<WithTutorialTips<W>, W>(
165+ * beforeShowing = { TutorialTipRunner.initialize(it.view) }
166+ * )
201167 *
202- * This fully featured variant of the function is able to initialize the freshly created
203- * [ScreenViewHolder], and transform the wrapped [ScreenViewHolder.runner].
168+ * override fun <U : Screen> map(transform: (W) -> U) =
169+ * WithTutorialTips(transform(content))
170+ * }
204171 *
205- * To make a wrapper that customizes [View] initialization:
172+ * @param prepEnvironment a function to process the initial [ViewEnvironment]
173+ * before the [ScreenViewFactory] is fetched. Note that this function is not
174+ * applied on updates. Add a [showWrapperScreen] function if you need that.
206175 *
207- * class WithTutorialTips<W : Screen>( val wrapped: W ) : AndroidScreen<WithTutorialTips<W>>,
208- * Compatible { override val compatibilityKey = Compatible.keyFor(wrapped) override
209- * val viewFactory = forWrapper<WithTutorialTips<W>, W>( unwrap = { it.wrapped },
210- * beforeShowing = { TutorialTipRunner.initialize(it.view) }, showWrapperScreen = { _,
211- * wrapper, environment, showWrapper -> showWrapper(unwrap(wrapper), environment) } ) }
176+ * @param prepContext a function to process the [Context] used to create each [View].
177+ * it is passed the product of [prepEnvironment]
212178 *
213179 * @param unwrap a function to extract [WrappedT] instances from [WrapperT]s.
180+ *
214181 * @param beforeShowing a function to be invoked immediately after a new [View] is built.
215- * @param showWrapperScreen a function to be invoked when an instance of [WrapperT] needs to be
216- * shown in a [View] built to display instances of [WrappedT]. Allows pre- and
217- * post-processing of the [View].
182+ *
183+ * @param showWrapperScreen a function to be invoked when an instance of [WrapperT] needs
184+ * to be shown in a [View] built to display instances of [WrappedT]. Allows pre-
185+ * and post-processing of the [View].
218186 */
219187 @WorkflowUiExperimentalApi
220- public inline fun <
221- reified WrapperT : Screen ,
222- WrappedT : Screen
223- > forWrapper (
224- crossinline unwrap : (wrapperScreen: WrapperT ) -> WrappedT ,
188+ public inline fun <reified WrapperT , WrappedT : Screen > forWrapper (
189+ crossinline prepEnvironment : (environment: ViewEnvironment ) -> ViewEnvironment = { it },
190+ crossinline prepContext : (
191+ environment: ViewEnvironment ,
192+ context: Context
193+ ) -> Context = { _, c -> c },
194+ crossinline unwrap : (wrapperScreen: WrapperT ) -> WrappedT = { it.content },
225195 crossinline beforeShowing : (viewHolder: ScreenViewHolder <WrapperT >) -> Unit = {},
226196 crossinline showWrapperScreen : (
227197 view: View ,
228198 wrapperScreen: WrapperT ,
229199 environment: ViewEnvironment ,
230200 showUnwrappedScreen: (WrappedT , ViewEnvironment ) -> Unit
231- ) -> Unit ,
232- ): ScreenViewFactory <WrapperT > =
233- fromCode { initialRendering, initialEnvironment, context, container ->
234- val wrappedFactory = unwrap(initialRendering).toViewFactory(initialEnvironment)
235- val wrapperFactory = wrappedFactory.toUnwrappingViewFactory(unwrap, showWrapperScreen)
236- wrapperFactory.buildView(
237- initialRendering,
238- initialEnvironment,
239- context,
240- container
241- ).also { beforeShowing(it) }
201+ ) -> Unit = { _, wrapper, e, showWrapper -> showWrapper(wrapper.content, e) },
202+ ): ScreenViewFactory <WrapperT > where WrapperT : Screen , WrapperT : Wrapper<Screen, WrappedT> {
203+ return fromCode { initialRendering, initialEnvironment, context, container ->
204+ val preppedEnvironment = prepEnvironment(initialEnvironment)
205+ val wrappedFactory = unwrap(initialRendering).toViewFactory(preppedEnvironment)
206+ val wrapperFactory = wrappedFactory.toUnwrappingViewFactory(
207+ prepEnvironment,
208+ prepContext,
209+ unwrap,
210+ showWrapperScreen
211+ )
212+
213+ // Note that we give the factory the original initialEnvironment.
214+ // It applies prepEnvironment itself.
215+ wrapperFactory.buildView(initialRendering, initialEnvironment, context, container)
216+ .also { beforeShowing(it) }
242217 }
218+ }
243219 }
244220}
245221
@@ -353,43 +329,34 @@ public fun interface ViewStarter {
353329 * @see [ScreenViewFactory.forWrapper].
354330 */
355331@WorkflowUiExperimentalApi
356- public inline fun <
357- reified WrapperT : Screen ,
358- WrappedT : Screen
359- > ScreenViewFactory<WrappedT>.toUnwrappingViewFactory (
360- crossinline unwrap : (wrapperScreen: WrapperT ) -> WrappedT
361- ): ScreenViewFactory <WrapperT > {
362- return toUnwrappingViewFactory(unwrap) { _, wrapperScreen, environment, showUnwrappedScreen ->
363- showUnwrappedScreen(unwrap(wrapperScreen), environment)
364- }
365- }
366-
367- /* *
368- * Transforms a [ScreenViewFactory] of [WrappedT] into one that can handle instances of [WrapperT].
369- *
370- * @see [ScreenViewFactory.forWrapper].
371- */
372- @WorkflowUiExperimentalApi
373- public inline fun <
374- reified WrapperT : Screen ,
375- WrappedT : Screen
376- > ScreenViewFactory<WrappedT>.toUnwrappingViewFactory (
377- crossinline unwrap : (wrapperScreen: WrapperT ) -> WrappedT ,
332+ public inline fun <reified WrapperT , WrappedT > ScreenViewFactory<WrappedT>.toUnwrappingViewFactory (
333+ crossinline prepEnvironment : (environment: ViewEnvironment ) -> ViewEnvironment = { e -> e },
334+ crossinline prepContext : (
335+ environment: ViewEnvironment ,
336+ context: Context
337+ ) -> Context = { _, c -> c },
338+ crossinline unwrap : (wrapperScreen: WrapperT ) -> WrappedT = { it.content },
378339 crossinline showWrapperScreen : (
379340 view: View ,
380341 wrapperScreen: WrapperT ,
381342 environment: ViewEnvironment ,
382343 showUnwrappedScreen: (WrappedT , ViewEnvironment ) -> Unit
383- ) -> Unit
384- ): ScreenViewFactory <WrapperT > {
344+ ) -> Unit = { _, wrapperScreen, environment, showUnwrappedScreen ->
345+ showUnwrappedScreen(wrapperScreen.content, environment)
346+ }
347+ ): ScreenViewFactory <WrapperT >
348+ where WrapperT : Screen , WrapperT : Wrapper <Screen , WrappedT >, WrappedT : Screen {
385349 val wrappedFactory = this
386350
387351 return object : ScreenViewFactory <WrapperT > by fromCode(
388352 buildView = { initialRendering, initialEnvironment, context, container ->
353+ val preppedInitialEnvironment = prepEnvironment(initialEnvironment)
354+ val preppedContext = prepContext(preppedInitialEnvironment, context)
355+
389356 val wrappedHolder = wrappedFactory.buildView(
390357 unwrap(initialRendering),
391- initialEnvironment ,
392- context ,
358+ preppedInitialEnvironment ,
359+ preppedContext ,
393360 container
394361 )
395362
0 commit comments