diff --git a/android/src/main/java/com/margelo/nitro/rive/HybridRiveFile.kt b/android/src/main/java/com/margelo/nitro/rive/HybridRiveFile.kt index b01c9ae9..147eb619 100644 --- a/android/src/main/java/com/margelo/nitro/rive/HybridRiveFile.kt +++ b/android/src/main/java/com/margelo/nitro/rive/HybridRiveFile.kt @@ -3,7 +3,6 @@ package com.margelo.nitro.rive import androidx.annotation.Keep import app.rive.runtime.kotlin.core.File import com.facebook.proguard.annotations.DoNotStrip -import com.margelo.nitro.NitroModules import java.lang.ref.WeakReference import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/android/src/main/java/com/margelo/nitro/rive/HybridViewModelInstance.kt b/android/src/main/java/com/margelo/nitro/rive/HybridViewModelInstance.kt index 893256a5..0ba683c7 100644 --- a/android/src/main/java/com/margelo/nitro/rive/HybridViewModelInstance.kt +++ b/android/src/main/java/com/margelo/nitro/rive/HybridViewModelInstance.kt @@ -11,66 +11,45 @@ class HybridViewModelInstance(val viewModelInstance: ViewModelInstance) : Hybrid override val instanceName: String get() = viewModelInstance.name - override fun numberProperty(path: String): HybridViewModelNumberPropertySpec? { - try { - val numberProper = viewModelInstance.getNumberProperty(path) - return HybridViewModelNumberProperty(numberProper) + // Returns null if ViewModelException is thrown for iOS parity + // (iOS SDK returns nil when property not found, Android SDK throws) + private inline fun getPropertyOrNull(block: () -> T): T? { + return try { + block() } catch (e: ViewModelException) { - return null + null } } - override fun stringProperty(path: String): HybridViewModelStringPropertySpec? { - try { - val stringProperty = viewModelInstance.getStringProperty(path) - return HybridViewModelStringProperty(stringProperty) - } catch (e: ViewModelException) { - return null - } + override fun numberProperty(path: String) = getPropertyOrNull { + HybridViewModelNumberProperty(viewModelInstance.getNumberProperty(path)) } - override fun booleanProperty(path: String): HybridViewModelBooleanPropertySpec? { - try { - val booleanProperty = viewModelInstance.getBooleanProperty(path) - return HybridViewModelBooleanProperty(booleanProperty) - } catch (e: ViewModelException) { - return null - } + override fun stringProperty(path: String) = getPropertyOrNull { + HybridViewModelStringProperty(viewModelInstance.getStringProperty(path)) } - override fun colorProperty(path: String): HybridViewModelColorPropertySpec? { - try { - val colorProperty = viewModelInstance.getColorProperty(path) - return HybridViewModelColorProperty(colorProperty) - } catch (e: ViewModelException) { - return null - } + override fun booleanProperty(path: String) = getPropertyOrNull { + HybridViewModelBooleanProperty(viewModelInstance.getBooleanProperty(path)) } - override fun enumProperty(path: String): HybridViewModelEnumPropertySpec? { - try { - val enumProperty = viewModelInstance.getEnumProperty(path) - return HybridViewModelEnumProperty(enumProperty) - } catch (e: ViewModelException) { - return null - } + override fun colorProperty(path: String) = getPropertyOrNull { + HybridViewModelColorProperty(viewModelInstance.getColorProperty(path)) } - override fun triggerProperty(path: String): HybridViewModelTriggerPropertySpec? { - try { - val triggerProperty = viewModelInstance.getTriggerProperty(path) - return HybridViewModelTriggerProperty(triggerProperty) - } catch (e: ViewModelException) { - return null - } + override fun enumProperty(path: String) = getPropertyOrNull { + HybridViewModelEnumProperty(viewModelInstance.getEnumProperty(path)) } - override fun imageProperty(path: String): HybridViewModelImagePropertySpec? { - try { - val imageProperty = viewModelInstance.getImageProperty(path) - return HybridViewModelImageProperty(imageProperty) - } catch (e: ViewModelException) { - return null - } + override fun triggerProperty(path: String) = getPropertyOrNull { + HybridViewModelTriggerProperty(viewModelInstance.getTriggerProperty(path)) + } + + override fun imageProperty(path: String) = getPropertyOrNull { + HybridViewModelImageProperty(viewModelInstance.getImageProperty(path)) + } + + override fun listProperty(path: String) = getPropertyOrNull { + HybridViewModelListProperty(viewModelInstance.getListProperty(path)) } } diff --git a/android/src/main/java/com/margelo/nitro/rive/HybridViewModelListProperty.kt b/android/src/main/java/com/margelo/nitro/rive/HybridViewModelListProperty.kt new file mode 100644 index 00000000..3dc77238 --- /dev/null +++ b/android/src/main/java/com/margelo/nitro/rive/HybridViewModelListProperty.kt @@ -0,0 +1,64 @@ +package com.margelo.nitro.rive + +import androidx.annotation.Keep +import app.rive.runtime.kotlin.core.ViewModelListProperty +import com.facebook.proguard.annotations.DoNotStrip +import kotlinx.coroutines.flow.map + +@Keep +@DoNotStrip +class HybridViewModelListProperty(private val listProperty: ViewModelListProperty) : + HybridViewModelListPropertySpec(), + BaseHybridViewModelProperty by BaseHybridViewModelPropertyImpl() { + override val length: Double + get() = listProperty.size.toDouble() + + private fun requireHybridInstance(instance: HybridViewModelInstanceSpec): HybridViewModelInstance { + return instance as? HybridViewModelInstance + ?: throw IllegalArgumentException("Expected HybridViewModelInstance but got ${instance::class.simpleName}") + } + + override fun getInstanceAt(index: Double): HybridViewModelInstanceSpec? { + val idx = index.toInt() + if (idx < 0 || idx >= listProperty.size) return null + return HybridViewModelInstance(listProperty.elementAt(idx)) + } + + override fun addInstance(instance: HybridViewModelInstanceSpec) { + val hybridInstance = requireHybridInstance(instance) + listProperty.add(hybridInstance.viewModelInstance) + } + + override fun addInstanceAt(instance: HybridViewModelInstanceSpec, index: Double): Boolean { + val hybridInstance = requireHybridInstance(instance) + val idx = index.toInt() + if (idx < 0 || idx > listProperty.size) return false + listProperty.add(idx, hybridInstance.viewModelInstance) + return true + } + + override fun removeInstance(instance: HybridViewModelInstanceSpec) { + val hybridInstance = requireHybridInstance(instance) + listProperty.remove(hybridInstance.viewModelInstance) + } + + override fun removeInstanceAt(index: Double) { + listProperty.removeAt(index.toInt()) + } + + override fun swap(index1: Double, index2: Double): Boolean { + val idx1 = index1.toInt() + val idx2 = index2.toInt() + if (idx1 < 0 || idx1 >= listProperty.size || idx2 < 0 || idx2 >= listProperty.size) { + return false + } + listProperty.swap(idx1, idx2) + return true + } + + override fun addListener(onChanged: () -> Unit): () -> Unit { + val remover = addListenerInternal { _ -> onChanged() } + ensureValueListenerJob(listProperty.valueFlow.map { }) + return remover + } +} diff --git a/example/assets/list.riv b/example/assets/list.riv new file mode 100644 index 00000000..80c4eae2 Binary files /dev/null and b/example/assets/list.riv differ diff --git a/example/src/pages/DataBindingListExample.tsx b/example/src/pages/DataBindingListExample.tsx new file mode 100644 index 00000000..4dc2b599 --- /dev/null +++ b/example/src/pages/DataBindingListExample.tsx @@ -0,0 +1,254 @@ +import { + View, + Text, + StyleSheet, + ActivityIndicator, + TouchableOpacity, +} from 'react-native'; +import { useMemo, useState, useCallback, useRef } from 'react'; +import { + Fit, + RiveView, + type ViewModelInstance, + type RiveFile, + type RiveViewRef, + useRiveFile, +} from '@rive-app/react-native'; +import { type Metadata } from '../helpers/metadata'; + +export default function DataBindingListExample() { + const { riveFile, isLoading, error } = useRiveFile( + require('../../assets/list.riv') + ); + + return ( + + + {isLoading ? ( + + ) : riveFile ? ( + + ) : ( + {error || 'Unexpected error'} + )} + + + ); +} + +function WithViewModelSetup({ file }: { file: RiveFile }) { + const viewModel = useMemo(() => file.viewModelByName('menu VM'), [file]); + const instance = useMemo( + () => viewModel?.createDefaultInstance(), + [viewModel] + ); + + if (!instance || !viewModel) { + return ( + + {!viewModel + ? "No view model 'menu VM' found" + : 'Failed to create view model instance'} + + ); + } + + return ; +} + +function ListExample({ + instance, + file, +}: { + instance: ViewModelInstance; + file: RiveFile; +}) { + const riveRef = useRef(null); + const [isPlaying, setIsPlaying] = useState(true); + const listProperty = useMemo( + () => instance.listProperty('ListItemVM'), + [instance] + ); + const [listLength, setListLength] = useState(listProperty?.length ?? 0); + + const refreshLength = useCallback(() => { + setListLength(listProperty?.length ?? 0); + }, [listProperty]); + + const handleAddItem = useCallback(() => { + if (!listProperty) return; + const buttonVM = file.viewModelByName('button VM'); + if (!buttonVM) { + console.error('button VM view model not found'); + return; + } + const newInstance = buttonVM.createInstance(); + if (!newInstance) { + console.error('Failed to create new button VM instance'); + return; + } + const stringProp = newInstance.stringProperty('string'); + if (stringProp) { + stringProp.value = 'new btn'; + } + listProperty.addInstance(newInstance); + riveRef.current?.playIfNeeded(); + refreshLength(); + }, [listProperty, file, refreshLength]); + + const handleRemoveFirst = useCallback(() => { + if (!listProperty || listProperty.length === 0) return; + listProperty.removeInstanceAt(0); + riveRef.current?.playIfNeeded(); + refreshLength(); + }, [listProperty, refreshLength]); + + const handleRemoveLast = useCallback(() => { + if (!listProperty || listProperty.length === 0) return; + listProperty.removeInstanceAt(listProperty.length - 1); + riveRef.current?.playIfNeeded(); + refreshLength(); + }, [listProperty, refreshLength]); + + const handleSwapFirstTwo = useCallback(() => { + if (!listProperty || listProperty.length < 2) return; + listProperty.swap(0, 1); + riveRef.current?.playIfNeeded(); + refreshLength(); + }, [listProperty, refreshLength]); + + const logListItems = useCallback(() => { + if (!listProperty) return; + console.log(`List has ${listProperty.length} items:`); + for (let i = 0; i < listProperty.length; i++) { + const item = listProperty.getInstanceAt(i); + console.log(` [${i}]: ${item?.instanceName ?? 'undefined'}`); + } + }, [listProperty]); + + const handlePlayPause = useCallback(() => { + if (isPlaying) { + riveRef.current?.pause(); + } else { + riveRef.current?.play(); + } + setIsPlaying(!isPlaying); + }, [isPlaying]); + + if (!listProperty) { + return ( + ListItemVM list property not found + ); + } + + return ( + + { + riveRef.current = ref; + }, + }} + style={styles.rive} + autoPlay={true} + dataBind={instance} + fit={Fit.Contain} + file={file} + /> + + List length: {listLength} + + + Add Item + + + Remove First + + + + + Remove Last + + + Swap 0↔1 + + + + + + {isPlaying ? 'Pause' : 'Play'} + + + + Log Items + + + + + ); +} + +DataBindingListExample.metadata = { + name: 'Data Binding Lists', + description: 'Test data binding with list properties (ViewModelListProperty)', +} satisfies Metadata; + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + }, + riveContainer: { + flex: 1, + backgroundColor: '#f5f5f5', + }, + rive: { + flex: 1, + width: '100%', + }, + controls: { + padding: 16, + backgroundColor: '#f0f0f0', + }, + infoText: { + fontSize: 16, + fontWeight: 'bold', + textAlign: 'center', + marginBottom: 12, + }, + buttonRow: { + flexDirection: 'row', + justifyContent: 'space-around', + marginBottom: 8, + }, + button: { + backgroundColor: '#007AFF', + paddingVertical: 10, + paddingHorizontal: 16, + borderRadius: 8, + minWidth: 120, + }, + playButton: { + backgroundColor: '#34C759', + }, + logButton: { + backgroundColor: '#666', + }, + buttonText: { + color: '#fff', + fontSize: 14, + fontWeight: 'bold', + textAlign: 'center', + }, + errorText: { + color: 'red', + textAlign: 'center', + padding: 20, + }, +}); diff --git a/example/src/pages/index.ts b/example/src/pages/index.ts index 3747327e..83ee0f79 100644 --- a/example/src/pages/index.ts +++ b/example/src/pages/index.ts @@ -9,3 +9,4 @@ export { default as OutOfBandAssetsWithSuspense } from './OutOfBandAssetsWithSus export { default as ManyViewModels } from './ManyViewModels'; export { default as ResponsiveLayouts } from './ResponsiveLayouts'; export { default as SharedValueListenerExample } from './SharedValueListenerExample'; +export { default as DataBindingListExample } from './DataBindingListExample'; diff --git a/ios/BaseHybridViewModelProperty.swift b/ios/BaseHybridViewModelProperty.swift index a37b8469..ccda8a73 100644 --- a/ios/BaseHybridViewModelProperty.swift +++ b/ios/BaseHybridViewModelProperty.swift @@ -23,6 +23,7 @@ typealias EnumPropertyType = RiveDataBindingViewModel.Instance.EnumProperty typealias ColorPropertyType = RiveDataBindingViewModel.Instance.ColorProperty typealias TriggerPropertyType = RiveDataBindingViewModel.Instance.TriggerProperty typealias ImagePropertyType = RiveDataBindingViewModel.Instance.ImageProperty +typealias ListPropertyType = RiveDataBindingViewModel.Instance.ListProperty // Make all Rive property types conform to the protocol extension BooleanPropertyType: RivePropertyWithListeners { @@ -56,6 +57,14 @@ extension ImagePropertyType: RivePropertyWithListeners { } } +extension ListPropertyType: RivePropertyWithListeners { + typealias ListenerValueType = Void + + func addListener(_ callback: @escaping ListenerType) -> UUID { + addListener { callback(()) } + } +} + /// Helper class for managing ViewModel property listeners class PropertyListenerHelper { private var listenerIds: [UUID] = [] diff --git a/ios/HybridViewModelInstance.swift b/ios/HybridViewModelInstance.swift index d6a4c7ca..001657b3 100644 --- a/ios/HybridViewModelInstance.swift +++ b/ios/HybridViewModelInstance.swift @@ -43,4 +43,9 @@ class HybridViewModelInstance: HybridViewModelInstanceSpec { guard let property = viewModelInstance?.imageProperty(fromPath: path) else { return nil } return HybridViewModelImageProperty(property: property) } + + func listProperty(path: String) throws -> (any HybridViewModelListPropertySpec)? { + guard let property = viewModelInstance?.listProperty(fromPath: path) else { return nil } + return HybridViewModelListProperty(property: property) + } } diff --git a/ios/HybridViewModelListProperty.swift b/ios/HybridViewModelListProperty.swift new file mode 100644 index 00000000..11ac39af --- /dev/null +++ b/ios/HybridViewModelListProperty.swift @@ -0,0 +1,62 @@ +import RiveRuntime + +class HybridViewModelListProperty: HybridViewModelListPropertySpec, ValuedPropertyProtocol { + var property: ListPropertyType! + lazy var helper = PropertyListenerHelper(property: property!) + + init(property: ListPropertyType) { + self.property = property + super.init() + } + + var length: Double { + Double(property.count) + } + + func getInstanceAt(index: Double) throws -> (any HybridViewModelInstanceSpec)? { + guard let instance = property.instance(at: Int32(index)) else { return nil } + return HybridViewModelInstance(viewModelInstance: instance) + } + + private func requireViewModelInstance(_ instance: any HybridViewModelInstanceSpec) throws -> RiveDataBindingViewModel.Instance { + guard let hybridInstance = instance as? HybridViewModelInstance, + let viewModelInstance = hybridInstance.viewModelInstance else { + throw NSError(domain: "HybridViewModelListProperty", code: 1, + userInfo: [NSLocalizedDescriptionKey: "Expected HybridViewModelInstance with valid viewModelInstance"]) + } + return viewModelInstance + } + + func addInstance(instance: any HybridViewModelInstanceSpec) throws { + let viewModelInstance = try requireViewModelInstance(instance) + property.append(viewModelInstance) + } + + func addInstanceAt(instance: any HybridViewModelInstanceSpec, index: Double) throws -> Bool { + let viewModelInstance = try requireViewModelInstance(instance) + return property.insert(viewModelInstance, at: Int32(index)) + } + + func removeInstance(instance: any HybridViewModelInstanceSpec) throws { + let viewModelInstance = try requireViewModelInstance(instance) + property.remove(viewModelInstance) + } + + func removeInstanceAt(index: Double) throws { + property.remove(at: Int32(index)) + } + + func swap(index1: Double, index2: Double) throws -> Bool { + let idx1 = UInt32(index1) + let idx2 = UInt32(index2) + guard idx1 < property.count && idx2 < property.count else { + return false + } + property.swap(at: idx1, with: idx2) + return true + } + + func addListener(onChanged: @escaping () -> Void) throws -> () -> Void { + helper.addListener({ _ in onChanged() }) + } +} diff --git a/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.cpp b/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.cpp index 943c29d9..741cb4a2 100644 --- a/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.cpp +++ b/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.cpp @@ -21,6 +21,8 @@ namespace margelo::nitro::rive { class HybridViewModelEnumPropertySpec; } namespace margelo::nitro::rive { class HybridViewModelTriggerPropertySpec; } // Forward declaration of `HybridViewModelImagePropertySpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelImagePropertySpec; } +// Forward declaration of `HybridViewModelListPropertySpec` to properly resolve imports. +namespace margelo::nitro::rive { class HybridViewModelListPropertySpec; } #include #include @@ -39,6 +41,8 @@ namespace margelo::nitro::rive { class HybridViewModelImagePropertySpec; } #include "JHybridViewModelTriggerPropertySpec.hpp" #include "HybridViewModelImagePropertySpec.hpp" #include "JHybridViewModelImagePropertySpec.hpp" +#include "HybridViewModelListPropertySpec.hpp" +#include "JHybridViewModelListPropertySpec.hpp" namespace margelo::nitro::rive { @@ -111,5 +115,10 @@ namespace margelo::nitro::rive { auto __result = method(_javaPart, jni::make_jstring(path)); return __result != nullptr ? std::make_optional(__result->cthis()->shared_cast()) : std::nullopt; } + std::optional> JHybridViewModelInstanceSpec::listProperty(const std::string& path) { + static const auto method = javaClassStatic()->getMethod(jni::alias_ref /* path */)>("listProperty"); + auto __result = method(_javaPart, jni::make_jstring(path)); + return __result != nullptr ? std::make_optional(__result->cthis()->shared_cast()) : std::nullopt; + } } // namespace margelo::nitro::rive diff --git a/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.hpp b/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.hpp index 2bde4785..8f5f8c2c 100644 --- a/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.hpp +++ b/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.hpp @@ -61,6 +61,7 @@ namespace margelo::nitro::rive { std::optional> enumProperty(const std::string& path) override; std::optional> triggerProperty(const std::string& path) override; std::optional> imageProperty(const std::string& path) override; + std::optional> listProperty(const std::string& path) override; private: friend HybridBase; diff --git a/nitrogen/generated/android/c++/JHybridViewModelListPropertySpec.cpp b/nitrogen/generated/android/c++/JHybridViewModelListPropertySpec.cpp new file mode 100644 index 00000000..6e073616 --- /dev/null +++ b/nitrogen/generated/android/c++/JHybridViewModelListPropertySpec.cpp @@ -0,0 +1,102 @@ +/// +/// JHybridViewModelListPropertySpec.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2025 Marc Rousavy @ Margelo +/// + +#include "JHybridViewModelListPropertySpec.hpp" + +// Forward declaration of `HybridViewModelInstanceSpec` to properly resolve imports. +namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } + +#include +#include "HybridViewModelInstanceSpec.hpp" +#include +#include "JHybridViewModelInstanceSpec.hpp" +#include +#include "JFunc_void.hpp" +#include + +namespace margelo::nitro::rive { + + jni::local_ref JHybridViewModelListPropertySpec::initHybrid(jni::alias_ref jThis) { + return makeCxxInstance(jThis); + } + + void JHybridViewModelListPropertySpec::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JHybridViewModelListPropertySpec::initHybrid), + }); + } + + size_t JHybridViewModelListPropertySpec::getExternalMemorySize() noexcept { + static const auto method = javaClassStatic()->getMethod("getMemorySize"); + return method(_javaPart); + } + + void JHybridViewModelListPropertySpec::dispose() noexcept { + static const auto method = javaClassStatic()->getMethod("dispose"); + method(_javaPart); + } + + std::string JHybridViewModelListPropertySpec::toString() { + static const auto method = javaClassStatic()->getMethod("toString"); + auto javaString = method(_javaPart); + return javaString->toStdString(); + } + + // Properties + double JHybridViewModelListPropertySpec::getLength() { + static const auto method = javaClassStatic()->getMethod("getLength"); + auto __result = method(_javaPart); + return __result; + } + + // Methods + std::optional> JHybridViewModelListPropertySpec::getInstanceAt(double index) { + static const auto method = javaClassStatic()->getMethod(double /* index */)>("getInstanceAt"); + auto __result = method(_javaPart, index); + return __result != nullptr ? std::make_optional(__result->cthis()->shared_cast()) : std::nullopt; + } + void JHybridViewModelListPropertySpec::addInstance(const std::shared_ptr& instance) { + static const auto method = javaClassStatic()->getMethod /* instance */)>("addInstance"); + method(_javaPart, std::dynamic_pointer_cast(instance)->getJavaPart()); + } + bool JHybridViewModelListPropertySpec::addInstanceAt(const std::shared_ptr& instance, double index) { + static const auto method = javaClassStatic()->getMethod /* instance */, double /* index */)>("addInstanceAt"); + auto __result = method(_javaPart, std::dynamic_pointer_cast(instance)->getJavaPart(), index); + return static_cast(__result); + } + void JHybridViewModelListPropertySpec::removeInstance(const std::shared_ptr& instance) { + static const auto method = javaClassStatic()->getMethod /* instance */)>("removeInstance"); + method(_javaPart, std::dynamic_pointer_cast(instance)->getJavaPart()); + } + void JHybridViewModelListPropertySpec::removeInstanceAt(double index) { + static const auto method = javaClassStatic()->getMethod("removeInstanceAt"); + method(_javaPart, index); + } + bool JHybridViewModelListPropertySpec::swap(double index1, double index2) { + static const auto method = javaClassStatic()->getMethod("swap"); + auto __result = method(_javaPart, index1, index2); + return static_cast(__result); + } + std::function JHybridViewModelListPropertySpec::addListener(const std::function& onChanged) { + static const auto method = javaClassStatic()->getMethod(jni::alias_ref /* onChanged */)>("addListener_cxx"); + auto __result = method(_javaPart, JFunc_void_cxx::fromCpp(onChanged)); + return [&]() -> std::function { + if (__result->isInstanceOf(JFunc_void_cxx::javaClassStatic())) [[likely]] { + auto downcast = jni::static_ref_cast(__result); + return downcast->cthis()->getFunction(); + } else { + auto __resultRef = jni::make_global(__result); + return JNICallable(std::move(__resultRef)); + } + }(); + } + void JHybridViewModelListPropertySpec::removeListeners() { + static const auto method = javaClassStatic()->getMethod("removeListeners"); + method(_javaPart); + } + +} // namespace margelo::nitro::rive diff --git a/nitrogen/generated/android/c++/JHybridViewModelListPropertySpec.hpp b/nitrogen/generated/android/c++/JHybridViewModelListPropertySpec.hpp new file mode 100644 index 00000000..b8550732 --- /dev/null +++ b/nitrogen/generated/android/c++/JHybridViewModelListPropertySpec.hpp @@ -0,0 +1,73 @@ +/// +/// HybridViewModelListPropertySpec.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2025 Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include +#include "HybridViewModelListPropertySpec.hpp" + +// Forward declaration of `JHybridViewModelPropertySpec` to properly resolve imports. +namespace margelo::nitro::rive { class JHybridViewModelPropertySpec; } +#include "JHybridViewModelPropertySpec.hpp" + +namespace margelo::nitro::rive { + + using namespace facebook; + + class JHybridViewModelListPropertySpec: public jni::HybridClass, + public virtual HybridViewModelListPropertySpec { + public: + static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/rive/HybridViewModelListPropertySpec;"; + static jni::local_ref initHybrid(jni::alias_ref jThis); + static void registerNatives(); + + protected: + // C++ constructor (called from Java via `initHybrid()`) + explicit JHybridViewModelListPropertySpec(jni::alias_ref jThis) : + HybridObject(HybridViewModelListPropertySpec::TAG), + HybridBase(jThis), + _javaPart(jni::make_global(jThis)) {} + + public: + ~JHybridViewModelListPropertySpec() override { + // Hermes GC can destroy JS objects on a non-JNI Thread. + jni::ThreadScope::WithClassLoader([&] { _javaPart.reset(); }); + } + + public: + size_t getExternalMemorySize() noexcept override; + void dispose() noexcept override; + std::string toString() override; + + public: + inline const jni::global_ref& getJavaPart() const noexcept { + return _javaPart; + } + + public: + // Properties + double getLength() override; + + public: + // Methods + std::optional> getInstanceAt(double index) override; + void addInstance(const std::shared_ptr& instance) override; + bool addInstanceAt(const std::shared_ptr& instance, double index) override; + void removeInstance(const std::shared_ptr& instance) override; + void removeInstanceAt(double index) override; + bool swap(double index1, double index2) override; + std::function addListener(const std::function& onChanged) override; + void removeListeners() override; + + private: + friend HybridBase; + using HybridBase::HybridBase; + jni::global_ref _javaPart; + }; + +} // namespace margelo::nitro::rive diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelInstanceSpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelInstanceSpec.kt index 9980765b..af6de3f6 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelInstanceSpec.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelInstanceSpec.kt @@ -74,6 +74,10 @@ abstract class HybridViewModelInstanceSpec: HybridObject() { @DoNotStrip @Keep abstract fun imageProperty(path: String): HybridViewModelImagePropertySpec? + + @DoNotStrip + @Keep + abstract fun listProperty(path: String): HybridViewModelListPropertySpec? private external fun initHybrid(): HybridData diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelListPropertySpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelListPropertySpec.kt new file mode 100644 index 00000000..27309b5c --- /dev/null +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelListPropertySpec.kt @@ -0,0 +1,92 @@ +/// +/// HybridViewModelListPropertySpec.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2025 Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.rive + +import androidx.annotation.Keep +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.margelo.nitro.core.HybridObject + +/** + * A Kotlin class representing the ViewModelListProperty HybridObject. + * Implement this abstract class to create Kotlin-based instances of ViewModelListProperty. + */ +@DoNotStrip +@Keep +@Suppress( + "KotlinJniMissingFunction", "unused", + "RedundantSuppression", "RedundantUnitReturnType", "SimpleRedundantLet", + "LocalVariableName", "PropertyName", "PrivatePropertyName", "FunctionName" +) +abstract class HybridViewModelListPropertySpec: HybridViewModelPropertySpec() { + @DoNotStrip + private var mHybridData: HybridData = initHybrid() + + init { + super.updateNative(mHybridData) + } + + override fun updateNative(hybridData: HybridData) { + mHybridData = hybridData + super.updateNative(hybridData) + } + + // Default implementation of `HybridObject.toString()` + override fun toString(): String { + return "[HybridObject ViewModelListProperty]" + } + + // Properties + @get:DoNotStrip + @get:Keep + abstract val length: Double + + // Methods + @DoNotStrip + @Keep + abstract fun getInstanceAt(index: Double): HybridViewModelInstanceSpec? + + @DoNotStrip + @Keep + abstract fun addInstance(instance: HybridViewModelInstanceSpec): Unit + + @DoNotStrip + @Keep + abstract fun addInstanceAt(instance: HybridViewModelInstanceSpec, index: Double): Boolean + + @DoNotStrip + @Keep + abstract fun removeInstance(instance: HybridViewModelInstanceSpec): Unit + + @DoNotStrip + @Keep + abstract fun removeInstanceAt(index: Double): Unit + + @DoNotStrip + @Keep + abstract fun swap(index1: Double, index2: Double): Boolean + + abstract fun addListener(onChanged: () -> Unit): () -> Unit + + @DoNotStrip + @Keep + private fun addListener_cxx(onChanged: Func_void): Func_void { + val __result = addListener(onChanged) + return Func_void_java(__result) + } + + @DoNotStrip + @Keep + abstract fun removeListeners(): Unit + + private external fun initHybrid(): HybridData + + companion object { + protected const val TAG = "HybridViewModelListPropertySpec" + } +} diff --git a/nitrogen/generated/android/rive+autolinking.cmake b/nitrogen/generated/android/rive+autolinking.cmake index d399dbd3..8615b2bc 100644 --- a/nitrogen/generated/android/rive+autolinking.cmake +++ b/nitrogen/generated/android/rive+autolinking.cmake @@ -50,6 +50,7 @@ target_sources( ../nitrogen/generated/shared/c++/HybridViewModelEnumPropertySpec.cpp ../nitrogen/generated/shared/c++/HybridViewModelTriggerPropertySpec.cpp ../nitrogen/generated/shared/c++/HybridViewModelImagePropertySpec.cpp + ../nitrogen/generated/shared/c++/HybridViewModelListPropertySpec.cpp # Android-specific Nitrogen C++ sources ../nitrogen/generated/android/c++/JHybridRiveSpec.cpp ../nitrogen/generated/android/c++/JHybridRiveFileSpec.cpp @@ -70,6 +71,7 @@ target_sources( ../nitrogen/generated/android/c++/JHybridViewModelEnumPropertySpec.cpp ../nitrogen/generated/android/c++/JHybridViewModelTriggerPropertySpec.cpp ../nitrogen/generated/android/c++/JHybridViewModelImagePropertySpec.cpp + ../nitrogen/generated/android/c++/JHybridViewModelListPropertySpec.cpp ) # From node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake diff --git a/nitrogen/generated/android/riveOnLoad.cpp b/nitrogen/generated/android/riveOnLoad.cpp index 031508ce..75783327 100644 --- a/nitrogen/generated/android/riveOnLoad.cpp +++ b/nitrogen/generated/android/riveOnLoad.cpp @@ -38,6 +38,7 @@ #include "JHybridViewModelEnumPropertySpec.hpp" #include "JHybridViewModelTriggerPropertySpec.hpp" #include "JHybridViewModelImagePropertySpec.hpp" +#include "JHybridViewModelListPropertySpec.hpp" #include namespace margelo::nitro::rive { @@ -72,6 +73,7 @@ int initialize(JavaVM* vm) { margelo::nitro::rive::JHybridViewModelEnumPropertySpec::registerNatives(); margelo::nitro::rive::JHybridViewModelTriggerPropertySpec::registerNatives(); margelo::nitro::rive::JHybridViewModelImagePropertySpec::registerNatives(); + margelo::nitro::rive::JHybridViewModelListPropertySpec::registerNatives(); // Register Nitro Hybrid Objects HybridObjectRegistry::registerHybridObjectConstructor( diff --git a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp index 1d1399af..f7836580 100644 --- a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp +++ b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp @@ -19,6 +19,7 @@ #include "HybridViewModelEnumPropertySpecSwift.hpp" #include "HybridViewModelImagePropertySpecSwift.hpp" #include "HybridViewModelInstanceSpecSwift.hpp" +#include "HybridViewModelListPropertySpecSwift.hpp" #include "HybridViewModelNumberPropertySpecSwift.hpp" #include "HybridViewModelPropertySpecSwift.hpp" #include "HybridViewModelSpecSwift.hpp" @@ -341,6 +342,22 @@ namespace margelo::nitro::rive::bridge::swift { return swiftPart.toUnsafe(); } + // pragma MARK: std::shared_ptr + std::shared_ptr create_std__shared_ptr_HybridViewModelListPropertySpec_(void* NON_NULL swiftUnsafePointer) noexcept { + RNRive::HybridViewModelListPropertySpec_cxx swiftPart = RNRive::HybridViewModelListPropertySpec_cxx::fromUnsafe(swiftUnsafePointer); + return std::make_shared(swiftPart); + } + void* NON_NULL get_std__shared_ptr_HybridViewModelListPropertySpec_(std__shared_ptr_HybridViewModelListPropertySpec_ cppType) { + std::shared_ptr swiftWrapper = std::dynamic_pointer_cast(cppType); + #ifdef NITRO_DEBUG + if (swiftWrapper == nullptr) [[unlikely]] { + throw std::runtime_error("Class \"HybridViewModelListPropertySpec\" is not implemented in Swift!"); + } + #endif + RNRive::HybridViewModelListPropertySpec_cxx& swiftPart = swiftWrapper->getSwiftPart(); + return swiftPart.toUnsafe(); + } + // pragma MARK: std::function Func_void_double create_Func_void_double(void* NON_NULL swiftClosureWrapper) noexcept { auto swiftClosure = RNRive::Func_void_double::fromUnsafe(swiftClosureWrapper); diff --git a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp index edd02b50..5ffe2193 100644 --- a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp +++ b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp @@ -42,6 +42,8 @@ namespace margelo::nitro::rive { class HybridViewModelEnumPropertySpec; } namespace margelo::nitro::rive { class HybridViewModelImagePropertySpec; } // Forward declaration of `HybridViewModelInstanceSpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } +// Forward declaration of `HybridViewModelListPropertySpec` to properly resolve imports. +namespace margelo::nitro::rive { class HybridViewModelListPropertySpec; } // Forward declaration of `HybridViewModelNumberPropertySpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelNumberPropertySpec; } // Forward declaration of `HybridViewModelPropertySpec` to properly resolve imports. @@ -88,6 +90,8 @@ namespace RNRive { class HybridViewModelEnumPropertySpec_cxx; } namespace RNRive { class HybridViewModelImagePropertySpec_cxx; } // Forward declaration of `HybridViewModelInstanceSpec_cxx` to properly resolve imports. namespace RNRive { class HybridViewModelInstanceSpec_cxx; } +// Forward declaration of `HybridViewModelListPropertySpec_cxx` to properly resolve imports. +namespace RNRive { class HybridViewModelListPropertySpec_cxx; } // Forward declaration of `HybridViewModelNumberPropertySpec_cxx` to properly resolve imports. namespace RNRive { class HybridViewModelNumberPropertySpec_cxx; } // Forward declaration of `HybridViewModelPropertySpec_cxx` to properly resolve imports. @@ -117,6 +121,7 @@ namespace RNRive { class HybridViewModelTriggerPropertySpec_cxx; } #include "HybridViewModelEnumPropertySpec.hpp" #include "HybridViewModelImagePropertySpec.hpp" #include "HybridViewModelInstanceSpec.hpp" +#include "HybridViewModelListPropertySpec.hpp" #include "HybridViewModelNumberPropertySpec.hpp" #include "HybridViewModelPropertySpec.hpp" #include "HybridViewModelSpec.hpp" @@ -1070,6 +1075,36 @@ namespace margelo::nitro::rive::bridge::swift { return *optional; } + // pragma MARK: std::shared_ptr + /** + * Specialized version of `std::shared_ptr`. + */ + using std__shared_ptr_HybridViewModelListPropertySpec_ = std::shared_ptr; + std::shared_ptr create_std__shared_ptr_HybridViewModelListPropertySpec_(void* NON_NULL swiftUnsafePointer) noexcept; + void* NON_NULL get_std__shared_ptr_HybridViewModelListPropertySpec_(std__shared_ptr_HybridViewModelListPropertySpec_ cppType); + + // pragma MARK: std::shared_ptr + inline std::shared_ptr upcast_ViewModelListProperty_to_ViewModelProperty(std::shared_ptr child) noexcept { return child; } + + // pragma MARK: std::weak_ptr + using std__weak_ptr_HybridViewModelListPropertySpec_ = std::weak_ptr; + inline std__weak_ptr_HybridViewModelListPropertySpec_ weakify_std__shared_ptr_HybridViewModelListPropertySpec_(const std::shared_ptr& strong) noexcept { return strong; } + + // pragma MARK: std::optional> + /** + * Specialized version of `std::optional>`. + */ + using std__optional_std__shared_ptr_HybridViewModelListPropertySpec__ = std::optional>; + inline std::optional> create_std__optional_std__shared_ptr_HybridViewModelListPropertySpec__(const std::shared_ptr& value) noexcept { + return std::optional>(value); + } + inline bool has_value_std__optional_std__shared_ptr_HybridViewModelListPropertySpec__(const std::optional>& optional) noexcept { + return optional.has_value(); + } + inline std::shared_ptr get_std__optional_std__shared_ptr_HybridViewModelListPropertySpec__(const std::optional>& optional) noexcept { + return *optional; + } + // pragma MARK: Result>> using Result_std__optional_std__shared_ptr_HybridViewModelNumberPropertySpec___ = Result>>; inline Result_std__optional_std__shared_ptr_HybridViewModelNumberPropertySpec___ create_Result_std__optional_std__shared_ptr_HybridViewModelNumberPropertySpec___(const std::optional>& value) noexcept { @@ -1133,6 +1168,15 @@ namespace margelo::nitro::rive::bridge::swift { return Result>>::withError(error); } + // pragma MARK: Result>> + using Result_std__optional_std__shared_ptr_HybridViewModelListPropertySpec___ = Result>>; + inline Result_std__optional_std__shared_ptr_HybridViewModelListPropertySpec___ create_Result_std__optional_std__shared_ptr_HybridViewModelListPropertySpec___(const std::optional>& value) noexcept { + return Result>>::withValue(value); + } + inline Result_std__optional_std__shared_ptr_HybridViewModelListPropertySpec___ create_Result_std__optional_std__shared_ptr_HybridViewModelListPropertySpec___(const std::exception_ptr& error) noexcept { + return Result>>::withError(error); + } + // pragma MARK: std::function /** * Specialized version of `std::function`. diff --git a/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp b/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp index 92eb7fe8..945b694a 100644 --- a/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp +++ b/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp @@ -42,6 +42,8 @@ namespace margelo::nitro::rive { class HybridViewModelEnumPropertySpec; } namespace margelo::nitro::rive { class HybridViewModelImagePropertySpec; } // Forward declaration of `HybridViewModelInstanceSpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } +// Forward declaration of `HybridViewModelListPropertySpec` to properly resolve imports. +namespace margelo::nitro::rive { class HybridViewModelListPropertySpec; } // Forward declaration of `HybridViewModelNumberPropertySpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelNumberPropertySpec; } // Forward declaration of `HybridViewModelPropertySpec` to properly resolve imports. @@ -83,6 +85,7 @@ namespace margelo::nitro::rive { struct UnifiedRiveEvent; } #include "HybridViewModelEnumPropertySpec.hpp" #include "HybridViewModelImagePropertySpec.hpp" #include "HybridViewModelInstanceSpec.hpp" +#include "HybridViewModelListPropertySpec.hpp" #include "HybridViewModelNumberPropertySpec.hpp" #include "HybridViewModelPropertySpec.hpp" #include "HybridViewModelSpec.hpp" @@ -137,6 +140,8 @@ namespace RNRive { class HybridViewModelEnumPropertySpec_cxx; } namespace RNRive { class HybridViewModelImagePropertySpec_cxx; } // Forward declaration of `HybridViewModelInstanceSpec_cxx` to properly resolve imports. namespace RNRive { class HybridViewModelInstanceSpec_cxx; } +// Forward declaration of `HybridViewModelListPropertySpec_cxx` to properly resolve imports. +namespace RNRive { class HybridViewModelListPropertySpec_cxx; } // Forward declaration of `HybridViewModelNumberPropertySpec_cxx` to properly resolve imports. namespace RNRive { class HybridViewModelNumberPropertySpec_cxx; } // Forward declaration of `HybridViewModelPropertySpec_cxx` to properly resolve imports. diff --git a/nitrogen/generated/ios/c++/HybridViewModelInstanceSpecSwift.hpp b/nitrogen/generated/ios/c++/HybridViewModelInstanceSpecSwift.hpp index 873ac8a4..0ff3bff3 100644 --- a/nitrogen/generated/ios/c++/HybridViewModelInstanceSpecSwift.hpp +++ b/nitrogen/generated/ios/c++/HybridViewModelInstanceSpecSwift.hpp @@ -26,6 +26,8 @@ namespace margelo::nitro::rive { class HybridViewModelEnumPropertySpec; } namespace margelo::nitro::rive { class HybridViewModelTriggerPropertySpec; } // Forward declaration of `HybridViewModelImagePropertySpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelImagePropertySpec; } +// Forward declaration of `HybridViewModelListPropertySpec` to properly resolve imports. +namespace margelo::nitro::rive { class HybridViewModelListPropertySpec; } #include #include @@ -37,6 +39,7 @@ namespace margelo::nitro::rive { class HybridViewModelImagePropertySpec; } #include "HybridViewModelEnumPropertySpec.hpp" #include "HybridViewModelTriggerPropertySpec.hpp" #include "HybridViewModelImagePropertySpec.hpp" +#include "HybridViewModelListPropertySpec.hpp" #include "RNRive-Swift-Cxx-Umbrella.hpp" @@ -141,6 +144,14 @@ namespace margelo::nitro::rive { auto __value = std::move(__result.value()); return __value; } + inline std::optional> listProperty(const std::string& path) override { + auto __result = _swiftPart.listProperty(path); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } private: RNRive::HybridViewModelInstanceSpec_cxx _swiftPart; diff --git a/nitrogen/generated/ios/c++/HybridViewModelListPropertySpecSwift.cpp b/nitrogen/generated/ios/c++/HybridViewModelListPropertySpecSwift.cpp new file mode 100644 index 00000000..37311de9 --- /dev/null +++ b/nitrogen/generated/ios/c++/HybridViewModelListPropertySpecSwift.cpp @@ -0,0 +1,11 @@ +/// +/// HybridViewModelListPropertySpecSwift.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2025 Marc Rousavy @ Margelo +/// + +#include "HybridViewModelListPropertySpecSwift.hpp" + +namespace margelo::nitro::rive { +} // namespace margelo::nitro::rive diff --git a/nitrogen/generated/ios/c++/HybridViewModelListPropertySpecSwift.hpp b/nitrogen/generated/ios/c++/HybridViewModelListPropertySpecSwift.hpp new file mode 100644 index 00000000..94392acc --- /dev/null +++ b/nitrogen/generated/ios/c++/HybridViewModelListPropertySpecSwift.hpp @@ -0,0 +1,134 @@ +/// +/// HybridViewModelListPropertySpecSwift.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2025 Marc Rousavy @ Margelo +/// + +#pragma once + +#include "HybridViewModelListPropertySpec.hpp" + +// Forward declaration of `HybridViewModelListPropertySpec_cxx` to properly resolve imports. +namespace RNRive { class HybridViewModelListPropertySpec_cxx; } + +// Forward declaration of `HybridViewModelInstanceSpec` to properly resolve imports. +namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } +// Forward declaration of `HybridViewModelPropertySpecSwift` to properly resolve imports. +namespace margelo::nitro::rive { class HybridViewModelPropertySpecSwift; } + +#include +#include "HybridViewModelInstanceSpec.hpp" +#include +#include +#include "HybridViewModelPropertySpecSwift.hpp" + +#include "RNRive-Swift-Cxx-Umbrella.hpp" + +namespace margelo::nitro::rive { + + /** + * The C++ part of HybridViewModelListPropertySpec_cxx.swift. + * + * HybridViewModelListPropertySpecSwift (C++) accesses HybridViewModelListPropertySpec_cxx (Swift), and might + * contain some additional bridging code for C++ <> Swift interop. + * + * Since this obviously introduces an overhead, I hope at some point in + * the future, HybridViewModelListPropertySpec_cxx can directly inherit from the C++ class HybridViewModelListPropertySpec + * to simplify the whole structure and memory management. + */ + class HybridViewModelListPropertySpecSwift: public virtual HybridViewModelListPropertySpec, public virtual HybridViewModelPropertySpecSwift { + public: + // Constructor from a Swift instance + explicit HybridViewModelListPropertySpecSwift(const RNRive::HybridViewModelListPropertySpec_cxx& swiftPart): + HybridObject(HybridViewModelListPropertySpec::TAG), + HybridViewModelPropertySpecSwift(swiftPart), + _swiftPart(swiftPart) { } + + public: + // Get the Swift part + inline RNRive::HybridViewModelListPropertySpec_cxx& getSwiftPart() noexcept { + return _swiftPart; + } + + public: + inline size_t getExternalMemorySize() noexcept override { + return _swiftPart.getMemorySize(); + } + void dispose() noexcept override { + _swiftPart.dispose(); + } + std::string toString() override { + return _swiftPart.toString(); + } + + public: + // Properties + inline double getLength() noexcept override { + return _swiftPart.getLength(); + } + + public: + // Methods + inline std::optional> getInstanceAt(double index) override { + auto __result = _swiftPart.getInstanceAt(std::forward(index)); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } + inline void addInstance(const std::shared_ptr& instance) override { + auto __result = _swiftPart.addInstance(instance); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + } + inline bool addInstanceAt(const std::shared_ptr& instance, double index) override { + auto __result = _swiftPart.addInstanceAt(instance, std::forward(index)); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } + inline void removeInstance(const std::shared_ptr& instance) override { + auto __result = _swiftPart.removeInstance(instance); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + } + inline void removeInstanceAt(double index) override { + auto __result = _swiftPart.removeInstanceAt(std::forward(index)); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + } + inline bool swap(double index1, double index2) override { + auto __result = _swiftPart.swap(std::forward(index1), std::forward(index2)); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } + inline std::function addListener(const std::function& onChanged) override { + auto __result = _swiftPart.addListener(onChanged); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } + inline void removeListeners() override { + auto __result = _swiftPart.removeListeners(); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + } + + private: + RNRive::HybridViewModelListPropertySpec_cxx _swiftPart; + }; + +} // namespace margelo::nitro::rive diff --git a/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec.swift b/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec.swift index 115ba736..bbb13b10 100644 --- a/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec.swift +++ b/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec.swift @@ -21,6 +21,7 @@ public protocol HybridViewModelInstanceSpec_protocol: HybridObject { func enumProperty(path: String) throws -> (any HybridViewModelEnumPropertySpec)? func triggerProperty(path: String) throws -> (any HybridViewModelTriggerPropertySpec)? func imageProperty(path: String) throws -> (any HybridViewModelImagePropertySpec)? + func listProperty(path: String) throws -> (any HybridViewModelListPropertySpec)? } public extension HybridViewModelInstanceSpec_protocol { diff --git a/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec_cxx.swift b/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec_cxx.swift index 56e4002e..dc7d1647 100644 --- a/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec_cxx.swift +++ b/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec_cxx.swift @@ -268,4 +268,25 @@ open class HybridViewModelInstanceSpec_cxx { return bridge.create_Result_std__optional_std__shared_ptr_HybridViewModelImagePropertySpec___(__exceptionPtr) } } + + @inline(__always) + public final func listProperty(path: std.string) -> bridge.Result_std__optional_std__shared_ptr_HybridViewModelListPropertySpec___ { + do { + let __result = try self.__implementation.listProperty(path: String(path)) + let __resultCpp = { () -> bridge.std__optional_std__shared_ptr_HybridViewModelListPropertySpec__ in + if let __unwrappedValue = __result { + return bridge.create_std__optional_std__shared_ptr_HybridViewModelListPropertySpec__({ () -> bridge.std__shared_ptr_HybridViewModelListPropertySpec_ in + let __cxxWrapped = __unwrappedValue.getCxxWrapper() + return __cxxWrapped.getCxxPart() + }()) + } else { + return .init() + } + }() + return bridge.create_Result_std__optional_std__shared_ptr_HybridViewModelListPropertySpec___(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_std__optional_std__shared_ptr_HybridViewModelListPropertySpec___(__exceptionPtr) + } + } } diff --git a/nitrogen/generated/ios/swift/HybridViewModelListPropertySpec.swift b/nitrogen/generated/ios/swift/HybridViewModelListPropertySpec.swift new file mode 100644 index 00000000..59ab737f --- /dev/null +++ b/nitrogen/generated/ios/swift/HybridViewModelListPropertySpec.swift @@ -0,0 +1,63 @@ +/// +/// HybridViewModelListPropertySpec.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2025 Marc Rousavy @ Margelo +/// + +import Foundation +import NitroModules + +/// See ``HybridViewModelListPropertySpec`` +public protocol HybridViewModelListPropertySpec_protocol: HybridObject, HybridViewModelPropertySpec_protocol { + // Properties + var length: Double { get } + + // Methods + func getInstanceAt(index: Double) throws -> (any HybridViewModelInstanceSpec)? + func addInstance(instance: (any HybridViewModelInstanceSpec)) throws -> Void + func addInstanceAt(instance: (any HybridViewModelInstanceSpec), index: Double) throws -> Bool + func removeInstance(instance: (any HybridViewModelInstanceSpec)) throws -> Void + func removeInstanceAt(index: Double) throws -> Void + func swap(index1: Double, index2: Double) throws -> Bool + func addListener(onChanged: @escaping () -> Void) throws -> () -> Void + func removeListeners() throws -> Void +} + +public extension HybridViewModelListPropertySpec_protocol { + /// Default implementation of ``HybridObject.toString`` + func toString() -> String { + return "[HybridObject ViewModelListProperty]" + } +} + +/// See ``HybridViewModelListPropertySpec`` +open class HybridViewModelListPropertySpec_base: HybridViewModelPropertySpec_base { + private weak var cxxWrapper: HybridViewModelListPropertySpec_cxx? = nil + public override init() { super.init() } + public override func getCxxWrapper() -> HybridViewModelListPropertySpec_cxx { + #if DEBUG + guard self is HybridViewModelListPropertySpec else { + fatalError("`self` is not a `HybridViewModelListPropertySpec`! Did you accidentally inherit from `HybridViewModelListPropertySpec_base` instead of `HybridViewModelListPropertySpec`?") + } + #endif + if let cxxWrapper = self.cxxWrapper { + return cxxWrapper + } else { + let cxxWrapper = HybridViewModelListPropertySpec_cxx(self as! HybridViewModelListPropertySpec) + self.cxxWrapper = cxxWrapper + return cxxWrapper + } + } +} + +/** + * A Swift base-protocol representing the ViewModelListProperty HybridObject. + * Implement this protocol to create Swift-based instances of ViewModelListProperty. + * ```swift + * class HybridViewModelListProperty : HybridViewModelListPropertySpec { + * // ... + * } + * ``` + */ +public typealias HybridViewModelListPropertySpec = HybridViewModelListPropertySpec_protocol & HybridViewModelListPropertySpec_base diff --git a/nitrogen/generated/ios/swift/HybridViewModelListPropertySpec_cxx.swift b/nitrogen/generated/ios/swift/HybridViewModelListPropertySpec_cxx.swift new file mode 100644 index 00000000..9fc88d02 --- /dev/null +++ b/nitrogen/generated/ios/swift/HybridViewModelListPropertySpec_cxx.swift @@ -0,0 +1,248 @@ +/// +/// HybridViewModelListPropertySpec_cxx.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2025 Marc Rousavy @ Margelo +/// + +import Foundation +import NitroModules + +/** + * A class implementation that bridges HybridViewModelListPropertySpec over to C++. + * In C++, we cannot use Swift protocols - so we need to wrap it in a class to make it strongly defined. + * + * Also, some Swift types need to be bridged with special handling: + * - Enums need to be wrapped in Structs, otherwise they cannot be accessed bi-directionally (Swift bug: https://github.com/swiftlang/swift/issues/75330) + * - Other HybridObjects need to be wrapped/unwrapped from the Swift TCxx wrapper + * - Throwing methods need to be wrapped with a Result type, as exceptions cannot be propagated to C++ + */ +open class HybridViewModelListPropertySpec_cxx : HybridViewModelPropertySpec_cxx { + /** + * The Swift <> C++ bridge's namespace (`margelo::nitro::rive::bridge::swift`) + * from `RNRive-Swift-Cxx-Bridge.hpp`. + * This contains specialized C++ templates, and C++ helper functions that can be accessed from Swift. + */ + public typealias bridge = margelo.nitro.rive.bridge.swift + + /** + * Holds an instance of the `HybridViewModelListPropertySpec` Swift protocol. + */ + private var __implementation: any HybridViewModelListPropertySpec + + /** + * Holds a weak pointer to the C++ class that wraps the Swift class. + */ + private var __cxxPart: bridge.std__weak_ptr_HybridViewModelListPropertySpec_ + + /** + * Create a new `HybridViewModelListPropertySpec_cxx` that wraps the given `HybridViewModelListPropertySpec`. + * All properties and methods bridge to C++ types. + */ + public init(_ implementation: any HybridViewModelListPropertySpec) { + self.__implementation = implementation + self.__cxxPart = .init() + super.init(implementation) + } + + /** + * Get the actual `HybridViewModelListPropertySpec` instance this class wraps. + */ + @inline(__always) + public func getHybridViewModelListPropertySpec() -> any HybridViewModelListPropertySpec { + return __implementation + } + + /** + * Casts this instance to a retained unsafe raw pointer. + * This acquires one additional strong reference on the object! + */ + public override func toUnsafe() -> UnsafeMutableRawPointer { + return Unmanaged.passRetained(self).toOpaque() + } + + /** + * Casts an unsafe pointer to a `HybridViewModelListPropertySpec_cxx`. + * The pointer has to be a retained opaque `Unmanaged`. + * This removes one strong reference from the object! + */ + public override class func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> HybridViewModelListPropertySpec_cxx { + return Unmanaged.fromOpaque(pointer).takeRetainedValue() + } + + /** + * Gets (or creates) the C++ part of this Hybrid Object. + * The C++ part is a `std::shared_ptr`. + */ + public func getCxxPart() -> bridge.std__shared_ptr_HybridViewModelListPropertySpec_ { + let cachedCxxPart = self.__cxxPart.lock() + if Bool(fromCxx: cachedCxxPart) { + return cachedCxxPart + } else { + let newCxxPart = bridge.create_std__shared_ptr_HybridViewModelListPropertySpec_(self.toUnsafe()) + __cxxPart = bridge.weakify_std__shared_ptr_HybridViewModelListPropertySpec_(newCxxPart) + return newCxxPart + } + } + + public override func getCxxPart() -> bridge.std__shared_ptr_HybridViewModelPropertySpec_ { + let ownCxxPart: bridge.std__shared_ptr_HybridViewModelListPropertySpec_ = getCxxPart() + return bridge.upcast_ViewModelListProperty_to_ViewModelProperty(ownCxxPart) + } + + /** + * Get the memory size of the Swift class (plus size of any other allocations) + * so the JS VM can properly track it and garbage-collect the JS object if needed. + */ + @inline(__always) + public override var memorySize: Int { + return MemoryHelper.getSizeOf(self.__implementation) + self.__implementation.memorySize + } + + /** + * Call dispose() on the Swift class. + * This _may_ be called manually from JS. + */ + @inline(__always) + public override func dispose() { + self.__implementation.dispose() + } + + /** + * Call toString() on the Swift class. + */ + @inline(__always) + public override func toString() -> String { + return self.__implementation.toString() + } + + // Properties + public final var length: Double { + @inline(__always) + get { + return self.__implementation.length + } + } + + // Methods + @inline(__always) + public final func getInstanceAt(index: Double) -> bridge.Result_std__optional_std__shared_ptr_HybridViewModelInstanceSpec___ { + do { + let __result = try self.__implementation.getInstanceAt(index: index) + let __resultCpp = { () -> bridge.std__optional_std__shared_ptr_HybridViewModelInstanceSpec__ in + if let __unwrappedValue = __result { + return bridge.create_std__optional_std__shared_ptr_HybridViewModelInstanceSpec__({ () -> bridge.std__shared_ptr_HybridViewModelInstanceSpec_ in + let __cxxWrapped = __unwrappedValue.getCxxWrapper() + return __cxxWrapped.getCxxPart() + }()) + } else { + return .init() + } + }() + return bridge.create_Result_std__optional_std__shared_ptr_HybridViewModelInstanceSpec___(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_std__optional_std__shared_ptr_HybridViewModelInstanceSpec___(__exceptionPtr) + } + } + + @inline(__always) + public final func addInstance(instance: bridge.std__shared_ptr_HybridViewModelInstanceSpec_) -> bridge.Result_void_ { + do { + try self.__implementation.addInstance(instance: { () -> HybridViewModelInstanceSpec in + let __unsafePointer = bridge.get_std__shared_ptr_HybridViewModelInstanceSpec_(instance) + let __instance = HybridViewModelInstanceSpec_cxx.fromUnsafe(__unsafePointer) + return __instance.getHybridViewModelInstanceSpec() + }()) + return bridge.create_Result_void_() + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_void_(__exceptionPtr) + } + } + + @inline(__always) + public final func addInstanceAt(instance: bridge.std__shared_ptr_HybridViewModelInstanceSpec_, index: Double) -> bridge.Result_bool_ { + do { + let __result = try self.__implementation.addInstanceAt(instance: { () -> HybridViewModelInstanceSpec in + let __unsafePointer = bridge.get_std__shared_ptr_HybridViewModelInstanceSpec_(instance) + let __instance = HybridViewModelInstanceSpec_cxx.fromUnsafe(__unsafePointer) + return __instance.getHybridViewModelInstanceSpec() + }(), index: index) + let __resultCpp = __result + return bridge.create_Result_bool_(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_bool_(__exceptionPtr) + } + } + + @inline(__always) + public final func removeInstance(instance: bridge.std__shared_ptr_HybridViewModelInstanceSpec_) -> bridge.Result_void_ { + do { + try self.__implementation.removeInstance(instance: { () -> HybridViewModelInstanceSpec in + let __unsafePointer = bridge.get_std__shared_ptr_HybridViewModelInstanceSpec_(instance) + let __instance = HybridViewModelInstanceSpec_cxx.fromUnsafe(__unsafePointer) + return __instance.getHybridViewModelInstanceSpec() + }()) + return bridge.create_Result_void_() + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_void_(__exceptionPtr) + } + } + + @inline(__always) + public final func removeInstanceAt(index: Double) -> bridge.Result_void_ { + do { + try self.__implementation.removeInstanceAt(index: index) + return bridge.create_Result_void_() + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_void_(__exceptionPtr) + } + } + + @inline(__always) + public final func swap(index1: Double, index2: Double) -> bridge.Result_bool_ { + do { + let __result = try self.__implementation.swap(index1: index1, index2: index2) + let __resultCpp = __result + return bridge.create_Result_bool_(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_bool_(__exceptionPtr) + } + } + + @inline(__always) + public final func addListener(onChanged: bridge.Func_void) -> bridge.Result_std__function_void____ { + do { + let __result = try self.__implementation.addListener(onChanged: { () -> () -> Void in + let __wrappedFunction = bridge.wrap_Func_void(onChanged) + return { () -> Void in + __wrappedFunction.call() + } + }()) + let __resultCpp = { () -> bridge.Func_void in + let __closureWrapper = Func_void(__result) + return bridge.create_Func_void(__closureWrapper.toUnsafe()) + }() + return bridge.create_Result_std__function_void____(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_std__function_void____(__exceptionPtr) + } + } + + @inline(__always) + public final func removeListeners() -> bridge.Result_void_ { + do { + try self.__implementation.removeListeners() + return bridge.create_Result_void_() + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_void_(__exceptionPtr) + } + } +} diff --git a/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.cpp b/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.cpp index c1dfbae6..497960e9 100644 --- a/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.cpp +++ b/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.cpp @@ -22,6 +22,7 @@ namespace margelo::nitro::rive { prototype.registerHybridMethod("enumProperty", &HybridViewModelInstanceSpec::enumProperty); prototype.registerHybridMethod("triggerProperty", &HybridViewModelInstanceSpec::triggerProperty); prototype.registerHybridMethod("imageProperty", &HybridViewModelInstanceSpec::imageProperty); + prototype.registerHybridMethod("listProperty", &HybridViewModelInstanceSpec::listProperty); }); } diff --git a/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.hpp b/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.hpp index 125d6ca0..a709211f 100644 --- a/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.hpp +++ b/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.hpp @@ -27,6 +27,8 @@ namespace margelo::nitro::rive { class HybridViewModelEnumPropertySpec; } namespace margelo::nitro::rive { class HybridViewModelTriggerPropertySpec; } // Forward declaration of `HybridViewModelImagePropertySpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelImagePropertySpec; } +// Forward declaration of `HybridViewModelListPropertySpec` to properly resolve imports. +namespace margelo::nitro::rive { class HybridViewModelListPropertySpec; } #include #include @@ -38,6 +40,7 @@ namespace margelo::nitro::rive { class HybridViewModelImagePropertySpec; } #include "HybridViewModelEnumPropertySpec.hpp" #include "HybridViewModelTriggerPropertySpec.hpp" #include "HybridViewModelImagePropertySpec.hpp" +#include "HybridViewModelListPropertySpec.hpp" namespace margelo::nitro::rive { @@ -77,6 +80,7 @@ namespace margelo::nitro::rive { virtual std::optional> enumProperty(const std::string& path) = 0; virtual std::optional> triggerProperty(const std::string& path) = 0; virtual std::optional> imageProperty(const std::string& path) = 0; + virtual std::optional> listProperty(const std::string& path) = 0; protected: // Hybrid Setup diff --git a/nitrogen/generated/shared/c++/HybridViewModelListPropertySpec.cpp b/nitrogen/generated/shared/c++/HybridViewModelListPropertySpec.cpp new file mode 100644 index 00000000..f92c84b6 --- /dev/null +++ b/nitrogen/generated/shared/c++/HybridViewModelListPropertySpec.cpp @@ -0,0 +1,30 @@ +/// +/// HybridViewModelListPropertySpec.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2025 Marc Rousavy @ Margelo +/// + +#include "HybridViewModelListPropertySpec.hpp" + +namespace margelo::nitro::rive { + + void HybridViewModelListPropertySpec::loadHybridMethods() { + // load base methods/properties + HybridObject::loadHybridMethods(); + HybridViewModelPropertySpec::loadHybridMethods(); + // load custom methods/properties + registerHybrids(this, [](Prototype& prototype) { + prototype.registerHybridGetter("length", &HybridViewModelListPropertySpec::getLength); + prototype.registerHybridMethod("getInstanceAt", &HybridViewModelListPropertySpec::getInstanceAt); + prototype.registerHybridMethod("addInstance", &HybridViewModelListPropertySpec::addInstance); + prototype.registerHybridMethod("addInstanceAt", &HybridViewModelListPropertySpec::addInstanceAt); + prototype.registerHybridMethod("removeInstance", &HybridViewModelListPropertySpec::removeInstance); + prototype.registerHybridMethod("removeInstanceAt", &HybridViewModelListPropertySpec::removeInstanceAt); + prototype.registerHybridMethod("swap", &HybridViewModelListPropertySpec::swap); + prototype.registerHybridMethod("addListener", &HybridViewModelListPropertySpec::addListener); + prototype.registerHybridMethod("removeListeners", &HybridViewModelListPropertySpec::removeListeners); + }); + } + +} // namespace margelo::nitro::rive diff --git a/nitrogen/generated/shared/c++/HybridViewModelListPropertySpec.hpp b/nitrogen/generated/shared/c++/HybridViewModelListPropertySpec.hpp new file mode 100644 index 00000000..25db0a91 --- /dev/null +++ b/nitrogen/generated/shared/c++/HybridViewModelListPropertySpec.hpp @@ -0,0 +1,76 @@ +/// +/// HybridViewModelListPropertySpec.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2025 Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +// Forward declaration of `HybridViewModelInstanceSpec` to properly resolve imports. +namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } +// Forward declaration of `HybridViewModelPropertySpec` to properly resolve imports. +namespace margelo::nitro::rive { class HybridViewModelPropertySpec; } + +#include +#include "HybridViewModelInstanceSpec.hpp" +#include +#include +#include "HybridViewModelPropertySpec.hpp" + +namespace margelo::nitro::rive { + + using namespace margelo::nitro; + + /** + * An abstract base class for `ViewModelListProperty` + * Inherit this class to create instances of `HybridViewModelListPropertySpec` in C++. + * You must explicitly call `HybridObject`'s constructor yourself, because it is virtual. + * @example + * ```cpp + * class HybridViewModelListProperty: public HybridViewModelListPropertySpec { + * public: + * HybridViewModelListProperty(...): HybridObject(TAG) { ... } + * // ... + * }; + * ``` + */ + class HybridViewModelListPropertySpec: public virtual HybridObject, public virtual HybridViewModelPropertySpec { + public: + // Constructor + explicit HybridViewModelListPropertySpec(): HybridObject(TAG) { } + + // Destructor + ~HybridViewModelListPropertySpec() override = default; + + public: + // Properties + virtual double getLength() = 0; + + public: + // Methods + virtual std::optional> getInstanceAt(double index) = 0; + virtual void addInstance(const std::shared_ptr& instance) = 0; + virtual bool addInstanceAt(const std::shared_ptr& instance, double index) = 0; + virtual void removeInstance(const std::shared_ptr& instance) = 0; + virtual void removeInstanceAt(double index) = 0; + virtual bool swap(double index1, double index2) = 0; + virtual std::function addListener(const std::function& onChanged) = 0; + virtual void removeListeners() = 0; + + protected: + // Hybrid Setup + void loadHybridMethods() override; + + protected: + // Tag for logging + static constexpr auto TAG = "ViewModelListProperty"; + }; + +} // namespace margelo::nitro::rive diff --git a/src/index.tsx b/src/index.tsx index deeb40a0..5896add0 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -30,6 +30,7 @@ export type { ViewModelEnumProperty, ViewModelTriggerProperty, ViewModelImageProperty, + ViewModelListProperty, } from './specs/ViewModel.nitro'; export { Fit } from './core/Fit'; export { Alignment } from './core/Alignment'; diff --git a/src/specs/ViewModel.nitro.ts b/src/specs/ViewModel.nitro.ts index 59a09c1b..6ee2c327 100644 --- a/src/specs/ViewModel.nitro.ts +++ b/src/specs/ViewModel.nitro.ts @@ -52,6 +52,9 @@ export interface ViewModelInstance /** Get an image property from the view model instance at the given path */ imageProperty(path: string): ViewModelImageProperty | undefined; + + /** Get a list property from the view model instance at the given path */ + listProperty(path: string): ViewModelListProperty | undefined; } export interface ViewModelProperty @@ -124,3 +127,28 @@ export interface ViewModelImageProperty /** Add a listener to the view model image property. Returns a function to remove the listener. */ addListener(onChanged: () => void): () => void; } + +/** + * A list property that contains a dynamic collection of {@link ViewModelInstance} objects. + * @see {@link https://rive.app/docs/runtimes/data-binding#lists Rive Data Binding Lists} + */ +export interface ViewModelListProperty + extends ViewModelProperty, + ObservableProperty { + /** The number of instances in the list */ + readonly length: number; + /** Get the instance at the given index */ + getInstanceAt(index: number): ViewModelInstance | undefined; + /** Add an instance to the end of the list */ + addInstance(instance: ViewModelInstance): void; + /** Add an instance at the given index, returns true if successful */ + addInstanceAt(instance: ViewModelInstance, index: number): boolean; + /** Remove an instance from the list */ + removeInstance(instance: ViewModelInstance): void; + /** Remove the instance at the given index */ + removeInstanceAt(index: number): void; + /** Swap the instances at the given indices, returns true if successful */ + swap(index1: number, index2: number): boolean; + /** Add a listener to be notified when the list changes. Returns a function to remove the listener. */ + addListener(onChanged: () => void): () => void; +}