diff --git a/RNRive.podspec b/RNRive.podspec index 99664968..dc62563b 100644 --- a/RNRive.podspec +++ b/RNRive.podspec @@ -24,11 +24,17 @@ if !rive_ios_version && package['runtimeVersions'] && package['runtimeVersions'] rive_ios_version = package['runtimeVersions']['ios'] end -if !rive_ios_version +use_rive_spm = ENV['USE_RIVE_SPM'] == '1' || (defined?($UseRiveSPM) && $UseRiveSPM) + +if !use_rive_spm && !rive_ios_version raise "Internal Error: Failed to determine Rive iOS SDK version. Please ensure package.json contains 'runtimeVersions.ios'" end -Pod::UI.puts "@rive-app/react-native: Rive iOS SDK #{rive_ios_version}" +if use_rive_spm + Pod::UI.puts "@rive-app/react-native: Using RiveRuntime via Swift Package Manager" +else + Pod::UI.puts "@rive-app/react-native: Rive iOS SDK #{rive_ios_version}" +end Pod::Spec.new do |s| s.name = "RNRive" @@ -47,7 +53,19 @@ Pod::Spec.new do |s| load 'nitrogen/generated/ios/RNRive+autolinking.rb' add_nitrogen_files(s) - s.dependency "RiveRuntime", rive_ios_version + if use_rive_spm + spm_dependency(s, + url: 'https://github.com/rive-app/rive-ios.git', + requirement: {kind: 'upToNextMajorVersion', minimumVersion: '6.15.0'}, + products: ['RiveRuntime'] + ) + else + s.dependency "RiveRuntime", rive_ios_version + end install_modules_dependencies(s) + + if use_rive_spm + s.xcconfig = { 'OTHER_SWIFT_FLAGS' => '$(inherited) -DRIVE_EXPERIMENTAL_API' } + end end 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 77a37f60..18a9b584 100644 --- a/android/src/main/java/com/margelo/nitro/rive/HybridRiveFile.kt +++ b/android/src/main/java/com/margelo/nitro/rive/HybridRiveFile.kt @@ -3,6 +3,7 @@ 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.core.Promise import java.lang.ref.WeakReference import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -96,6 +97,22 @@ class HybridRiveFile : HybridRiveFileSpec() { } } + override fun getEnums(): Promise> { + return Promise.async { + val file = riveFile ?: return@async emptyArray() + try { + file.enums.map { enum -> + RiveEnumDefinition( + name = enum.name, + values = enum.values.toTypedArray() + ) + }.toTypedArray() + } catch (e: NoSuchMethodError) { + throw UnsupportedOperationException("getEnums requires rive-android SDK with enums support") + } + } + } + override fun dispose() { scope.cancel() weakViews.clear() diff --git a/example/__tests__/viewmodel-properties.harness.ts b/example/__tests__/viewmodel-properties.harness.ts index 783fe5c3..e8736a6a 100644 --- a/example/__tests__/viewmodel-properties.harness.ts +++ b/example/__tests__/viewmodel-properties.harness.ts @@ -1,5 +1,8 @@ import { describe, it, expect } from 'react-native-harness'; -import type { ViewModelInstance } from '@rive-app/react-native'; +import type { + ViewModelInstance, + RiveEnumDefinition, +} from '@rive-app/react-native'; import { RiveFileFactory } from '@rive-app/react-native'; const DATABINDING = require('../assets/rive/databinding.riv'); @@ -225,3 +228,18 @@ describe('Property Listeners', () => { expect(() => cleanup2()).not.toThrow(); }); }); + +describe('RiveFile Enums', () => { + const expectedEnums: RiveEnumDefinition[] = [ + { name: 'Pets', values: ['chipmunk', 'rat', 'frog', 'owl', 'cat', 'dog'] }, + ]; + + it('getEnums returns enum definitions from file', async () => { + const file = await RiveFileFactory.fromSource(DATABINDING, undefined); + const enums = await file.getEnums(); + + expect(enums.length).toBe(expectedEnums.length); + expect(enums[0]?.name).toBe(expectedEnums[0]?.name); + expect(enums[0]?.values).toEqual(expectedEnums[0]?.values); + }); +}); diff --git a/example/ios/Podfile b/example/ios/Podfile index c04206ab..bcbc85a5 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,7 @@ ENV['RCT_NEW_ARCH_ENABLED'] = '1' +$UseRiveSPM = ENV['USE_RIVE_SPM'] == '1' + # Resolve react_native_pods.rb with node to allow for hoisting require Pod::Executable.execute_command('node', ['-p', 'require.resolve( diff --git a/example/ios/RiveExample.xcworkspace/xcshareddata/swiftpm/Package.resolved b/example/ios/RiveExample.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000..5989f508 --- /dev/null +++ b/example/ios/RiveExample.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,15 @@ +{ + "originHash" : "fe80d800fd3546609c8e9654610353e79fda7758e5303f523f9d300219eddff7", + "pins" : [ + { + "identity" : "rive-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/rive-app/rive-ios.git", + "state" : { + "revision" : "40fb81bc71de8902d45364a0709ee1bde37c10d7", + "version" : "6.15.0" + } + } + ], + "version" : 3 +} diff --git a/ios/HybridRiveFile.swift b/ios/HybridRiveFile.swift index b7e8d5e2..73629347 100644 --- a/ios/HybridRiveFile.swift +++ b/ios/HybridRiveFile.swift @@ -1,7 +1,17 @@ +import NitroModules import RiveRuntime +#if RIVE_EXPERIMENTAL_API +@_spi(RiveExperimental) import RiveRuntime +#endif typealias ReferencedAssetCache = [String: RiveFileAsset] +/// Source for creating experimental File instances +enum ExperimentalFileSource { + case data(Data) + case resource(String) +} + class HybridRiveFile: HybridRiveFileSpec, RiveViewSource { var riveFile: RiveFile? var referencedAssetCache: ReferencedAssetCache? @@ -9,6 +19,9 @@ class HybridRiveFile: HybridRiveFileSpec, RiveViewSource { var cachedFactory: RiveFactory? private var weakViews: [Weak] = [] + /// Source for experimental API - stored to create experimental File on demand + var experimentalSource: ExperimentalFileSource? + public func setRiveFile(_ riveFile: RiveFile) { self.riveFile = riveFile } @@ -118,6 +131,42 @@ class HybridRiveFile: HybridRiveFileSpec, RiveViewSource { } } + func getEnums() throws -> Promise<[RiveEnumDefinition]> { + return Promise.async { [weak self] in + #if RIVE_EXPERIMENTAL_API + guard let source = self?.experimentalSource else { + throw NSError( + domain: "RiveError", + code: 1, + userInfo: [NSLocalizedDescriptionKey: "getEnums requires experimental API. Use USE_RIVE_SPM=1 with pod install."] + ) + } + + // Create worker and experimental file on demand + let worker = await Worker() + let experimentalSource: Source + switch source { + case .data(let data): + experimentalSource = .data(data) + case .resource(let name): + experimentalSource = .local(name, nil) + } + + let file = try await File(source: experimentalSource, worker: worker) + let viewModelEnums = try await file.getViewModelEnums() + return viewModelEnums.map { vmEnum in + RiveEnumDefinition(name: vmEnum.name, values: vmEnum.values) + } + #else + throw NSError( + domain: "RiveError", + code: 1, + userInfo: [NSLocalizedDescriptionKey: "getEnums requires RiveRuntime 6.15.0+ with experimental API. Use USE_RIVE_SPM=1 with pod install."] + ) + #endif + } + } + func dispose() { weakViews.removeAll() referencedAssetCache = nil diff --git a/ios/HybridRiveFileFactory.swift b/ios/HybridRiveFileFactory.swift index 305871a1..03b9ee28 100644 --- a/ios/HybridRiveFileFactory.swift +++ b/ios/HybridRiveFileFactory.swift @@ -16,6 +16,7 @@ final class HybridRiveFileFactory: HybridRiveFileFactorySpec, @unchecked Sendabl /// - fileWithCustomAssetLoader: Closure to load the file with a custom asset loader. /// - file: Closure to load the file without a custom asset loader. /// - referencedAssets: Optional referenced assets. + /// - experimentalSource: Closure to extract the experimental source from the prepared result. /// - Returns: A promise resolving to a `HybridRiveFileSpec`. /// - Throws: Runtime errors if any step fails. func genericFrom( @@ -23,12 +24,14 @@ final class HybridRiveFileFactory: HybridRiveFileFactorySpec, @unchecked Sendabl prepare: @escaping (CheckResult) async throws -> Prepared, fileWithCustomAssetLoader: @escaping (Prepared, @escaping LoadAsset) throws -> RiveFile, file: @escaping (Prepared) throws -> RiveFile, - referencedAssets: ReferencedAssetsType? + referencedAssets: ReferencedAssetsType?, + experimentalSource: @escaping (Prepared) -> ExperimentalFileSource? ) throws -> Promise<(any HybridRiveFileSpec)> { return Promise.async { do { let checked = try check() let prepared = try await prepare(checked) + let expSource = experimentalSource(prepared) let result = try await withCheckedThrowingContinuation { continuation in DispatchQueue.global(qos: .userInitiated).async { @@ -73,6 +76,7 @@ final class HybridRiveFileFactory: HybridRiveFileFactorySpec, @unchecked Sendabl hybridRiveFile.cachedFactory = factory } hybridRiveFile.assetLoader = result.loader + hybridRiveFile.experimentalSource = expSource return hybridRiveFile } catch let error as NSError { throw RuntimeError.error( @@ -98,7 +102,8 @@ final class HybridRiveFileFactory: HybridRiveFileFactorySpec, @unchecked Sendabl try RiveFile(data: data, loadCdn: loadCdn, customAssetLoader: loader) }, file: { (data) in try RiveFile(data: data, loadCdn: loadCdn) }, - referencedAssets: referencedAssets + referencedAssets: referencedAssets, + experimentalSource: { data in .data(data) } ) } @@ -119,7 +124,8 @@ final class HybridRiveFileFactory: HybridRiveFileFactorySpec, @unchecked Sendabl try RiveFile(data: data, loadCdn: loadCdn, customAssetLoader: loader) }, file: { (data) in try RiveFile(data: data, loadCdn: loadCdn) }, - referencedAssets: referencedAssets + referencedAssets: referencedAssets, + experimentalSource: { data in .data(data) } ) } @@ -137,7 +143,8 @@ final class HybridRiveFileFactory: HybridRiveFileFactorySpec, @unchecked Sendabl try RiveFile(resource: resource, loadCdn: loadCdn, customAssetLoader: loader) }, file: { (resource) in try RiveFile(resource: resource, loadCdn: loadCdn) }, - referencedAssets: referencedAssets + referencedAssets: referencedAssets, + experimentalSource: { resource in .resource(resource) } ) } @@ -157,7 +164,8 @@ final class HybridRiveFileFactory: HybridRiveFileFactorySpec, @unchecked Sendabl try RiveFile(data: data, loadCdn: loadCdn, customAssetLoader: loader) }, file: { (data) in try RiveFile(data: data, loadCdn: loadCdn) }, - referencedAssets: referencedAssets + referencedAssets: referencedAssets, + experimentalSource: { data in .data(data) } ) } } diff --git a/nitrogen/generated/android/c++/JHybridRiveFileSpec.cpp b/nitrogen/generated/android/c++/JHybridRiveFileSpec.cpp index 0c0b133b..dbef3aad 100644 --- a/nitrogen/generated/android/c++/JHybridRiveFileSpec.cpp +++ b/nitrogen/generated/android/c++/JHybridRiveFileSpec.cpp @@ -11,6 +11,8 @@ namespace margelo::nitro::rive { class HybridViewModelSpec; } // Forward declaration of `HybridBindableArtboardSpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridBindableArtboardSpec; } +// Forward declaration of `RiveEnumDefinition` to properly resolve imports. +namespace margelo::nitro::rive { struct RiveEnumDefinition; } // Forward declaration of `ArtboardBy` to properly resolve imports. namespace margelo::nitro::rive { struct ArtboardBy; } // Forward declaration of `ArtboardByTypes` to properly resolve imports. @@ -30,6 +32,10 @@ namespace margelo::nitro::rive { class HybridRiveImageSpec; } #include "JHybridViewModelSpec.hpp" #include "HybridBindableArtboardSpec.hpp" #include "JHybridBindableArtboardSpec.hpp" +#include "RiveEnumDefinition.hpp" +#include +#include +#include "JRiveEnumDefinition.hpp" #include "ArtboardBy.hpp" #include "JArtboardBy.hpp" #include "ArtboardByTypes.hpp" @@ -128,5 +134,30 @@ namespace margelo::nitro::rive { auto __result = method(_javaPart, jni::make_jstring(name)); return __result->cthis()->shared_cast(); } + std::shared_ptr>> JHybridRiveFileSpec::getEnums() { + static const auto method = javaClassStatic()->getMethod()>("getEnums"); + auto __result = method(_javaPart); + return [&]() { + auto __promise = Promise>::create(); + __result->cthis()->addOnResolvedListener([=](const jni::alias_ref& __boxedResult) { + auto __result = jni::static_ref_cast>(__boxedResult); + __promise->resolve([&]() { + size_t __size = __result->size(); + std::vector __vector; + __vector.reserve(__size); + for (size_t __i = 0; __i < __size; __i++) { + auto __element = __result->getElement(__i); + __vector.push_back(__element->toCpp()); + } + return __vector; + }()); + }); + __result->cthis()->addOnRejectedListener([=](const jni::alias_ref& __throwable) { + jni::JniException __jniError(__throwable); + __promise->reject(std::make_exception_ptr(__jniError)); + }); + return __promise; + }(); + } } // namespace margelo::nitro::rive diff --git a/nitrogen/generated/android/c++/JHybridRiveFileSpec.hpp b/nitrogen/generated/android/c++/JHybridRiveFileSpec.hpp index bcd57e0a..580bf580 100644 --- a/nitrogen/generated/android/c++/JHybridRiveFileSpec.hpp +++ b/nitrogen/generated/android/c++/JHybridRiveFileSpec.hpp @@ -62,6 +62,7 @@ namespace margelo::nitro::rive { std::optional> defaultArtboardViewModel(const std::optional& artboardBy) override; void updateReferencedAssets(const ReferencedAssetsType& referencedAssets) override; std::shared_ptr getBindableArtboard(const std::string& name) override; + std::shared_ptr>> getEnums() override; private: friend HybridBase; diff --git a/nitrogen/generated/android/c++/JRiveEnumDefinition.hpp b/nitrogen/generated/android/c++/JRiveEnumDefinition.hpp new file mode 100644 index 00000000..1c772dc6 --- /dev/null +++ b/nitrogen/generated/android/c++/JRiveEnumDefinition.hpp @@ -0,0 +1,80 @@ +/// +/// JRiveEnumDefinition.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include "RiveEnumDefinition.hpp" + +#include +#include + +namespace margelo::nitro::rive { + + using namespace facebook; + + /** + * The C++ JNI bridge between the C++ struct "RiveEnumDefinition" and the the Kotlin data class "RiveEnumDefinition". + */ + struct JRiveEnumDefinition final: public jni::JavaClass { + public: + static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/rive/RiveEnumDefinition;"; + + public: + /** + * Convert this Java/Kotlin-based struct to the C++ struct RiveEnumDefinition by copying all values to C++. + */ + [[maybe_unused]] + [[nodiscard]] + RiveEnumDefinition toCpp() const { + static const auto clazz = javaClassStatic(); + static const auto fieldName = clazz->getField("name"); + jni::local_ref name = this->getFieldValue(fieldName); + static const auto fieldValues = clazz->getField>("values"); + jni::local_ref> values = this->getFieldValue(fieldValues); + return RiveEnumDefinition( + name->toStdString(), + [&]() { + size_t __size = values->size(); + std::vector __vector; + __vector.reserve(__size); + for (size_t __i = 0; __i < __size; __i++) { + auto __element = values->getElement(__i); + __vector.push_back(__element->toStdString()); + } + return __vector; + }() + ); + } + + public: + /** + * Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java. + */ + [[maybe_unused]] + static jni::local_ref fromCpp(const RiveEnumDefinition& value) { + using JSignature = JRiveEnumDefinition(jni::alias_ref, jni::alias_ref>); + static const auto clazz = javaClassStatic(); + static const auto create = clazz->getStaticMethod("fromCpp"); + return create( + clazz, + jni::make_jstring(value.name), + [&]() { + size_t __size = value.values.size(); + jni::local_ref> __array = jni::JArrayClass::newArray(__size); + for (size_t __i = 0; __i < __size; __i++) { + const auto& __element = value.values[__i]; + auto __elementJni = jni::make_jstring(__element); + __array->setElement(__i, *__elementJni); + } + return __array; + }() + ); + } + }; + +} // namespace margelo::nitro::rive diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridRiveFileSpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridRiveFileSpec.kt index 0c5de270..f84ac8fb 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridRiveFileSpec.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridRiveFileSpec.kt @@ -10,6 +10,7 @@ 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.Promise import com.margelo.nitro.core.HybridObject /** @@ -74,6 +75,10 @@ abstract class HybridRiveFileSpec: HybridObject() { @DoNotStrip @Keep abstract fun getBindableArtboard(name: String): HybridBindableArtboardSpec + + @DoNotStrip + @Keep + abstract fun getEnums(): Promise> private external fun initHybrid(): HybridData diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/RiveEnumDefinition.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/RiveEnumDefinition.kt new file mode 100644 index 00000000..a463258a --- /dev/null +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/RiveEnumDefinition.kt @@ -0,0 +1,41 @@ +/// +/// RiveEnumDefinition.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.rive + +import androidx.annotation.Keep +import com.facebook.proguard.annotations.DoNotStrip + + +/** + * Represents the JavaScript object/struct "RiveEnumDefinition". + */ +@DoNotStrip +@Keep +data class RiveEnumDefinition( + @DoNotStrip + @Keep + val name: String, + @DoNotStrip + @Keep + val values: Array +) { + /* primary constructor */ + + companion object { + /** + * Constructor called from C++ + */ + @DoNotStrip + @Keep + @Suppress("unused") + @JvmStatic + private fun fromCpp(name: String, values: Array): RiveEnumDefinition { + return RiveEnumDefinition(name, values) + } + } +} diff --git a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp index bd53b582..321931dc 100644 --- a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp +++ b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp @@ -96,6 +96,22 @@ namespace margelo::nitro::rive::bridge::swift { return swiftPart.toUnsafe(); } + // pragma MARK: std::function& /* result */)> + Func_void_std__vector_RiveEnumDefinition_ create_Func_void_std__vector_RiveEnumDefinition_(void* NON_NULL swiftClosureWrapper) noexcept { + auto swiftClosure = RNRive::Func_void_std__vector_RiveEnumDefinition_::fromUnsafe(swiftClosureWrapper); + return [swiftClosure = std::move(swiftClosure)](const std::vector& result) mutable -> void { + swiftClosure.call(result); + }; + } + + // pragma MARK: std::function + Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* NON_NULL swiftClosureWrapper) noexcept { + auto swiftClosure = RNRive::Func_void_std__exception_ptr::fromUnsafe(swiftClosureWrapper); + return [swiftClosure = std::move(swiftClosure)](const std::exception_ptr& error) mutable -> void { + swiftClosure.call(error); + }; + } + // pragma MARK: std::shared_ptr std::shared_ptr create_std__shared_ptr_HybridRiveFileSpec_(void* NON_NULL swiftUnsafePointer) noexcept { RNRive::HybridRiveFileSpec_cxx swiftPart = RNRive::HybridRiveFileSpec_cxx::fromUnsafe(swiftUnsafePointer); @@ -120,14 +136,6 @@ namespace margelo::nitro::rive::bridge::swift { }; } - // pragma MARK: std::function - Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* NON_NULL swiftClosureWrapper) noexcept { - auto swiftClosure = RNRive::Func_void_std__exception_ptr::fromUnsafe(swiftClosureWrapper); - return [swiftClosure = std::move(swiftClosure)](const std::exception_ptr& error) mutable -> void { - swiftClosure.call(error); - }; - } - // pragma MARK: std::shared_ptr std::shared_ptr create_std__shared_ptr_HybridRiveFileFactorySpec_(void* NON_NULL swiftUnsafePointer) noexcept { RNRive::HybridRiveFileFactorySpec_cxx swiftPart = RNRive::HybridRiveFileFactorySpec_cxx::fromUnsafe(swiftUnsafePointer); diff --git a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp index 7946fcfe..55ca0004 100644 --- a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp +++ b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp @@ -62,6 +62,8 @@ namespace margelo::nitro::rive { class HybridViewModelTriggerPropertySpec; } namespace margelo::nitro::rive { struct ReferencedAssetsType; } // Forward declaration of `ResolvedReferencedAsset` to properly resolve imports. namespace margelo::nitro::rive { struct ResolvedReferencedAsset; } +// Forward declaration of `RiveEnumDefinition` to properly resolve imports. +namespace margelo::nitro::rive { struct RiveEnumDefinition; } // Forward declaration of `RiveErrorType` to properly resolve imports. namespace margelo::nitro::rive { enum class RiveErrorType; } // Forward declaration of `RiveError` to properly resolve imports. @@ -139,6 +141,7 @@ namespace RNRive { class HybridViewModelTriggerPropertySpec_cxx; } #include "HybridViewModelTriggerPropertySpec.hpp" #include "ReferencedAssetsType.hpp" #include "ResolvedReferencedAsset.hpp" +#include "RiveEnumDefinition.hpp" #include "RiveError.hpp" #include "RiveErrorType.hpp" #include "RiveEventType.hpp" @@ -344,6 +347,73 @@ namespace margelo::nitro::rive::bridge::swift { return vector; } + // pragma MARK: std::vector + /** + * Specialized version of `std::vector`. + */ + using std__vector_RiveEnumDefinition_ = std::vector; + inline std::vector create_std__vector_RiveEnumDefinition_(size_t size) noexcept { + std::vector vector; + vector.reserve(size); + return vector; + } + + // pragma MARK: std::shared_ptr>> + /** + * Specialized version of `std::shared_ptr>>`. + */ + using std__shared_ptr_Promise_std__vector_RiveEnumDefinition___ = std::shared_ptr>>; + inline std::shared_ptr>> create_std__shared_ptr_Promise_std__vector_RiveEnumDefinition___() noexcept { + return Promise>::create(); + } + inline PromiseHolder> wrap_std__shared_ptr_Promise_std__vector_RiveEnumDefinition___(std::shared_ptr>> promise) noexcept { + return PromiseHolder>(std::move(promise)); + } + + // pragma MARK: std::function& /* result */)> + /** + * Specialized version of `std::function&)>`. + */ + using Func_void_std__vector_RiveEnumDefinition_ = std::function& /* result */)>; + /** + * Wrapper class for a `std::function& / * result * /)>`, this can be used from Swift. + */ + class Func_void_std__vector_RiveEnumDefinition__Wrapper final { + public: + explicit Func_void_std__vector_RiveEnumDefinition__Wrapper(std::function& /* result */)>&& func): _function(std::make_unique& /* result */)>>(std::move(func))) {} + inline void call(std::vector result) const noexcept { + _function->operator()(result); + } + private: + std::unique_ptr& /* result */)>> _function; + } SWIFT_NONCOPYABLE; + Func_void_std__vector_RiveEnumDefinition_ create_Func_void_std__vector_RiveEnumDefinition_(void* NON_NULL swiftClosureWrapper) noexcept; + inline Func_void_std__vector_RiveEnumDefinition__Wrapper wrap_Func_void_std__vector_RiveEnumDefinition_(Func_void_std__vector_RiveEnumDefinition_ value) noexcept { + return Func_void_std__vector_RiveEnumDefinition__Wrapper(std::move(value)); + } + + // pragma MARK: std::function + /** + * Specialized version of `std::function`. + */ + using Func_void_std__exception_ptr = std::function; + /** + * Wrapper class for a `std::function`, this can be used from Swift. + */ + class Func_void_std__exception_ptr_Wrapper final { + public: + explicit Func_void_std__exception_ptr_Wrapper(std::function&& func): _function(std::make_unique>(std::move(func))) {} + inline void call(std::exception_ptr error) const noexcept { + _function->operator()(error); + } + private: + std::unique_ptr> _function; + } SWIFT_NONCOPYABLE; + Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* NON_NULL swiftClosureWrapper) noexcept; + inline Func_void_std__exception_ptr_Wrapper wrap_Func_void_std__exception_ptr(Func_void_std__exception_ptr value) noexcept { + return Func_void_std__exception_ptr_Wrapper(std::move(value)); + } + // pragma MARK: std::shared_ptr /** * Specialized version of `std::shared_ptr`. @@ -383,6 +453,15 @@ namespace margelo::nitro::rive::bridge::swift { return Result>::withError(error); } + // pragma MARK: Result>>> + using Result_std__shared_ptr_Promise_std__vector_RiveEnumDefinition____ = Result>>>; + inline Result_std__shared_ptr_Promise_std__vector_RiveEnumDefinition____ create_Result_std__shared_ptr_Promise_std__vector_RiveEnumDefinition____(const std::shared_ptr>>& value) noexcept { + return Result>>>::withValue(value); + } + inline Result_std__shared_ptr_Promise_std__vector_RiveEnumDefinition____ create_Result_std__shared_ptr_Promise_std__vector_RiveEnumDefinition____(const std::exception_ptr& error) noexcept { + return Result>>>::withError(error); + } + // pragma MARK: std::shared_ptr>> /** * Specialized version of `std::shared_ptr>>`. @@ -417,28 +496,6 @@ namespace margelo::nitro::rive::bridge::swift { return Func_void_std__shared_ptr_HybridRiveFileSpec__Wrapper(std::move(value)); } - // pragma MARK: std::function - /** - * Specialized version of `std::function`. - */ - using Func_void_std__exception_ptr = std::function; - /** - * Wrapper class for a `std::function`, this can be used from Swift. - */ - class Func_void_std__exception_ptr_Wrapper final { - public: - explicit Func_void_std__exception_ptr_Wrapper(std::function&& func): _function(std::make_unique>(std::move(func))) {} - inline void call(std::exception_ptr error) const noexcept { - _function->operator()(error); - } - private: - std::unique_ptr> _function; - } SWIFT_NONCOPYABLE; - Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* NON_NULL swiftClosureWrapper) noexcept; - inline Func_void_std__exception_ptr_Wrapper wrap_Func_void_std__exception_ptr(Func_void_std__exception_ptr value) noexcept { - return Func_void_std__exception_ptr_Wrapper(std::move(value)); - } - // pragma MARK: std::optional /** * Specialized version of `std::optional`. diff --git a/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp b/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp index 3f761ca0..026d4ca2 100644 --- a/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp +++ b/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp @@ -62,6 +62,8 @@ namespace margelo::nitro::rive { class HybridViewModelTriggerPropertySpec; } namespace margelo::nitro::rive { struct ReferencedAssetsType; } // Forward declaration of `ResolvedReferencedAsset` to properly resolve imports. namespace margelo::nitro::rive { struct ResolvedReferencedAsset; } +// Forward declaration of `RiveEnumDefinition` to properly resolve imports. +namespace margelo::nitro::rive { struct RiveEnumDefinition; } // Forward declaration of `RiveErrorType` to properly resolve imports. namespace margelo::nitro::rive { enum class RiveErrorType; } // Forward declaration of `RiveError` to properly resolve imports. @@ -99,6 +101,7 @@ namespace margelo::nitro::rive { struct UnifiedRiveEvent; } #include "HybridViewModelTriggerPropertySpec.hpp" #include "ReferencedAssetsType.hpp" #include "ResolvedReferencedAsset.hpp" +#include "RiveEnumDefinition.hpp" #include "RiveError.hpp" #include "RiveErrorType.hpp" #include "RiveEventType.hpp" diff --git a/nitrogen/generated/ios/c++/HybridRiveFileSpecSwift.hpp b/nitrogen/generated/ios/c++/HybridRiveFileSpecSwift.hpp index c2d1cd57..8c926ad3 100644 --- a/nitrogen/generated/ios/c++/HybridRiveFileSpecSwift.hpp +++ b/nitrogen/generated/ios/c++/HybridRiveFileSpecSwift.hpp @@ -26,6 +26,8 @@ namespace margelo::nitro::rive { struct ResolvedReferencedAsset; } namespace margelo::nitro::rive { class HybridRiveImageSpec; } // Forward declaration of `HybridBindableArtboardSpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridBindableArtboardSpec; } +// Forward declaration of `RiveEnumDefinition` to properly resolve imports. +namespace margelo::nitro::rive { struct RiveEnumDefinition; } #include #include @@ -39,6 +41,8 @@ namespace margelo::nitro::rive { class HybridBindableArtboardSpec; } #include #include "HybridRiveImageSpec.hpp" #include "HybridBindableArtboardSpec.hpp" +#include "RiveEnumDefinition.hpp" +#include #include "RNRive-Swift-Cxx-Umbrella.hpp" @@ -138,6 +142,14 @@ namespace margelo::nitro::rive { auto __value = std::move(__result.value()); return __value; } + inline std::shared_ptr>> getEnums() override { + auto __result = _swiftPart.getEnums(); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } private: RNRive::HybridRiveFileSpec_cxx _swiftPart; diff --git a/nitrogen/generated/ios/swift/Func_void_std__vector_RiveEnumDefinition_.swift b/nitrogen/generated/ios/swift/Func_void_std__vector_RiveEnumDefinition_.swift new file mode 100644 index 00000000..328c173f --- /dev/null +++ b/nitrogen/generated/ios/swift/Func_void_std__vector_RiveEnumDefinition_.swift @@ -0,0 +1,47 @@ +/// +/// Func_void_std__vector_RiveEnumDefinition_.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import Foundation +import NitroModules + +/** + * Wraps a Swift `(_ value: [RiveEnumDefinition]) -> Void` as a class. + * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`. + */ +public final class Func_void_std__vector_RiveEnumDefinition_ { + public typealias bridge = margelo.nitro.rive.bridge.swift + + private let closure: (_ value: [RiveEnumDefinition]) -> Void + + public init(_ closure: @escaping (_ value: [RiveEnumDefinition]) -> Void) { + self.closure = closure + } + + @inline(__always) + public func call(value: bridge.std__vector_RiveEnumDefinition_) -> Void { + self.closure(value.map({ __item in __item })) + } + + /** + * Casts this instance to a retained unsafe raw pointer. + * This acquires one additional strong reference on the object! + */ + @inline(__always) + public func toUnsafe() -> UnsafeMutableRawPointer { + return Unmanaged.passRetained(self).toOpaque() + } + + /** + * Casts an unsafe pointer to a `Func_void_std__vector_RiveEnumDefinition_`. + * The pointer has to be a retained opaque `Unmanaged`. + * This removes one strong reference from the object! + */ + @inline(__always) + public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_void_std__vector_RiveEnumDefinition_ { + return Unmanaged.fromOpaque(pointer).takeRetainedValue() + } +} diff --git a/nitrogen/generated/ios/swift/HybridRiveFileSpec.swift b/nitrogen/generated/ios/swift/HybridRiveFileSpec.swift index 1c22c3dc..d253e22f 100644 --- a/nitrogen/generated/ios/swift/HybridRiveFileSpec.swift +++ b/nitrogen/generated/ios/swift/HybridRiveFileSpec.swift @@ -21,6 +21,7 @@ public protocol HybridRiveFileSpec_protocol: HybridObject { func defaultArtboardViewModel(artboardBy: ArtboardBy?) throws -> (any HybridViewModelSpec)? func updateReferencedAssets(referencedAssets: ReferencedAssetsType) throws -> Void func getBindableArtboard(name: String) throws -> (any HybridBindableArtboardSpec) + func getEnums() throws -> Promise<[RiveEnumDefinition]> } public extension HybridRiveFileSpec_protocol { diff --git a/nitrogen/generated/ios/swift/HybridRiveFileSpec_cxx.swift b/nitrogen/generated/ios/swift/HybridRiveFileSpec_cxx.swift index 906a1ab1..f0482765 100644 --- a/nitrogen/generated/ios/swift/HybridRiveFileSpec_cxx.swift +++ b/nitrogen/generated/ios/swift/HybridRiveFileSpec_cxx.swift @@ -244,4 +244,29 @@ open class HybridRiveFileSpec_cxx { return bridge.create_Result_std__shared_ptr_HybridBindableArtboardSpec__(__exceptionPtr) } } + + @inline(__always) + public final func getEnums() -> bridge.Result_std__shared_ptr_Promise_std__vector_RiveEnumDefinition____ { + do { + let __result = try self.__implementation.getEnums() + let __resultCpp = { () -> bridge.std__shared_ptr_Promise_std__vector_RiveEnumDefinition___ in + let __promise = bridge.create_std__shared_ptr_Promise_std__vector_RiveEnumDefinition___() + let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__vector_RiveEnumDefinition___(__promise) + __result + .then({ __result in __promiseHolder.resolve({ () -> bridge.std__vector_RiveEnumDefinition_ in + var __vector = bridge.create_std__vector_RiveEnumDefinition_(__result.count) + for __item in __result { + __vector.push_back(__item) + } + return __vector + }()) }) + .catch({ __error in __promiseHolder.reject(__error.toCpp()) }) + return __promise + }() + return bridge.create_Result_std__shared_ptr_Promise_std__vector_RiveEnumDefinition____(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_std__shared_ptr_Promise_std__vector_RiveEnumDefinition____(__exceptionPtr) + } + } } diff --git a/nitrogen/generated/ios/swift/RiveEnumDefinition.swift b/nitrogen/generated/ios/swift/RiveEnumDefinition.swift new file mode 100644 index 00000000..2cae08c7 --- /dev/null +++ b/nitrogen/generated/ios/swift/RiveEnumDefinition.swift @@ -0,0 +1,41 @@ +/// +/// RiveEnumDefinition.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import Foundation +import NitroModules + +/** + * Represents an instance of `RiveEnumDefinition`, backed by a C++ struct. + */ +public typealias RiveEnumDefinition = margelo.nitro.rive.RiveEnumDefinition + +public extension RiveEnumDefinition { + private typealias bridge = margelo.nitro.rive.bridge.swift + + /** + * Create a new instance of `RiveEnumDefinition`. + */ + init(name: String, values: [String]) { + self.init(std.string(name), { () -> bridge.std__vector_std__string_ in + var __vector = bridge.create_std__vector_std__string_(values.count) + for __item in values { + __vector.push_back(std.string(__item)) + } + return __vector + }()) + } + + @inline(__always) + var name: String { + return String(self.__name) + } + + @inline(__always) + var values: [String] { + return self.__values.map({ __item in String(__item) }) + } +} diff --git a/nitrogen/generated/shared/c++/HybridRiveFileSpec.cpp b/nitrogen/generated/shared/c++/HybridRiveFileSpec.cpp index 2aae1434..c4aebd7f 100644 --- a/nitrogen/generated/shared/c++/HybridRiveFileSpec.cpp +++ b/nitrogen/generated/shared/c++/HybridRiveFileSpec.cpp @@ -22,6 +22,7 @@ namespace margelo::nitro::rive { prototype.registerHybridMethod("defaultArtboardViewModel", &HybridRiveFileSpec::defaultArtboardViewModel); prototype.registerHybridMethod("updateReferencedAssets", &HybridRiveFileSpec::updateReferencedAssets); prototype.registerHybridMethod("getBindableArtboard", &HybridRiveFileSpec::getBindableArtboard); + prototype.registerHybridMethod("getEnums", &HybridRiveFileSpec::getEnums); }); } diff --git a/nitrogen/generated/shared/c++/HybridRiveFileSpec.hpp b/nitrogen/generated/shared/c++/HybridRiveFileSpec.hpp index 30a466b1..7a0fd20b 100644 --- a/nitrogen/generated/shared/c++/HybridRiveFileSpec.hpp +++ b/nitrogen/generated/shared/c++/HybridRiveFileSpec.hpp @@ -21,6 +21,8 @@ namespace margelo::nitro::rive { struct ArtboardBy; } namespace margelo::nitro::rive { struct ReferencedAssetsType; } // Forward declaration of `HybridBindableArtboardSpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridBindableArtboardSpec; } +// Forward declaration of `RiveEnumDefinition` to properly resolve imports. +namespace margelo::nitro::rive { struct RiveEnumDefinition; } #include #include @@ -30,6 +32,8 @@ namespace margelo::nitro::rive { class HybridBindableArtboardSpec; } #include "ArtboardBy.hpp" #include "ReferencedAssetsType.hpp" #include "HybridBindableArtboardSpec.hpp" +#include "RiveEnumDefinition.hpp" +#include namespace margelo::nitro::rive { @@ -69,6 +73,7 @@ namespace margelo::nitro::rive { virtual std::optional> defaultArtboardViewModel(const std::optional& artboardBy) = 0; virtual void updateReferencedAssets(const ReferencedAssetsType& referencedAssets) = 0; virtual std::shared_ptr getBindableArtboard(const std::string& name) = 0; + virtual std::shared_ptr>> getEnums() = 0; protected: // Hybrid Setup diff --git a/nitrogen/generated/shared/c++/RiveEnumDefinition.hpp b/nitrogen/generated/shared/c++/RiveEnumDefinition.hpp new file mode 100644 index 00000000..dc411546 --- /dev/null +++ b/nitrogen/generated/shared/c++/RiveEnumDefinition.hpp @@ -0,0 +1,88 @@ +/// +/// RiveEnumDefinition.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + + + +#include +#include + +namespace margelo::nitro::rive { + + /** + * A struct which can be represented as a JavaScript object (RiveEnumDefinition). + */ + struct RiveEnumDefinition final { + public: + std::string name SWIFT_PRIVATE; + std::vector values SWIFT_PRIVATE; + + public: + RiveEnumDefinition() = default; + explicit RiveEnumDefinition(std::string name, std::vector values): name(name), values(values) {} + + public: + friend bool operator==(const RiveEnumDefinition& lhs, const RiveEnumDefinition& rhs) = default; + }; + +} // namespace margelo::nitro::rive + +namespace margelo::nitro { + + // C++ RiveEnumDefinition <> JS RiveEnumDefinition (object) + template <> + struct JSIConverter final { + static inline margelo::nitro::rive::RiveEnumDefinition fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + jsi::Object obj = arg.asObject(runtime); + return margelo::nitro::rive::RiveEnumDefinition( + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "name"))), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "values"))) + ); + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::rive::RiveEnumDefinition& arg) { + jsi::Object obj(runtime); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "name"), JSIConverter::toJSI(runtime, arg.name)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "values"), JSIConverter>::toJSI(runtime, arg.values)); + return obj; + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isObject()) { + return false; + } + jsi::Object obj = value.getObject(runtime); + if (!nitro::isPlainObject(runtime, obj)) { + return false; + } + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "name")))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "values")))) return false; + return true; + } + }; + +} // namespace margelo::nitro diff --git a/src/index.tsx b/src/index.tsx index f37bd9eb..e83208f0 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -19,7 +19,7 @@ export { NitroRiveView } from './core/NitroRiveViewComponent'; export { RiveView, type RiveViewProps } from './core/RiveView'; export type { RiveViewMethods }; export type RiveViewRef = HybridView; -export type { RiveFile } from './specs/RiveFile.nitro'; +export type { RiveFile, RiveEnumDefinition } from './specs/RiveFile.nitro'; export type { ViewModel, ViewModelInstance, diff --git a/src/specs/RiveFile.nitro.ts b/src/specs/RiveFile.nitro.ts index 02822c38..e7376df6 100644 --- a/src/specs/RiveFile.nitro.ts +++ b/src/specs/RiveFile.nitro.ts @@ -4,6 +4,17 @@ import type { ArtboardBy } from './ArtboardBy'; import type { RiveImage } from './RiveImage.nitro'; import type { BindableArtboard } from './BindableArtboard.nitro'; +/** + * Represents an enum definition from a Rive file. + * Useful for debugging and building dynamic UIs based on available enum values. + */ +export interface RiveEnumDefinition { + /** The name of the enum (e.g., "Status") */ + readonly name: string; + /** All possible values for this enum (e.g., ["Active", "Inactive", "Pending"]) */ + readonly values: string[]; +} + export type ResolvedReferencedAsset = { sourceUrl?: string; sourceAsset?: string; @@ -42,6 +53,13 @@ export interface RiveFile * @see {@link https://rive.app/docs/runtimes/data-binding Rive Data Binding Documentation} */ getBindableArtboard(name: string): BindableArtboard; + + /** + * Get all enums defined in this Rive file. + * Useful for debugging and building dynamic UIs. + * @experimental Uses the experimental Rive API on iOS + */ + getEnums(): Promise; } export interface RiveFileFactory