Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions buildSrc/src/main/java/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ object Dependencies {
const val activity = "androidx.activity:activity:1.3.0"
const val activityKtx = "androidx.activity:activity-ktx:1.3.0"
const val appcompat = "androidx.appcompat:appcompat:1.3.1"
const val coreKtx = "androidx.core:core-ktx:1.6.0"

object Compose {
const val activity = "androidx.activity:activity-compose:1.3.1"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")

package com.squareup.sample.container.panel

import com.squareup.workflow1.ui.Screen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,23 @@ import com.squareup.workflow1.StatefulWorkflow
import com.squareup.workflow1.WorkflowAction.Companion.noAction
import com.squareup.workflow1.action
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
import com.squareup.workflow1.ui.modal.AlertContainerScreen
import com.squareup.workflow1.ui.modal.AlertScreen
import com.squareup.workflow1.ui.modal.AlertScreen.Button.NEGATIVE
import com.squareup.workflow1.ui.modal.AlertScreen.Button.POSITIVE
import com.squareup.workflow1.ui.modal.AlertScreen.Event.ButtonClicked
import com.squareup.workflow1.ui.modal.AlertScreen.Event.Canceled
import com.squareup.workflow1.ui.container.AlertOverlay
import com.squareup.workflow1.ui.container.AlertOverlay.Button.NEGATIVE
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 com.squareup.workflow1.ui.container.BodyAndModalsScreen
import com.squareup.workflow1.ui.toParcelable
import com.squareup.workflow1.ui.toSnapshot
import kotlinx.parcelize.Parcelize

/**
* Wraps [HelloBackButtonWorkflow] to (sometimes) pop a confirmation dialog when the back
* Wraps [HelloBackButtonWorkflow] to (sometimes) pop a confirmation alert when the back
* button is pressed.
*/
@OptIn(WorkflowUiExperimentalApi::class)
object AreYouSureWorkflow : StatefulWorkflow<Unit, State, Finished, AlertContainerScreen<*>>() {
object AreYouSureWorkflow :
StatefulWorkflow<Unit, State, Finished, BodyAndModalsScreen<*, AlertOverlay>>() {
override fun initialState(
props: Unit,
snapshot: Snapshot?
Expand All @@ -44,42 +45,42 @@ object AreYouSureWorkflow : StatefulWorkflow<Unit, State, Finished, AlertContain
renderProps: Unit,
renderState: State,
context: RenderContext
): AlertContainerScreen<*> {
): BodyAndModalsScreen<*, AlertOverlay> {
val ableBakerCharlie = context.renderChild(HelloBackButtonWorkflow, Unit) { noAction() }

return when (renderState) {
Running -> {
AlertContainerScreen(
BackButtonScreen(ableBakerCharlie) {
// While we always provide a back button handler, by default the view code
// associated with BackButtonScreen ignores ours if the view created for the
// wrapped rendering sets a handler of its own. (Set BackButtonScreen.override
// to change this precedence.)
context.actionSink.send(maybeQuit)
}
BodyAndModalsScreen(
BackButtonScreen(ableBakerCharlie) {
// While we always provide a back button handler, by default the view code
// associated with BackButtonScreen ignores ours if the view created for the
// wrapped rendering sets a handler of its own. (Set BackButtonScreen.override
// to change this precedence.)
context.actionSink.send(maybeQuit)
}
)
}
Quitting -> {
val dialog = AlertScreen(
buttons = mapOf(
POSITIVE to "I'm Positive",
NEGATIVE to "Negatory"
),
message = "Are you sure you want to do this thing?",
onEvent = { alertEvent ->
context.actionSink.send(
when (alertEvent) {
is ButtonClicked -> when (alertEvent.button) {
POSITIVE -> confirmQuit
else -> cancelQuit
}
Canceled -> cancelQuit
}
)
}
val alert = AlertOverlay(
buttons = mapOf(
POSITIVE to "I'm Positive",
NEGATIVE to "Negatory"
),
message = "Are you sure you want to do this thing?",
onEvent = { alertEvent ->
context.actionSink.send(
when (alertEvent) {
is ButtonClicked -> when (alertEvent.button) {
POSITIVE -> confirmQuit
else -> cancelQuit
}
Canceled -> cancelQuit
}
)
}
)

AlertContainerScreen(ableBakerCharlie, dialog)
BodyAndModalsScreen(ableBakerCharlie, alert)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@file:Suppress("DEPRECATION")
@file:OptIn(WorkflowUiExperimentalApi::class)

package com.squareup.sample.hellobackbutton
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")

package com.squareup.sample.dungeon

import android.content.Context.VIBRATOR_SERVICE
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")

package com.squareup.sample.dungeon

import com.squareup.sample.dungeon.DungeonAppWorkflow.Props
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")

package com.squareup.sample.dungeon

import android.os.Vibrator
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")

package com.squareup.sample.mainactivity

import android.os.Bundle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.squareup.workflow1.ui.modal.AlertScreen.Event.Canceled
* Renders the [AlertScreen]s of an [AlertContainerScreen] as [AlertDialog]s.
*/
@WorkflowUiExperimentalApi
@Deprecated("Use BodyAndModalsContainer and the built in OverlayDialogFactory for AlertOverlay")
public class AlertContainer @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")

package com.squareup.workflow1.ui.modal

import com.squareup.workflow1.ui.Screen
Expand All @@ -9,6 +11,16 @@ import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
* @param B the type of [beneathModals]
*/
@WorkflowUiExperimentalApi
// Can't quite deprecate this yet, because such warnings are impossible to suppress
// in the typealias uses in the Tic Tac Toe sample. Will uncomment before merging to main.
// https://github.com/square/workflow-kotlin/issues/589
// @Deprecated(
// "Use BodyAndModalsScreen",
// ReplaceWith(
// "BodyAndModalsScreen<B>(beneathModals, modals)",
// "com.squareup.workflow1.ui.container.BodyAndModalsScreen"
// )
// )
public data class AlertContainerScreen<B : Any>(
override val beneathModals: B,
override val modals: List<AlertScreen> = emptyList()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")

package com.squareup.workflow1.ui.modal

import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
Expand All @@ -6,6 +8,16 @@ import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
* Models a typical "You sure about that?" alert box.
*/
@WorkflowUiExperimentalApi
// Can't quite deprecate this yet, because such warnings are impossible to suppress
// in the typealias uses in the Tic Tac Toe sample. Will uncomment before merging to main.
// https://github.com/square/workflow-kotlin/issues/589
// @Deprecated(
// "Use AlertOverlay",
// ReplaceWith(
// "AlertOverlay(buttons, message, title, cancelable, onEvent)",
// "com.squareup.workflow1.ui.container.AlertOverlay"
// )
// )
public data class AlertScreen(
val buttons: Map<Button, String> = emptyMap(),
val message: String = "",
Expand All @@ -32,9 +44,9 @@ public data class AlertScreen(
other as AlertScreen

return buttons == other.buttons &&
message == other.message &&
title == other.title &&
cancelable == other.cancelable
message == other.message &&
title == other.title &&
cancelable == other.cancelable
}

override fun hashCode(): Int {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
* like `ModalContainer` in the `workflow-ui:core-android` module.
*/
@WorkflowUiExperimentalApi
// Can't quite deprecate this yet, because such warnings are impossible to suppress
// in the typealias uses in the Tic Tac Toe sample. Will uncomment before merging to main.
// https://github.com/square/workflow-kotlin/issues/589
// @Deprecated("Use BodyAndModalsScreen")
public interface HasModals<out B : Any, out M : Any> {
public val beneathModals: B
public val modals: List<M>
Expand Down
59 changes: 49 additions & 10 deletions workflow-ui/core-android/api/core-android.api
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,6 @@ public abstract interface class com/squareup/workflow1/ui/AndroidScreen : com/sq
public abstract fun getViewFactory ()Lcom/squareup/workflow1/ui/ScreenViewFactory;
}

public final class com/squareup/workflow1/ui/AndroidScreenKt {
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 final class com/squareup/workflow1/ui/AndroidViewEnvironmentKt {
public static final fun getViewFactoryForRendering (Lcom/squareup/workflow1/ui/ViewEnvironment;Lcom/squareup/workflow1/ui/Screen;)Lcom/squareup/workflow1/ui/ScreenViewFactory;
public static final fun showFirstRendering (Landroid/view/View;)V
}

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;
Expand Down Expand Up @@ -101,6 +91,12 @@ public final class com/squareup/workflow1/ui/ScreenViewFactory$DefaultImpls {
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;
}

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 abstract interface class com/squareup/workflow1/ui/ScreenViewRunner {
public static final field Companion Lcom/squareup/workflow1/ui/ScreenViewRunner$Companion;
public abstract fun showRendering (Lcom/squareup/workflow1/ui/Screen;Lcom/squareup/workflow1/ui/ViewEnvironment;)V
Expand Down Expand Up @@ -208,6 +204,16 @@ public final class com/squareup/workflow1/ui/androidx/WorkflowLifecycleOwner$Com
public static synthetic fun installOn$default (Lcom/squareup/workflow1/ui/androidx/WorkflowLifecycleOwner$Companion;Landroid/view/View;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
}

public final class com/squareup/workflow1/ui/container/AlertDialogThemeResId : com/squareup/workflow1/ui/ViewEnvironmentKey {
public static final field INSTANCE Lcom/squareup/workflow1/ui/container/AlertDialogThemeResId;
public fun getDefault ()Ljava/lang/Integer;
public synthetic fun getDefault ()Ljava/lang/Object;
}

public abstract interface class com/squareup/workflow1/ui/container/AndroidOverlay : com/squareup/workflow1/ui/container/Overlay {
public abstract fun getDialogFactory ()Lcom/squareup/workflow1/ui/container/OverlayDialogFactory;
}

public final class com/squareup/workflow1/ui/container/BackStackConfig : java/lang/Enum {
public static final field Companion Lcom/squareup/workflow1/ui/container/BackStackConfig$Companion;
public static final field First Lcom/squareup/workflow1/ui/container/BackStackConfig;
Expand Down Expand Up @@ -240,6 +246,39 @@ public final class com/squareup/workflow1/ui/container/BackStackStateKeyKt {
public static final fun withBackStackStateKeyPrefix (Lcom/squareup/workflow1/ui/ViewEnvironment;Ljava/lang/String;)Lcom/squareup/workflow1/ui/ViewEnvironment;
}

public final class com/squareup/workflow1/ui/container/LayeredDialogs {
public fun <init> (Landroid/content/Context;Lkotlin/jvm/functions/Function0;)V
public fun <init> (Landroid/view/View;)V
public final fun getHasDialogs ()Z
public final fun onRestoreInstanceState (Lcom/squareup/workflow1/ui/container/LayeredDialogs$SavedState;)V
public final fun onSaveInstanceState ()Lcom/squareup/workflow1/ui/container/LayeredDialogs$SavedState;
public final fun update (Ljava/util/List;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function0;)V
public static synthetic fun update$default (Lcom/squareup/workflow1/ui/container/LayeredDialogs;Ljava/util/List;Lcom/squareup/workflow1/ui/ViewEnvironment;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V
}

public final class com/squareup/workflow1/ui/container/LayeredDialogs$SavedState : android/os/Parcelable {
public static final field CREATOR Lcom/squareup/workflow1/ui/container/LayeredDialogs$SavedState$CREATOR;
public fun <init> (Landroid/os/Parcel;)V
public fun describeContents ()I
public fun writeToParcel (Landroid/os/Parcel;I)V
}

public final class com/squareup/workflow1/ui/container/LayeredDialogs$SavedState$CREATOR : android/os/Parcelable$Creator {
public fun createFromParcel (Landroid/os/Parcel;)Lcom/squareup/workflow1/ui/container/LayeredDialogs$SavedState;
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
public fun newArray (I)[Lcom/squareup/workflow1/ui/container/LayeredDialogs$SavedState;
public synthetic fun newArray (I)[Ljava/lang/Object;
}

public abstract interface class com/squareup/workflow1/ui/container/OverlayDialogFactory : com/squareup/workflow1/ui/ViewRegistry$Entry {
public abstract fun buildDialog (Lcom/squareup/workflow1/ui/container/Overlay;Lcom/squareup/workflow1/ui/ViewEnvironment;Landroid/content/Context;)Landroid/app/Dialog;
public abstract fun updateDialog (Landroid/app/Dialog;Lcom/squareup/workflow1/ui/container/Overlay;Lcom/squareup/workflow1/ui/ViewEnvironment;)V
}

public final class com/squareup/workflow1/ui/container/OverlayDialogFactoryKt {
public static final fun toDialogFactory (Lcom/squareup/workflow1/ui/container/Overlay;Lcom/squareup/workflow1/ui/ViewEnvironment;)Lcom/squareup/workflow1/ui/container/OverlayDialogFactory;
}

public final class com/squareup/workflow1/ui/container/ViewStateCache : android/os/Parcelable {
public static final field CREATOR Lcom/squareup/workflow1/ui/container/ViewStateCache$CREATOR;
public fun <init> ()V
Expand Down
1 change: 1 addition & 0 deletions workflow-ui/core-android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dependencies {
api(Dependencies.Kotlin.Stdlib.jdk6)

implementation(Dependencies.AndroidX.activity)
implementation(Dependencies.AndroidX.coreKtx)
implementation(Dependencies.AndroidX.fragment)
implementation(Dependencies.AndroidX.Lifecycle.ktx)
implementation(Dependencies.AndroidX.savedstate)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package com.squareup.workflow1.ui

import android.content.Context
import android.view.View
import android.view.ViewGroup

/**
* Interface implemented by a rendering class to allow it to drive an Android UI
* via an appropriate [ScreenViewFactory] implementation.
Expand Down Expand Up @@ -31,65 +27,14 @@ import android.view.ViewGroup
* reason, you can use [ViewRegistry] to bind your renderings to [ScreenViewFactory]
* implementations at runtime. Also note that a [ViewRegistry] entry will override
* the [viewFactory] returned by an [AndroidScreen].
*
* @see com.squareup.workflow1.ui.container.AndroidOverlay
*/
@WorkflowUiExperimentalApi
public interface AndroidScreen<V : AndroidScreen<V>> : Screen {
public interface AndroidScreen<S : AndroidScreen<S>> : Screen {
/**
* Used to build instances of [android.view.View] as needed to
* display renderings of this type.
*/
public val viewFactory: ScreenViewFactory<V>
}

/**
* It is usually more convenient to use [WorkflowViewStub] or [DecorativeScreenViewFactory]
* than to call this method directly.
*
* Finds a [ScreenViewFactory] to create a [View] to display [this@buildView]. The new view
* can be updated via calls to [View.showRendering] -- that is, it is guaranteed that
* [bindShowRendering] has been called on this view.
*
* The returned view will have a
* [WorkflowLifecycleOwner][com.squareup.workflow1.ui.androidx.WorkflowLifecycleOwner]
* set on it. The returned view must EITHER:
*
* 1. Be attached at least once to ensure that the lifecycle eventually gets destroyed (because its
* parent is destroyed), or
* 2. Have its
* [WorkflowLifecycleOwner.destroyOnDetach][com.squareup.workflow1.ui.androidx.WorkflowLifecycleOwner.destroyOnDetach]
* called, which will either schedule the
* lifecycle to be destroyed if the view is attached, or destroy it immediately if it's detached.
*
* [WorkflowViewStub] takes care of this chore itself.
*
* @param initializeView Optional function invoked immediately after the [View] is
* created (that is, immediately after the call to [ScreenViewFactory.buildView]).
* [showRendering], [getRendering] and [environment] are all available when this is called.
* Defaults to a call to [View.showFirstRendering].
*
* @throws IllegalArgumentException if no builder can be find for type [ScreenT]
*
* @throws IllegalStateException if the matching [ScreenViewFactory] fails to call
* [View.bindShowRendering] when constructing the view
*/
@WorkflowUiExperimentalApi
public fun <ScreenT : Screen> ScreenT.buildView(
viewEnvironment: ViewEnvironment,
contextForNewView: Context,
container: ViewGroup? = null,
initializeView: View.() -> Unit = { showFirstRendering() }
): View {
val entry = viewEnvironment.getViewFactoryForRendering(this)
val viewFactory = (entry as? ScreenViewFactory<ScreenT>)
?: error("Require a ScreenViewFactory for $this, found $entry")

return viewFactory.buildView(
this, viewEnvironment, contextForNewView, container
).also { view ->
checkNotNull(view.showRenderingTag) {
"View.bindShowRendering should have been called for $view, typically by the " +
"${ScreenViewFactory::class.java.name} that created it."
}
initializeView.invoke(view)
}
public val viewFactory: ScreenViewFactory<S>
}
Loading