Skip to content

Commit eb63743

Browse files
committed
feat: migrate viewModelByIndex, createInstanceByIndex, viewModel to async
1 parent d3a9063 commit eb63743

File tree

47 files changed

+623
-94
lines changed

Some content is hidden

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

47 files changed

+623
-94
lines changed

android/src/experimental/java/com/margelo/nitro/rive/HybridRiveFile.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,28 @@ class HybridRiveFile(
3737
}
3838
}
3939

40-
override fun viewModelByIndex(index: Double): HybridViewModelSpec? {
40+
private suspend fun viewModelByIndexImpl(index: Double): HybridViewModelSpec? {
4141
val file = riveFile ?: return null
42+
val names = file.getViewModelNames()
43+
val idx = index.toInt()
44+
if (idx < 0 || idx >= names.size) return null
45+
return HybridViewModel(file, riveWorker, names[idx], this)
46+
}
47+
48+
// Deprecated: Use viewModelByIndexAsync instead
49+
override fun viewModelByIndex(index: Double): HybridViewModelSpec? {
4250
return try {
43-
val names = runBlocking { file.getViewModelNames() }
44-
val idx = index.toInt()
45-
if (idx < 0 || idx >= names.size) return null
46-
HybridViewModel(file, riveWorker, names[idx], this)
51+
runBlocking { viewModelByIndexImpl(index) }
4752
} catch (e: Exception) {
4853
Log.e(TAG, "viewModelByIndex($index) failed", e)
4954
null
5055
}
5156
}
5257

58+
override fun viewModelByIndexAsync(index: Double): Promise<HybridViewModelSpec?> {
59+
return Promise.async { viewModelByIndexImpl(index) }
60+
}
61+
5362
override fun viewModelByName(name: String): HybridViewModelSpec? {
5463
val file = riveFile ?: return null
5564
return try {

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import app.rive.ViewModelInstanceSource
88
import app.rive.ViewModelSource
99
import app.rive.core.CommandQueue
1010
import com.facebook.proguard.annotations.DoNotStrip
11+
import com.margelo.nitro.core.Promise
1112
import kotlinx.coroutines.runBlocking
1213

1314
@Keep
@@ -42,10 +43,19 @@ class HybridViewModel(
4243
override val modelName: String
4344
get() = viewModelName
4445

46+
// Deprecated: Use createInstanceByIndexAsync instead
4547
override fun createInstanceByIndex(index: Double): HybridViewModelInstanceSpec? {
4648
return createDefaultInstance()
4749
}
4850

51+
override fun createInstanceByIndexAsync(index: Double): Promise<HybridViewModelInstanceSpec?> {
52+
return Promise.async {
53+
val source = vmSource.defaultInstance()
54+
val vmi = ViewModelInstance.fromFile(riveFile, source)
55+
HybridViewModelInstance(vmi, riveWorker, parentFile, viewModelName)
56+
}
57+
}
58+
4959
override fun createInstanceByName(name: String): HybridViewModelInstanceSpec? {
5060
return try {
5161
val instanceNames = runBlocking { riveFile.getViewModelInstanceNames(viewModelName) }

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import app.rive.ViewModelInstance
66
import app.rive.ViewModelInstanceSource
77
import app.rive.core.CommandQueue
88
import com.facebook.proguard.annotations.DoNotStrip
9+
import com.margelo.nitro.core.Promise
910
import kotlinx.coroutines.flow.first
1011
import kotlinx.coroutines.runBlocking
1112

@@ -128,19 +129,28 @@ class HybridViewModelInstance(
128129
}
129130
}
130131

131-
override fun viewModel(path: String): HybridViewModelInstanceSpec? {
132+
private fun viewModelImpl(path: String): HybridViewModelInstanceSpec? {
132133
if (!hasProperty(path)) return null
134+
val file = parentFile.riveFile ?: return null
135+
val source = ViewModelInstanceSource.Reference(viewModelInstance, path)
136+
val childVmi = ViewModelInstance.fromFile(file, source)
137+
return HybridViewModelInstance(childVmi, riveWorker, parentFile)
138+
}
139+
140+
// Deprecated: Use viewModelAsync instead
141+
override fun viewModel(path: String): HybridViewModelInstanceSpec? {
133142
return try {
134-
val file = parentFile.riveFile ?: return null
135-
val source = ViewModelInstanceSource.Reference(viewModelInstance, path)
136-
val childVmi = ViewModelInstance.fromFile(file, source)
137-
HybridViewModelInstance(childVmi, riveWorker, parentFile)
143+
viewModelImpl(path)
138144
} catch (e: Exception) {
139145
Log.e(TAG, "viewModel failed for path '$path'", e)
140146
null
141147
}
142148
}
143149

150+
override fun viewModelAsync(path: String): Promise<HybridViewModelInstanceSpec?> {
151+
return Promise.async { viewModelImpl(path) }
152+
}
153+
144154
override fun replaceViewModel(path: String, instance: HybridViewModelInstanceSpec) {
145155
Log.w(TAG, "replaceViewModel not yet supported in experimental API")
146156
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class HybridRiveFile : HybridRiveFileSpec() {
2424
override val viewModelCount: Double?
2525
get() = riveFile?.viewModelCount?.toDouble()
2626

27+
// Deprecated: Use viewModelByIndexAsync instead
2728
override fun viewModelByIndex(index: Double): HybridViewModelSpec? {
2829
if (index < 0) return null
2930
return try {
@@ -34,6 +35,17 @@ class HybridRiveFile : HybridRiveFileSpec() {
3435
}
3536
}
3637

38+
override fun viewModelByIndexAsync(index: Double): Promise<HybridViewModelSpec?> {
39+
return Promise.async {
40+
try {
41+
val vm = riveFile?.getViewModelByIndex(index.toInt()) ?: return@async null
42+
HybridViewModel(vm)
43+
} catch (e: Exception) {
44+
null
45+
}
46+
}
47+
}
48+
3749
override fun viewModelByName(name: String): HybridViewModelSpec? {
3850
return try {
3951
val vm = riveFile?.getViewModelByName(name) ?: return null

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.annotation.Keep
44
import app.rive.runtime.kotlin.core.ViewModel
55
import app.rive.runtime.kotlin.core.errors.ViewModelException
66
import com.facebook.proguard.annotations.DoNotStrip
7+
import com.margelo.nitro.core.Promise
78

89
@Keep
910
@DoNotStrip
@@ -15,6 +16,7 @@ class HybridViewModel(private val viewModel: ViewModel) : HybridViewModelSpec()
1516
override val modelName: String
1617
get() = viewModel.name
1718

19+
// Deprecated: Use createInstanceByIndexAsync instead
1820
override fun createInstanceByIndex(index: Double): HybridViewModelInstanceSpec? {
1921
if (index < 0) return null
2022
try {
@@ -25,6 +27,17 @@ class HybridViewModel(private val viewModel: ViewModel) : HybridViewModelSpec()
2527
}
2628
}
2729

30+
override fun createInstanceByIndexAsync(index: Double): Promise<HybridViewModelInstanceSpec?> {
31+
return Promise.async {
32+
try {
33+
val vmi = viewModel.createInstanceFromIndex(index.toInt())
34+
HybridViewModelInstance(vmi)
35+
} catch (e: ViewModelException) {
36+
null
37+
}
38+
}
39+
}
40+
2841
override fun createInstanceByName(name: String): HybridViewModelInstanceSpec? {
2942
try {
3043
val vmi = viewModel.createInstanceFromName(name)

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import androidx.annotation.Keep
55
import app.rive.runtime.kotlin.core.ViewModelInstance
66
import app.rive.runtime.kotlin.core.errors.ViewModelException
77
import com.facebook.proguard.annotations.DoNotStrip
8+
import com.margelo.nitro.core.Promise
89

910
@Keep
1011
@DoNotStrip
@@ -60,10 +61,19 @@ class HybridViewModelInstance(val viewModelInstance: ViewModelInstance) : Hybrid
6061
HybridViewModelArtboardProperty(viewModelInstance.getArtboardProperty(path))
6162
}
6263

64+
// Deprecated: Use viewModelAsync instead
6365
override fun viewModel(path: String) = getPropertyOrNull {
6466
HybridViewModelInstance(viewModelInstance.getInstanceProperty(path))
6567
}
6668

69+
override fun viewModelAsync(path: String): Promise<HybridViewModelInstanceSpec?> {
70+
return Promise.async {
71+
getPropertyOrNull {
72+
HybridViewModelInstance(viewModelInstance.getInstanceProperty(path))
73+
}
74+
}
75+
}
76+
6777
override fun replaceViewModel(path: String, instance: HybridViewModelInstanceSpec) {
6878
val nativeInstance = (instance as HybridViewModelInstance).viewModelInstance
6979
viewModelInstance.setInstanceProperty(path, nativeInstance)

example/__tests__/databinding-advanced.harness.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ describe('RiveFile ViewModel Access', () => {
2626

2727
it('viewModelByIndex(0) returns a ViewModel', async () => {
2828
const file = await loadFile(DATABINDING);
29-
const vm = file.viewModelByIndex(0);
29+
const vm = await file.viewModelByIndexAsync(0);
3030
expect(vm).toBeDefined();
3131
});
3232

3333
it('viewModelByIndex(-1) returns undefined or throws', async () => {
3434
const file = await loadFile(DATABINDING);
3535
try {
36-
const vm = file.viewModelByIndex(-1);
36+
const vm = await file.viewModelByIndexAsync(-1);
3737
expect(vm).toBeUndefined();
3838
} catch {
3939
// Android Rive SDK throws a JNI exception for invalid indices
@@ -43,7 +43,7 @@ describe('RiveFile ViewModel Access', () => {
4343
it('viewModelByIndex(100) returns undefined or throws', async () => {
4444
const file = await loadFile(DATABINDING);
4545
try {
46-
const vm = file.viewModelByIndex(100);
46+
const vm = await file.viewModelByIndexAsync(100);
4747
expect(vm).toBeUndefined();
4848
} catch {
4949
// Android Rive SDK throws a JNI exception for out-of-range indices
@@ -129,10 +129,10 @@ describe('ViewModel Creation Variants', () => {
129129

130130
it('createInstanceByIndex(0) works', async () => {
131131
const file = await loadFile(DATABINDING);
132-
const vm = file.viewModelByIndex(0);
132+
const vm = await file.viewModelByIndexAsync(0);
133133
expectDefined(vm);
134134

135-
const instance = vm.createInstanceByIndex(0);
135+
const instance = await vm.createInstanceByIndexAsync(0);
136136
expectDefined(instance);
137137
});
138138

@@ -142,7 +142,7 @@ describe('ViewModel Creation Variants', () => {
142142
expectDefined(vm);
143143

144144
// Legacy returns undefined, experimental returns an empty instance
145-
vm.createInstanceByIndex(100);
145+
await vm.createInstanceByIndexAsync(100);
146146
expect(true).toBe(true);
147147
});
148148

@@ -355,7 +355,7 @@ describe.skip('Image Properties', () => {
355355
const file = await loadFile(DATABINDING_IMAGES);
356356
const vm = file.viewModelByName('MyViewModel');
357357
expectDefined(vm);
358-
const instance = vm.createInstanceByIndex(0);
358+
const instance = await vm.createInstanceByIndexAsync(0);
359359
expectDefined(instance);
360360

361361
const imageProp = instance.imageProperty('bound_image');

example/__tests__/rive.harness.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ describe('ViewModel', () => {
3030
const instance = vm?.createDefaultInstance();
3131
expect(instance).toBeDefined();
3232

33-
const vm1 = instance?.viewModel('vm1');
34-
const vm2 = instance?.viewModel('vm2');
33+
const vm1 = await instance?.viewModelAsync('vm1');
34+
const vm2 = await instance?.viewModelAsync('vm2');
3535
expect(vm1).toBeDefined();
3636
expect(vm2).toBeDefined();
3737

38-
expect(instance?.viewModel('nonexistent')).toBeUndefined();
38+
expect(await instance?.viewModelAsync('nonexistent')).toBeUndefined();
3939

4040
expect(vm1?.instanceName).toBeDefined();
4141
expect(typeof vm1?.instanceName).toBe('string');
@@ -48,7 +48,7 @@ describe('ViewModel', () => {
4848
const instance = vm?.createDefaultInstance();
4949
expect(instance).toBeDefined();
5050

51-
const vm2Instance = instance?.viewModel('vm2');
51+
const vm2Instance = await instance?.viewModelAsync('vm2');
5252
expect(vm2Instance).toBeDefined();
5353

5454
const vm2NameProp = vm2Instance?.stringProperty('name');
@@ -58,7 +58,7 @@ describe('ViewModel', () => {
5858

5959
instance?.replaceViewModel('vm1', vm2Instance!);
6060

61-
const vm1AfterReplace = instance?.viewModel('vm1');
61+
const vm1AfterReplace = await instance?.viewModelAsync('vm1');
6262
const vm1NameProp = vm1AfterReplace?.stringProperty('name');
6363
// Android experimental backend doesn't support replaceViewModel yet (no-op)
6464
const val = vm1NameProp?.value;

example/__tests__/viewmodel-properties.harness.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ describe('ViewModel Properties', () => {
104104

105105
it('nested viewModel property access works', async () => {
106106
const instance = await createGordonInstance();
107-
const petViewModel = instance.viewModel('pet');
107+
const petViewModel = await instance.viewModelAsync('pet');
108108
expectDefined(petViewModel);
109109

110110
const petName = petViewModel.stringProperty('name');
@@ -146,7 +146,7 @@ describe('ViewModel Properties', () => {
146146
expect(instance.colorProperty('nonexistent')).toBeUndefined();
147147
expect(instance.enumProperty('nonexistent')).toBeUndefined();
148148
expect(instance.triggerProperty('nonexistent')).toBeUndefined();
149-
expect(instance.viewModel('nonexistent')).toBeUndefined();
149+
expect(await instance.viewModelAsync('nonexistent')).toBeUndefined();
150150
});
151151
});
152152

example/android/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ newArchEnabled=true
3838
# If set to false, you will be using JSC instead.
3939
hermesEnabled=true
4040

41-
USE_RIVE_NEW_API=true
41+
USE_RIVE_NEW_API=false

0 commit comments

Comments
 (0)