Skip to content

Commit 64e550c

Browse files
authored
Merge pull request #101 from Konyaco/separate_slider
Seperate slider to `Slider` and `BasicSlider`
2 parents d6335ae + 5186f6d commit 64e550c

File tree

3 files changed

+148
-41
lines changed

3 files changed

+148
-41
lines changed

fluent/src/commonMain/kotlin/com/konyaco/fluent/component/ColorPicker.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ fun ColorPicker(
114114
) {}
115115
}
116116
val (hug, saturation, _) = spectrumColor.value.hsv()
117-
Slider(
117+
BasicSlider(
118118
modifier = Modifier.padding(top = 21.dp).width(312.dp).height(32.dp),
119119
value = value,
120120
onValueChange = {
@@ -151,7 +151,7 @@ fun ColorPicker(
151151
}
152152
)
153153
if (alphaEnabled) {
154-
Slider(
154+
BasicSlider(
155155
modifier = Modifier.width(312.dp),
156156
value = alpha,
157157
onValueChange = {

fluent/src/commonMain/kotlin/com/konyaco/fluent/component/Slider.kt

Lines changed: 68 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -63,40 +63,85 @@ fun Slider(
6363
enabled: Boolean = true,
6464
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
6565
steps: Int = 0,
66+
snap: Boolean = steps != 0,
67+
showTickMark: Boolean = steps != 0,
6668
onValueChangeFinished: ((Float) -> Unit)? = null,
69+
tooltipContent: @Composable (SliderState) -> Unit = { SliderDefaults.Tooltip(it, snap = snap) },
6770
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
6871
) {
69-
Slider(
72+
BasicSlider(
7073
value = value,
7174
onValueChange = onValueChange,
7275
modifier = modifier,
7376
enabled = enabled,
7477
valueRange = valueRange,
7578
steps = steps,
79+
snap = snap,
7680
onValueChangeFinished = onValueChangeFinished,
7781
interactionSource = interactionSource,
78-
rail = { state -> SliderDefaults.Rail(state, enabled = enabled) },
79-
track = { state -> SliderDefaults.Track(state, enabled = enabled) },
80-
thumb = { state -> SliderDefaults.Thumb(state, enabled = enabled) }
82+
rail = { state ->
83+
SliderDefaults.Rail(
84+
state = state,
85+
enabled = enabled,
86+
showTick = showTickMark
87+
)
88+
},
89+
track = { state ->
90+
SliderDefaults.Track(state, enabled = enabled)
91+
},
92+
thumb = { state ->
93+
SliderDefaults.Thumb(state, enabled = enabled, label = tooltipContent)
94+
}
8195
)
8296
}
8397

8498
@Composable
8599
fun Slider(
100+
state: SliderState,
101+
modifier: Modifier = Modifier,
102+
enabled: Boolean = true,
103+
showTickMark: Boolean = state.steps != 0,
104+
tooltipContent: @Composable (SliderState) -> Unit = { SliderDefaults.Tooltip(it, snap = state.snap) },
105+
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
106+
) {
107+
BasicSlider(
108+
state = state,
109+
modifier = modifier,
110+
enabled = enabled,
111+
interactionSource = interactionSource,
112+
rail = { state ->
113+
SliderDefaults.Rail(
114+
state = state,
115+
enabled = enabled,
116+
showTick = showTickMark
117+
)
118+
},
119+
track = { state ->
120+
SliderDefaults.Track(state, enabled = enabled)
121+
},
122+
thumb = { state ->
123+
SliderDefaults.Thumb(state, enabled = enabled, label = tooltipContent)
124+
}
125+
)
126+
}
127+
128+
@Composable
129+
fun BasicSlider(
86130
value: Float,
87131
onValueChange: (Float) -> Unit,
88132
modifier: Modifier = Modifier,
89133
enabled: Boolean = true,
90134
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
91135
steps: Int = 0,
136+
snap: Boolean = steps != 0,
92137
onValueChangeFinished: ((Float) -> Unit)? = null,
93138
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
94139
rail: @Composable (SliderState) -> Unit,
95140
track: @Composable (SliderState) -> Unit,
96141
thumb: @Composable (SliderState) -> Unit,
97142
) {
98143
val state =
99-
remember(steps, valueRange) { SliderState(value, steps, onValueChangeFinished, valueRange) }
144+
remember(steps, valueRange) { SliderState(value, steps, snap, onValueChangeFinished, valueRange) }
100145
state.value = value
101146
state.onValueChangeFinished = onValueChangeFinished
102147
state.onValueChange = onValueChange
@@ -113,25 +158,7 @@ fun Slider(
113158
}
114159

115160
@Composable
116-
fun Slider(
117-
state: SliderState,
118-
modifier: Modifier = Modifier,
119-
enabled: Boolean = true,
120-
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
121-
) {
122-
SliderImpl(
123-
modifier = modifier,
124-
state = state,
125-
enabled = enabled,
126-
interactionSource = interactionSource,
127-
rail = { state -> SliderDefaults.Rail(state, enabled = enabled) },
128-
track = { state -> SliderDefaults.Track(state, enabled = enabled) },
129-
thumb = { state -> SliderDefaults.Thumb(state, enabled = enabled) }
130-
)
131-
}
132-
133-
@Composable
134-
fun Slider(
161+
fun BasicSlider(
135162
state: SliderState,
136163
modifier: Modifier = Modifier,
137164
enabled: Boolean = true,
@@ -233,6 +260,7 @@ private fun SliderImpl(
233260
class SliderState(
234261
value: Float = 0f,
235262
val steps: Int = 0,
263+
val snap: Boolean = steps != 0,
236264
var onValueChangeFinished: ((Float) -> Unit)? = null,
237265
val valueRange: ClosedFloatingPointRange<Float>
238266
) {
@@ -301,10 +329,15 @@ class SliderState(
301329
// Snap
302330
// TODO: Add snap animation, maybe we should use anchoredDraggable?
303331
val currentValue = this.value
304-
val nearestValue = snapToNearestTickValue(currentValue)
305-
val fraction = valueToFraction(nearestValue, this.valueRange)
306-
this.value = nearestValue
307-
setRawFraction(fraction, width, density)
332+
if (this.snap) {
333+
val nearestValue = snapToNearestTickValue(currentValue)
334+
val fraction = valueToFraction(nearestValue, this.valueRange)
335+
this.value = nearestValue
336+
setRawFraction(fraction, width, density)
337+
} else {
338+
val fraction = valueToFraction(currentValue, this.valueRange)
339+
setRawFraction(fraction, width, density)
340+
}
308341
}
309342

310343
this.onValueChangeFinished?.invoke(this.value)
@@ -316,6 +349,12 @@ class SliderState(
316349
.map { lerp(this.valueRange.start, this.valueRange.endInclusive, it) }
317350
.minBy { abs(it - value) }
318351
}
352+
353+
fun nearestValue(): Float {
354+
return this.stepFractions
355+
.map { lerp(this.valueRange.start, this.valueRange.endInclusive, it) }
356+
.minBy { abs(it - value) }
357+
}
319358
}
320359

321360
private fun getStepFractions(steps: Int): FloatArray {
@@ -561,7 +600,7 @@ object SliderDefaults {
561600
}
562601

563602
@Composable
564-
fun Tooltip(state: SliderState, snap: Boolean = state.steps != 0) {
603+
fun Tooltip(state: SliderState, snap: Boolean = state.snap) {
565604
Text(
566605
if (snap) state.snapToNearestTickValue(state.value).toString()
567606
else state.value.toString()

gallery/src/commonMain/kotlin/com/konyaco/fluent/gallery/screen/basicinput/SliderScreen.kt

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
package com.konyaco.fluent.gallery.screen.basicinput
22

3-
import androidx.compose.foundation.layout.width
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.*
5+
import androidx.compose.foundation.shape.CircleShape
46
import androidx.compose.runtime.Composable
57
import androidx.compose.runtime.mutableStateOf
68
import androidx.compose.runtime.remember
79
import androidx.compose.ui.Modifier
10+
import androidx.compose.ui.draw.clip
11+
import androidx.compose.ui.graphics.Brush
12+
import androidx.compose.ui.graphics.Color
813
import androidx.compose.ui.unit.dp
9-
import com.konyaco.fluent.component.Slider
10-
import com.konyaco.fluent.component.SliderState
11-
import com.konyaco.fluent.component.Text
14+
import com.konyaco.fluent.component.*
1215
import com.konyaco.fluent.gallery.annotation.Component
1316
import com.konyaco.fluent.gallery.annotation.Sample
1417
import com.konyaco.fluent.gallery.component.ComponentPagePath
1518
import com.konyaco.fluent.gallery.component.GalleryPage
1619
import com.konyaco.fluent.gallery.component.TodoComponent
1720
import com.konyaco.fluent.source.generated.FluentSourceFile
21+
import kotlin.math.roundToInt
1822

1923
@Component(
2024
index = 12,
@@ -38,21 +42,39 @@ fun SliderScreen() {
3842
}
3943
)
4044

45+
Section(
46+
title = "A Slider with tick marks.",
47+
sourceCode = sourceCodeOfSliderTickMarkSample,
48+
content = { SliderTickMarkSample() }
49+
)
50+
4151
val (confirmValue, setConfirmValue) = remember { mutableStateOf(0f) }
42-
val stepsSliderState = remember { SliderState(0f, 4, setConfirmValue, 0f..100f) }
52+
val stepsSliderState = remember {
53+
SliderState(
54+
value = 0f,
55+
steps = 4,
56+
snap = true,
57+
onValueChangeFinished = setConfirmValue,
58+
valueRange = 0f..100f
59+
)
60+
}
4361

4462
Section(
45-
title = "A Slider with range, steps and tick marks.",
63+
title = "A Slider with custom tooltip content and snaps to tickmark.",
4664
sourceCode = sourceCodeOfSliderStepsSample,
4765
content = { SliderStepsSample(stepsSliderState) },
4866
output = {
4967
Text("value: ${stepsSliderState.value}")
5068
Text("confirmValue: $confirmValue")
5169
}
5270
)
53-
/*Section("A Slider with tick marks.", "") {
54-
TodoComponent()
55-
}*/
71+
72+
Section(
73+
title = "Customize slider by using BasicSlider.",
74+
sourceCode = sourceCodeOfBasicSliderSample,
75+
content = { BasicSliderSample(remember { SliderState(valueRange = 0f..100f) }) },
76+
)
77+
5678
Section("A vertical slider with range and tick marks specified.", "") {
5779
TodoComponent()
5880
}
@@ -69,11 +91,57 @@ private fun SliderSample(value: Float, onValueChanged: (Float) -> Unit) {
6991
)
7092
}
7193

94+
@Sample
95+
@Composable
96+
private fun SliderTickMarkSample() {
97+
val (value, setValue) = remember { mutableStateOf(0f) }
98+
Slider(
99+
modifier = Modifier.width(200.dp),
100+
valueRange = 0f..100f,
101+
value = value,
102+
steps = 5,
103+
showTickMark = true,
104+
snap = false,
105+
onValueChange = setValue,
106+
)
107+
}
108+
72109
@Sample
73110
@Composable
74111
private fun SliderStepsSample(state: SliderState) {
75112
Slider(
76113
modifier = Modifier.width(200.dp),
77-
state = state
114+
state = state,
115+
tooltipContent = {
116+
Text(it.nearestValue().roundToInt().toString())
117+
},
118+
)
119+
}
120+
121+
@Sample
122+
@Composable
123+
private fun BasicSliderSample(state: SliderState) {
124+
BasicSlider(
125+
modifier = Modifier.width(200.dp),
126+
state = state,
127+
rail = {
128+
Box(
129+
modifier = Modifier
130+
.fillMaxWidth()
131+
.requiredHeight(12.dp)
132+
.clip(CircleShape)
133+
.background(
134+
Brush.horizontalGradient(
135+
0f to Color.White.copy(0f),
136+
1f to Color.Red.copy(1f)
137+
)
138+
)
139+
)
140+
},
141+
track = {
142+
},
143+
thumb = {
144+
SliderDefaults.Thumb(state)
145+
}
78146
)
79147
}

0 commit comments

Comments
 (0)