diff options
| author | 2024-09-18 07:53:38 +0000 | |
|---|---|---|
| committer | 2024-09-20 08:47:43 +0000 | |
| commit | 0832f75f4bef2bde4a3eb5352dde6a62c63ef7a2 (patch) | |
| tree | 704d53fa965fc2ffb843441214f05787946324a7 | |
| parent | 670f987aedf3cbc5cb4c0a074dcfda2ef5b321a0 (diff) | |
[expressive design] Create IntroPreference layout.
Test: visual
Bug: 360916599
Flag: EXEMPT bug fix
Change-Id: I8f912c4aab416666acaf4688c9a7325bd5ebc3cc
6 files changed, 279 insertions, 0 deletions
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt index 83d657ef380d..cff00591bceb 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt @@ -42,6 +42,7 @@ import com.android.settingslib.spa.gallery.page.LoadingBarPageProvider import com.android.settingslib.spa.gallery.page.ProgressBarPageProvider import com.android.settingslib.spa.gallery.scaffold.NonScrollablePagerPageProvider import com.android.settingslib.spa.gallery.page.SliderPageProvider +import com.android.settingslib.spa.gallery.preference.IntroPreferencePageProvider import com.android.settingslib.spa.gallery.preference.ListPreferencePageProvider import com.android.settingslib.spa.gallery.preference.MainSwitchPreferencePageProvider import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider @@ -109,6 +110,7 @@ class GallerySpaEnvironment(context: Context) : SpaEnvironment(context) { SuwScaffoldPageProvider, BannerPageProvider, CopyablePageProvider, + IntroPreferencePageProvider, ), rootPages = listOf( HomePageProvider.createSettingsPage(), diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/IntroPreferencePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/IntroPreferencePageProvider.kt new file mode 100644 index 000000000000..603fceed9900 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/IntroPreferencePageProvider.kt @@ -0,0 +1,78 @@ +/* + * 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.settingslib.spa.gallery.preference + +import android.os.Bundle +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.AirplanemodeActive +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.android.settingslib.spa.framework.common.SettingsEntry +import com.android.settingslib.spa.framework.common.SettingsEntryBuilder +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.widget.preference.IntroPreference +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel + +private const val TITLE = "Sample IntroPreference" + +object IntroPreferencePageProvider : SettingsPageProvider { + override val name = "IntroPreference" + private val owner = createSettingsPage() + + override fun buildEntry(arguments: Bundle?): List<SettingsEntry> { + val entryList = mutableListOf<SettingsEntry>() + entryList.add( + SettingsEntryBuilder.create("IntroPreference", owner) + .setUiLayoutFn { SampleIntroPreference() } + .build() + ) + + return entryList + } + + fun buildInjectEntry(): SettingsEntryBuilder { + return SettingsEntryBuilder.createInject(owner).setUiLayoutFn { + Preference( + object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + } + ) + } + } + + override fun getTitle(arguments: Bundle?): String { + return TITLE + } +} + +@Composable +private fun SampleIntroPreference() { + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + IntroPreference( + title = "Preferred network type", + descriptions = listOf("Description"), + imageVector = Icons.Outlined.AirplanemodeActive, + ) + } +} diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt index ce9678bab684..6d1396748727 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt @@ -39,6 +39,7 @@ object PreferenceMainPageProvider : SettingsPageProvider { ListPreferencePageProvider.buildInjectEntry().setLink(fromPage = owner).build(), TwoTargetSwitchPreferencePageProvider.buildInjectEntry() .setLink(fromPage = owner).build(), + IntroPreferencePageProvider.buildInjectEntry().setLink(fromPage = owner).build(), ) } 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 1f3e24254027..1b4f856e73ff 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 @@ -21,6 +21,7 @@ import androidx.compose.ui.unit.dp object SettingsDimension { val paddingTiny = 2.dp + val paddingExtraSmall = 4.dp val paddingSmall = 4.dp val paddingLarge = 16.dp val paddingExtraLarge = 24.dp @@ -56,6 +57,7 @@ object SettingsDimension { val itemDividerHeight = 32.dp val iconLarge = 48.dp + val introIconSize = 40.dp /** The size when app icon is displayed in list. */ val appIconItemSize = 32.dp diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/IntroPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/IntroPreference.kt new file mode 100644 index 000000000000..22a57554eeaf --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/IntroPreference.kt @@ -0,0 +1,145 @@ +/* + * 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.settingslib.spa.widget.preference + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.AirplanemodeActive +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.theme.SettingsDimension + +@Composable +fun IntroPreference( + title: String, + descriptions: List<String>? = null, + imageVector: ImageVector? = null, +) { + IntroPreference(title = title, descriptions = descriptions, icon = { IntroIcon(imageVector) }) +} + +@Composable +fun IntroAppPreference( + title: String, + descriptions: List<String>? = null, + appIcon: @Composable (() -> Unit), +) { + IntroPreference(title = title, descriptions = descriptions, icon = { IntroAppIcon(appIcon) }) +} + +@Composable +internal fun IntroPreference( + title: String, + descriptions: List<String>?, + icon: @Composable (() -> Unit), +) { + Column( + modifier = + Modifier.fillMaxWidth() + .padding( + horizontal = SettingsDimension.paddingExtraLarge, + vertical = SettingsDimension.paddingLarge, + ), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + icon() + IntroTitle(title) + IntroDescription(descriptions) + } +} + +@Composable +private fun IntroIcon(imageVector: ImageVector?) { + if (imageVector != null) { + Box( + modifier = + Modifier.size(SettingsDimension.itemIconContainerSize) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.secondaryContainer), + contentAlignment = Alignment.Center, + ) { + Icon( + imageVector = imageVector, + contentDescription = null, + modifier = Modifier.size(SettingsDimension.introIconSize), + tint = MaterialTheme.colorScheme.onSecondary, + ) + } + } +} + +@Composable +private fun IntroAppIcon(appIcon: @Composable () -> Unit) { + Box( + modifier = Modifier.size(SettingsDimension.itemIconContainerSize).clip(CircleShape), + contentAlignment = Alignment.Center, + ) { + appIcon() + } +} + +@Composable +private fun IntroTitle(title: String) { + Box(modifier = Modifier.padding(top = SettingsDimension.paddingLarge)) { + Text( + text = title, + textAlign = TextAlign.Center, + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onSurface, + ) + } +} + +@Composable +private fun IntroDescription(descriptions: List<String>?) { + if (descriptions != null) { + for (description in descriptions) { + if (description.isEmpty()) continue + Text( + text = description, + textAlign = TextAlign.Center, + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = SettingsDimension.paddingExtraSmall), + ) + } + } +} + +@Preview +@Composable +private fun IntroPreferencePreview() { + IntroPreference( + title = "Preferred network type", + descriptions = listOf("Description", "Version"), + imageVector = Icons.Outlined.AirplanemodeActive, + ) +} diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/IntroPreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/IntroPreferenceTest.kt new file mode 100644 index 000000000000..5d801451adcb --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/IntroPreferenceTest.kt @@ -0,0 +1,51 @@ +/* + * 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.settingslib.spa.widget.preference + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsNotDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class IntroPreferenceTest { + @get:Rule val composeTestRule = createComposeRule() + + @Test + fun title_displayed() { + composeTestRule.setContent { IntroPreference(title = TITLE) } + + composeTestRule.onNodeWithText(TITLE).assertIsDisplayed() + } + + @Test + fun description_displayed() { + composeTestRule.setContent { IntroPreference(title = TITLE, descriptions = DESCRIPTION) } + + composeTestRule.onNodeWithText(DESCRIPTION.component1()).assertIsDisplayed() + composeTestRule.onNodeWithText(DESCRIPTION.component2()).assertIsNotDisplayed() + } + + private companion object { + const val TITLE = "Title" + val DESCRIPTION = listOf("Description", "") + } +} |