feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,845 @@
#include "NativeReanimatedModule.h"
#ifdef RCT_NEW_ARCH_ENABLED
#include <react/renderer/uimanager/UIManagerBinding.h>
#include <react/renderer/uimanager/primitives.h>
#if REACT_NATIVE_MINOR_VERSION >= 73 && defined(RCT_NEW_ARCH_ENABLED)
#include <react/utils/CoreFeatures.h>
#endif
#endif
#include <functional>
#include <iomanip>
#include <memory>
#include <sstream>
#include <string>
#include <thread>
#include <unordered_map>
#ifdef RCT_NEW_ARCH_ENABLED
#include "ReanimatedCommitMarker.h"
#include "ShadowTreeCloner.h"
#endif
#include "AsyncQueue.h"
#include "CollectionUtils.h"
#include "EventHandlerRegistry.h"
#include "FeaturesConfig.h"
#include "JSScheduler.h"
#include "ReanimatedHiddenHeaders.h"
#include "Shareables.h"
#include "UIRuntimeDecorator.h"
#include "WorkletEventHandler.h"
#ifdef __ANDROID__
#include <fbjni/fbjni.h>
#endif
using namespace facebook;
#if REACT_NATIVE_MINOR_VERSION == 73 && defined(RCT_NEW_ARCH_ENABLED)
// Android can't find the definition of this static field
bool CoreFeatures::useNativeState;
#endif
namespace reanimated {
NativeReanimatedModule::NativeReanimatedModule(
jsi::Runtime &rnRuntime,
const std::shared_ptr<JSScheduler> &jsScheduler,
const std::shared_ptr<MessageQueueThread> &jsQueue,
const std::shared_ptr<UIScheduler> &uiScheduler,
const PlatformDepMethodsHolder &platformDepMethodsHolder,
const std::string &valueUnpackerCode,
const bool isBridgeless)
: NativeReanimatedModuleSpec(
isBridgeless ? nullptr : jsScheduler->getJSCallInvoker()),
isBridgeless_(isBridgeless),
jsQueue_(jsQueue),
jsScheduler_(jsScheduler),
uiScheduler_(uiScheduler),
uiWorkletRuntime_(std::make_shared<WorkletRuntime>(
rnRuntime,
jsQueue,
jsScheduler_,
"Reanimated UI runtime",
true /* supportsLocking */,
valueUnpackerCode)),
valueUnpackerCode_(valueUnpackerCode),
eventHandlerRegistry_(std::make_unique<EventHandlerRegistry>()),
requestRender_(platformDepMethodsHolder.requestRender),
onRenderCallback_([this](const double timestampMs) {
renderRequested_ = false;
onRender(timestampMs);
}),
animatedSensorModule_(platformDepMethodsHolder),
jsLogger_(std::make_shared<JSLogger>(jsScheduler_)),
layoutAnimationsManager_(jsLogger_),
#ifdef RCT_NEW_ARCH_ENABLED
synchronouslyUpdateUIPropsFunction_(
platformDepMethodsHolder.synchronouslyUpdateUIPropsFunction),
propsRegistry_(std::make_shared<PropsRegistry>()),
#else
obtainPropFunction_(platformDepMethodsHolder.obtainPropFunction),
configurePropsPlatformFunction_(
platformDepMethodsHolder.configurePropsFunction),
updatePropsFunction_(platformDepMethodsHolder.updatePropsFunction),
#endif
subscribeForKeyboardEventsFunction_(
platformDepMethodsHolder.subscribeForKeyboardEvents),
unsubscribeFromKeyboardEventsFunction_(
platformDepMethodsHolder.unsubscribeFromKeyboardEvents) {
commonInit(platformDepMethodsHolder);
}
void NativeReanimatedModule::commonInit(
const PlatformDepMethodsHolder &platformDepMethodsHolder) {
auto requestAnimationFrame =
[this](jsi::Runtime &rt, const jsi::Value &callback) {
this->requestAnimationFrame(rt, callback);
};
#ifdef RCT_NEW_ARCH_ENABLED
auto updateProps = [this](jsi::Runtime &rt, const jsi::Value &operations) {
this->updateProps(rt, operations);
};
auto removeFromPropsRegistry =
[this](jsi::Runtime &rt, const jsi::Value &viewTags) {
this->removeFromPropsRegistry(rt, viewTags);
};
auto measure = [this](jsi::Runtime &rt, const jsi::Value &shadowNodeValue) {
return this->measure(rt, shadowNodeValue);
};
auto dispatchCommand = [this](
jsi::Runtime &rt,
const jsi::Value &shadowNodeValue,
const jsi::Value &commandNameValue,
const jsi::Value &argsValue) {
this->dispatchCommand(rt, shadowNodeValue, commandNameValue, argsValue);
};
auto obtainProp = [this](
jsi::Runtime &rt,
const jsi::Value &shadowNodeWrapper,
const jsi::Value &propName) {
return this->obtainProp(rt, shadowNodeWrapper, propName);
};
#endif
jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
UIRuntimeDecorator::decorate(
uiRuntime,
#ifdef RCT_NEW_ARCH_ENABLED
removeFromPropsRegistry,
obtainProp,
updateProps,
measure,
dispatchCommand,
#else
platformDepMethodsHolder.scrollToFunction,
platformDepMethodsHolder.obtainPropFunction,
platformDepMethodsHolder.updatePropsFunction,
platformDepMethodsHolder.measureFunction,
platformDepMethodsHolder.dispatchCommandFunction,
#endif
requestAnimationFrame,
platformDepMethodsHolder.getAnimationTimestamp,
platformDepMethodsHolder.setGestureStateFunction,
platformDepMethodsHolder.progressLayoutAnimation,
platformDepMethodsHolder.endLayoutAnimation,
platformDepMethodsHolder.maybeFlushUIUpdatesQueueFunction);
}
NativeReanimatedModule::~NativeReanimatedModule() {
// event handler registry and frame callbacks store some JSI values from UI
// runtime, so they have to go away before we tear down the runtime
eventHandlerRegistry_.reset();
frameCallbacks_.clear();
uiWorkletRuntime_.reset();
}
void NativeReanimatedModule::scheduleOnUI(
jsi::Runtime &rt,
const jsi::Value &worklet) {
auto shareableWorklet = extractShareableOrThrow<ShareableWorklet>(
rt, worklet, "[Reanimated] Only worklets can be scheduled to run on UI.");
uiScheduler_->scheduleOnUI([=] {
#if JS_RUNTIME_HERMES
// JSI's scope defined here allows for JSI-objects to be cleared up after
// each runtime loop. Within these loops we typically create some temporary
// JSI objects and hence it allows for such objects to be garbage collected
// much sooner.
// Apparently the scope API is only supported on Hermes at the moment.
const auto scope = jsi::Scope(uiWorkletRuntime_->getJSIRuntime());
#endif
uiWorkletRuntime_->runGuarded(shareableWorklet);
});
}
jsi::Value NativeReanimatedModule::executeOnUIRuntimeSync(
jsi::Runtime &rt,
const jsi::Value &worklet) {
return uiWorkletRuntime_->executeSync(rt, worklet);
}
jsi::Value NativeReanimatedModule::createWorkletRuntime(
jsi::Runtime &rt,
const jsi::Value &name,
const jsi::Value &initializer) {
auto workletRuntime = std::make_shared<WorkletRuntime>(
rt,
jsQueue_,
jsScheduler_,
name.asString(rt).utf8(rt),
false /* supportsLocking */,
valueUnpackerCode_);
auto initializerShareable = extractShareableOrThrow<ShareableWorklet>(
rt, initializer, "[Reanimated] Initializer must be a worklet.");
workletRuntime->runGuarded(initializerShareable);
return jsi::Object::createFromHostObject(rt, workletRuntime);
}
jsi::Value NativeReanimatedModule::scheduleOnRuntime(
jsi::Runtime &rt,
const jsi::Value &workletRuntimeValue,
const jsi::Value &shareableWorkletValue) {
reanimated::scheduleOnRuntime(rt, workletRuntimeValue, shareableWorkletValue);
return jsi::Value::undefined();
}
jsi::Value NativeReanimatedModule::makeShareableClone(
jsi::Runtime &rt,
const jsi::Value &value,
const jsi::Value &shouldRetainRemote,
const jsi::Value &nativeStateSource) {
return reanimated::makeShareableClone(
rt, value, shouldRetainRemote, nativeStateSource);
}
jsi::Value NativeReanimatedModule::registerEventHandler(
jsi::Runtime &rt,
const jsi::Value &worklet,
const jsi::Value &eventName,
const jsi::Value &emitterReactTag) {
static uint64_t NEXT_EVENT_HANDLER_ID = 1;
uint64_t newRegistrationId = NEXT_EVENT_HANDLER_ID++;
auto eventNameStr = eventName.asString(rt).utf8(rt);
auto handlerShareable = extractShareableOrThrow<ShareableWorklet>(
rt, worklet, "[Reanimated] Event handler must be a worklet.");
int emitterReactTagInt = emitterReactTag.asNumber();
uiScheduler_->scheduleOnUI([=] {
auto handler = std::make_shared<WorkletEventHandler>(
newRegistrationId, eventNameStr, emitterReactTagInt, handlerShareable);
eventHandlerRegistry_->registerEventHandler(std::move(handler));
});
return jsi::Value(static_cast<double>(newRegistrationId));
}
void NativeReanimatedModule::unregisterEventHandler(
jsi::Runtime &,
const jsi::Value &registrationId) {
uint64_t id = registrationId.asNumber();
uiScheduler_->scheduleOnUI(
[=] { eventHandlerRegistry_->unregisterEventHandler(id); });
}
#ifdef RCT_NEW_ARCH_ENABLED
static inline std::string intColorToHex(const int val) {
std::stringstream
invertedHexColorStream; // By default transparency is first, color second
invertedHexColorStream << std::setfill('0') << std::setw(8) << std::hex
<< val;
auto invertedHexColor = invertedHexColorStream.str();
auto hexColor =
"#" + invertedHexColor.substr(2, 6) + invertedHexColor.substr(0, 2);
return hexColor;
}
std::string NativeReanimatedModule::obtainPropFromShadowNode(
jsi::Runtime &rt,
const std::string &propName,
const ShadowNode::Shared &shadowNode) {
auto newestCloneOfShadowNode =
uiManager_->getNewestCloneOfShadowNode(*shadowNode);
if (propName == "width" || propName == "height" || propName == "top" ||
propName == "left") {
// These props are calculated from frame
auto layoutableShadowNode = dynamic_cast<LayoutableShadowNode const *>(
newestCloneOfShadowNode.get());
const auto &frame = layoutableShadowNode->layoutMetrics_.frame;
if (propName == "width") {
return std::to_string(frame.size.width);
} else if (propName == "height") {
return std::to_string(frame.size.height);
} else if (propName == "top") {
return std::to_string(frame.origin.y);
} else if (propName == "left") {
return std::to_string(frame.origin.x);
}
} else {
// These props are calculated from viewProps
auto props = newestCloneOfShadowNode->getProps();
auto viewProps = std::static_pointer_cast<const ViewProps>(props);
if (propName == "opacity") {
return std::to_string(viewProps->opacity);
} else if (propName == "zIndex") {
if (viewProps->zIndex.has_value()) {
return std::to_string(*viewProps->zIndex);
}
} else if (propName == "backgroundColor") {
return intColorToHex(*viewProps->backgroundColor);
}
}
throw std::runtime_error(std::string(
"Getting property `" + propName +
"` with function `getViewProp` is not supported"));
}
jsi::Value NativeReanimatedModule::getViewProp(
jsi::Runtime &rnRuntime,
const jsi::Value &shadowNodeWrapper,
const jsi::Value &propName,
const jsi::Value &callback) {
const auto propNameStr = propName.asString(rnRuntime).utf8(rnRuntime);
const auto funPtr = std::make_shared<jsi::Function>(
callback.getObject(rnRuntime).asFunction(rnRuntime));
const auto shadowNode = shadowNodeFromValue(rnRuntime, shadowNodeWrapper);
uiScheduler_->scheduleOnUI([=]() {
jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
const auto resultStr =
obtainPropFromShadowNode(uiRuntime, propNameStr, shadowNode);
jsScheduler_->scheduleOnJS([=](jsi::Runtime &rnRuntime) {
const auto resultValue =
jsi::String::createFromUtf8(rnRuntime, resultStr);
funPtr->call(rnRuntime, resultValue);
});
});
return jsi::Value::undefined();
}
#else
jsi::Value NativeReanimatedModule::getViewProp(
jsi::Runtime &rnRuntime,
const jsi::Value &viewTag,
const jsi::Value &propName,
const jsi::Value &callback) {
const auto propNameStr = propName.asString(rnRuntime).utf8(rnRuntime);
const auto funPtr = std::make_shared<jsi::Function>(
callback.getObject(rnRuntime).asFunction(rnRuntime));
const int viewTagInt = viewTag.asNumber();
uiScheduler_->scheduleOnUI([=]() {
jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
const jsi::Value propNameValue =
jsi::String::createFromUtf8(uiRuntime, propNameStr);
const auto resultValue =
obtainPropFunction_(uiRuntime, viewTagInt, propNameValue);
const auto resultStr = resultValue.asString(uiRuntime).utf8(uiRuntime);
jsScheduler_->scheduleOnJS([=](jsi::Runtime &rnRuntime) {
const auto resultValue =
jsi::String::createFromUtf8(rnRuntime, resultStr);
funPtr->call(rnRuntime, resultValue);
});
});
return jsi::Value::undefined();
}
#endif
jsi::Value NativeReanimatedModule::enableLayoutAnimations(
jsi::Runtime &,
const jsi::Value &config) {
FeaturesConfig::setLayoutAnimationEnabled(config.getBool());
return jsi::Value::undefined();
}
jsi::Value NativeReanimatedModule::configureProps(
jsi::Runtime &rt,
const jsi::Value &uiProps,
const jsi::Value &nativeProps) {
#ifdef RCT_NEW_ARCH_ENABLED
auto uiPropsArray = uiProps.asObject(rt).asArray(rt);
for (size_t i = 0; i < uiPropsArray.size(rt); ++i) {
auto name = uiPropsArray.getValueAtIndex(rt, i).asString(rt).utf8(rt);
animatablePropNames_.insert(name);
}
auto nativePropsArray = nativeProps.asObject(rt).asArray(rt);
for (size_t i = 0; i < nativePropsArray.size(rt); ++i) {
auto name = nativePropsArray.getValueAtIndex(rt, i).asString(rt).utf8(rt);
nativePropNames_.insert(name);
animatablePropNames_.insert(name);
}
#else
configurePropsPlatformFunction_(rt, uiProps, nativeProps);
#endif // RCT_NEW_ARCH_ENABLED
return jsi::Value::undefined();
}
jsi::Value NativeReanimatedModule::configureLayoutAnimationBatch(
jsi::Runtime &rt,
const jsi::Value &layoutAnimationsBatch) {
auto array = layoutAnimationsBatch.asObject(rt).asArray(rt);
size_t length = array.size(rt);
std::vector<LayoutAnimationConfig> batch(length);
for (int i = 0; i < length; i++) {
auto item = array.getValueAtIndex(rt, i).asObject(rt);
auto &batchItem = batch[i];
batchItem.tag = item.getProperty(rt, "viewTag").asNumber();
batchItem.type = static_cast<LayoutAnimationType>(
item.getProperty(rt, "type").asNumber());
auto config = item.getProperty(rt, "config");
if (config.isUndefined()) {
batchItem.config = nullptr;
} else {
batchItem.config = extractShareableOrThrow<ShareableObject>(
rt,
config,
"[Reanimated] Layout animation config must be an object.");
}
if (batch[i].type != SHARED_ELEMENT_TRANSITION &&
batch[i].type != SHARED_ELEMENT_TRANSITION_PROGRESS) {
continue;
}
auto sharedTransitionTag = item.getProperty(rt, "sharedTransitionTag");
if (sharedTransitionTag.isUndefined()) {
batch[i].config = nullptr;
} else {
batch[i].sharedTransitionTag = sharedTransitionTag.asString(rt).utf8(rt);
}
}
layoutAnimationsManager_.configureAnimationBatch(batch);
return jsi::Value::undefined();
}
void NativeReanimatedModule::setShouldAnimateExiting(
jsi::Runtime &rt,
const jsi::Value &viewTag,
const jsi::Value &shouldAnimate) {
layoutAnimationsManager_.setShouldAnimateExiting(
viewTag.asNumber(), shouldAnimate.getBool());
}
bool NativeReanimatedModule::isAnyHandlerWaitingForEvent(
const std::string &eventName,
const int emitterReactTag) {
return eventHandlerRegistry_->isAnyHandlerWaitingForEvent(
eventName, emitterReactTag);
}
void NativeReanimatedModule::requestAnimationFrame(
jsi::Runtime &rt,
const jsi::Value &callback) {
frameCallbacks_.push_back(std::make_shared<jsi::Value>(rt, callback));
maybeRequestRender();
}
void NativeReanimatedModule::maybeRequestRender() {
if (!renderRequested_) {
renderRequested_ = true;
jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
requestRender_(onRenderCallback_, uiRuntime);
}
}
void NativeReanimatedModule::onRender(double timestampMs) {
auto callbacks = std::move(frameCallbacks_);
frameCallbacks_.clear();
jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
jsi::Value timestamp{timestampMs};
for (const auto &callback : callbacks) {
runOnRuntimeGuarded(uiRuntime, *callback, timestamp);
}
}
jsi::Value NativeReanimatedModule::registerSensor(
jsi::Runtime &rt,
const jsi::Value &sensorType,
const jsi::Value &interval,
const jsi::Value &iosReferenceFrame,
const jsi::Value &sensorDataHandler) {
return animatedSensorModule_.registerSensor(
rt,
uiWorkletRuntime_,
sensorType,
interval,
iosReferenceFrame,
sensorDataHandler);
}
void NativeReanimatedModule::unregisterSensor(
jsi::Runtime &,
const jsi::Value &sensorId) {
animatedSensorModule_.unregisterSensor(sensorId);
}
void NativeReanimatedModule::cleanupSensors() {
animatedSensorModule_.unregisterAllSensors();
}
#ifdef RCT_NEW_ARCH_ENABLED
bool NativeReanimatedModule::isThereAnyLayoutProp(
jsi::Runtime &rt,
const jsi::Object &props) {
const jsi::Array propNames = props.getPropertyNames(rt);
for (size_t i = 0; i < propNames.size(rt); ++i) {
const std::string propName =
propNames.getValueAtIndex(rt, i).asString(rt).utf8(rt);
bool isLayoutProp =
nativePropNames_.find(propName) != nativePropNames_.end();
if (isLayoutProp) {
return true;
}
}
return false;
}
jsi::Value NativeReanimatedModule::filterNonAnimatableProps(
jsi::Runtime &rt,
const jsi::Value &props) {
jsi::Object nonAnimatableProps(rt);
bool hasAnyNonAnimatableProp = false;
const jsi::Object &propsObject = props.asObject(rt);
const jsi::Array &propNames = propsObject.getPropertyNames(rt);
for (size_t i = 0; i < propNames.size(rt); ++i) {
const std::string &propName =
propNames.getValueAtIndex(rt, i).asString(rt).utf8(rt);
if (!collection::contains(animatablePropNames_, propName)) {
hasAnyNonAnimatableProp = true;
const auto &propNameStr = propName.c_str();
const jsi::Value &propValue = propsObject.getProperty(rt, propNameStr);
nonAnimatableProps.setProperty(rt, propNameStr, propValue);
}
}
if (!hasAnyNonAnimatableProp) {
return jsi::Value::undefined();
}
return nonAnimatableProps;
}
#endif // RCT_NEW_ARCH_ENABLED
bool NativeReanimatedModule::handleEvent(
const std::string &eventName,
const int emitterReactTag,
const jsi::Value &payload,
double currentTime) {
eventHandlerRegistry_->processEvent(
uiWorkletRuntime_, currentTime, eventName, emitterReactTag, payload);
// TODO: return true if Reanimated successfully handled the event
// to avoid sending it to JavaScript
return false;
}
#ifdef RCT_NEW_ARCH_ENABLED
bool NativeReanimatedModule::handleRawEvent(
const RawEvent &rawEvent,
double currentTime) {
const EventTarget *eventTarget = rawEvent.eventTarget.get();
if (eventTarget == nullptr) {
// after app reload scrollView is unmounted and its content offset is set
// to 0 and view is thrown into recycle pool setting content offset
// triggers scroll event eventTarget is null though, because it's
// unmounting we can just ignore this event, because it's an event on
// unmounted component
return false;
}
int tag = eventTarget->getTag();
auto eventType = rawEvent.type;
if (eventType.rfind("top", 0) == 0) {
eventType = "on" + eventType.substr(3);
}
jsi::Runtime &rt = uiWorkletRuntime_->getJSIRuntime();
#if REACT_NATIVE_MINOR_VERSION >= 73
const auto &eventPayload = rawEvent.eventPayload;
jsi::Value payload = eventPayload->asJSIValue(rt);
#else
const auto &payloadFactory = rawEvent.payloadFactory;
jsi::Value payload = payloadFactory(rt);
#endif
auto res = handleEvent(eventType, tag, std::move(payload), currentTime);
// TODO: we should call performOperations conditionally if event is handled
// (res == true), but for now handleEvent always returns false. Thankfully,
// performOperations does not trigger a lot of code if there is nothing to
// be done so this is fine for now.
performOperations();
return res;
}
void NativeReanimatedModule::updateProps(
jsi::Runtime &rt,
const jsi::Value &operations) {
auto array = operations.asObject(rt).asArray(rt);
size_t length = array.size(rt);
for (size_t i = 0; i < length; ++i) {
auto item = array.getValueAtIndex(rt, i).asObject(rt);
auto shadowNodeWrapper = item.getProperty(rt, "shadowNodeWrapper");
auto shadowNode = shadowNodeFromValue(rt, shadowNodeWrapper);
const jsi::Value &updates = item.getProperty(rt, "updates");
operationsInBatch_.emplace_back(
shadowNode, std::make_unique<jsi::Value>(rt, updates));
// TODO: support multiple surfaces
surfaceId_ = shadowNode->getSurfaceId();
}
}
void NativeReanimatedModule::performOperations() {
if (operationsInBatch_.empty() && tagsToRemove_.empty()) {
// nothing to do
return;
}
auto copiedOperationsQueue = std::move(operationsInBatch_);
operationsInBatch_.clear();
jsi::Runtime &rt = uiWorkletRuntime_->getJSIRuntime();
{
auto lock = propsRegistry_->createLock();
// remove recently unmounted ShadowNodes from PropsRegistry
if (!tagsToRemove_.empty()) {
for (auto tag : tagsToRemove_) {
propsRegistry_->remove(tag);
}
tagsToRemove_.clear();
}
// Even if only non-layout props are changed, we need to store the update
// in PropsRegistry anyway so that React doesn't overwrite it in the next
// render. Currently, only opacity and transform are treated in a special
// way but backgroundColor, shadowOpacity etc. would get overwritten (see
// `_propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN`).
for (const auto &[shadowNode, props] : copiedOperationsQueue) {
propsRegistry_->update(shadowNode, dynamicFromValue(rt, *props));
}
}
for (const auto &[shadowNode, props] : copiedOperationsQueue) {
const jsi::Value &nonAnimatableProps = filterNonAnimatableProps(rt, *props);
if (nonAnimatableProps.isUndefined()) {
continue;
}
Tag viewTag = shadowNode->getTag();
jsi::Value maybeJSPropsUpdater =
rt.global().getProperty(rt, "updateJSProps");
assert(
maybeJSPropsUpdater.isObject() &&
"[Reanimated] `updateJSProps` not found");
jsi::Function jsPropsUpdater =
maybeJSPropsUpdater.asObject(rt).asFunction(rt);
jsPropsUpdater.call(rt, viewTag, nonAnimatableProps);
}
bool hasLayoutUpdates = false;
for (const auto &[shadowNode, props] : copiedOperationsQueue) {
if (isThereAnyLayoutProp(rt, props->asObject(rt))) {
hasLayoutUpdates = true;
break;
}
}
if (!hasLayoutUpdates) {
// If there's no layout props to be updated, we can apply the updates
// directly onto the components and skip the commit.
for (const auto &[shadowNode, props] : copiedOperationsQueue) {
Tag tag = shadowNode->getTag();
synchronouslyUpdateUIPropsFunction_(rt, tag, props->asObject(rt));
}
return;
}
if (propsRegistry_->shouldReanimatedSkipCommit()) {
// It may happen that `performOperations` is called on the UI thread
// while React Native tries to commit a new tree on the JS thread.
// In this case, we should skip the commit here and let React Native do
// it. The commit will include the current values from PropsRegistry which
// will be applied in ReanimatedCommitHook.
return;
}
react_native_assert(uiManager_ != nullptr);
const auto &shadowTreeRegistry = uiManager_->getShadowTreeRegistry();
shadowTreeRegistry.visit(surfaceId_, [&](ShadowTree const &shadowTree) {
// Mark the commit as Reanimated commit so that we can distinguish it
// in ReanimatedCommitHook.
ReanimatedCommitMarker commitMarker;
shadowTree.commit(
[&](RootShadowNode const &oldRootShadowNode)
-> RootShadowNode::Unshared {
auto rootNode =
oldRootShadowNode.ShadowNode::clone(ShadowNodeFragment{});
for (const auto &[shadowNode, props] : copiedOperationsQueue) {
const ShadowNodeFamily &family = shadowNode->getFamily();
react_native_assert(family.getSurfaceId() == surfaceId_);
#if REACT_NATIVE_MINOR_VERSION >= 73
// Fix for catching nullptr returned from commit hook was
// introduced in 0.72.4 but we have only check for minor version
// of React Native so enable that optimization in React Native >=
// 0.73
if (propsRegistry_->shouldReanimatedSkipCommit()) {
return nullptr;
}
#endif
auto newRootNode = cloneShadowTreeWithNewProps(
rootNode, family, RawProps(rt, *props));
if (newRootNode == nullptr) {
// this happens when React removed the component but Reanimated
// still tries to animate it, let's skip update for this
// specific component
continue;
}
rootNode = newRootNode;
}
auto newRoot = std::static_pointer_cast<RootShadowNode>(rootNode);
return newRoot;
},
{ /* .enableStateReconciliation = */
false,
#if REACT_NATIVE_MINOR_VERSION >= 72
/* .mountSynchronously = */ true,
#endif
/* .shouldYield = */ [this]() {
return propsRegistry_->shouldReanimatedSkipCommit();
}
});
});
}
void NativeReanimatedModule::removeFromPropsRegistry(
jsi::Runtime &rt,
const jsi::Value &viewTags) {
auto array = viewTags.asObject(rt).asArray(rt);
for (size_t i = 0, size = array.size(rt); i < size; ++i) {
tagsToRemove_.push_back(array.getValueAtIndex(rt, i).asNumber());
}
}
void NativeReanimatedModule::dispatchCommand(
jsi::Runtime &rt,
const jsi::Value &shadowNodeValue,
const jsi::Value &commandNameValue,
const jsi::Value &argsValue) {
ShadowNode::Shared shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
std::string commandName = stringFromValue(rt, commandNameValue);
folly::dynamic args = commandArgsFromValue(rt, argsValue);
uiManager_->dispatchCommand(shadowNode, commandName, args);
}
jsi::String NativeReanimatedModule::obtainProp(
jsi::Runtime &rt,
const jsi::Value &shadowNodeWrapper,
const jsi::Value &propName) {
jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
const auto propNameStr = propName.asString(rt).utf8(rt);
const auto shadowNode = shadowNodeFromValue(rt, shadowNodeWrapper);
const auto resultStr =
obtainPropFromShadowNode(uiRuntime, propNameStr, shadowNode);
return jsi::String::createFromUtf8(rt, resultStr);
}
jsi::Value NativeReanimatedModule::measure(
jsi::Runtime &rt,
const jsi::Value &shadowNodeValue) {
// based on implementation from UIManagerBinding.cpp
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
auto layoutMetrics = uiManager_->getRelativeLayoutMetrics(
*shadowNode, nullptr, {/* .includeTransform = */ true});
if (layoutMetrics == EmptyLayoutMetrics) {
// Originally, in this case React Native returns `{0, 0, 0, 0, 0, 0}`,
// most likely due to the type of measure callback function which accepts
// just an array of numbers (not null). In Reanimated, `measure` returns
// `MeasuredDimensions | null`.
return jsi::Value::null();
}
auto newestCloneOfShadowNode =
uiManager_->getNewestCloneOfShadowNode(*shadowNode);
auto layoutableShadowNode =
dynamic_cast<LayoutableShadowNode const *>(newestCloneOfShadowNode.get());
facebook::react::Point originRelativeToParent =
layoutableShadowNode != nullptr
? layoutableShadowNode->getLayoutMetrics().frame.origin
: facebook::react::Point();
auto frame = layoutMetrics.frame;
jsi::Object result(rt);
result.setProperty(
rt, "x", jsi::Value(static_cast<double>(originRelativeToParent.x)));
result.setProperty(
rt, "y", jsi::Value(static_cast<double>(originRelativeToParent.y)));
result.setProperty(
rt, "width", jsi::Value(static_cast<double>(frame.size.width)));
result.setProperty(
rt, "height", jsi::Value(static_cast<double>(frame.size.height)));
result.setProperty(
rt, "pageX", jsi::Value(static_cast<double>(frame.origin.x)));
result.setProperty(
rt, "pageY", jsi::Value(static_cast<double>(frame.origin.y)));
return result;
}
void NativeReanimatedModule::initializeFabric(
const std::shared_ptr<UIManager> &uiManager) {
uiManager_ = uiManager;
commitHook_ =
std::make_shared<ReanimatedCommitHook>(propsRegistry_, uiManager_);
#if REACT_NATIVE_MINOR_VERSION >= 73
mountHook_ =
std::make_shared<ReanimatedMountHook>(propsRegistry_, uiManager_);
#endif
}
#endif // RCT_NEW_ARCH_ENABLED
jsi::Value NativeReanimatedModule::subscribeForKeyboardEvents(
jsi::Runtime &rt,
const jsi::Value &handlerWorklet,
const jsi::Value &isStatusBarTranslucent) {
auto shareableHandler = extractShareableOrThrow<ShareableWorklet>(
rt,
handlerWorklet,
"[Reanimated] Keyboard event handler must be a worklet.");
return subscribeForKeyboardEventsFunction_(
[=](int keyboardState, int height) {
uiWorkletRuntime_->runGuarded(
shareableHandler, jsi::Value(keyboardState), jsi::Value(height));
},
isStatusBarTranslucent.getBool());
}
void NativeReanimatedModule::unsubscribeFromKeyboardEvents(
jsi::Runtime &,
const jsi::Value &listenerId) {
unsubscribeFromKeyboardEventsFunction_(listenerId.asNumber());
}
} // namespace reanimated

View File

@@ -0,0 +1,239 @@
#pragma once
#ifdef RCT_NEW_ARCH_ENABLED
#include <react/renderer/uimanager/UIManager.h>
#endif
#include <memory>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include "AnimatedSensorModule.h"
#include "EventHandlerRegistry.h"
#include "JSScheduler.h"
#include "LayoutAnimationsManager.h"
#include "NativeReanimatedModuleSpec.h"
#include "PlatformDepMethodsHolder.h"
#include "SingleInstanceChecker.h"
#include "UIScheduler.h"
#ifdef RCT_NEW_ARCH_ENABLED
#include "PropsRegistry.h"
#include "ReanimatedCommitHook.h"
#if REACT_NATIVE_MINOR_VERSION >= 73
#include "ReanimatedMountHook.h"
#endif
#endif
namespace reanimated {
class NativeReanimatedModule : public NativeReanimatedModuleSpec {
public:
NativeReanimatedModule(
jsi::Runtime &rnRuntime,
const std::shared_ptr<JSScheduler> &jsScheduler,
const std::shared_ptr<MessageQueueThread> &jsQueue,
const std::shared_ptr<UIScheduler> &uiScheduler,
const PlatformDepMethodsHolder &platformDepMethodsHolder,
const std::string &valueUnpackerCode,
const bool isBridgeless);
~NativeReanimatedModule();
jsi::Value makeShareableClone(
jsi::Runtime &rt,
const jsi::Value &value,
const jsi::Value &shouldRetainRemote,
const jsi::Value &nativeStateSource) override;
void scheduleOnUI(jsi::Runtime &rt, const jsi::Value &worklet) override;
jsi::Value executeOnUIRuntimeSync(jsi::Runtime &rt, const jsi::Value &worklet)
override;
jsi::Value createWorkletRuntime(
jsi::Runtime &rt,
const jsi::Value &name,
const jsi::Value &initializer) override;
jsi::Value scheduleOnRuntime(
jsi::Runtime &rt,
const jsi::Value &workletRuntimeValue,
const jsi::Value &shareableWorkletValue) override;
jsi::Value registerEventHandler(
jsi::Runtime &rt,
const jsi::Value &worklet,
const jsi::Value &eventName,
const jsi::Value &emitterReactTag) override;
void unregisterEventHandler(
jsi::Runtime &rt,
const jsi::Value &registrationId) override;
jsi::Value getViewProp(
jsi::Runtime &rt,
#ifdef RCT_NEW_ARCH_ENABLED
const jsi::Value &shadowNodeWrapper,
#else
const jsi::Value &viewTag,
#endif
const jsi::Value &propName,
const jsi::Value &callback) override;
jsi::Value enableLayoutAnimations(jsi::Runtime &rt, const jsi::Value &config)
override;
jsi::Value configureProps(
jsi::Runtime &rt,
const jsi::Value &uiProps,
const jsi::Value &nativeProps) override;
jsi::Value configureLayoutAnimationBatch(
jsi::Runtime &rt,
const jsi::Value &layoutAnimationsBatch) override;
void setShouldAnimateExiting(
jsi::Runtime &rt,
const jsi::Value &viewTag,
const jsi::Value &shouldAnimate) override;
void onRender(double timestampMs);
bool isAnyHandlerWaitingForEvent(
const std::string &eventName,
const int emitterReactTag);
void maybeRequestRender();
bool handleEvent(
const std::string &eventName,
const int emitterReactTag,
const jsi::Value &payload,
double currentTime);
inline std::shared_ptr<JSLogger> getJSLogger() const {
return jsLogger_;
}
#ifdef RCT_NEW_ARCH_ENABLED
bool handleRawEvent(const RawEvent &rawEvent, double currentTime);
void updateProps(jsi::Runtime &rt, const jsi::Value &operations);
void removeFromPropsRegistry(jsi::Runtime &rt, const jsi::Value &viewTags);
void performOperations();
void dispatchCommand(
jsi::Runtime &rt,
const jsi::Value &shadowNodeValue,
const jsi::Value &commandNameValue,
const jsi::Value &argsValue);
jsi::String obtainProp(
jsi::Runtime &rt,
const jsi::Value &shadowNodeWrapper,
const jsi::Value &propName);
jsi::Value measure(jsi::Runtime &rt, const jsi::Value &shadowNodeValue);
void initializeFabric(const std::shared_ptr<UIManager> &uiManager);
std::string obtainPropFromShadowNode(
jsi::Runtime &rt,
const std::string &propName,
const ShadowNode::Shared &shadowNode);
#endif
jsi::Value registerSensor(
jsi::Runtime &rt,
const jsi::Value &sensorType,
const jsi::Value &interval,
const jsi::Value &iosReferenceFrame,
const jsi::Value &sensorDataContainer) override;
void unregisterSensor(jsi::Runtime &rt, const jsi::Value &sensorId) override;
void cleanupSensors();
jsi::Value subscribeForKeyboardEvents(
jsi::Runtime &rt,
const jsi::Value &keyboardEventContainer,
const jsi::Value &isStatusBarTranslucent) override;
void unsubscribeFromKeyboardEvents(
jsi::Runtime &rt,
const jsi::Value &listenerId) override;
inline LayoutAnimationsManager &layoutAnimationsManager() {
return layoutAnimationsManager_;
}
inline jsi::Runtime &getUIRuntime() {
return uiWorkletRuntime_->getJSIRuntime();
}
inline bool isBridgeless() const {
return isBridgeless_;
}
private:
void commonInit(const PlatformDepMethodsHolder &platformDepMethodsHolder);
void requestAnimationFrame(jsi::Runtime &rt, const jsi::Value &callback);
#ifdef RCT_NEW_ARCH_ENABLED
bool isThereAnyLayoutProp(jsi::Runtime &rt, const jsi::Object &props);
jsi::Value filterNonAnimatableProps(
jsi::Runtime &rt,
const jsi::Value &props);
#endif // RCT_NEW_ARCH_ENABLED
const bool isBridgeless_;
const std::shared_ptr<MessageQueueThread> jsQueue_;
const std::shared_ptr<JSScheduler> jsScheduler_;
const std::shared_ptr<UIScheduler> uiScheduler_;
std::shared_ptr<WorkletRuntime> uiWorkletRuntime_;
std::string valueUnpackerCode_;
std::unique_ptr<EventHandlerRegistry> eventHandlerRegistry_;
const RequestRenderFunction requestRender_;
std::vector<std::shared_ptr<jsi::Value>> frameCallbacks_;
volatile bool renderRequested_{false};
const std::function<void(const double)> onRenderCallback_;
AnimatedSensorModule animatedSensorModule_;
const std::shared_ptr<JSLogger> jsLogger_;
LayoutAnimationsManager layoutAnimationsManager_;
#ifdef RCT_NEW_ARCH_ENABLED
const SynchronouslyUpdateUIPropsFunction synchronouslyUpdateUIPropsFunction_;
std::unordered_set<std::string> nativePropNames_; // filled by configureProps
std::unordered_set<std::string>
animatablePropNames_; // filled by configureProps
std::shared_ptr<UIManager> uiManager_;
// After app reload, surfaceId on iOS is still 1 but on Android it's 11.
// We can store surfaceId of the most recent ShadowNode as a workaround.
SurfaceId surfaceId_ = -1;
std::vector<std::pair<ShadowNode::Shared, std::unique_ptr<jsi::Value>>>
operationsInBatch_; // TODO: refactor std::pair to custom struct
std::shared_ptr<PropsRegistry> propsRegistry_;
std::shared_ptr<ReanimatedCommitHook> commitHook_;
#if REACT_NATIVE_MINOR_VERSION >= 73
std::shared_ptr<ReanimatedMountHook> mountHook_;
#endif
std::vector<Tag> tagsToRemove_; // from `propsRegistry_`
#else
const ObtainPropFunction obtainPropFunction_;
const ConfigurePropsFunction configurePropsPlatformFunction_;
const UpdatePropsFunction updatePropsFunction_;
#endif
const KeyboardEventSubscribeFunction subscribeForKeyboardEventsFunction_;
const KeyboardEventUnsubscribeFunction unsubscribeFromKeyboardEventsFunction_;
#ifndef NDEBUG
SingleInstanceChecker<NativeReanimatedModule> singleInstanceChecker_;
#endif
};
} // namespace reanimated

View File

@@ -0,0 +1,209 @@
#include "NativeReanimatedModuleSpec.h"
#include <utility>
#define SPEC_PREFIX(FN_NAME) __hostFunction_NativeReanimatedModuleSpec_##FN_NAME
namespace reanimated {
// SharedValue
static jsi::Value SPEC_PREFIX(makeShareableClone)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->makeShareableClone(
rt, std::move(args[0]), std::move(args[1]), std::move(args[2]));
}
// scheduler
static jsi::Value SPEC_PREFIX(scheduleOnUI)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->scheduleOnUI(rt, std::move(args[0]));
return jsi::Value::undefined();
}
static jsi::Value SPEC_PREFIX(executeOnUIRuntimeSync)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->executeOnUIRuntimeSync(rt, std::move(args[0]));
}
static jsi::Value SPEC_PREFIX(createWorkletRuntime)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->createWorkletRuntime(rt, std::move(args[0]), std::move(args[1]));
}
static jsi::Value SPEC_PREFIX(scheduleOnRuntime)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->scheduleOnRuntime(rt, std::move(args[0]), std::move(args[1]));
}
static jsi::Value SPEC_PREFIX(registerEventHandler)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->registerEventHandler(
rt, std::move(args[0]), std::move(args[1]), std::move(args[2]));
}
static jsi::Value SPEC_PREFIX(unregisterEventHandler)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->unregisterEventHandler(rt, std::move(args[0]));
return jsi::Value::undefined();
}
static jsi::Value SPEC_PREFIX(getViewProp)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->getViewProp(
rt, std::move(args[0]), std::move(args[1]), std::move(args[2]));
return jsi::Value::undefined();
}
static jsi::Value SPEC_PREFIX(enableLayoutAnimations)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->enableLayoutAnimations(rt, std::move(args[0]));
return jsi::Value::undefined();
}
static jsi::Value SPEC_PREFIX(registerSensor)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->registerSensor(
rt,
std::move(args[0]),
std::move(args[1]),
std::move(args[2]),
std::move(args[3]));
}
static jsi::Value SPEC_PREFIX(unregisterSensor)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->unregisterSensor(rt, std::move(args[0]));
return jsi::Value::undefined();
}
static jsi::Value SPEC_PREFIX(configureProps)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->configureProps(rt, std::move(args[0]), std::move(args[1]));
return jsi::Value::undefined();
}
static jsi::Value SPEC_PREFIX(subscribeForKeyboardEvents)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->subscribeForKeyboardEvents(rt, std::move(args[0]), std::move(args[1]));
}
static jsi::Value SPEC_PREFIX(unsubscribeFromKeyboardEvents)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->unsubscribeFromKeyboardEvents(rt, std::move(args[0]));
return jsi::Value::undefined();
}
static jsi::Value SPEC_PREFIX(configureLayoutAnimationBatch)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->configureLayoutAnimationBatch(rt, std::move(args[0]));
}
static jsi::Value SPEC_PREFIX(setShouldAnimateExiting)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->setShouldAnimateExiting(rt, std::move(args[0]), std::move(args[1]));
return jsi::Value::undefined();
}
NativeReanimatedModuleSpec::NativeReanimatedModuleSpec(
const std::shared_ptr<CallInvoker> &jsInvoker)
: TurboModule("NativeReanimated", jsInvoker) {
methodMap_["makeShareableClone"] =
MethodMetadata{2, SPEC_PREFIX(makeShareableClone)};
methodMap_["scheduleOnUI"] = MethodMetadata{1, SPEC_PREFIX(scheduleOnUI)};
methodMap_["executeOnUIRuntimeSync"] =
MethodMetadata{1, SPEC_PREFIX(executeOnUIRuntimeSync)};
methodMap_["createWorkletRuntime"] =
MethodMetadata{2, SPEC_PREFIX(createWorkletRuntime)};
methodMap_["scheduleOnRuntime"] =
MethodMetadata{2, SPEC_PREFIX(scheduleOnRuntime)};
methodMap_["registerEventHandler"] =
MethodMetadata{3, SPEC_PREFIX(registerEventHandler)};
methodMap_["unregisterEventHandler"] =
MethodMetadata{1, SPEC_PREFIX(unregisterEventHandler)};
methodMap_["getViewProp"] = MethodMetadata{3, SPEC_PREFIX(getViewProp)};
methodMap_["enableLayoutAnimations"] =
MethodMetadata{2, SPEC_PREFIX(enableLayoutAnimations)};
methodMap_["registerSensor"] = MethodMetadata{4, SPEC_PREFIX(registerSensor)};
methodMap_["unregisterSensor"] =
MethodMetadata{1, SPEC_PREFIX(unregisterSensor)};
methodMap_["configureProps"] = MethodMetadata{2, SPEC_PREFIX(configureProps)};
methodMap_["subscribeForKeyboardEvents"] =
MethodMetadata{2, SPEC_PREFIX(subscribeForKeyboardEvents)};
methodMap_["unsubscribeFromKeyboardEvents"] =
MethodMetadata{1, SPEC_PREFIX(unsubscribeFromKeyboardEvents)};
methodMap_["configureLayoutAnimationBatch"] =
MethodMetadata{1, SPEC_PREFIX(configureLayoutAnimationBatch)};
methodMap_["setShouldAnimateExitingForTag"] =
MethodMetadata{2, SPEC_PREFIX(setShouldAnimateExiting)};
}
} // namespace reanimated

View File

@@ -0,0 +1,110 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
#ifdef ANDROID
#include "TurboModule.h"
#else
#include <ReactCommon/TurboModule.h>
#endif
#include <ReactCommon/CallInvoker.h>
using namespace facebook;
using namespace react;
namespace reanimated {
class JSI_EXPORT NativeReanimatedModuleSpec : public TurboModule {
protected:
explicit NativeReanimatedModuleSpec(
const std::shared_ptr<CallInvoker> &jsInvoker);
public:
// SharedValue
virtual jsi::Value makeShareableClone(
jsi::Runtime &rt,
const jsi::Value &value,
const jsi::Value &shouldRetainRemote,
const jsi::Value &nativeStateSource) = 0;
// Scheduling
virtual void scheduleOnUI(jsi::Runtime &rt, const jsi::Value &worklet) = 0;
virtual jsi::Value executeOnUIRuntimeSync(
jsi::Runtime &rt,
const jsi::Value &worklet) = 0;
// Worklet runtime
virtual jsi::Value createWorkletRuntime(
jsi::Runtime &rt,
const jsi::Value &name,
const jsi::Value &initializer) = 0;
virtual jsi::Value scheduleOnRuntime(
jsi::Runtime &rt,
const jsi::Value &workletRuntimeValue,
const jsi::Value &shareableWorkletValue) = 0;
// events
virtual jsi::Value registerEventHandler(
jsi::Runtime &rt,
const jsi::Value &worklet,
const jsi::Value &eventName,
const jsi::Value &emitterReactTag) = 0;
virtual void unregisterEventHandler(
jsi::Runtime &rt,
const jsi::Value &registrationId) = 0;
// views
virtual jsi::Value getViewProp(
jsi::Runtime &rt,
#ifdef RCT_NEW_ARCH_ENABLED
const jsi::Value &shadowNodeWrapper,
#else
const jsi::Value &viewTag,
#endif
const jsi::Value &propName,
const jsi::Value &callback) = 0;
// sensors
virtual jsi::Value registerSensor(
jsi::Runtime &rt,
const jsi::Value &sensorType,
const jsi::Value &interval,
const jsi::Value &iosReferenceFrame,
const jsi::Value &sensorDataContainer) = 0;
virtual void unregisterSensor(
jsi::Runtime &rt,
const jsi::Value &sensorId) = 0;
// keyboard
virtual jsi::Value subscribeForKeyboardEvents(
jsi::Runtime &rt,
const jsi::Value &keyboardEventContainer,
const jsi::Value &isStatusBarTranslucent) = 0;
virtual void unsubscribeFromKeyboardEvents(
jsi::Runtime &rt,
const jsi::Value &listenerId) = 0;
// other
virtual jsi::Value enableLayoutAnimations(
jsi::Runtime &rt,
const jsi::Value &config) = 0;
virtual jsi::Value configureProps(
jsi::Runtime &rt,
const jsi::Value &uiProps,
const jsi::Value &nativeProps) = 0;
// layout animations
virtual jsi::Value configureLayoutAnimationBatch(
jsi::Runtime &rt,
const jsi::Value &layoutAnimationsBatch) = 0;
virtual void setShouldAnimateExiting(
jsi::Runtime &rt,
const jsi::Value &viewTag,
const jsi::Value &shouldAnimate) = 0;
};
} // namespace reanimated