From 54038d8a83555905b595c869d23ce7886493b950 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Mon, 19 Sep 2022 13:41:48 +0800 Subject: [PATCH] Create Category & CategoryTitle for SpaLib Bug: 244122804 Test: Manual with Gallery App Change-Id: I8b22de50f8b1bb064963fea1271ff7494d0df0f9 --- .../settingslib/spa/gallery/SpaEnvironment.kt | 2 + .../settingslib/spa/gallery/home/HomePage.kt | 2 + .../spa/gallery/ui/CategoryPage.kt | 96 +++++++++++++++++++ .../settingslib/spa/widget/ui/Category.kt | 78 +++++++++++++++ .../settingslib/spa/widget/ui/CategoryTest.kt | 70 ++++++++++++++ 5 files changed, 248 insertions(+) create mode 100644 packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt create mode 100644 packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt create mode 100644 packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt index 787d0961fb21e..e5d009930edf0 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt @@ -30,6 +30,7 @@ import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider import com.android.settingslib.spa.gallery.preference.PreferencePageProvider import com.android.settingslib.spa.gallery.preference.SwitchPreferencePageProvider import com.android.settingslib.spa.gallery.preference.TwoTargetSwitchPreferencePageProvider +import com.android.settingslib.spa.gallery.ui.CategoryPageProvider import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider object SpaEnvironment { @@ -49,6 +50,7 @@ object SpaEnvironment { SettingsPagerPageProvider, FooterPageProvider, IllustrationPageProvider, + CategoryPageProvider, ), rootPages = listOf( SettingsPage.create(HomePageProvider.name) diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt index d8ef937b50c2e..f840a37fa81b3 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt @@ -32,6 +32,7 @@ import com.android.settingslib.spa.gallery.page.IllustrationPageProvider import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider import com.android.settingslib.spa.gallery.page.SliderPageProvider import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider +import com.android.settingslib.spa.gallery.ui.CategoryPageProvider import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider import com.android.settingslib.spa.widget.scaffold.HomeScaffold @@ -48,6 +49,7 @@ object HomePageProvider : SettingsPageProvider { SettingsPagerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), FooterPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), IllustrationPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), + CategoryPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), ) } diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt new file mode 100644 index 0000000000000..9a525bf5426de --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 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.gallery.ui + +import android.os.Bundle +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.common.SettingsEntryBuilder +import com.android.settingslib.spa.framework.common.SettingsPage +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.framework.compose.stateOf +import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.scaffold.RegularScaffold +import com.android.settingslib.spa.widget.ui.Category +import com.android.settingslib.spa.widget.ui.CategoryTitle + +private const val TITLE = "Sample Category" + +object CategoryPageProvider : SettingsPageProvider { + override val name = "Spinner" + + fun buildInjectEntry(): SettingsEntryBuilder { + return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name)) + .setIsAllowSearch(true) + .setUiLayoutFn { + Preference(object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + }) + } + } + + @Composable + override fun Page(arguments: Bundle?) { + CategoryPage() + } +} + +@Composable +private fun CategoryPage() { + RegularScaffold(title = TITLE) { + CategoryTitle("Category A") + Preference(remember { + object : PreferenceModel { + override val title = "Preference 1" + override val summary = stateOf("Summary 1") + } + }) + Preference(remember { + object : PreferenceModel { + override val title = "Preference 2" + override val summary = stateOf("Summary 2") + } + }) + Category("Category B") { + Preference(remember { + object : PreferenceModel { + override val title = "Preference 3" + override val summary = stateOf("Summary 3") + } + }) + Preference(remember { + object : PreferenceModel { + override val title = "Preference 4" + override val summary = stateOf("Summary 4") + } + }) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun SpinnerPagePreview() { + SettingsTheme { + SpinnerPageProvider.Page(null) + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt new file mode 100644 index 0000000000000..6aac5bf3839ad --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2022 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.ui + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.framework.theme.SettingsTheme + +/** + * A category title that is placed before a group of similar items. + */ +@Composable +fun CategoryTitle(title: String) { + Text( + text = title, + modifier = Modifier.padding( + start = SettingsDimension.itemPaddingStart, + top = 20.dp, + end = SettingsDimension.itemPaddingEnd, + bottom = 8.dp, + ), + color = SettingsTheme.colorScheme.categoryTitle, + style = MaterialTheme.typography.labelMedium, + ) +} + +/** + * A container that is used to group similar items. A [Category] displays a [CategoryTitle] and + * visually separates groups of items. + */ +@Composable +fun Category(title: String, content: @Composable ColumnScope.() -> Unit) { + Column { + var displayTitle by remember { mutableStateOf(false) } + if (displayTitle) CategoryTitle(title = title) + Column( + modifier = Modifier.onGloballyPositioned { coordinates -> + displayTitle = coordinates.size.height > 0 + }, + content = content, + ) + } +} + +@Preview +@Composable +private fun CategoryPreview() { + SettingsTheme { + CategoryTitle("Appearance") + } +} diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt new file mode 100644 index 0000000000000..16e09ee854d80 --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2022 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.ui + +import androidx.compose.runtime.remember +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settingslib.spa.framework.compose.stateOf +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class CategoryTest { + + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun categoryTitle() { + composeTestRule.setContent { + CategoryTitle(title = "CategoryTitle") + } + + composeTestRule.onNodeWithText("CategoryTitle").assertIsDisplayed() + } + + @Test + fun category_hasContent_titleDisplayed() { + composeTestRule.setContent { + Category(title = "CategoryTitle") { + Preference(remember { + object : PreferenceModel { + override val title = "Some Preference" + override val summary = stateOf("Some summary") + } + }) + } + } + + composeTestRule.onNodeWithText("CategoryTitle").assertIsDisplayed() + } + + @Test + fun category_noContent_titleNotDisplayed() { + composeTestRule.setContent { + Category(title = "CategoryTitle") {} + } + + composeTestRule.onNodeWithText("CategoryTitle").assertDoesNotExist() + } +}