Loading packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt +6 −6 Original line number Diff line number Diff line Loading @@ -33,8 +33,8 @@ 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.theme.SettingsTheme import com.android.settingslib.spa.widget.SettingsSlider import com.android.settingslib.spa.widget.SettingsSliderModel 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.scaffold.RegularScaffold Loading @@ -51,7 +51,7 @@ object SliderPageProvider : SettingsPageProvider { SettingsEntryBuilder.create("Simple Slider", owner) .setIsAllowSearch(true) .setUiLayoutFn { SettingsSlider(object : SettingsSliderModel { SliderPreference(object : SliderPreferenceModel { override val title = "Simple Slider" override val initValue = 40 }) Loading @@ -61,7 +61,7 @@ object SliderPageProvider : SettingsPageProvider { SettingsEntryBuilder.create("Slider with icon", owner) .setIsAllowSearch(true) .setUiLayoutFn { SettingsSlider(object : SettingsSliderModel { SliderPreference(object : SliderPreferenceModel { override val title = "Slider with icon" override val initValue = 30 override val onValueChangeFinished = { Loading @@ -78,7 +78,7 @@ object SliderPageProvider : SettingsPageProvider { val initValue = 0 var icon by remember { mutableStateOf(Icons.Outlined.MusicOff) } var sliderPosition by remember { mutableStateOf(initValue) } SettingsSlider(object : SettingsSliderModel { SliderPreference(object : SliderPreferenceModel { override val title = "Slider with changeable icon" override val initValue = initValue override val onValueChange = { it: Int -> Loading @@ -96,7 +96,7 @@ object SliderPageProvider : SettingsPageProvider { SettingsEntryBuilder.create("Slider with steps", owner) .setIsAllowSearch(true) .setUiLayoutFn { SettingsSlider(object : SettingsSliderModel { SliderPreference(object : SliderPreferenceModel { override val title = "Slider with steps" override val initValue = 2 override val valueRange = 1..5 Loading packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/SettingsSlider.kt→packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt +45 −51 Original line number Diff line number Diff line Loading @@ -14,14 +14,13 @@ * limitations under the License. */ package com.android.settingslib.spa.widget package com.android.settingslib.spa.widget.preference import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.AccessAlarm import androidx.compose.material.icons.outlined.MusicNote import androidx.compose.material.icons.outlined.MusicOff import androidx.compose.material3.Icon import androidx.compose.material3.Slider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf Loading @@ -33,32 +32,31 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.framework.util.EntryHighlight import com.android.settingslib.spa.widget.preference.BaseLayout import kotlin.math.roundToInt import com.android.settingslib.spa.widget.ui.SettingsSlider /** * The widget model for [SettingsSlider] widget. * The widget model for [SliderPreference] widget. */ interface SettingsSliderModel { interface SliderPreferenceModel { /** * The title of this [SettingsSlider]. * The title of this [SliderPreference]. */ val title: String /** * The initial position of the [SettingsSlider]. * The initial position of the [SliderPreference]. */ val initValue: Int /** * The value range for this [SettingsSlider]. * The value range for this [SliderPreference]. */ val valueRange: IntRange get() = 0..100 /** * The lambda to be invoked during the value change by dragging or a click. This callback is * used to get the real time value of the [SettingsSlider]. * used to get the real time value of the [SliderPreference]. */ val onValueChange: ((value: Int) -> Unit)? get() = null Loading @@ -71,7 +69,7 @@ interface SettingsSliderModel { get() = null /** * The icon image for [SettingsSlider]. If not specified, the slider hides the icon by default. * The icon image for [SliderPreference]. If not specified, the slider hides the icon by default. */ val icon: ImageVector? get() = null Loading @@ -90,11 +88,12 @@ interface SettingsSliderModel { /** * Settings slider widget. * * Data is provided through [SettingsSliderModel]. * Data is provided through [SliderPreferenceModel]. */ @Composable fun SettingsSlider(model: SettingsSliderModel) { SettingsSlider( fun SliderPreference(model: SliderPreferenceModel) { EntryHighlight { SliderPreference( title = model.title, initValue = model.initValue, valueRange = model.valueRange, Loading @@ -104,9 +103,10 @@ fun SettingsSlider(model: SettingsSliderModel) { showSteps = model.showSteps, ) } } @Composable internal fun SettingsSlider( internal fun SliderPreference( title: String, initValue: Int, modifier: Modifier = Modifier, Loading @@ -116,21 +116,16 @@ internal fun SettingsSlider( icon: ImageVector? = null, showSteps: Boolean = false, ) { var sliderPosition by rememberSaveable { mutableStateOf(initValue.toFloat()) } EntryHighlight { BaseLayout( title = title, subTitle = { Slider( value = sliderPosition, onValueChange = { sliderPosition = it onValueChange?.invoke(sliderPosition.roundToInt()) }, modifier = modifier, valueRange = valueRange.first.toFloat()..valueRange.last.toFloat(), steps = if (showSteps) (valueRange.count() - 2) else 0, onValueChangeFinished = onValueChangeFinished, SettingsSlider( initValue, modifier, valueRange, onValueChange, onValueChangeFinished, showSteps ) }, icon = if (icon != null) ({ Loading @@ -138,15 +133,14 @@ internal fun SettingsSlider( }) else null, ) } } @Preview @Composable private fun SettingsSliderPreview() { private fun SliderPreferencePreview() { SettingsTheme { val initValue = 30 var sliderPosition by rememberSaveable { mutableStateOf(initValue) } SettingsSlider( SliderPreference( title = "Alarm Volume", initValue = 30, onValueChange = { sliderPosition = it }, Loading @@ -160,10 +154,10 @@ private fun SettingsSliderPreview() { @Preview @Composable private fun SettingsSliderIconChangePreview() { private fun SliderPreferenceIconChangePreview() { SettingsTheme { var icon by remember { mutableStateOf(Icons.Outlined.MusicNote) } SettingsSlider( SliderPreference( title = "Media Volume", initValue = 40, onValueChange = { it: Int -> Loading @@ -176,9 +170,9 @@ private fun SettingsSliderIconChangePreview() { @Preview @Composable private fun SettingsSliderStepsPreview() { private fun SliderPreferenceStepsPreview() { SettingsTheme { SettingsSlider( SliderPreference( title = "Display Text", initValue = 2, valueRange = 1..5, Loading packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/SettingsSlider.kt 0 → 100644 +49 −0 Original line number Diff line number Diff line /* * 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.material3.Slider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import kotlin.math.roundToInt @Composable fun SettingsSlider( initValue: Int, modifier: Modifier = Modifier, valueRange: IntRange = 0..100, onValueChange: ((value: Int) -> Unit)? = null, onValueChangeFinished: (() -> Unit)? = null, showSteps: Boolean = false, ) { var sliderPosition by rememberSaveable { mutableStateOf(initValue.toFloat()) } Slider( value = sliderPosition, onValueChange = { sliderPosition = it onValueChange?.invoke(sliderPosition.roundToInt()) }, modifier = modifier, valueRange = valueRange.first.toFloat()..valueRange.last.toFloat(), steps = if (showSteps) (valueRange.count() - 2) else 0, onValueChangeFinished = onValueChangeFinished, ) } packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/SettingsSliderTest.kt→packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/SliderPreferenceTest.kt +4 −4 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ * limitations under the License. */ package com.android.settingslib.spa.widget package com.android.settingslib.spa.widget.preference import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.createComposeRule Loading @@ -25,14 +25,14 @@ import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class SettingsSliderTest { class SliderPreferenceTest { @get:Rule val composeTestRule = createComposeRule() @Test fun title_displayed() { composeTestRule.setContent { SettingsSlider(object : SettingsSliderModel { SliderPreference(object : SliderPreferenceModel { override val title = "Slider" override val initValue = 40 }) Loading @@ -41,5 +41,5 @@ class SettingsSliderTest { composeTestRule.onNodeWithText("Slider").assertIsDisplayed() } // TODO: Add more unit tests for SettingsSlider widget. // TODO: Add more unit tests for SliderPreference widget. } Loading
packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt +6 −6 Original line number Diff line number Diff line Loading @@ -33,8 +33,8 @@ 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.theme.SettingsTheme import com.android.settingslib.spa.widget.SettingsSlider import com.android.settingslib.spa.widget.SettingsSliderModel 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.scaffold.RegularScaffold Loading @@ -51,7 +51,7 @@ object SliderPageProvider : SettingsPageProvider { SettingsEntryBuilder.create("Simple Slider", owner) .setIsAllowSearch(true) .setUiLayoutFn { SettingsSlider(object : SettingsSliderModel { SliderPreference(object : SliderPreferenceModel { override val title = "Simple Slider" override val initValue = 40 }) Loading @@ -61,7 +61,7 @@ object SliderPageProvider : SettingsPageProvider { SettingsEntryBuilder.create("Slider with icon", owner) .setIsAllowSearch(true) .setUiLayoutFn { SettingsSlider(object : SettingsSliderModel { SliderPreference(object : SliderPreferenceModel { override val title = "Slider with icon" override val initValue = 30 override val onValueChangeFinished = { Loading @@ -78,7 +78,7 @@ object SliderPageProvider : SettingsPageProvider { val initValue = 0 var icon by remember { mutableStateOf(Icons.Outlined.MusicOff) } var sliderPosition by remember { mutableStateOf(initValue) } SettingsSlider(object : SettingsSliderModel { SliderPreference(object : SliderPreferenceModel { override val title = "Slider with changeable icon" override val initValue = initValue override val onValueChange = { it: Int -> Loading @@ -96,7 +96,7 @@ object SliderPageProvider : SettingsPageProvider { SettingsEntryBuilder.create("Slider with steps", owner) .setIsAllowSearch(true) .setUiLayoutFn { SettingsSlider(object : SettingsSliderModel { SliderPreference(object : SliderPreferenceModel { override val title = "Slider with steps" override val initValue = 2 override val valueRange = 1..5 Loading
packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/SettingsSlider.kt→packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt +45 −51 Original line number Diff line number Diff line Loading @@ -14,14 +14,13 @@ * limitations under the License. */ package com.android.settingslib.spa.widget package com.android.settingslib.spa.widget.preference import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.AccessAlarm import androidx.compose.material.icons.outlined.MusicNote import androidx.compose.material.icons.outlined.MusicOff import androidx.compose.material3.Icon import androidx.compose.material3.Slider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf Loading @@ -33,32 +32,31 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.framework.util.EntryHighlight import com.android.settingslib.spa.widget.preference.BaseLayout import kotlin.math.roundToInt import com.android.settingslib.spa.widget.ui.SettingsSlider /** * The widget model for [SettingsSlider] widget. * The widget model for [SliderPreference] widget. */ interface SettingsSliderModel { interface SliderPreferenceModel { /** * The title of this [SettingsSlider]. * The title of this [SliderPreference]. */ val title: String /** * The initial position of the [SettingsSlider]. * The initial position of the [SliderPreference]. */ val initValue: Int /** * The value range for this [SettingsSlider]. * The value range for this [SliderPreference]. */ val valueRange: IntRange get() = 0..100 /** * The lambda to be invoked during the value change by dragging or a click. This callback is * used to get the real time value of the [SettingsSlider]. * used to get the real time value of the [SliderPreference]. */ val onValueChange: ((value: Int) -> Unit)? get() = null Loading @@ -71,7 +69,7 @@ interface SettingsSliderModel { get() = null /** * The icon image for [SettingsSlider]. If not specified, the slider hides the icon by default. * The icon image for [SliderPreference]. If not specified, the slider hides the icon by default. */ val icon: ImageVector? get() = null Loading @@ -90,11 +88,12 @@ interface SettingsSliderModel { /** * Settings slider widget. * * Data is provided through [SettingsSliderModel]. * Data is provided through [SliderPreferenceModel]. */ @Composable fun SettingsSlider(model: SettingsSliderModel) { SettingsSlider( fun SliderPreference(model: SliderPreferenceModel) { EntryHighlight { SliderPreference( title = model.title, initValue = model.initValue, valueRange = model.valueRange, Loading @@ -104,9 +103,10 @@ fun SettingsSlider(model: SettingsSliderModel) { showSteps = model.showSteps, ) } } @Composable internal fun SettingsSlider( internal fun SliderPreference( title: String, initValue: Int, modifier: Modifier = Modifier, Loading @@ -116,21 +116,16 @@ internal fun SettingsSlider( icon: ImageVector? = null, showSteps: Boolean = false, ) { var sliderPosition by rememberSaveable { mutableStateOf(initValue.toFloat()) } EntryHighlight { BaseLayout( title = title, subTitle = { Slider( value = sliderPosition, onValueChange = { sliderPosition = it onValueChange?.invoke(sliderPosition.roundToInt()) }, modifier = modifier, valueRange = valueRange.first.toFloat()..valueRange.last.toFloat(), steps = if (showSteps) (valueRange.count() - 2) else 0, onValueChangeFinished = onValueChangeFinished, SettingsSlider( initValue, modifier, valueRange, onValueChange, onValueChangeFinished, showSteps ) }, icon = if (icon != null) ({ Loading @@ -138,15 +133,14 @@ internal fun SettingsSlider( }) else null, ) } } @Preview @Composable private fun SettingsSliderPreview() { private fun SliderPreferencePreview() { SettingsTheme { val initValue = 30 var sliderPosition by rememberSaveable { mutableStateOf(initValue) } SettingsSlider( SliderPreference( title = "Alarm Volume", initValue = 30, onValueChange = { sliderPosition = it }, Loading @@ -160,10 +154,10 @@ private fun SettingsSliderPreview() { @Preview @Composable private fun SettingsSliderIconChangePreview() { private fun SliderPreferenceIconChangePreview() { SettingsTheme { var icon by remember { mutableStateOf(Icons.Outlined.MusicNote) } SettingsSlider( SliderPreference( title = "Media Volume", initValue = 40, onValueChange = { it: Int -> Loading @@ -176,9 +170,9 @@ private fun SettingsSliderIconChangePreview() { @Preview @Composable private fun SettingsSliderStepsPreview() { private fun SliderPreferenceStepsPreview() { SettingsTheme { SettingsSlider( SliderPreference( title = "Display Text", initValue = 2, valueRange = 1..5, Loading
packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/SettingsSlider.kt 0 → 100644 +49 −0 Original line number Diff line number Diff line /* * 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.material3.Slider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import kotlin.math.roundToInt @Composable fun SettingsSlider( initValue: Int, modifier: Modifier = Modifier, valueRange: IntRange = 0..100, onValueChange: ((value: Int) -> Unit)? = null, onValueChangeFinished: (() -> Unit)? = null, showSteps: Boolean = false, ) { var sliderPosition by rememberSaveable { mutableStateOf(initValue.toFloat()) } Slider( value = sliderPosition, onValueChange = { sliderPosition = it onValueChange?.invoke(sliderPosition.roundToInt()) }, modifier = modifier, valueRange = valueRange.first.toFloat()..valueRange.last.toFloat(), steps = if (showSteps) (valueRange.count() - 2) else 0, onValueChangeFinished = onValueChangeFinished, ) }
packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/SettingsSliderTest.kt→packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/SliderPreferenceTest.kt +4 −4 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ * limitations under the License. */ package com.android.settingslib.spa.widget package com.android.settingslib.spa.widget.preference import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.createComposeRule Loading @@ -25,14 +25,14 @@ import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class SettingsSliderTest { class SliderPreferenceTest { @get:Rule val composeTestRule = createComposeRule() @Test fun title_displayed() { composeTestRule.setContent { SettingsSlider(object : SettingsSliderModel { SliderPreference(object : SliderPreferenceModel { override val title = "Slider" override val initValue = 40 }) Loading @@ -41,5 +41,5 @@ class SettingsSliderTest { composeTestRule.onNodeWithText("Slider").assertIsDisplayed() } // TODO: Add more unit tests for SettingsSlider widget. // TODO: Add more unit tests for SliderPreference widget. }