[Spa] New SuwScaffold

A scaffold with Setup Wizard style.

Fix: 315274217
Test: manual - with Gallery
Test: unit test
Change-Id: I6198bfaa17a9357243079b3a6911d9e1cbc6cb48
diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts
index acd90f3..7eccfe5 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -57,7 +57,7 @@
     api("androidx.slice:slice-builders:1.1.0-alpha02")
     api("androidx.slice:slice-core:1.1.0-alpha02")
     api("androidx.slice:slice-view:1.1.0-alpha02")
-    api("androidx.compose.material3:material3:1.2.0-alpha11")
+    api("androidx.compose.material3:material3:1.2.0-alpha12")
     api("androidx.compose.material:material-icons-extended:$jetpackComposeVersion")
     api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion")
     api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion")
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
index 5a1120e..c143390 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
@@ -37,11 +37,13 @@
     val itemPaddingAround = 8.dp
     val itemDividerHeight = 32.dp
 
+    val iconLarge = 48.dp
+
     /** The size when app icon is displayed in list. */
     val appIconItemSize = 32.dp
 
     /** The size when app icon is displayed in App info page. */
-    val appIconInfoSize = 48.dp
+    val appIconInfoSize = iconLarge
 
     /** The vertical padding for buttons. */
     val buttonPaddingVertical = 12.dp
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SuwScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SuwScaffold.kt
new file mode 100644
index 0000000..354b95d
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SuwScaffold.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2023 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.settingslib.spa.widget.scaffold
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxWithConstraints
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.Button
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.toMediumWeight
+
+data class BottomAppBarButton(
+    val text: String,
+    val onClick: () -> Unit,
+)
+
+@Composable
+fun SuwScaffold(
+    imageVector: ImageVector,
+    title: String,
+    actionButton: BottomAppBarButton? = null,
+    dismissButton: BottomAppBarButton? = null,
+    content: @Composable ColumnScope.() -> Unit,
+) {
+    ActivityTitle(title)
+    Scaffold { innerPadding ->
+        BoxWithConstraints(
+            Modifier
+                .padding(innerPadding)
+                .padding(top = SettingsDimension.itemPaddingAround)
+        ) {
+            // Use single column layout in portrait, two columns in landscape.
+            val useSingleColumn = maxWidth < maxHeight
+            if (useSingleColumn) {
+                Column {
+                    Column(
+                        Modifier
+                            .weight(1f)
+                            .verticalScroll(rememberScrollState())
+                    ) {
+                        Header(imageVector, title)
+                        content()
+                    }
+                    BottomBar(actionButton, dismissButton)
+                }
+            } else {
+                Column(Modifier.padding(horizontal = SettingsDimension.itemPaddingAround)) {
+                    Row((Modifier.weight(1f))) {
+                        Box(Modifier.weight(1f)) {
+                            Header(imageVector, title)
+                        }
+                        Column(
+                            Modifier
+                                .weight(1f)
+                                .verticalScroll(rememberScrollState())) {
+                            content()
+                        }
+                    }
+                    BottomBar(actionButton, dismissButton)
+                }
+            }
+        }
+    }
+}
+
+@Composable
+private fun Header(
+    imageVector: ImageVector,
+    title: String
+) {
+    Column(Modifier.padding(SettingsDimension.itemPadding)) {
+        Icon(
+            imageVector = imageVector,
+            contentDescription = null,
+            modifier = Modifier
+                .padding(vertical = SettingsDimension.itemPaddingAround)
+                .size(SettingsDimension.iconLarge),
+            tint = MaterialTheme.colorScheme.primary,
+        )
+        Text(
+            text = title,
+            modifier = Modifier.padding(vertical = SettingsDimension.itemPaddingVertical),
+            color = MaterialTheme.colorScheme.onSurface,
+            style = MaterialTheme.typography.displaySmall,
+        )
+    }
+}
+
+@Composable
+private fun BottomBar(
+    actionButton: BottomAppBarButton?,
+    dismissButton: BottomAppBarButton?,
+) {
+    Row(modifier = Modifier.padding(SettingsDimension.itemPaddingAround)) {
+        dismissButton?.apply {
+            TextButton(onClick) {
+                ActionText(text)
+            }
+        }
+        Spacer(modifier = Modifier.weight(1f))
+        actionButton?.apply {
+            Button(onClick) {
+                ActionText(text)
+            }
+        }
+    }
+}
+
+@Composable
+private fun ActionText(text: String) {
+    Text(
+        text = text,
+        style = MaterialTheme.typography.bodyMedium.toMediumWeight(),
+    )
+}