Loading packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt→packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPageProvider.kt +55 −42 Original line number Diff line number Diff line Loading @@ -33,10 +33,10 @@ 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.framework.theme.SettingsTheme import com.android.settingslib.spa.widget.preference.SliderPreference import com.android.settingslib.spa.widget.preference.SliderPreferenceModel import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel import com.android.settingslib.spa.widget.preference.SliderPreference import com.android.settingslib.spa.widget.preference.SliderPreferenceModel private const val TITLE = "Sample Slider" Loading @@ -49,24 +49,30 @@ object SliderPageProvider : SettingsPageProvider { entryList.add( SettingsEntryBuilder.create("Simple Slider", owner) .setUiLayoutFn { SliderPreference(object : SliderPreferenceModel { SliderPreference( object : SliderPreferenceModel { override val title = "Simple Slider" override val initValue = 40 }) }.build() } ) } .build() ) entryList.add( SettingsEntryBuilder.create("Slider with icon", owner) .setUiLayoutFn { SliderPreference(object : SliderPreferenceModel { SliderPreference( object : SliderPreferenceModel { override val title = "Slider with icon" override val initValue = 30 override val onValueChangeFinished = { println("onValueChangeFinished") } override val icon = Icons.Outlined.AccessAlarm }) }.build() override val iconStart = Icons.Outlined.AccessAlarm } ) } .build() ) entryList.add( SettingsEntryBuilder.create("Slider with changeable icon", owner) Loading @@ -74,42 +80,51 @@ object SliderPageProvider : SettingsPageProvider { val initValue = 0 var icon by remember { mutableStateOf(Icons.Outlined.MusicOff) } var sliderPosition by remember { mutableStateOf(initValue) } SliderPreference(object : SliderPreferenceModel { SliderPreference( object : SliderPreferenceModel { override val title = "Slider with changeable icon" override val initValue = initValue override val onValueChange = { it: Int -> sliderPosition = it icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff } override val onValueChangeFinished = { println("onValueChangeFinished: the value is $sliderPosition") } override val icon = icon }) }.build() override val iconEnd = icon } ) } .build() ) entryList.add( SettingsEntryBuilder.create("Slider with steps", owner) .setUiLayoutFn { SliderPreference(object : SliderPreferenceModel { SliderPreference( object : SliderPreferenceModel { override val title = "Slider with steps" override val initValue = 2 override val valueRange = 1..5 override val showSteps = true }) }.build() } ) } .build() ) return entryList } fun buildInjectEntry(): SettingsEntryBuilder { return SettingsEntryBuilder.createInject(owner) .setUiLayoutFn { Preference(object : PreferenceModel { return SettingsEntryBuilder.createInject(owner).setUiLayoutFn { Preference( object : PreferenceModel { override val title = TITLE override val onClick = navigator(name) }) } ) } } Loading @@ -121,7 +136,5 @@ object SliderPageProvider : SettingsPageProvider { @Preview(showBackground = true) @Composable private fun SliderPagePreview() { SettingsTheme { SliderPageProvider.Page(null) } SettingsTheme { SliderPageProvider.Page(null) } } packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SliderPreferenceScreenshotTest.kt +1 −1 Original line number Diff line number Diff line Loading @@ -60,7 +60,7 @@ class SliderPreferenceScreenshotTest(emulationSpec: DeviceEmulationSpec) { override val onValueChangeFinished = { println("onValueChangeFinished") } override val icon = Icons.Outlined.AccessAlarm override val iconStart = Icons.Outlined.AccessAlarm }) SliderPreference(object : SliderPreferenceModel { Loading packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt +73 −37 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package com.android.settingslib.spa.widget.preference import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.AccessAlarm import androidx.compose.material.icons.outlined.MusicNote Loading @@ -27,30 +31,25 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector 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 import com.android.settingslib.spa.framework.util.EntryHighlight import com.android.settingslib.spa.widget.ui.SettingsSlider /** * The widget model for [SliderPreference] widget. */ /** The widget model for [SliderPreference] widget. */ interface SliderPreferenceModel { /** * The title of this [SliderPreference]. */ /** The title of this [SliderPreference]. */ val title: String /** * The initial position of the [SliderPreference]. */ /** The initial position of the [SliderPreference]. */ val initValue: Int /** * The value range for this [SliderPreference]. */ /** The value range for this [SliderPreference]. */ val valueRange: IntRange get() = 0..100 Loading @@ -69,15 +68,23 @@ interface SliderPreferenceModel { get() = null /** * The icon image for [SliderPreference]. If not specified, the slider hides the icon by default. * The start icon image for [SliderPreference]. If not specified, the slider hides the icon by * default. */ val icon: ImageVector? val iconStart: ImageVector? get() = null /** * Indicates whether to show step marks. If show step marks, when user finish sliding, * the slider will automatically jump to the nearest step mark. Otherwise, the slider hides * the step marks by default. * The end icon image for [SliderPreference]. If not specified, the slider hides the icon by * default. */ val iconEnd: ImageVector? get() = null /** * Indicates whether to show step marks. If show step marks, when user finish sliding, the * slider will automatically jump to the nearest step mark. Otherwise, the slider hides the step * marks by default. * * The step is fixed to 1. */ Loading @@ -99,7 +106,8 @@ fun SliderPreference(model: SliderPreferenceModel) { valueRange = model.valueRange, onValueChange = model.onValueChange, onValueChangeFinished = model.onValueChangeFinished, icon = model.icon, iconStart = model.iconStart, iconEnd = model.iconEnd, showSteps = model.showSteps, ) } Loading @@ -113,27 +121,45 @@ internal fun SliderPreference( valueRange: IntRange = 0..100, onValueChange: ((value: Int) -> Unit)? = null, onValueChangeFinished: (() -> Unit)? = null, icon: ImageVector? = null, iconStart: ImageVector? = null, iconEnd: ImageVector? = null, showSteps: Boolean = false, ) { BaseLayout( title = title, subTitle = { Row(verticalAlignment = Alignment.CenterVertically) { if (iconStart != null) { SliderIcon(icon = iconStart) Spacer(Modifier.padding(SettingsDimension.paddingSmall)) } Box(Modifier.weight(1f)) { SettingsSlider( initValue, modifier, valueRange, onValueChange, onValueChangeFinished, showSteps showSteps, ) } if (iconEnd != null) { Spacer(Modifier.padding(SettingsDimension.paddingSmall)) SliderIcon(icon = iconEnd) } } }, icon = if (icon != null) ({ Icon(imageVector = icon, contentDescription = null) }) else null, ) } @Composable fun SliderIcon(icon: ImageVector) { Box(modifier = Modifier.padding(8.dp), contentAlignment = Alignment.Center) { Icon(imageVector = icon, contentDescription = null) } } @Preview @Composable private fun SliderPreferencePreview() { Loading @@ -147,7 +173,7 @@ private fun SliderPreferencePreview() { onValueChangeFinished = { println("onValueChangeFinished: the value is $sliderPosition") }, icon = Icons.Outlined.AccessAlarm, iconStart = Icons.Outlined.AccessAlarm, ) } } Loading @@ -163,20 +189,30 @@ private fun SliderPreferenceIconChangePreview() { onValueChange = { it: Int -> icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff }, icon = icon, iconEnd = icon, ) } } @Preview @Composable private fun SliderPreferenceStepsPreview() { private fun SliderPreferenceTwoIconPreview() { SettingsTheme { val iconStart by remember { mutableStateOf(Icons.Outlined.MusicNote) } val iconEnd by remember { mutableStateOf(Icons.Outlined.MusicOff) } SliderPreference( title = "Display Text", initValue = 2, valueRange = 1..5, showSteps = true, title = "Media Volume", initValue = 40, iconStart = iconStart, iconEnd = iconEnd, ) } } @Preview @Composable private fun SliderPreferenceStepsPreview() { SettingsTheme { SliderPreference(title = "Display Text", initValue = 2, valueRange = 1..5, showSteps = true) } } Loading
packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt→packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPageProvider.kt +55 −42 Original line number Diff line number Diff line Loading @@ -33,10 +33,10 @@ 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.framework.theme.SettingsTheme import com.android.settingslib.spa.widget.preference.SliderPreference import com.android.settingslib.spa.widget.preference.SliderPreferenceModel import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel import com.android.settingslib.spa.widget.preference.SliderPreference import com.android.settingslib.spa.widget.preference.SliderPreferenceModel private const val TITLE = "Sample Slider" Loading @@ -49,24 +49,30 @@ object SliderPageProvider : SettingsPageProvider { entryList.add( SettingsEntryBuilder.create("Simple Slider", owner) .setUiLayoutFn { SliderPreference(object : SliderPreferenceModel { SliderPreference( object : SliderPreferenceModel { override val title = "Simple Slider" override val initValue = 40 }) }.build() } ) } .build() ) entryList.add( SettingsEntryBuilder.create("Slider with icon", owner) .setUiLayoutFn { SliderPreference(object : SliderPreferenceModel { SliderPreference( object : SliderPreferenceModel { override val title = "Slider with icon" override val initValue = 30 override val onValueChangeFinished = { println("onValueChangeFinished") } override val icon = Icons.Outlined.AccessAlarm }) }.build() override val iconStart = Icons.Outlined.AccessAlarm } ) } .build() ) entryList.add( SettingsEntryBuilder.create("Slider with changeable icon", owner) Loading @@ -74,42 +80,51 @@ object SliderPageProvider : SettingsPageProvider { val initValue = 0 var icon by remember { mutableStateOf(Icons.Outlined.MusicOff) } var sliderPosition by remember { mutableStateOf(initValue) } SliderPreference(object : SliderPreferenceModel { SliderPreference( object : SliderPreferenceModel { override val title = "Slider with changeable icon" override val initValue = initValue override val onValueChange = { it: Int -> sliderPosition = it icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff } override val onValueChangeFinished = { println("onValueChangeFinished: the value is $sliderPosition") } override val icon = icon }) }.build() override val iconEnd = icon } ) } .build() ) entryList.add( SettingsEntryBuilder.create("Slider with steps", owner) .setUiLayoutFn { SliderPreference(object : SliderPreferenceModel { SliderPreference( object : SliderPreferenceModel { override val title = "Slider with steps" override val initValue = 2 override val valueRange = 1..5 override val showSteps = true }) }.build() } ) } .build() ) return entryList } fun buildInjectEntry(): SettingsEntryBuilder { return SettingsEntryBuilder.createInject(owner) .setUiLayoutFn { Preference(object : PreferenceModel { return SettingsEntryBuilder.createInject(owner).setUiLayoutFn { Preference( object : PreferenceModel { override val title = TITLE override val onClick = navigator(name) }) } ) } } Loading @@ -121,7 +136,5 @@ object SliderPageProvider : SettingsPageProvider { @Preview(showBackground = true) @Composable private fun SliderPagePreview() { SettingsTheme { SliderPageProvider.Page(null) } SettingsTheme { SliderPageProvider.Page(null) } }
packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SliderPreferenceScreenshotTest.kt +1 −1 Original line number Diff line number Diff line Loading @@ -60,7 +60,7 @@ class SliderPreferenceScreenshotTest(emulationSpec: DeviceEmulationSpec) { override val onValueChangeFinished = { println("onValueChangeFinished") } override val icon = Icons.Outlined.AccessAlarm override val iconStart = Icons.Outlined.AccessAlarm }) SliderPreference(object : SliderPreferenceModel { Loading
packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt +73 −37 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package com.android.settingslib.spa.widget.preference import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.AccessAlarm import androidx.compose.material.icons.outlined.MusicNote Loading @@ -27,30 +31,25 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector 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 import com.android.settingslib.spa.framework.util.EntryHighlight import com.android.settingslib.spa.widget.ui.SettingsSlider /** * The widget model for [SliderPreference] widget. */ /** The widget model for [SliderPreference] widget. */ interface SliderPreferenceModel { /** * The title of this [SliderPreference]. */ /** The title of this [SliderPreference]. */ val title: String /** * The initial position of the [SliderPreference]. */ /** The initial position of the [SliderPreference]. */ val initValue: Int /** * The value range for this [SliderPreference]. */ /** The value range for this [SliderPreference]. */ val valueRange: IntRange get() = 0..100 Loading @@ -69,15 +68,23 @@ interface SliderPreferenceModel { get() = null /** * The icon image for [SliderPreference]. If not specified, the slider hides the icon by default. * The start icon image for [SliderPreference]. If not specified, the slider hides the icon by * default. */ val icon: ImageVector? val iconStart: ImageVector? get() = null /** * Indicates whether to show step marks. If show step marks, when user finish sliding, * the slider will automatically jump to the nearest step mark. Otherwise, the slider hides * the step marks by default. * The end icon image for [SliderPreference]. If not specified, the slider hides the icon by * default. */ val iconEnd: ImageVector? get() = null /** * Indicates whether to show step marks. If show step marks, when user finish sliding, the * slider will automatically jump to the nearest step mark. Otherwise, the slider hides the step * marks by default. * * The step is fixed to 1. */ Loading @@ -99,7 +106,8 @@ fun SliderPreference(model: SliderPreferenceModel) { valueRange = model.valueRange, onValueChange = model.onValueChange, onValueChangeFinished = model.onValueChangeFinished, icon = model.icon, iconStart = model.iconStart, iconEnd = model.iconEnd, showSteps = model.showSteps, ) } Loading @@ -113,27 +121,45 @@ internal fun SliderPreference( valueRange: IntRange = 0..100, onValueChange: ((value: Int) -> Unit)? = null, onValueChangeFinished: (() -> Unit)? = null, icon: ImageVector? = null, iconStart: ImageVector? = null, iconEnd: ImageVector? = null, showSteps: Boolean = false, ) { BaseLayout( title = title, subTitle = { Row(verticalAlignment = Alignment.CenterVertically) { if (iconStart != null) { SliderIcon(icon = iconStart) Spacer(Modifier.padding(SettingsDimension.paddingSmall)) } Box(Modifier.weight(1f)) { SettingsSlider( initValue, modifier, valueRange, onValueChange, onValueChangeFinished, showSteps showSteps, ) } if (iconEnd != null) { Spacer(Modifier.padding(SettingsDimension.paddingSmall)) SliderIcon(icon = iconEnd) } } }, icon = if (icon != null) ({ Icon(imageVector = icon, contentDescription = null) }) else null, ) } @Composable fun SliderIcon(icon: ImageVector) { Box(modifier = Modifier.padding(8.dp), contentAlignment = Alignment.Center) { Icon(imageVector = icon, contentDescription = null) } } @Preview @Composable private fun SliderPreferencePreview() { Loading @@ -147,7 +173,7 @@ private fun SliderPreferencePreview() { onValueChangeFinished = { println("onValueChangeFinished: the value is $sliderPosition") }, icon = Icons.Outlined.AccessAlarm, iconStart = Icons.Outlined.AccessAlarm, ) } } Loading @@ -163,20 +189,30 @@ private fun SliderPreferenceIconChangePreview() { onValueChange = { it: Int -> icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff }, icon = icon, iconEnd = icon, ) } } @Preview @Composable private fun SliderPreferenceStepsPreview() { private fun SliderPreferenceTwoIconPreview() { SettingsTheme { val iconStart by remember { mutableStateOf(Icons.Outlined.MusicNote) } val iconEnd by remember { mutableStateOf(Icons.Outlined.MusicOff) } SliderPreference( title = "Display Text", initValue = 2, valueRange = 1..5, showSteps = true, title = "Media Volume", initValue = 40, iconStart = iconStart, iconEnd = iconEnd, ) } } @Preview @Composable private fun SliderPreferenceStepsPreview() { SettingsTheme { SliderPreference(title = "Display Text", initValue = 2, valueRange = 1..5, showSteps = true) } }