Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 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.foundation.interaction.MutableInteractionSource |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 23 | import androidx.compose.foundation.layout.Box |
| 24 | import androidx.compose.foundation.layout.BoxScope |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 25 | import androidx.compose.foundation.layout.Column |
| 26 | import androidx.compose.foundation.layout.ColumnScope |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 27 | import androidx.compose.foundation.layout.PaddingValues |
| 28 | import androidx.compose.foundation.layout.Row |
| 29 | import androidx.compose.foundation.layout.aspectRatio |
| 30 | import androidx.compose.foundation.layout.padding |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 31 | import androidx.compose.foundation.shape.RoundedCornerShape |
| 32 | import androidx.compose.runtime.Composable |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 33 | import androidx.compose.runtime.CompositionLocalProvider |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 34 | import androidx.compose.runtime.ReadOnlyComposable |
| 35 | import androidx.compose.runtime.remember |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 36 | import androidx.compose.ui.Alignment |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 37 | import androidx.compose.ui.Modifier |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 38 | import androidx.compose.ui.draw.drawWithCache |
| 39 | import androidx.compose.ui.graphics.Brush |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 40 | import androidx.compose.ui.graphics.Color |
| 41 | import androidx.compose.ui.graphics.Shape |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 42 | import androidx.compose.ui.graphics.graphicsLayer |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 43 | import androidx.compose.ui.unit.dp |
| 44 | |
| 45 | /** |
| 46 | * Cards contain content and actions that relate information about a subject. |
| 47 | * |
| 48 | * This Card handles click events, calling its [onClick] lambda. |
| 49 | * |
| 50 | * @param onClick called when this card is clicked |
| 51 | * @param modifier the [Modifier] to be applied to this card |
| 52 | * @param shape [CardShape] defines the shape of this card's container in different interaction |
| 53 | * states. See [CardDefaults.shape]. |
| 54 | * @param colors [CardColors] defines the background & content colors used in this card for |
| 55 | * different interaction states. See [CardDefaults.colors]. |
| 56 | * @param scale [CardScale] defines size of the card relative to its original size for different |
| 57 | * interaction states. See [CardDefaults.scale]. |
| 58 | * @param border [CardBorder] defines a border around the card for different interaction states. |
| 59 | * See [CardDefaults.border]. |
| 60 | * @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction |
| 61 | * states. See [CardDefaults.glow]. |
| 62 | * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s |
| 63 | * for this card. You can create and pass in your own `remember`ed instance to observe |
| 64 | * [Interaction]s and customize the appearance / behavior of this card in different states. |
| 65 | * @param content defines the [Composable] content inside the Card. |
| 66 | */ |
| 67 | @ExperimentalTvMaterial3Api |
| 68 | @Composable |
| 69 | fun Card( |
| 70 | onClick: () -> Unit, |
| 71 | modifier: Modifier = Modifier, |
| 72 | shape: CardShape = CardDefaults.shape(), |
| 73 | colors: CardColors = CardDefaults.colors(), |
| 74 | scale: CardScale = CardDefaults.scale(), |
| 75 | border: CardBorder = CardDefaults.border(), |
| 76 | glow: CardGlow = CardDefaults.glow(), |
| 77 | interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, |
| 78 | content: @Composable ColumnScope.() -> Unit |
| 79 | ) { |
| 80 | Surface( |
| 81 | onClick = onClick, |
| 82 | modifier = modifier, |
| 83 | shape = shape.toClickableSurfaceShape(), |
| 84 | color = colors.toClickableSurfaceContainerColor(), |
| 85 | contentColor = colors.toClickableSurfaceContentColor(), |
| 86 | scale = scale.toClickableSurfaceScale(), |
| 87 | border = border.toClickableSurfaceBorder(), |
| 88 | glow = glow.toClickableSurfaceGlow(), |
| 89 | interactionSource = interactionSource, |
| 90 | ) { |
| 91 | Column(content = content) |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | /** |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 96 | * [ClassicCard] is an opinionated TV Material card that offers a 4 slot layout to show |
| 97 | * information about a subject. |
| 98 | * |
| 99 | * This card has a vertical layout with the interactive surface [Surface], which provides the image |
| 100 | * slot at the top, followed by the title, subtitle, and description slots. |
| 101 | * |
| 102 | * This Card handles click events, calling its [onClick] lambda. |
| 103 | * |
| 104 | * @param onClick called when this card is clicked |
| 105 | * @param image defines the [Composable] image to be displayed on top of the Card. |
| 106 | * @param title defines the [Composable] title placed below the image in the Card. |
| 107 | * @param modifier the [Modifier] to be applied to this card. |
| 108 | * @param subtitle defines the [Composable] supporting text placed below the title of the Card. |
| 109 | * @param description defines the [Composable] description placed below the subtitle of the Card. |
| 110 | * @param shape [CardShape] defines the shape of this card's container in different interaction |
| 111 | * states. See [CardDefaults.shape]. |
| 112 | * @param colors [CardColors] defines the background & content colors used in this card for |
| 113 | * different interaction states. See [CardDefaults.colors]. |
| 114 | * @param scale [CardScale] defines size of the card relative to its original size for different |
| 115 | * interaction states. See [CardDefaults.scale]. |
| 116 | * @param border [CardBorder] defines a border around the card for different interaction states. |
| 117 | * See [CardDefaults.border]. |
| 118 | * @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction |
| 119 | * states. See [CardDefaults.glow]. |
| 120 | * @param contentPadding [PaddingValues] defines the inner padding applied to the card's content. |
| 121 | * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s |
| 122 | * for this card. You can create and pass in your own `remember`ed instance to observe |
| 123 | * [Interaction]s and customize the appearance / behavior of this card in different states. |
| 124 | */ |
| 125 | @ExperimentalTvMaterial3Api |
| 126 | @Composable |
| 127 | fun ClassicCard( |
| 128 | onClick: () -> Unit, |
| 129 | image: @Composable BoxScope.() -> Unit, |
| 130 | title: @Composable () -> Unit, |
| 131 | modifier: Modifier = Modifier, |
| 132 | subtitle: @Composable () -> Unit = {}, |
| 133 | description: @Composable () -> Unit = {}, |
| 134 | shape: CardShape = CardDefaults.shape(), |
| 135 | colors: CardColors = CardDefaults.colors(), |
| 136 | scale: CardScale = CardDefaults.scale(), |
| 137 | border: CardBorder = CardDefaults.border(), |
| 138 | glow: CardGlow = CardDefaults.glow(), |
| 139 | contentPadding: PaddingValues = PaddingValues(), |
| 140 | interactionSource: MutableInteractionSource = remember { MutableInteractionSource() } |
| 141 | ) { |
| 142 | Card( |
| 143 | onClick = onClick, |
| 144 | modifier = modifier, |
| 145 | interactionSource = interactionSource, |
| 146 | shape = shape, |
| 147 | colors = colors, |
| 148 | scale = scale, |
| 149 | border = border, |
| 150 | glow = glow |
| 151 | ) { |
| 152 | Column( |
| 153 | modifier = Modifier.padding(contentPadding) |
| 154 | ) { |
| 155 | Box( |
| 156 | contentAlignment = CardDefaults.ContentImageAlignment, |
| 157 | content = image |
| 158 | ) |
| 159 | Column { |
| 160 | CardContent( |
| 161 | title = title, |
| 162 | subtitle = subtitle, |
| 163 | description = description |
| 164 | ) |
| 165 | } |
| 166 | } |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | /** |
| 171 | * [CompactCard] is an opinionated TV Material card that offers a 4 slot layout to show |
| 172 | * information about a subject. |
| 173 | * |
| 174 | * This card provides the interactive surface [Surface] with the image slot as the background |
| 175 | * (with an overlay scrim gradient). Other slots for the title, subtitle, and description are |
| 176 | * placed over it. |
| 177 | * |
| 178 | * This Card handles click events, calling its [onClick] lambda. |
| 179 | * |
| 180 | * @param onClick called when this card is clicked |
| 181 | * @param image defines the [Composable] image to be displayed on top of the Card. |
| 182 | * @param title defines the [Composable] title placed below the image in the Card. |
| 183 | * @param modifier the [Modifier] to be applied to this card. |
| 184 | * @param subtitle defines the [Composable] supporting text placed below the title of the Card. |
| 185 | * @param description defines the [Composable] description placed below the subtitle of the Card. |
| 186 | * @param shape [CardShape] defines the shape of this card's container in different interaction |
| 187 | * states. See [CardDefaults.shape]. |
| 188 | * @param colors [CardColors] defines the background & content colors used in this card for |
| 189 | * different interaction states. See [CardDefaults.compactCardColors]. |
| 190 | * @param scale [CardScale] defines size of the card relative to its original size for different |
| 191 | * interaction states. See [CardDefaults.scale]. |
| 192 | * @param border [CardBorder] defines a border around the card for different interaction states. |
| 193 | * See [CardDefaults.border]. |
| 194 | * @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction |
| 195 | * states. See [CardDefaults.glow]. |
| 196 | * @param scrimBrush [Brush] defines a brush/gradient to be used to draw the scrim over the image |
| 197 | * in the background. See [CardDefaults.ContainerGradient]. |
| 198 | * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s |
| 199 | * for this card. You can create and pass in your own `remember`ed instance to observe |
| 200 | * [Interaction]s and customize the appearance / behavior of this card in different states. |
| 201 | */ |
| 202 | @ExperimentalTvMaterial3Api |
| 203 | @Composable |
| 204 | fun CompactCard( |
| 205 | onClick: () -> Unit, |
| 206 | image: @Composable BoxScope.() -> Unit, |
| 207 | title: @Composable () -> Unit, |
| 208 | modifier: Modifier = Modifier, |
| 209 | subtitle: @Composable () -> Unit = {}, |
| 210 | description: @Composable () -> Unit = {}, |
| 211 | shape: CardShape = CardDefaults.shape(), |
| 212 | colors: CardColors = CardDefaults.compactCardColors(), |
| 213 | scale: CardScale = CardDefaults.scale(), |
| 214 | border: CardBorder = CardDefaults.border(), |
| 215 | glow: CardGlow = CardDefaults.glow(), |
| 216 | scrimBrush: Brush = CardDefaults.ContainerGradient, |
| 217 | interactionSource: MutableInteractionSource = remember { MutableInteractionSource() } |
| 218 | ) { |
| 219 | Card( |
| 220 | onClick = onClick, |
| 221 | modifier = modifier, |
| 222 | interactionSource = interactionSource, |
| 223 | shape = shape, |
| 224 | colors = colors, |
| 225 | scale = scale, |
| 226 | border = border, |
| 227 | glow = glow |
| 228 | ) { |
| 229 | Box(contentAlignment = Alignment.BottomStart) { |
| 230 | Box( |
| 231 | modifier = Modifier |
| 232 | .drawWithCache { |
| 233 | onDrawWithContent { |
| 234 | drawContent() |
| 235 | drawRect(brush = scrimBrush) |
| 236 | } |
| 237 | }, |
| 238 | contentAlignment = CardDefaults.ContentImageAlignment, |
| 239 | content = image |
| 240 | ) |
| 241 | Column { |
| 242 | CardContent( |
| 243 | title = title, |
| 244 | subtitle = subtitle, |
| 245 | description = description |
| 246 | ) |
| 247 | } |
| 248 | } |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | /** |
| 253 | * [WideClassicCard] is an opinionated TV Material card that offers a 4 slot layout to show |
| 254 | * information about a subject. |
| 255 | * |
| 256 | * This card has a horizontal layout with the interactive surface [Surface], which provides the |
| 257 | * image slot at the start, followed by the title, subtitle, and description slots at the end. |
| 258 | * |
| 259 | * This Card handles click events, calling its [onClick] lambda. |
| 260 | * |
| 261 | * @param onClick called when this card is clicked |
| 262 | * @param image defines the [Composable] image to be displayed on top of the Card. |
| 263 | * @param title defines the [Composable] title placed below the image in the Card. |
| 264 | * @param modifier the [Modifier] to be applied to this card. |
| 265 | * @param subtitle defines the [Composable] supporting text placed below the title of the Card. |
| 266 | * @param description defines the [Composable] description placed below the subtitle of the Card. |
| 267 | * @param shape [CardShape] defines the shape of this card's container in different interaction |
| 268 | * states. See [CardDefaults.shape]. |
| 269 | * @param colors [CardColors] defines the background & content colors used in this card for |
| 270 | * different interaction states. See [CardDefaults.colors]. |
| 271 | * @param scale [CardScale] defines size of the card relative to its original size for different |
| 272 | * interaction states. See [CardDefaults.scale]. |
| 273 | * @param border [CardBorder] defines a border around the card for different interaction states. |
| 274 | * See [CardDefaults.border]. |
| 275 | * @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction |
| 276 | * states. See [CardDefaults.glow]. |
| 277 | * @param contentPadding [PaddingValues] defines the inner padding applied to the card's content. |
| 278 | * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s |
| 279 | * for this card. You can create and pass in your own `remember`ed instance to observe |
| 280 | * [Interaction]s and customize the appearance / behavior of this card in different states. |
| 281 | */ |
| 282 | @ExperimentalTvMaterial3Api |
| 283 | @Composable |
| 284 | fun WideClassicCard( |
| 285 | onClick: () -> Unit, |
| 286 | image: @Composable BoxScope.() -> Unit, |
| 287 | title: @Composable () -> Unit, |
| 288 | modifier: Modifier = Modifier, |
| 289 | subtitle: @Composable () -> Unit = {}, |
| 290 | description: @Composable () -> Unit = {}, |
| 291 | shape: CardShape = CardDefaults.shape(), |
| 292 | colors: CardColors = CardDefaults.colors(), |
| 293 | scale: CardScale = CardDefaults.scale(), |
| 294 | border: CardBorder = CardDefaults.border(), |
| 295 | glow: CardGlow = CardDefaults.glow(), |
| 296 | contentPadding: PaddingValues = PaddingValues(), |
| 297 | interactionSource: MutableInteractionSource = remember { MutableInteractionSource() } |
| 298 | ) { |
| 299 | Card( |
| 300 | onClick = onClick, |
| 301 | modifier = modifier, |
| 302 | interactionSource = interactionSource, |
| 303 | shape = shape, |
| 304 | colors = colors, |
| 305 | scale = scale, |
| 306 | border = border, |
| 307 | glow = glow |
| 308 | ) { |
| 309 | Row( |
| 310 | modifier = Modifier.padding(contentPadding) |
| 311 | ) { |
| 312 | Box( |
| 313 | contentAlignment = CardDefaults.ContentImageAlignment, |
| 314 | content = image |
| 315 | ) |
| 316 | Column { |
| 317 | CardContent( |
| 318 | title = title, |
| 319 | subtitle = subtitle, |
| 320 | description = description |
| 321 | ) |
| 322 | } |
| 323 | } |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | @Composable |
| 328 | private fun CardContent( |
| 329 | title: @Composable () -> Unit, |
| 330 | subtitle: @Composable () -> Unit = {}, |
| 331 | description: @Composable () -> Unit = {}, |
| 332 | contentColor: Color |
| 333 | ) { |
| 334 | CompositionLocalProvider(LocalContentColor provides contentColor) { |
| 335 | CardContent(title, subtitle, description) |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | @Composable |
| 340 | private fun CardContent( |
| 341 | title: @Composable () -> Unit, |
| 342 | subtitle: @Composable () -> Unit = {}, |
| 343 | description: @Composable () -> Unit = {} |
| 344 | ) { |
| 345 | ProvideTextStyle(MaterialTheme.typography.titleMedium) { |
| 346 | title.invoke() |
| 347 | } |
| 348 | ProvideTextStyle(MaterialTheme.typography.bodySmall) { |
| 349 | Box(Modifier.graphicsLayer { alpha = SubtitleAlpha }) { |
| 350 | subtitle.invoke() |
| 351 | } |
| 352 | } |
| 353 | ProvideTextStyle(MaterialTheme.typography.bodySmall) { |
| 354 | Box(Modifier.graphicsLayer { alpha = DescriptionAlpha }) { |
| 355 | description.invoke() |
| 356 | } |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | /** |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 361 | * Contains the default values used by all card types. |
| 362 | */ |
| 363 | @ExperimentalTvMaterial3Api |
| 364 | object CardDefaults { |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 365 | internal val ContentImageAlignment = Alignment.Center |
| 366 | |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 367 | /** |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 368 | * The default [Shape] used by Cards. |
| 369 | */ |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 370 | private val ContainerShape = RoundedCornerShape(8.dp) |
| 371 | |
| 372 | /** |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 373 | * Recommended aspect ratio [Float] to get square images, can be applied using the modifier |
| 374 | * [Modifier.aspectRatio]. |
| 375 | */ |
| 376 | const val SquareImageAspectRatio = 1f |
| 377 | |
| 378 | /** |
| 379 | * Recommended aspect ratio [Float] for vertical images, can be applied using the modifier |
| 380 | * [Modifier.aspectRatio]. |
| 381 | */ |
| 382 | const val VerticalImageAspectRatio = 2f / 3 |
| 383 | |
| 384 | /** |
| 385 | * Recommended aspect ratio [Float] for horizontal images, can be applied using the modifier |
| 386 | * [Modifier.aspectRatio]. |
| 387 | */ |
| 388 | const val HorizontalImageAspectRatio = 16f / 9 |
| 389 | |
| 390 | /** |
| 391 | * Gradient used in cards to give more emphasis to the textual content that is generally |
| 392 | * displayed above an image. |
| 393 | */ |
| 394 | val ContainerGradient = Brush.verticalGradient( |
| 395 | listOf( |
| 396 | Color(red = 28, green = 27, blue = 31, alpha = 0), |
| 397 | Color(red = 28, green = 27, blue = 31, alpha = 204) |
| 398 | ) |
| 399 | ) |
| 400 | |
| 401 | /** |
| 402 | * Returns the content color [Color] from the colors [CardColors] for different |
| 403 | * interaction states. |
| 404 | */ |
| 405 | internal fun contentColor( |
| 406 | focused: Boolean, |
| 407 | pressed: Boolean, |
| 408 | colors: CardColors |
| 409 | ): Color { |
| 410 | return when { |
| 411 | focused -> colors.focusedContentColor |
| 412 | pressed -> colors.pressedContentColor |
| 413 | else -> colors.contentColor |
| 414 | } |
| 415 | } |
| 416 | |
| 417 | /** |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 418 | * Creates a [CardShape] that represents the default container shapes used in a Card. |
| 419 | * |
| 420 | * @param shape the default shape used when the Card has no other [Interaction]s. |
| 421 | * @param focusedShape the shape used when the Card is focused. |
| 422 | * @param pressedShape the shape used when the Card is pressed. |
| 423 | */ |
| 424 | fun shape( |
| 425 | shape: Shape = ContainerShape, |
| 426 | focusedShape: Shape = shape, |
| 427 | pressedShape: Shape = shape |
| 428 | ) = CardShape( |
| 429 | shape = shape, |
| 430 | focusedShape = focusedShape, |
| 431 | pressedShape = pressedShape |
| 432 | ) |
| 433 | |
| 434 | /** |
| 435 | * Creates [CardColors] that represents the default container & content colors used in a Card. |
| 436 | * |
| 437 | * @param containerColor the default container color of this Card. |
| 438 | * @param contentColor the default content color of this Card. |
| 439 | * @param focusedContainerColor the container color of this Card when focused. |
| 440 | * @param focusedContentColor the content color of this Card when focused. |
| 441 | * @param pressedContainerColor the container color of this Card when pressed. |
| 442 | * @param pressedContentColor the content color of this Card when pressed. |
| 443 | */ |
| 444 | @ReadOnlyComposable |
| 445 | @Composable |
| 446 | fun colors( |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 447 | containerColor: Color = MaterialTheme.colorScheme.surfaceVariant, |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 448 | contentColor: Color = contentColorFor(containerColor), |
| 449 | focusedContainerColor: Color = containerColor, |
| 450 | focusedContentColor: Color = contentColorFor(focusedContainerColor), |
| 451 | pressedContainerColor: Color = focusedContainerColor, |
| 452 | pressedContentColor: Color = contentColorFor(pressedContainerColor) |
| 453 | ) = CardColors( |
| 454 | containerColor = containerColor, |
| 455 | contentColor = contentColor, |
| 456 | focusedContainerColor = focusedContainerColor, |
| 457 | focusedContentColor = focusedContentColor, |
| 458 | pressedContainerColor = pressedContainerColor, |
| 459 | pressedContentColor = pressedContentColor |
| 460 | ) |
| 461 | |
| 462 | /** |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 463 | * Creates [CardColors] that represents the default colors used in a Compact Card. |
| 464 | * |
| 465 | * @param containerColor the default container color of this Card. |
| 466 | * @param contentColor the default content color of this Card. |
| 467 | * @param focusedContainerColor the container color of this Card when focused. |
| 468 | * @param focusedContentColor the content color of this Card when focused. |
| 469 | * @param pressedContainerColor the container color of this Card when pressed. |
| 470 | * @param pressedContentColor the content color of this Card when pressed. |
| 471 | */ |
| 472 | @ReadOnlyComposable |
| 473 | @Composable |
| 474 | fun compactCardColors( |
| 475 | containerColor: Color = MaterialTheme.colorScheme.surfaceVariant, |
| 476 | contentColor: Color = Color.White, |
| 477 | focusedContainerColor: Color = containerColor, |
| 478 | focusedContentColor: Color = contentColor, |
| 479 | pressedContainerColor: Color = focusedContainerColor, |
| 480 | pressedContentColor: Color = focusedContentColor |
| 481 | ) = CardColors( |
| 482 | containerColor = containerColor, |
| 483 | contentColor = contentColor, |
| 484 | focusedContainerColor = focusedContainerColor, |
| 485 | focusedContentColor = focusedContentColor, |
| 486 | pressedContainerColor = pressedContainerColor, |
| 487 | pressedContentColor = pressedContentColor |
| 488 | ) |
| 489 | |
| 490 | /** |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 491 | * Creates a [CardScale] that represents the default scales used in a Card. |
| 492 | * Scales are used to modify the size of a composable in different [Interaction] states |
| 493 | * e.g. 1f (original) in default state, 1.1f (scaled up) in focused state, 0.8f (scaled down) |
| 494 | * in pressed state, etc. |
| 495 | * |
| 496 | * @param scale the default scale to be used for this Card. |
| 497 | * @param focusedScale the scale to be used for this Card when focused. |
| 498 | * @param pressedScale the scale to be used for this Card when pressed. |
| 499 | */ |
| 500 | fun scale( |
| 501 | @FloatRange(from = 0.0) scale: Float = 1f, |
| 502 | @FloatRange(from = 0.0) focusedScale: Float = 1.1f, |
| 503 | @FloatRange(from = 0.0) pressedScale: Float = scale |
| 504 | ) = CardScale( |
| 505 | scale = scale, |
| 506 | focusedScale = focusedScale, |
| 507 | pressedScale = pressedScale |
| 508 | ) |
| 509 | |
| 510 | /** |
| 511 | * Creates a [CardBorder] that represents the border [Border]s applied on a Card in |
| 512 | * different [Interaction] states. |
| 513 | * |
| 514 | * @param border the default [Border] to be used for this Card. |
| 515 | * @param focusedBorder the [Border] to be used for this Card when focused. |
| 516 | * @param pressedBorder the [Border] to be used for this Card when pressed. |
| 517 | */ |
| 518 | @ReadOnlyComposable |
| 519 | @Composable |
| 520 | fun border( |
| 521 | border: Border = Border.None, |
| 522 | focusedBorder: Border = Border( |
| 523 | border = BorderStroke( |
| 524 | width = 3.dp, |
| 525 | color = MaterialTheme.colorScheme.border |
| 526 | ), |
| 527 | shape = ContainerShape |
| 528 | ), |
| 529 | pressedBorder: Border = focusedBorder |
| 530 | ) = CardBorder( |
| 531 | border = border, |
| 532 | focusedBorder = focusedBorder, |
| 533 | pressedBorder = pressedBorder |
| 534 | ) |
| 535 | |
| 536 | /** |
| 537 | * Creates a [CardGlow] that represents the default [Glow]s used in a card. |
| 538 | * |
| 539 | * @param glow the default [Glow] behind this Card. |
| 540 | * @param focusedGlow the [Glow] behind this Card when focused. |
| 541 | * @param pressedGlow the [Glow] behind this Card when pressed. |
| 542 | */ |
| 543 | fun glow( |
| 544 | glow: Glow = Glow.None, |
| 545 | focusedGlow: Glow = glow, |
| 546 | pressedGlow: Glow = glow |
| 547 | ) = CardGlow( |
| 548 | glow = glow, |
| 549 | focusedGlow = focusedGlow, |
| 550 | pressedGlow = pressedGlow |
| 551 | ) |
| 552 | } |
| 553 | |
Aditya Arora | 9929351 | 2023-03-31 13:03:37 +0530 | [diff] [blame^] | 554 | private const val SubtitleAlpha = 0.6f |
| 555 | private const val DescriptionAlpha = 0.8f |
| 556 | |
Aditya Arora | 26dd0be | 2023-03-09 12:15:34 +0530 | [diff] [blame] | 557 | @OptIn(ExperimentalTvMaterial3Api::class) |
| 558 | private fun CardColors.toClickableSurfaceContainerColor() = |
| 559 | ClickableSurfaceColor( |
| 560 | color = containerColor, |
| 561 | focusedColor = focusedContainerColor, |
| 562 | pressedColor = pressedContainerColor, |
| 563 | disabledColor = containerColor |
| 564 | ) |
| 565 | |
| 566 | @OptIn(ExperimentalTvMaterial3Api::class) |
| 567 | private fun CardColors.toClickableSurfaceContentColor() = |
| 568 | ClickableSurfaceColor( |
| 569 | color = contentColor, |
| 570 | focusedColor = focusedContentColor, |
| 571 | pressedColor = pressedContentColor, |
| 572 | disabledColor = contentColor |
| 573 | ) |
| 574 | |
| 575 | @OptIn(ExperimentalTvMaterial3Api::class) |
| 576 | private fun CardShape.toClickableSurfaceShape() = |
| 577 | ClickableSurfaceShape( |
| 578 | shape = shape, |
| 579 | focusedShape = focusedShape, |
| 580 | pressedShape = pressedShape, |
| 581 | disabledShape = shape, |
| 582 | focusedDisabledShape = shape |
| 583 | ) |
| 584 | |
| 585 | @OptIn(ExperimentalTvMaterial3Api::class) |
| 586 | private fun CardScale.toClickableSurfaceScale() = |
| 587 | ClickableSurfaceScale( |
| 588 | scale = scale, |
| 589 | focusedScale = focusedScale, |
| 590 | pressedScale = pressedScale, |
| 591 | disabledScale = scale, |
| 592 | focusedDisabledScale = scale |
| 593 | ) |
| 594 | |
| 595 | @OptIn(ExperimentalTvMaterial3Api::class) |
| 596 | private fun CardBorder.toClickableSurfaceBorder() = |
| 597 | ClickableSurfaceBorder( |
| 598 | border = border, |
| 599 | focusedBorder = focusedBorder, |
| 600 | pressedBorder = pressedBorder, |
| 601 | disabledBorder = border, |
| 602 | focusedDisabledBorder = border |
| 603 | ) |
| 604 | |
| 605 | @OptIn(ExperimentalTvMaterial3Api::class) |
| 606 | private fun CardGlow.toClickableSurfaceGlow() = |
| 607 | ClickableSurfaceGlow( |
| 608 | glow = glow, |
| 609 | focusedGlow = focusedGlow, |
| 610 | pressedGlow = pressedGlow |
| 611 | ) |