Skip to content
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

1/4 fun ComponentDialog.setContent() replaces ScreenOverlayDialogFactory #1026

Merged
merged 4 commits into from
Jun 26, 2023

Conversation

rjrjr
Copy link
Contributor

@rjrjr rjrjr commented Jun 14, 2023

With AndroidX 1.6.0, ComponentDialog serves as its own LifecycleOwner and OnBackPressedDispatcherOwner. To take advantage of this we introduce a new ComponentDialog.setContent extension function, deprecate ScreenOverlayDialogFactory, and deprecate our hooks for customizing Dialog back press handling.

Related kdoc is improved, and a factory function is bound to OverlayDialogFactory.Companion.

Update: this PR also collects three downstream ones, in prepration for merging them all into main:

@rjrjr rjrjr changed the title fun ComponentDialog.setContent() replaces ScreenOverlayDialogFactory 1. fun ComponentDialog.setContent() replaces ScreenOverlayDialogFactory Jun 14, 2023
@rjrjr rjrjr changed the title 1. fun ComponentDialog.setContent() replaces ScreenOverlayDialogFactory 1/3 fun ComponentDialog.setContent() replaces ScreenOverlayDialogFactory Jun 14, 2023
@rjrjr rjrjr force-pushed the ray/1-component-set-dialog branch from 8ff77ce to 7154b36 Compare June 14, 2023 21:03
@rjrjr
Copy link
Contributor Author

rjrjr commented Jun 14, 2023

LeakCanary failures. 😬

@rjrjr
Copy link
Contributor Author

rjrjr commented Jun 14, 2023

LeakCanary failures. 😬

Oh -- actually espresso failures. Pretty sure fixing those will also fix the leaks.

@rjrjr rjrjr force-pushed the ray/1-component-set-dialog branch from 7154b36 to 7f258e5 Compare June 14, 2023 22:37
Copy link

@helios175 helios175 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have my blessing. I'll look at the others...

@rjrjr rjrjr force-pushed the ray/1-component-set-dialog branch from 7f258e5 to e4f4fe1 Compare June 15, 2023 16:48
@rjrjr rjrjr marked this pull request as ready for review June 15, 2023 16:48
@rjrjr rjrjr requested review from a team and zach-klippenstein as code owners June 15, 2023 16:48
@rjrjr rjrjr force-pushed the ray/1-component-set-dialog branch from e4f4fe1 to 8d1228d Compare June 15, 2023 17:16
@rjrjr
Copy link
Contributor Author

rjrjr commented Jun 15, 2023

This loses the crucial call to window.addFlags(FLAG_NOT_TOUCH_MODAL), required to allow clicks past a "modal" dialog that doesn't fill the screen. Missed it because I still haven't figured out how to cover that behavior in NestedOverlaysAppTest w/o open sourcing a ton of horrible Espresso hackery we use in house. Maybe time to do something about that. :(

@rjrjr rjrjr force-pushed the ray/1-component-set-dialog branch from 8d1228d to 5973c5b Compare June 15, 2023 23:24
@rjrjr rjrjr changed the title 1/3 fun ComponentDialog.setContent() replaces ScreenOverlayDialogFactory 1/4 fun ComponentDialog.setContent() replaces ScreenOverlayDialogFactory Jun 15, 2023
@rjrjr
Copy link
Contributor Author

rjrjr commented Jun 15, 2023

This loses the crucial call to window.addFlags(FLAG_NOT_TOUCH_MODAL), required to allow clicks past a "modal" dialog that doesn't fill the screen. Missed it because I still haven't figured out how to cover that behavior in NestedOverlaysAppTest w/o open sourcing a ton of horrible Espresso hackery we use in house. Maybe time to do something about that. :(

Fixed.

@rjrjr rjrjr force-pushed the ray/1-component-set-dialog branch 2 times, most recently from a9e7dda to 6f4712f Compare June 24, 2023 00:51
rjrjr added 4 commits June 26, 2023 14:42
With AndroidX 1.6.0, `ComponentDialog` serves as its own `LifecycleOwner` and `OnBackPressedDispatcherOwner`. To take advantage of this we introduce a new `ComponentDialog.setContent` extension function, deprecate `ScreenOverlayDialogFactory`, and deprecate our hooks for customizing `Dialog` back press handling.

Related kdoc is improved, and a factory function is bound to `OverlayDialogFactory.Companion`.
`fun View.findViewTreeOnBackPressedDispatcherOwner()` is AndroidX's preferred entry point to the exciting new world of `OnBackPressedDispatcherOwner`. With this PR we support it explicitly, in particular taking care to ensure that it can be called by newly constructed views before they have been attached to a parent. That is, we take care to make eager calls `View.setViewTreeSavedStateRegistryOwner` on every view we build.

We accomplish this mainly by riding the rails previously laid down via `WorkflowLifecycleOwner.installOn`, which now requires an `OnBackPressedDispatcherOwner` parameter. (This is the method used by `WorkflowViewStub` _et al_ to ensure that we're managing the JetPack Lifecycle correctly, and `OnBackPressedDispatcherOwner` is just another piece of that puzzle.)

In aid of that, we introduce a new `ViewEnvironmentKey`, `OnBackPressedDispatcherOwnerKey`. It is initialized by `WorkflowLayout`, our new `ComponentDialog.setContent` extension, and `@Composable fun WorkflowRendering()`. This key is not intended for use by feature code, it's more of an implementation detail that has to stay public to allow custom containers to be built. It ensures that `WorkflowViewStub` and friends will have access to the correct `OnBackPressedDispatcherOwner` before they have access to a parent view.

TODO: add tests of `@Composable fun BackHandler()`, in both activity and dialog windows.
`val View.backPressedHandler` is overly complicated and kind of naive. The replacement, `fun View.setBackHandler()`, carefully echoes the API and behavior of [`@Composable fun BackHandler()`](https://developer.android.com/reference/kotlin/androidx/activity/compose/package-summary#BackHandler(kotlin.Boolean,kotlin.Function0)). We also provide a single argument overload that take a nullable handler function, and sets `enabled` to true for non-`null` handlers, false for `null`.

The biggest change in implementation is that we now use the preferred `OnBackPressedDispatcher.addCallback(LifecycleOwner, OnBackPressedCallback)` overload, which should allow AndroidX to do all the lifecycle bookkeeping for us -- taking advantage of all the hard work we've done to make `WorkflowLifecycleOwner` behave correctly.

This work revealed a problem where there was no `WorkflowLifecycleOwner` in place in time for the first update of the content view in `ScreenOverlayDialogFactory`, which prevented us from repeating that mistake in the new `ComponentDialog.setContent()` extension function introduced two PRs up. So that's nice.
1. `setContent` as a method name gave no clue that we were returning a new manager object, so now it's called `asDialogHolderWithContent`

2. Hard coding the call to `Dialog.setContent` interferes with code that needs to make that call itself. We now accept a `setContent: (ScreenViewHolder<C>) -> Unit` lambda to do that work, which defaults to the current behavior.

3. Decouple building and starting views. This allows us to ensure that a Dialog's content view is attached to its window before its first rendering -- before the first call to `ScreenViewHolder.show`. Necessary to ensure that the strictly view-tree-based AndroidX `findViewTreeOnBackPressedDispatcherOwner()` call works immediately. This was always the original intention, but never actually found a use case until now.

4. Moves most of that default behavior to a public `Dialog.fixBackgroundAndDimming` extension function to keep it available and more self documenting (hard learned lessons in there). Pretty similar to how `ScreenOverlayDialogFactory` acts.

5. Big kdoc update
@rjrjr rjrjr force-pushed the ray/1-component-set-dialog branch from 408fafd to 0f909ea Compare June 26, 2023 21:42
@rjrjr rjrjr enabled auto-merge June 26, 2023 21:43
@rjrjr rjrjr merged commit 25eba05 into main Jun 26, 2023
@rjrjr rjrjr deleted the ray/1-component-set-dialog branch June 26, 2023 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants