Merge "Extract slider in SettingsSlider to a simple ui widget and rename the slider preference widget to SliderPreference."

This commit is contained in:
Kelly Zhang
2022-10-19 07:36:30 +00:00
committed by Android (Google) Code Review
4 changed files with 104 additions and 61 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -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,
)
}

View File

@@ -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.
}