diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt index 937e594936323..36361ddfe08a6 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt @@ -17,7 +17,6 @@ package com.android.settingslib.spa.gallery.page import android.os.Bundle -import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import androidx.navigation.NavType @@ -28,12 +27,14 @@ import com.android.settingslib.spa.framework.compose.toState 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 +private const val TITLE = "Sample page with arguments" private const val STRING_PARAM_NAME = "stringParam" private const val INT_PARAM_NAME = "intParam" object ArgumentPageProvider : SettingsPageProvider { - override val name = Destinations.Argument + override val name = "Argument" override val arguments = listOf( navArgument(STRING_PARAM_NAME) { type = NavType.StringType }, @@ -51,17 +52,17 @@ object ArgumentPageProvider : SettingsPageProvider { @Composable fun EntryItem(stringParam: String, intParam: Int) { Preference(object : PreferenceModel { - override val title = "Sample page with arguments" + override val title = TITLE override val summary = "$STRING_PARAM_NAME=$stringParam, $INT_PARAM_NAME=$intParam".toState() - override val onClick = navigator("${Destinations.Argument}/$stringParam/$intParam") + override val onClick = navigator("$name/$stringParam/$intParam") }) } } @Composable fun ArgumentPage(stringParam: String, intParam: Int) { - Column { + RegularScaffold(title = TITLE) { Preference(object : PreferenceModel { override val title = "String param value" override val summary = stringParam.toState() diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt index 143c365d3a748..82005ec44c741 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt @@ -17,12 +17,8 @@ package com.android.settingslib.spa.gallery.page import android.os.Bundle -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.api.SettingsPageProvider import com.android.settingslib.spa.framework.compose.navigator @@ -30,8 +26,11 @@ 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.Footer +private const val TITLE = "Sample Footer" + object FooterPageProvider : SettingsPageProvider { override val name = "Footer" @@ -43,7 +42,7 @@ object FooterPageProvider : SettingsPageProvider { @Composable fun EntryItem() { Preference(object : PreferenceModel { - override val title = "Sample Footer" + override val title = TITLE override val onClick = navigator(name) }) } @@ -51,7 +50,7 @@ object FooterPageProvider : SettingsPageProvider { @Composable private fun FooterPage() { - Column(Modifier.verticalScroll(rememberScrollState())) { + RegularScaffold(title = TITLE) { Preference(remember { object : PreferenceModel { override val title = "Some Preference" diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/HomePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/HomePage.kt index ee077f4a25e64..6b7de8d29d0fb 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/HomePage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/HomePage.kt @@ -31,7 +31,7 @@ import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.gallery.R object HomePageProvider : SettingsPageProvider { - override val name = Destinations.Home + override val name = "Home" @Composable override fun Page(arguments: Bundle?) { diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PageRepository.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PageRepository.kt index 64652257c20b0..cbfc60395d69d 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PageRepository.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PageRepository.kt @@ -18,14 +18,6 @@ package com.android.settingslib.spa.gallery.page import com.android.settingslib.spa.framework.api.SettingsPageRepository -object Destinations { - const val Home = "Home" - const val Preference = "Preference" - const val SwitchPreference = "SwitchPreference" - const val Argument = "Argument" - const val Slider = "Slider" -} - val galleryPageRepository = SettingsPageRepository( allPages = listOf( HomePageProvider, @@ -36,5 +28,5 @@ val galleryPageRepository = SettingsPageRepository( SettingsPagerPageProvider, FooterPageProvider, ), - startDestination = Destinations.Home, + startDestination = HomePageProvider.name, ) diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt index 8a29d35ad9d94..0463e58f09f6d 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt @@ -17,9 +17,6 @@ package com.android.settingslib.spa.gallery.page import android.os.Bundle -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.DisabledByDefault import androidx.compose.material.icons.outlined.TouchApp @@ -31,7 +28,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.api.SettingsPageProvider import com.android.settingslib.spa.framework.compose.navigator @@ -39,11 +35,14 @@ import com.android.settingslib.spa.framework.compose.toState 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.SettingsIcon import kotlinx.coroutines.delay +private const val TITLE = "Sample Preference" + object PreferencePageProvider : SettingsPageProvider { - override val name = Destinations.Preference + override val name = "Preference" @Composable override fun Page(arguments: Bundle?) { @@ -53,15 +52,15 @@ object PreferencePageProvider : SettingsPageProvider { @Composable fun EntryItem() { Preference(object : PreferenceModel { - override val title = "Sample Preference" - override val onClick = navigator(Destinations.Preference) + override val title = TITLE + override val onClick = navigator(name) }) } } @Composable private fun PreferencePage() { - Column(Modifier.verticalScroll(rememberScrollState())) { + RegularScaffold(title = TITLE) { Preference(object : PreferenceModel { override val title = "Preference" }) diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt index 9bcac1b84a0b9..04046fa18df11 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt @@ -17,9 +17,6 @@ package com.android.settingslib.spa.gallery.page import android.os.Bundle -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.AccessAlarm import androidx.compose.material.icons.outlined.MusicNote @@ -29,18 +26,20 @@ 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.tooling.preview.Preview import com.android.settingslib.spa.framework.api.SettingsPageProvider import com.android.settingslib.spa.framework.compose.navigator 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.SettingsSlider import com.android.settingslib.spa.widget.ui.SettingsSliderModel +private const val TITLE = "Sample Slider" + object SliderPageProvider : SettingsPageProvider { - override val name = Destinations.Slider + override val name = "Slider" @Composable override fun Page(arguments: Bundle?) { @@ -50,15 +49,15 @@ object SliderPageProvider : SettingsPageProvider { @Composable fun EntryItem() { Preference(object : PreferenceModel { - override val title = "Sample Slider" - override val onClick = navigator(Destinations.Slider) + override val title = TITLE + override val onClick = navigator(name) }) } } @Composable private fun SliderPage() { - Column(Modifier.verticalScroll(rememberScrollState())) { + RegularScaffold(title = TITLE) { SettingsSlider(object : SettingsSliderModel { override val title = "Slider" override val initValue = 40 diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt index b6f7258217280..e9e5d356d2d4a 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt @@ -17,15 +17,11 @@ package com.android.settingslib.spa.gallery.page import android.os.Bundle -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.api.SettingsPageProvider import com.android.settingslib.spa.framework.compose.navigator @@ -35,10 +31,13 @@ import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel import com.android.settingslib.spa.widget.preference.SwitchPreference import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel +import com.android.settingslib.spa.widget.scaffold.RegularScaffold import kotlinx.coroutines.delay +private const val TITLE = "Sample SwitchPreference" + object SwitchPreferencePageProvider : SettingsPageProvider { - override val name = Destinations.SwitchPreference + override val name = "SwitchPreference" @Composable override fun Page(arguments: Bundle?) { @@ -48,15 +47,15 @@ object SwitchPreferencePageProvider : SettingsPageProvider { @Composable fun EntryItem() { Preference(object : PreferenceModel { - override val title = "Sample SwitchPreference" - override val onClick = navigator(Destinations.SwitchPreference) + override val title = TITLE + override val onClick = navigator(name) }) } } @Composable private fun SwitchPreferencePage() { - Column(Modifier.verticalScroll(rememberScrollState())) { + RegularScaffold(title = TITLE) { SampleSwitchPreference() SampleSwitchPreferenceWithSummary() SampleSwitchPreferenceWithAsyncSummary() 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 e1ca69bd79409..7d3e10768e460 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 @@ -31,4 +31,5 @@ object SettingsDimension { end = itemPaddingEnd, bottom = itemPaddingVertical, ) + val itemPaddingAround = 8.dp } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt new file mode 100644 index 0000000000000..0a41a1a95936b --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt @@ -0,0 +1,46 @@ +/* + * 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.scaffold + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import com.android.settingslib.spa.framework.compose.LocalNavController + +@Composable +internal fun NavigateUp() { + val navController = LocalNavController.current + val contentDescription = stringResource( + id = androidx.appcompat.R.string.abc_action_bar_up_description, + ) + BackAction(contentDescription) { + navController.navigateUp() + } +} + +@Composable +private fun BackAction(contentDescription: String, onClick: () -> Unit) { + IconButton(onClick) { + Icon( + imageVector = Icons.Outlined.ArrowBack, + contentDescription = contentDescription, + ) + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/RegularScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/RegularScaffold.kt new file mode 100644 index 0000000000000..3325d5382f2e6 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/RegularScaffold.kt @@ -0,0 +1,83 @@ +/* + * 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.scaffold + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SmallTopAppBar +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.framework.theme.SettingsTheme + +/** + * A [Scaffold] which content is scrollable and wrapped in a [Column]. + * + * For example, this is for the pages with some preferences and is scrollable when the items out of + * the screen. + */ +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun RegularScaffold( + title: String, + actions: @Composable RowScope.() -> Unit = {}, + content: @Composable () -> Unit, +) { + Scaffold( + topBar = { + SmallTopAppBar( + title = { + Text( + text = title, + modifier = Modifier.padding(SettingsDimension.itemPaddingAround), + ) + }, + navigationIcon = { NavigateUp() }, + actions = actions, + colors = settingsTopAppBarColors(), + ) + }, + ) { paddingValues -> + Column(Modifier.verticalScroll(rememberScrollState())) { + Spacer(Modifier.padding(paddingValues)) + content() + } + } +} + +@Composable +internal fun settingsTopAppBarColors() = TopAppBarDefaults.largeTopAppBarColors( + containerColor = SettingsTheme.colorScheme.surfaceHeader, + scrolledContainerColor = SettingsTheme.colorScheme.surfaceHeader, +) + +@Preview +@Composable +private fun RegularScaffoldPreview() { + SettingsTheme { + RegularScaffold(title = "Display") {} + } +}