Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt 0 → 100644 +60 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.panels.ui.compose import com.android.compose.animation.Bounceable import com.android.systemui.qs.panels.shared.model.SizedTile import com.android.systemui.qs.panels.ui.model.GridCell import com.android.systemui.qs.panels.ui.model.TileGridCell import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel data class BounceableInfo( val bounceable: BounceableTileViewModel, val previousTile: Bounceable?, val nextTile: Bounceable?, val bounceEnd: Boolean, ) fun List<Pair<GridCell, BounceableTileViewModel>>.bounceableInfo( index: Int, columns: Int, ): BounceableInfo { val cell = this[index].first as TileGridCell // Only look for neighbor bounceables if they are on the same row val onLastColumn = cell.onLastColumn(cell.column, columns) val previousTile = getOrNull(index - 1)?.takeIf { cell.column != 0 } val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn } return BounceableInfo(this[index].second, previousTile?.second, nextTile?.second, !onLastColumn) } fun List<BounceableTileViewModel>.bounceableInfo( sizedTile: SizedTile<TileViewModel>, index: Int, column: Int, columns: Int, ): BounceableInfo { // Only look for neighbor bounceables if they are on the same row val onLastColumn = sizedTile.onLastColumn(column, columns) val previousTile = getOrNull(index - 1)?.takeIf { column != 0 } val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn } return BounceableInfo(this[index], previousTile, nextTile, !onLastColumn) } private fun <T> SizedTile<T>.onLastColumn(column: Int, columns: Int): Boolean { return column == columns - width } packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt +2 −2 Original line number Original line Diff line number Diff line Loading @@ -116,9 +116,9 @@ class EditTileListState(tiles: List<SizedTile<EditTileViewModel>>, private val c regenerateGrid() regenerateGrid() _tiles.add(insertionIndex.coerceIn(0, _tiles.size), cell) _tiles.add(insertionIndex.coerceIn(0, _tiles.size), cell) } else { } else { // Add the tile with a temporary row which will get reassigned when // Add the tile with a temporary row/col which will get reassigned when // regenerating spacers // regenerating spacers _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0)) _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0, 0)) } } regenerateGrid() regenerateGrid() Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt +10 −0 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,8 @@ import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.util.fastMap import androidx.compose.ui.util.fastMap Loading @@ -29,6 +31,7 @@ import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.grid.ui.compose.VerticalSpannedGrid import com.android.systemui.grid.ui.compose.VerticalSpannedGrid import com.android.systemui.qs.composefragment.ui.GridAnchor import com.android.systemui.qs.composefragment.ui.GridAnchor import com.android.systemui.qs.panels.ui.compose.infinitegrid.Tile import com.android.systemui.qs.panels.ui.compose.infinitegrid.Tile import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel import com.android.systemui.qs.shared.ui.ElementKeys.toElementKey import com.android.systemui.qs.shared.ui.ElementKeys.toElementKey import com.android.systemui.res.R import com.android.systemui.res.R Loading @@ -41,7 +44,9 @@ fun SceneScope.QuickQuickSettings( val sizedTiles by val sizedTiles by viewModel.tileViewModels.collectAsStateWithLifecycle(initialValue = emptyList()) viewModel.tileViewModels.collectAsStateWithLifecycle(initialValue = emptyList()) val tiles = sizedTiles.fastMap { it.tile } val tiles = sizedTiles.fastMap { it.tile } val bounceables = remember(sizedTiles) { List(sizedTiles.size) { BounceableTileViewModel() } } val squishiness by viewModel.squishinessViewModel.squishiness.collectAsStateWithLifecycle() val squishiness by viewModel.squishinessViewModel.squishiness.collectAsStateWithLifecycle() val scope = rememberCoroutineScope() DisposableEffect(tiles) { DisposableEffect(tiles) { val token = Any() val token = Any() Loading @@ -49,6 +54,7 @@ fun SceneScope.QuickQuickSettings( onDispose { tiles.forEach { it.stopListening(token) } } onDispose { tiles.forEach { it.stopListening(token) } } } } val columns by viewModel.columns.collectAsStateWithLifecycle() val columns by viewModel.columns.collectAsStateWithLifecycle() var cellIndex = 0 Box(modifier = modifier) { Box(modifier = modifier) { GridAnchor() GridAnchor() VerticalSpannedGrid( VerticalSpannedGrid( Loading @@ -59,11 +65,15 @@ fun SceneScope.QuickQuickSettings( modifier = Modifier.sysuiResTag("qqs_tile_layout"), modifier = Modifier.sysuiResTag("qqs_tile_layout"), ) { spanIndex -> ) { spanIndex -> val it = sizedTiles[spanIndex] val it = sizedTiles[spanIndex] val column = cellIndex % columns cellIndex += it.width Tile( Tile( tile = it.tile, tile = it.tile, iconOnly = it.isIcon, iconOnly = it.isIcon, modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)), modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)), squishiness = { squishiness }, squishiness = { squishiness }, coroutineScope = scope, bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns), ) ) } } } } Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt +12 −7 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect Loading @@ -54,6 +55,7 @@ import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.semantics.toggleableState import androidx.compose.ui.semantics.toggleableState import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp import com.android.compose.modifiers.background import com.android.compose.modifiers.background import com.android.compose.modifiers.thenIf import com.android.compose.modifiers.thenIf Loading @@ -64,7 +66,6 @@ import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState import com.android.systemui.res.R import com.android.systemui.res.R import kotlinx.coroutines.delay private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target" private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target" Loading Loading @@ -138,13 +139,20 @@ fun LargeTileLabels( accessibilityUiState: AccessibilityUiState? = null, accessibilityUiState: AccessibilityUiState? = null, ) { ) { Column(verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxHeight()) { Column(verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxHeight()) { Text(label, color = colors.label, modifier = Modifier.tileMarquee()) Text( label, style = MaterialTheme.typography.labelLarge, color = colors.label, maxLines = 1, overflow = TextOverflow.Ellipsis, ) if (!TextUtils.isEmpty(secondaryLabel)) { if (!TextUtils.isEmpty(secondaryLabel)) { Text( Text( secondaryLabel ?: "", secondaryLabel ?: "", color = colors.secondaryLabel, color = colors.secondaryLabel, style = MaterialTheme.typography.bodyMedium, modifier = modifier = Modifier.tileMarquee().thenIf( Modifier.thenIf( accessibilityUiState?.stateDescription?.contains(secondaryLabel ?: "") == accessibilityUiState?.stateDescription?.contains(secondaryLabel ?: "") == true true ) { ) { Loading Loading @@ -182,10 +190,7 @@ fun SmallTileContent( rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = true) rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = true) } else { } else { var atEnd by remember(icon.res) { mutableStateOf(false) } var atEnd by remember(icon.res) { mutableStateOf(false) } LaunchedEffect(key1 = icon.res) { LaunchedEffect(key1 = icon.res) { atEnd = true } delay(350) atEnd = true } rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = atEnd) rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = atEnd) } } } } Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt +123 −229 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt 0 → 100644 +60 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.panels.ui.compose import com.android.compose.animation.Bounceable import com.android.systemui.qs.panels.shared.model.SizedTile import com.android.systemui.qs.panels.ui.model.GridCell import com.android.systemui.qs.panels.ui.model.TileGridCell import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel data class BounceableInfo( val bounceable: BounceableTileViewModel, val previousTile: Bounceable?, val nextTile: Bounceable?, val bounceEnd: Boolean, ) fun List<Pair<GridCell, BounceableTileViewModel>>.bounceableInfo( index: Int, columns: Int, ): BounceableInfo { val cell = this[index].first as TileGridCell // Only look for neighbor bounceables if they are on the same row val onLastColumn = cell.onLastColumn(cell.column, columns) val previousTile = getOrNull(index - 1)?.takeIf { cell.column != 0 } val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn } return BounceableInfo(this[index].second, previousTile?.second, nextTile?.second, !onLastColumn) } fun List<BounceableTileViewModel>.bounceableInfo( sizedTile: SizedTile<TileViewModel>, index: Int, column: Int, columns: Int, ): BounceableInfo { // Only look for neighbor bounceables if they are on the same row val onLastColumn = sizedTile.onLastColumn(column, columns) val previousTile = getOrNull(index - 1)?.takeIf { column != 0 } val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn } return BounceableInfo(this[index], previousTile, nextTile, !onLastColumn) } private fun <T> SizedTile<T>.onLastColumn(column: Int, columns: Int): Boolean { return column == columns - width }
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt +2 −2 Original line number Original line Diff line number Diff line Loading @@ -116,9 +116,9 @@ class EditTileListState(tiles: List<SizedTile<EditTileViewModel>>, private val c regenerateGrid() regenerateGrid() _tiles.add(insertionIndex.coerceIn(0, _tiles.size), cell) _tiles.add(insertionIndex.coerceIn(0, _tiles.size), cell) } else { } else { // Add the tile with a temporary row which will get reassigned when // Add the tile with a temporary row/col which will get reassigned when // regenerating spacers // regenerating spacers _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0)) _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0, 0)) } } regenerateGrid() regenerateGrid() Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt +10 −0 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,8 @@ import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.util.fastMap import androidx.compose.ui.util.fastMap Loading @@ -29,6 +31,7 @@ import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.grid.ui.compose.VerticalSpannedGrid import com.android.systemui.grid.ui.compose.VerticalSpannedGrid import com.android.systemui.qs.composefragment.ui.GridAnchor import com.android.systemui.qs.composefragment.ui.GridAnchor import com.android.systemui.qs.panels.ui.compose.infinitegrid.Tile import com.android.systemui.qs.panels.ui.compose.infinitegrid.Tile import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel import com.android.systemui.qs.shared.ui.ElementKeys.toElementKey import com.android.systemui.qs.shared.ui.ElementKeys.toElementKey import com.android.systemui.res.R import com.android.systemui.res.R Loading @@ -41,7 +44,9 @@ fun SceneScope.QuickQuickSettings( val sizedTiles by val sizedTiles by viewModel.tileViewModels.collectAsStateWithLifecycle(initialValue = emptyList()) viewModel.tileViewModels.collectAsStateWithLifecycle(initialValue = emptyList()) val tiles = sizedTiles.fastMap { it.tile } val tiles = sizedTiles.fastMap { it.tile } val bounceables = remember(sizedTiles) { List(sizedTiles.size) { BounceableTileViewModel() } } val squishiness by viewModel.squishinessViewModel.squishiness.collectAsStateWithLifecycle() val squishiness by viewModel.squishinessViewModel.squishiness.collectAsStateWithLifecycle() val scope = rememberCoroutineScope() DisposableEffect(tiles) { DisposableEffect(tiles) { val token = Any() val token = Any() Loading @@ -49,6 +54,7 @@ fun SceneScope.QuickQuickSettings( onDispose { tiles.forEach { it.stopListening(token) } } onDispose { tiles.forEach { it.stopListening(token) } } } } val columns by viewModel.columns.collectAsStateWithLifecycle() val columns by viewModel.columns.collectAsStateWithLifecycle() var cellIndex = 0 Box(modifier = modifier) { Box(modifier = modifier) { GridAnchor() GridAnchor() VerticalSpannedGrid( VerticalSpannedGrid( Loading @@ -59,11 +65,15 @@ fun SceneScope.QuickQuickSettings( modifier = Modifier.sysuiResTag("qqs_tile_layout"), modifier = Modifier.sysuiResTag("qqs_tile_layout"), ) { spanIndex -> ) { spanIndex -> val it = sizedTiles[spanIndex] val it = sizedTiles[spanIndex] val column = cellIndex % columns cellIndex += it.width Tile( Tile( tile = it.tile, tile = it.tile, iconOnly = it.isIcon, iconOnly = it.isIcon, modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)), modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)), squishiness = { squishiness }, squishiness = { squishiness }, coroutineScope = scope, bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns), ) ) } } } } Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt +12 −7 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect Loading @@ -54,6 +55,7 @@ import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.semantics.toggleableState import androidx.compose.ui.semantics.toggleableState import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp import com.android.compose.modifiers.background import com.android.compose.modifiers.background import com.android.compose.modifiers.thenIf import com.android.compose.modifiers.thenIf Loading @@ -64,7 +66,6 @@ import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState import com.android.systemui.res.R import com.android.systemui.res.R import kotlinx.coroutines.delay private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target" private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target" Loading Loading @@ -138,13 +139,20 @@ fun LargeTileLabels( accessibilityUiState: AccessibilityUiState? = null, accessibilityUiState: AccessibilityUiState? = null, ) { ) { Column(verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxHeight()) { Column(verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxHeight()) { Text(label, color = colors.label, modifier = Modifier.tileMarquee()) Text( label, style = MaterialTheme.typography.labelLarge, color = colors.label, maxLines = 1, overflow = TextOverflow.Ellipsis, ) if (!TextUtils.isEmpty(secondaryLabel)) { if (!TextUtils.isEmpty(secondaryLabel)) { Text( Text( secondaryLabel ?: "", secondaryLabel ?: "", color = colors.secondaryLabel, color = colors.secondaryLabel, style = MaterialTheme.typography.bodyMedium, modifier = modifier = Modifier.tileMarquee().thenIf( Modifier.thenIf( accessibilityUiState?.stateDescription?.contains(secondaryLabel ?: "") == accessibilityUiState?.stateDescription?.contains(secondaryLabel ?: "") == true true ) { ) { Loading Loading @@ -182,10 +190,7 @@ fun SmallTileContent( rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = true) rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = true) } else { } else { var atEnd by remember(icon.res) { mutableStateOf(false) } var atEnd by remember(icon.res) { mutableStateOf(false) } LaunchedEffect(key1 = icon.res) { LaunchedEffect(key1 = icon.res) { atEnd = true } delay(350) atEnd = true } rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = atEnd) rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = atEnd) } } } } Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt +123 −229 File changed.Preview size limit exceeded, changes collapsed. Show changes