diff --git a/apps/simple-camera/ios/Podfile.lock b/apps/simple-camera/ios/Podfile.lock index 4ed30e9640..63e9f1ed57 100644 --- a/apps/simple-camera/ios/Podfile.lock +++ b/apps/simple-camera/ios/Podfile.lock @@ -70,7 +70,7 @@ PODS: - nanopb/encode (= 3.30910.0) - nanopb/decode (3.30910.0) - nanopb/encode (3.30910.0) - - NitroImage (0.15.1): + - NitroImage (0.15.2): - hermes-engine - NitroModules - RCTRequired @@ -94,7 +94,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - NitroModules (0.36.5): + - NitroModules (0.37.0): - hermes-engine - RCTRequired - RCTTypeSafety @@ -2787,8 +2787,8 @@ SPEC CHECKSUMS: MLKitCommon: 47d47b50a031d00db62f1b0efe5a1d8b09a3b2e6 MLKitVision: 39a5a812db83c4a0794445088e567f3631c11961 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 - NitroImage: 2f592086cbdecbbaa1c10dd97e0cdd43b1bb0817 - NitroModules: 452230d9b63c6c3f59dd97eeaa27ec3449271d4a + NitroImage: 5daf897d2f37ed419186278d6b0fcdd8aab313b0 + NitroModules: cda827b31eb05c1bfcc0e2bbd9b647a69c6c314f PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 RCTDeprecation: a4c521821fab57cbb125b36effe84d897d0dfa12 RCTRequired: 9f3a7e5645d4bc3f551593de7550bb66ab6e42bc diff --git a/apps/simple-camera/package.json b/apps/simple-camera/package.json index afe92fae19..c10d75e32e 100644 --- a/apps/simple-camera/package.json +++ b/apps/simple-camera/package.json @@ -25,8 +25,8 @@ "react": "19.2.3", "react-native": "0.85.3", "react-native-gesture-handler": "^3.0.0", - "react-native-nitro-image": "0.15.1", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-image": "0.15.2", + "react-native-nitro-modules": "0.37.0", "react-native-reanimated": "4.4.0", "react-native-safe-area-context": "^5.8.0", "react-native-screens": "^4.25.2", diff --git a/bun.lock b/bun.lock index 7fd41c396a..b9a390d059 100644 --- a/bun.lock +++ b/bun.lock @@ -32,8 +32,8 @@ "react": "19.2.3", "react-native": "0.85.3", "react-native-gesture-handler": "^3.0.0", - "react-native-nitro-image": "0.15.1", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-image": "0.15.2", + "react-native-nitro-modules": "0.37.0", "react-native-reanimated": "4.4.0", "react-native-safe-area-context": "^5.8.0", "react-native-screens": "^4.25.2", @@ -106,11 +106,11 @@ "version": "5.2.2", "devDependencies": { "@types/react": "19.2.15", - "nitrogen": "0.36.5", + "nitrogen": "0.37.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-image": "0.15.1", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-image": "0.15.2", + "react-native-nitro-modules": "0.37.0", "typescript": "6.0.3", }, "peerDependencies": { @@ -128,11 +128,11 @@ "version": "5.2.2", "devDependencies": { "@types/react": "19.2.15", - "nitrogen": "0.36.5", + "nitrogen": "0.37.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-image": "0.15.1", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-image": "0.15.2", + "react-native-nitro-modules": "0.37.0", "react-native-vision-camera": "*", "typescript": "6.0.3", }, @@ -152,10 +152,10 @@ "version": "5.2.2", "devDependencies": { "@types/react": "19.2.15", - "nitrogen": "0.36.5", + "nitrogen": "0.37.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-modules": "0.37.0", "react-native-vision-camera": "*", "typescript": "6.0.3", }, @@ -174,10 +174,10 @@ "version": "5.2.2", "devDependencies": { "@types/react": "19.2.15", - "nitrogen": "0.36.5", + "nitrogen": "0.37.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-modules": "0.37.0", "react-native-vision-camera": "*", "typescript": "6.0.3", }, @@ -199,7 +199,7 @@ "@types/react": "19.2.15", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-modules": "0.37.0", "react-native-reanimated": "4.4.0", "react-native-vision-camera": "*", "react-native-vision-camera-worklets": "*", @@ -221,10 +221,10 @@ "version": "5.2.2", "devDependencies": { "@types/react": "19.2.15", - "nitrogen": "0.36.5", + "nitrogen": "0.37.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-modules": "0.37.0", "react-native-vision-camera": "*", "react-native-worklets": "0.9.1", "typescript": "6.0.3", @@ -2220,7 +2220,7 @@ "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], - "nitrogen": ["nitrogen@0.36.5", "", { "dependencies": { "chalk": "^5.3.0", "react-native-nitro-modules": "^0.36.5", "ts-morph": "^28.0.0", "yargs": "^18.0.0", "zod": "^4.4.3" }, "bin": { "nitrogen": "lib/index.js" } }, "sha512-PvlHrBVaoKEaD6CCUCG7om8MTvLeh4ZSDxHoRx2YiEWUVXPXrRN9NwMn1gjie9Bd91jHA3dYMF7no9Eme4txMA=="], + "nitrogen": ["nitrogen@0.37.0", "", { "dependencies": { "chalk": "^5.3.0", "react-native-nitro-modules": "^0.37.0", "ts-morph": "^28.0.0", "yargs": "^18.0.0", "zod": "^4.4.3" }, "bin": { "nitrogen": "lib/index.js" } }, "sha512-lrWmvctRyazMLU6y4ThUl6q129wMCOvmQfdtqCeZShgmmh3Nbplm9dSJLN2OZSBnDWA5k+T2P8aiNyjr1yiJAg=="], "nocache": ["nocache@3.0.4", "", {}, "sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw=="], @@ -2404,9 +2404,9 @@ "react-native-is-edge-to-edge": ["react-native-is-edge-to-edge@1.3.1", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-NIXU/iT5+ORyCc7p0z2nnlkouYKX425vuU1OEm6bMMtWWR9yvb+Xg5AZmImTKoF9abxCPqrKC3rOZsKzUYgYZA=="], - "react-native-nitro-image": ["react-native-nitro-image@0.15.1", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "*" } }, "sha512-slrImfUgasAdzylTiNWuTkawE0R4t7LGh+7N2VFa/D9+SxlQbkKYp1J6hA3XkkEnTnUCKaea39ZVg+1xx665MQ=="], + "react-native-nitro-image": ["react-native-nitro-image@0.15.2", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "*" }, "optionalPeers": ["react-native-nitro-modules"] }, "sha512-WiaGnORmfNIIqtRJW76TWYNet1YZx1MWDlSOxd0jfcIBN4KjkVVMDVpvO01eCfpxKVG0ez9nA2iLQkPVlGFj+A=="], - "react-native-nitro-modules": ["react-native-nitro-modules@0.36.5", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-SJby84+hovD70JmQ1fq+56tw3oapJeChehUqXA4Gqjm+ktJhMAcj8LGwoAjStSOUwRaK7czbzBPB0Widj+EDoQ=="], + "react-native-nitro-modules": ["react-native-nitro-modules@0.37.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-ULS2CBZcdwGw5d4Y35EV/tbCOsNsQOnQ9LC9CehMhDNm5c90lwF/LxRamzKuFpjI547G7teTQgD0peqYSGnP9g=="], "react-native-reanimated": ["react-native-reanimated@4.4.0", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.3.1", "semver": "^7.7.3" }, "peerDependencies": { "react": "*", "react-native": "0.83 - 0.86", "react-native-worklets": "0.9.x" } }, "sha512-0XbC1SpF3JZOz5QfmTEx3vt8VkmkTlS05CBIOKEg5q5ZSNlGtlacntlhj5CrfZlN1ciHAeoliJouTC2cLGKbDA=="], diff --git a/packages/react-native-vision-camera-barcode-scanner/package.json b/packages/react-native-vision-camera-barcode-scanner/package.json index eb778c4057..6f2000c686 100644 --- a/packages/react-native-vision-camera-barcode-scanner/package.json +++ b/packages/react-native-vision-camera-barcode-scanner/package.json @@ -66,11 +66,11 @@ }, "devDependencies": { "@types/react": "19.2.15", - "nitrogen": "0.36.5", + "nitrogen": "0.37.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-image": "0.15.1", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-image": "0.15.2", + "react-native-nitro-modules": "0.37.0", "react-native-vision-camera": "*", "typescript": "6.0.3" }, diff --git a/packages/react-native-vision-camera-location/package.json b/packages/react-native-vision-camera-location/package.json index 9118dc47e4..42ee31490e 100644 --- a/packages/react-native-vision-camera-location/package.json +++ b/packages/react-native-vision-camera-location/package.json @@ -65,10 +65,10 @@ }, "devDependencies": { "@types/react": "19.2.15", - "nitrogen": "0.36.5", + "nitrogen": "0.37.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-modules": "0.37.0", "react-native-vision-camera": "*", "typescript": "6.0.3" }, diff --git a/packages/react-native-vision-camera-resizer/package.json b/packages/react-native-vision-camera-resizer/package.json index 528ccc9580..e077328f1a 100644 --- a/packages/react-native-vision-camera-resizer/package.json +++ b/packages/react-native-vision-camera-resizer/package.json @@ -70,10 +70,10 @@ }, "devDependencies": { "@types/react": "19.2.15", - "nitrogen": "0.36.5", + "nitrogen": "0.37.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-modules": "0.37.0", "react-native-vision-camera": "*", "typescript": "6.0.3" }, diff --git a/packages/react-native-vision-camera-skia/package.json b/packages/react-native-vision-camera-skia/package.json index 9528860cfe..61de147577 100644 --- a/packages/react-native-vision-camera-skia/package.json +++ b/packages/react-native-vision-camera-skia/package.json @@ -56,7 +56,7 @@ "@types/react": "19.2.15", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-modules": "0.37.0", "react-native-reanimated": "4.4.0", "react-native-worklets": "0.9.1", "react-native-vision-camera": "*", diff --git a/packages/react-native-vision-camera-worklets/package.json b/packages/react-native-vision-camera-worklets/package.json index c443136174..7d3f2e8d48 100644 --- a/packages/react-native-vision-camera-worklets/package.json +++ b/packages/react-native-vision-camera-worklets/package.json @@ -66,10 +66,10 @@ }, "devDependencies": { "@types/react": "19.2.15", - "nitrogen": "0.36.5", + "nitrogen": "0.37.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-modules": "0.37.0", "react-native-worklets": "0.9.1", "react-native-vision-camera": "*", "typescript": "6.0.3" diff --git a/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridFrameRendererViewStateUpdater.cpp b/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridFrameRendererViewStateUpdater.cpp index 6d3a83af77..bf8b0acd55 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridFrameRendererViewStateUpdater.cpp +++ b/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridFrameRendererViewStateUpdater.cpp @@ -15,41 +15,59 @@ namespace margelo::nitro::camera::views { using namespace facebook; using ConcreteStateData = react::ConcreteState; -void JHybridFrameRendererViewStateUpdater::updateViewProps(jni::alias_ref /* class */, - jni::alias_ref javaView, - jni::alias_ref stateWrapperInterface) { - std::shared_ptr hybridView = javaView->getJHybridFrameRendererViewSpec(); - +std::shared_ptr JHybridFrameRendererViewStateUpdater::getPropsFromStateWrapper( + jni::alias_ref stateWrapper) { + if (stateWrapper.get() == nullptr) { + return nullptr; + } // Get concrete StateWrapperImpl from passed StateWrapper interface object - jobject rawStateWrapper = stateWrapperInterface.get(); - if (!stateWrapperInterface->isInstanceOf(react::StateWrapperImpl::javaClassStatic())) [[unlikely]] { - throw std::runtime_error("StateWrapper is not a StateWrapperImpl"); + jobject rawStateWrapper = stateWrapper.get(); + if (!stateWrapper->isInstanceOf(react::StateWrapperImpl::javaClassStatic())) [[unlikely]] { + throw std::runtime_error("StateWrapper is not a StateWrapperImpl"); + } + auto stateWrapperImpl = jni::alias_ref{ + static_cast(rawStateWrapper) + }; + std::shared_ptr state = stateWrapperImpl->cthis()->getState(); + if (state == nullptr) { + return nullptr; } - auto stateWrapper = jni::alias_ref{ - static_cast(rawStateWrapper)}; - std::shared_ptr state = stateWrapper->cthis()->getState(); auto concreteState = std::static_pointer_cast(state); const HybridFrameRendererViewState& data = concreteState->getData(); - const std::shared_ptr& props = data.getProps(); + const std::shared_ptr& props = data.getProps(); if (props == nullptr) [[unlikely]] { - // Props aren't set yet! throw std::runtime_error("HybridFrameRendererViewState's data doesn't contain any props!"); } + return props; +} + +void JHybridFrameRendererViewStateUpdater::updateViewProps(jni::alias_ref /* class */, + jni::alias_ref javaView, + jni::alias_ref newState, + jni::alias_ref oldState) { + std::shared_ptr hybridView = javaView->getJHybridFrameRendererViewSpec(); + std::shared_ptr newProps = getPropsFromStateWrapper(newState); + std::shared_ptr oldProps = getPropsFromStateWrapper(oldState); + if (newProps == nullptr) [[unlikely]] { + throw std::runtime_error("Current StateWrapper doesn't contain any props!"); + } - // Update all props if they are dirty - if (props->renderer.isDirty) { - hybridView->setRenderer(props->renderer.value); - props->renderer.isDirty = false; + // Update only props that differ from the previous State snapshot. + if (oldProps == nullptr + ? newProps->renderer.isProvided() + : !newProps->renderer.hasSameValue(oldProps->renderer)) { + hybridView->setRenderer(newProps->renderer.get()); } // Update hybridRef if it changed - if (props->hybridRef.isDirty) { + if (oldProps == nullptr + ? newProps->hybridRef.isProvided() + : !newProps->hybridRef.hasSameValue(oldProps->hybridRef)) { // hybridRef changed - call it with new this - const auto& maybeFunc = props->hybridRef.value; + const auto& maybeFunc = newProps->hybridRef.get(); if (maybeFunc.has_value()) { maybeFunc.value()(hybridView); } - props->hybridRef.isDirty = false; } } diff --git a/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridFrameRendererViewStateUpdater.hpp b/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridFrameRendererViewStateUpdater.hpp index 46c9a4ca5c..387f411f39 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridFrameRendererViewStateUpdater.hpp +++ b/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridFrameRendererViewStateUpdater.hpp @@ -31,7 +31,12 @@ class JHybridFrameRendererViewStateUpdater final: public jni::JavaClass /* class */, jni::alias_ref view, - jni::alias_ref stateWrapperInterface); + jni::alias_ref newState, + jni::alias_ref oldState); + +private: + static std::shared_ptr getPropsFromStateWrapper( + jni::alias_ref stateWrapper); public: static void registerNatives() { diff --git a/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridPreviewViewStateUpdater.cpp b/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridPreviewViewStateUpdater.cpp index e21b794c7d..ed5395c657 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridPreviewViewStateUpdater.cpp +++ b/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridPreviewViewStateUpdater.cpp @@ -15,61 +15,84 @@ namespace margelo::nitro::camera::views { using namespace facebook; using ConcreteStateData = react::ConcreteState; -void JHybridPreviewViewStateUpdater::updateViewProps(jni::alias_ref /* class */, - jni::alias_ref javaView, - jni::alias_ref stateWrapperInterface) { - std::shared_ptr hybridView = javaView->getJHybridPreviewViewSpec(); - +std::shared_ptr JHybridPreviewViewStateUpdater::getPropsFromStateWrapper( + jni::alias_ref stateWrapper) { + if (stateWrapper.get() == nullptr) { + return nullptr; + } // Get concrete StateWrapperImpl from passed StateWrapper interface object - jobject rawStateWrapper = stateWrapperInterface.get(); - if (!stateWrapperInterface->isInstanceOf(react::StateWrapperImpl::javaClassStatic())) [[unlikely]] { - throw std::runtime_error("StateWrapper is not a StateWrapperImpl"); + jobject rawStateWrapper = stateWrapper.get(); + if (!stateWrapper->isInstanceOf(react::StateWrapperImpl::javaClassStatic())) [[unlikely]] { + throw std::runtime_error("StateWrapper is not a StateWrapperImpl"); + } + auto stateWrapperImpl = jni::alias_ref{ + static_cast(rawStateWrapper) + }; + std::shared_ptr state = stateWrapperImpl->cthis()->getState(); + if (state == nullptr) { + return nullptr; } - auto stateWrapper = jni::alias_ref{ - static_cast(rawStateWrapper)}; - std::shared_ptr state = stateWrapper->cthis()->getState(); auto concreteState = std::static_pointer_cast(state); const HybridPreviewViewState& data = concreteState->getData(); - const std::shared_ptr& props = data.getProps(); + const std::shared_ptr& props = data.getProps(); if (props == nullptr) [[unlikely]] { - // Props aren't set yet! throw std::runtime_error("HybridPreviewViewState's data doesn't contain any props!"); } + return props; +} + +void JHybridPreviewViewStateUpdater::updateViewProps(jni::alias_ref /* class */, + jni::alias_ref javaView, + jni::alias_ref newState, + jni::alias_ref oldState) { + std::shared_ptr hybridView = javaView->getJHybridPreviewViewSpec(); + std::shared_ptr newProps = getPropsFromStateWrapper(newState); + std::shared_ptr oldProps = getPropsFromStateWrapper(oldState); + if (newProps == nullptr) [[unlikely]] { + throw std::runtime_error("Current StateWrapper doesn't contain any props!"); + } - // Update all props if they are dirty - if (props->previewOutput.isDirty) { - hybridView->setPreviewOutput(props->previewOutput.value); - props->previewOutput.isDirty = false; + // Update only props that differ from the previous State snapshot. + if (oldProps == nullptr + ? newProps->previewOutput.isProvided() + : !newProps->previewOutput.hasSameValue(oldProps->previewOutput)) { + hybridView->setPreviewOutput(newProps->previewOutput.get()); } - if (props->resizeMode.isDirty) { - hybridView->setResizeMode(props->resizeMode.value); - props->resizeMode.isDirty = false; + if (oldProps == nullptr + ? newProps->resizeMode.isProvided() + : !newProps->resizeMode.hasSameValue(oldProps->resizeMode)) { + hybridView->setResizeMode(newProps->resizeMode.get()); } - if (props->implementationMode.isDirty) { - hybridView->setImplementationMode(props->implementationMode.value); - props->implementationMode.isDirty = false; + if (oldProps == nullptr + ? newProps->implementationMode.isProvided() + : !newProps->implementationMode.hasSameValue(oldProps->implementationMode)) { + hybridView->setImplementationMode(newProps->implementationMode.get()); } - if (props->gestureControllers.isDirty) { - hybridView->setGestureControllers(props->gestureControllers.value); - props->gestureControllers.isDirty = false; + if (oldProps == nullptr + ? newProps->gestureControllers.isProvided() + : !newProps->gestureControllers.hasSameValue(oldProps->gestureControllers)) { + hybridView->setGestureControllers(newProps->gestureControllers.get()); } - if (props->onPreviewStarted.isDirty) { - hybridView->setOnPreviewStarted(props->onPreviewStarted.value); - props->onPreviewStarted.isDirty = false; + if (oldProps == nullptr + ? newProps->onPreviewStarted.isProvided() + : !newProps->onPreviewStarted.hasSameValue(oldProps->onPreviewStarted)) { + hybridView->setOnPreviewStarted(newProps->onPreviewStarted.get()); } - if (props->onPreviewStopped.isDirty) { - hybridView->setOnPreviewStopped(props->onPreviewStopped.value); - props->onPreviewStopped.isDirty = false; + if (oldProps == nullptr + ? newProps->onPreviewStopped.isProvided() + : !newProps->onPreviewStopped.hasSameValue(oldProps->onPreviewStopped)) { + hybridView->setOnPreviewStopped(newProps->onPreviewStopped.get()); } // Update hybridRef if it changed - if (props->hybridRef.isDirty) { + if (oldProps == nullptr + ? newProps->hybridRef.isProvided() + : !newProps->hybridRef.hasSameValue(oldProps->hybridRef)) { // hybridRef changed - call it with new this - const auto& maybeFunc = props->hybridRef.value; + const auto& maybeFunc = newProps->hybridRef.get(); if (maybeFunc.has_value()) { maybeFunc.value()(hybridView); } - props->hybridRef.isDirty = false; } } diff --git a/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridPreviewViewStateUpdater.hpp b/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridPreviewViewStateUpdater.hpp index 02c4652bd4..60c6ee0643 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridPreviewViewStateUpdater.hpp +++ b/packages/react-native-vision-camera/nitrogen/generated/android/c++/views/JHybridPreviewViewStateUpdater.hpp @@ -31,7 +31,12 @@ class JHybridPreviewViewStateUpdater final: public jni::JavaClass /* class */, jni::alias_ref view, - jni::alias_ref stateWrapperInterface); + jni::alias_ref newState, + jni::alias_ref oldState); + +private: + static std::shared_ptr getPropsFromStateWrapper( + jni::alias_ref stateWrapper); public: static void registerNatives() { diff --git a/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridFrameRendererViewManager.kt b/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridFrameRendererViewManager.kt index ade581cb64..883c5bfd15 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridFrameRendererViewManager.kt +++ b/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridFrameRendererViewManager.kt @@ -20,6 +20,14 @@ import com.margelo.nitro.camera.* * Represents the React Native `ViewManager` for the "FrameRendererView" Nitro HybridView. */ public class HybridFrameRendererViewManager: SimpleViewManager() { + /** + * Represents the View and its last state snapshot (mutable) + */ + private class HybridViewHolder( + val hybridView: HybridFrameRendererView, + var lastState: StateWrapper? = null, + ) + init { if (RecyclableView::class.java.isAssignableFrom(HybridFrameRendererView::class.java)) { // Enable view recycling @@ -34,33 +42,41 @@ public class HybridFrameRendererViewManager: SimpleViewManager() { override fun createViewInstance(reactContext: ThemedReactContext): View { val hybridView = HybridFrameRendererView(reactContext) val view = hybridView.view - view.setTag(associated_hybrid_view_tag, hybridView) + view.setTag(associated_hybrid_view_tag, HybridViewHolder(hybridView)) return view } override fun updateState(view: View, props: ReactStylesDiffMap, stateWrapper: StateWrapper): Any? { - val hybridView = getHybridView(view) + val holder = getHybridViewHolder(view) ?: throw Error("Couldn't find view $view in local views table!") + val hybridView = holder.hybridView + val oldState = holder.lastState + val newState = stateWrapper // 1. Update each prop individually hybridView.beforeUpdate() - HybridFrameRendererViewStateUpdater.updateViewProps(hybridView, stateWrapper) + HybridFrameRendererViewStateUpdater.updateViewProps(hybridView, newState, oldState) hybridView.afterUpdate() + holder.lastState = newState // 2. Continue in base View props - return super.updateState(view, props, stateWrapper) + return super.updateState(view, props, newState) } override fun onDropViewInstance(view: View) { - val hybridView = getHybridView(view) - hybridView?.onDropView() + val holder = getHybridViewHolder(view) + holder?.lastState = null + holder?.hybridView?.onDropView() return super.onDropViewInstance(view) } protected override fun prepareToRecycleView(reactContext: ThemedReactContext, view: View): View? { - super.prepareToRecycleView(reactContext, view) - val hybridView = getHybridView(view) + val preparedView = super.prepareToRecycleView(reactContext, view) + ?: return null + val holder = getHybridViewHolder(preparedView) ?: return null + val hybridView = holder.hybridView + holder.lastState = null @Suppress("USELESS_IS_CHECK") if (hybridView is RecyclableView) { @@ -74,7 +90,7 @@ public class HybridFrameRendererViewManager: SimpleViewManager() { } } - private fun getHybridView(view: View): HybridFrameRendererView? { - return view.getTag(associated_hybrid_view_tag) as? HybridFrameRendererView + private fun getHybridViewHolder(view: View): HybridViewHolder? { + return view.getTag(associated_hybrid_view_tag) as? HybridViewHolder } } diff --git a/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridFrameRendererViewStateUpdater.kt b/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridFrameRendererViewStateUpdater.kt index cb09475a10..85615e7006 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridFrameRendererViewStateUpdater.kt +++ b/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridFrameRendererViewStateUpdater.kt @@ -14,10 +14,10 @@ internal class HybridFrameRendererViewStateUpdater { companion object { /** * Updates the props for [view] through C++. - * The [state] prop is expected to contain [view]'s props as wrapped Fabric state. + * The [newState] prop is expected to contain [view]'s props as wrapped Fabric state. */ @Suppress("KotlinJniMissingFunction") @JvmStatic - external fun updateViewProps(view: HybridFrameRendererViewSpec, state: StateWrapper) + external fun updateViewProps(view: HybridFrameRendererViewSpec, newState: StateWrapper, oldState: StateWrapper?) } } diff --git a/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridPreviewViewManager.kt b/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridPreviewViewManager.kt index 2e3f5b4a62..d2a79480d0 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridPreviewViewManager.kt +++ b/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridPreviewViewManager.kt @@ -20,6 +20,14 @@ import com.margelo.nitro.camera.* * Represents the React Native `ViewManager` for the "PreviewView" Nitro HybridView. */ public class HybridPreviewViewManager: SimpleViewManager() { + /** + * Represents the View and its last state snapshot (mutable) + */ + private class HybridViewHolder( + val hybridView: HybridPreviewView, + var lastState: StateWrapper? = null, + ) + init { if (RecyclableView::class.java.isAssignableFrom(HybridPreviewView::class.java)) { // Enable view recycling @@ -34,33 +42,41 @@ public class HybridPreviewViewManager: SimpleViewManager() { override fun createViewInstance(reactContext: ThemedReactContext): View { val hybridView = HybridPreviewView(reactContext) val view = hybridView.view - view.setTag(associated_hybrid_view_tag, hybridView) + view.setTag(associated_hybrid_view_tag, HybridViewHolder(hybridView)) return view } override fun updateState(view: View, props: ReactStylesDiffMap, stateWrapper: StateWrapper): Any? { - val hybridView = getHybridView(view) + val holder = getHybridViewHolder(view) ?: throw Error("Couldn't find view $view in local views table!") + val hybridView = holder.hybridView + val oldState = holder.lastState + val newState = stateWrapper // 1. Update each prop individually hybridView.beforeUpdate() - HybridPreviewViewStateUpdater.updateViewProps(hybridView, stateWrapper) + HybridPreviewViewStateUpdater.updateViewProps(hybridView, newState, oldState) hybridView.afterUpdate() + holder.lastState = newState // 2. Continue in base View props - return super.updateState(view, props, stateWrapper) + return super.updateState(view, props, newState) } override fun onDropViewInstance(view: View) { - val hybridView = getHybridView(view) - hybridView?.onDropView() + val holder = getHybridViewHolder(view) + holder?.lastState = null + holder?.hybridView?.onDropView() return super.onDropViewInstance(view) } protected override fun prepareToRecycleView(reactContext: ThemedReactContext, view: View): View? { - super.prepareToRecycleView(reactContext, view) - val hybridView = getHybridView(view) + val preparedView = super.prepareToRecycleView(reactContext, view) + ?: return null + val holder = getHybridViewHolder(preparedView) ?: return null + val hybridView = holder.hybridView + holder.lastState = null @Suppress("USELESS_IS_CHECK") if (hybridView is RecyclableView) { @@ -74,7 +90,7 @@ public class HybridPreviewViewManager: SimpleViewManager() { } } - private fun getHybridView(view: View): HybridPreviewView? { - return view.getTag(associated_hybrid_view_tag) as? HybridPreviewView + private fun getHybridViewHolder(view: View): HybridViewHolder? { + return view.getTag(associated_hybrid_view_tag) as? HybridViewHolder } } diff --git a/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridPreviewViewStateUpdater.kt b/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridPreviewViewStateUpdater.kt index d4736fe730..bad443073e 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridPreviewViewStateUpdater.kt +++ b/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/views/HybridPreviewViewStateUpdater.kt @@ -14,10 +14,10 @@ internal class HybridPreviewViewStateUpdater { companion object { /** * Updates the props for [view] through C++. - * The [state] prop is expected to contain [view]'s props as wrapped Fabric state. + * The [newState] prop is expected to contain [view]'s props as wrapped Fabric state. */ @Suppress("KotlinJniMissingFunction") @JvmStatic - external fun updateViewProps(view: HybridPreviewViewSpec, state: StateWrapper) + external fun updateViewProps(view: HybridPreviewViewSpec, newState: StateWrapper, oldState: StateWrapper?) } } diff --git a/packages/react-native-vision-camera/nitrogen/generated/ios/c++/views/HybridFrameRendererViewComponent.mm b/packages/react-native-vision-camera/nitrogen/generated/ios/c++/views/HybridFrameRendererViewComponent.mm index 9a33d534da..3b6dda44dc 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/ios/c++/views/HybridFrameRendererViewComponent.mm +++ b/packages/react-native-vision-camera/nitrogen/generated/ios/c++/views/HybridFrameRendererViewComponent.mm @@ -37,6 +37,7 @@ + (BOOL)shouldBeRecycled; @implementation HybridFrameRendererViewComponent { std::shared_ptr _hybridView; + BOOL _didDropView; } + (void) load { @@ -50,6 +51,7 @@ + (void) load { - (instancetype) init { if (self = [super init]) { + _props = HybridFrameRendererViewShadowNode::defaultSharedProps(); std::shared_ptr hybridView = VisionCamera::VisionCameraAutolinking::createFrameRendererView(); _hybridView = std::dynamic_pointer_cast(hybridView); [self updateView]; @@ -69,35 +71,55 @@ - (void) updateView { [self setContentView:view]; } +- (void) notifyOnDropView { + // A recycled component can later be invalidated. Notify only once per mount. + if (_didDropView) { + return; + } + VisionCamera::HybridFrameRendererViewSpec_cxx& swiftPart = _hybridView->getSwiftPart(); + swiftPart.onDropView(); + _didDropView = YES; +} + - (void) updateProps:(const std::shared_ptr&)props oldProps:(const std::shared_ptr&)oldProps { + // A props update marks a newly mounted or still-active component. + _didDropView = NO; + // 1. Downcast props - const auto& newViewPropsConst = *std::static_pointer_cast(props); - auto& newViewProps = const_cast(newViewPropsConst); + const auto& newViewProps = *std::static_pointer_cast(props); + const auto* oldViewProps = static_cast(oldProps.get()); VisionCamera::HybridFrameRendererViewSpec_cxx& swiftPart = _hybridView->getSwiftPart(); - // 2. Update each prop individually - swiftPart.beforeUpdate(); - - // renderer: optional - if (newViewProps.renderer.isDirty) { - swiftPart.setRenderer(newViewProps.renderer.value); - newViewProps.renderer.isDirty = false; - } - - swiftPart.afterUpdate(); + // 2. Update only props that differ from the previous Props snapshot. + const bool hasTransactionPropChanges = oldViewProps == nullptr + ? newViewProps.hasAnyProvidedProps() + : !newViewProps.hasSameProps(*oldViewProps); + if (hasTransactionPropChanges) { + swiftPart.beforeUpdate(); + + // renderer: optional + if (oldViewProps == nullptr + ? newViewProps.renderer.isProvided() + : !newViewProps.renderer.hasSameValue(oldViewProps->renderer)) { + swiftPart.setRenderer(newViewProps.renderer.get()); + } - // 3. Update hybridRef if it changed - if (newViewProps.hybridRef.isDirty) { - // hybridRef changed - call it with new this - const auto& maybeFunc = newViewProps.hybridRef.value; - if (maybeFunc.has_value()) { - maybeFunc.value()(_hybridView); + // Update hybridRef if it changed + if (oldViewProps == nullptr + ? newViewProps.hybridRef.isProvided() + : !newViewProps.hybridRef.hasSameValue(oldViewProps->hybridRef)) { + // hybridRef changed - call it with new this + const auto& maybeFunc = newViewProps.hybridRef.get(); + if (maybeFunc.has_value()) { + maybeFunc.value()(_hybridView); + } } - newViewProps.hybridRef.isDirty = false; + + swiftPart.afterUpdate(); } - // 4. Continue in base class + // 3. Continue in base class [super updateProps:props oldProps:oldProps]; } @@ -106,6 +128,7 @@ + (BOOL)shouldBeRecycled { } - (void)prepareForRecycle { + [self notifyOnDropView]; [super prepareForRecycle]; VisionCamera::HybridFrameRendererViewSpec_cxx& swiftPart = _hybridView->getSwiftPart(); swiftPart.maybePrepareForRecycle(); @@ -113,8 +136,7 @@ - (void)prepareForRecycle { #ifdef ENABLE_RCT_COMPONENT_VIEW_INVALIDATE - (void)invalidate { - VisionCamera::HybridFrameRendererViewSpec_cxx& swiftPart = _hybridView->getSwiftPart(); - swiftPart.onDropView(); + [self notifyOnDropView]; [super invalidate]; } #endif diff --git a/packages/react-native-vision-camera/nitrogen/generated/ios/c++/views/HybridPreviewViewComponent.mm b/packages/react-native-vision-camera/nitrogen/generated/ios/c++/views/HybridPreviewViewComponent.mm index 888870cb39..3251d7b4fe 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/ios/c++/views/HybridPreviewViewComponent.mm +++ b/packages/react-native-vision-camera/nitrogen/generated/ios/c++/views/HybridPreviewViewComponent.mm @@ -37,6 +37,7 @@ + (BOOL)shouldBeRecycled; @implementation HybridPreviewViewComponent { std::shared_ptr _hybridView; + BOOL _didDropView; } + (void) load { @@ -50,6 +51,7 @@ + (void) load { - (instancetype) init { if (self = [super init]) { + _props = HybridPreviewViewShadowNode::defaultSharedProps(); std::shared_ptr hybridView = VisionCamera::VisionCameraAutolinking::createPreviewView(); _hybridView = std::dynamic_pointer_cast(hybridView); [self updateView]; @@ -69,60 +71,85 @@ - (void) updateView { [self setContentView:view]; } +- (void) notifyOnDropView { + // A recycled component can later be invalidated. Notify only once per mount. + if (_didDropView) { + return; + } + VisionCamera::HybridPreviewViewSpec_cxx& swiftPart = _hybridView->getSwiftPart(); + swiftPart.onDropView(); + _didDropView = YES; +} + - (void) updateProps:(const std::shared_ptr&)props oldProps:(const std::shared_ptr&)oldProps { + // A props update marks a newly mounted or still-active component. + _didDropView = NO; + // 1. Downcast props - const auto& newViewPropsConst = *std::static_pointer_cast(props); - auto& newViewProps = const_cast(newViewPropsConst); + const auto& newViewProps = *std::static_pointer_cast(props); + const auto* oldViewProps = static_cast(oldProps.get()); VisionCamera::HybridPreviewViewSpec_cxx& swiftPart = _hybridView->getSwiftPart(); - // 2. Update each prop individually - swiftPart.beforeUpdate(); - - // previewOutput: optional - if (newViewProps.previewOutput.isDirty) { - swiftPart.setPreviewOutput(newViewProps.previewOutput.value); - newViewProps.previewOutput.isDirty = false; - } - // resizeMode: optional - if (newViewProps.resizeMode.isDirty) { - swiftPart.setResizeMode(newViewProps.resizeMode.value); - newViewProps.resizeMode.isDirty = false; - } - // implementationMode: optional - if (newViewProps.implementationMode.isDirty) { - swiftPart.setImplementationMode(newViewProps.implementationMode.value); - newViewProps.implementationMode.isDirty = false; - } - // gestureControllers: optional - if (newViewProps.gestureControllers.isDirty) { - swiftPart.setGestureControllers(newViewProps.gestureControllers.value); - newViewProps.gestureControllers.isDirty = false; - } - // onPreviewStarted: optional - if (newViewProps.onPreviewStarted.isDirty) { - swiftPart.setOnPreviewStarted(newViewProps.onPreviewStarted.value); - newViewProps.onPreviewStarted.isDirty = false; - } - // onPreviewStopped: optional - if (newViewProps.onPreviewStopped.isDirty) { - swiftPart.setOnPreviewStopped(newViewProps.onPreviewStopped.value); - newViewProps.onPreviewStopped.isDirty = false; - } - - swiftPart.afterUpdate(); + // 2. Update only props that differ from the previous Props snapshot. + const bool hasTransactionPropChanges = oldViewProps == nullptr + ? newViewProps.hasAnyProvidedProps() + : !newViewProps.hasSameProps(*oldViewProps); + if (hasTransactionPropChanges) { + swiftPart.beforeUpdate(); + + // previewOutput: optional + if (oldViewProps == nullptr + ? newViewProps.previewOutput.isProvided() + : !newViewProps.previewOutput.hasSameValue(oldViewProps->previewOutput)) { + swiftPart.setPreviewOutput(newViewProps.previewOutput.get()); + } + // resizeMode: optional + if (oldViewProps == nullptr + ? newViewProps.resizeMode.isProvided() + : !newViewProps.resizeMode.hasSameValue(oldViewProps->resizeMode)) { + swiftPart.setResizeMode(newViewProps.resizeMode.get()); + } + // implementationMode: optional + if (oldViewProps == nullptr + ? newViewProps.implementationMode.isProvided() + : !newViewProps.implementationMode.hasSameValue(oldViewProps->implementationMode)) { + swiftPart.setImplementationMode(newViewProps.implementationMode.get()); + } + // gestureControllers: optional + if (oldViewProps == nullptr + ? newViewProps.gestureControllers.isProvided() + : !newViewProps.gestureControllers.hasSameValue(oldViewProps->gestureControllers)) { + swiftPart.setGestureControllers(newViewProps.gestureControllers.get()); + } + // onPreviewStarted: optional + if (oldViewProps == nullptr + ? newViewProps.onPreviewStarted.isProvided() + : !newViewProps.onPreviewStarted.hasSameValue(oldViewProps->onPreviewStarted)) { + swiftPart.setOnPreviewStarted(newViewProps.onPreviewStarted.get()); + } + // onPreviewStopped: optional + if (oldViewProps == nullptr + ? newViewProps.onPreviewStopped.isProvided() + : !newViewProps.onPreviewStopped.hasSameValue(oldViewProps->onPreviewStopped)) { + swiftPart.setOnPreviewStopped(newViewProps.onPreviewStopped.get()); + } - // 3. Update hybridRef if it changed - if (newViewProps.hybridRef.isDirty) { - // hybridRef changed - call it with new this - const auto& maybeFunc = newViewProps.hybridRef.value; - if (maybeFunc.has_value()) { - maybeFunc.value()(_hybridView); + // Update hybridRef if it changed + if (oldViewProps == nullptr + ? newViewProps.hybridRef.isProvided() + : !newViewProps.hybridRef.hasSameValue(oldViewProps->hybridRef)) { + // hybridRef changed - call it with new this + const auto& maybeFunc = newViewProps.hybridRef.get(); + if (maybeFunc.has_value()) { + maybeFunc.value()(_hybridView); + } } - newViewProps.hybridRef.isDirty = false; + + swiftPart.afterUpdate(); } - // 4. Continue in base class + // 3. Continue in base class [super updateProps:props oldProps:oldProps]; } @@ -131,6 +158,7 @@ + (BOOL)shouldBeRecycled { } - (void)prepareForRecycle { + [self notifyOnDropView]; [super prepareForRecycle]; VisionCamera::HybridPreviewViewSpec_cxx& swiftPart = _hybridView->getSwiftPart(); swiftPart.maybePrepareForRecycle(); @@ -138,8 +166,7 @@ - (void)prepareForRecycle { #ifdef ENABLE_RCT_COMPONENT_VIEW_INVALIDATE - (void)invalidate { - VisionCamera::HybridPreviewViewSpec_cxx& swiftPart = _hybridView->getSwiftPart(); - swiftPart.onDropView(); + [self notifyOnDropView]; [super invalidate]; } #endif diff --git a/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.cpp b/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.cpp index fc6741057b..5255f8e05c 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.cpp +++ b/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.cpp @@ -7,45 +7,21 @@ #include "HybridFrameRendererViewComponent.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include namespace margelo::nitro::camera::views { + using namespace facebook; + extern const char HybridFrameRendererViewComponentName[] = "FrameRendererView"; HybridFrameRendererViewProps::HybridFrameRendererViewProps(const react::PropsParserContext& context, const HybridFrameRendererViewProps& sourceProps, const react::RawProps& rawProps): react::ViewProps(context, sourceProps, rawProps, filterObjectKeys), - renderer([&]() -> CachedProp>> { - try { - const react::RawValue* rawValue = rawProps.at("renderer", nullptr, nullptr); - if (rawValue == nullptr) return sourceProps.renderer; - const auto& [runtime, value] = (std::pair)*rawValue; - return CachedProp>>::fromRawValue(*runtime, value, sourceProps.renderer); - } catch (const std::exception& exc) { - throw std::runtime_error(std::string("FrameRendererView.renderer: ") + exc.what()); - } - }()), - hybridRef([&]() -> CachedProp& /* ref */)>>> { - try { - const react::RawValue* rawValue = rawProps.at("hybridRef", nullptr, nullptr); - if (rawValue == nullptr) return sourceProps.hybridRef; - const auto& [runtime, value] = (std::pair)*rawValue; - return CachedProp& /* ref */)>>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.hybridRef); - } catch (const std::exception& exc) { - throw std::runtime_error(std::string("FrameRendererView.hybridRef: ") + exc.what()); - } - }()) { } + renderer(nitro::ReactProp>>::fromRawValue("FrameRendererView", "renderer", rawProps, sourceProps.renderer)), + hybridRef(nitro::ReactProp& /* ref */)>>>::fromRawValue("FrameRendererView", "hybridRef", rawProps, sourceProps.hybridRef)) { } bool HybridFrameRendererViewProps::filterObjectKeys(const std::string& propName) { switch (hashString(propName)) { @@ -55,29 +31,4 @@ namespace margelo::nitro::camera::views { } } - HybridFrameRendererViewComponentDescriptor::HybridFrameRendererViewComponentDescriptor(const react::ComponentDescriptorParameters& parameters) - : ConcreteComponentDescriptor(parameters, - react::RawPropsParser()) {} - - std::shared_ptr HybridFrameRendererViewComponentDescriptor::cloneProps(const react::PropsParserContext& context, - const std::shared_ptr& props, - react::RawProps rawProps) const { - // 1. Prepare raw props parser - rawProps.parse(rawPropsParser_); - // 2. Copy props with Nitro's cached copy constructor - return HybridFrameRendererViewShadowNode::Props(context, /* & */ rawProps, props); - } - -#ifdef ANDROID - void HybridFrameRendererViewComponentDescriptor::adopt(react::ShadowNode& shadowNode) const { - // This is called immediately after `ShadowNode` is created, cloned or in progress. - // On Android, we need to wrap props in our state, which gets routed through Java and later unwrapped in JNI/C++. - auto& concreteShadowNode = static_cast(shadowNode); - const std::shared_ptr& constProps = concreteShadowNode.getConcreteSharedProps(); - const std::shared_ptr& props = std::const_pointer_cast(constProps); - HybridFrameRendererViewState state{props}; - concreteShadowNode.setStateData(std::move(state)); - } -#endif - } // namespace margelo::nitro::camera::views diff --git a/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.hpp b/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.hpp index cac70f501e..537ae4a3ad 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.hpp +++ b/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.hpp @@ -7,14 +7,15 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include +#include +#include #include #include +#include +#include + +#include #include #include "HybridFrameRendererSpec.hpp" @@ -42,8 +43,20 @@ namespace margelo::nitro::camera::views { const react::RawProps& rawProps); public: - CachedProp>> renderer; - CachedProp& /* ref */)>>> hybridRef; + nitro::ReactProp>> renderer; + nitro::ReactProp& /* ref */)>>> hybridRef; + + [[nodiscard]] + bool hasSameProps(const HybridFrameRendererViewProps& other) const noexcept { + return renderer.hasSameValue(other.renderer) && + hybridRef.hasSameValue(other.hybridRef); + } + + [[nodiscard]] + bool hasAnyProvidedProps() const noexcept { + return renderer.isProvided() || + hybridRef.isProvided(); + } private: static bool filterObjectKeys(const std::string& propName); @@ -52,32 +65,7 @@ namespace margelo::nitro::camera::views { /** * State for the "FrameRendererView" View. */ - class HybridFrameRendererViewState final { - public: - HybridFrameRendererViewState() = default; - explicit HybridFrameRendererViewState(const std::shared_ptr& props): - _props(props) {} - - public: - [[nodiscard]] - const std::shared_ptr& getProps() const { - return _props; - } - - public: -#ifdef ANDROID - HybridFrameRendererViewState(const HybridFrameRendererViewState& /* previousState */, folly::dynamic /* data */) {} - folly::dynamic getDynamic() const { - throw std::runtime_error("HybridFrameRendererViewState does not support folly!"); - } - react::MapBuffer getMapBuffer() const { - throw std::runtime_error("HybridFrameRendererViewState does not support MapBuffer!"); - }; -#endif - - private: - std::shared_ptr _props; - }; + using HybridFrameRendererViewState = nitro::ViewPropsHolderState; /** * The Shadow Node for the "FrameRendererView" View. @@ -90,21 +78,7 @@ namespace margelo::nitro::camera::views { /** * The Component Descriptor for the "FrameRendererView" View. */ - class HybridFrameRendererViewComponentDescriptor final: public react::ConcreteComponentDescriptor { - public: - explicit HybridFrameRendererViewComponentDescriptor(const react::ComponentDescriptorParameters& parameters); - - public: - /** - * A faster path for cloning props - reuses the caching logic from `HybridFrameRendererViewProps`. - */ - std::shared_ptr cloneProps(const react::PropsParserContext& context, - const std::shared_ptr& props, - react::RawProps rawProps) const override; -#ifdef ANDROID - void adopt(react::ShadowNode& shadowNode) const override; -#endif - }; + using HybridFrameRendererViewComponentDescriptor = nitro::ViewComponentDescriptor; /* The actual view for "FrameRendererView" needs to be implemented in platform-specific code. */ diff --git a/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.cpp b/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.cpp index d9eac55a28..7e6f73b6d1 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.cpp +++ b/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.cpp @@ -7,95 +7,26 @@ #include "HybridPreviewViewComponent.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include namespace margelo::nitro::camera::views { + using namespace facebook; + extern const char HybridPreviewViewComponentName[] = "PreviewView"; HybridPreviewViewProps::HybridPreviewViewProps(const react::PropsParserContext& context, const HybridPreviewViewProps& sourceProps, const react::RawProps& rawProps): react::ViewProps(context, sourceProps, rawProps, filterObjectKeys), - previewOutput([&]() -> CachedProp>> { - try { - const react::RawValue* rawValue = rawProps.at("previewOutput", nullptr, nullptr); - if (rawValue == nullptr) return sourceProps.previewOutput; - const auto& [runtime, value] = (std::pair)*rawValue; - return CachedProp>>::fromRawValue(*runtime, value, sourceProps.previewOutput); - } catch (const std::exception& exc) { - throw std::runtime_error(std::string("PreviewView.previewOutput: ") + exc.what()); - } - }()), - resizeMode([&]() -> CachedProp> { - try { - const react::RawValue* rawValue = rawProps.at("resizeMode", nullptr, nullptr); - if (rawValue == nullptr) return sourceProps.resizeMode; - const auto& [runtime, value] = (std::pair)*rawValue; - return CachedProp>::fromRawValue(*runtime, value, sourceProps.resizeMode); - } catch (const std::exception& exc) { - throw std::runtime_error(std::string("PreviewView.resizeMode: ") + exc.what()); - } - }()), - implementationMode([&]() -> CachedProp> { - try { - const react::RawValue* rawValue = rawProps.at("implementationMode", nullptr, nullptr); - if (rawValue == nullptr) return sourceProps.implementationMode; - const auto& [runtime, value] = (std::pair)*rawValue; - return CachedProp>::fromRawValue(*runtime, value, sourceProps.implementationMode); - } catch (const std::exception& exc) { - throw std::runtime_error(std::string("PreviewView.implementationMode: ") + exc.what()); - } - }()), - gestureControllers([&]() -> CachedProp>>> { - try { - const react::RawValue* rawValue = rawProps.at("gestureControllers", nullptr, nullptr); - if (rawValue == nullptr) return sourceProps.gestureControllers; - const auto& [runtime, value] = (std::pair)*rawValue; - return CachedProp>>>::fromRawValue(*runtime, value, sourceProps.gestureControllers); - } catch (const std::exception& exc) { - throw std::runtime_error(std::string("PreviewView.gestureControllers: ") + exc.what()); - } - }()), - onPreviewStarted([&]() -> CachedProp>> { - try { - const react::RawValue* rawValue = rawProps.at("onPreviewStarted", nullptr, nullptr); - if (rawValue == nullptr) return sourceProps.onPreviewStarted; - const auto& [runtime, value] = (std::pair)*rawValue; - return CachedProp>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.onPreviewStarted); - } catch (const std::exception& exc) { - throw std::runtime_error(std::string("PreviewView.onPreviewStarted: ") + exc.what()); - } - }()), - onPreviewStopped([&]() -> CachedProp>> { - try { - const react::RawValue* rawValue = rawProps.at("onPreviewStopped", nullptr, nullptr); - if (rawValue == nullptr) return sourceProps.onPreviewStopped; - const auto& [runtime, value] = (std::pair)*rawValue; - return CachedProp>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.onPreviewStopped); - } catch (const std::exception& exc) { - throw std::runtime_error(std::string("PreviewView.onPreviewStopped: ") + exc.what()); - } - }()), - hybridRef([&]() -> CachedProp& /* ref */)>>> { - try { - const react::RawValue* rawValue = rawProps.at("hybridRef", nullptr, nullptr); - if (rawValue == nullptr) return sourceProps.hybridRef; - const auto& [runtime, value] = (std::pair)*rawValue; - return CachedProp& /* ref */)>>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.hybridRef); - } catch (const std::exception& exc) { - throw std::runtime_error(std::string("PreviewView.hybridRef: ") + exc.what()); - } - }()) { } + previewOutput(nitro::ReactProp>>::fromRawValue("PreviewView", "previewOutput", rawProps, sourceProps.previewOutput)), + resizeMode(nitro::ReactProp>::fromRawValue("PreviewView", "resizeMode", rawProps, sourceProps.resizeMode)), + implementationMode(nitro::ReactProp>::fromRawValue("PreviewView", "implementationMode", rawProps, sourceProps.implementationMode)), + gestureControllers(nitro::ReactProp>>>::fromRawValue("PreviewView", "gestureControllers", rawProps, sourceProps.gestureControllers)), + onPreviewStarted(nitro::ReactProp>>::fromRawValue("PreviewView", "onPreviewStarted", rawProps, sourceProps.onPreviewStarted)), + onPreviewStopped(nitro::ReactProp>>::fromRawValue("PreviewView", "onPreviewStopped", rawProps, sourceProps.onPreviewStopped)), + hybridRef(nitro::ReactProp& /* ref */)>>>::fromRawValue("PreviewView", "hybridRef", rawProps, sourceProps.hybridRef)) { } bool HybridPreviewViewProps::filterObjectKeys(const std::string& propName) { switch (hashString(propName)) { @@ -110,29 +41,4 @@ namespace margelo::nitro::camera::views { } } - HybridPreviewViewComponentDescriptor::HybridPreviewViewComponentDescriptor(const react::ComponentDescriptorParameters& parameters) - : ConcreteComponentDescriptor(parameters, - react::RawPropsParser()) {} - - std::shared_ptr HybridPreviewViewComponentDescriptor::cloneProps(const react::PropsParserContext& context, - const std::shared_ptr& props, - react::RawProps rawProps) const { - // 1. Prepare raw props parser - rawProps.parse(rawPropsParser_); - // 2. Copy props with Nitro's cached copy constructor - return HybridPreviewViewShadowNode::Props(context, /* & */ rawProps, props); - } - -#ifdef ANDROID - void HybridPreviewViewComponentDescriptor::adopt(react::ShadowNode& shadowNode) const { - // This is called immediately after `ShadowNode` is created, cloned or in progress. - // On Android, we need to wrap props in our state, which gets routed through Java and later unwrapped in JNI/C++. - auto& concreteShadowNode = static_cast(shadowNode); - const std::shared_ptr& constProps = concreteShadowNode.getConcreteSharedProps(); - const std::shared_ptr& props = std::const_pointer_cast(constProps); - HybridPreviewViewState state{props}; - concreteShadowNode.setStateData(std::move(state)); - } -#endif - } // namespace margelo::nitro::camera::views diff --git a/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.hpp b/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.hpp index 1aa231c0d5..7c586454ea 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.hpp +++ b/packages/react-native-vision-camera/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.hpp @@ -7,14 +7,15 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include +#include +#include #include #include +#include +#include + +#include #include #include "HybridCameraPreviewOutputSpec.hpp" @@ -46,13 +47,35 @@ namespace margelo::nitro::camera::views { const react::RawProps& rawProps); public: - CachedProp>> previewOutput; - CachedProp> resizeMode; - CachedProp> implementationMode; - CachedProp>>> gestureControllers; - CachedProp>> onPreviewStarted; - CachedProp>> onPreviewStopped; - CachedProp& /* ref */)>>> hybridRef; + nitro::ReactProp>> previewOutput; + nitro::ReactProp> resizeMode; + nitro::ReactProp> implementationMode; + nitro::ReactProp>>> gestureControllers; + nitro::ReactProp>> onPreviewStarted; + nitro::ReactProp>> onPreviewStopped; + nitro::ReactProp& /* ref */)>>> hybridRef; + + [[nodiscard]] + bool hasSameProps(const HybridPreviewViewProps& other) const noexcept { + return previewOutput.hasSameValue(other.previewOutput) && + resizeMode.hasSameValue(other.resizeMode) && + implementationMode.hasSameValue(other.implementationMode) && + gestureControllers.hasSameValue(other.gestureControllers) && + onPreviewStarted.hasSameValue(other.onPreviewStarted) && + onPreviewStopped.hasSameValue(other.onPreviewStopped) && + hybridRef.hasSameValue(other.hybridRef); + } + + [[nodiscard]] + bool hasAnyProvidedProps() const noexcept { + return previewOutput.isProvided() || + resizeMode.isProvided() || + implementationMode.isProvided() || + gestureControllers.isProvided() || + onPreviewStarted.isProvided() || + onPreviewStopped.isProvided() || + hybridRef.isProvided(); + } private: static bool filterObjectKeys(const std::string& propName); @@ -61,32 +84,7 @@ namespace margelo::nitro::camera::views { /** * State for the "PreviewView" View. */ - class HybridPreviewViewState final { - public: - HybridPreviewViewState() = default; - explicit HybridPreviewViewState(const std::shared_ptr& props): - _props(props) {} - - public: - [[nodiscard]] - const std::shared_ptr& getProps() const { - return _props; - } - - public: -#ifdef ANDROID - HybridPreviewViewState(const HybridPreviewViewState& /* previousState */, folly::dynamic /* data */) {} - folly::dynamic getDynamic() const { - throw std::runtime_error("HybridPreviewViewState does not support folly!"); - } - react::MapBuffer getMapBuffer() const { - throw std::runtime_error("HybridPreviewViewState does not support MapBuffer!"); - }; -#endif - - private: - std::shared_ptr _props; - }; + using HybridPreviewViewState = nitro::ViewPropsHolderState; /** * The Shadow Node for the "PreviewView" View. @@ -99,21 +97,7 @@ namespace margelo::nitro::camera::views { /** * The Component Descriptor for the "PreviewView" View. */ - class HybridPreviewViewComponentDescriptor final: public react::ConcreteComponentDescriptor { - public: - explicit HybridPreviewViewComponentDescriptor(const react::ComponentDescriptorParameters& parameters); - - public: - /** - * A faster path for cloning props - reuses the caching logic from `HybridPreviewViewProps`. - */ - std::shared_ptr cloneProps(const react::PropsParserContext& context, - const std::shared_ptr& props, - react::RawProps rawProps) const override; -#ifdef ANDROID - void adopt(react::ShadowNode& shadowNode) const override; -#endif - }; + using HybridPreviewViewComponentDescriptor = nitro::ViewComponentDescriptor; /* The actual view for "PreviewView" needs to be implemented in platform-specific code. */ diff --git a/packages/react-native-vision-camera/package.json b/packages/react-native-vision-camera/package.json index 40efb063bd..e0832ce100 100644 --- a/packages/react-native-vision-camera/package.json +++ b/packages/react-native-vision-camera/package.json @@ -70,11 +70,11 @@ }, "devDependencies": { "@types/react": "19.2.15", - "nitrogen": "0.36.5", + "nitrogen": "0.37.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-nitro-image": "0.15.1", - "react-native-nitro-modules": "0.36.5", + "react-native-nitro-image": "0.15.2", + "react-native-nitro-modules": "0.37.0", "typescript": "6.0.3" }, "peerDependencies": {