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.interaction.Interaction
21 import androidx.compose.runtime.Immutable
22 import androidx.compose.ui.graphics.Color
23 import androidx.compose.ui.graphics.Shape
24
25 /** Defines [Shape] for all TV [Interaction] states of Button. */
26 @Immutable
27 class ButtonShape
28 internal constructor(
29 internal val shape: Shape,
30 internal val focusedShape: Shape,
31 internal val pressedShape: Shape,
32 internal val disabledShape: Shape,
33 internal val focusedDisabledShape: Shape
34 ) {
equalsnull35 override fun equals(other: Any?): Boolean {
36 if (this === other) return true
37 if (other == null || this::class != other::class) return false
38
39 other as ButtonShape
40
41 if (shape != other.shape) return false
42 if (focusedShape != other.focusedShape) return false
43 if (pressedShape != other.pressedShape) return false
44 if (disabledShape != other.disabledShape) return false
45 if (focusedDisabledShape != other.focusedDisabledShape) return false
46
47 return true
48 }
49
hashCodenull50 override fun hashCode(): Int {
51 var result = shape.hashCode()
52 result = 31 * result + focusedShape.hashCode()
53 result = 31 * result + pressedShape.hashCode()
54 result = 31 * result + disabledShape.hashCode()
55 result = 31 * result + focusedDisabledShape.hashCode()
56
57 return result
58 }
59
toStringnull60 override fun toString(): String {
61 return "ButtonShape(shape=$shape, focusedShape=$focusedShape, pressedShape=$pressedShape," +
62 " disabledShape=$disabledShape, focusedDisabledShape=$focusedDisabledShape)"
63 }
64 }
65
66 /** Defines [Color]s for all TV [Interaction] states of Button. */
67 @Immutable
68 class ButtonColors
69 internal constructor(
70 internal val containerColor: Color,
71 internal val contentColor: Color,
72 internal val focusedContainerColor: Color,
73 internal val focusedContentColor: Color,
74 internal val pressedContainerColor: Color,
75 internal val pressedContentColor: Color,
76 internal val disabledContainerColor: Color,
77 internal val disabledContentColor: Color,
78 ) {
equalsnull79 override fun equals(other: Any?): Boolean {
80 if (this === other) return true
81 if (other == null || this::class != other::class) return false
82
83 other as ButtonColors
84
85 if (containerColor != other.containerColor) return false
86 if (contentColor != other.contentColor) return false
87 if (focusedContainerColor != other.focusedContainerColor) return false
88 if (focusedContentColor != other.focusedContentColor) return false
89 if (pressedContainerColor != other.pressedContainerColor) return false
90 if (pressedContentColor != other.pressedContentColor) return false
91 if (disabledContainerColor != other.disabledContainerColor) return false
92 if (disabledContentColor != other.disabledContentColor) return false
93
94 return true
95 }
96
hashCodenull97 override fun hashCode(): Int {
98 var result = containerColor.hashCode()
99 result = 31 * result + contentColor.hashCode()
100 result = 31 * result + focusedContainerColor.hashCode()
101 result = 31 * result + focusedContentColor.hashCode()
102 result = 31 * result + pressedContainerColor.hashCode()
103 result = 31 * result + pressedContentColor.hashCode()
104 result = 31 * result + disabledContainerColor.hashCode()
105 result = 31 * result + disabledContentColor.hashCode()
106 return result
107 }
108
toStringnull109 override fun toString(): String {
110 return "ButtonColors(containerColor=$containerColor, contentColor=$contentColor, " +
111 "focusedContainerColor=$focusedContainerColor, " +
112 "focusedContentColor=$focusedContentColor, " +
113 "pressedContainerColor=$pressedContainerColor, " +
114 "pressedContentColor=$pressedContentColor, " +
115 "disabledContainerColor=$disabledContainerColor, " +
116 "disabledContentColor=$disabledContentColor)"
117 }
118 }
119
120 /** Defines [Color]s for all TV [Interaction] states of a WideButton */
121 @Immutable
122 class WideButtonContentColor
123 internal constructor(
124 internal val contentColor: Color,
125 internal val focusedContentColor: Color,
126 internal val pressedContentColor: Color,
127 internal val disabledContentColor: Color,
128 ) {
equalsnull129 override fun equals(other: Any?): Boolean {
130 if (this === other) return true
131 if (other == null || this::class != other::class) return false
132
133 other as WideButtonContentColor
134
135 if (contentColor != other.contentColor) return false
136 if (focusedContentColor != other.focusedContentColor) return false
137 if (pressedContentColor != other.pressedContentColor) return false
138 if (disabledContentColor != other.disabledContentColor) return false
139
140 return true
141 }
142
hashCodenull143 override fun hashCode(): Int {
144 var result = contentColor.hashCode()
145 result = 31 * result + focusedContentColor.hashCode()
146 result = 31 * result + pressedContentColor.hashCode()
147 result = 31 * result + disabledContentColor.hashCode()
148 return result
149 }
150
toStringnull151 override fun toString(): String {
152 return "WideButtonContentColor(contentColor=$contentColor, " +
153 "focusedContentColor=$focusedContentColor, " +
154 "pressedContentColor=$pressedContentColor, " +
155 "disabledContentColor=$disabledContentColor)"
156 }
157 }
158
159 /** Defines the scale for all TV [Interaction] states of Button. */
160 @Immutable
161 class ButtonScale
162 internal constructor(
163 @FloatRange(from = 0.0) internal val scale: Float,
164 @FloatRange(from = 0.0) internal val focusedScale: Float,
165 @FloatRange(from = 0.0) internal val pressedScale: Float,
166 @FloatRange(from = 0.0) internal val disabledScale: Float,
167 @FloatRange(from = 0.0) internal val focusedDisabledScale: Float
168 ) {
equalsnull169 override fun equals(other: Any?): Boolean {
170 if (this === other) return true
171 if (other == null || this::class != other::class) return false
172
173 other as ButtonScale
174
175 if (scale != other.scale) return false
176 if (focusedScale != other.focusedScale) return false
177 if (pressedScale != other.pressedScale) return false
178 if (disabledScale != other.disabledScale) return false
179 if (focusedDisabledScale != other.focusedDisabledScale) return false
180
181 return true
182 }
183
hashCodenull184 override fun hashCode(): Int {
185 var result = scale.hashCode()
186 result = 31 * result + focusedScale.hashCode()
187 result = 31 * result + pressedScale.hashCode()
188 result = 31 * result + disabledScale.hashCode()
189 result = 31 * result + focusedDisabledScale.hashCode()
190
191 return result
192 }
193
toStringnull194 override fun toString(): String {
195 return "ButtonScale(scale=$scale, focusedScale=$focusedScale, pressedScale=$pressedScale," +
196 " disabledScale=$disabledScale, focusedDisabledScale=$focusedDisabledScale)"
197 }
198
199 companion object {
200 /** Signifies the absence of a [ScaleIndication] in Button component. */
201 val None =
202 ButtonScale(
203 scale = 1f,
204 focusedScale = 1f,
205 pressedScale = 1f,
206 disabledScale = 1f,
207 focusedDisabledScale = 1f
208 )
209 }
210 }
211
212 /** Defines [Border] for all TV [Interaction] states of Button. */
213 @Immutable
214 class ButtonBorder
215 internal constructor(
216 internal val border: Border,
217 internal val focusedBorder: Border,
218 internal val pressedBorder: Border,
219 internal val disabledBorder: Border,
220 internal val focusedDisabledBorder: Border
221 ) {
equalsnull222 override fun equals(other: Any?): Boolean {
223 if (this === other) return true
224 if (other == null || this::class != other::class) return false
225
226 other as ButtonBorder
227
228 if (border != other.border) return false
229 if (focusedBorder != other.focusedBorder) return false
230 if (pressedBorder != other.pressedBorder) return false
231 if (disabledBorder != other.disabledBorder) return false
232 if (focusedDisabledBorder != other.focusedDisabledBorder) return false
233
234 return true
235 }
236
hashCodenull237 override fun hashCode(): Int {
238 var result = border.hashCode()
239 result = 31 * result + focusedBorder.hashCode()
240 result = 31 * result + pressedBorder.hashCode()
241 result = 31 * result + disabledBorder.hashCode()
242 result = 31 * result + focusedDisabledBorder.hashCode()
243
244 return result
245 }
246
toStringnull247 override fun toString(): String {
248 return "ButtonBorder(border=$border, focusedBorder=$focusedBorder," +
249 "pressedBorder=$pressedBorder, disabledBorder=$disabledBorder, " +
250 "focusedDisabledBorder=$focusedDisabledBorder)"
251 }
252 }
253
254 /** Defines [Glow] for all TV [Interaction] states of Button. */
255 @Immutable
256 class ButtonGlow
257 internal constructor(
258 internal val glow: Glow,
259 internal val focusedGlow: Glow,
260 internal val pressedGlow: Glow
261 ) {
equalsnull262 override fun equals(other: Any?): Boolean {
263 if (this === other) return true
264 if (other == null || this::class != other::class) return false
265
266 other as ButtonGlow
267
268 if (glow != other.glow) return false
269 if (focusedGlow != other.focusedGlow) return false
270 if (pressedGlow != other.pressedGlow) return false
271
272 return true
273 }
274
hashCodenull275 override fun hashCode(): Int {
276 var result = glow.hashCode()
277 result = 31 * result + focusedGlow.hashCode()
278 result = 31 * result + pressedGlow.hashCode()
279
280 return result
281 }
282
toStringnull283 override fun toString(): String {
284 return "ButtonGlow(glow=$glow, focusedGlow=$focusedGlow, pressedGlow=$pressedGlow)"
285 }
286 }
287
288 private val WideButtonContainerColor = Color.Transparent
289
toClickableSurfaceShapenull290 internal fun ButtonShape.toClickableSurfaceShape(): ClickableSurfaceShape =
291 ClickableSurfaceShape(
292 shape = shape,
293 focusedShape = focusedShape,
294 pressedShape = pressedShape,
295 disabledShape = disabledShape,
296 focusedDisabledShape = focusedDisabledShape
297 )
298
299 internal fun ButtonColors.toClickableSurfaceColors(): ClickableSurfaceColors =
300 ClickableSurfaceColors(
301 containerColor = containerColor,
302 contentColor = contentColor,
303 focusedContainerColor = focusedContainerColor,
304 focusedContentColor = focusedContentColor,
305 pressedContainerColor = pressedContainerColor,
306 pressedContentColor = pressedContentColor,
307 disabledContainerColor = disabledContainerColor,
308 disabledContentColor = disabledContentColor
309 )
310
311 internal fun WideButtonContentColor.toClickableSurfaceColors(): ClickableSurfaceColors =
312 ClickableSurfaceColors(
313 containerColor = WideButtonContainerColor,
314 contentColor = contentColor,
315 focusedContainerColor = WideButtonContainerColor,
316 focusedContentColor = focusedContentColor,
317 pressedContainerColor = WideButtonContainerColor,
318 pressedContentColor = pressedContentColor,
319 disabledContainerColor = WideButtonContainerColor,
320 disabledContentColor = disabledContentColor
321 )
322
323 internal fun ButtonScale.toClickableSurfaceScale() =
324 ClickableSurfaceScale(
325 scale = scale,
326 focusedScale = focusedScale,
327 pressedScale = pressedScale,
328 disabledScale = disabledScale,
329 focusedDisabledScale = focusedDisabledScale
330 )
331
332 internal fun ButtonBorder.toClickableSurfaceBorder() =
333 ClickableSurfaceBorder(
334 border = border,
335 focusedBorder = focusedBorder,
336 pressedBorder = pressedBorder,
337 disabledBorder = disabledBorder,
338 focusedDisabledBorder = focusedDisabledBorder
339 )
340
341 internal fun ButtonGlow.toClickableSurfaceGlow() =
342 ClickableSurfaceGlow(glow = glow, focusedGlow = focusedGlow, pressedGlow = pressedGlow)
343