Skip to content

//workflow/com.squareup.workflow1.ui/toUnwrappingViewFactory

toUnwrappingViewFactory

[androidJvm]
Content
@WorkflowUiExperimentalApi()

inline fun <WrapperT : Screen, WrappedT : Screen> ScreenViewFactory<WrappedT>.toUnwrappingViewFactory(crossinline unwrap: (WrapperT) -> WrappedT): ScreenViewFactory<WrapperT>
More info

Transforms a ScreenViewFactory of WrappedT into one that can handle instances of WrapperT. Allows WrapperT to wrap instances of WrappedT to add information or behavior, without requiring wasteful wrapping in the view system.

One general note: when creating a wrapper rendering, you’re very likely to want it to implement Compatible, to ensure that checks made to update or replace a view are based on the wrapped item. Each wrapper example below illustrates this.

This a simpler variant of the like named function that takes two arguments, for use when there is no need to customize the view or the environment.

Examples

To make one rendering type an “alias” for another – that is, to use the same ScreenViewFactory to display it:

1
2
3
4
5
6
7
8
9
class RealScreen(val data: String): Screen
object RealScreenViewFactory = ScreenViewFactory.fromLayout(...)

class AliasScreen(val similarData: String) : Screen

object AliasScreenViewFactory =
  RealScreenViewFactory.toUnwrappingViewFactory<AliasScreen, RealScreen> { aliasScreen ->
    RealScreen(aliasScreen.similarData)
  }

To make one rendering type a wrapper for others:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Wrapper<W>(val wrapped: W: Screen) : Screen, Compatible {
  override val compatibilityKey = Compatible.keyFor(wrapped)
}

fun <W : Screen> WrapperViewFactory() =
  ScreenViewFactory.forBuiltView<Wrapper<W>> { wrapper, env, context, container ->
    // Get the view factory of the wrapped screen.
    wrapper.wrapped.toViewFactory(env)
      // Transform it to factory that accepts Wrapper<W>
      .toUnwrappingViewFactory<Wrapper<W>, W> { it.wrapped }
      // Delegate to the transformed factory to build the view.
      .buildView(wrapper, env, context, container)
  }

To make a wrapper that adds information to the ViewEnvironment:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class NeutronFlowPolarity(val reversed: Boolean) {
  companion object : ViewEnvironmentKey<NeutronFlowPolarity>(
    NeutronFlowPolarity::class
  ) {
    override val default: NeutronFlowPolarity =
      NeutronFlowPolarity(reversed = false)
  }
}

class OverrideNeutronFlow<W : Screen>(
  val wrapped: W,
  val polarity: NeutronFlowPolarity
) : Screen, Compatible {
  override val compatibilityKey: String = Compatible.keyFor(wrapped)
}

fun <W : Screen> OverrideNeutronFlowViewFactory() =
  ScreenViewFactory.forBuiltView<OverrideNeutronFlow<W>> { wrapper, env, context, container ->
    // Get the view factory of the wrapped screen.
    wrapper.wrapped.toViewFactory(env)
      // Transform it to factory that accepts OverrideNeutronFlow<W>, by
      // replacing the OverrideNeutronFlow<W> with an EnvironmentScreen<W>
      .toUnwrappingViewFactory<OverrideNeutronFlow<W>, EnvironmentScreen<W>> {
        it.wrapped.withEnvironment(
          Environment.EMPTY + (NeutronFlowPolarity to it.polarity)
        )
      }
      // Delegate to the transformed factory to build the view.
      .buildView(wrapper, env, context, container)
  }

Parameters

androidJvm

unwrap

a function to extract WrappedT instances from WrapperTs.

[androidJvm]
Content
@WorkflowUiExperimentalApi()

inline fun <WrapperT : Screen, WrappedT : Screen> ScreenViewFactory<WrappedT>.toUnwrappingViewFactory(crossinline unwrap: (WrapperT) -> WrappedT, crossinline showWrapperScreen: (view: View, WrapperT, environment: ViewEnvironment, showUnwrappedScreen: (WrappedT, ViewEnvironment) -> Unit) -> Unit): ScreenViewFactory<WrapperT>
More info

Transforms a ScreenViewFactory of WrappedT into one that can handle instances of WrapperT.

One general note: when creating a wrapper rendering, you’re very likely to want it to implement Compatible, to ensure that checks made to update or replace a view are based on the wrapped item. Each wrapper example below illustrates this.

Also see the simpler variant of this function that takes only an unwrap argument.

Example

To make a wrapper that customizes View initialization:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class WithTutorialTips<W : Screen>(val wrapped: W) : Screen, Compatible {
  override val compatibilityKey = Compatible.keyFor(wrapped)
}

fun <W: Screen> WithTutorialTipsFactory<W>() =
  ScreenViewFactory.forBuiltView<WithTutorialTips<*>> = {
    initialRendering, initialEnv, context, container ->
      // Get the view factory of the wrapped screen.
      initialRendering.wrapped.toViewFactory(initialEnv)
        // Transform it to factory that accepts WithTutorialTips<W>
        .toUnwrappingViewFactory<WithTutorialTips<W>, W>(
          unwrap = { it.wrapped },
          showWrapperScreen = { view, withTips, env, showUnwrapped ->
            TutorialTipRunner.run(view)
            showUnwrapped(withTips.wrapped, env)
          }
          // Delegate to the transformed factory to build the view.
          .buildView(initialRendering, initialEnv, context, container)
  }

Parameters

androidJvm

unwrap

a function to extract WrappedT instances from WrapperTs.

showWrapperScreen

a function invoked when an instance of WrapperT needs to be shown in a View built to display instances of WrappedT. Allows pre- and post-processing of the View.