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 kotlinx.coroutines.flow.collect
25 
26 // An interface, not a sealed class, to allow adding new types here in a safe way (and not break
27 // exhaustive when clauses)
28 /**
29  * An interaction related to focus events.
30  *
31  * @see androidx.compose.foundation.focusable
32  * @see Focus
33  * @see Unfocus
34  */
35 interface FocusInteraction : Interaction {
36     /**
37      * An interaction representing a focus event on a component.
38      *
39      * @see androidx.compose.foundation.focusable
40      * @see Unfocus
41      */
42     class Focus : FocusInteraction
43 
44     /**
45      * An interaction representing a [Focus] event being released on a component.
46      *
47      * @property focus the source [Focus] interaction that is being released
48      * @see androidx.compose.foundation.focusable
49      * @see Focus
50      */
51     class Unfocus(val focus: Focus) : FocusInteraction
52 }
53 
54 /**
55  * Subscribes to this [MutableInteractionSource] and returns a [State] representing whether this
56  * component is focused or not.
57  *
58  * [FocusInteraction] is typically set by [androidx.compose.foundation.focusable] and focusable
59  * components, such as [androidx.compose.foundation.text.BasicTextField].
60  *
61  * @return [State] representing whether this component is being focused or not
62  */
63 @Composable
collectIsFocusedAsStatenull64 fun InteractionSource.collectIsFocusedAsState(): State<Boolean> {
65     val isFocused = remember { mutableStateOf(false) }
66     LaunchedEffect(this) {
67         val focusInteractions = mutableListOf<FocusInteraction.Focus>()
68         interactions.collect { interaction ->
69             when (interaction) {
70                 is FocusInteraction.Focus -> focusInteractions.add(interaction)
71                 is FocusInteraction.Unfocus -> focusInteractions.remove(interaction.focus)
72             }
73             isFocused.value = focusInteractions.isNotEmpty()
74         }
75     }
76     return isFocused
77 }
78