-
Notifications
You must be signed in to change notification settings - Fork 104
Introduces Overlay, and its first uses: BodyAndModalsScreen, AlertOverlay #588
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
bfa3a55
to
b928193
Compare
232fe8d
to
58ca707
Compare
@@ -31,3 +37,87 @@ public interface ScreenViewFactory<in RenderingT : Screen> : ViewRegistry.Entry< | |||
container: ViewGroup? = null | |||
): View | |||
} | |||
|
|||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outside of making getViewFactoryForRendering
non-public, no real changes in this file, just moved code in from another location.
fef7cac
to
4976aeb
Compare
...-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/BodyAndModalsContainer.kt
Outdated
Show resolved
Hide resolved
59eaca3
to
7781b18
Compare
?: (rendering as? BackStackScreen<*>)?.let { | ||
BackStackScreenViewFactory as ScreenViewFactory<ScreenT> | ||
} | ||
?: (rendering as? BodyAndModalsScreen<*, *>)?.let { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I lied -- this line is new
workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/RectProvider.kt
Outdated
Show resolved
Hide resolved
workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/DialogRunner.kt
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank-you for the final kdoc commit. I will likely need more to understand everything going on here, but hopefully @helios175 has a better understanding?
...low-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/ListenToCoordinates.kt
Outdated
Show resolved
Hide resolved
...low-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/ListenToCoordinates.kt
Outdated
Show resolved
Hide resolved
import com.squareup.workflow1.ui.bindShowRendering | ||
|
||
@WorkflowUiExperimentalApi | ||
internal class BodyAndModalsContainer @JvmOverloads constructor( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the risk of another bikeshed why isn't this BodyAndOverlaysContainer
? And the screen BodyAndOverlaysScreen
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well spotted, and not an accident. I've realized that modals are a subset of overlays, and this name is meant to respect that distinction -- a modal is an overlay whose presence implies that things beneath it are blocked from receiving any events. The presence of a modal is a visual indicator that we are in a different mode of the app -- channeling ancient Macintosh developer docs here.
Contrast this with tooltips and other pop-ups that are also naturally modeled via Overlay, and which should not have the side effect of modality.
Fell into this because the container itself actually has to participate -- dialogs simply can't do the job all by themselves, as we've re-learned painfully through BugSnag in the past year. (Thinking we should double down on that fact and put the container in charge of showing the scrim, which would fix double-shadow issues we have right now.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes this makes total sense and is a great place to settle. We should document this.
workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/DialogStack.kt
Outdated
Show resolved
Hide resolved
workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/DialogStack.kt
Outdated
Show resolved
Hide resolved
...flow-ui/core-common/src/main/java/com/squareup/workflow1/ui/container/BodyAndModalsScreen.kt
Show resolved
Hide resolved
Updated to remove the controversial bits (RectangleProvider and its uses), which are also unused at the moment. Figure we can get this merged and then sort that out. Squashed what's left and updated the commit message. |
// Custom behavior from the container to be fired when we show a new dialog. | ||
// The default modal container uses this to flush its body of partially | ||
// processed touch events that should have been blocked by the modal. | ||
beforeShowing() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably will need to tweak this to pass the Dialog itself in the next PR.
} | ||
} | ||
|
||
(runners - newRunners.toSet()).forEach { it.dismiss() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The IDE prompted me to add the toSet()
call as an optimization, and I'm very suggestible.
Damn espresso tests are so flaky, I can't tell if I've made them more so. |
Simply cannot get a green build. #590 is awful, and clearly unrelated to this PR, we didn't change that app or anything it uses. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely understand now! Still have more naming change requests that I think coudl be helpful.
return compatible(this.rendering, rendering) | ||
} | ||
|
||
fun showRendering( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would change this to bindRendering
as I'm thinking of the RecyclerView ViewHolder analogy. What you are doing is 'binding' the rendering to this dialog - nothing is actually changing with respect to its shown/hidden state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know why exactly but bind
bugs me. How about canTakeRendering
and takeRendering
?
import com.squareup.workflow1.ui.compatible | ||
|
||
@WorkflowUiExperimentalApi | ||
internal class DialogRunner<T : Overlay>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would change this to DialogHolder
. I realize we use Runner
elsewhere but I also just realized that while I got the 'Runner' metaphor the 'ViewHolder' analogy (as in the RecyclerView sense) is much more powerful to me as an Android person with RecyclerView experience.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great call. When we use Runner
elsewhere it really means something else entirely.
} | ||
} | ||
|
||
fun canShowRendering(rendering: Overlay): Boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
canBindRendering
?
* Provides a [LifecycleOwner] per managed dialog, and view persistence support. | ||
*/ | ||
@WorkflowUiExperimentalApi | ||
public class DialogStack( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DialogStackContainer
we use the Container
prefix for these logic classes that deal with interaction between groups of Views bound to Renderings no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Container
isn't good b/c that's consistently meant "a workflow view that displays other workflow views". This is a support class to create such views.
And as @helios175 pointed out, Stack
isn't good because this is so completely different from BackStack
.
How about LayeredDialogHolders
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, but DialogHolder
is a private type. So just LayeredDialogs
.
/** | ||
* 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. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** | |
* 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. | |
*/ | |
/** | |
* 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. | |
* Passing an [Overlay] rendering as part of [modals] here marks that | |
* Overlay as modal - that is, it should block input events around outside | |
* of its content area. The logic for that input event blocking is handled | |
* for users of this screen by the internal [BodyAndModalsContainer]. | |
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should block input events around outside of its content area
Oh, no no no no no. It should only block events within the bounds of the body. Blocking events outside of that area is a contract violation. And in fact turning on the "modal" flag for an Android Dialog implementation would be a bug precisely because of this.
I'm too tired to phrase this properly right now. Will come up with something before merging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually…let me leave this as is and rephrase with the next PR, where I'll actually be implementing proper custom dialogs. There may be more nuances then.
Update with name changes proposed during review:
Still need to find a home for the essay explaining |
…rlay New platform-neutral rendering types: - `Overlay` is a marker type that identifies a window-like rendering. - `AlertOverlay` is the first use of `Overlay`, models Android's `AlertDialog` - `BodyAndModalsScreen` has a body `Screen` covered by zero or more `Overlay`s that are given a modal treatment -- its body is shielded from events while any `Overlay` is present. Android support code that uses them to manage `Dialog`s: - `OverlayDialogFactory` is to `Overlay` as `ScreenViewRunner` and `ScreenViewFactory` are to `Screen`. - `LayeredDialogs` is a support class that uses `OverlayDialogFactory` to display `List<Overlay>` as a pile of `Dialog`s. It's meant to simplify the implementation of container views that use `Overlay`. - `BodyAndModalsContainer` is a `FrameLayout` that uses `DialogStack` to display `BodyAndModalScreen`. First use of `LayeredDialogs`. - `AlertOverlayDialogFactory` creates `AlertDialog` instances for `AlertOverlay`. Note that `BodyAndModalsContainer` and `AlertOverlayDialogFactory` are `internal`, with default binings built into `Overlay.toDialogFactory()` and `Screen.buildView`. Also note that `AndroidViewEnvironment.kt` and the bulk of `AndroidScreen.kt` have been moved to `ScreenViewFactory.kt`, which seemed like a less surprising home for them. Updates `hellobackbutton` sample to demonstrate the use of all of this. Note the commented out deprecations. Turns out its impossible to suppress deprecation warnings in `typealias` calls like the ones our sample apps are still using, and those can't be ported until we have a replacement for `ModalViewContainer`. Tracked in #589.
Updated the kdoc on /**
* Marker interface implemented by window-like renderings that map to a layer above
* a base [Screen][com.squareup.workflow1.ui.Screen].
*
* Note that an Overlay is not necessarily a modal window, though that is how
* they are used in [BodyAndModalsScreen]. An Overlay can be any part of the UI
* that visually floats in a layer above the main UI, or above other Overlays.
* Possible examples include alerts, drawers, and tooltips.
*
* Whether or not an Overlay's presence indicates that events are blocked from lower
* layers is a separate concern.
*/
@WorkflowUiExperimentalApi
public interface Overlay If no one complains I'll merge this when CI blesses it. |
New platform-neutral rendering types:
Overlay
is a marker type that identifies a window-like rendering.AlertOverlay
is the first use ofOverlay
, models Android'sAlertDialog
BodyAndModalsScreen
has a bodyScreen
covered by zero or moreOverlay
s that are given a modal treatment -- its body is shieldedfrom events while any
Overlay
is present.Android support code that uses them to manage
Dialog
s:OverlayDialogFactory
is toOverlay
asScreenViewRunner
andScreenViewFactory
are toScreen
DialogStack
usesOverlayDialogFactory
to displayList<Overlay>
as a pile of
Dialog
sBodyAndModalsContainer
is aFrameLayout
that usesDialogStack
to display
BodyAndModalScreen
AlertOverlayDialogFactory
createsAlertDialog
instances forAlertOverlay
Note that
BodyAndModalsContainer
andAlertOverlayDialogFactory
areinternal
, with default binings built intoOverlay.toDialogFactory()
and
Screen.buildView
.Also note that
AndroidViewEnvironment.kt
and the bulk ofAndroidScreen.kt
have been moved to
ScreenViewFactory.kt
, which seemed like a lesssurprising home for them.
Updates
hellobackbutton
sample to demonstrate the use of all of this.Note the commented out deprecations. Turns out its impossible to suppress
deprecation warnings in
typealias
calls like the ones our sample apps arestill using, and those can't be ported until we have a replacement for
ModalViewContainer
. Tracked in #589.