1 /*
2  * Copyright 2020 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.ui.focus
18 
19 import androidx.compose.ui.Modifier
20 import androidx.compose.ui.internal.JvmDefaultWithCompatibility
21 
22 /**
23  * A [modifier][Modifier.Element] that can be used to set a custom focus traversal order.
24  *
25  * @see Modifier.focusOrder
26  */
27 @Deprecated("Use Modifier.focusProperties() instead")
28 @JvmDefaultWithCompatibility
29 interface FocusOrderModifier : Modifier.Element {
30 
31     /**
32      * Populates the [next][FocusOrder.next] / [left][FocusOrder.left] / [right][FocusOrder.right] /
33      * [up][FocusOrder.up] / [down][FocusOrder.down] items if you don't want to use the default
34      * focus traversal order.
35      */
populateFocusOrdernull36     @Suppress("DEPRECATION") fun populateFocusOrder(focusOrder: FocusOrder)
37 }
38 
39 /**
40  * Specifies custom focus destinations that are used instead of the default focus traversal order.
41  *
42  * @sample androidx.compose.ui.samples.CustomFocusOrderSample
43  */
44 @Deprecated("Use FocusProperties instead")
45 class FocusOrder internal constructor(private val focusProperties: FocusProperties) {
46     @Suppress("unused") constructor() : this(FocusPropertiesImpl())
47 
48     /**
49      * A custom item to be used when the user requests a focus moves to the "next" item.
50      *
51      * @sample androidx.compose.ui.samples.CustomFocusOrderSample
52      */
53     var next: FocusRequester
54         get() = focusProperties.next
55         set(next) {
56             focusProperties.next = next
57         }
58 
59     /**
60      * A custom item to be used when the user requests a focus moves to the "previous" item.
61      *
62      * @sample androidx.compose.ui.samples.CustomFocusOrderSample
63      */
64     var previous: FocusRequester
65         get() = focusProperties.previous
66         set(previous) {
67             focusProperties.previous = previous
68         }
69 
70     /**
71      * A custom item to be used when the user moves focus "up".
72      *
73      * @sample androidx.compose.ui.samples.CustomFocusOrderSample
74      */
75     var up: FocusRequester
76         get() = focusProperties.up
77         set(up) {
78             focusProperties.up = up
79         }
80 
81     /**
82      * A custom item to be used when the user moves focus "down".
83      *
84      * @sample androidx.compose.ui.samples.CustomFocusOrderSample
85      */
86     var down: FocusRequester
87         get() = focusProperties.down
88         set(down) {
89             focusProperties.down = down
90         }
91 
92     /**
93      * A custom item to be used when the user requests a focus moves to the "left" item.
94      *
95      * @sample androidx.compose.ui.samples.CustomFocusOrderSample
96      */
97     var left: FocusRequester
98         get() = focusProperties.left
99         set(left) {
100             focusProperties.left = left
101         }
102 
103     /**
104      * A custom item to be used when the user requests a focus moves to the "right" item.
105      *
106      * @sample androidx.compose.ui.samples.CustomFocusOrderSample
107      */
108     var right: FocusRequester
109         get() = focusProperties.right
110         set(right) {
111             focusProperties.right = right
112         }
113 
114     /**
115      * A custom item to be used when the user requests a focus moves to the "left" in LTR mode and
116      * "right" in RTL mode.
117      *
118      * @sample androidx.compose.ui.samples.CustomFocusOrderSample
119      */
120     var start: FocusRequester
121         get() = focusProperties.start
122         set(start) {
123             focusProperties.start = start
124         }
125 
126     /**
127      * A custom item to be used when the user requests a focus moves to the "right" in LTR mode and
128      * "left" in RTL mode.
129      *
130      * @sample androidx.compose.ui.samples.CustomFocusOrderSample
131      */
132     var end: FocusRequester
133         get() = focusProperties.end
134         set(end) {
135             focusProperties.end = end
136         }
137 }
138 
139 /**
140  * Use this modifier to specify a custom focus traversal order.
141  *
142  * @param focusOrderReceiver Specifies [FocusRequester]s that are used when the user wants to move
143  *   the current focus to the [next][FocusOrder.next] item, or wants to move focus
144  *   [left][FocusOrder.left], [right][FocusOrder.right], [up][FocusOrder.up] or
145  *   [down][FocusOrder.down].
146  * @sample androidx.compose.ui.samples.CustomFocusOrderSample
147  */
148 @Deprecated(
149     "Use focusProperties() instead",
150     ReplaceWith(
151         "this.focusProperties(focusOrderReceiver)",
152         "androidx.compose.ui.focus.focusProperties"
153     )
154 )
Modifiernull155 fun Modifier.focusOrder(
156     @Suppress("DEPRECATION") focusOrderReceiver: FocusOrder.() -> Unit
157 ): Modifier {
158     val scope = FocusOrderToProperties(focusOrderReceiver)
159     return focusProperties { scope.apply(this) }
160 }
161 
162 /**
163  * A modifier that lets you specify a [FocusRequester] for the current composable so that this
164  * [focusRequester] can be used by another composable to specify a custom focus order.
165  *
166  * @sample androidx.compose.ui.samples.CustomFocusOrderSample
167  */
168 @Deprecated(
169     "Use focusRequester() instead",
170     ReplaceWith("this.focusRequester(focusRequester)", "androidx.compose.ui.focus.focusRequester")
171 )
Modifiernull172 fun Modifier.focusOrder(focusRequester: FocusRequester): Modifier = focusRequester(focusRequester)
173 
174 /**
175  * A modifier that lets you specify a [FocusRequester] for the current composable along with
176  * [focusOrder].
177  */
178 @Deprecated(
179     "Use focusProperties() and focusRequester() instead",
180     ReplaceWith(
181         "this.focusRequester(focusRequester).focusProperties(focusOrderReceiver)",
182         "androidx.compose.ui.focus.focusProperties, androidx.compose.ui.focus.focusRequester"
183     )
184 )
185 fun Modifier.focusOrder(
186     focusRequester: FocusRequester,
187     @Suppress("DEPRECATION") focusOrderReceiver: FocusOrder.() -> Unit
188 ): Modifier {
189     val scope = FocusOrderToProperties(focusOrderReceiver)
190     return this.focusRequester(focusRequester).focusProperties { scope.apply(this) }
191 }
192 
193 @Suppress("DEPRECATION")
194 internal class FocusOrderToProperties(val focusOrderReceiver: FocusOrder.() -> Unit) :
195     FocusPropertiesScope {
applynull196     override fun apply(focusProperties: FocusProperties) {
197         focusOrderReceiver(FocusOrder(focusProperties))
198     }
199 }
200 
201 // Note: Implementing function interface is prohibited in K/JS (class A: () -> Unit)
202 // therefore we workaround this limitation by inheriting a fun interface instead
203 internal fun interface FocusPropertiesScope {
applynull204     fun apply(focusProperties: FocusProperties)
205 }
206