Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ class HybridViewModel(private val viewModel: ViewModel) : HybridViewModelSpec()
}
}

override fun getPropertiesAsync(): Promise<Array<ViewModelPropertyInfo>> {
return Promise.rejected(UnsupportedOperationException("getPropertiesAsync is not supported on the legacy backend"))
}

override fun getPropertyCountAsync(): Promise<Double> {
return Promise.async { propertyCount }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ class HybridViewModelInstance(val viewModelInstance: ViewModelInstance) : Hybrid
override val instanceName: String
get() = viewModelInstance.name

override fun getPropertiesAsync(): Promise<Array<ViewModelPropertyInfo>> {
return Promise.rejected(UnsupportedOperationException("getPropertiesAsync is not supported on the legacy backend"))
}

// Returns null if ViewModelException is thrown for iOS parity
// (iOS SDK returns nil when property not found, Android SDK throws)
private inline fun <T> getPropertyOrNull(block: () -> T): T? {
Expand Down
28 changes: 28 additions & 0 deletions android/src/new/java/com/margelo/nitro/rive/HybridViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import app.rive.RiveFile
import app.rive.ViewModelInstance
import app.rive.ViewModelSource
import app.rive.core.CommandQueue
import app.rive.runtime.kotlin.core.ViewModel
import com.facebook.proguard.annotations.DoNotStrip
import com.margelo.nitro.core.Promise
import kotlinx.coroutines.runBlocking
Expand All @@ -22,6 +23,17 @@ class HybridViewModel(
private const val TAG = "HybridViewModel"
}

override fun getPropertiesAsync(): Promise<Array<ViewModelPropertyInfo>> {
val name = viewModelName ?: return Promise.resolved(emptyArray())
return Promise.async {
riveFile
.getViewModelProperties(name)
.map { prop ->
ViewModelPropertyInfo(name = prop.name, type = mapPropertyType(prop.type))
}.toTypedArray()
}
}

override val propertyCount: Double
get() {
DeprecationWarning.warn("propertyCount", "getPropertyCountAsync")
Expand Down Expand Up @@ -147,3 +159,19 @@ class HybridViewModel(
}
}
}

internal fun mapPropertyType(type: ViewModel.PropertyDataType): ViewModelPropertyType = when (type) {
ViewModel.PropertyDataType.NONE -> ViewModelPropertyType.NONE
ViewModel.PropertyDataType.STRING -> ViewModelPropertyType.STRING
ViewModel.PropertyDataType.NUMBER -> ViewModelPropertyType.NUMBER
ViewModel.PropertyDataType.BOOLEAN -> ViewModelPropertyType.BOOLEAN
ViewModel.PropertyDataType.COLOR -> ViewModelPropertyType.COLOR
ViewModel.PropertyDataType.LIST -> ViewModelPropertyType.LIST
ViewModel.PropertyDataType.ENUM -> ViewModelPropertyType.ENUM
ViewModel.PropertyDataType.TRIGGER -> ViewModelPropertyType.TRIGGER
ViewModel.PropertyDataType.VIEW_MODEL -> ViewModelPropertyType.VIEWMODEL
ViewModel.PropertyDataType.INTEGER -> ViewModelPropertyType.INTEGER
ViewModel.PropertyDataType.SYMBOL_LIST_INDEX -> ViewModelPropertyType.SYMBOLLISTINDEX
ViewModel.PropertyDataType.ASSET_IMAGE -> ViewModelPropertyType.ASSETIMAGE
ViewModel.PropertyDataType.ARTBOARD -> ViewModelPropertyType.ARTBOARD
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ class HybridViewModelInstance(
override val instanceName: String
get() = _instanceName ?: ""

override fun getPropertiesAsync(): Promise<Array<ViewModelPropertyInfo>> {
val name = viewModelName ?: return Promise.resolved(emptyArray())
val file = parentFile.riveFile ?: return Promise.resolved(emptyArray())
return Promise.async {
file
.getViewModelProperties(name)
.map { prop ->
ViewModelPropertyInfo(name = prop.name, type = mapPropertyType(prop.type))
}.toTypedArray()
}
}

override fun numberProperty(path: String): HybridViewModelNumberPropertySpec? {
return try {
runBlocking { viewModelInstance.getNumberFlow(path).first() }
Expand Down
6 changes: 5 additions & 1 deletion ios/legacy/HybridViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ class HybridViewModel: HybridViewModelSpec {
var instanceCount: Double { Double(viewModel?.instanceCount ?? 0) }

var modelName: String { viewModel?.name ?? "" }


func getPropertiesAsync() throws -> Promise<[ViewModelPropertyInfo]> {
throw RuntimeError.error(withMessage: "getPropertiesAsync is not supported on the legacy backend")
}

func createInstanceByIndex(index: Double) throws -> (any HybridViewModelInstanceSpec)? {
guard index >= 0 else { return nil }
guard let viewModel = viewModel,
Expand Down
4 changes: 4 additions & 0 deletions ios/legacy/HybridViewModelInstance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ class HybridViewModelInstance: HybridViewModelInstanceSpec {

var instanceName: String { viewModelInstance?.name ?? "" }

func getPropertiesAsync() throws -> Promise<[ViewModelPropertyInfo]> {
throw RuntimeError.error(withMessage: "getPropertiesAsync is not supported on the legacy backend")
}

func numberProperty(path: String) throws -> (any HybridViewModelNumberPropertySpec)? {
guard let property = viewModelInstance?.numberProperty(fromPath: path) else { return nil }
return HybridViewModelNumberProperty(property: property)
Expand Down
36 changes: 32 additions & 4 deletions ios/new/HybridViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ class HybridViewModel: HybridViewModelSpec {
}
}

func getPropertiesAsync() throws -> Promise<[ViewModelPropertyInfo]> {
return Promise.async {
let props = try await self.file.getProperties(of: self.vmName)
return props.map { ViewModelPropertyInfo(name: $0.name, type: mapPropertyType($0.type)) }
}
}

func getPropertyCountAsync() throws -> Promise<Double> {
return Promise.async {
Double(try await self.file.getProperties(of: self.vmName).count)
Expand All @@ -48,7 +55,7 @@ class HybridViewModel: HybridViewModelSpec {

private func createDefaultInstanceImpl() async throws -> (any HybridViewModelInstanceSpec)? {
let vmi = try await self.file.createViewModelInstance(.viewModelDefault(from: .name(self.vmName)))
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker)
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, file: self.file, vmName: self.vmName)
}

private func createInstanceByIndexImpl(index: Double) async throws -> (any HybridViewModelInstanceSpec)? {
Expand All @@ -57,7 +64,7 @@ class HybridViewModel: HybridViewModelSpec {
guard idx >= 0 && idx < names.count else { return nil }
let name = names[idx]
let vmi = try await self.file.createViewModelInstance(.name(name, from: .name(self.vmName)))
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, instanceName: name)
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, instanceName: name, file: self.file, vmName: self.vmName)
}

// Deprecated: Use createInstanceByNameAsync instead
Expand All @@ -68,7 +75,7 @@ class HybridViewModel: HybridViewModelSpec {

private func createInstanceByNameImpl(name: String) async throws -> (any HybridViewModelInstanceSpec)? {
let vmi = try await self.file.createViewModelInstance(.name(name, from: .name(self.vmName)))
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, instanceName: name)
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, instanceName: name, file: self.file, vmName: self.vmName)
}

// Deprecated: Use createInstanceByNameAsync instead
Expand All @@ -93,7 +100,7 @@ class HybridViewModel: HybridViewModelSpec {

private func createInstanceImpl() async throws -> (any HybridViewModelInstanceSpec)? {
let vmi = try await self.file.createViewModelInstance(.blank(from: .name(self.vmName)))
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker)
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, file: self.file, vmName: self.vmName)
}

// Deprecated: Use createBlankInstanceAsync instead
Expand All @@ -106,3 +113,24 @@ class HybridViewModel: HybridViewModelSpec {
return Promise.async { try await self.createInstanceImpl() }
}
}

func mapPropertyType(_ type: RiveRuntime.ViewModelProperty.DataType) -> ViewModelPropertyType {
switch type {
case .none: return .none
case .string: return .string
case .number: return .number
case .boolean: return .boolean
case .color: return .color
case .list: return .list
case .enum: return .enum
case .trigger: return .trigger
case .viewModel: return .viewmodel
case .integer: return .integer
case .symbolListIndex: return .symbollistindex
case .assetImage: return .assetimage
case .artboard: return .artboard
case .input: return .input
case .any: return .any
@unknown default: return .none
}
}
16 changes: 13 additions & 3 deletions ios/new/HybridViewModelInstance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,27 @@ class HybridViewModelInstance: HybridViewModelInstanceSpec {
let viewModelInstance: ViewModelInstance
let worker: Worker
private let _instanceName: String
private let file: File?
private let vmName: String?

init(viewModelInstance: ViewModelInstance, worker: Worker, instanceName: String = "") {
init(viewModelInstance: ViewModelInstance, worker: Worker, instanceName: String = "", file: File? = nil, vmName: String? = nil) {
self.viewModelInstance = viewModelInstance
self.worker = worker
self._instanceName = instanceName
self.file = file
self.vmName = vmName
}

// TODO: Workaround — rive-ios experimental SDK doesn't expose ViewModelInstance.name.
// Only works when caller knows the name (createInstanceByName). Falls back to "" otherwise.
var instanceName: String { _instanceName }

func getPropertiesAsync() throws -> Promise<[ViewModelPropertyInfo]> {
guard let file = file, let vmName = vmName else { return Promise.resolved(withResult: []) }
return Promise.async {
let props = try await file.getProperties(of: vmName)
return props.map { ViewModelPropertyInfo(name: $0.name, type: mapPropertyType($0.type)) }
}
}

// Note: Unlike legacy API, experimental API can't sync-validate if property exists
// Non-existent properties return wrapper objects that fail on getValue()
// This is a known limitation documented in EXPERIMENTAL_IOS_API.md
Expand Down
38 changes: 36 additions & 2 deletions nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.cpp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions nitrogen/generated/android/c++/JHybridViewModelSpec.cpp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions nitrogen/generated/android/c++/JHybridViewModelSpec.hpp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading