Skip to content

Commit ef58dbc

Browse files
committed
unstable: Use new UpdateFunc API instead of animationFrame
Source-Commit: d51588082b8cfd15e711acd1e6dad102221ff0a5
1 parent e209426 commit ef58dbc

File tree

2 files changed

+19
-36
lines changed

2 files changed

+19
-36
lines changed

unstable/layoutdsl/src/main/kotlin/gg/essential/elementa/util/elementaExtensions.kt

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,38 +27,19 @@ inline fun <reified T : Effect> UIComponent.getOrPut(init: () -> T) =
2727

2828
fun <T> UIComponent.pollingState(initialValue: T? = null, getter: () -> T): State<T> {
2929
val state = BasicState(initialValue ?: getter())
30-
enableEffect(object : Effect() {
31-
override fun animationFrame() {
32-
state.set(getter())
33-
}
34-
})
30+
addUpdateFunc { _, _ -> state.set(getter()) }
3531
return state
3632
}
3733

3834
fun <T> UIComponent.pollingStateV2(initialValue: T? = null, getter: () -> T): StateV2<T> {
3935
val state = mutableStateOf(initialValue ?: getter())
40-
enableEffect(object : Effect() {
41-
override fun animationFrame() {
42-
state.set(getter())
43-
}
44-
})
36+
addUpdateFunc { _, _ -> state.set(getter()) }
4537
return state
4638
}
4739

40+
@Deprecated("pollingState is now layout-safe by default", ReplaceWith("pollingStateV2(initialValue, getter)"))
4841
fun <T> UIComponent.layoutSafePollingState(initialValue: T? = null, getter: () -> T): StateV2<T> {
49-
val state = mutableStateOf(initialValue ?: getter())
50-
enableEffect(object : Effect() {
51-
override fun animationFrame() {
52-
val window = Window.of(boundComponent)
53-
// Start one-shot timer which will trigger immediately once the current `animationFrame` is complete
54-
window.startTimer(0) { timerId ->
55-
window.stopTimer(timerId)
56-
57-
state.set(getter())
58-
}
59-
}
60-
})
61-
return state
42+
return pollingStateV2(initialValue, getter)
6243
}
6344

6445
/**

unstable/statev2/src/main/kotlin/gg/essential/elementa/state/v2/animate.kt

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package gg.essential.elementa.state.v2
22

33
import gg.essential.elementa.UIComponent
4+
import gg.essential.elementa.components.UpdateFunc
45
import gg.essential.elementa.components.Window
56
import gg.essential.elementa.constraints.animation.AnimationStrategy
67
import gg.essential.elementa.constraints.animation.Animations
@@ -34,34 +35,36 @@ fun State<State<Float>>.animateTransitions(
3435
}
3536

3637
private class AnimationDriver(
37-
private val driver: State<State<Float>>,
38+
driver: State<State<Float>>,
3839
private val resultStateWeakReference: WeakReference<MutableState<State<Float>>>,
3940
private val duration: Float,
4041
private val animationStrategy: AnimationStrategy
41-
): Effect() {
42+
): Effect(), UpdateFunc {
4243
private val animationEventList = mutableListOf<AnimationEvent>()
43-
private lateinit var driverEffect: () -> Unit
44-
private var durationFrames = 1
44+
private val driverEffect: () -> Unit
4545

4646
private var previousDriverStateValue = stateOf(0f)
4747
private var isDestroying = false
4848

49-
override fun setup() {
49+
init {
5050
previousDriverStateValue = driver.getUntracked()
51-
durationFrames = (Window.of(boundComponent).animationFPS * duration).toInt().coerceAtLeast(1)
5251
driverEffect = driver.onChange(ReferenceHolder.Weak) { input ->
53-
animationEventList.add(AnimationEvent(previousDriverStateValue, input, durationFrames))
52+
if (animationEventList.isEmpty()) {
53+
addUpdateFunc(this@AnimationDriver)
54+
}
55+
animationEventList.add(AnimationEvent(previousDriverStateValue, input))
5456
previousDriverStateValue = input
5557
}
5658
}
5759

58-
override fun animationFrame() {
60+
override fun invoke(dt: Float, dtMs: Int) {
5961
val resultState = resultStateWeakReference.get()
6062
if (resultState == null) {
6163
destroy()
6264
} else {
63-
animationEventList.forEach { it.age++ }
64-
animationEventList.removeIf { it.age >= durationFrames }
65+
animationEventList.forEach { it.age += dt }
66+
animationEventList.removeIf { it.age >= duration }
67+
if (animationEventList.isEmpty()) removeUpdateFunc(this@AnimationDriver)
6568
resultState.set(State { getAnimationValue() })
6669
}
6770
}
@@ -83,7 +86,7 @@ private class AnimationDriver(
8386
}
8487

8588
return animationEventList.fold(animationEventList.first().startValue()) { acc, event ->
86-
val linearProgress = event.age.toFloat() / event.duration.toFloat()
89+
val linearProgress = event.age / duration
8790
val animatedProgress = animationStrategy.getValue(linearProgress)
8891
acc + ((event.endValue() - acc) * animatedProgress)
8992
}
@@ -92,8 +95,7 @@ private class AnimationDriver(
9295
private data class AnimationEvent(
9396
val startValue: State<Float>,
9497
val endValue: State<Float>,
95-
val duration: Int,
96-
var age: Int = 0,
98+
var age: Float = 0f,
9799
)
98100

99101
}

0 commit comments

Comments
 (0)