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,24 @@
#import <Foundation/Foundation.h>
#import <RNReanimated/RNGestureHandlerStateManager.h>
#import <React/RCTUIManager.h>
#include <string>
#include <utility>
#include <vector>
namespace reanimated {
std::vector<std::pair<std::string, double>> measure(
int viewTag,
RCTUIManager *uiManager);
void scrollTo(
int scrollViewTag,
RCTUIManager *uiManager,
double x,
double y,
bool animated);
void setGestureState(
id<RNGestureHandlerStateManager> gestureHandlerStateManager,
int handlerTag,
int newState);
} // namespace reanimated

View File

@@ -0,0 +1,53 @@
#import <RNReanimated/NativeMethods.h>
#import <RNReanimated/REAUIKit.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTScrollView.h>
namespace reanimated {
std::vector<std::pair<std::string, double>> measure(int viewTag, RCTUIManager *uiManager)
{
REAUIView *view = [uiManager viewForReactTag:@(viewTag)];
REAUIView *rootView = view;
if (view == nil) {
return std::vector<std::pair<std::string, double>>(1, std::make_pair("x", -1234567.0));
}
while (rootView.superview && ![rootView isReactRootView]) {
rootView = rootView.superview;
}
if (rootView == nil) {
return std::vector<std::pair<std::string, double>>(1, std::make_pair("x", -1234567.0));
}
CGRect frame = view.frame;
CGRect globalBounds = [view convertRect:view.bounds toView:rootView];
return {
{"x", frame.origin.x},
{"y", frame.origin.y},
{"width", globalBounds.size.width},
{"height", globalBounds.size.height},
{"pageX", globalBounds.origin.x},
{"pageY", globalBounds.origin.y},
};
}
void scrollTo(int scrollViewTag, RCTUIManager *uiManager, double x, double y, bool animated)
{
REAUIView *view = [uiManager viewForReactTag:@(scrollViewTag)];
RCTScrollView *scrollView = (RCTScrollView *)view;
[scrollView scrollToOffset:(CGPoint){(CGFloat)x, (CGFloat)y} animated:animated];
}
void setGestureState(id<RNGestureHandlerStateManager> gestureHandlerStateManager, int handlerTag, int newState)
{
if (gestureHandlerStateManager != nil) {
[gestureHandlerStateManager setGestureState:newState forHandler:handlerTag];
}
}
} // namespace reanimated

View File

@@ -0,0 +1,42 @@
#if __cplusplus
#import <REAAnimationsManager.h>
#import <REAKeyboardEventObserver.h>
#import <REAModule.h>
#import <REANodesManager.h>
#import <RNReanimated/NativeReanimatedModule.h>
#import <React/RCTEventDispatcher.h>
#import <ReanimatedSensorContainer.h>
#include <memory>
namespace reanimated {
std::shared_ptr<reanimated::NativeReanimatedModule> createReanimatedModule(
RCTBridge *bridge,
const std::shared_ptr<facebook::react::CallInvoker> &jsInvoker,
const std::string &valueUnpackerCode);
#if REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED)
std::shared_ptr<reanimated::NativeReanimatedModule>
createReanimatedModuleBridgeless(
RCTModuleRegistry *moduleRegistry,
jsi::Runtime &runtime,
const std::string &valueUnpackerCode,
RuntimeExecutor runtimeExecutor);
#endif // REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED)
void commonInit(
REAModule *reaModule,
std::shared_ptr<NativeReanimatedModule> nativeReanimatedModule);
#ifdef RCT_NEW_ARCH_ENABLED
// nothing
#else // RCT_NEW_ARCH_ENABLED
void setupLayoutAnimationCallbacks(
std::shared_ptr<NativeReanimatedModule> nativeReanimatedModule,
REAAnimationsManager *animationsManager);
#endif // RCT_NEW_ARCH_ENABLED
} // namespace reanimated
#endif //__cplusplus

View File

@@ -0,0 +1,227 @@
#import <RNReanimated/LayoutAnimationsManager.h>
#import <RNReanimated/NativeMethods.h>
#import <RNReanimated/NativeProxy.h>
#import <RNReanimated/PlatformDepMethodsHolder.h>
#import <RNReanimated/PlatformDepMethodsHolderImpl.h>
#import <RNReanimated/REAAnimationsManager.h>
#import <RNReanimated/REAIOSUIScheduler.h>
#import <RNReanimated/REAJSIUtils.h>
#import <RNReanimated/REAKeyboardEventObserver.h>
#import <RNReanimated/REAMessageThread.h>
#import <RNReanimated/REAModule.h>
#import <RNReanimated/REANodesManager.h>
#import <RNReanimated/REASlowAnimations.h>
#import <RNReanimated/REASwizzledUIManager.h>
#import <RNReanimated/RNGestureHandlerStateManager.h>
#import <RNReanimated/ReanimatedRuntime.h>
#import <RNReanimated/ReanimatedSensorContainer.h>
#ifndef NDEBUG
#import <RNReanimated/REAScreensHelper.h>
#endif
#ifdef RCT_NEW_ARCH_ENABLED
#import <React/RCTBridge+Private.h>
#import <React/RCTScheduler.h>
#import <React/RCTSurfacePresenter.h>
#import <react/renderer/core/ShadowNode.h>
#import <react/renderer/uimanager/primitives.h>
#endif
#import <React/RCTUIManager.h>
#if TARGET_IPHONE_SIMULATOR
#import <dlfcn.h>
#endif
#import <RNReanimated/READisplayLink.h>
@interface RCTBridge (JSIRuntime)
- (void *)runtime;
@end
namespace reanimated {
using namespace facebook;
using namespace react;
std::shared_ptr<NativeReanimatedModule> createReanimatedModule(
RCTBridge *bridge,
const std::shared_ptr<CallInvoker> &jsInvoker,
const std::string &valueUnpackerCode)
{
REAModule *reaModule = [bridge moduleForClass:[REAModule class]];
auto nodesManager = reaModule.nodesManager;
jsi::Runtime &rnRuntime = *reinterpret_cast<facebook::jsi::Runtime *>(reaModule.bridge.runtime);
auto jsQueue = std::make_shared<REAMessageThread>([NSRunLoop currentRunLoop], ^(NSError *error) {
throw error;
});
PlatformDepMethodsHolder platformDepMethodsHolder = makePlatformDepMethodsHolder(bridge, nodesManager, reaModule);
std::shared_ptr<UIScheduler> uiScheduler = std::make_shared<REAIOSUIScheduler>();
std::shared_ptr<JSScheduler> jsScheduler = std::make_shared<JSScheduler>(rnRuntime, jsInvoker);
constexpr bool isBridgeless = false;
auto nativeReanimatedModule = std::make_shared<NativeReanimatedModule>(
rnRuntime, jsScheduler, jsQueue, uiScheduler, platformDepMethodsHolder, valueUnpackerCode, isBridgeless);
commonInit(reaModule, nativeReanimatedModule);
// Layout Animation callbacks setup
#ifdef RCT_NEW_ARCH_ENABLED
// nothing
#else
REAAnimationsManager *animationsManager = reaModule.animationsManager;
setupLayoutAnimationCallbacks(nativeReanimatedModule, animationsManager);
#endif // RCT_NEW_ARCH_ENABLED
return nativeReanimatedModule;
}
#if REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED)
std::shared_ptr<NativeReanimatedModule> createReanimatedModuleBridgeless(
RCTModuleRegistry *moduleRegistry,
jsi::Runtime &runtime,
const std::string &valueUnpackerCode,
RuntimeExecutor runtimeExecutor)
{
REAModule *reaModule = [moduleRegistry moduleForName:"ReanimatedModule"];
auto nodesManager = reaModule.nodesManager;
auto jsQueue = std::make_shared<REAMessageThread>([NSRunLoop currentRunLoop], ^(NSError *error) {
throw error;
});
PlatformDepMethodsHolder platformDepMethodsHolder =
makePlatformDepMethodsHolderBridgeless(moduleRegistry, nodesManager, reaModule);
auto uiScheduler = std::make_shared<REAIOSUIScheduler>();
auto jsScheduler = std::make_shared<JSScheduler>(runtime, runtimeExecutor);
constexpr bool isBridgeless = true;
auto nativeReanimatedModule = std::make_shared<NativeReanimatedModule>(
runtime, jsScheduler, jsQueue, uiScheduler, platformDepMethodsHolder, valueUnpackerCode, isBridgeless);
commonInit(reaModule, nativeReanimatedModule);
return nativeReanimatedModule;
}
#endif // REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED)
void commonInit(REAModule *reaModule, std::shared_ptr<NativeReanimatedModule> nativeReanimatedModule)
{
[reaModule.nodesManager registerEventHandler:^(id<RCTEvent> event) {
// handles RCTEvents from RNGestureHandler
std::string eventName = [event.eventName UTF8String];
int emitterReactTag = [event.viewTag intValue];
id eventData = [event arguments][2];
jsi::Runtime &uiRuntime = nativeReanimatedModule->getUIRuntime();
jsi::Value payload = convertObjCObjectToJSIValue(uiRuntime, eventData);
double currentTime = CACurrentMediaTime() * 1000;
nativeReanimatedModule->handleEvent(eventName, emitterReactTag, payload, currentTime);
}];
#ifdef RCT_NEW_ARCH_ENABLED
std::weak_ptr<NativeReanimatedModule> weakNativeReanimatedModule = nativeReanimatedModule; // to avoid retain cycle
[reaModule.nodesManager registerPerformOperations:^() {
if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
nativeReanimatedModule->performOperations();
}
}];
#endif // RCT_NEW_ARCH_ENABLED
}
#ifdef RCT_NEW_ARCH_ENABLED
// nothing
#else // RCT_NEW_ARCH_ENABLED
void setupLayoutAnimationCallbacks(
std::shared_ptr<NativeReanimatedModule> nativeReanimatedModule,
REAAnimationsManager *animationsManager)
{
std::weak_ptr<NativeReanimatedModule> weakNativeReanimatedModule = nativeReanimatedModule; // to avoid retain cycle
[animationsManager
setAnimationStartingBlock:^(NSNumber *_Nonnull tag, LayoutAnimationType type, NSDictionary *_Nonnull values) {
if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
jsi::Runtime &rt = nativeReanimatedModule->getUIRuntime();
jsi::Object yogaValues(rt);
for (NSString *key in values.allKeys) {
NSObject *value = values[key];
if ([values[key] isKindOfClass:[NSArray class]]) {
NSArray *transformArray = (NSArray *)value;
jsi::Array matrix(rt, 9);
for (int i = 0; i < 9; i++) {
matrix.setValueAtIndex(rt, i, [(NSNumber *)transformArray[i] doubleValue]);
}
yogaValues.setProperty(rt, [key UTF8String], matrix);
} else {
yogaValues.setProperty(rt, [key UTF8String], [(NSNumber *)value doubleValue]);
}
}
nativeReanimatedModule->layoutAnimationsManager().startLayoutAnimation(rt, [tag intValue], type, yogaValues);
}
}];
[animationsManager setHasAnimationBlock:^(NSNumber *_Nonnull tag, LayoutAnimationType type) {
if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
bool hasLayoutAnimation =
nativeReanimatedModule->layoutAnimationsManager().hasLayoutAnimation([tag intValue], type);
return hasLayoutAnimation ? YES : NO;
}
return NO;
}];
[animationsManager setShouldAnimateExitingBlock:^(NSNumber *_Nonnull tag, BOOL shouldAnimate) {
if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
bool shouldAnimateExiting =
nativeReanimatedModule->layoutAnimationsManager().shouldAnimateExiting([tag intValue], shouldAnimate);
return shouldAnimateExiting ? YES : NO;
}
return NO;
}];
[animationsManager setAnimationRemovingBlock:^(NSNumber *_Nonnull tag) {
if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
nativeReanimatedModule->layoutAnimationsManager().clearLayoutAnimationConfig([tag intValue]);
}
}];
[animationsManager setSharedTransitionRemovingBlock:^(NSNumber *_Nonnull tag) {
if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
nativeReanimatedModule->layoutAnimationsManager().clearSharedTransitionConfig([tag intValue]);
}
}];
[animationsManager setCancelAnimationBlock:^(NSNumber *_Nonnull tag) {
if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
jsi::Runtime &rt = nativeReanimatedModule->getUIRuntime();
nativeReanimatedModule->layoutAnimationsManager().cancelLayoutAnimation(rt, [tag intValue]);
}
}];
[animationsManager setFindPrecedingViewTagForTransitionBlock:^NSNumber *_Nullable(NSNumber *_Nonnull tag) {
if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
int resultTag =
nativeReanimatedModule->layoutAnimationsManager().findPrecedingViewTagForTransition([tag intValue]);
return resultTag == -1 ? nil : @(resultTag);
}
return nil;
}];
#ifndef NDEBUG
[animationsManager setCheckDuplicateSharedTagBlock:^(REAUIView *view, NSNumber *_Nonnull viewTag) {
if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
REAUIView *screen = [REAScreensHelper getScreenForView:(REAUIView *)view];
auto screenTag = [screen.reactTag intValue];
// Here we check if there are duplicate tags (we don't use return bool value currently)
nativeReanimatedModule->layoutAnimationsManager().checkDuplicateSharedTag([viewTag intValue], screenTag);
}
}];
#endif // NDEBUG
}
#endif // RCT_NEW_ARCH_ENABLED
} // namespace reanimated

View File

@@ -0,0 +1,59 @@
#if __cplusplus
#import <REAAnimationsManager.h>
#import <REAKeyboardEventObserver.h>
#import <REAModule.h>
#import <REANodesManager.h>
#import <RNReanimated/NativeReanimatedModule.h>
#import <React/RCTEventDispatcher.h>
#import <ReanimatedSensorContainer.h>
#include <memory>
namespace reanimated {
PlatformDepMethodsHolder makePlatformDepMethodsHolder(
RCTBridge *bridge,
REANodesManager *nodesManager,
REAModule *reaModule);
#if REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED)
PlatformDepMethodsHolder makePlatformDepMethodsHolderBridgeless(
RCTModuleRegistry *moduleRegistry,
REANodesManager *nodesManager,
REAModule *reaModule);
SetGestureStateFunction makeSetGestureStateFunctionBridgeless(
RCTModuleRegistry *moduleRegistry);
#endif // REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED)
#ifdef RCT_NEW_ARCH_ENABLED
SynchronouslyUpdateUIPropsFunction makeSynchronouslyUpdateUIPropsFunction(
REANodesManager *nodesManager);
#else // RCT_NEW_ARCH_ENABLED
UpdatePropsFunction makeUpdatePropsFunction(REAModule *reaModule);
MeasureFunction makeMeasureFunction(RCTUIManager *uiManager);
ScrollToFunction makeScrollToFunction(RCTUIManager *uiManager);
DispatchCommandFunction makeDispatchCommandFunction(RCTUIManager *uiManager);
ConfigurePropsFunction makeConfigurePropsFunction(REAModule *reaModule);
ObtainPropFunction makeObtainPropFunction(REAModule *reaModule);
#endif // RCT_NEW_ARCH_ENABLED
SetGestureStateFunction makeSetGestureStateFunction(RCTBridge *bridge);
RequestRenderFunction makeRequestRender(REANodesManager *nodesManager);
GetAnimationTimestampFunction makeGetAnimationTimestamp();
ProgressLayoutAnimationFunction makeProgressLayoutAnimation(
REAModule *reaModule);
EndLayoutAnimationFunction makeEndLayoutAnimation(REAModule *reaModule);
MaybeFlushUIUpdatesQueueFunction makeMaybeFlushUIUpdatesQueueFunction(
REANodesManager *nodesManager);
RegisterSensorFunction makeRegisterSensorFunction(
ReanimatedSensorContainer *reanimatedSensorContainer);
UnregisterSensorFunction makeUnregisterSensorFunction(
ReanimatedSensorContainer *reanimatedSensorContainer);
KeyboardEventSubscribeFunction makeSubscribeForKeyboardEventsFunction(
REAKeyboardEventObserver *keyboardObserver);
KeyboardEventUnsubscribeFunction makeUnsubscribeFromKeyboardEventsFunction(
REAKeyboardEventObserver *keyboardObserver);
} // namespace reanimated
#endif //__cplusplus

View File

@@ -0,0 +1,429 @@
#import <RNReanimated/LayoutAnimationsManager.h>
#import <RNReanimated/NativeMethods.h>
#import <RNReanimated/NativeProxy.h>
#import <RNReanimated/PlatformDepMethodsHolder.h>
#import <RNReanimated/REAAnimationsManager.h>
#import <RNReanimated/REAIOSUIScheduler.h>
#import <RNReanimated/REAJSIUtils.h>
#import <RNReanimated/REAKeyboardEventObserver.h>
#import <RNReanimated/REAMessageThread.h>
#import <RNReanimated/REAModule.h>
#import <RNReanimated/REANodesManager.h>
#import <RNReanimated/REASlowAnimations.h>
#import <RNReanimated/REASwizzledUIManager.h>
#import <RNReanimated/RNGestureHandlerStateManager.h>
#import <RNReanimated/ReanimatedRuntime.h>
#import <RNReanimated/ReanimatedSensorContainer.h>
#ifndef NDEBUG
#import <RNReanimated/REAScreensHelper.h>
#endif
#ifdef RCT_NEW_ARCH_ENABLED
#import <React/RCTBridge+Private.h>
#import <React/RCTScheduler.h>
#import <React/RCTSurfacePresenter.h>
#import <react/renderer/core/ShadowNode.h>
#import <react/renderer/uimanager/primitives.h>
#endif
#import <React/RCTUIManager.h>
#if TARGET_IPHONE_SIMULATOR
#import <dlfcn.h>
#endif
#import <RNReanimated/READisplayLink.h>
@interface RCTUIManager (DispatchCommand)
- (void)dispatchViewManagerCommand:(nonnull NSNumber *)reactTag
commandID:(id /*(NSString or NSNumber) */)commandID
commandArgs:(NSArray<id> *)commandArgs;
@end
namespace reanimated {
using namespace facebook;
using namespace react;
static NSSet *convertProps(jsi::Runtime &rt, const jsi::Value &props)
{
NSMutableSet *propsSet = [[NSMutableSet alloc] init];
jsi::Array propsNames = props.asObject(rt).asArray(rt);
for (int i = 0; i < propsNames.size(rt); i++) {
NSString *propName = @(propsNames.getValueAtIndex(rt, i).asString(rt).utf8(rt).c_str());
[propsSet addObject:propName];
}
return propsSet;
}
SetGestureStateFunction makeSetGestureStateFunction(RCTBridge *bridge)
{
id<RNGestureHandlerStateManager> gestureHandlerStateManager = nil;
auto setGestureStateFunction = [gestureHandlerStateManager, bridge](int handlerTag, int newState) mutable {
if (gestureHandlerStateManager == nil) {
gestureHandlerStateManager = [bridge moduleForName:@"RNGestureHandlerModule"];
}
setGestureState(gestureHandlerStateManager, handlerTag, newState);
};
return setGestureStateFunction;
}
#if REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED)
SetGestureStateFunction makeSetGestureStateFunctionBridgeless(RCTModuleRegistry *moduleRegistry)
{
id<RNGestureHandlerStateManager> gestureHandlerStateManager = nil;
auto setGestureStateFunction = [gestureHandlerStateManager, moduleRegistry](int handlerTag, int newState) mutable {
if (gestureHandlerStateManager == nil) {
gestureHandlerStateManager = [moduleRegistry moduleForName:"RNGestureHandlerModule"];
}
setGestureState(gestureHandlerStateManager, handlerTag, newState);
};
return setGestureStateFunction;
}
#endif // REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED)
RequestRenderFunction makeRequestRender(REANodesManager *nodesManager)
{
auto requestRender = [nodesManager](std::function<void(double)> onRender, jsi::Runtime &rt) {
[nodesManager postOnAnimation:^(READisplayLink *displayLink) {
#if !TARGET_OS_OSX
auto targetTimestamp = displayLink.targetTimestamp;
#else
// TODO macOS targetTimestamp isn't available on macOS
auto targetTimestamp = displayLink.timestamp + displayLink.duration;
#endif
double frameTimestamp =
(targetTimestamp)*1000;
onRender(frameTimestamp);
}];
};
return requestRender;
}
#ifdef RCT_NEW_ARCH_ENABLED
SynchronouslyUpdateUIPropsFunction makeSynchronouslyUpdateUIPropsFunction(REANodesManager *nodesManager)
{
auto synchronouslyUpdateUIPropsFunction = [nodesManager](jsi::Runtime &rt, Tag tag, const jsi::Object &props) {
NSNumber *viewTag = @(tag);
NSDictionary *uiProps = convertJSIObjectToNSDictionary(rt, props);
[nodesManager synchronouslyUpdateViewOnUIThread:viewTag props:uiProps];
};
return synchronouslyUpdateUIPropsFunction;
}
#endif // RCT_NEW_ARCH_ENABLED
#ifdef RCT_NEW_ARCH_ENABLED
// nothing
#else // RCT_NEW_ARCH_ENABLED
UpdatePropsFunction makeUpdatePropsFunction(REAModule *reaModule)
{
auto updatePropsFunction = [reaModule](jsi::Runtime &rt, const jsi::Value &operations) -> void {
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);
int viewTag = item.getProperty(rt, "tag").asNumber();
const jsi::Value &viewName = item.getProperty(rt, "name");
const jsi::Object &props = item.getProperty(rt, "updates").asObject(rt);
NSString *nsViewName = [NSString stringWithCString:viewName.asString(rt).utf8(rt).c_str()
encoding:[NSString defaultCStringEncoding]];
NSDictionary *propsDict = convertJSIObjectToNSDictionary(rt, props);
[reaModule.nodesManager updateProps:propsDict ofViewWithTag:[NSNumber numberWithInt:viewTag] withName:nsViewName];
}
};
return updatePropsFunction;
}
MeasureFunction makeMeasureFunction(RCTUIManager *uiManager)
{
auto measureFunction = [uiManager](int viewTag) -> std::vector<std::pair<std::string, double>> {
return measure(viewTag, uiManager);
};
return measureFunction;
}
ScrollToFunction makeScrollToFunction(RCTUIManager *uiManager)
{
auto scrollToFunction = [uiManager](int viewTag, double x, double y, bool animated) {
scrollTo(viewTag, uiManager, x, y, animated);
};
return scrollToFunction;
}
DispatchCommandFunction makeDispatchCommandFunction(RCTUIManager *uiManager)
{
auto dispatchCommandFunction =
[uiManager](
jsi::Runtime &rt, const int tag, const jsi::Value &commandNameValue, const jsi::Value &argsValue) -> void {
NSNumber *viewTag = [NSNumber numberWithInt:tag];
NSString *commandID = [NSString stringWithCString:commandNameValue.asString(rt).utf8(rt).c_str()
encoding:[NSString defaultCStringEncoding]];
NSArray *commandArgs = convertJSIArrayToNSArray(rt, argsValue.asObject(rt).asArray(rt));
RCTExecuteOnUIManagerQueue(^{
[uiManager dispatchViewManagerCommand:viewTag commandID:commandID commandArgs:commandArgs];
});
};
return dispatchCommandFunction;
}
ConfigurePropsFunction makeConfigurePropsFunction(REAModule *reaModule)
{
auto configurePropsFunction = [reaModule](
jsi::Runtime &rt, const jsi::Value &uiProps, const jsi::Value &nativeProps) {
NSSet *uiPropsSet = convertProps(rt, uiProps);
NSSet *nativePropsSet = convertProps(rt, nativeProps);
[reaModule.nodesManager configureUiProps:uiPropsSet andNativeProps:nativePropsSet];
};
return configurePropsFunction;
}
ObtainPropFunction makeObtainPropFunction(REAModule *reaModule)
{
auto obtainPropFunction = [reaModule](jsi::Runtime &rt, const int viewTag, const jsi::Value &propName) -> jsi::Value {
NSString *propNameConverted = [NSString stringWithFormat:@"%s", propName.asString(rt).utf8(rt).c_str()];
std::string resultStr = std::string([[reaModule.nodesManager obtainProp:[NSNumber numberWithInt:viewTag]
propName:propNameConverted] UTF8String]);
jsi::Value val = jsi::String::createFromUtf8(rt, resultStr);
return val;
};
return obtainPropFunction;
}
#endif // RCT_NEW_ARCH_ENABLED
GetAnimationTimestampFunction makeGetAnimationTimestamp()
{
auto getAnimationTimestamp = []() { return calculateTimestampWithSlowAnimations(CACurrentMediaTime()) * 1000; };
return getAnimationTimestamp;
}
ProgressLayoutAnimationFunction makeProgressLayoutAnimation(REAModule *reaModule)
{
#ifdef RCT_NEW_ARCH_ENABLED
auto progressLayoutAnimation = [=](jsi::Runtime &rt, int tag, const jsi::Object &newStyle, bool isSharedTransition) {
// noop
};
#else // RCT_NEW_ARCH_ENABLED
REAAnimationsManager *animationsManager = reaModule.animationsManager;
__weak REAAnimationsManager *weakAnimationsManager = animationsManager;
auto progressLayoutAnimation = [=](jsi::Runtime &rt, int tag, const jsi::Object &newStyle, bool isSharedTransition) {
NSDictionary *propsDict = convertJSIObjectToNSDictionary(rt, newStyle);
[weakAnimationsManager progressLayoutAnimationWithStyle:propsDict
forTag:@(tag)
isSharedTransition:isSharedTransition];
};
#endif // RCT_NEW_ARCH_ENABLED
return progressLayoutAnimation;
}
EndLayoutAnimationFunction makeEndLayoutAnimation(REAModule *reaModule)
{
#ifdef RCT_NEW_ARCH_ENABLED
auto endLayoutAnimation = [=](int tag, bool removeView) {
// noop
};
#else // RCT_NEW_ARCH_ENABLED
REAAnimationsManager *animationsManager = reaModule.animationsManager;
__weak REAAnimationsManager *weakAnimationsManager = animationsManager;
auto endLayoutAnimation = [=](int tag, bool removeView) {
[weakAnimationsManager endLayoutAnimationForTag:@(tag) removeView:removeView];
};
#endif // RCT_NEW_ARCH_ENABLED
return endLayoutAnimation;
}
MaybeFlushUIUpdatesQueueFunction makeMaybeFlushUIUpdatesQueueFunction(REANodesManager *nodesManager)
{
auto maybeFlushUIUpdatesQueueFunction = [nodesManager]() { [nodesManager maybeFlushUIUpdatesQueue]; };
return maybeFlushUIUpdatesQueueFunction;
}
RegisterSensorFunction makeRegisterSensorFunction(ReanimatedSensorContainer *reanimatedSensorContainer)
{
auto registerSensorFunction =
[=](int sensorType, int interval, int iosReferenceFrame, std::function<void(double[], int)> setter) -> int {
return [reanimatedSensorContainer registerSensor:(ReanimatedSensorType)sensorType
interval:interval
iosReferenceFrame:iosReferenceFrame
setter:^(double *data, int orientationDegrees) {
setter(data, orientationDegrees);
}];
};
return registerSensorFunction;
}
UnregisterSensorFunction makeUnregisterSensorFunction(ReanimatedSensorContainer *reanimatedSensorContainer)
{
auto unregisterSensorFunction = [=](int sensorId) { [reanimatedSensorContainer unregisterSensor:sensorId]; };
return unregisterSensorFunction;
}
KeyboardEventSubscribeFunction makeSubscribeForKeyboardEventsFunction(REAKeyboardEventObserver *keyboardObserver)
{
auto subscribeForKeyboardEventsFunction =
[=](std::function<void(int keyboardState, int height)> keyboardEventDataUpdater, bool isStatusBarTranslucent) {
// ignore isStatusBarTranslucent - it's Android only
return [keyboardObserver subscribeForKeyboardEvents:^(int keyboardState, int height) {
keyboardEventDataUpdater(keyboardState, height);
}];
};
return subscribeForKeyboardEventsFunction;
}
KeyboardEventUnsubscribeFunction makeUnsubscribeFromKeyboardEventsFunction(REAKeyboardEventObserver *keyboardObserver)
{
auto unsubscribeFromKeyboardEventsFunction = [=](int listenerId) {
[keyboardObserver unsubscribeFromKeyboardEvents:listenerId];
};
return unsubscribeFromKeyboardEventsFunction;
}
PlatformDepMethodsHolder
makePlatformDepMethodsHolder(RCTBridge *bridge, REANodesManager *nodesManager, REAModule *reaModule)
{
auto requestRender = makeRequestRender(nodesManager);
#ifdef RCT_NEW_ARCH_ENABLED
auto synchronouslyUpdateUIPropsFunction = makeSynchronouslyUpdateUIPropsFunction(nodesManager);
#endif // RCT_NEW_ARCH_ENABLED
#ifdef RCT_NEW_ARCH_ENABLED
// nothing
#else
RCTUIManager *uiManager = nodesManager.uiManager;
auto updatePropsFunction = makeUpdatePropsFunction(reaModule);
auto measureFunction = makeMeasureFunction(uiManager);
auto scrollToFunction = makeScrollToFunction(uiManager);
auto dispatchCommandFunction = makeDispatchCommandFunction(uiManager);
#endif // RCT_NEW_ARCH_ENABLED
auto getAnimationTimestamp = makeGetAnimationTimestamp();
auto setGestureStateFunction = makeSetGestureStateFunction(bridge);
#ifdef RCT_NEW_ARCH_ENABLED
auto progressLayoutAnimation = makeProgressLayoutAnimation(reaModule);
auto endLayoutAnimation = makeEndLayoutAnimation(reaModule);
#else
// Layout Animations start
auto progressLayoutAnimation = makeProgressLayoutAnimation(reaModule);
auto endLayoutAnimation = makeEndLayoutAnimation(reaModule);
auto configurePropsFunction = makeConfigurePropsFunction(reaModule);
// Layout Animations end
#endif
auto maybeFlushUIUpdatesQueueFunction = makeMaybeFlushUIUpdatesQueueFunction(nodesManager);
ReanimatedSensorContainer *reanimatedSensorContainer = [[ReanimatedSensorContainer alloc] init];
auto registerSensorFunction = makeRegisterSensorFunction(reanimatedSensorContainer);
auto unregisterSensorFunction = makeUnregisterSensorFunction(reanimatedSensorContainer);
REAKeyboardEventObserver *keyboardObserver = [[REAKeyboardEventObserver alloc] init];
auto subscribeForKeyboardEventsFunction = makeSubscribeForKeyboardEventsFunction(keyboardObserver);
auto unsubscribeFromKeyboardEventsFunction = makeUnsubscribeFromKeyboardEventsFunction(keyboardObserver);
// end keyboard events
#ifdef RCT_NEW_ARCH_ENABLED
// nothing
#else
auto obtainPropFunction = makeObtainPropFunction(reaModule);
#endif
PlatformDepMethodsHolder platformDepMethodsHolder = {
requestRender,
#ifdef RCT_NEW_ARCH_ENABLED
synchronouslyUpdateUIPropsFunction,
#else
updatePropsFunction,
scrollToFunction,
dispatchCommandFunction,
measureFunction,
configurePropsFunction,
obtainPropFunction,
#endif
getAnimationTimestamp,
progressLayoutAnimation,
endLayoutAnimation,
registerSensorFunction,
unregisterSensorFunction,
setGestureStateFunction,
subscribeForKeyboardEventsFunction,
unsubscribeFromKeyboardEventsFunction,
maybeFlushUIUpdatesQueueFunction,
};
return platformDepMethodsHolder;
}
#if REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED)
PlatformDepMethodsHolder makePlatformDepMethodsHolderBridgeless(
RCTModuleRegistry *moduleRegistry,
REANodesManager *nodesManager,
REAModule *reaModule)
{
auto requestRender = makeRequestRender(nodesManager);
auto synchronouslyUpdateUIPropsFunction = makeSynchronouslyUpdateUIPropsFunction(nodesManager);
auto getAnimationTimestamp = makeGetAnimationTimestamp();
auto progressLayoutAnimation = makeProgressLayoutAnimation(reaModule);
auto endLayoutAnimation = makeEndLayoutAnimation(reaModule);
ReanimatedSensorContainer *reanimatedSensorContainer = [[ReanimatedSensorContainer alloc] init];
auto registerSensorFunction = makeRegisterSensorFunction(reanimatedSensorContainer);
auto unregisterSensorFunction = makeUnregisterSensorFunction(reanimatedSensorContainer);
auto setGestureStateFunction = makeSetGestureStateFunctionBridgeless(moduleRegistry);
REAKeyboardEventObserver *keyboardObserver = [[REAKeyboardEventObserver alloc] init];
auto subscribeForKeyboardEventsFunction = makeSubscribeForKeyboardEventsFunction(keyboardObserver);
auto unsubscribeFromKeyboardEventsFunction = makeUnsubscribeFromKeyboardEventsFunction(keyboardObserver);
auto maybeFlushUIUpdatesQueueFunction = makeMaybeFlushUIUpdatesQueueFunction(nodesManager);
PlatformDepMethodsHolder platformDepMethodsHolder = {
requestRender,
synchronouslyUpdateUIPropsFunction,
getAnimationTimestamp,
progressLayoutAnimation,
endLayoutAnimation,
registerSensorFunction,
unregisterSensorFunction,
setGestureStateFunction,
subscribeForKeyboardEventsFunction,
unsubscribeFromKeyboardEventsFunction,
maybeFlushUIUpdatesQueueFunction,
};
return platformDepMethodsHolder;
}
#endif // REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED)
} // namespace reanimated

View File

@@ -0,0 +1,15 @@
#import <RNReanimated/ReanimatedHiddenHeaders.h>
#include <stdio.h>
namespace reanimated {
class REAIOSLogger : public LoggerInterface {
public:
void log(const char *str) override;
void log(const std::string &str) override;
void log(double d) override;
void log(int i) override;
void log(bool b) override;
};
} // namespace reanimated

View File

@@ -0,0 +1,33 @@
#import <Foundation/Foundation.h>
#import <RNReanimated/REAIOSLogger.h>
namespace reanimated {
std::unique_ptr<LoggerInterface> Logger::instance = std::make_unique<REAIOSLogger>();
void REAIOSLogger::log(const char *str)
{
NSLog(@"%@", [NSString stringWithCString:str encoding:[NSString defaultCStringEncoding]]);
}
void REAIOSLogger::log(const std::string &str)
{
log(str.c_str());
}
void REAIOSLogger::log(double d)
{
NSLog(@"%lf", d);
}
void REAIOSLogger::log(int i)
{
NSLog(@"%i", i);
}
void REAIOSLogger::log(bool b)
{
log(b ? "true" : "false");
}
} // namespace reanimated

View File

@@ -0,0 +1,17 @@
#import <RNReanimated/UIScheduler.h>
#import <React/RCTUIManager.h>
#import <ReactCommon/CallInvoker.h>
#include <memory>
namespace reanimated {
using namespace facebook;
using namespace react;
class REAIOSUIScheduler : public UIScheduler {
public:
void scheduleOnUI(std::function<void()> job) override;
};
} // namespace reanimated

View File

@@ -0,0 +1,24 @@
#import <RNReanimated/REAIOSUIScheduler.h>
namespace reanimated {
using namespace facebook;
using namespace react;
void REAIOSUIScheduler::scheduleOnUI(std::function<void()> job)
{
if ([NSThread isMainThread]) {
job();
return;
}
UIScheduler::scheduleOnUI(job);
if (!scheduledOnUI_) {
dispatch_async(dispatch_get_main_queue(), ^{
triggerUI();
});
}
}
} // namespace reanimated

View File

@@ -0,0 +1,38 @@
/*
Note: Files REAInitializer.h and REAInitializer.m are deprecated and will
be removed in future releases. They are currently kept for backward
compatibility and will be retained for a few upcoming releases.
*/
#ifndef RCT_NEW_ARCH_ENABLED
#import <Foundation/Foundation.h>
#import <React/RCTBridge.h>
#if REACT_NATIVE_MINOR_VERSION <= 71
#import <React/RCTJSIExecutorRuntimeInstaller.h>
using namespace facebook::react;
#endif // REACT_NATIVE_MINOR_VERSION <= 71
NS_ASSUME_NONNULL_BEGIN
namespace reanimated {
[[deprecated(
"REAInitializer method is no longer required, you can just remove invocation.")]] void
REAInitializer(RCTBridge *bridge);
#if REACT_NATIVE_MINOR_VERSION <= 71
[[deprecated(
"REAJSIExecutorRuntimeInstaller method is no longer required, you can just remove invocation.")]] JSIExecutor::
RuntimeInstaller
REAJSIExecutorRuntimeInstaller(
RCTBridge *bridge,
JSIExecutor::RuntimeInstaller runtimeInstallerToWrap);
#endif // REACT_NATIVE_MINOR_VERSION <= 71
} // namespace reanimated
NS_ASSUME_NONNULL_END
#endif // RCT_NEW_ARCH_ENABLED

View File

@@ -0,0 +1,30 @@
#ifndef RCT_NEW_ARCH_ENABLED
#import <RNReanimated/REAInitializer.h>
namespace reanimated {
void REAInitializer(RCTBridge *bridge)
{
// do nothing, just for backward compatibility
}
#if REACT_NATIVE_MINOR_VERSION <= 71
JSIExecutor::RuntimeInstaller REAJSIExecutorRuntimeInstaller(
RCTBridge *bridge,
JSIExecutor::RuntimeInstaller runtimeInstallerToWrap)
{
const auto runtimeInstaller = [runtimeInstallerToWrap](facebook::jsi::Runtime &runtime) {
if (runtimeInstallerToWrap) {
runtimeInstallerToWrap(runtime);
}
};
return runtimeInstaller;
}
#endif // REACT_NATIVE_MINOR_VERSION <= 71
} // namespace reanimated
#endif // RCT_NEW_ARCH_ENABLED

View File

@@ -0,0 +1,124 @@
#pragma once
#include <jsi/jsi.h>
using namespace facebook;
// Copied from RCTTurboModule.mm
/**
* All static helper functions are ObjC++ specific.
*/
static jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime &runtime, NSNumber *value)
{
return jsi::Value((bool)[value boolValue]);
}
static jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *value)
{
return jsi::Value([value doubleValue]);
}
static jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value)
{
return jsi::String::createFromUtf8(runtime, [value UTF8String] ?: "");
}
static jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value);
static jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value)
{
jsi::Object result = jsi::Object(runtime);
for (NSString *k in value) {
result.setProperty(runtime, [k UTF8String], convertObjCObjectToJSIValue(runtime, value[k]));
}
return result;
}
static jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value)
{
jsi::Array result = jsi::Array(runtime, value.count);
for (size_t i = 0; i < value.count; i++) {
result.setValueAtIndex(runtime, i, convertObjCObjectToJSIValue(runtime, value[i]));
}
return result;
}
static jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value)
{
if ([value isKindOfClass:[NSString class]]) {
return convertNSStringToJSIString(runtime, (NSString *)value);
} else if ([value isKindOfClass:[NSNumber class]]) {
if ([value isKindOfClass:[@YES class]]) {
return convertNSNumberToJSIBoolean(runtime, (NSNumber *)value);
}
return convertNSNumberToJSINumber(runtime, (NSNumber *)value);
} else if ([value isKindOfClass:[NSDictionary class]]) {
return convertNSDictionaryToJSIObject(runtime, (NSDictionary *)value);
} else if ([value isKindOfClass:[NSArray class]]) {
return convertNSArrayToJSIArray(runtime, (NSArray *)value);
} else if (value == (id)kCFNull) {
return jsi::Value::null();
}
return jsi::Value::undefined();
}
// Other
static id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value);
static NSString *convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &value)
{
return [NSString stringWithUTF8String:value.utf8(runtime).c_str()];
}
static NSDictionary *convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value)
{
jsi::Array propertyNames = value.getPropertyNames(runtime);
size_t size = propertyNames.size(runtime);
NSMutableDictionary *result = [NSMutableDictionary new];
for (size_t i = 0; i < size; i++) {
jsi::String name = propertyNames.getValueAtIndex(runtime, i).getString(runtime);
NSString *k = convertJSIStringToNSString(runtime, name);
id v = convertJSIValueToObjCObject(runtime, value.getProperty(runtime, name));
if (v) {
result[k] = v;
}
}
return [result copy];
}
static NSArray *convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value)
{
size_t size = value.size(runtime);
NSMutableArray *result = [NSMutableArray new];
for (size_t i = 0; i < size; i++) {
// Insert kCFNull when it's `undefined` value to preserve the indices.
[result addObject:convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i)) ?: (id)kCFNull];
}
return [result copy];
}
static id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value)
{
if (value.isUndefined() || value.isNull()) {
return nil;
}
if (value.isBool()) {
return @(value.getBool());
}
if (value.isNumber()) {
return @(value.getNumber());
}
if (value.isString()) {
return convertJSIStringToNSString(runtime, value.getString(runtime));
}
if (value.isObject()) {
jsi::Object o = value.getObject(runtime);
if (o.isArray(runtime)) {
return convertJSIArrayToNSArray(runtime, o.getArray(runtime));
}
return convertJSIObjectToNSDictionary(runtime, o);
}
throw std::runtime_error("[Reanimated] Unsupported jsi::Value kind.");
}

View File

@@ -0,0 +1,22 @@
#pragma once
#import <memory>
#import <string>
#import <Foundation/Foundation.h>
#import <React/RCTJavaScriptExecutor.h>
#import <React/RCTMessageThread.h>
#import <cxxreact/MessageQueueThread.h>
namespace facebook {
namespace react {
class REAMessageThread : public RCTMessageThread {
public:
using RCTMessageThread::RCTMessageThread;
virtual void quitSynchronous() override;
};
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,38 @@
#import <RNReanimated/REAMessageThread.h>
#include <condition_variable>
#include <mutex>
#import <React/RCTCxxUtils.h>
#import <React/RCTMessageThread.h>
#import <React/RCTUtils.h>
namespace facebook {
namespace react {
// Essentially the same as RCTMessageThread, but with public fields.
struct REAMessageThreadPublic {
// I don't know why we need three vtables (if you know then feel free to
// explain it instead of this message), but this is what makes the casts in
// quitSynchronous() work correctly.
void *vtable1;
void *vtable2;
void *vtable3;
CFRunLoopRef m_cfRunLoop;
RCTJavaScriptCompleteBlock m_errorBlock;
std::atomic_bool m_shutdown;
};
// We need to prevent any new code from being executed on the thread as there
// is an assertion for that in the destructor of RCTMessageThread, but we have
// to override quitSynchronous() as it would quit the main looper and freeze
// the app.
void REAMessageThread::quitSynchronous()
{
RCTMessageThread *rctThread = static_cast<RCTMessageThread *>(this);
REAMessageThreadPublic *rctThreadPublic = reinterpret_cast<REAMessageThreadPublic *>(rctThread);
rctThreadPublic->m_shutdown = true;
}
} // namespace react
} // namespace facebook