1
1
package io.monstarlab.mosaic.features
2
2
3
+ import androidx.compose.animation.animateColor
4
+ import androidx.compose.animation.core.LinearEasing
5
+ import androidx.compose.animation.core.RepeatMode
6
+ import androidx.compose.animation.core.animateFloat
7
+ import androidx.compose.animation.core.infiniteRepeatable
8
+ import androidx.compose.animation.core.rememberInfiniteTransition
9
+ import androidx.compose.animation.core.tween
3
10
import androidx.compose.foundation.background
4
11
import androidx.compose.foundation.layout.Arrangement
5
12
import androidx.compose.foundation.layout.Box
6
13
import androidx.compose.foundation.layout.Column
7
14
import androidx.compose.foundation.layout.Row
15
+ import androidx.compose.foundation.layout.Spacer
16
+ import androidx.compose.foundation.layout.fillMaxWidth
17
+ import androidx.compose.foundation.layout.height
8
18
import androidx.compose.foundation.layout.padding
9
19
import androidx.compose.foundation.layout.size
10
20
import androidx.compose.foundation.shape.CircleShape
21
+ import androidx.compose.foundation.shape.RoundedCornerShape
22
+ import androidx.compose.material3.MaterialTheme
11
23
import androidx.compose.material3.Scaffold
24
+ import androidx.compose.material3.Switch
12
25
import androidx.compose.material3.Text
13
26
import androidx.compose.runtime.Composable
14
27
import androidx.compose.runtime.getValue
15
28
import androidx.compose.runtime.mutableFloatStateOf
29
+ import androidx.compose.runtime.mutableStateOf
16
30
import androidx.compose.runtime.remember
17
31
import androidx.compose.runtime.setValue
32
+ import androidx.compose.ui.Alignment
18
33
import androidx.compose.ui.Modifier
34
+ import androidx.compose.ui.draw.clip
35
+ import androidx.compose.ui.draw.rotate
19
36
import androidx.compose.ui.graphics.Color
37
+ import androidx.compose.ui.text.style.TextAlign
20
38
import androidx.compose.ui.tooling.preview.Preview
21
39
import androidx.compose.ui.unit.dp
22
40
import io.monstarlab.mosaic.slider.Slider
@@ -41,99 +59,147 @@ fun SliderDemo() = Scaffold(modifier = Modifier) {
41
59
onValueChange = { materialSliderValue = it },
42
60
valueRange = 0f .. 100f ,
43
61
)
44
- Text (text = materialSliderValue.toString())
45
62
46
- MosaicSliderDemo (
47
- label = " Linear division strategy" ,
48
- range = 0f .. 1000f ,
49
- valuesDistribution = SliderValueDistribution .Linear ,
50
- disabledRange = 0f .. 500f ,
63
+ MosaicSliderDemo ()
64
+ }
65
+ }
66
+
67
+ @Composable
68
+ fun MosaicSliderDemo () {
69
+ Column {
70
+ val colors = SliderColors (
71
+ activeTrackColor = Color .Black ,
72
+ disabledRangeTrackColor = Color .Red ,
73
+ thumbColor = Color .Yellow ,
51
74
)
52
- MosaicSliderDemo (
53
- label = " Parabolic" ,
54
- range = 0f .. 1000f ,
55
- disabledRange = 800f .. 1000f ,
56
- valuesDistribution = SliderValueDistribution .parabolic(
75
+ var enabled by remember { mutableStateOf(true ) }
76
+ var isCustom by remember { mutableStateOf(false ) }
77
+ var linearDistribution by remember { mutableStateOf(false ) }
78
+
79
+ val modifier = if (isCustom) {
80
+ Modifier
81
+ .clip(RoundedCornerShape (16 .dp))
82
+ .height(15 .dp)
83
+ } else {
84
+ Modifier
85
+ }
86
+
87
+ val parabolic: SliderValueDistribution = remember {
88
+ SliderValueDistribution .parabolic(
57
89
a = (1000 - 100 * 0.1f ) / (1000 * 1000 ),
58
90
b = 0.1f ,
59
91
c = 1f ,
60
- ),
92
+ )
93
+ }
94
+
95
+ val state = rememberSliderState(
96
+ value = 500f ,
97
+ valueDistribution = if (linearDistribution) {
98
+ SliderValueDistribution .Linear
99
+ } else {
100
+ parabolic
101
+ },
102
+ range = 0f .. 1000f ,
61
103
)
62
104
63
105
Slider (
64
- state = rememberSliderState(value = 0.5f ),
65
- colors = SliderColors (Color .Magenta , Color .Red ),
106
+ modifier = modifier,
107
+ enabled = enabled,
108
+ state = state,
109
+ colors = colors,
110
+ thumb = {
111
+ if (isCustom) {
112
+ val transition = rememberInfiniteTransition(label = " " )
113
+ val color = transition.animateColor(
114
+ initialValue = Color .Red ,
115
+ targetValue = Color .Green ,
116
+ animationSpec = infiniteRepeatable(
117
+ animation = tween(1000 , easing = LinearEasing ),
118
+ repeatMode = RepeatMode .Reverse ,
119
+ ),
120
+ label = " " ,
121
+ )
122
+
123
+ val rotation = transition.animateFloat(
124
+ initialValue = 0f ,
125
+ targetValue = 360f ,
126
+ animationSpec = infiniteRepeatable(
127
+ tween(5000 , easing = LinearEasing ),
128
+ repeatMode = RepeatMode .Restart ,
129
+ ),
130
+ label = " " ,
131
+ )
132
+
133
+ Box (
134
+ modifier = Modifier
135
+ .rotate(rotation.value)
136
+ .size(48 .dp)
137
+ .background(color.value),
138
+ )
139
+ } else {
140
+ Box (
141
+ modifier = Modifier
142
+ .size(16 .dp)
143
+ .background(colors.thumbColor(enabled), CircleShape ),
144
+ )
145
+ }
146
+ },
147
+
148
+ )
149
+
150
+ Text (
151
+ text = " Current value: ${state.value.roundToInt()} " ,
152
+ modifier = Modifier .align(Alignment .CenterHorizontally ),
153
+ textAlign = TextAlign .Center ,
154
+ style = MaterialTheme .typography.bodyLarge,
155
+ )
156
+
157
+ Row (
158
+ horizontalArrangement = Arrangement .SpaceBetween ,
159
+ modifier = Modifier
160
+ .fillMaxWidth()
161
+ .padding(top = 32 .dp),
66
162
) {
67
- Box (
68
- modifier = Modifier
69
- .size( 32 .dp)
70
- .background( Color . Black ) ,
163
+ LabeledSwitch (
164
+ label = " Slider enabled " ,
165
+ checked = enabled,
166
+ onValueChange = { enabled = it } ,
71
167
)
72
- }
73
168
74
- Slider (
75
- state = rememberSliderState(value = 0.5f ),
76
- colors = SliderColors (Color .Black ),
77
- enabled = true ,
78
- ) {
79
- Box (modifier = Modifier .background(Color .Red , shape = CircleShape ).size(32 .dp))
169
+ LabeledSwitch (
170
+ label = " Customise" ,
171
+ checked = isCustom,
172
+ onValueChange = { isCustom = it },
173
+ )
80
174
}
81
175
82
- var v by remember { mutableFloatStateOf(0.5f ) }
83
- Slider (
84
- value = v,
85
- onValueChange = { v = it },
86
- colors = SliderColors (Color .Black ),
87
- enabled = false ,
88
- ) {
89
- Box (modifier = Modifier .background(Color .Red , shape = CircleShape ).size(32 .dp))
90
- }
176
+ LabeledSwitch (
177
+ label = " Use linear distribution or parabolic" ,
178
+ checked = linearDistribution,
179
+ onValueChange = { linearDistribution = it },
180
+ modifier = Modifier .align(Alignment .CenterHorizontally ),
181
+ )
91
182
}
92
183
}
93
184
94
185
@Composable
95
- fun MosaicSliderDemo (
186
+ private fun LabeledSwitch (
96
187
label : String ,
97
- range : ClosedFloatingPointRange < Float > ,
98
- valuesDistribution : SliderValueDistribution ,
188
+ checked : Boolean ,
189
+ onValueChange : ( Boolean ) -> Unit ,
99
190
modifier : Modifier = Modifier ,
100
- disabledRange : ClosedFloatingPointRange <Float > = 0f..0f,
101
191
) {
102
- Column (modifier) {
103
- Text (text = label)
192
+ Column (
193
+ modifier = modifier,
194
+ horizontalAlignment = Alignment .CenterHorizontally ,
104
195
105
- var value by remember { mutableFloatStateOf(50f ) }
106
- Row (
107
- horizontalArrangement = Arrangement .Start ,
108
- modifier = Modifier ,
109
- ) {
110
- Text (
111
- text = range.start.toString(),
112
- modifier = Modifier .weight(0.2f ),
113
- )
114
- Slider (
115
- modifier = Modifier .weight(0.8f ),
116
- value = value,
117
- onValueChange = { value = it },
118
- colors = SliderColors (Color .Black , disabledRangeTrackColor = Color .Red ),
119
- range = range,
120
- valueDistribution = valuesDistribution,
121
- disabledRange = disabledRange,
122
- thumb = {
123
- Box (
124
- modifier = Modifier
125
- .size(32 .dp)
126
- .background(Color .Yellow ),
127
- ) {
128
- Text (text = value.roundToInt().toString())
129
- }
130
- },
131
- )
132
- Text (
133
- text = range.endInclusive.toString(),
134
- modifier = Modifier .weight(0.2f ),
135
- )
136
- }
196
+ ) {
197
+ Text (text = label, textAlign = TextAlign .Center )
198
+ Spacer (modifier = Modifier .height(3 .dp))
199
+ Switch (
200
+ checked = checked,
201
+ onCheckedChange = onValueChange,
202
+ )
137
203
}
138
204
}
139
205
0 commit comments