Extract slider in SettingsSlider to a simple ui widget and rename the
slider preference widget to SliderPreference. Test: Manually Test on device and unit test. Bug: 241857459 Change-Id: I90302f997211213f9d91987bf9d19acba088035a
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
})
|
||||
@@ -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 = {
|
||||
@@ -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 ->
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -90,23 +88,25 @@ interface SettingsSliderModel {
|
||||
/**
|
||||
* Settings slider widget.
|
||||
*
|
||||
* Data is provided through [SettingsSliderModel].
|
||||
* Data is provided through [SliderPreferenceModel].
|
||||
*/
|
||||
@Composable
|
||||
fun SettingsSlider(model: SettingsSliderModel) {
|
||||
SettingsSlider(
|
||||
title = model.title,
|
||||
initValue = model.initValue,
|
||||
valueRange = model.valueRange,
|
||||
onValueChange = model.onValueChange,
|
||||
onValueChangeFinished = model.onValueChangeFinished,
|
||||
icon = model.icon,
|
||||
showSteps = model.showSteps,
|
||||
)
|
||||
fun SliderPreference(model: SliderPreferenceModel) {
|
||||
EntryHighlight {
|
||||
SliderPreference(
|
||||
title = model.title,
|
||||
initValue = model.initValue,
|
||||
valueRange = model.valueRange,
|
||||
onValueChange = model.onValueChange,
|
||||
onValueChangeFinished = model.onValueChangeFinished,
|
||||
icon = model.icon,
|
||||
showSteps = model.showSteps,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun SettingsSlider(
|
||||
internal fun SliderPreference(
|
||||
title: String,
|
||||
initValue: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
@@ -116,37 +116,31 @@ 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,
|
||||
)
|
||||
},
|
||||
icon = if (icon != null) ({
|
||||
Icon(imageVector = icon, contentDescription = null)
|
||||
}) else null,
|
||||
)
|
||||
}
|
||||
BaseLayout(
|
||||
title = title,
|
||||
subTitle = {
|
||||
SettingsSlider(
|
||||
initValue,
|
||||
modifier,
|
||||
valueRange,
|
||||
onValueChange,
|
||||
onValueChangeFinished,
|
||||
showSteps
|
||||
)
|
||||
},
|
||||
icon = if (icon != null) ({
|
||||
Icon(imageVector = icon, contentDescription = null)
|
||||
}) 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 },
|
||||
@@ -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 ->
|
||||
@@ -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,
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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,
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
})
|
||||
@@ -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.
|
||||
}
|
||||
Reference in New Issue
Block a user