@@ -68,9 +68,13 @@ import androidx.compose.runtime.setValue
6868import androidx.compose.ui.Alignment
6969import androidx.compose.ui.Modifier
7070import androidx.compose.ui.draw.clip
71+ import androidx.compose.ui.draw.drawBehind
72+ import androidx.compose.ui.geometry.Offset
7173import androidx.compose.ui.geometry.Size
74+ import androidx.compose.ui.graphics.Brush
7275import androidx.compose.ui.graphics.Color
7376import androidx.compose.ui.graphics.Shape
77+ import androidx.compose.ui.graphics.SolidColor
7478import androidx.compose.ui.platform.LocalConfiguration
7579import androidx.compose.ui.platform.LocalContext
7680import androidx.compose.ui.platform.LocalDensity
@@ -339,7 +343,14 @@ fun ContentScope.Tile(
339343 .size(CommonTileDefaults .TileHeight )
340344 .align(Alignment .Center )
341345 .clip(CircleShape )
342- .background(animatedColor)
346+ .drawBehind {
347+ val brush = colors.iconBackgroundGradient
348+ if (brush != null ) {
349+ drawRect(brush = brush)
350+ } else {
351+ drawRect(color = animatedColor)
352+ }
353+ }
343354 .indication(interaction, LocalIndication .current)
344355 .tileCombinedClickable(
345356 onClick = { click?.invoke() ? : Unit },
@@ -371,6 +382,7 @@ fun ContentScope.Tile(
371382 iconOnly = iconOnly,
372383 isDualTarget = isDualTarget,
373384 modifier = contentRevealModifier,
385+ colors = colors,
374386 ) {
375387 val iconProvider: Context .() -> Icon = { getTileIcon(icon = icon) }
376388 if (iconOnly) {
@@ -442,6 +454,7 @@ fun TileContainer(
442454 isDualTarget : Boolean ,
443455 interactionSource : MutableInteractionSource ? ,
444456 modifier : Modifier = Modifier ,
457+ colors : TileColors ,
445458 content : @Composable BoxScope .() -> Unit ,
446459) {
447460 Box (
@@ -457,7 +470,16 @@ fun TileContainer(
457470 isDualTarget = isDualTarget,
458471 interactionSource = interactionSource,
459472 )
460- .tileTestTag(iconOnly),
473+ .tileTestTag(iconOnly)
474+ .thenIf(! isDualTarget || iconOnly) {
475+ Modifier
476+ .drawBehind {
477+ val brush = colors.iconBackgroundGradient
478+ if (brush != null ) {
479+ drawRect(brush = brush)
480+ }
481+ }
482+ },
461483 content = content,
462484 )
463485}
@@ -475,7 +497,14 @@ fun LargeStaticTile(
475497 Box (
476498 modifier
477499 .clip(TileDefaults .animateTileShapeAsState(state = uiState.state, shapeMode = shapeMode).value)
478- .background(colors.background)
500+ .drawBehind {
501+ val brush = colors.iconBackgroundGradient
502+ if (brush != null ) {
503+ drawRect(brush = brush)
504+ } else {
505+ drawRect(color = colors.background)
506+ }
507+ }
479508 .height(TileHeight )
480509 .largeTilePadding()
481510 ) {
@@ -547,6 +576,7 @@ data class TileColors(
547576 val label : Color ,
548577 val secondaryLabel : Color ,
549578 val icon : Color ,
579+ val iconBackgroundGradient : Brush ? = null ,
550580)
551581
552582@Composable
@@ -629,32 +659,74 @@ fun rememberTileHaptic(): Boolean {
629659 return hapticEnabled
630660}
631661
662+ @Composable
663+ fun rememberQsGradient (): Boolean {
664+ val context = LocalContext .current
665+ val contentResolver = context.contentResolver
666+
667+ fun readEnabled (): Boolean {
668+ return try {
669+ Settings .System .getIntForUser(
670+ contentResolver, Settings .System .QS_TILE_GRADIENT , 0 ,
671+ UserHandle .USER_CURRENT
672+ ) != 0
673+ } catch (_: Throwable ) {
674+ false
675+ }
676+ }
677+
678+ var enabled by remember { mutableStateOf(readEnabled()) }
679+
680+ DisposableEffect (contentResolver) {
681+ val observer = object : ContentObserver (null ) {
682+ override fun onChange (selfChange : Boolean ) {
683+ enabled = readEnabled()
684+ }
685+ }
686+ contentResolver.registerContentObserver(
687+ Settings .System .getUriFor(Settings .System .QS_TILE_GRADIENT ),
688+ false , observer, UserHandle .USER_ALL
689+ )
690+ onDispose { contentResolver.unregisterContentObserver(observer) }
691+ }
692+
693+ return enabled
694+ }
695+
632696private object TileDefaults {
633697 val ActiveIconCornerRadius = 16 .dp
634698
635699 /* * An active tile uses the active color as background */
636700 @Composable
637- @ReadOnlyComposable
638- fun activeTileColors (): TileColors =
639- TileColors (
701+ fun activeTileColors (): TileColors {
702+ val gradientEnabled = rememberQsGradient()
703+ val gradient = qsTileBackgroundBrush(gradientEnabled)
704+
705+ return TileColors (
640706 background = MaterialTheme .colorScheme.primary,
641707 iconBackground = MaterialTheme .colorScheme.primary,
642708 label = MaterialTheme .colorScheme.onPrimary,
643709 secondaryLabel = MaterialTheme .colorScheme.onPrimary,
644710 icon = MaterialTheme .colorScheme.onPrimary,
711+ iconBackgroundGradient = gradient,
645712 )
713+ }
646714
647715 /* * An active tile with dual target only show the active color on the icon */
648716 @Composable
649- @ReadOnlyComposable
650- fun activeDualTargetTileColors (): TileColors =
651- TileColors (
717+ fun activeDualTargetTileColors (): TileColors {
718+ val gradientEnabled = rememberQsGradient()
719+ val gradient = qsTileBackgroundBrush(gradientEnabled)
720+
721+ return TileColors (
652722 background = LocalAndroidColorScheme .current.surfaceEffect1,
653723 iconBackground = MaterialTheme .colorScheme.primary,
654724 label = MaterialTheme .colorScheme.onSurface,
655725 secondaryLabel = MaterialTheme .colorScheme.onSurface,
656726 icon = MaterialTheme .colorScheme.onPrimary,
727+ iconBackgroundGradient = gradient,
657728 )
729+ }
658730
659731 @Composable
660732 @ReadOnlyComposable
@@ -693,7 +765,6 @@ private object TileDefaults {
693765 }
694766
695767 @Composable
696- @ReadOnlyComposable
697768 fun getColorForState (uiState : TileUiState , iconOnly : Boolean ): TileColors {
698769 return when (uiState.state) {
699770 STATE_ACTIVE -> {
@@ -765,6 +836,20 @@ private object TileDefaults {
765836 mutableStateOf(RoundedCornerShape (corner))
766837 }
767838 }
839+
840+ @Composable
841+ fun qsTileBackgroundBrush (enabled : Boolean ): Brush ? {
842+ if (! enabled) return null
843+
844+ return Brush .linearGradient(
845+ colors = listOf (
846+ MaterialTheme .colorScheme.primary,
847+ MaterialTheme .colorScheme.secondary
848+ ),
849+ start = Offset (0f , 0f ),
850+ end = Offset .Infinite
851+ )
852+ }
768853}
769854
770855/* *
0 commit comments