Skip to content

Commit 78a68fa

Browse files
authored
feat: add setValueAsync to all scalar ViewModel property types (#291)
Stacked on #289. Adds `setValueAsync(value)` to Number, String, Boolean, Color, and Enum property types across all 4 backends (iOS experimental, iOS legacy, Android experimental, Android legacy). On iOS experimental, this is a proper async write — the promise resolves only after the SDK `setValue` call completes on the main actor, giving ordering guarantees and error propagation. On legacy and Android, `set()` is already synchronous so `setValueAsync` is a thin wrapper that makes the API consistent. Includes harness tests covering all 5 property types.
1 parent 17674fa commit 78a68fa

63 files changed

Lines changed: 422 additions & 23 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

android/src/legacy/java/com/margelo/nitro/rive/HybridViewModelBooleanProperty.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ class HybridViewModelBooleanProperty(private val viewModelBoolean: ViewModelBool
2424
viewModelBoolean.value = value
2525
}
2626

27+
override fun setValueAsync(value: Boolean): Promise<Unit> {
28+
return Promise.async { set(value) }
29+
}
30+
2731
override fun addListener(onChanged: (value: Boolean) -> Unit): () -> Unit {
2832
val remover = addListenerInternal(onChanged)
2933
ensureValueListenerJob(viewModelBoolean.valueFlow)

android/src/legacy/java/com/margelo/nitro/rive/HybridViewModelColorProperty.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ class HybridViewModelColorProperty(private val viewModelColor: ViewModelColorPro
2424
viewModelColor.value = value.toLong().toInt()
2525
}
2626

27+
override fun setValueAsync(value: Double): Promise<Unit> {
28+
return Promise.async { set(value) }
29+
}
30+
2731
override fun addListener(onChanged: (value: Double) -> Unit): () -> Unit {
2832
val remover = addListenerInternal { intValue: Int -> onChanged(intValue.toDouble()) }
2933
ensureValueListenerJob(viewModelColor.valueFlow)

android/src/legacy/java/com/margelo/nitro/rive/HybridViewModelEnumProperty.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ class HybridViewModelEnumProperty(private val viewModelEnum: ViewModelEnumProper
2424
viewModelEnum.value = value
2525
}
2626

27+
override fun setValueAsync(value: String): Promise<Unit> {
28+
return Promise.async { set(value) }
29+
}
30+
2731
override fun addListener(onChanged: (value: String) -> Unit): () -> Unit {
2832
val remover = addListenerInternal(onChanged)
2933
ensureValueListenerJob(viewModelEnum.valueFlow)

android/src/legacy/java/com/margelo/nitro/rive/HybridViewModelNumberProperty.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ class HybridViewModelNumberProperty(private val viewModelNumber: ViewModelNumber
2525
viewModelNumber.value = value.toFloat()
2626
}
2727

28+
override fun setValueAsync(value: Double): Promise<Unit> {
29+
return Promise.async { set(value) }
30+
}
31+
2832
override fun addListener(onChanged: (value: Double) -> Unit): () -> Unit {
2933
val remover = addListenerInternal(onChanged)
3034
ensureValueListenerJob(viewModelNumber.valueFlow.map { it.toDouble() })

android/src/legacy/java/com/margelo/nitro/rive/HybridViewModelStringProperty.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ class HybridViewModelStringProperty(private val viewModelString: ViewModelString
2424
viewModelString.value = value
2525
}
2626

27+
override fun setValueAsync(value: String): Promise<Unit> {
28+
return Promise.async { set(value) }
29+
}
30+
2731
override fun addListener(onChanged: (value: String) -> Unit): () -> Unit {
2832
val remover = addListenerInternal(onChanged)
2933
ensureValueListenerJob(viewModelString.valueFlow)

android/src/new/java/com/margelo/nitro/rive/HybridViewModel.kt

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import kotlinx.coroutines.runBlocking
1515
class HybridViewModel(
1616
private val riveFile: RiveFile,
1717
private val riveWorker: CommandQueue,
18-
private val viewModelName: String?,
18+
private val viewModelName: String,
1919
private val parentFile: HybridRiveFile,
2020
private val vmSource: ViewModelSource
2121
) : HybridViewModelSpec() {
@@ -24,10 +24,9 @@ class HybridViewModel(
2424
}
2525

2626
override fun getPropertiesAsync(): Promise<Array<ViewModelPropertyInfo>> {
27-
val name = viewModelName ?: return Promise.resolved(emptyArray())
2827
return Promise.async {
2928
riveFile
30-
.getViewModelProperties(name)
29+
.getViewModelProperties(viewModelName)
3130
.map { prop ->
3231
ViewModelPropertyInfo(name = prop.name, type = mapPropertyType(prop.type))
3332
}.toTypedArray()
@@ -37,9 +36,8 @@ class HybridViewModel(
3736
override val propertyCount: Double
3837
get() {
3938
DeprecationWarning.warn("propertyCount", "getPropertyCountAsync")
40-
val name = viewModelName ?: throw UnsupportedOperationException("ViewModel name is unavailable")
4139
return try {
42-
runBlocking { riveFile.getViewModelProperties(name) }.size.toDouble()
40+
runBlocking { riveFile.getViewModelProperties(viewModelName) }.size.toDouble()
4341
} catch (e: Exception) {
4442
RiveLog.e(TAG, "propertyCount failed: ${e.message}")
4543
0.0
@@ -49,71 +47,60 @@ class HybridViewModel(
4947
override val instanceCount: Double
5048
get() {
5149
DeprecationWarning.warn("instanceCount", "getInstanceCountAsync")
52-
val name = viewModelName ?: throw UnsupportedOperationException("ViewModel name is unavailable")
5350
return try {
54-
runBlocking { riveFile.getViewModelInstanceNames(name) }.size.toDouble()
51+
runBlocking { riveFile.getViewModelInstanceNames(viewModelName) }.size.toDouble()
5552
} catch (e: Exception) {
5653
RiveLog.e(TAG, "instanceCount failed: ${e.message}")
5754
0.0
5855
}
5956
}
6057

6158
override val modelName: String
62-
get() = viewModelName ?: throw UnsupportedOperationException("ViewModel name is unavailable")
59+
get() = viewModelName
6360

6461
override fun getPropertyCountAsync(): Promise<Double> {
65-
val name = viewModelName ?: return Promise.rejected(UnsupportedOperationException("ViewModel name is unavailable"))
66-
return Promise.async { riveFile.getViewModelProperties(name).size.toDouble() }
62+
return Promise.async { riveFile.getViewModelProperties(viewModelName).size.toDouble() }
6763
}
6864

6965
override fun getInstanceCountAsync(): Promise<Double> {
70-
val name = viewModelName ?: return Promise.rejected(UnsupportedOperationException("ViewModel name is unavailable"))
71-
return Promise.async { riveFile.getViewModelInstanceNames(name).size.toDouble() }
66+
return Promise.async { riveFile.getViewModelInstanceNames(viewModelName).size.toDouble() }
7267
}
7368

7469
// Deprecated: Use createInstanceByNameAsync instead
7570
override fun createInstanceByIndex(index: Double): HybridViewModelInstanceSpec? {
7671
DeprecationWarning.warn("createInstanceByIndex", "createInstanceByNameAsync")
77-
val name = viewModelName ?: throw UnsupportedOperationException("ViewModel name is unavailable")
7872
return try {
7973
val idx = index.toInt()
80-
val instanceNames = runBlocking { riveFile.getViewModelInstanceNames(name) }
74+
val instanceNames = runBlocking { riveFile.getViewModelInstanceNames(viewModelName) }
8175
if (idx < 0 || idx >= instanceNames.size) return null
8276
val instanceName = instanceNames[idx]
8377
runBlocking { createInstanceByNameImpl(instanceName) }
84-
} catch (e: UnsupportedOperationException) {
85-
throw e
8678
} catch (e: Exception) {
8779
RiveLog.e(TAG, "createInstanceByIndex($index) failed: ${e.message}")
8880
null
8981
}
9082
}
9183

9284
private suspend fun createInstanceByNameImpl(instanceName: String): HybridViewModelInstanceSpec? {
93-
val name = viewModelName ?: throw UnsupportedOperationException("ViewModel name is unavailable")
94-
val instanceNames = riveFile.getViewModelInstanceNames(name)
85+
val instanceNames = riveFile.getViewModelInstanceNames(viewModelName)
9586
if (!instanceNames.contains(instanceName)) return null
9687
val source = vmSource.namedInstance(instanceName)
9788
val vmi = ViewModelInstance.fromFile(riveFile, source)
98-
return HybridViewModelInstance(vmi, riveWorker, parentFile, name, instanceName)
89+
return HybridViewModelInstance(vmi, riveWorker, parentFile, viewModelName, instanceName)
9990
}
10091

10192
// Deprecated: Use createInstanceByNameAsync instead
10293
override fun createInstanceByName(name: String): HybridViewModelInstanceSpec? {
10394
DeprecationWarning.warn("createInstanceByName", "createInstanceByNameAsync")
104-
if (viewModelName == null) throw UnsupportedOperationException("ViewModel name is unavailable")
10595
return try {
10696
runBlocking { createInstanceByNameImpl(name) }
107-
} catch (e: UnsupportedOperationException) {
108-
throw e
10997
} catch (e: Exception) {
11098
RiveLog.e(TAG, "createInstanceByName('$name') failed: ${e.message}")
11199
null
112100
}
113101
}
114102

115103
override fun createInstanceByNameAsync(name: String): Promise<HybridViewModelInstanceSpec?> {
116-
if (viewModelName == null) return Promise.rejected(UnsupportedOperationException("ViewModel name is unavailable"))
117104
return Promise.async { createInstanceByNameImpl(name) }
118105
}
119106

android/src/new/java/com/margelo/nitro/rive/HybridViewModelBooleanProperty.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class HybridViewModelBooleanProperty(
3737
instance.setBoolean(path, value)
3838
}
3939

40+
override fun setValueAsync(value: Boolean): Promise<Unit> {
41+
return Promise.async { set(value) }
42+
}
43+
4044
override fun getValueAsync(): Promise<Boolean> {
4145
return Promise.async { instance.getBooleanFlow(path).first() }
4246
}

android/src/new/java/com/margelo/nitro/rive/HybridViewModelColorProperty.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class HybridViewModelColorProperty(
3737
instance.setColor(path, value.toLong().toInt())
3838
}
3939

40+
override fun setValueAsync(value: Double): Promise<Unit> {
41+
return Promise.async { set(value) }
42+
}
43+
4044
override fun getValueAsync(): Promise<Double> {
4145
return Promise.async { instance.getColorFlow(path).first().toDouble() }
4246
}

android/src/new/java/com/margelo/nitro/rive/HybridViewModelEnumProperty.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class HybridViewModelEnumProperty(
3737
instance.setEnum(path, value)
3838
}
3939

40+
override fun setValueAsync(value: String): Promise<Unit> {
41+
return Promise.async { set(value) }
42+
}
43+
4044
override fun getValueAsync(): Promise<String> {
4145
return Promise.async { instance.getEnumFlow(path).first() }
4246
}

android/src/new/java/com/margelo/nitro/rive/HybridViewModelNumberProperty.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class HybridViewModelNumberProperty(
3737
instance.setNumber(path, value.toFloat())
3838
}
3939

40+
override fun setValueAsync(value: Double): Promise<Unit> {
41+
return Promise.async { set(value) }
42+
}
43+
4044
override fun getValueAsync(): Promise<Double> {
4145
return Promise.async { instance.getNumberFlow(path).first().toDouble() }
4246
}

0 commit comments

Comments
 (0)