diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/views/LoaderSpinner.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/views/LoaderSpinner.kt index f361c3e5fd..b66af14082 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/views/LoaderSpinner.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/views/LoaderSpinner.kt @@ -1,38 +1,31 @@ package com.squareup.benchmarks.performance.complex.poetry.views -import android.app.Dialog -import android.content.Context -import android.view.ViewGroup.LayoutParams +import android.view.Gravity.CENTER +import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import android.widget.FrameLayout import android.widget.ProgressBar -import com.squareup.workflow1.ui.ViewEnvironment +import com.squareup.workflow1.ui.AndroidScreen +import com.squareup.workflow1.ui.ScreenViewFactory +import com.squareup.workflow1.ui.ScreenViewHolder import com.squareup.workflow1.ui.WorkflowUiExperimentalApi -import com.squareup.workflow1.ui.container.AndroidOverlay -import com.squareup.workflow1.ui.container.OverlayDialogFactory @OptIn(WorkflowUiExperimentalApi::class) -object LoaderSpinner : AndroidOverlay { - override val dialogFactory: OverlayDialogFactory - get() = object : OverlayDialogFactory { - override val type = LoaderSpinner::class - - override fun buildDialog( - initialRendering: LoaderSpinner, - initialEnvironment: ViewEnvironment, - context: Context - ): Dialog = Dialog(context).apply { - setContentView( - ProgressBar(context).apply { - layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT) - isIndeterminate = true - } - ) +object LoaderSpinner : AndroidScreen { + override val viewFactory = + ScreenViewFactory.fromCode { _, initialEnvironment, context, _ -> + val progressBar = ProgressBar(context).apply { + layoutParams = FrameLayout.LayoutParams( + ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT) + ).apply { + gravity = CENTER + } + isIndeterminate = true } - override fun updateDialog( - dialog: Dialog, - rendering: LoaderSpinner, - environment: ViewEnvironment - ) = Unit + FrameLayout(context).let { view -> + view.addView(progressBar) + ScreenViewHolder(initialEnvironment, view) { _, _ -> } + } } } diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/views/MayBeLoadingScreen.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/views/MayBeLoadingScreen.kt index b550fe56ab..81a300e16a 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/views/MayBeLoadingScreen.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/views/MayBeLoadingScreen.kt @@ -4,20 +4,27 @@ import com.squareup.sample.container.overviewdetail.OverviewDetailScreen import com.squareup.sample.container.panel.ScrimScreen import com.squareup.workflow1.ui.WorkflowUiExperimentalApi import com.squareup.workflow1.ui.container.BodyAndModalsScreen +import com.squareup.workflow1.ui.container.ModalScreenOverlay @OptIn(WorkflowUiExperimentalApi::class) -typealias MayBeLoadingScreen = BodyAndModalsScreen, LoaderSpinner> +typealias MayBeLoadingScreen = + BodyAndModalsScreen, ModalScreenOverlay> @OptIn(WorkflowUiExperimentalApi::class) fun MayBeLoadingScreen( baseScreen: OverviewDetailScreen, loaders: List = emptyList() ): MayBeLoadingScreen { - return BodyAndModalsScreen(ScrimScreen(baseScreen, dimmed = loaders.isNotEmpty()), loaders) + return BodyAndModalsScreen( + ScrimScreen(baseScreen, dimmed = loaders.isNotEmpty()), + loaders.map { ModalScreenOverlay(it) } + ) } @OptIn(WorkflowUiExperimentalApi::class) -val MayBeLoadingScreen.baseScreen: OverviewDetailScreen get() = body.content +val MayBeLoadingScreen.baseScreen: OverviewDetailScreen + get() = body.content @OptIn(WorkflowUiExperimentalApi::class) -val MayBeLoadingScreen.loaders: List get() = modals +val MayBeLoadingScreen.loaders: List + get() = modals.map { it.content } diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/res/values/ids.xml b/benchmarks/performance-poetry/complex-poetry/src/main/res/values/ids.xml deleted file mode 100644 index 370d01ec9d..0000000000 --- a/benchmarks/performance-poetry/complex-poetry/src/main/res/values/ids.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/samples/containers/android/src/main/java/com/squareup/sample/container/panel/PanelOverlayDialogFactory.kt b/samples/containers/android/src/main/java/com/squareup/sample/container/panel/PanelOverlayDialogFactory.kt index efb8b7898f..8541e6706d 100644 --- a/samples/containers/android/src/main/java/com/squareup/sample/container/panel/PanelOverlayDialogFactory.kt +++ b/samples/containers/android/src/main/java/com/squareup/sample/container/panel/PanelOverlayDialogFactory.kt @@ -2,12 +2,11 @@ package com.squareup.sample.container.panel import android.app.Dialog import android.graphics.Rect -import android.graphics.drawable.ColorDrawable -import android.util.TypedValue import android.view.View import com.squareup.sample.container.R import com.squareup.workflow1.ui.WorkflowUiExperimentalApi import com.squareup.workflow1.ui.container.ModalScreenOverlayDialogFactory +import com.squareup.workflow1.ui.container.setModalContent /** * Android support for [PanelOverlay]. @@ -16,20 +15,13 @@ import com.squareup.workflow1.ui.container.ModalScreenOverlayDialogFactory internal object PanelOverlayDialogFactory : ModalScreenOverlayDialogFactory>( type = PanelOverlay::class ) { + /** + * Forks the default implementation to apply [R.style.PanelDialog], for + * enter and exit animation. + */ override fun buildDialogWithContentView(contentView: View): Dialog { - val context = contentView.context - return Dialog(context, R.style.PanelDialog).also { dialog -> - dialog.setContentView(contentView) - - // Welcome to Android. Nothing workflow-related here, this is just how one - // finds the window background color for the theme. I sure hope it's better in Compose. - val maybeWindowColor = TypedValue() - context.theme.resolveAttribute(android.R.attr.windowBackground, maybeWindowColor, true) - if ( - maybeWindowColor.type in TypedValue.TYPE_FIRST_COLOR_INT..TypedValue.TYPE_LAST_COLOR_INT - ) { - dialog.window!!.setBackgroundDrawable(ColorDrawable(maybeWindowColor.data)) - } + return Dialog(contentView.context, R.style.PanelDialog).also { + it.setModalContent(contentView) } } diff --git a/workflow-ui/core-android/api/core-android.api b/workflow-ui/core-android/api/core-android.api index 5c9947ce16..d6d77a3791 100644 --- a/workflow-ui/core-android/api/core-android.api +++ b/workflow-ui/core-android/api/core-android.api @@ -422,11 +422,13 @@ public final class com/squareup/workflow1/ui/container/AlertDialogThemeResId : c public synthetic fun getDefault ()Ljava/lang/Object; } -public final class com/squareup/workflow1/ui/container/AlertOverlayDialogFactory : com/squareup/workflow1/ui/container/OverlayDialogFactory { - public static final field INSTANCE Lcom/squareup/workflow1/ui/container/AlertOverlayDialogFactory; +public class com/squareup/workflow1/ui/container/AlertOverlayDialogFactory : com/squareup/workflow1/ui/container/OverlayDialogFactory { + public fun ()V public fun buildDialog (Lcom/squareup/workflow1/ui/container/AlertOverlay;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;)Landroid/app/AlertDialog; public synthetic fun buildDialog (Lcom/squareup/workflow1/ui/container/Overlay;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;)Landroid/app/Dialog; public fun getType ()Lkotlin/reflect/KClass; + protected final fun toId (Lcom/squareup/workflow1/ui/container/AlertOverlay$Button;)I + protected final fun updateButtonsOnShow (Landroid/app/AlertDialog;Lcom/squareup/workflow1/ui/container/AlertOverlay;)V public fun updateDialog (Landroid/app/Dialog;Lcom/squareup/workflow1/ui/container/AlertOverlay;Lcom/squareup/workflow1/ui/ViewEnvironment;)V public synthetic fun updateDialog (Landroid/app/Dialog;Lcom/squareup/workflow1/ui/container/Overlay;Lcom/squareup/workflow1/ui/ViewEnvironment;)V } @@ -614,17 +616,21 @@ public final class com/squareup/workflow1/ui/container/ModalAreaKt { public static final fun plus (Lcom/squareup/workflow1/ui/ViewEnvironment;Lcom/squareup/workflow1/ui/container/ModalArea;)Lcom/squareup/workflow1/ui/ViewEnvironment; } -public abstract class com/squareup/workflow1/ui/container/ModalScreenOverlayDialogFactory : com/squareup/workflow1/ui/container/OverlayDialogFactory { +public class com/squareup/workflow1/ui/container/ModalScreenOverlayDialogFactory : com/squareup/workflow1/ui/container/OverlayDialogFactory { public fun (Lkotlin/reflect/KClass;)V public synthetic fun buildDialog (Lcom/squareup/workflow1/ui/container/Overlay;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;)Landroid/app/Dialog; public final fun buildDialog (Lcom/squareup/workflow1/ui/container/ScreenOverlay;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;)Landroid/app/Dialog; - public abstract fun buildDialogWithContentView (Landroid/view/View;)Landroid/app/Dialog; + public fun buildDialogWithContentView (Landroid/view/View;)Landroid/app/Dialog; public fun getType ()Lkotlin/reflect/KClass; public fun updateBounds (Landroid/app/Dialog;Landroid/graphics/Rect;)V public synthetic fun updateDialog (Landroid/app/Dialog;Lcom/squareup/workflow1/ui/container/Overlay;Lcom/squareup/workflow1/ui/ViewEnvironment;)V public final fun updateDialog (Landroid/app/Dialog;Lcom/squareup/workflow1/ui/container/ScreenOverlay;Lcom/squareup/workflow1/ui/ViewEnvironment;)V } +public final class com/squareup/workflow1/ui/container/ModalScreenOverlayDialogFactoryKt { + public static final fun setModalContent (Landroid/app/Dialog;Landroid/view/View;)V +} + public abstract interface class com/squareup/workflow1/ui/container/ModalScreenOverlayOnBackPressed { public static final field Companion Lcom/squareup/workflow1/ui/container/ModalScreenOverlayOnBackPressed$Companion; public abstract fun onBackPressed (Landroid/view/View;)Z diff --git a/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/ScreenViewFactoryFinder.kt b/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/ScreenViewFactoryFinder.kt index 91db863ea7..a265fd31f0 100644 --- a/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/ScreenViewFactoryFinder.kt +++ b/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/ScreenViewFactoryFinder.kt @@ -11,7 +11,7 @@ import com.squareup.workflow1.ui.container.EnvironmentScreenViewFactory * [ViewEnvironment] service object used by [Screen.toViewFactory] to find the right * [ScreenViewFactory] to build and manage a [View][android.view.View] to display * [Screen]s of the type of the receiver. The default implementation makes [AndroidScreen] - * work and provides default bindings for [NamedScreen], [EnvironmentScreen], [BackStackScreen], + * work, and provides default bindings for [NamedScreen], [EnvironmentScreen], [BackStackScreen], * etc. * * Here is how this hook could be used to provide a custom view to handle [BackStackScreen]: @@ -28,24 +28,27 @@ import com.squareup.workflow1.ui.container.EnvironmentScreenViewFactory * ) * * object MyFinder : ScreenViewFactoryFinder { - * @Suppress("UNCHECKED_CAST") - * if (rendering is BackStackScreen<*>) - * return MyViewFactory as ScreenViewFactory - * return super.getViewFactoryForRendering(environment, rendering) + * override fun getViewFactoryForRendering( + * environment: ViewEnvironment, + * rendering: ScreenT + * ): ScreenViewFactory { + * @Suppress("UNCHECKED_CAST") + * if (rendering is BackStackScreen<*>) return MyViewFactory as ScreenViewFactory + * return super.getViewFactoryForRendering(environment, rendering) + * } * } * * class MyViewModel(savedState: SavedStateHandle) : ViewModel() { * val renderings: StateFlow by lazy { - * val customized = ViewEnvironment.EMPTY + (ScreenViewFactoryFinder to MyFinder) + * val env = ViewEnvironment.EMPTY + (ScreenViewFactoryFinder to MyFinder) * renderWorkflowIn( - * workflow = MyRootWorkflow.withEnvironment(customized), + * workflow = MyRootWorkflow.mapRenderings { it.withEnvironment(env) }, * scope = viewModelScope, * savedStateHandle = savedState * ) * } * } */ - @WorkflowUiExperimentalApi public interface ScreenViewFactoryFinder { public fun getViewFactoryForRendering( diff --git a/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/AlertOverlayDialogFactory.kt b/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/AlertOverlayDialogFactory.kt index 25bfed0acb..3b725f9e3e 100644 --- a/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/AlertOverlayDialogFactory.kt +++ b/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/AlertOverlayDialogFactory.kt @@ -14,12 +14,19 @@ import com.squareup.workflow1.ui.container.AlertOverlay.Button.NEUTRAL import com.squareup.workflow1.ui.container.AlertOverlay.Button.POSITIVE import com.squareup.workflow1.ui.container.AlertOverlay.Event.ButtonClicked import com.squareup.workflow1.ui.container.AlertOverlay.Event.Canceled +import kotlin.reflect.KClass +/** + * Default [OverlayDialogFactory] for [AlertOverlay]. + * + * This class is non-final for ease of customization of [AlertOverlay] handling, + * see [OverlayDialogFactoryFinder] for details. + */ @WorkflowUiExperimentalApi -internal object AlertOverlayDialogFactory : OverlayDialogFactory { - override val type = AlertOverlay::class +public open class AlertOverlayDialogFactory : OverlayDialogFactory { + override val type: KClass = AlertOverlay::class - override fun buildDialog( + open override fun buildDialog( initialRendering: AlertOverlay, initialEnvironment: ViewEnvironment, context: Context @@ -48,7 +55,7 @@ internal object AlertOverlayDialogFactory : OverlayDialogFactory { } } - override fun updateDialog( + open override fun updateDialog( dialog: Dialog, rendering: AlertOverlay, environment: ViewEnvironment @@ -71,13 +78,13 @@ internal object AlertOverlayDialogFactory : OverlayDialogFactory { } } - private fun Button.toId(): Int = when (this) { + protected fun Button.toId(): Int = when (this) { POSITIVE -> DialogInterface.BUTTON_POSITIVE NEGATIVE -> DialogInterface.BUTTON_NEGATIVE NEUTRAL -> DialogInterface.BUTTON_NEUTRAL } - private fun AlertDialog.updateButtonsOnShow(rendering: AlertOverlay) { + protected fun AlertDialog.updateButtonsOnShow(rendering: AlertOverlay) { setOnShowListener(null) for (button in Button.values()) getButton(button.toId()).visibility = GONE diff --git a/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/ModalScreenOverlayDialogFactory.kt b/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/ModalScreenOverlayDialogFactory.kt index 0b505c87ad..875aeff39e 100644 --- a/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/ModalScreenOverlayDialogFactory.kt +++ b/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/ModalScreenOverlayDialogFactory.kt @@ -3,6 +3,8 @@ package com.squareup.workflow1.ui.container import android.app.Dialog import android.content.Context import android.graphics.Rect +import android.graphics.drawable.ColorDrawable +import android.util.TypedValue import android.view.KeyEvent import android.view.KeyEvent.ACTION_UP import android.view.KeyEvent.KEYCODE_BACK @@ -22,30 +24,42 @@ import com.squareup.workflow1.ui.toViewFactory import kotlin.reflect.KClass /** - * Convenient base class for building [ScreenOverlay] UIs that are compatible - * with [View.backPressedHandler], and which honor the [ModalArea] constraint - * placed in the [ViewEnvironment] by the standard [BodyAndModalsScreen] container. + * Default [OverlayDialogFactory] for [ModalScreenOverlay]. + * + * This class is non-final for ease of customization of [ModalScreenOverlay] handling, + * see [OverlayDialogFactoryFinder] for details. It is also convenient to use as a + * base class for custom [ScreenOverlay] rendering types. + * + * Dialogs built by this class are compatible with [View.backPressedHandler], and + * honor the [ModalArea] constraint placed in the [ViewEnvironment] by the + * standard [BodyAndModalsScreen] container. * * Ironically, [Dialog] instances are created with [FLAG_NOT_TOUCH_MODAL], to ensure * that events outside of the bounds reported by [updateBounds] reach views in * lower windows. See that method for details. */ @WorkflowUiExperimentalApi -public abstract class ModalScreenOverlayDialogFactory>( +public open class ModalScreenOverlayDialogFactory>( override val type: KClass ) : OverlayDialogFactory { /** * Called from [buildDialog]. Builds (but does not show) the [Dialog] to * display a [contentView] built for a [ScreenOverlay.content]. + * + * Custom implementations are not required to call `super`. + * + * Default implementation calls [Dialog.setModalContent]. */ - public abstract fun buildDialogWithContentView(contentView: View): Dialog + public open fun buildDialogWithContentView(contentView: View): Dialog { + return Dialog(contentView.context).also { it.setModalContent(contentView) } + } /** * If the [ScreenOverlay] displayed by a [dialog] created by this * factory is contained in a [BodyAndModalsScreen], this method will - * be called to report the bounds of the managing view. It is expected - * that such a dialog will be restricted to those bounds. + * be called to report the bounds of the managing view, as reported by [ModalArea]. + * It is expected that such a dialog will be restricted to those bounds. * * Honoring this contract makes it easy to define areas of the display * that are outside of the "shadow" of a modal dialog. Imagine an app @@ -125,3 +139,30 @@ public abstract class ModalScreenOverlayDialogFactory>( ) } } + +/** + * The default implementation of [ModalScreenOverlayDialogFactory.buildDialogWithContentView]. + * + * Sets the [background][Window.setBackgroundDrawable] of the receiver's [Window] based + * on its theme, if any, or else `null`. (Setting the background to `null` ensures the window + * can go full bleed.) + */ +@OptIn(WorkflowUiExperimentalApi::class) +public fun Dialog.setModalContent(contentView: View) { + setCancelable(false) + setContentView(contentView) + + // Welcome to Android. Nothing workflow-related here, this is just how one + // finds the window background color for the theme. I sure hope it's better in Compose. + val maybeWindowColor = TypedValue() + context.theme.resolveAttribute(android.R.attr.windowBackground, maybeWindowColor, true) + + val background = + if (maybeWindowColor.type in TypedValue.TYPE_FIRST_COLOR_INT..TypedValue.TYPE_LAST_COLOR_INT) { + ColorDrawable(maybeWindowColor.data) + } else { + // If we don't at least set it to null, the window cannot go full bleed. + null + } + window!!.setBackgroundDrawable(background) +} diff --git a/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/OverlayDialogFactoryFinder.kt b/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/OverlayDialogFactoryFinder.kt index 236fb4c1e5..7167c0074b 100644 --- a/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/OverlayDialogFactoryFinder.kt +++ b/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/OverlayDialogFactoryFinder.kt @@ -8,7 +8,41 @@ import com.squareup.workflow1.ui.WorkflowUiExperimentalApi /** * [ViewEnvironment] service object used by [Overlay.toDialogFactory] to find the right * [OverlayDialogFactoryScreenViewFactory]. The default implementation makes [AndroidOverlay] - * work, and provides a default binding for [AlertOverlay]. + * work, and provides default bindings for [AlertOverlay] and [ModalScreenOverlay]. + * + * Here is how this hook could be used to provide a custom dialog to handle [ModalScreenOverlay]: + * + * class MyDialogFactory : ModalScreenOverlayDialogFactory>( + * ModalScreenOverlay::class + * ) { + * override fun buildDialogWithContentView(contentView: View): Dialog { + * return super.buildDialogWithContentView(contentView).also { + * // Whatever, man, go wild. For that matter don't feel obligated to call super. + * } + * } + * } + * + * object MyFinder: OverlayDialogFactoryFinder { + * override fun getDialogFactoryForRendering( + * environment: ViewEnvironment, + * rendering: OverlayT + * ): OverlayDialogFactory { + * if (rendering is ModalScreenOverlay<*>) + * return MyDialogFactory as OverlayDialogFactory + * return super.getDialogFactoryForRendering(environment, rendering) + * } + * } + * + * class MyViewModel(savedState: SavedStateHandle) : ViewModel() { + * val renderings: StateFlow by lazy { + * val env = ViewEnvironment.EMPTY + (OverlayDialogFactoryFinder to MyFinder) + * renderWorkflowIn( + * workflow = MyRootWorkflow.mapRenderings { it.withEnvironment(env) }, + * scope = viewModelScope, + * savedStateHandle = savedState + * ) + * } + * } */ @WorkflowUiExperimentalApi public interface OverlayDialogFactoryFinder { @@ -22,7 +56,12 @@ public interface OverlayDialogFactoryFinder { return entry as? OverlayDialogFactory ?: (rendering as? AndroidOverlay<*>)?.dialogFactory as? OverlayDialogFactory ?: (rendering as? AlertOverlay)?.let { - AlertOverlayDialogFactory as OverlayDialogFactory + AlertOverlayDialogFactory() as OverlayDialogFactory + } + ?: (rendering as? ModalScreenOverlay<*>)?.let { + ModalScreenOverlayDialogFactory>( + ModalScreenOverlay::class + ) as OverlayDialogFactory } ?: throw IllegalArgumentException( "An OverlayDialogFactory should have been registered to display $rendering, " + diff --git a/workflow-ui/core-common/api/core-common.api b/workflow-ui/core-common/api/core-common.api index 25bf2f98cb..f18bf4368d 100644 --- a/workflow-ui/core-common/api/core-common.api +++ b/workflow-ui/core-common/api/core-common.api @@ -232,6 +232,12 @@ public final class com/squareup/workflow1/ui/container/EnvironmentScreenKt { public static final fun withRegistry (Lcom/squareup/workflow1/ui/Screen;Lcom/squareup/workflow1/ui/ViewRegistry;)Lcom/squareup/workflow1/ui/container/EnvironmentScreen; } +public final class com/squareup/workflow1/ui/container/ModalScreenOverlay : com/squareup/workflow1/ui/container/ScreenOverlay { + public fun (Lcom/squareup/workflow1/ui/Screen;)V + public fun getCompatibilityKey ()Ljava/lang/String; + public fun getContent ()Lcom/squareup/workflow1/ui/Screen; +} + public abstract interface class com/squareup/workflow1/ui/container/Overlay { } diff --git a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/NamedScreen.kt b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/NamedScreen.kt index c4767072e6..28c6eef6b3 100644 --- a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/NamedScreen.kt +++ b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/NamedScreen.kt @@ -4,6 +4,8 @@ package com.squareup.workflow1.ui * Allows [Screen] renderings that do not implement [Compatible] themselves to be distinguished * by more than just their type. Instances are [compatible] if they have the same name * and have [compatible] [wrapped] fields. + * + * UI kits are expected to provide handling for this class by default. */ @WorkflowUiExperimentalApi public data class NamedScreen( diff --git a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/AlertOverlay.kt b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/AlertOverlay.kt index 2dae78ba68..c6576fb43e 100644 --- a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/AlertOverlay.kt +++ b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/AlertOverlay.kt @@ -4,6 +4,8 @@ import com.squareup.workflow1.ui.WorkflowUiExperimentalApi /** * Models a typical "You sure about that?" alert box. + * + * UI kits are expected to provide handling for this class by default. */ @WorkflowUiExperimentalApi public data class AlertOverlay( diff --git a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/BackStackScreen.kt b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/BackStackScreen.kt index 8cd82a1073..4b52e6573b 100644 --- a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/BackStackScreen.kt +++ b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/BackStackScreen.kt @@ -10,6 +10,8 @@ import com.squareup.workflow1.ui.WorkflowUiExperimentalApi * * Effectively a list that can never be empty. * + * UI kits are expected to provide handling for this class by default. + * * @param bottom the bottom-most entry in the stack * @param rest the rest of the stack, empty by default */ diff --git a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/BodyAndModalsScreen.kt b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/BodyAndModalsScreen.kt index 0e598389d7..1839abb452 100644 --- a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/BodyAndModalsScreen.kt +++ b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/BodyAndModalsScreen.kt @@ -7,6 +7,8 @@ import com.squareup.workflow1.ui.WorkflowUiExperimentalApi * A screen that may stack a number of modal [Overlay]s over a body. * While modals are present, the body is expected to ignore any * input events -- touch, keyboard, etc. + * + * UI kits are expected to provide handling for this class by default. */ @WorkflowUiExperimentalApi public class BodyAndModalsScreen( diff --git a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/EnvironmentScreen.kt b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/EnvironmentScreen.kt index 52511f2ba5..e724491ba8 100644 --- a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/EnvironmentScreen.kt +++ b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/EnvironmentScreen.kt @@ -12,6 +12,8 @@ import com.squareup.workflow1.ui.merge * Typically the rendering type (`RenderingT`) of the root of a UI workflow, * but can be used at any point to modify the [ViewEnvironment] received from * a parent view. + * + * UI kits are expected to provide handling for this class by default. */ @WorkflowUiExperimentalApi public class EnvironmentScreen( diff --git a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/ModalScreenOverlay.kt b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/ModalScreenOverlay.kt new file mode 100644 index 0000000000..2591ecca61 --- /dev/null +++ b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/ModalScreenOverlay.kt @@ -0,0 +1,14 @@ +package com.squareup.workflow1.ui.container + +import com.squareup.workflow1.ui.Screen +import com.squareup.workflow1.ui.WorkflowUiExperimentalApi + +/** + * A basic [ScreenOverlay] that fills all available space. + * + * UI kits are expected to provide handling for this class by default. + */ +@WorkflowUiExperimentalApi +public class ModalScreenOverlay( + public override val content: ContentT +) : ScreenOverlay diff --git a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/ScreenOverlay.kt b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/ScreenOverlay.kt index 2a757ef8b3..23a459ae28 100644 --- a/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/ScreenOverlay.kt +++ b/workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/ScreenOverlay.kt @@ -12,5 +12,6 @@ import com.squareup.workflow1.ui.WorkflowUiExperimentalApi public interface ScreenOverlay : Overlay, Compatible { public val content: ContentT - override val compatibilityKey: String get() = keyFor(content, "ScreenOverlay") + override val compatibilityKey: String + get() = keyFor(content, this::class.simpleName ?: ScreenOverlay::class.simpleName!!) }