-
Notifications
You must be signed in to change notification settings - Fork 101
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
3/4 fun View.setBackHandler()
replaces val View.backPressedHandler
#1028
Conversation
fun View.backHandler()
replaces val View.backPressedHandler
fun View.backHandler()
replaces val View.backPressedHandler
.../src/main/java/com/squareup/sample/timemachine/shakeable/ShakeableTimeMachineLayoutRunner.kt
Outdated
Show resolved
Hide resolved
samples/tictactoe/app/src/main/java/com/squareup/sample/authworkflow/LoginViewFactory.kt
Outdated
Show resolved
Hide resolved
...ui/core-android/src/main/java/com/squareup/workflow1/ui/container/ContentDialogSetContent.kt
Outdated
Show resolved
Hide resolved
// so becomes our parent. | ||
WorkflowLifecycleOwner.installOn( | ||
view, | ||
initialEnvironment.onBackPressedDispatcherOwner(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.
This will pull in the wrong OnBackPressedDispatcherOwner, but that was always the case. This problem is why we've deprecated ScreenOverlayDialogFactory
and replaced it with fun ComponentDialog.setContent()
-- it was fundamentally broken, requiring us to create the content view before the Dialog
that would host it.
fun View.backHandler()
replaces val View.backPressedHandler
fun View.backHandler()
replaces val View.setBackPressedHandler
4a789a8
to
053dccd
Compare
fun View.backHandler()
replaces val View.setBackPressedHandler
fun View.setBackHandler()
replaces val View.backPressedHandler
d29aea2
to
f62b52f
Compare
c7194c9
to
6664cfe
Compare
f62b52f
to
35ce30e
Compare
f4b8dc7
to
8900743
Compare
35ce30e
to
dfe3296
Compare
8900743
to
df94fc9
Compare
workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/container/BackButtonScreen.kt
Show resolved
Hide resolved
df94fc9
to
fcb88a7
Compare
dfe3296
to
faec646
Compare
bf2d754
to
bb48afd
Compare
78620bb
to
08e8dd3
Compare
fun View.setBackHandler()
replaces val View.backPressedHandler
fun View.setBackHandler()
replaces val View.backPressedHandler
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.
Should name this file SetBackHandler.kt
.around(scenarioRule) | ||
.around(IdlingDispatcherRule) | ||
|
||
private var viewHandlerCount = 0 |
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.
nit:
private var viewHandlerCount = 0 | |
private var viewHandlerBackPressedCount = 0 |
@@ -13,6 +13,7 @@ import com.squareup.workflow1.ui.androidx.WorkflowAndroidXSupport.onBackPressedD | |||
* A function passed to [View.backPressedHandler], to be called if the back | |||
* button is pressed while that view is attached to a window. | |||
*/ | |||
@Deprecated("Use View.backHandler()") |
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.
@Deprecated("Use View.backHandler()") | |
@Deprecated("Use View.setBackHandler()") |
@WorkflowUiExperimentalApi | ||
@Deprecated("Use setOrClearBackHandler") |
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.
@Deprecated("Use setOrClearBackHandler") | |
@Deprecated("Use setBackHandler") |
I see you went through some naming iterations 😄
import com.squareup.workflow1.ui.androidx.WorkflowAndroidXSupport.onBackPressedDispatcherOwnerOrNull | ||
|
||
/** | ||
* A function to be called if the device back button is pressed while this |
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 function to be called if the device back button is pressed while this | |
* Sets a function to be called if the device back button is pressed while this |
onBack: () -> Unit | ||
) { | ||
val callback = onBackPressedCallbackOrNull ?: MutableOnBackPressedCallback().apply { | ||
onBackPressedCallbackOrNull = this |
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 this is an interesting pattern. 🤔 .
public fun View.setBackHandler(onBack: (() -> Unit)?) { | ||
onBack?.let { setBackHandler(enabled = true, it) } | ||
?: setBackHandler(enabled = false) {} | ||
} |
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.
Do you think setBackHandler(null)
is the most understandable way of clearing/disabling this?
I personally like setBackHandler(enabled = false)
and then making {}
the default value of onBack
in the version of the function above (not needing this overload then). I could see how you could end up with setBackHandler(false)
but even that I don't find confusing.
private var View.onBackPressedCallbackOrNull: MutableOnBackPressedCallback? | ||
get() = getTag(R.id.view_back_handler) as MutableOnBackPressedCallback? | ||
set(value) { | ||
setTag(R.id.view_back_handler, value) | ||
} |
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.
You truly are an Android view maestro how you nicely abstract this. 👨🏻🍳 💋
// decorView before updating, to ensure that the global androidx | ||
// OnBackPressedDispatcher doesn't fire any set by lower layers. We put this | ||
// in place before each call to show(), so the real content view will be able | ||
// to clobber it. | ||
if (modal) content.view.backPressedHandler = {} | ||
if (modal) content.view.setBackHandler {} |
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.
Given all the no-op handlers we use, having a default of {}
might be nice. Although maybe that's just in these internal use cases?
08e8dd3
to
d417e33
Compare
bb48afd
to
af3caaf
Compare
`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.
af3caaf
to
eb3de9c
Compare
d417e33
to
0335e65
Compare
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()
. We also provide a single argument overload that take a nullable handler function, and setsenabled
to true for non-null
handlers, false fornull
.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 makeWorkflowLifecycleOwner
behave correctly.This work revealed a problem where there was no
WorkflowLifecycleOwner
in place in time for the first update of the content view inScreenOverlayDialogFactory
, which prevented us from repeating that mistake in the newComponentDialog.setContent()
extension function introduced two PRs up. So that's nice.