1 /*
2  * Copyright 2023 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.tv.material3
18 
19 import androidx.annotation.FloatRange
20 import androidx.compose.foundation.BorderStroke
21 import androidx.compose.foundation.interaction.Interaction
22 import androidx.compose.runtime.Composable
23 import androidx.compose.runtime.ReadOnlyComposable
24 import androidx.compose.ui.graphics.Color
25 import androidx.compose.ui.graphics.RectangleShape
26 import androidx.compose.ui.graphics.Shape
27 import androidx.compose.ui.unit.dp
28 
29 /** Contains the default values used by a non-interactive [Surface] */
30 object SurfaceDefaults {
31     /** Represents the default shape used by a non-interactive [Surface] */
32     val shape: Shape
33         @ReadOnlyComposable @Composable get() = RectangleShape
34 
35     /**
36      * Creates a [SurfaceColors] that represents the default container & content colors used by a
37      * non-interactive [Surface].
38      *
39      * @param containerColor the container color of this Surface
40      * @param contentColor the content color of this Surface
41      */
42     @ReadOnlyComposable
43     @Composable
colorsnull44     fun colors(
45         containerColor: Color = MaterialTheme.colorScheme.surface,
46         contentColor: Color = contentColorFor(containerColor)
47     ) = SurfaceColors(containerColor = containerColor, contentColor = contentColor)
48 
49     /** Represents the default border used by a non-interactive [Surface] */
50     internal val border: Border = Border.None
51 
52     /** Represents the default glow used by a non-interactive [Surface] */
53     internal val glow: Glow = Glow.None
54 }
55 
56 /** Contains the default values used by clickable Surface. */
57 object ClickableSurfaceDefaults {
58     /**
59      * Creates a [ClickableSurfaceShape] that represents the default container shapes used in a
60      * Surface.
61      *
62      * @param shape the shape used when the Surface is enabled, and has no other [Interaction]s.
63      * @param focusedShape the shape used when the Surface is enabled and focused.
64      * @param pressedShape the shape used when the Surface is enabled pressed.
65      * @param disabledShape the shape used when the Surface is not enabled.
66      * @param focusedDisabledShape the shape used when the Surface is not enabled and focused.
67      */
68     @ReadOnlyComposable
69     @Composable
70     fun shape(
71         shape: Shape = MaterialTheme.shapes.medium,
72         focusedShape: Shape = shape,
73         pressedShape: Shape = shape,
74         disabledShape: Shape = shape,
75         focusedDisabledShape: Shape = disabledShape
76     ) =
77         ClickableSurfaceShape(
78             shape = shape,
79             focusedShape = focusedShape,
80             pressedShape = pressedShape,
81             disabledShape = disabledShape,
82             focusedDisabledShape = focusedDisabledShape
83         )
84 
85     /**
86      * Creates a [ClickableSurfaceColors] that represents the default container & content colors
87      * used in a Surface.
88      *
89      * @param containerColor the container color of this Surface when enabled
90      * @param contentColor the content color of this Surface when enabled
91      * @param focusedContainerColor the container color of this Surface when enabled and focused
92      * @param focusedContentColor the content color of this Surface when enabled and focused
93      * @param pressedContainerColor the container color of this Surface when enabled and pressed
94      * @param pressedContentColor the content color of this Surface when enabled and pressed
95      * @param disabledContainerColor the container color of this Surface when not enabled
96      * @param disabledContentColor the content color of this Surface when not enabled
97      */
98     @ReadOnlyComposable
99     @Composable
100     fun colors(
101         containerColor: Color = MaterialTheme.colorScheme.surface,
102         contentColor: Color = contentColorFor(containerColor),
103         focusedContainerColor: Color = MaterialTheme.colorScheme.inverseSurface,
104         focusedContentColor: Color = contentColorFor(focusedContainerColor),
105         pressedContainerColor: Color = focusedContainerColor,
106         pressedContentColor: Color = contentColorFor(pressedContainerColor),
107         disabledContainerColor: Color =
108             MaterialTheme.colorScheme.surfaceVariant.copy(alpha = DisabledContainerAlpha),
109         disabledContentColor: Color = MaterialTheme.colorScheme.onSurface
110     ) =
111         ClickableSurfaceColors(
112             containerColor = containerColor,
113             contentColor = contentColor,
114             focusedContainerColor = focusedContainerColor,
115             focusedContentColor = focusedContentColor,
116             pressedContainerColor = pressedContainerColor,
117             pressedContentColor = pressedContentColor,
118             disabledContainerColor = disabledContainerColor,
119             disabledContentColor = disabledContentColor
120         )
121 
122     /**
123      * Creates a [ClickableSurfaceScale] that represents the default scales used in a Surface.
124      * scales are used to modify the size of a composable in different [Interaction] states e.g. 1f
125      * (original) in default state, 1.2f (scaled up) in focused state, 0.8f (scaled down) in pressed
126      * state, etc.
127      *
128      * @param scale the scale to be used for this Surface when enabled
129      * @param focusedScale the scale to be used for this Surface when focused
130      * @param pressedScale the scale to be used for this Surface when pressed
131      * @param disabledScale the scale to be used for this Surface when disabled
132      * @param focusedDisabledScale the scale to be used for this Surface when disabled and focused
133      */
134     fun scale(
135         @FloatRange(from = 0.0) scale: Float = 1f,
136         @FloatRange(from = 0.0) focusedScale: Float = 1.1f,
137         @FloatRange(from = 0.0) pressedScale: Float = scale,
138         @FloatRange(from = 0.0) disabledScale: Float = scale,
139         @FloatRange(from = 0.0) focusedDisabledScale: Float = disabledScale
140     ) =
141         ClickableSurfaceScale(
142             scale = scale,
143             focusedScale = focusedScale,
144             pressedScale = pressedScale,
145             disabledScale = disabledScale,
146             focusedDisabledScale = focusedDisabledScale
147         )
148 
149     /**
150      * Creates a [ClickableSurfaceBorder] that represents the default [Border]s applied on a Surface
151      * in different [Interaction] states.
152      *
153      * @param border the [Border] to be used for this Surface when enabled
154      * @param focusedBorder the [Border] to be used for this Surface when focused
155      * @param pressedBorder the [Border] to be used for this Surface when pressed
156      * @param disabledBorder the [Border] to be used for this Surface when disabled
157      * @param focusedDisabledBorder the [Border] to be used for this Surface when disabled and
158      *   focused
159      */
160     @ReadOnlyComposable
161     @Composable
162     fun border(
163         border: Border = Border.None,
164         focusedBorder: Border = border,
165         pressedBorder: Border = focusedBorder,
166         disabledBorder: Border = border,
167         focusedDisabledBorder: Border =
168             Border(
169                 border = BorderStroke(width = 2.dp, color = MaterialTheme.colorScheme.border),
170                 inset = 0.dp,
171                 shape = ShapeDefaults.Small
172             )
173     ) =
174         ClickableSurfaceBorder(
175             border = border,
176             focusedBorder = focusedBorder,
177             pressedBorder = pressedBorder,
178             disabledBorder = disabledBorder,
179             focusedDisabledBorder = focusedDisabledBorder
180         )
181 
182     /**
183      * Creates a [ClickableSurfaceGlow] that represents the default [Glow]s used in a Surface.
184      *
185      * @param glow the Glow behind this Surface when enabled
186      * @param focusedGlow the Glow behind this Surface when focused
187      * @param pressedGlow the Glow behind this Surface when pressed
188      */
189     fun glow(glow: Glow = Glow.None, focusedGlow: Glow = glow, pressedGlow: Glow = glow) =
190         ClickableSurfaceGlow(glow = glow, focusedGlow = focusedGlow, pressedGlow = pressedGlow)
191 }
192 
193 /** Contains the default values used by Selectable Surface. */
194 object SelectableSurfaceDefaults {
195     /**
196      * Creates a [SelectableSurfaceShape] that represents the default container shapes used in a
197      * selectable Surface.
198      *
199      * @param shape the shape used when the Surface is enabled, and has no other [Interaction]s.
200      * @param focusedShape the shape used when the Surface is enabled and focused.
201      * @param pressedShape the shape used when the Surface is enabled and pressed.
202      * @param selectedShape the shape used when the Surface is enabled and selected.
203      * @param disabledShape the shape used when the Surface is not enabled.
204      * @param focusedSelectedShape the shape used when the Surface is enabled, focused and selected.
205      * @param focusedDisabledShape the shape used when the Surface is not enabled and focused.
206      * @param pressedSelectedShape the shape used when the Surface is enabled, pressed and selected.
207      * @param selectedDisabledShape the shape used when the Surface is not enabled and selected.
208      * @param focusedSelectedDisabledShape the shape used when the Surface is not enabled, focused
209      *   and selected.
210      */
211     @ReadOnlyComposable
212     @Composable
shapenull213     fun shape(
214         shape: Shape = MaterialTheme.shapes.medium,
215         focusedShape: Shape = shape,
216         pressedShape: Shape = shape,
217         selectedShape: Shape = shape,
218         disabledShape: Shape = shape,
219         focusedSelectedShape: Shape = shape,
220         focusedDisabledShape: Shape = disabledShape,
221         pressedSelectedShape: Shape = shape,
222         selectedDisabledShape: Shape = disabledShape,
223         focusedSelectedDisabledShape: Shape = disabledShape
224     ) =
225         SelectableSurfaceShape(
226             shape = shape,
227             focusedShape = focusedShape,
228             pressedShape = pressedShape,
229             selectedShape = selectedShape,
230             disabledShape = disabledShape,
231             focusedSelectedShape = focusedSelectedShape,
232             focusedDisabledShape = focusedDisabledShape,
233             pressedSelectedShape = pressedSelectedShape,
234             selectedDisabledShape = selectedDisabledShape,
235             focusedSelectedDisabledShape = focusedSelectedDisabledShape
236         )
237 
238     /**
239      * Creates a [SelectableSurfaceColors] that represents the default container & content colors
240      * used in a selectable Surface.
241      *
242      * @param containerColor the container color used when the Surface is enabled, and has no other
243      *   [Interaction]s.
244      * @param contentColor the content color used when the Surface is enabled, and has no other
245      *   [Interaction]s.
246      * @param focusedContainerColor the container color used when the Surface is enabled and
247      *   focused.
248      * @param focusedContentColor the content color used when the Surface is enabled and focused.
249      * @param pressedContainerColor the container color used when the Surface is enabled and
250      *   pressed.
251      * @param pressedContentColor the content color used when the Surface is enabled and pressed.
252      * @param selectedContainerColor the container color used when the Surface is enabled and
253      *   selected.
254      * @param selectedContentColor the content color used when the Surface is enabled and selected.
255      * @param disabledContainerColor the container color used when the Surface is not enabled.
256      * @param disabledContentColor the content color used when the Surface is not enabled.
257      * @param focusedSelectedContainerColor the container color used when the Surface is enabled,
258      *   focused and selected.
259      * @param focusedSelectedContentColor the content color used when the Surface is enabled,
260      *   focused and selected.
261      * @param pressedSelectedContainerColor the container color used when the Surface is enabled,
262      *   pressed and selected.
263      * @param pressedSelectedContentColor the content color used when the Surface is enabled,
264      *   pressed and selected.
265      */
266     @ReadOnlyComposable
267     @Composable
268     fun colors(
269         containerColor: Color = MaterialTheme.colorScheme.surface,
270         contentColor: Color = contentColorFor(containerColor),
271         focusedContainerColor: Color = MaterialTheme.colorScheme.inverseSurface,
272         focusedContentColor: Color = contentColorFor(focusedContainerColor),
273         pressedContainerColor: Color = focusedContainerColor,
274         pressedContentColor: Color = contentColorFor(pressedContainerColor),
275         selectedContainerColor: Color =
276             MaterialTheme.colorScheme.inverseSurface.copy(alpha = SelectedContainerAlpha),
277         selectedContentColor: Color = MaterialTheme.colorScheme.inverseOnSurface,
278         disabledContainerColor: Color =
279             MaterialTheme.colorScheme.surfaceVariant.copy(alpha = DisabledContainerAlpha),
280         disabledContentColor: Color = MaterialTheme.colorScheme.onSurface,
281         focusedSelectedContainerColor: Color =
282             MaterialTheme.colorScheme.inverseSurface.copy(alpha = SelectedContainerAlpha),
283         focusedSelectedContentColor: Color = MaterialTheme.colorScheme.inverseOnSurface,
284         pressedSelectedContainerColor: Color = focusedSelectedContainerColor,
285         pressedSelectedContentColor: Color = focusedSelectedContentColor
286     ) =
287         SelectableSurfaceColors(
288             containerColor = containerColor,
289             contentColor = contentColor,
290             focusedContainerColor = focusedContainerColor,
291             focusedContentColor = focusedContentColor,
292             pressedContainerColor = pressedContainerColor,
293             pressedContentColor = pressedContentColor,
294             selectedContainerColor = selectedContainerColor,
295             selectedContentColor = selectedContentColor,
296             disabledContainerColor = disabledContainerColor,
297             disabledContentColor = disabledContentColor,
298             focusedSelectedContainerColor = focusedSelectedContainerColor,
299             focusedSelectedContentColor = focusedSelectedContentColor,
300             pressedSelectedContainerColor = pressedSelectedContainerColor,
301             pressedSelectedContentColor = pressedSelectedContentColor
302         )
303 
304     /**
305      * Creates a [SelectableSurfaceScale] that represents the default scales used in a selectable
306      * Surface. scales are used to modify the size of a composable in different [Interaction] states
307      * e.g. 1f (original) in default state, 1.2f (scaled up) in focused state, 0.8f (scaled down) in
308      * pressed state, etc.
309      *
310      * @param scale the scale used when the Surface is enabled, and has no other [Interaction]s.
311      * @param focusedScale the scale used when the Surface is enabled and focused.
312      * @param pressedScale the scale used when the Surface is enabled and pressed.
313      * @param selectedScale the scale used when the Surface is enabled and selected.
314      * @param disabledScale the scale used when the Surface is not enabled.
315      * @param focusedSelectedScale the scale used when the Surface is enabled, focused and selected.
316      * @param focusedDisabledScale the scale used when the Surface is not enabled and focused.
317      * @param pressedSelectedScale the scale used when the Surface is enabled, pressed and selected.
318      * @param selectedDisabledScale the scale used when the Surface is not enabled and selected.
319      * @param focusedSelectedDisabledScale the scale used when the Surface is not enabled, focused
320      *   and selected.
321      */
322     fun scale(
323         scale: Float = 1f,
324         focusedScale: Float = 1.1f,
325         pressedScale: Float = scale,
326         selectedScale: Float = scale,
327         disabledScale: Float = scale,
328         focusedSelectedScale: Float = focusedScale,
329         focusedDisabledScale: Float = disabledScale,
330         pressedSelectedScale: Float = scale,
331         selectedDisabledScale: Float = disabledScale,
332         focusedSelectedDisabledScale: Float = disabledScale
333     ) =
334         SelectableSurfaceScale(
335             scale = scale,
336             focusedScale = focusedScale,
337             pressedScale = pressedScale,
338             selectedScale = selectedScale,
339             disabledScale = disabledScale,
340             focusedSelectedScale = focusedSelectedScale,
341             focusedDisabledScale = focusedDisabledScale,
342             pressedSelectedScale = pressedSelectedScale,
343             selectedDisabledScale = selectedDisabledScale,
344             focusedSelectedDisabledScale = focusedSelectedDisabledScale
345         )
346 
347     /**
348      * Creates a [SelectableSurfaceBorder] that represents the default [Border]s applied on a
349      * selectable Surface in different [Interaction] states.
350      *
351      * @param border the [Border] used when the Surface is enabled, and has no other [Interaction]s.
352      * @param focusedBorder the [Border] used when the Surface is enabled and focused.
353      * @param pressedBorder the [Border] used when the Surface is enabled and pressed.
354      * @param selectedBorder the [Border] used when the Surface is enabled and selected.
355      * @param disabledBorder the [Border] used when the Surface is not enabled.
356      * @param focusedSelectedBorder the [Border] used when the Surface is enabled, focused and
357      *   selected.
358      * @param focusedDisabledBorder the [Border] used when the Surface is not enabled and focused.
359      * @param pressedSelectedBorder the [Border] used when the Surface is enabled, pressed and
360      *   selected.
361      * @param selectedDisabledBorder the [Border] used when the Surface is not enabled and selected.
362      * @param focusedSelectedDisabledBorder the [Border] used when the Surface is not enabled,
363      *   focused and selected.
364      */
365     fun border(
366         border: Border = Border.None,
367         focusedBorder: Border = border,
368         pressedBorder: Border = focusedBorder,
369         selectedBorder: Border = border,
370         disabledBorder: Border = border,
371         focusedSelectedBorder: Border = focusedBorder,
372         focusedDisabledBorder: Border = disabledBorder,
373         pressedSelectedBorder: Border = border,
374         selectedDisabledBorder: Border = disabledBorder,
375         focusedSelectedDisabledBorder: Border = disabledBorder
376     ) =
377         SelectableSurfaceBorder(
378             border = border,
379             focusedBorder = focusedBorder,
380             pressedBorder = pressedBorder,
381             selectedBorder = selectedBorder,
382             disabledBorder = disabledBorder,
383             focusedSelectedBorder = focusedSelectedBorder,
384             focusedDisabledBorder = focusedDisabledBorder,
385             pressedSelectedBorder = pressedSelectedBorder,
386             selectedDisabledBorder = selectedDisabledBorder,
387             focusedSelectedDisabledBorder = focusedSelectedDisabledBorder
388         )
389 
390     /**
391      * Creates a [SelectableSurfaceGlow] that represents the default [Glow]s used in a selectable
392      * Surface.
393      *
394      * @param glow the [Glow] used when the Surface is enabled, and has no other [Interaction]s.
395      * @param focusedGlow the [Glow] used when the Surface is enabled and focused.
396      * @param pressedGlow the [Glow] used when the Surface is enabled and pressed.
397      * @param selectedGlow the [Glow] used when the Surface is enabled and selected.
398      * @param focusedSelectedGlow the [Glow] used when the Surface is enabled, focused and selected.
399      * @param pressedSelectedGlow the [Glow] used when the Surface is enabled, pressed and selected.
400      */
401     fun glow(
402         glow: Glow = Glow.None,
403         focusedGlow: Glow = glow,
404         pressedGlow: Glow = glow,
405         selectedGlow: Glow = glow,
406         focusedSelectedGlow: Glow = focusedGlow,
407         pressedSelectedGlow: Glow = glow
408     ) =
409         SelectableSurfaceGlow(
410             glow = glow,
411             focusedGlow = focusedGlow,
412             pressedGlow = pressedGlow,
413             selectedGlow = selectedGlow,
414             focusedSelectedGlow = focusedSelectedGlow,
415             pressedSelectedGlow = pressedSelectedGlow
416         )
417 }
418 
419 private const val DisabledContainerAlpha = 0.4f
420 private const val SelectedContainerAlpha = 0.5f
421