diff options
| author | 2024-05-28 15:05:14 +0000 | |
|---|---|---|
| committer | 2024-05-28 15:05:14 +0000 | |
| commit | dcb0555ffb778ecce9bfac4aaeb7bbfde1e7bec5 (patch) | |
| tree | e5345bab58cf0cbb6cb5a28bf5e08633568b3daf | |
| parent | 139f2e7759e02c94781b52c2705178841a7b7bf3 (diff) | |
| parent | 404e8d4f5cbabc4e62760766c4c5d9d4ab2f76ce (diff) | |
Merge "Add optional labels to icon tiles." into main
20 files changed, 581 insertions, 55 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt index d161c6b834c0..7b679932de3e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt @@ -28,6 +28,7 @@ import com.android.systemui.qs.panels.domain.interactor.InfiniteGridConsistencyI import com.android.systemui.qs.panels.domain.interactor.NoopGridConsistencyInteractor import com.android.systemui.qs.panels.shared.model.GridConsistencyLog import com.android.systemui.qs.panels.shared.model.GridLayoutType +import com.android.systemui.qs.panels.shared.model.IconLabelVisibilityLog import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType import com.android.systemui.qs.panels.shared.model.PartitionedGridLayoutType import com.android.systemui.qs.panels.shared.model.StretchedGridLayoutType @@ -35,6 +36,12 @@ import com.android.systemui.qs.panels.ui.compose.GridLayout import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout import com.android.systemui.qs.panels.ui.compose.PartitionedGridLayout import com.android.systemui.qs.panels.ui.compose.StretchedGridLayout +import com.android.systemui.qs.panels.ui.viewmodel.IconLabelVisibilityViewModel +import com.android.systemui.qs.panels.ui.viewmodel.IconLabelVisibilityViewModelImpl +import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModel +import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModelImpl +import com.android.systemui.qs.panels.ui.viewmodel.InfiniteGridSizeViewModel +import com.android.systemui.qs.panels.ui.viewmodel.InfiniteGridSizeViewModelImpl import dagger.Binds import dagger.Module import dagger.Provides @@ -53,6 +60,15 @@ interface PanelsModule { impl: NoopGridConsistencyInteractor ): GridTypeConsistencyInteractor + @Binds fun bindIconTilesViewModel(impl: IconTilesViewModelImpl): IconTilesViewModel + + @Binds fun bindGridSizeViewModel(impl: InfiniteGridSizeViewModelImpl): InfiniteGridSizeViewModel + + @Binds + fun bindIconLabelVisibilityViewModel( + impl: IconLabelVisibilityViewModelImpl + ): IconLabelVisibilityViewModel + @Binds @Named("Default") fun bindDefaultGridLayout(impl: PartitionedGridLayout): GridLayout companion object { @@ -64,6 +80,13 @@ interface PanelsModule { } @Provides + @SysUISingleton + @IconLabelVisibilityLog + fun providesIconTileLabelVisibilityLog(factory: LogBufferFactory): LogBuffer { + return factory.create("IconLabelVisibilityLog", 50) + } + + @Provides @IntoSet fun provideGridLayout(gridLayout: InfiniteGridLayout): Pair<GridLayoutType, GridLayout> { return Pair(InfiniteGridLayoutType, gridLayout) diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepository.kt new file mode 100644 index 000000000000..686e5f49442b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepository.kt @@ -0,0 +1,35 @@ +/* + * 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.data.repository + +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +/** Repository for whether to show the labels of icon tiles. */ +@SysUISingleton +class IconLabelVisibilityRepository @Inject constructor() { + // TODO(b/341735914): Persist and back up showLabels + private val _showLabels = MutableStateFlow(false) + val showLabels: StateFlow<Boolean> = _showLabels.asStateFlow() + + fun setShowLabels(showLabels: Boolean) { + _showLabels.value = showLabels + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt new file mode 100644 index 000000000000..a871531f283a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt @@ -0,0 +1,61 @@ +/* + * 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.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.LogLevel +import com.android.systemui.qs.panels.data.repository.IconLabelVisibilityRepository +import com.android.systemui.qs.panels.shared.model.IconLabelVisibilityLog +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.stateIn + +@SysUISingleton +class IconLabelVisibilityInteractor +@Inject +constructor( + private val repo: IconLabelVisibilityRepository, + @IconLabelVisibilityLog private val logBuffer: LogBuffer, + @Application scope: CoroutineScope, +) { + val showLabels: StateFlow<Boolean> = + repo.showLabels + .onEach { logChange(it) } + .stateIn(scope, SharingStarted.WhileSubscribed(), repo.showLabels.value) + + fun setShowLabels(showLabels: Boolean) { + repo.setShowLabels(showLabels) + } + + private fun logChange(showLabels: Boolean) { + logBuffer.log( + LOG_BUFFER_ICON_TILE_LABEL_VISIBILITY_CHANGE_TAG, + LogLevel.DEBUG, + { bool1 = showLabels }, + { "Icon tile label visibility changed: $bool1" } + ) + } + + private companion object { + const val LOG_BUFFER_ICON_TILE_LABEL_VISIBILITY_CHANGE_TAG = "IconLabelVisibilityChange" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/IconLabelVisibilityLog.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/IconLabelVisibilityLog.kt new file mode 100644 index 000000000000..c92234c3e535 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/IconLabelVisibilityLog.kt @@ -0,0 +1,24 @@ +/* + * 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.shared.model + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class IconLabelVisibilityLog() diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt index f5ee720faff6..4aeaa7d23771 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt @@ -26,9 +26,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.qs.panels.domain.interactor.IconTilesInteractor -import com.android.systemui.qs.panels.domain.interactor.InfiniteGridSizeInteractor import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel +import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModel +import com.android.systemui.qs.panels.ui.viewmodel.InfiniteGridSizeViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.res.R @@ -38,8 +38,8 @@ import javax.inject.Inject class InfiniteGridLayout @Inject constructor( - private val iconTilesInteractor: IconTilesInteractor, - private val gridSizeInteractor: InfiniteGridSizeInteractor + private val iconTilesViewModel: IconTilesViewModel, + private val gridSizeViewModel: InfiniteGridSizeViewModel, ) : GridLayout { @Composable @@ -52,8 +52,8 @@ constructor( tiles.forEach { it.startListening(token) } onDispose { tiles.forEach { it.stopListening(token) } } } - val iconTilesSpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle() - val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle() + val iconTilesSpecs by iconTilesViewModel.iconTilesSpecs.collectAsStateWithLifecycle() + val columns by gridSizeViewModel.columns.collectAsStateWithLifecycle() TileLazyGrid(modifier = modifier, columns = GridCells.Fixed(columns)) { items( @@ -68,9 +68,9 @@ constructor( } ) { index -> Tile( - tiles[index], - iconTilesSpecs.contains(tiles[index].spec), - Modifier.height(dimensionResource(id = R.dimen.qs_tile_height)) + tile = tiles[index], + iconOnly = iconTilesSpecs.contains(tiles[index].spec), + modifier = Modifier.height(dimensionResource(id = R.dimen.qs_tile_height)) ) } } @@ -83,8 +83,8 @@ constructor( onAddTile: (TileSpec, Int) -> Unit, onRemoveTile: (TileSpec) -> Unit, ) { - val iconOnlySpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle() - val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle() + val iconOnlySpecs by iconTilesViewModel.iconTilesSpecs.collectAsStateWithLifecycle() + val columns by gridSizeViewModel.columns.collectAsStateWithLifecycle() DefaultEditTileGrid( tiles = tiles, diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt index 8d0b386bd817..708ef0dd7ff6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt @@ -20,6 +20,7 @@ import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -32,6 +33,8 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Switch +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue @@ -39,14 +42,14 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.modifiers.background import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.qs.panels.domain.interactor.IconTilesInteractor -import com.android.systemui.qs.panels.domain.interactor.InfiniteGridSizeInteractor import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel +import com.android.systemui.qs.panels.ui.viewmodel.PartitionedGridViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor import com.android.systemui.qs.pipeline.shared.TileSpec @@ -54,12 +57,8 @@ import com.android.systemui.res.R import javax.inject.Inject @SysUISingleton -class PartitionedGridLayout -@Inject -constructor( - private val iconTilesInteractor: IconTilesInteractor, - private val gridSizeInteractor: InfiniteGridSizeInteractor, -) : GridLayout { +class PartitionedGridLayout @Inject constructor(private val viewModel: PartitionedGridViewModel) : + GridLayout { @Composable override fun TileGrid(tiles: List<TileViewModel>, modifier: Modifier) { DisposableEffect(tiles) { @@ -67,9 +66,11 @@ constructor( tiles.forEach { it.startListening(token) } onDispose { tiles.forEach { it.stopListening(token) } } } - val iconTilesSpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle() - val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle() - val tileHeight = dimensionResource(id = R.dimen.qs_tile_height) + val iconTilesSpecs by viewModel.iconTilesSpecs.collectAsStateWithLifecycle() + val columns by viewModel.columns.collectAsStateWithLifecycle() + val showLabels by viewModel.showLabels.collectAsStateWithLifecycle() + val largeTileHeight = tileHeight() + val iconTileHeight = tileHeight(showLabels) val (smallTiles, largeTiles) = tiles.partition { iconTilesSpecs.contains(it.spec) } TileLazyGrid(modifier = modifier, columns = GridCells.Fixed(columns)) { @@ -78,7 +79,7 @@ constructor( Tile( tile = largeTiles[index], iconOnly = false, - modifier = Modifier.height(tileHeight) + modifier = Modifier.height(largeTileHeight) ) } fillUpRow(nTiles = largeTiles.size, columns = columns / 2) @@ -88,7 +89,8 @@ constructor( Tile( tile = smallTiles[index], iconOnly = true, - modifier = Modifier.height(tileHeight) + showLabels = showLabels, + modifier = Modifier.height(iconTileHeight) ) } } @@ -101,8 +103,9 @@ constructor( onAddTile: (TileSpec, Int) -> Unit, onRemoveTile: (TileSpec) -> Unit ) { - val iconOnlySpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle() - val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle() + val iconOnlySpecs by viewModel.iconTilesSpecs.collectAsStateWithLifecycle() + val columns by viewModel.columns.collectAsStateWithLifecycle() + val showLabels by viewModel.showLabels.collectAsStateWithLifecycle() val (currentTiles, otherTiles) = tiles.partition { it.isCurrent } val addTileToEnd: (TileSpec) -> Unit by rememberUpdatedState { @@ -110,27 +113,56 @@ constructor( } val isIconOnly: (TileSpec) -> Boolean = remember(iconOnlySpecs) { { tileSpec: TileSpec -> tileSpec in iconOnlySpecs } } - val tileHeight = dimensionResource(id = R.dimen.qs_tile_height) + val largeTileHeight = tileHeight() + val iconTileHeight = tileHeight(showLabels) val tilePadding = dimensionResource(R.dimen.qs_tile_margin_vertical) Column( verticalArrangement = Arrangement.spacedBy(tilePadding), modifier = modifier.fillMaxSize().verticalScroll(rememberScrollState()) ) { + Row( + modifier = + Modifier.background( + color = MaterialTheme.colorScheme.surfaceVariant, + alpha = { 1f }, + shape = RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius)) + ) + .padding(tilePadding) + ) { + Column(Modifier.padding(start = tilePadding)) { + Text( + text = "Show text labels", + color = MaterialTheme.colorScheme.onBackground, + fontWeight = FontWeight.Bold + ) + Text( + text = "Display names under each tile", + color = MaterialTheme.colorScheme.onBackground + ) + } + Spacer(modifier = Modifier.weight(1f)) + Switch(checked = showLabels, onCheckedChange = { viewModel.setShowLabels(it) }) + } + CurrentTiles( tiles = currentTiles, - tileHeight = tileHeight, + largeTileHeight = largeTileHeight, + iconTileHeight = iconTileHeight, tilePadding = tilePadding, onRemoveTile = onRemoveTile, isIconOnly = isIconOnly, columns = columns, + showLabels = showLabels, ) AvailableTiles( tiles = otherTiles, - tileHeight = tileHeight, + largeTileHeight = largeTileHeight, + iconTileHeight = iconTileHeight, tilePadding = tilePadding, addTileToEnd = addTileToEnd, isIconOnly = isIconOnly, + showLabels = showLabels, columns = columns, ) } @@ -139,23 +171,31 @@ constructor( @Composable private fun CurrentTiles( tiles: List<EditTileViewModel>, - tileHeight: Dp, + largeTileHeight: Dp, + iconTileHeight: Dp, tilePadding: Dp, onRemoveTile: (TileSpec) -> Unit, isIconOnly: (TileSpec) -> Boolean, + showLabels: Boolean, columns: Int, ) { val (smallTiles, largeTiles) = tiles.partition { isIconOnly(it.tileSpec) } - val largeGridHeight = gridHeight(largeTiles.size, tileHeight, columns / 2, tilePadding) - val smallGridHeight = gridHeight(smallTiles.size, tileHeight, columns, tilePadding) + val largeGridHeight = gridHeight(largeTiles.size, largeTileHeight, columns / 2, tilePadding) + val smallGridHeight = gridHeight(smallTiles.size, iconTileHeight, columns, tilePadding) CurrentTilesContainer { TileLazyGrid( columns = GridCells.Fixed(columns), modifier = Modifier.height(largeGridHeight), ) { - editTiles(largeTiles, ClickAction.REMOVE, onRemoveTile, { false }, true) + editTiles( + largeTiles, + ClickAction.REMOVE, + onRemoveTile, + { false }, + indicatePosition = true + ) } } CurrentTilesContainer { @@ -163,7 +203,14 @@ constructor( columns = GridCells.Fixed(columns), modifier = Modifier.height(smallGridHeight), ) { - editTiles(smallTiles, ClickAction.REMOVE, onRemoveTile, { true }, true) + editTiles( + smallTiles, + ClickAction.REMOVE, + onRemoveTile, + { true }, + showLabels = showLabels, + indicatePosition = true + ) } } } @@ -171,19 +218,21 @@ constructor( @Composable private fun AvailableTiles( tiles: List<EditTileViewModel>, - tileHeight: Dp, + largeTileHeight: Dp, + iconTileHeight: Dp, tilePadding: Dp, addTileToEnd: (TileSpec) -> Unit, isIconOnly: (TileSpec) -> Boolean, + showLabels: Boolean, columns: Int, ) { val (tilesStock, tilesCustom) = tiles.partition { it.appName == null } val (smallTiles, largeTiles) = tilesStock.partition { isIconOnly(it.tileSpec) } - val largeGridHeight = gridHeight(largeTiles.size, tileHeight, columns / 2, tilePadding) - val smallGridHeight = gridHeight(smallTiles.size, tileHeight, columns, tilePadding) + val largeGridHeight = gridHeight(largeTiles.size, largeTileHeight, columns / 2, tilePadding) + val smallGridHeight = gridHeight(smallTiles.size, iconTileHeight, columns, tilePadding) val largeGridHeightCustom = - gridHeight(tilesCustom.size, tileHeight, columns / 2, tilePadding) + gridHeight(tilesCustom.size, largeTileHeight, columns / 2, tilePadding) // Add up the height of all three grids and add padding in between val gridHeight = @@ -199,7 +248,13 @@ constructor( fillUpRow(nTiles = largeTiles.size, columns = columns / 2) // Small tiles - editTiles(smallTiles, ClickAction.ADD, addTileToEnd, isIconOnly) + editTiles( + smallTiles, + ClickAction.ADD, + addTileToEnd, + isIconOnly, + showLabels = showLabels + ) fillUpRow(nTiles = smallTiles.size, columns = columns) // Custom tiles, all large diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/StretchedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/StretchedGridLayout.kt index ddd97c2e8944..70d629fa7c70 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/StretchedGridLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/StretchedGridLayout.kt @@ -27,11 +27,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.qs.panels.domain.interactor.IconTilesInteractor -import com.android.systemui.qs.panels.domain.interactor.InfiniteGridSizeInteractor import com.android.systemui.qs.panels.shared.model.SizedTile import com.android.systemui.qs.panels.shared.model.TileRow import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel +import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModel +import com.android.systemui.qs.panels.ui.viewmodel.InfiniteGridSizeViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.res.R @@ -41,8 +41,8 @@ import javax.inject.Inject class StretchedGridLayout @Inject constructor( - private val iconTilesInteractor: IconTilesInteractor, - private val gridSizeInteractor: InfiniteGridSizeInteractor, + private val iconTilesViewModel: IconTilesViewModel, + private val gridSizeViewModel: InfiniteGridSizeViewModel, ) : GridLayout { @Composable @@ -60,7 +60,7 @@ constructor( // Icon [3 | 4] // Large [6 | 8] val columns = 12 - val iconTilesSpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle() + val iconTilesSpecs by iconTilesViewModel.iconTilesSpecs.collectAsStateWithLifecycle() val stretchedTiles = remember(tiles) { val sizedTiles = @@ -80,9 +80,9 @@ constructor( TileLazyGrid(columns = GridCells.Fixed(columns), modifier = modifier) { items(stretchedTiles.size, span = { GridItemSpan(stretchedTiles[it].width) }) { index -> Tile( - stretchedTiles[index].tile, - iconTilesSpecs.contains(stretchedTiles[index].tile.spec), - Modifier.height(dimensionResource(id = R.dimen.qs_tile_height)) + tile = stretchedTiles[index].tile, + iconOnly = iconTilesSpecs.contains(stretchedTiles[index].tile.spec), + modifier = Modifier.height(dimensionResource(id = R.dimen.qs_tile_height)) ) } } @@ -95,8 +95,8 @@ constructor( onAddTile: (TileSpec, Int) -> Unit, onRemoveTile: (TileSpec) -> Unit ) { - val iconOnlySpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle() - val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle() + val iconOnlySpecs by iconTilesViewModel.iconTilesSpecs.collectAsStateWithLifecycle() + val columns by gridSizeViewModel.columns.collectAsStateWithLifecycle() DefaultEditTileGrid( tiles = tiles, diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt index e8c65a5ac78a..a6838c0c06a2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt @@ -69,6 +69,9 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.onClick import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.stateDescription +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.Expandable @@ -98,6 +101,7 @@ object TileType fun Tile( tile: TileViewModel, iconOnly: Boolean, + showLabels: Boolean = false, modifier: Modifier, ) { val state: TileUiState by @@ -136,7 +140,8 @@ fun Tile( secondaryLabel = state.secondaryLabel.toString(), icon = icon, colors = state.colors, - iconOnly = iconOnly + iconOnly = iconOnly, + showLabels = showLabels, ) } } @@ -213,6 +218,7 @@ fun LazyGridScope.editTiles( clickAction: ClickAction, onClick: (TileSpec) -> Unit, isIconOnly: (TileSpec) -> Boolean, + showLabels: Boolean = false, indicatePosition: Boolean = false, ) { items( @@ -250,10 +256,13 @@ fun LazyGridScope.editTiles( this.stateDescription = stateDescription } ) { + val iconOnly = isIconOnly(viewModel.tileSpec) + val tileHeight = tileHeight(iconOnly && showLabels) EditTile( tileViewModel = viewModel, - isIconOnly(viewModel.tileSpec), - modifier = Modifier.height(dimensionResource(id = R.dimen.qs_tile_height)) + iconOnly = iconOnly, + showLabels = showLabels, + modifier = Modifier.height(tileHeight) ) if (canClick) { Badge(clickAction, Modifier.align(Alignment.TopEnd)) @@ -281,6 +290,7 @@ fun Badge(action: ClickAction, modifier: Modifier = Modifier) { fun EditTile( tileViewModel: EditTileViewModel, iconOnly: Boolean, + showLabels: Boolean, modifier: Modifier = Modifier, ) { val label = tileViewModel.label.load() ?: tileViewModel.tileSpec.spec @@ -297,6 +307,7 @@ fun EditTile( colors = colors, icon = tileViewModel.icon, iconOnly = iconOnly, + showLabels = showLabels, animateIconToEnd = true, ) } @@ -380,9 +391,26 @@ private fun TileContent( icon: Icon, colors: TileColorAttributes, iconOnly: Boolean, + showLabels: Boolean = false, animateIconToEnd: Boolean = false, ) { - TileIcon(icon, colorAttr(colors.icon), animateIconToEnd) + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier.fillMaxHeight() + ) { + TileIcon(icon, colorAttr(colors.icon), animateIconToEnd) + + if (iconOnly && showLabels) { + Text( + label, + maxLines = 2, + color = colorAttr(colors.label), + overflow = TextOverflow.Ellipsis, + textAlign = TextAlign.Center, + ) + } + } if (!iconOnly) { Column(verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight()) { @@ -401,3 +429,16 @@ private fun TileContent( } } } + +@Composable +fun tileHeight(iconWithLabel: Boolean = false): Dp { + return if (iconWithLabel) { + TileDimensions.IconTileWithLabelHeight + } else { + dimensionResource(id = R.dimen.qs_tile_height) + } +} + +private object TileDimensions { + val IconTileWithLabelHeight = 100.dp +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModel.kt new file mode 100644 index 000000000000..5d4b8f1773f2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModel.kt @@ -0,0 +1,39 @@ +/* + * 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.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.panels.domain.interactor.IconLabelVisibilityInteractor +import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow + +interface IconLabelVisibilityViewModel { + val showLabels: StateFlow<Boolean> + + fun setShowLabels(showLabels: Boolean) +} + +@SysUISingleton +class IconLabelVisibilityViewModelImpl +@Inject +constructor(private val interactor: IconLabelVisibilityInteractor) : IconLabelVisibilityViewModel { + override val showLabels: StateFlow<Boolean> = interactor.showLabels + + override fun setShowLabels(showLabels: Boolean) { + interactor.setShowLabels(showLabels) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt new file mode 100644 index 000000000000..9ad00c8d3cfa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt @@ -0,0 +1,33 @@ +/* + * 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.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.panels.domain.interactor.IconTilesInteractor +import com.android.systemui.qs.pipeline.shared.TileSpec +import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow + +interface IconTilesViewModel { + val iconTilesSpecs: StateFlow<Set<TileSpec>> +} + +@SysUISingleton +class IconTilesViewModelImpl @Inject constructor(interactor: IconTilesInteractor) : + IconTilesViewModel { + override val iconTilesSpecs = interactor.iconTilesSpecs +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/InfiniteGridSizeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/InfiniteGridSizeViewModel.kt new file mode 100644 index 000000000000..a4ee58f0963c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/InfiniteGridSizeViewModel.kt @@ -0,0 +1,32 @@ +/* + * 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.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.panels.domain.interactor.InfiniteGridSizeInteractor +import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow + +interface InfiniteGridSizeViewModel { + val columns: StateFlow<Int> +} + +@SysUISingleton +class InfiniteGridSizeViewModelImpl @Inject constructor(interactor: InfiniteGridSizeInteractor) : + InfiniteGridSizeViewModel { + override val columns: StateFlow<Int> = interactor.columns +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModel.kt new file mode 100644 index 000000000000..730cf635972d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModel.kt @@ -0,0 +1,32 @@ +/* + * 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.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +@SysUISingleton +class PartitionedGridViewModel +@Inject +constructor( + iconTilesViewModel: IconTilesViewModel, + gridSizeViewModel: InfiniteGridSizeViewModel, + iconLabelVisibilityViewModel: IconLabelVisibilityViewModel, +) : + IconTilesViewModel by iconTilesViewModel, + InfiniteGridSizeViewModel by gridSizeViewModel, + IconLabelVisibilityViewModel by iconLabelVisibilityViewModel diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt new file mode 100644 index 000000000000..277dbb7016ad --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt @@ -0,0 +1,21 @@ +/* + * 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.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.iconLabelVisibilityRepository by Kosmos.Fixture { IconLabelVisibilityRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorKosmos.kt new file mode 100644 index 000000000000..7b9e4a17e998 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorKosmos.kt @@ -0,0 +1,31 @@ +/* + * 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.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.log.core.FakeLogBuffer +import com.android.systemui.qs.panels.data.repository.iconLabelVisibilityRepository + +val Kosmos.iconLabelVisibilityInteractor by + Kosmos.Fixture { + IconLabelVisibilityInteractor( + iconLabelVisibilityRepository, + FakeLogBuffer.Factory.create(), + applicationCoroutineScope + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt index 34b266a54f41..82cfaf50f823 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt @@ -18,6 +18,8 @@ package com.android.systemui.qs.panels.domain.interactor import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout +import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel +import com.android.systemui.qs.panels.ui.viewmodel.infiniteGridSizeViewModel val Kosmos.infiniteGridLayout by - Kosmos.Fixture { InfiniteGridLayout(iconTilesInteractor, infiniteGridSizeInteractor) } + Kosmos.Fixture { InfiniteGridLayout(iconTilesViewModel, infiniteGridSizeViewModel) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/PartitionedGridLayoutKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/PartitionedGridLayoutKosmos.kt index 4febfe9160ab..37c9552ded44 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/PartitionedGridLayoutKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/PartitionedGridLayoutKosmos.kt @@ -18,6 +18,7 @@ package com.android.systemui.qs.panels.domain.interactor import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.panels.ui.compose.PartitionedGridLayout +import com.android.systemui.qs.panels.ui.viewmodel.partitionedGridViewModel val Kosmos.partitionedGridLayout by - Kosmos.Fixture { PartitionedGridLayout(iconTilesInteractor, infiniteGridSizeInteractor) } + Kosmos.Fixture { PartitionedGridLayout(partitionedGridViewModel) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModelKosmos.kt new file mode 100644 index 000000000000..daf6087c2d6f --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModelKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.viewmodel + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.panels.domain.interactor.iconLabelVisibilityInteractor + +val Kosmos.iconLabelVisibilityViewModel by + Kosmos.Fixture { IconLabelVisibilityViewModelImpl(iconLabelVisibilityInteractor) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModelKosmos.kt new file mode 100644 index 000000000000..89b42a69c326 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModelKosmos.kt @@ -0,0 +1,22 @@ +/* + * 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.viewmodel + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.panels.domain.interactor.iconTilesInteractor + +val Kosmos.iconTilesViewModel by Kosmos.Fixture { IconTilesViewModelImpl(iconTilesInteractor) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/InfiniteGridSizeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/InfiniteGridSizeViewModelKosmos.kt new file mode 100644 index 000000000000..f6dfb8bcd47b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/InfiniteGridSizeViewModelKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.viewmodel + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.panels.domain.interactor.infiniteGridSizeInteractor + +val Kosmos.infiniteGridSizeViewModel by + Kosmos.Fixture { InfiniteGridSizeViewModelImpl(infiniteGridSizeInteractor) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt new file mode 100644 index 000000000000..b07cc7d8612d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt @@ -0,0 +1,28 @@ +/* + * 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.viewmodel + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.partitionedGridViewModel by + Kosmos.Fixture { + PartitionedGridViewModel( + iconTilesViewModel, + infiniteGridSizeViewModel, + iconLabelVisibilityViewModel, + ) + } |