Loading packages/SystemUI/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -2599,6 +2599,9 @@ <!-- Accessibility description indicating the currently selected tile's position. Only used for tiles that are currently in use [CHAR LIMIT=NONE] --> <string name="accessibility_qs_edit_position">Position <xliff:g id="position" example="5">%1$d</xliff:g></string> <!-- Accessibility description indicating the currently selected tile is already added [CHAR LIMIT=NONE] --> <string name="accessibility_qs_edit_tile_already_added">Tile already added</string> <!-- Accessibility announcement after a tile has been added [CHAR LIMIT=NONE] --> <string name="accessibility_qs_edit_tile_added">Tile added</string> Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt +55 −29 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import androidx.compose.animation.AnimatedContent import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut Loading Loading @@ -78,6 +79,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope Loading Loading @@ -140,6 +142,7 @@ import com.android.systemui.qs.panels.ui.compose.selection.TileState import com.android.systemui.qs.panels.ui.compose.selection.rememberResizingState import com.android.systemui.qs.panels.ui.compose.selection.rememberSelectionState import com.android.systemui.qs.panels.ui.compose.selection.selectableTile import com.android.systemui.qs.panels.ui.model.AvailableTileGridCell import com.android.systemui.qs.panels.ui.model.GridCell import com.android.systemui.qs.panels.ui.model.SpacerGridCell import com.android.systemui.qs.panels.ui.model.TileGridCell Loading Loading @@ -290,8 +293,19 @@ fun DefaultEditTileGrid( Text(text = stringResource(id = R.string.drag_to_add_tiles)) } val availableTiles = remember { mutableStateListOf<AvailableTileGridCell>().apply { addAll(toAvailableTiles(listState.tiles, otherTiles)) } } LaunchedEffect(listState.tiles, otherTiles) { availableTiles.apply { clear() addAll(toAvailableTiles(listState.tiles, otherTiles)) } } AvailableTileGrid( otherTiles, availableTiles, selectionState, columns, onAddTile, Loading Loading @@ -444,7 +458,7 @@ private fun CurrentTilesGrid( @Composable private fun AvailableTileGrid( tiles: List<SizedTile<EditTileViewModel>>, tiles: List<AvailableTileGridCell>, selectionState: MutableSelectionState, columns: Int, onAddTile: (TileSpec) -> Unit, Loading @@ -453,7 +467,7 @@ private fun AvailableTileGrid( // Available tiles aren't visible during drag and drop, so the row/col isn't needed val groupedTiles = remember(tiles.fastMap { it.tile.category }, tiles.fastMap { it.tile.label }) { groupAndSort(tiles.fastMap { TileGridCell(it, 0, 0) }) groupAndSort(tiles) } val labelColors = EditModeTileDefaults.editTileColors() Loading @@ -478,11 +492,10 @@ private fun AvailableTileGrid( horizontalArrangement = spacedBy(TileArrangementPadding), modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Max), ) { row.forEachIndexed { index, tileGridCell -> key(tileGridCell.tile.tileSpec) { row.forEach { tileGridCell -> key(tileGridCell.key) { AvailableTileGridCell( cell = tileGridCell, index = index, dragAndDropState = dragAndDropState, selectionState = selectionState, onAddTile = onAddTile, Loading @@ -505,10 +518,7 @@ fun gridHeight(rows: Int, tileHeight: Dp, tilePadding: Dp, gridPadding: Dp): Dp } private fun GridCell.key(index: Int): Any { return when (this) { is TileGridCell -> key is SpacerGridCell -> index } return if (this is TileGridCell) key else index } /** Loading Loading @@ -687,41 +697,44 @@ private fun TileGridCell( @Composable private fun AvailableTileGridCell( cell: TileGridCell, index: Int, cell: AvailableTileGridCell, dragAndDropState: DragAndDropState, selectionState: MutableSelectionState, onAddTile: (TileSpec) -> Unit, modifier: Modifier = Modifier, ) { val onClickActionName = stringResource(id = R.string.accessibility_qs_edit_tile_add_action) val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1) val stateDescription: String? = if (cell.isAvailable) null else stringResource(R.string.accessibility_qs_edit_tile_already_added) val alpha by animateFloatAsState(if (cell.isAvailable) 1f else .38f) val colors = EditModeTileDefaults.editTileColors() val onClick = { onAddTile(cell.tile.tileSpec) selectionState.select(cell.tile.tileSpec) } // Displays the tile as an icon tile with the label underneath Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = spacedBy(CommonTileDefaults.TilePadding, Alignment.Top), modifier = modifier, modifier = modifier .graphicsLayer { this.alpha = alpha } .semantics(mergeDescendants = true) { stateDescription?.let { this.stateDescription = it } }, ) { Box(Modifier.fillMaxWidth().height(TileHeight)) { Box( Modifier.fillMaxSize() .clickable(onClick = onClick, onClickLabel = onClickActionName) .semantics(mergeDescendants = true) { this.stateDescription = stateDescription } .dragAndDropTileSource( val draggableModifier = if (cell.isAvailable) { Modifier.dragAndDropTileSource( SizedTileImpl(cell.tile, cell.width), dragAndDropState, DragType.Add, ) { selectionState.unSelect() } .tileBackground(colors.background) ) { } else { Modifier } Box(draggableModifier.fillMaxSize().tileBackground(colors.background)) { // Icon SmallTileContent( iconProvider = { cell.tile.icon }, Loading @@ -733,9 +746,13 @@ private fun AvailableTileGridCell( StaticTileBadge( icon = Icons.Default.Add, contentDescription = onClickActionName, onClick = onClick, ) contentDescription = stringResource(id = R.string.accessibility_qs_edit_tile_add_action), enabled = cell.isAvailable, ) { onAddTile(cell.tile.tileSpec) selectionState.select(cell.tile.tileSpec) } } Box(Modifier.fillMaxSize()) { Text( Loading Loading @@ -819,6 +836,15 @@ fun EditTile( } } private fun toAvailableTiles( currentTiles: List<GridCell>, otherTiles: List<SizedTile<EditTileViewModel>>, ): List<AvailableTileGridCell> { return currentTiles.filterIsInstance<TileGridCell>().fastMap { AvailableTileGridCell(it.tile, isAvailable = false) } + otherTiles.fastMap { AvailableTileGridCell(it.tile) } } private fun MeasureScope.iconHorizontalCenter(containerSize: Int): Float { return (containerSize - ToggleTargetSize.roundToPx()) / 2f - CommonTileDefaults.TilePadding.toPx() Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt +32 −9 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.qs.panels.ui.compose.selection import androidx.compose.animation.animateColor import androidx.compose.animation.core.Transition import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateOffset import androidx.compose.animation.core.animateSize import androidx.compose.animation.core.updateTransition Loading Loading @@ -61,6 +62,7 @@ import androidx.compose.ui.unit.dp 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 import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BadgeSize Loading Loading @@ -184,18 +186,37 @@ private fun Modifier.selectionBorder( } } /** * Draws a clickable badge in the top end corner of the parent composable. * * The badge will fade in and fade out based on whether or not it's enabled. * * @param icon the [ImageVector] to display in the badge * @param contentDescription the content description for the icon * @param enabled Whether the badge should be visible and clickable * @param onClick the callback when the badge is clicked */ @Composable fun StaticTileBadge(icon: ImageVector, contentDescription: String?, onClick: () -> Unit) { fun StaticTileBadge( icon: ImageVector, contentDescription: String?, enabled: Boolean, onClick: () -> Unit, ) { val offset = with(LocalDensity.current) { Offset(BadgeXOffset.toPx(), BadgeYOffset.toPx()) } val alpha by animateFloatAsState(if (enabled) 1f else 0f) MinimumInteractiveSizeComponent(angle = { BADGE_ANGLE_RAD }, offset = { offset }) { Box( Modifier.fillMaxSize() .clickable( .graphicsLayer { this.alpha = alpha } .thenIf(enabled) { Modifier.clickable( interactionSource = null, indication = null, onClickLabel = contentDescription, onClick = onClick, ) } ) { val secondaryColor = MaterialTheme.colorScheme.secondary Icon( Loading @@ -214,7 +235,8 @@ fun StaticTileBadge(icon: ImageVector, contentDescription: String?, onClick: () private fun MinimumInteractiveSizeComponent( angle: () -> Float, offset: () -> Offset, content: @Composable BoxScope.() -> Unit, modifier: Modifier = Modifier, content: @Composable BoxScope.() -> Unit = {}, ) { // Use a higher zIndex than the tile to draw over it, and manually create the touch target // as we're drawing over neighbor tiles as well. Loading @@ -222,7 +244,8 @@ private fun MinimumInteractiveSizeComponent( Box( contentAlignment = Alignment.Center, modifier = Modifier.zIndex(2f) modifier .zIndex(2f) .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) } .layout { measurable, constraints -> val size = minTouchTargetSize.roundToPx() Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt +13 −3 Original line number Diff line number Diff line Loading @@ -21,13 +21,13 @@ import androidx.compose.runtime.Immutable import com.android.systemui.qs.panels.shared.model.SizedTile import com.android.systemui.qs.panels.shared.model.splitInRowsSequence import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.shared.model.CategoryAndName /** Represents an item from a grid associated with a row and a span */ sealed interface GridCell { val row: Int val span: GridItemSpan val s: String } /** Loading @@ -40,7 +40,6 @@ data class TileGridCell( override val row: Int, override val width: Int, override val span: GridItemSpan = GridItemSpan(width), override val s: String = "${tile.tileSpec.spec}-$row-$width", val column: Int, ) : GridCell, SizedTile<EditTileViewModel>, CategoryAndName by tile { val key: String = "${tile.tileSpec.spec}-$row" Loading @@ -52,12 +51,23 @@ data class TileGridCell( ) : this(tile = sizedTile.tile, row = row, column = column, width = sizedTile.width) } /** * Represents a [EditTileViewModel] from the edit mode available tiles grid and whether it is * available to add or not. */ @Immutable data class AvailableTileGridCell( override val tile: EditTileViewModel, override val width: Int = 1, val isAvailable: Boolean = true, val key: TileSpec = tile.tileSpec, ) : SizedTile<EditTileViewModel>, CategoryAndName by tile /** Represents an empty space used to fill incomplete rows. Will always display as a 1x1 tile */ @Immutable data class SpacerGridCell( override val row: Int, override val span: GridItemSpan = GridItemSpan(1), override val s: String = "spacer", ) : GridCell /** Loading packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/EditModeTest.kt +10 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onAllNodesWithText import androidx.compose.ui.test.onFirst import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick Loading Loading @@ -80,7 +82,9 @@ class EditModeTest : SysuiTestCase() { composeRule.assertCurrentTilesGridContainsExactly( listOf("tileA", "tileB", "tileC", "tileD_large", "tileE", "tileF") ) composeRule.assertAvailableTilesGridContainsExactly(listOf("tileG_large")) composeRule.assertAvailableTilesGridContainsExactly( TestEditTiles.map { it.tile.tileSpec.spec } ) } @Test Loading @@ -88,7 +92,8 @@ class EditModeTest : SysuiTestCase() { composeRule.setContent { EditTileGridUnderTest() } composeRule.waitForIdle() composeRule.onNodeWithContentDescription("tileA").performClick() // Selects // Selects first "tileA", i.e. the one in the current grid composeRule.onAllNodesWithText("tileA").onFirst().performClick() composeRule.onNodeWithText("Remove").performClick() // Removes composeRule.waitForIdle() Loading @@ -96,7 +101,9 @@ class EditModeTest : SysuiTestCase() { composeRule.assertCurrentTilesGridContainsExactly( listOf("tileB", "tileC", "tileD_large", "tileE") ) composeRule.assertAvailableTilesGridContainsExactly(listOf("tileA", "tileF", "tileG_large")) composeRule.assertAvailableTilesGridContainsExactly( TestEditTiles.map { it.tile.tileSpec.spec } ) } private fun ComposeContentTestRule.assertCurrentTilesGridContainsExactly(specs: List<String>) = Loading Loading
packages/SystemUI/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -2599,6 +2599,9 @@ <!-- Accessibility description indicating the currently selected tile's position. Only used for tiles that are currently in use [CHAR LIMIT=NONE] --> <string name="accessibility_qs_edit_position">Position <xliff:g id="position" example="5">%1$d</xliff:g></string> <!-- Accessibility description indicating the currently selected tile is already added [CHAR LIMIT=NONE] --> <string name="accessibility_qs_edit_tile_already_added">Tile already added</string> <!-- Accessibility announcement after a tile has been added [CHAR LIMIT=NONE] --> <string name="accessibility_qs_edit_tile_added">Tile added</string> Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt +55 −29 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import androidx.compose.animation.AnimatedContent import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut Loading Loading @@ -78,6 +79,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope Loading Loading @@ -140,6 +142,7 @@ import com.android.systemui.qs.panels.ui.compose.selection.TileState import com.android.systemui.qs.panels.ui.compose.selection.rememberResizingState import com.android.systemui.qs.panels.ui.compose.selection.rememberSelectionState import com.android.systemui.qs.panels.ui.compose.selection.selectableTile import com.android.systemui.qs.panels.ui.model.AvailableTileGridCell import com.android.systemui.qs.panels.ui.model.GridCell import com.android.systemui.qs.panels.ui.model.SpacerGridCell import com.android.systemui.qs.panels.ui.model.TileGridCell Loading Loading @@ -290,8 +293,19 @@ fun DefaultEditTileGrid( Text(text = stringResource(id = R.string.drag_to_add_tiles)) } val availableTiles = remember { mutableStateListOf<AvailableTileGridCell>().apply { addAll(toAvailableTiles(listState.tiles, otherTiles)) } } LaunchedEffect(listState.tiles, otherTiles) { availableTiles.apply { clear() addAll(toAvailableTiles(listState.tiles, otherTiles)) } } AvailableTileGrid( otherTiles, availableTiles, selectionState, columns, onAddTile, Loading Loading @@ -444,7 +458,7 @@ private fun CurrentTilesGrid( @Composable private fun AvailableTileGrid( tiles: List<SizedTile<EditTileViewModel>>, tiles: List<AvailableTileGridCell>, selectionState: MutableSelectionState, columns: Int, onAddTile: (TileSpec) -> Unit, Loading @@ -453,7 +467,7 @@ private fun AvailableTileGrid( // Available tiles aren't visible during drag and drop, so the row/col isn't needed val groupedTiles = remember(tiles.fastMap { it.tile.category }, tiles.fastMap { it.tile.label }) { groupAndSort(tiles.fastMap { TileGridCell(it, 0, 0) }) groupAndSort(tiles) } val labelColors = EditModeTileDefaults.editTileColors() Loading @@ -478,11 +492,10 @@ private fun AvailableTileGrid( horizontalArrangement = spacedBy(TileArrangementPadding), modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Max), ) { row.forEachIndexed { index, tileGridCell -> key(tileGridCell.tile.tileSpec) { row.forEach { tileGridCell -> key(tileGridCell.key) { AvailableTileGridCell( cell = tileGridCell, index = index, dragAndDropState = dragAndDropState, selectionState = selectionState, onAddTile = onAddTile, Loading @@ -505,10 +518,7 @@ fun gridHeight(rows: Int, tileHeight: Dp, tilePadding: Dp, gridPadding: Dp): Dp } private fun GridCell.key(index: Int): Any { return when (this) { is TileGridCell -> key is SpacerGridCell -> index } return if (this is TileGridCell) key else index } /** Loading Loading @@ -687,41 +697,44 @@ private fun TileGridCell( @Composable private fun AvailableTileGridCell( cell: TileGridCell, index: Int, cell: AvailableTileGridCell, dragAndDropState: DragAndDropState, selectionState: MutableSelectionState, onAddTile: (TileSpec) -> Unit, modifier: Modifier = Modifier, ) { val onClickActionName = stringResource(id = R.string.accessibility_qs_edit_tile_add_action) val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1) val stateDescription: String? = if (cell.isAvailable) null else stringResource(R.string.accessibility_qs_edit_tile_already_added) val alpha by animateFloatAsState(if (cell.isAvailable) 1f else .38f) val colors = EditModeTileDefaults.editTileColors() val onClick = { onAddTile(cell.tile.tileSpec) selectionState.select(cell.tile.tileSpec) } // Displays the tile as an icon tile with the label underneath Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = spacedBy(CommonTileDefaults.TilePadding, Alignment.Top), modifier = modifier, modifier = modifier .graphicsLayer { this.alpha = alpha } .semantics(mergeDescendants = true) { stateDescription?.let { this.stateDescription = it } }, ) { Box(Modifier.fillMaxWidth().height(TileHeight)) { Box( Modifier.fillMaxSize() .clickable(onClick = onClick, onClickLabel = onClickActionName) .semantics(mergeDescendants = true) { this.stateDescription = stateDescription } .dragAndDropTileSource( val draggableModifier = if (cell.isAvailable) { Modifier.dragAndDropTileSource( SizedTileImpl(cell.tile, cell.width), dragAndDropState, DragType.Add, ) { selectionState.unSelect() } .tileBackground(colors.background) ) { } else { Modifier } Box(draggableModifier.fillMaxSize().tileBackground(colors.background)) { // Icon SmallTileContent( iconProvider = { cell.tile.icon }, Loading @@ -733,9 +746,13 @@ private fun AvailableTileGridCell( StaticTileBadge( icon = Icons.Default.Add, contentDescription = onClickActionName, onClick = onClick, ) contentDescription = stringResource(id = R.string.accessibility_qs_edit_tile_add_action), enabled = cell.isAvailable, ) { onAddTile(cell.tile.tileSpec) selectionState.select(cell.tile.tileSpec) } } Box(Modifier.fillMaxSize()) { Text( Loading Loading @@ -819,6 +836,15 @@ fun EditTile( } } private fun toAvailableTiles( currentTiles: List<GridCell>, otherTiles: List<SizedTile<EditTileViewModel>>, ): List<AvailableTileGridCell> { return currentTiles.filterIsInstance<TileGridCell>().fastMap { AvailableTileGridCell(it.tile, isAvailable = false) } + otherTiles.fastMap { AvailableTileGridCell(it.tile) } } private fun MeasureScope.iconHorizontalCenter(containerSize: Int): Float { return (containerSize - ToggleTargetSize.roundToPx()) / 2f - CommonTileDefaults.TilePadding.toPx() Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt +32 −9 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.qs.panels.ui.compose.selection import androidx.compose.animation.animateColor import androidx.compose.animation.core.Transition import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateOffset import androidx.compose.animation.core.animateSize import androidx.compose.animation.core.updateTransition Loading Loading @@ -61,6 +62,7 @@ import androidx.compose.ui.unit.dp 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 import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BadgeSize Loading Loading @@ -184,18 +186,37 @@ private fun Modifier.selectionBorder( } } /** * Draws a clickable badge in the top end corner of the parent composable. * * The badge will fade in and fade out based on whether or not it's enabled. * * @param icon the [ImageVector] to display in the badge * @param contentDescription the content description for the icon * @param enabled Whether the badge should be visible and clickable * @param onClick the callback when the badge is clicked */ @Composable fun StaticTileBadge(icon: ImageVector, contentDescription: String?, onClick: () -> Unit) { fun StaticTileBadge( icon: ImageVector, contentDescription: String?, enabled: Boolean, onClick: () -> Unit, ) { val offset = with(LocalDensity.current) { Offset(BadgeXOffset.toPx(), BadgeYOffset.toPx()) } val alpha by animateFloatAsState(if (enabled) 1f else 0f) MinimumInteractiveSizeComponent(angle = { BADGE_ANGLE_RAD }, offset = { offset }) { Box( Modifier.fillMaxSize() .clickable( .graphicsLayer { this.alpha = alpha } .thenIf(enabled) { Modifier.clickable( interactionSource = null, indication = null, onClickLabel = contentDescription, onClick = onClick, ) } ) { val secondaryColor = MaterialTheme.colorScheme.secondary Icon( Loading @@ -214,7 +235,8 @@ fun StaticTileBadge(icon: ImageVector, contentDescription: String?, onClick: () private fun MinimumInteractiveSizeComponent( angle: () -> Float, offset: () -> Offset, content: @Composable BoxScope.() -> Unit, modifier: Modifier = Modifier, content: @Composable BoxScope.() -> Unit = {}, ) { // Use a higher zIndex than the tile to draw over it, and manually create the touch target // as we're drawing over neighbor tiles as well. Loading @@ -222,7 +244,8 @@ private fun MinimumInteractiveSizeComponent( Box( contentAlignment = Alignment.Center, modifier = Modifier.zIndex(2f) modifier .zIndex(2f) .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) } .layout { measurable, constraints -> val size = minTouchTargetSize.roundToPx() Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt +13 −3 Original line number Diff line number Diff line Loading @@ -21,13 +21,13 @@ import androidx.compose.runtime.Immutable import com.android.systemui.qs.panels.shared.model.SizedTile import com.android.systemui.qs.panels.shared.model.splitInRowsSequence import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.shared.model.CategoryAndName /** Represents an item from a grid associated with a row and a span */ sealed interface GridCell { val row: Int val span: GridItemSpan val s: String } /** Loading @@ -40,7 +40,6 @@ data class TileGridCell( override val row: Int, override val width: Int, override val span: GridItemSpan = GridItemSpan(width), override val s: String = "${tile.tileSpec.spec}-$row-$width", val column: Int, ) : GridCell, SizedTile<EditTileViewModel>, CategoryAndName by tile { val key: String = "${tile.tileSpec.spec}-$row" Loading @@ -52,12 +51,23 @@ data class TileGridCell( ) : this(tile = sizedTile.tile, row = row, column = column, width = sizedTile.width) } /** * Represents a [EditTileViewModel] from the edit mode available tiles grid and whether it is * available to add or not. */ @Immutable data class AvailableTileGridCell( override val tile: EditTileViewModel, override val width: Int = 1, val isAvailable: Boolean = true, val key: TileSpec = tile.tileSpec, ) : SizedTile<EditTileViewModel>, CategoryAndName by tile /** Represents an empty space used to fill incomplete rows. Will always display as a 1x1 tile */ @Immutable data class SpacerGridCell( override val row: Int, override val span: GridItemSpan = GridItemSpan(1), override val s: String = "spacer", ) : GridCell /** Loading
packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/EditModeTest.kt +10 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onAllNodesWithText import androidx.compose.ui.test.onFirst import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick Loading Loading @@ -80,7 +82,9 @@ class EditModeTest : SysuiTestCase() { composeRule.assertCurrentTilesGridContainsExactly( listOf("tileA", "tileB", "tileC", "tileD_large", "tileE", "tileF") ) composeRule.assertAvailableTilesGridContainsExactly(listOf("tileG_large")) composeRule.assertAvailableTilesGridContainsExactly( TestEditTiles.map { it.tile.tileSpec.spec } ) } @Test Loading @@ -88,7 +92,8 @@ class EditModeTest : SysuiTestCase() { composeRule.setContent { EditTileGridUnderTest() } composeRule.waitForIdle() composeRule.onNodeWithContentDescription("tileA").performClick() // Selects // Selects first "tileA", i.e. the one in the current grid composeRule.onAllNodesWithText("tileA").onFirst().performClick() composeRule.onNodeWithText("Remove").performClick() // Removes composeRule.waitForIdle() Loading @@ -96,7 +101,9 @@ class EditModeTest : SysuiTestCase() { composeRule.assertCurrentTilesGridContainsExactly( listOf("tileB", "tileC", "tileD_large", "tileE") ) composeRule.assertAvailableTilesGridContainsExactly(listOf("tileA", "tileF", "tileG_large")) composeRule.assertAvailableTilesGridContainsExactly( TestEditTiles.map { it.tile.tileSpec.spec } ) } private fun ComposeContentTestRule.assertCurrentTilesGridContainsExactly(specs: List<String>) = Loading