Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 42261925 authored by Olivier St-Onge's avatar Olivier St-Onge
Browse files

Use blur color tokens for QS

This includes some UX changes for edit mode such as:
- Removing the "Hold and drag" string above available tiles
- Adding background containers for available tiles categories
- Adding background to current tiles grid
- Using different badge colors for removal and addition

Flag: com.android.systemui.qs_ui_refactor_compose_fragment
Bug: 339262264
Test: manually - both dark and light mode
Test: manually - both dark and ligh wallpapers
Change-Id: Ic14dfcd7019f9b6abcd369fbaad6a8a0430ef066
parent ae8da20d
Loading
Loading
Loading
Loading
+17 −49
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.systemui.qs.composefragment

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Configuration
import android.graphics.PointF
import android.graphics.Rect
import android.os.Bundle
@@ -49,7 +48,6 @@ import androidx.compose.foundation.layout.requiredHeightIn
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -72,8 +70,6 @@ import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.layout.positionOnScreen
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.CustomAccessibilityAction
@@ -255,7 +251,7 @@ constructor(

    @Composable
    private fun Content() {
        PlatformTheme(isDarkTheme = true /* Delete AlwaysDarkMode when removing this */) {
        PlatformTheme {
            ProvideShortcutHelperIndication(interactionsConfig = interactionsConfig()) {
                // TODO(b/389985793): Make sure that there is no coroutine work or recompositions
                // happening when alwaysCompose is true but isQsVisibleAndAnyShadeExpanded is false.
@@ -746,7 +742,6 @@ constructor(
                        )
                        val BrightnessSlider =
                            @Composable {
                                AlwaysDarkMode {
                                Box(
                                    Modifier.systemGestureExclusionInShade(
                                        enabled = {
@@ -755,8 +750,7 @@ constructor(
                                    )
                                ) {
                                    BrightnessSliderContainer(
                                            viewModel =
                                                containerViewModel.brightnessSliderViewModel,
                                        viewModel = containerViewModel.brightnessSliderViewModel,
                                        containerColors =
                                            ContainerColors(
                                                Color.Transparent,
@@ -766,7 +760,6 @@ constructor(
                                    )
                                }
                            }
                            }
                        val TileGrid =
                            @Composable {
                                Box {
@@ -1241,28 +1234,3 @@ private fun interactionsConfig() =

private inline val alwaysCompose
    get() = Flags.alwaysComposeQsUiFragment()

/**
 * Forces the configuration and themes to be dark theme. This is needed in order to have
 * [colorResource] retrieve the dark mode colors.
 *
 * This should be removed when we remove the force dark mode in [PlatformTheme] at the root of the
 * compose hierarchy.
 */
@Composable
private fun AlwaysDarkMode(content: @Composable () -> Unit) {
    val currentConfig = LocalConfiguration.current
    val darkConfig =
        Configuration(currentConfig).apply {
            uiMode =
                (uiMode and (Configuration.UI_MODE_NIGHT_MASK.inv())) or
                    Configuration.UI_MODE_NIGHT_YES
        }
    val newContext = LocalContext.current.createConfigurationContext(darkConfig)
    CompositionLocalProvider(
        LocalConfiguration provides darkConfig,
        LocalContext provides newContext,
    ) {
        content()
    }
}
+85 −45
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -89,6 +90,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.isSpecified
import androidx.compose.ui.graphics.Color
@@ -114,6 +116,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.util.fastMap
import com.android.compose.modifiers.height
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.common.ui.compose.load
import com.android.systemui.qs.panels.shared.model.SizedTile
import com.android.systemui.qs.panels.shared.model.SizedTileImpl
@@ -131,6 +134,7 @@ import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaul
import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.AUTO_SCROLL_SPEED
import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.AvailableTilesGridMinHeight
import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.CurrentTilesGridPadding
import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.GridBackgroundCornerRadius
import com.android.systemui.qs.panels.ui.compose.selection.InteractiveTileContainer
import com.android.systemui.qs.panels.ui.compose.selection.MutableSelectionState
import com.android.systemui.qs.panels.ui.compose.selection.ResizingState
@@ -163,14 +167,27 @@ object TileType
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun EditModeTopBar(onStopEditing: () -> Unit, onReset: (() -> Unit)?) {

    val primaryContainerColor = MaterialTheme.colorScheme.primaryContainer
    TopAppBar(
        colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent),
        title = { Text(text = stringResource(id = R.string.qs_edit)) },
        colors =
            TopAppBarDefaults.topAppBarColors(
                containerColor = Color.Transparent,
                titleContentColor = MaterialTheme.colorScheme.onSurface,
            ),
        title = {
            Text(
                text = stringResource(id = R.string.qs_edit),
                modifier = Modifier.padding(start = 24.dp),
            )
        },
        navigationIcon = {
            IconButton(onClick = onStopEditing) {
            IconButton(
                onClick = onStopEditing,
                modifier = Modifier.drawBehind { drawCircle(primaryContainerColor) },
            ) {
                Icon(
                    Icons.AutoMirrored.Filled.ArrowBack,
                    tint = MaterialTheme.colorScheme.onSurface,
                    contentDescription =
                        stringResource(id = com.android.internal.R.string.action_bar_up_description),
                )
@@ -178,11 +195,19 @@ private fun EditModeTopBar(onStopEditing: () -> Unit, onReset: (() -> Unit)?) {
        },
        actions = {
            if (onReset != null) {
                TextButton(onClick = onReset) {
                TextButton(
                    onClick = onReset,
                    colors =
                        ButtonDefaults.textButtonColors(
                            containerColor = MaterialTheme.colorScheme.primary,
                            contentColor = MaterialTheme.colorScheme.onPrimary,
                        ),
                ) {
                    Text(stringResource(id = com.android.internal.R.string.reset))
                }
            }
        },
        modifier = Modifier.padding(vertical = 8.dp),
    )
}

@@ -244,7 +269,7 @@ fun DefaultEditTileGrid(
                    targetState = listState.dragInProgress || selectionState.selected,
                    label = "QSEditHeader",
                    contentAlignment = Alignment.Center,
                    modifier = Modifier.fillMaxWidth().heightIn(min = 80.dp),
                    modifier = Modifier.fillMaxWidth().heightIn(min = 48.dp),
                ) { showRemoveTarget ->
                    EditGridHeader {
                        if (showRemoveTarget) {
@@ -289,10 +314,6 @@ fun DefaultEditTileGrid(
                                spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin)),
                            modifier = modifier.fillMaxSize(),
                        ) {
                            EditGridHeader {
                                Text(text = stringResource(id = R.string.drag_to_add_tiles))
                            }

                            val availableTiles = remember {
                                mutableStateListOf<AvailableTileGridCell>().apply {
                                    addAll(toAvailableTiles(listState.tiles, otherTiles))
@@ -371,9 +392,7 @@ private fun EditGridHeader(
    modifier: Modifier = Modifier,
    content: @Composable BoxScope.() -> Unit,
) {
    CompositionLocalProvider(
        LocalContentColor provides MaterialTheme.colorScheme.onBackground.copy(alpha = .5f)
    ) {
    CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) {
        Box(contentAlignment = Alignment.Center, modifier = modifier.fillMaxWidth()) { content() }
    }
}
@@ -420,6 +439,7 @@ private fun CurrentTilesGrid(
            listState.tiles.fastMap { Pair(it, BounceableTileViewModel()) }
        }

    val primaryColor = MaterialTheme.colorScheme.primary
    TileLazyGrid(
        state = gridState,
        columns = GridCells.Fixed(columns),
@@ -428,9 +448,9 @@ private fun CurrentTilesGrid(
            Modifier.fillMaxWidth()
                .height { totalHeight.roundToPx() }
                .border(
                    width = 1.dp,
                    color = MaterialTheme.colorScheme.onBackground.copy(alpha = .5f),
                    shape = RoundedCornerShape((TileHeight / 2) + CurrentTilesGridPadding),
                    width = 2.dp,
                    color = primaryColor,
                    shape = RoundedCornerShape(GridBackgroundCornerRadius),
                )
                .dragAndDropTileList(gridState, { gridContentOffset }, listState) { spec ->
                    onSetTiles(currentListState.tileSpecs())
@@ -439,6 +459,13 @@ private fun CurrentTilesGrid(
                .onGloballyPositioned { coordinates ->
                    gridContentOffset = coordinates.positionInRoot()
                }
                .drawBehind {
                    drawRoundRect(
                        primaryColor,
                        cornerRadius = CornerRadius(GridBackgroundCornerRadius.toPx()),
                        alpha = .15f,
                    )
                }
                .testTag(CURRENT_TILES_GRID_TEST_TAG),
    ) {
        EditTiles(cells, listState, selectionState, coroutineScope, largeTilesSpan, onRemoveTile) {
@@ -469,7 +496,6 @@ private fun AvailableTileGrid(
        remember(tiles.fastMap { it.tile.category }, tiles.fastMap { it.tile.label }) {
            groupAndSort(tiles)
        }
    val labelColors = EditModeTileDefaults.editTileColors()

    // Available tiles
    Column(
@@ -480,12 +506,24 @@ private fun AvailableTileGrid(
    ) {
        groupedTiles.forEach { (category, tiles) ->
            key(category) {
                val surfaceColor = MaterialTheme.colorScheme.surface
                Column(
                    verticalArrangement = spacedBy(16.dp),
                    modifier =
                        Modifier.drawBehind {
                                drawRoundRect(
                                    surfaceColor,
                                    cornerRadius = CornerRadius(GridBackgroundCornerRadius.toPx()),
                                    alpha = .32f,
                                )
                            }
                            .padding(16.dp),
                ) {
                    Text(
                        text = category.label.load() ?: "",
                        fontSize = 20.sp,
                    color = labelColors.label,
                    modifier =
                        Modifier.fillMaxWidth().padding(start = 16.dp, bottom = 8.dp, top = 8.dp),
                        color = MaterialTheme.colorScheme.onSurface,
                        modifier = Modifier.fillMaxWidth().padding(start = 8.dp, bottom = 16.dp),
                    )
                    tiles.chunked(columns).forEach { row ->
                        Row(
@@ -512,6 +550,7 @@ private fun AvailableTileGrid(
            }
        }
    }
}

fun gridHeight(rows: Int, tileHeight: Dp, tilePadding: Dp, gridPadding: Dp): Dp {
    return ((tileHeight + tilePadding) * rows) + gridPadding * 2
@@ -761,7 +800,7 @@ private fun AvailableTileGridCell(
                color = colors.label,
                overflow = TextOverflow.Ellipsis,
                textAlign = TextAlign.Center,
                modifier = Modifier.align(Alignment.Center),
                modifier = Modifier.align(Alignment.TopCenter),
            )
        }
    }
@@ -861,15 +900,16 @@ private object EditModeTileDefaults {
    const val AUTO_SCROLL_SPEED = 2 // 2ms per pixel
    val CurrentTilesGridPadding = 10.dp
    val AvailableTilesGridMinHeight = 200.dp
    val GridBackgroundCornerRadius = 42.dp

    @Composable
    fun editTileColors(): TileColors =
        TileColors(
            background = MaterialTheme.colorScheme.surfaceVariant,
            iconBackground = MaterialTheme.colorScheme.surfaceVariant,
            label = MaterialTheme.colorScheme.onSurfaceVariant,
            secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant,
            icon = MaterialTheme.colorScheme.onSurfaceVariant,
            background = LocalAndroidColorScheme.current.surfaceEffect2,
            iconBackground = Color.Transparent,
            label = MaterialTheme.colorScheme.onSurface,
            secondaryLabel = MaterialTheme.colorScheme.onSurface,
            icon = MaterialTheme.colorScheme.onSurface,
        )
}

+26 −18
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.service.quicksettings.Tile.STATE_ACTIVE
import android.service.quicksettings.Tile.STATE_INACTIVE
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
@@ -59,6 +60,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.semantics.Role
@@ -75,6 +77,7 @@ import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.compose.animation.Expandable
import com.android.compose.animation.bounceable
import com.android.compose.modifiers.thenIf
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.Flags
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
@@ -165,6 +168,7 @@ fun Tile(
        // TODO(b/361789146): Draw the shapes instead of clipping
        val tileShape by TileDefaults.animateTileShapeAsState(uiState.state)
        val animatedColor by animateColorAsState(colors.background, label = "QSTileBackgroundColor")
        val animatedAlpha by animateFloatAsState(colors.alpha, label = "QSTileAlpha")

        TileExpandable(
            color = { animatedColor },
@@ -181,7 +185,8 @@ fun Tile(
                        nextBounceable = currentBounceableInfo.nextTile,
                        orientation = Orientation.Horizontal,
                        bounceEnd = currentBounceableInfo.bounceEnd,
                    ),
                    )
                    .graphicsLayer { alpha = animatedAlpha },
        ) { expandable ->
            val longClick: (() -> Unit)? =
                {
@@ -370,6 +375,7 @@ data class TileColors(
    val label: Color,
    val secondaryLabel: Color,
    val icon: Color,
    val alpha: Float = 1f,
)

private object TileDefaults {
@@ -393,10 +399,10 @@ private object TileDefaults {
    @ReadOnlyComposable
    fun activeDualTargetTileColors(): TileColors =
        TileColors(
            background = MaterialTheme.colorScheme.surfaceVariant,
            background = LocalAndroidColorScheme.current.surfaceEffect2,
            iconBackground = MaterialTheme.colorScheme.primary,
            label = MaterialTheme.colorScheme.onSurfaceVariant,
            secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant,
            label = MaterialTheme.colorScheme.onSurface,
            secondaryLabel = MaterialTheme.colorScheme.onSurface,
            icon = MaterialTheme.colorScheme.onPrimary,
        )

@@ -404,34 +410,36 @@ private object TileDefaults {
    @ReadOnlyComposable
    fun inactiveDualTargetTileColors(): TileColors =
        TileColors(
            background = MaterialTheme.colorScheme.surfaceVariant,
            iconBackground = MaterialTheme.colorScheme.surfaceContainerHighest,
            label = MaterialTheme.colorScheme.onSurfaceVariant,
            secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant,
            icon = MaterialTheme.colorScheme.onSurfaceVariant,
            background = LocalAndroidColorScheme.current.surfaceEffect2,
            iconBackground = LocalAndroidColorScheme.current.surfaceEffect3,
            label = MaterialTheme.colorScheme.onSurface,
            secondaryLabel = MaterialTheme.colorScheme.onSurface,
            icon = MaterialTheme.colorScheme.onSurface,
        )

    @Composable
    @ReadOnlyComposable
    fun inactiveTileColors(): TileColors =
        TileColors(
            background = MaterialTheme.colorScheme.surfaceVariant,
            iconBackground = MaterialTheme.colorScheme.surfaceVariant,
            label = MaterialTheme.colorScheme.onSurfaceVariant,
            secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant,
            icon = MaterialTheme.colorScheme.onSurfaceVariant,
            background = LocalAndroidColorScheme.current.surfaceEffect2,
            iconBackground = Color.Transparent,
            label = MaterialTheme.colorScheme.onSurface,
            secondaryLabel = MaterialTheme.colorScheme.onSurface,
            icon = MaterialTheme.colorScheme.onSurface,
        )

    @Composable
    @ReadOnlyComposable
    fun unavailableTileColors(): TileColors =
        TileColors(
            background = MaterialTheme.colorScheme.surface,
            iconBackground = MaterialTheme.colorScheme.surface,
    fun unavailableTileColors(): TileColors {
        return TileColors(
            background = LocalAndroidColorScheme.current.surfaceEffect2,
            iconBackground = LocalAndroidColorScheme.current.surfaceEffect2,
            label = MaterialTheme.colorScheme.onSurface,
            secondaryLabel = MaterialTheme.colorScheme.onSurface,
            icon = MaterialTheme.colorScheme.onSurface,
            alpha = .38f,
        )
    }

    @Composable
    @ReadOnlyComposable
+5 −4
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.toSize
import androidx.compose.ui.zIndex
import com.android.compose.modifiers.size
import com.android.compose.modifiers.thenIf
import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BADGE_ANGLE_RAD
@@ -155,6 +154,7 @@ fun InteractiveTileContainer(
                Icon(
                    Icons.Default.Remove,
                    contentDescription = null,
                    tint = MaterialTheme.colorScheme.onPrimaryContainer,
                    modifier =
                        Modifier.size(size).align(Alignment.Center).graphicsLayer {
                            this.alpha = badgeIconAlpha
@@ -218,14 +218,15 @@ fun StaticTileBadge(
                    )
                }
        ) {
            val secondaryColor = MaterialTheme.colorScheme.secondary
            val size = with(LocalDensity.current) { BadgeIconSize.toDp() }
            val primaryColor = MaterialTheme.colorScheme.primary
            Icon(
                icon,
                contentDescription = contentDescription,
                tint = MaterialTheme.colorScheme.onPrimary,
                modifier =
                    Modifier.size(size).align(Alignment.Center).drawBehind {
                        drawCircle(secondaryColor, radius = BadgeSize.toPx() / 2)
                        drawCircle(primaryColor, radius = BadgeSize.toPx() / 2)
                    },
            )
        }
@@ -291,7 +292,7 @@ private fun Transition<TileState>.animateColor(): State<Color> {
    return animateColor { state ->
        when (state) {
            None -> Color.Transparent
            Removable -> MaterialTheme.colorScheme.secondary
            Removable -> MaterialTheme.colorScheme.primaryContainer
            Selected -> MaterialTheme.colorScheme.primary
        }
    }
+16 −13
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import androidx.compose.ui.text.AnnotatedString
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
import com.android.compose.theme.PlatformTheme
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
@@ -55,6 +56,7 @@ class DragAndDropTest : SysuiTestCase() {
        listState: EditTileListState,
        onSetTiles: (List<TileSpec>) -> Unit,
    ) {
        PlatformTheme {
            DefaultEditTileGrid(
                listState = listState,
                otherTiles = listOf(),
@@ -69,6 +71,7 @@ class DragAndDropTest : SysuiTestCase() {
                onReset = null,
            )
        }
    }

    @Test
    fun draggedTile_shouldDisappear() {
Loading