I want to show a slider that can be either updated by the user using drag/drop, or updated from the server in real-time.
When the user finishes their dragging gesture, I want to send the final value to the server.
My initial attempt is:
@Composable
fun LightView(
channel: UiChannel,
onDimmerChanged: (Float) -> Unit
) {
val sliderValue = channel....
Slider(value = sliderValue, onValueChange = onDimmerChanged)
}
And the onDimmerChanged method comes from my ViewModel, which updates the server value.
It works well, however onValueChange is called for each move, which bombards the server with unneeded requests.
I tried to create a custom slider:
@Composable
fun LightView(
channel: UiChannel,
onDimmerChanged: (Float) -> Unit
) {
val sliderValue = channel....
Slider(initialValue = sliderValue, valueSetter = onDimmerChanged)
}
@Composable
fun Slider(initialValue: Float, valueSetter: (Float) -> Unit) {
var value by remember { mutableStateOf(initialValue) }
Slider(
value = value,
onValueChange = { value = it },
onValueChangeFinished = { valueSetter(value) }
)
}
It works well on the app side, and the value is only sent once, when the user stops dragging.
However, it fails updating the view when there is an update from the server. I'm guessing this has something to do with remember. So I tried without remember:
@Composable
fun Slider(initialValue: Float, valueSetter: (Float) -> Unit) {
var value by mutableStateOf(initialValue)
Slider(
value = value,
onValueChange = { value = it },
onValueChangeFinished = { valueSetter(value) }
)
}
This time the view updates correctly when the value is updated by the server, but does not move anymore when the user drags the slider.
I'm sure I'm missing something with state hoisting and all, but I can't figure out what.
So my final question: how to create a Slider that can be either updated by the ViewModel, or by the user, and notifies the ViewModel of a new value only when the user finishes dragging?
EDIT:
I also tried what @CommonsWare suggested:
@Composable
fun LightView(
channel: UiChannel,
onDimmerChanged: (Float) -> Unit
) {
val sliderValue = channel....
val sliderState = mutableStateOf(sliderValue)
Slider(state = sliderState, valueSet = { onDimmerChanged(sliderState.value) })
}
@Composable
fun Slider(state: MutableState<Float>, valueSet: () -> Unit) {
Slider(
value = state.value,
onValueChange = { state.value = it },
onValueChangeFinished = valueSet
)
}
And it does not work either. When using drag and drop, sliderState is correctly updated, and onDimmerChanged() is called with the correct value. But for some reason, when tapping of the sliding (rather than sliding), valueSet is called and sliderState.value does not contain the correct value. I don't understand where this value comes from.