xref: /aosp_15_r20/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.qs.panels.ui.model
18 
19 import androidx.compose.foundation.lazy.grid.GridItemSpan
20 import androidx.compose.runtime.Immutable
21 import com.android.systemui.qs.panels.shared.model.SizedTile
22 import com.android.systemui.qs.panels.shared.model.splitInRowsSequence
23 import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
24 import com.android.systemui.qs.shared.model.CategoryAndName
25 
26 /** Represents an item from a grid associated with a row and a span */
27 sealed interface GridCell {
28     val row: Int
29     val span: GridItemSpan
30     val s: String
31 }
32 
33 /**
34  * Represents a [EditTileViewModel] from a grid associated with a tile format and the row and column
35  * it's positioned at
36  */
37 @Immutable
38 data class TileGridCell(
39     override val tile: EditTileViewModel,
40     override val row: Int,
41     override val width: Int,
42     override val span: GridItemSpan = GridItemSpan(width),
43     override val s: String = "${tile.tileSpec.spec}-$row-$width",
44     val column: Int,
45 ) : GridCell, SizedTile<EditTileViewModel>, CategoryAndName by tile {
46     val key: String = "${tile.tileSpec.spec}-$row"
47 
48     constructor(
49         sizedTile: SizedTile<EditTileViewModel>,
50         row: Int,
51         column: Int,
52     ) : this(tile = sizedTile.tile, row = row, column = column, width = sizedTile.width)
53 }
54 
55 /** Represents an empty space used to fill incomplete rows. Will always display as a 1x1 tile */
56 @Immutable
57 data class SpacerGridCell(
58     override val row: Int,
59     override val span: GridItemSpan = GridItemSpan(1),
60     override val s: String = "spacer",
61 ) : GridCell
62 
63 /**
64  * Generates a list of [GridCell] from a list of [SizedTile]
65  *
66  * Builds rows based on the tiles' widths, and fill each hole with a [SpacerGridCell]
67  *
68  * @param startingRow The row index the grid is built from, used in cases where only end rows need
69  *   to be regenerated
70  */
Listnull71 fun List<SizedTile<EditTileViewModel>>.toGridCells(
72     columns: Int,
73     startingRow: Int = 0,
74 ): List<GridCell> {
75     return splitInRowsSequence(this, columns)
76         .flatMapIndexed { rowIndex, sizedTiles ->
77             val correctedRowIndex = rowIndex + startingRow
78             var column = 0
79             val row: List<GridCell> =
80                 sizedTiles.map {
81                     TileGridCell(it, correctedRowIndex, column).also { cell ->
82                         column += cell.width
83                     }
84                 }
85 
86             // Fill the incomplete rows with spacers
87             val numSpacers = columns - sizedTiles.sumOf { it.width }
88             row.toMutableList().apply {
89                 repeat(numSpacers) { add(SpacerGridCell(correctedRowIndex)) }
90             }
91         }
92         .toList()
93 }
94