Skip to content

Commit 9b86e77

Browse files
authored
feat(preference): add SliderPreference and RangeSliderPreference (#336)
* feat(preference): add SliderPreference and RangeSliderPreference Introduce new preference components for slider-based value adjustments: - `SliderPreference`: A single-value slider preference. - `RangeSliderPreference`: A dual-value range slider preference. Both components integrate with `BasicComponent` and support: - Title and summary text. - Custom `valueText` display. - Customizable `startAction` and `endActions`. - `onClick` support with arrow icon indicator. - Integration with existing `Slider` and `RangeSlider` components. Also updated documentation (English and Chinese) and example usage. * refactor(preference): update summary text color to use theme color scheme Update the color of the summary text in `SliderPreference` and `RangeSliderPreference` to use `MiuixTheme.colorScheme` values instead of `summaryColor` to ensure better consistency with the theme.
1 parent a69894a commit 9b86e77

12 files changed

Lines changed: 972 additions & 216 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,5 @@ docs/public/compose
4444
docs/public/icons
4545
miuix-ui/**/generated/baselineProfiles/**
4646
example/ios/iosApp/Generated.xcconfig
47+
/build-plugins/bin
48+
/docs/iconGen/bin

docs/components/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ The Scaffold component provides a suitable container for cross-platform popup wi
5252
| [SwitchPreference](../components/switchpreference) | Switch component based on BasicComponent | Setting switches, feature enabling |
5353
| [CheckboxPreference](../components/checkboxpreference) | Checkbox component based on BasicComponent | Multiple selection, terms agreement |
5454
| [RadioButtonPreference](../components/radiobuttonpreference) | Radio button component based on BasicComponent | Exclusive choices, option selection |
55+
| [SliderPreference](../components/sliderpreference) | Slider component based on BasicComponent | Value adjustment, volume/brightness |
56+
| [RangeSliderPreference](../components/rangesliderpreference) | Range slider component based on BasicComponent | Range selection, price filter |
5557
| [OverlayListPopup](../components/overlaylistpopup) | List popup component based on BasicComponent (uses MiuixPopupUtils; requires `Scaffold`) | Option selection, feature list |
5658
| [OverlayCascadingListPopup](../components/overlaycascadinglistpopup) | Two-level cascading list popup (uses MiuixPopupUtils; requires `Scaffold`) | Submenus, grouped action panels |
5759
| [OverlayDropdownPreference](../components/overlaydropdownpreference) | Dropdown selector based on BasicComponent (uses MiuixPopupUtils; requires `Scaffold`) | Option selection, feature list |
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# RangeSliderPreference
2+
3+
`RangeSliderPreference` is a preference component in Miuix that combines a title/summary with a range slider control. The range slider is placed in the bottom action area of the `BasicComponent`, making it ideal for settings screens where users need to select a range of values such as price filters, frequency bands, or dual-threshold controls.
4+
5+
## Import
6+
7+
```kotlin
8+
import top.yukonga.miuix.kmp.preference.RangeSliderPreference
9+
```
10+
11+
## Basic Usage
12+
13+
```kotlin
14+
var rangeValue by remember { mutableStateOf(0.2f..0.8f) }
15+
16+
RangeSliderPreference(
17+
value = rangeValue,
18+
onValueChange = { rangeValue = it },
19+
title = "Range Selection"
20+
)
21+
```
22+
23+
## With Summary
24+
25+
```kotlin
26+
var priceRange by remember { mutableStateOf(100f..500f) }
27+
28+
RangeSliderPreference(
29+
value = priceRange,
30+
onValueChange = { priceRange = it },
31+
title = "Price Range",
32+
summary = "$${priceRange.start.roundToInt()} - $${priceRange.endInclusive.roundToInt()}",
33+
valueRange = 0f..1000f
34+
)
35+
```
36+
37+
## Component States
38+
39+
### Disabled State
40+
41+
```kotlin
42+
var rangeValue by remember { mutableStateOf(0.3f..0.7f) }
43+
44+
RangeSliderPreference(
45+
value = rangeValue,
46+
onValueChange = { rangeValue = it },
47+
title = "Disabled Range",
48+
summary = "This range slider is currently unavailable",
49+
enabled = false
50+
)
51+
```
52+
53+
## Properties
54+
55+
### RangeSliderPreference Properties
56+
57+
| Property Name | Type | Description | Default Value | Required |
58+
| --------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------- | -------- |
59+
| value | ClosedFloatingPointRange\<Float\> | Current values of the range slider. If either value is outside of valueRange, it will be coerced | - | Yes |
60+
| onValueChange | (ClosedFloatingPointRange\<Float\>) -> Unit | Lambda in which values should be updated | - | Yes |
61+
| title | String? | Title of the preference | null | No |
62+
| modifier | Modifier | Modifier applied to the component | Modifier | No |
63+
| titleColor | BasicComponentColors | Title text color configuration | BasicComponentDefaults.titleColor() | No |
64+
| summary | String? | Summary description | null | No |
65+
| summaryColor | BasicComponentColors | Summary text color configuration | BasicComponentDefaults.summaryColor() | No |
66+
| startAction | @Composable (() -> Unit)? | Custom start side content | null | No |
67+
| valueText | String? | Current slider value text displayed in the end area with summary-style formatting. Rendered inside the Row layout with center-vertical alignment and weight | null | No |
68+
| endActions | @Composable (RowScope.() -> Unit)? | Custom end side content, rendered after valueText within the same Row | null | No |
69+
| bottomAction | @Composable (() -> Unit)? | Custom content at the top of the bottom area, above the range slider | null | No |
70+
| onClick | (() -> Unit)? | Callback triggered on click. When non-null, an arrow icon is displayed in the end area | null | No |
71+
| holdDownState | Boolean | Whether the component is in the pressed state | false | No |
72+
| enabled | Boolean | Whether the preference is enabled | true | No |
73+
| valueRange | ClosedFloatingPointRange\<Float\> | Range of values that range slider values can take. Passed value will be coerced to this range | 0f..1f | No |
74+
| steps | Int | Amount of discrete allowable values. If 0, the slider will behave continuously. Must not be negative | 0 | No |
75+
| onValueChangeFinished | (() -> Unit)? | Called when value change has ended | null | No |
76+
| sliderHeight | Dp | Height of the range slider | SliderDefaults.MinHeight | No |
77+
| sliderColors | SliderColors | Color configuration of the range slider | SliderDefaults.sliderColors() | No |
78+
| hapticEffect | SliderDefaults.SliderHapticEffect | Type of haptic feedback | SliderDefaults.DefaultHapticEffect | No |
79+
| showKeyPoints | Boolean | Whether to show key point indicators on the slider. Only works when keyPoints is not null | false | No |
80+
| keyPoints | List\<Float\>? | Custom key point values to display on the slider. If null, uses step positions from steps parameter. Values should be within valueRange | null | No |
81+
| magnetThreshold | Float | Magnetic snap threshold as a fraction (0.0 to 1.0). When slider value is within this distance from a key point, it will snap to that point. Only applies when keyPoints is set | 0.02f | No |
82+
| insideMargin | PaddingValues | Internal content padding | BasicComponentDefaults.InsideMargin | No |
83+
84+
## Advanced Usage
85+
86+
### Price Range Filter
87+
88+
```kotlin
89+
var priceRange by remember { mutableStateOf(100f..500f) }
90+
91+
RangeSliderPreference(
92+
value = priceRange,
93+
onValueChange = { priceRange = it },
94+
title = "Price Filter",
95+
summary = "$${priceRange.start.roundToInt()} - $${priceRange.endInclusive.roundToInt()}",
96+
valueRange = 0f..1000f,
97+
steps = 99
98+
)
99+
```
100+
101+
### With Start Icon
102+
103+
```kotlin
104+
var frequencyRange by remember { mutableStateOf(20f..20000f) }
105+
106+
RangeSliderPreference(
107+
value = frequencyRange,
108+
onValueChange = { frequencyRange = it },
109+
title = "Frequency Range",
110+
summary = "${frequencyRange.start.roundToInt()}Hz - ${frequencyRange.endInclusive.roundToInt()}Hz",
111+
startAction = {
112+
Icon(
113+
imageVector = MiuixIcons.Basic.Audio,
114+
contentDescription = "Frequency Icon",
115+
tint = MiuixTheme.colorScheme.onBackground,
116+
modifier = Modifier.padding(end = 16.dp)
117+
)
118+
},
119+
valueRange = 20f..20000f,
120+
showKeyPoints = true,
121+
keyPoints = listOf(20f, 100f, 1000f, 5000f, 10000f, 20000f)
122+
)
123+
```
124+
125+
### With Custom Key Points
126+
127+
```kotlin
128+
var range by remember { mutableStateOf(20f..80f) }
129+
130+
RangeSliderPreference(
131+
value = range,
132+
onValueChange = { range = it },
133+
title = "Custom Range",
134+
summary = "${range.start.roundToInt()}% - ${range.endInclusive.roundToInt()}%",
135+
valueRange = 0f..100f,
136+
showKeyPoints = true,
137+
keyPoints = listOf(0f, 20f, 40f, 60f, 80f, 100f),
138+
magnetThreshold = 0.03f
139+
)
140+
```

0 commit comments

Comments
 (0)