Fixed
Status Update
Comments
ap...@google.com <ap...@google.com> #2
Project: platform/frameworks/support
Branch: androidx-main
commit 2ae4491c96160cde4b70863202542499c68da4b7
Author: Louis Pullen-Freilich <lpf@google.com>
Date: Sat Feb 06 21:48:44 2021
InteractionState -> [Mutable]InteractionSource rework
This CL replaces InteractionState with [Mutable]InteractionSource - interfaces responsible for emitting / observing Interaction events. InteractionSource exposes interactions: Flow<Interaction>, which allows consumers to observe the ordered stream of Interactions and change how components appear accordingly.
This resolves a few issues with the existing InteractionState implementation:
- No handling for multiple sources of the same Interaction
For example, a compound component with two `clickable`s - if one `clickable` is pressed, then the other, then the first `clickable` is released, this would appear as though the entire InteractionState was not pressed.
- Lossy compression of events into state
InteractionState turns a stream events into a snapshot state at a given point in time. Complex components / indications such as Ripple care about the ordering of events, and trying to reconstruct ordering from a snapshot state is a bit messy and can lose information.
- Batched state writes
State<> is not a great fit for representing events as the name suggests - one of the reasons for this is that state writes are batched, so multiple changes (such as multiple fast presses) will be batched into one write. This means that we might skip showing ripples for presses if events happen too closely together.
- Lack of detailed information for events
For simple components, just knowing if the component is pressed or not can be enough to change how it appears, but for complicated components it can be important to know if a press was stopped / cancelled - this sort of information did not exist in InteractionState. Additionally metadata such as press position can be important, but there was no scalable way to support this. Now Interactions can just be unique instances with metadata, so Pressed() can contain a press position just as a property for consumers that need to know this information.
As well as the `interactions` Flow, simple extension functions on InteractionSource (collectIsDraggedAsState, collectIsFocusedAsState, collectIsPressedAsState) have been added for cases when components only care about the binary state of a particular interaction, and not the entire stream of events.
MutableInteractionSource exposes `emit()` and `tryEmit()` methods that allow emitting Interactions to the `interactions` Flow.
This CL also changes the existing Interactions to be classes, and adds further classes representing stop / cancel events for the initial events.
Bug: b/152525426
Fixes: b/171913923
Fixes: b/171710801
Fixes: b/174852378
Test: InteractionSourceTest
Test: updateApi
Relnote: "InteractionState has been replaced with [Mutable]InteractionSource - interfaces responsible for emitting / collecting Interaction events. Instead of passing `interactionState = remember { InteractionState() }` to components such as Button and Modifier.clickable(), use `interactionSource = remember { MutableInteractionSource() }`. Instead of: `Interaction.Pressed in interactionState` you should instead use the extension functions on InteractionSource, such as InteractionSource.collectIsPressedAsState(). For complex use cases you can use InteractionSource.interactions to observe the stream of Interactions. See the InteractionSource documentation and samples for more information."
Change-Id: I85965d0dba39d1740c097915d1d1a367eea2a78c
M compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/MultiDimensionalAnimationDemo.kt
M compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SingleValueAnimationDemo.kt
M compose/foundation/foundation/api/current.txt
M compose/foundation/foundation/api/public_plus_experimental_current.txt
M compose/foundation/foundation/api/restricted_current.txt
M compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
M compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/ListDemos.kt
M compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/ComposeVariousInputField.kt
M compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/FocusableSample.kt
M compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/IndicationSamples.kt
A compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/InteractionSourceSample.kt
D compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/InteractionStateSample.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ClickableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/DraggableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/FocusableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/IndicationTest.kt
A compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/InteractionSourceTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SelectableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ToggleableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/TextFieldInteractionsTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldScrollTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldTest.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Focusable.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Indication.kt
D compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Interaction.kt
D compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/InteractionState.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Draggable.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
A compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/DragInteraction.kt
A compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/FocusInteraction.kt
A compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/Interaction.kt
A compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/InteractionSource.kt
A compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/PressInteraction.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListState.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldGestureModifiers.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldPressGestureFilter.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldScroll.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionContainer.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt
M compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/Scrollbar.desktop.kt
D compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/InteractionStateTest.kt
M compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/Ripple.kt
M compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleAnimation.kt
M compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleTheme.kt
M compose/material/material/api/current.txt
M compose/material/material/api/public_plus_experimental_current.txt
M compose/material/material/api/restricted_current.txt
M compose/material/material/integration-tests/material-studies/src/main/java/androidx/compose/material/studies/rally/TopAppBar.kt
M compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BottomNavigationScreenshotTest.kt
M compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialRippleThemeTest.kt
M compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SwipeableTest.kt
M compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/TabScreenshotTest.kt
M compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
M compose/material/material/src/androidMain/kotlin/androidx/compose/material/AndroidMenu.android.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomNavigation.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Button.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Elevation.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/FloatingActionButton.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Tab.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldDefaults.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
M compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopMenu.desktop.kt
M compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/gestures/ScrollGestureFilterDemo.kt
https://android-review.googlesource.com/1579423
Branch: androidx-main
commit 2ae4491c96160cde4b70863202542499c68da4b7
Author: Louis Pullen-Freilich <lpf@google.com>
Date: Sat Feb 06 21:48:44 2021
InteractionState -> [Mutable]InteractionSource rework
This CL replaces InteractionState with [Mutable]InteractionSource - interfaces responsible for emitting / observing Interaction events. InteractionSource exposes interactions: Flow<Interaction>, which allows consumers to observe the ordered stream of Interactions and change how components appear accordingly.
This resolves a few issues with the existing InteractionState implementation:
- No handling for multiple sources of the same Interaction
For example, a compound component with two `clickable`s - if one `clickable` is pressed, then the other, then the first `clickable` is released, this would appear as though the entire InteractionState was not pressed.
- Lossy compression of events into state
InteractionState turns a stream events into a snapshot state at a given point in time. Complex components / indications such as Ripple care about the ordering of events, and trying to reconstruct ordering from a snapshot state is a bit messy and can lose information.
- Batched state writes
State<> is not a great fit for representing events as the name suggests - one of the reasons for this is that state writes are batched, so multiple changes (such as multiple fast presses) will be batched into one write. This means that we might skip showing ripples for presses if events happen too closely together.
- Lack of detailed information for events
For simple components, just knowing if the component is pressed or not can be enough to change how it appears, but for complicated components it can be important to know if a press was stopped / cancelled - this sort of information did not exist in InteractionState. Additionally metadata such as press position can be important, but there was no scalable way to support this. Now Interactions can just be unique instances with metadata, so Pressed() can contain a press position just as a property for consumers that need to know this information.
As well as the `interactions` Flow, simple extension functions on InteractionSource (collectIsDraggedAsState, collectIsFocusedAsState, collectIsPressedAsState) have been added for cases when components only care about the binary state of a particular interaction, and not the entire stream of events.
MutableInteractionSource exposes `emit()` and `tryEmit()` methods that allow emitting Interactions to the `interactions` Flow.
This CL also changes the existing Interactions to be classes, and adds further classes representing stop / cancel events for the initial events.
Bug:
Fixes:
Fixes:
Fixes:
Test: InteractionSourceTest
Test: updateApi
Relnote: "InteractionState has been replaced with [Mutable]InteractionSource - interfaces responsible for emitting / collecting Interaction events. Instead of passing `interactionState = remember { InteractionState() }` to components such as Button and Modifier.clickable(), use `interactionSource = remember { MutableInteractionSource() }`. Instead of: `Interaction.Pressed in interactionState` you should instead use the extension functions on InteractionSource, such as InteractionSource.collectIsPressedAsState(). For complex use cases you can use InteractionSource.interactions to observe the stream of Interactions. See the InteractionSource documentation and samples for more information."
Change-Id: I85965d0dba39d1740c097915d1d1a367eea2a78c
M compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/MultiDimensionalAnimationDemo.kt
M compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SingleValueAnimationDemo.kt
M compose/foundation/foundation/api/current.txt
M compose/foundation/foundation/api/public_plus_experimental_current.txt
M compose/foundation/foundation/api/restricted_current.txt
M compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
M compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/ListDemos.kt
M compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/ComposeVariousInputField.kt
M compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/FocusableSample.kt
M compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/IndicationSamples.kt
A compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/InteractionSourceSample.kt
D compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/InteractionStateSample.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ClickableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/DraggableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/FocusableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/IndicationTest.kt
A compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/InteractionSourceTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SelectableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ToggleableTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/TextFieldInteractionsTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldScrollTest.kt
M compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldTest.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Focusable.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Indication.kt
D compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Interaction.kt
D compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/InteractionState.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Draggable.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
A compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/DragInteraction.kt
A compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/FocusInteraction.kt
A compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/Interaction.kt
A compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/InteractionSource.kt
A compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/PressInteraction.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListState.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldGestureModifiers.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldPressGestureFilter.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldScroll.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionContainer.kt
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt
M compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/Scrollbar.desktop.kt
D compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/InteractionStateTest.kt
M compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/Ripple.kt
M compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleAnimation.kt
M compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleTheme.kt
M compose/material/material/api/current.txt
M compose/material/material/api/public_plus_experimental_current.txt
M compose/material/material/api/restricted_current.txt
M compose/material/material/integration-tests/material-studies/src/main/java/androidx/compose/material/studies/rally/TopAppBar.kt
M compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BottomNavigationScreenshotTest.kt
M compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialRippleThemeTest.kt
M compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SwipeableTest.kt
M compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/TabScreenshotTest.kt
M compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
M compose/material/material/src/androidMain/kotlin/androidx/compose/material/AndroidMenu.android.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomNavigation.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Button.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Elevation.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/FloatingActionButton.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Tab.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldDefaults.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
M compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopMenu.desktop.kt
M compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/gestures/ScrollGestureFilterDemo.kt
Description
Currently if the same InteractionState is added in two places that both add the same
Interaction
(such asModifier.clickable
), both components will remove each other'sInteraction
. Instead we should ensure that both producers must remove their state before theInteraction
is removed from theInteractionState
.