diff --git a/packages/react-native/ReactCxxPlatform/react/renderer/animated/AnimatedModule.cpp b/packages/react-native/ReactCxxPlatform/react/renderer/animated/AnimatedModule.cpp index f3f394239b9..1555db1dcff 100644 --- a/packages/react-native/ReactCxxPlatform/react/renderer/animated/AnimatedModule.cpp +++ b/packages/react-native/ReactCxxPlatform/react/renderer/animated/AnimatedModule.cpp @@ -26,17 +26,21 @@ void AnimatedModule::finishOperationBatch(jsi::Runtime& /*rt*/) { std::vector operations; std::swap(preOperations_, preOperations); std::swap(operations_, operations); - scheduleOperationOnUI([preOperations = std::move(preOperations), - operations = std::move(operations)]( - NativeAnimatedNodesManager& nodesManager) { - for (auto& preOperation : preOperations) { - preOperation(nodesManager); - } - for (auto& operation : operations) { - operation(nodesManager); - } - }); + if (nodesManager_) { + // TODO: nodesManager_ must exist at all times. But without this check + // AnimatedProps-itest.js fails. + nodesManager_->scheduleOnUI([this, + preOperations = std::move(preOperations), + operations = std::move(operations)]() { + for (auto& preOperation : preOperations) { + executeOperation(preOperation); + } + for (auto& operation : operations) { + executeOperation(operation); + } + }); + } } void AnimatedModule::createAnimatedNode( @@ -44,10 +48,8 @@ void AnimatedModule::createAnimatedNode( Tag tag, jsi::Object config) { auto configDynamic = dynamicFromValue(rt, jsi::Value(rt, config)); - addOperation([tag, configDynamic = std::move(configDynamic)]( - NativeAnimatedNodesManager& nodesManager) { - nodesManager.createAnimatedNode(tag, configDynamic); - }); + operations_.emplace_back( + CreateAnimatedNodeOp{.tag = tag, .config = std::move(configDynamic)}); } void AnimatedModule::updateAnimatedNodeConfig( @@ -60,64 +62,37 @@ void AnimatedModule::updateAnimatedNodeConfig( void AnimatedModule::getValue( jsi::Runtime& /*rt*/, Tag tag, - const AsyncCallback& saveValueCallback) { - addOperation([tag, - saveValueCallback, - weakJsInvoker = std::weak_ptr(jsInvoker_)]( - NativeAnimatedNodesManager& nodesManager) { - auto animValue = nodesManager.getValue(tag); - auto jsInvoker = weakJsInvoker.lock(); - if (animValue && jsInvoker) { - jsInvoker->invokeAsync( - [animValue, saveValueCallback = saveValueCallback]() { - saveValueCallback.call(animValue.value()); - }); - }; - }); + AsyncCallback saveValueCallback) { + operations_.emplace_back( + GetValueOp{.tag = tag, .callback = std::move(saveValueCallback)}); } void AnimatedModule::startListeningToAnimatedNodeValue( jsi::Runtime& /*rt*/, Tag tag) { - addOperation([tag, this](NativeAnimatedNodesManager& nodesManager) { - nodesManager.startListeningToAnimatedNodeValue( - tag, [this, tag](double value) { - emitDeviceEvent( - "onAnimatedValueUpdate", - [tag, value](jsi::Runtime& rt, std::vector& args) { - auto arg = jsi::Object(rt); - arg.setProperty(rt, "tag", jsi::Value(tag)); - arg.setProperty(rt, "value", jsi::Value(value)); - args.emplace_back(rt, arg); - }); - }); - }); + operations_.emplace_back(StartListeningToAnimatedNodeValueOp{tag}); } void AnimatedModule::stopListeningToAnimatedNodeValue( jsi::Runtime& /*rt*/, Tag tag) { - addOperation([tag](NativeAnimatedNodesManager& nodesManager) { - nodesManager.stopListeningToAnimatedNodeValue(tag); - }); + operations_.emplace_back(StopListeningToAnimatedNodeValueOp{tag}); } void AnimatedModule::connectAnimatedNodes( jsi::Runtime& /*rt*/, Tag parentTag, Tag childTag) { - addOperation([parentTag, childTag](NativeAnimatedNodesManager& nodesManager) { - nodesManager.connectAnimatedNodes(parentTag, childTag); - }); + operations_.emplace_back( + ConnectAnimatedNodesOp{.parentTag = parentTag, .childTag = childTag}); } void AnimatedModule::disconnectAnimatedNodes( jsi::Runtime& /*rt*/, Tag parentTag, Tag childTag) { - addOperation([parentTag, childTag](NativeAnimatedNodesManager& nodesManager) { - nodesManager.disconnectAnimatedNodes(parentTag, childTag); - }); + operations_.emplace_back( + DisconnectAnimatedNodesOp{.parentTag = parentTag, .childTag = childTag}); } void AnimatedModule::startAnimatingNode( @@ -127,48 +102,40 @@ void AnimatedModule::startAnimatingNode( jsi::Object config, AnimationEndCallback endCallback) { auto configDynamic = dynamicFromValue(rt, jsi::Value(rt, config)); - addOperation([animationId, - nodeTag, - configDynamic = std::move(configDynamic), - endCallback = std::move(endCallback)]( - NativeAnimatedNodesManager& nodesManager) { - nodesManager.startAnimatingNode( - animationId, nodeTag, configDynamic, endCallback); - }); + operations_.emplace_back(StartAnimatingNodeOp{ + .animationId = animationId, + .nodeTag = nodeTag, + .config = std::move(configDynamic), + .endCallback = std::move(endCallback)}); } void AnimatedModule::stopAnimation(jsi::Runtime& /*rt*/, int animationId) { - addOperation([animationId](NativeAnimatedNodesManager& nodesManager) { - nodesManager.stopAnimation( - animationId, false /* TODO: isTrackingAnimation */); - }); + operations_.emplace_back(StopAnimationOp{animationId}); } void AnimatedModule::setAnimatedNodeValue( jsi::Runtime& /*rt*/, Tag nodeTag, double value) { - addOperation([nodeTag, value](NativeAnimatedNodesManager& nodesManager) { - nodesManager.setAnimatedNodeValue(nodeTag, value); - }); + operations_.emplace_back(SetAnimatedNodeValueOp{nodeTag, value}); } void AnimatedModule::setAnimatedNodeOffset( jsi::Runtime& /*rt*/, - Tag nodeTag, - double offset) { + Tag /*nodeTag*/, + double /*offset*/) { // TODO: missing implementation } void AnimatedModule::flattenAnimatedNodeOffset( jsi::Runtime& /*rt*/, - Tag nodeTag) { + Tag /*nodeTag*/) { // TODO: missing implementation } void AnimatedModule::extractAnimatedNodeOffset( jsi::Runtime& /*rt*/, - Tag nodeTag) { + Tag /*nodeTag*/) { // TODO: missing implementation } @@ -176,73 +143,124 @@ void AnimatedModule::connectAnimatedNodeToView( jsi::Runtime& /*rt*/, Tag nodeTag, Tag viewTag) { - addOperation([nodeTag, viewTag](NativeAnimatedNodesManager& nodesManager) { - nodesManager.connectAnimatedNodeToView(nodeTag, viewTag); - }); + operations_.emplace_back(ConnectAnimatedNodeToViewOp{nodeTag, viewTag}); } void AnimatedModule::disconnectAnimatedNodeFromView( jsi::Runtime& /*rt*/, Tag nodeTag, Tag viewTag) { - addOperation([nodeTag, viewTag](NativeAnimatedNodesManager& nodesManager) { - nodesManager.disconnectAnimatedNodeFromView(nodeTag, viewTag); - }); + operations_.emplace_back(DisconnectAnimatedNodeFromViewOp{nodeTag, viewTag}); } void AnimatedModule::restoreDefaultValues(jsi::Runtime& /*rt*/, Tag nodeTag) { - addOperation( - [nodeTag](NativeAnimatedNodesManager& nodesManager) { - nodesManager.restoreDefaultValues(nodeTag); - }, - /* preOperation = */ true); + preOperations_.emplace_back(RestoreDefaultValuesOp{nodeTag}); } void AnimatedModule::dropAnimatedNode(jsi::Runtime& /*rt*/, Tag tag) { - addOperation([tag](NativeAnimatedNodesManager& nodesManager) { - nodesManager.dropAnimatedNode(tag); - }); + operations_.emplace_back(DropAnimatedNodeOp{tag}); } void AnimatedModule::addAnimatedEventToView( jsi::Runtime& rt, Tag viewTag, - const std::string& eventName, + std::string eventName, jsi::Object eventMapping) { auto eventMappingDynamic = dynamicFromValue(rt, jsi::Value(rt, eventMapping)); - addOperation([viewTag, eventName, eventMappingDynamic]( - NativeAnimatedNodesManager& nodesManager) { - nodesManager.addAnimatedEventToView( - viewTag, eventName, eventMappingDynamic); - }); + operations_.emplace_back(AddAnimatedEventToViewOp{ + .viewTag = viewTag, + .eventName = std::move(eventName), + .eventMapping = std::move(eventMappingDynamic)}); } void AnimatedModule::removeAnimatedEventFromView( jsi::Runtime& /*rt*/, Tag viewTag, - const std::string& eventName, + std::string eventName, Tag animatedNodeTag) { - addOperation([viewTag, eventName, animatedNodeTag]( - NativeAnimatedNodesManager& nodesManager) { - nodesManager.removeAnimatedEventFromView( - viewTag, eventName, animatedNodeTag); - }); + operations_.emplace_back(RemoveAnimatedEventFromViewOp{ + .viewTag = viewTag, + .eventName = std::move(eventName), + .animatedNodeTag = animatedNodeTag}); } void AnimatedModule::addListener( - jsi::Runtime& rt, - const std::string& eventName) {} + jsi::Runtime& /*rt*/, + const std::string& /*eventName*/) { + // TODO: missing implementation +} -void AnimatedModule::removeListeners(jsi::Runtime& rt, int count) {} +void AnimatedModule::removeListeners(jsi::Runtime& /*rt*/, int /*count*/) { + // TODO: missing implementation +} void AnimatedModule::queueAndExecuteBatchedOperations( - jsi::Runtime& rt, - jsi::Array operationsAndArgs) {} + jsi::Runtime& /*rt*/, + jsi::Array /*operationsAndArgs*/) { + // TODO: missing implementation +} -void AnimatedModule::addOperation(Operation&& operation, bool preOperation) { - // No mutex needed, operations only added via TurboModule method invocation - auto& queue = preOperation ? preOperations_ : operations_; - queue.push_back(std::move(operation)); +void AnimatedModule::executeOperation(const Operation& operation) { + std::visit( + [&](const auto& op) { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + nodesManager_->createAnimatedNode(op.tag, op.config); + } else if constexpr (std::is_same_v) { + auto animValue = nodesManager_->getValue(op.tag); + if (animValue) { + op.callback.call(animValue.value()); + } + } else if constexpr (std::is_same_v< + T, + StartListeningToAnimatedNodeValueOp>) { + nodesManager_->startListeningToAnimatedNodeValue( + op.tag, [this, tag = op.tag](double value) { + emitDeviceEvent( + "onAnimatedValueUpdate", + [tag, value]( + jsi::Runtime& rt, std::vector& args) { + auto arg = jsi::Object(rt); + arg.setProperty(rt, "tag", jsi::Value(tag)); + arg.setProperty(rt, "value", jsi::Value(value)); + args.emplace_back(rt, arg); + }); + }); + } else if constexpr (std::is_same_v< + T, + StopListeningToAnimatedNodeValueOp>) { + nodesManager_->stopListeningToAnimatedNodeValue(op.tag); + } else if constexpr (std::is_same_v) { + nodesManager_->connectAnimatedNodes(op.parentTag, op.childTag); + } else if constexpr (std::is_same_v) { + nodesManager_->disconnectAnimatedNodes(op.parentTag, op.childTag); + } else if constexpr (std::is_same_v) { + nodesManager_->startAnimatingNode( + op.animationId, op.nodeTag, op.config, op.endCallback); + } else if constexpr (std::is_same_v) { + nodesManager_->stopAnimation(op.animationId, false); + } else if constexpr (std::is_same_v) { + nodesManager_->setAnimatedNodeValue(op.nodeTag, op.value); + } else if constexpr (std::is_same_v) { + nodesManager_->connectAnimatedNodeToView(op.nodeTag, op.viewTag); + } else if constexpr (std::is_same_v< + T, + DisconnectAnimatedNodeFromViewOp>) { + nodesManager_->disconnectAnimatedNodeFromView(op.nodeTag, op.viewTag); + } else if constexpr (std::is_same_v) { + nodesManager_->restoreDefaultValues(op.nodeTag); + } else if constexpr (std::is_same_v) { + nodesManager_->dropAnimatedNode(op.tag); + } else if constexpr (std::is_same_v) { + nodesManager_->addAnimatedEventToView( + op.viewTag, op.eventName, op.eventMapping); + } else if constexpr (std::is_same_v) { + nodesManager_->removeAnimatedEventFromView( + op.viewTag, op.eventName, op.animatedNodeTag); + } + }, + operation); } void AnimatedModule::installJSIBindingsWithRuntime(jsi::Runtime& runtime) { diff --git a/packages/react-native/ReactCxxPlatform/react/renderer/animated/AnimatedModule.h b/packages/react-native/ReactCxxPlatform/react/renderer/animated/AnimatedModule.h index ea179146297..a164c59d2ee 100644 --- a/packages/react-native/ReactCxxPlatform/react/renderer/animated/AnimatedModule.h +++ b/packages/react-native/ReactCxxPlatform/react/renderer/animated/AnimatedModule.h @@ -9,18 +9,111 @@ #include #include +#include #include #include #include #include #include +#include namespace facebook::react { class AnimatedModule : public NativeAnimatedModuleCxxSpec, public TurboModuleWithJSIBindings { - using Operation = - std::function; +#pragma mark - Operation structures for each type of animated operation + struct CreateAnimatedNodeOp { + Tag tag{}; + folly::dynamic config; + }; + + struct GetValueOp { + Tag tag{}; + AsyncCallback callback; + }; + + struct StartListeningToAnimatedNodeValueOp { + Tag tag{}; + }; + + struct StopListeningToAnimatedNodeValueOp { + Tag tag{}; + }; + + struct ConnectAnimatedNodesOp { + Tag parentTag{}; + Tag childTag{}; + }; + + struct DisconnectAnimatedNodesOp { + Tag parentTag{}; + Tag childTag{}; + }; + + struct StartAnimatingNodeOp { + int animationId{}; + Tag nodeTag{}; + folly::dynamic config; + AnimationEndCallback endCallback; + }; + + struct StopAnimationOp { + int animationId{}; + }; + + struct SetAnimatedNodeValueOp { + Tag nodeTag{}; + double value{}; + }; + + struct ConnectAnimatedNodeToViewOp { + Tag nodeTag{}; + Tag viewTag{}; + }; + + struct DisconnectAnimatedNodeFromViewOp { + Tag nodeTag{}; + Tag viewTag{}; + }; + + struct RestoreDefaultValuesOp { + Tag nodeTag{}; + }; + + struct DropAnimatedNodeOp { + Tag tag{}; + }; + + struct AddAnimatedEventToViewOp { + Tag viewTag{}; + std::string eventName; + folly::dynamic eventMapping; + }; + + struct RemoveAnimatedEventFromViewOp { + Tag viewTag{}; + std::string eventName; + Tag animatedNodeTag{}; + }; + + using Operation = std::variant< + CreateAnimatedNodeOp, + GetValueOp, + StartListeningToAnimatedNodeValueOp, + StopListeningToAnimatedNodeValueOp, + ConnectAnimatedNodesOp, + DisconnectAnimatedNodesOp, + StartAnimatingNodeOp, + StopAnimationOp, + SetAnimatedNodeValueOp, + ConnectAnimatedNodeToViewOp, + DisconnectAnimatedNodeFromViewOp, + RestoreDefaultValuesOp, + DropAnimatedNodeOp, + AddAnimatedEventToViewOp, + RemoveAnimatedEventFromViewOp>; + +#pragma mark - public: AnimatedModule( @@ -35,10 +128,8 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec, void updateAnimatedNodeConfig(jsi::Runtime& rt, Tag tag, jsi::Object config); - void getValue( - jsi::Runtime& rt, - Tag tag, - const AsyncCallback& saveValueCallback); + void + getValue(jsi::Runtime& rt, Tag tag, AsyncCallback saveValueCallback); void startListeningToAnimatedNodeValue(jsi::Runtime& rt, Tag tag); @@ -77,13 +168,13 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec, void addAnimatedEventToView( jsi::Runtime& rt, Tag viewTag, - const std::string& eventName, + std::string eventName, jsi::Object eventMapping); void removeAnimatedEventFromView( jsi::Runtime& rt, Tag viewTag, - const std::string& eventName, + std::string eventName, Tag animatedNodeTag); void addListener(jsi::Runtime& rt, const std::string& eventName); @@ -94,29 +185,13 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec, jsi::Runtime& rt, jsi::Array operationsAndArgs); - void scheduleOperationOnUI(Operation&& fn) { - if (nodesManager_) { - nodesManager_->scheduleOnUI( - [fn = std::move(fn), - weakNodesManager = - std::weak_ptr(nodesManager_)]() { - if (auto nodesManager = weakNodesManager.lock()) { - fn(*nodesManager); - } - }); - } - } - - protected: - std::shared_ptr nodesManagerProvider_; - private: + std::shared_ptr nodesManagerProvider_; std::shared_ptr nodesManager_; std::vector preOperations_; std::vector operations_; - void addOperation(Operation&& operation, bool preOperation = false); - + void executeOperation(const Operation& operation); void installJSIBindingsWithRuntime(jsi::Runtime& runtime) override; };