1 /*
<lambda>null2  * Copyright 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.compose.foundation.interaction
18 
19 import androidx.compose.runtime.Composable
20 import androidx.compose.runtime.LaunchedEffect
21 import androidx.compose.runtime.State
22 import androidx.compose.runtime.mutableStateOf
23 import androidx.compose.runtime.remember
24 import androidx.compose.ui.geometry.Offset
25 import androidx.compose.ui.platform.ViewConfiguration
26 import kotlinx.coroutines.flow.collect
27 
28 // An interface, not a sealed class, to allow adding new types here in a safe way (and not break
29 // exhaustive when clauses)
30 /**
31  * An interaction related to press events.
32  *
33  * @see androidx.compose.foundation.clickable
34  * @see Press
35  * @see Release
36  * @see Cancel
37  */
38 interface PressInteraction : Interaction {
39     /**
40      * An interaction representing a press event on a component.
41      *
42      * @property pressPosition the [Offset] describing where this press event occurred within the
43      *   component. The [Offset] can be outside the actual component bounds meaning the [Offset] can
44      *   be negative or larger than the component bounds if the touch target is smaller than the
45      *   [ViewConfiguration.minimumTouchTargetSize].
46      * @see androidx.compose.foundation.clickable
47      * @see Release
48      * @see Cancel
49      */
50     class Press(val pressPosition: Offset) : PressInteraction
51 
52     /**
53      * An interaction representing the release of a [Press] event on a component.
54      *
55      * @property press the source [Press] interaction that is being released
56      * @see androidx.compose.foundation.clickable
57      * @see Press
58      */
59     class Release(val press: Press) : PressInteraction
60 
61     /**
62      * An interaction representing the cancellation of a [Press] event on a component.
63      *
64      * @property press the source [Press] interaction that is being cancelled
65      * @see androidx.compose.foundation.clickable
66      * @see Press
67      */
68     class Cancel(val press: Press) : PressInteraction
69 }
70 
71 /**
72  * Subscribes to this [MutableInteractionSource] and returns a [State] representing whether this
73  * component is pressed or not.
74  *
75  * [PressInteraction] is typically set by [androidx.compose.foundation.clickable] and clickable
76  * higher level components, such as buttons.
77  *
78  * @return [State] representing whether this component is being pressed or not
79  */
80 @Composable
collectIsPressedAsStatenull81 fun InteractionSource.collectIsPressedAsState(): State<Boolean> {
82     val isPressed = remember { mutableStateOf(false) }
83     LaunchedEffect(this) {
84         val pressInteractions = mutableListOf<PressInteraction.Press>()
85         interactions.collect { interaction ->
86             when (interaction) {
87                 is PressInteraction.Press -> pressInteractions.add(interaction)
88                 is PressInteraction.Release -> pressInteractions.remove(interaction.press)
89                 is PressInteraction.Cancel -> pressInteractions.remove(interaction.press)
90             }
91             isPressed.value = pressInteractions.isNotEmpty()
92         }
93     }
94     return isPressed
95 }
96