Skip to content

Commit e2a2b1c

Browse files
committed
feat: add view model properties
1 parent 3fdc43a commit e2a2b1c

30 files changed

+1247
-32
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.margelo.nitro.rive
2+
3+
import androidx.annotation.Keep
4+
import com.facebook.proguard.annotations.DoNotStrip
5+
import kotlinx.coroutines.CoroutineScope
6+
import kotlinx.coroutines.Job
7+
import kotlinx.coroutines.flow.Flow
8+
9+
@Keep
10+
@DoNotStrip
11+
interface BaseHybridViewModelProperty<T> {
12+
val scope: CoroutineScope?
13+
val job: Job?
14+
val listeners: MutableList<(T) -> Unit>
15+
16+
fun ensureValueListenerJob(valueFlow: Flow<T>, drop: Int = 0)
17+
fun onChanged(value: T)
18+
fun removeListeners()
19+
fun dispose()
20+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.margelo.nitro.rive
2+
3+
import androidx.annotation.Keep
4+
import com.facebook.proguard.annotations.DoNotStrip
5+
import kotlinx.coroutines.CoroutineScope
6+
import kotlinx.coroutines.Dispatchers
7+
import kotlinx.coroutines.Job
8+
import kotlinx.coroutines.cancel
9+
import kotlinx.coroutines.launch
10+
import kotlinx.coroutines.flow.Flow
11+
import kotlinx.coroutines.flow.drop
12+
13+
@Keep
14+
@DoNotStrip
15+
class BaseHybridViewModelPropertyImpl<T> : BaseHybridViewModelProperty<T> {
16+
override var scope: CoroutineScope? = null
17+
override var job: Job? = null
18+
override val listeners = mutableListOf<(T) -> Unit>()
19+
20+
override fun ensureValueListenerJob(valueFlow: Flow<T>, drop: Int) {
21+
if (scope == null) {
22+
scope = CoroutineScope(Dispatchers.Default)
23+
}
24+
if (job == null) {
25+
job = scope?.launch {
26+
valueFlow.drop(drop).collect { value ->
27+
onChanged(value)
28+
}
29+
}
30+
}
31+
}
32+
33+
override fun onChanged(value: T) {
34+
listeners.forEach { listener ->
35+
listener(value)
36+
}
37+
}
38+
39+
override fun removeListeners() {
40+
listeners.clear()
41+
job?.cancel()
42+
scope?.cancel()
43+
job = null
44+
scope = null
45+
}
46+
47+
override fun dispose() {
48+
removeListeners()
49+
}
50+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.margelo.nitro.rive
2+
3+
import androidx.annotation.Keep
4+
import app.rive.runtime.kotlin.core.ViewModelBooleanProperty
5+
import com.facebook.proguard.annotations.DoNotStrip
6+
7+
@Keep
8+
@DoNotStrip
9+
class HybridViewModelBooleanProperty(private val viewModelBoolean: ViewModelBooleanProperty) :
10+
HybridViewModelBooleanPropertySpec(),
11+
BaseHybridViewModelProperty<Boolean> by BaseHybridViewModelPropertyImpl() {
12+
override var value: Boolean
13+
get() = viewModelBoolean.value
14+
set(value) {
15+
viewModelBoolean.value = value
16+
}
17+
18+
override fun addListener(onChanged: (value: Boolean) -> Unit) {
19+
listeners.add(onChanged)
20+
ensureValueListenerJob(viewModelBoolean.valueFlow)
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.margelo.nitro.rive
2+
3+
import androidx.annotation.Keep
4+
import app.rive.runtime.kotlin.core.ViewModelColorProperty
5+
import com.facebook.proguard.annotations.DoNotStrip
6+
7+
@Keep
8+
@DoNotStrip
9+
class HybridViewModelColorProperty(private val viewModelColor: ViewModelColorProperty) :
10+
HybridViewModelColorPropertySpec(),
11+
BaseHybridViewModelProperty<Int> by BaseHybridViewModelPropertyImpl() {
12+
override var value: Double
13+
get() = viewModelColor.value.toDouble()
14+
set(value) {
15+
viewModelColor.value = value.toInt()
16+
}
17+
18+
override fun addListener(onChanged: (value: Double) -> Unit) {
19+
listeners.add { intValue: Int -> onChanged(intValue.toDouble()) }
20+
ensureValueListenerJob(viewModelColor.valueFlow)
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.margelo.nitro.rive
2+
3+
import androidx.annotation.Keep
4+
import app.rive.runtime.kotlin.core.ViewModelEnumProperty
5+
import com.facebook.proguard.annotations.DoNotStrip
6+
7+
@Keep
8+
@DoNotStrip
9+
class HybridViewModelEnumProperty(private val viewModelEnum: ViewModelEnumProperty) :
10+
HybridViewModelEnumPropertySpec(),
11+
BaseHybridViewModelProperty<String> by BaseHybridViewModelPropertyImpl() {
12+
override var value: String
13+
get() = viewModelEnum.value
14+
set(value) {
15+
viewModelEnum.value = value
16+
}
17+
18+
override fun addListener(onChanged: (value: String) -> Unit) {
19+
listeners.add(onChanged)
20+
ensureValueListenerJob(viewModelEnum.valueFlow)
21+
}
22+
}

android/src/main/java/com/margelo/nitro/rive/HybridViewModelInstance.kt

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,66 @@ package com.margelo.nitro.rive
22

33
import androidx.annotation.Keep
44
import app.rive.runtime.kotlin.core.ViewModelInstance
5+
import app.rive.runtime.kotlin.core.errors.ViewModelException
56
import com.facebook.proguard.annotations.DoNotStrip
67

78
@Keep
89
@DoNotStrip
910
class HybridViewModelInstance(val viewModelInstance: ViewModelInstance) : HybridViewModelInstanceSpec() {
1011
override val name: String
1112
get() = viewModelInstance.name
13+
14+
override fun numberProperty(path: String): HybridViewModelNumberPropertySpec? {
15+
try {
16+
val numberProper = viewModelInstance.getNumberProperty(path)
17+
return HybridViewModelNumberProperty(numberProper)
18+
} catch (e: ViewModelException) {
19+
return null
20+
}
21+
}
22+
23+
override fun stringProperty(path: String): HybridViewModelStringPropertySpec? {
24+
try {
25+
val stringProperty = viewModelInstance.getStringProperty(path)
26+
return HybridViewModelStringProperty(stringProperty)
27+
} catch (e: ViewModelException) {
28+
return null
29+
}
30+
}
31+
32+
override fun booleanProperty(path: String): HybridViewModelBooleanPropertySpec? {
33+
try {
34+
val booleanProperty = viewModelInstance.getBooleanProperty(path)
35+
return HybridViewModelBooleanProperty(booleanProperty)
36+
} catch (e: ViewModelException) {
37+
return null
38+
}
39+
}
40+
41+
override fun colorProperty(path: String): HybridViewModelColorPropertySpec? {
42+
try {
43+
val colorProperty = viewModelInstance.getColorProperty(path)
44+
return HybridViewModelColorProperty(colorProperty)
45+
} catch (e: ViewModelException) {
46+
return null
47+
}
48+
}
49+
50+
override fun enumProperty(path: String): HybridViewModelEnumPropertySpec? {
51+
try {
52+
val enumProperty = viewModelInstance.getEnumProperty(path)
53+
return HybridViewModelEnumProperty(enumProperty)
54+
} catch (e: ViewModelException) {
55+
return null
56+
}
57+
}
58+
59+
override fun triggerProperty(path: String): HybridViewModelTriggerPropertySpec? {
60+
try {
61+
val triggerProperty = viewModelInstance.getTriggerProperty(path)
62+
return HybridViewModelTriggerProperty(triggerProperty)
63+
} catch (e: ViewModelException) {
64+
return null
65+
}
66+
}
1267
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.margelo.nitro.rive
2+
3+
import androidx.annotation.Keep
4+
import app.rive.runtime.kotlin.core.ViewModelNumberProperty
5+
import com.facebook.proguard.annotations.DoNotStrip
6+
import kotlinx.coroutines.flow.map
7+
8+
@Keep
9+
@DoNotStrip
10+
class HybridViewModelNumberProperty(private val viewModelNumber: ViewModelNumberProperty) :
11+
HybridViewModelNumberPropertySpec(),
12+
BaseHybridViewModelProperty<Double> by BaseHybridViewModelPropertyImpl() {
13+
override var value: Double
14+
get() = viewModelNumber.value.toDouble()
15+
set(value) {
16+
viewModelNumber.value = value.toFloat()
17+
}
18+
19+
override fun addListener(onChanged: (value: Double) -> Unit) {
20+
listeners.add(onChanged)
21+
ensureValueListenerJob(viewModelNumber.valueFlow.map { it.toDouble() })
22+
}
23+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.margelo.nitro.rive
2+
3+
import androidx.annotation.Keep
4+
import app.rive.runtime.kotlin.core.ViewModelStringProperty
5+
import com.facebook.proguard.annotations.DoNotStrip
6+
7+
@Keep
8+
@DoNotStrip
9+
class HybridViewModelStringProperty(private val viewModelString: ViewModelStringProperty) :
10+
HybridViewModelStringPropertySpec(),
11+
BaseHybridViewModelProperty<String> by BaseHybridViewModelPropertyImpl() {
12+
override var value: String
13+
get() = viewModelString.value
14+
set(value) {
15+
viewModelString.value = value
16+
}
17+
18+
override fun addListener(onChanged: (value: String) -> Unit) {
19+
listeners.add(onChanged)
20+
ensureValueListenerJob(viewModelString.valueFlow)
21+
}
22+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.margelo.nitro.rive
2+
3+
import androidx.annotation.Keep
4+
import app.rive.runtime.kotlin.core.ViewModelTriggerProperty
5+
import com.facebook.proguard.annotations.DoNotStrip
6+
7+
@Keep
8+
@DoNotStrip
9+
class HybridViewModelTriggerProperty(private val viewModelTrigger: ViewModelTriggerProperty) :
10+
HybridViewModelTriggerPropertySpec(),
11+
BaseHybridViewModelProperty<ViewModelTriggerProperty.TriggerUnit> by BaseHybridViewModelPropertyImpl() {
12+
override fun trigger() {
13+
viewModelTrigger.trigger()
14+
}
15+
16+
override fun addListener(onChanged: () -> Unit) {
17+
listeners.add { _ -> onChanged() }
18+
// We drop the first value as a trigger has no initial value
19+
ensureValueListenerJob(viewModelTrigger.valueFlow, 1)
20+
}
21+
}

android/src/main/java/com/rive/RiveReactNativeView.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ class RiveReactNativeView(context: ThemedReactContext) : FrameLayout(context) {
2828

2929
//region Public Methods (API)
3030
fun bindViewModelInstance(vmi: ViewModelInstance) {
31-
riveAnimationView?.controller?.stateMachines?.first()?.viewModelInstance = vmi
31+
val stateMachines = riveAnimationView?.controller?.stateMachines
32+
if (!stateMachines.isNullOrEmpty()) {
33+
stateMachines.first().viewModelInstance = vmi
34+
}
3235
}
3336

3437
fun play() {

0 commit comments

Comments
 (0)