Add paging to modes dialog

Bug: 376450983
Test: manually scroll through pages and see that things look good
Flag: com.android.systemui.modes_ui_dialog_paging

Change-Id: I475e50e15725c844975768c0f041663948f7bc4f
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 2278789..a52e8a0 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -26,6 +26,13 @@
 }
 
 flag {
+   name: "modes_ui_dialog_paging"
+   namespace: "systemui"
+   description: "Add pagination to the Modes dialog in quick settings."
+   bug: "376450983"
+}
+
+flag {
    name: "priority_people_section"
    namespace: "systemui"
    description: "Add a new section for priority people (aka important conversations)."
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
index 76389f3..b033b36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
@@ -46,7 +46,7 @@
 import com.android.systemui.statusbar.policy.ui.dialog.viewmodel.ModeTileViewModel
 
 @Composable
-fun ModeTile(viewModel: ModeTileViewModel) {
+fun ModeTile(viewModel: ModeTileViewModel, modifier: Modifier = Modifier) {
     val tileColor: Color by
         animateColorAsState(
             if (viewModel.enabled) MaterialTheme.colorScheme.primary
@@ -59,7 +59,7 @@
         )
 
     CompositionLocalProvider(LocalContentColor provides contentColor) {
-        Surface(color = tileColor, shape = RoundedCornerShape(16.dp)) {
+        Surface(color = tileColor, shape = RoundedCornerShape(16.dp), modifier = modifier) {
             Row(
                 modifier =
                     Modifier.combinedClickable(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
index 903c7e1..16f24f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
@@ -17,29 +17,74 @@
 package com.android.systemui.statusbar.policy.ui.dialog.composable
 
 import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.lazy.grid.GridCells
 import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.rememberPagerState
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.systemui.Flags
+import com.android.systemui.qs.panels.ui.compose.PagerDots
 import com.android.systemui.statusbar.policy.ui.dialog.viewmodel.ModesDialogViewModel
 
 @Composable
 fun ModeTileGrid(viewModel: ModesDialogViewModel) {
     val tiles by viewModel.tiles.collectAsStateWithLifecycle(initialValue = emptyList())
 
-    LazyVerticalGrid(
-        columns = GridCells.Fixed(1),
-        modifier = Modifier.fillMaxWidth().heightIn(max = 280.dp),
-        verticalArrangement = Arrangement.spacedBy(8.dp),
-        horizontalArrangement = Arrangement.spacedBy(8.dp),
-    ) {
-        items(tiles.size, key = { index -> tiles[index].id }) { index ->
-            ModeTile(viewModel = tiles[index])
+    if (Flags.modesUiDialogPaging()) {
+        val tilesPerPage = 3
+        val totalPages = { (tiles.size + tilesPerPage - 1) / tilesPerPage }
+        val pagerState = rememberPagerState(initialPage = 0, pageCount = totalPages)
+
+        Column {
+            HorizontalPager(
+                state = pagerState,
+                modifier = Modifier.fillMaxWidth(),
+                pageSpacing = 16.dp,
+                verticalAlignment = Alignment.Top,
+                // Pre-emptively layout and compose the next page, to make sure the height stays
+                // the same even if we have fewer than [tilesPerPage] tiles on the last page.
+                beyondViewportPageCount = 1,
+            ) { page ->
+                Column(
+                    modifier = Modifier.fillMaxWidth().fillMaxHeight(),
+                    verticalArrangement = Arrangement.spacedBy(8.dp, alignment = Alignment.Top),
+                ) {
+                    val startIndex = page * tilesPerPage
+                    val endIndex = minOf((page + 1) * tilesPerPage, tiles.size)
+                    for (index in startIndex until endIndex) {
+                        ModeTile(viewModel = tiles[index], modifier = Modifier.fillMaxWidth())
+                    }
+                }
+            }
+
+            PagerDots(
+                pagerState = pagerState,
+                activeColor = MaterialTheme.colorScheme.primary,
+                nonActiveColor = MaterialTheme.colorScheme.onSurfaceVariant,
+                modifier = Modifier.align(Alignment.CenterHorizontally).padding(top = 8.dp),
+            )
+        }
+    } else {
+        LazyVerticalGrid(
+            columns = GridCells.Fixed(1),
+            modifier = Modifier.fillMaxWidth().heightIn(max = 280.dp),
+            verticalArrangement = Arrangement.spacedBy(8.dp),
+            horizontalArrangement = Arrangement.spacedBy(8.dp),
+        ) {
+            items(tiles.size, key = { index -> tiles[index].id }) { index ->
+                ModeTile(viewModel = tiles[index])
+            }
         }
     }
 }