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,9 @@
package com.swmansion.reanimated;
public class ReactFeatureFlagsWrapper {
public static void enableMountHooks() {
// no-op
}
}

View File

@@ -0,0 +1,11 @@
package com.swmansion.reanimated;
import com.facebook.react.config.ReactFeatureFlags;
public class ReactFeatureFlagsWrapper {
public static void enableMountHooks() {
ReactFeatureFlags.enableMountHooks = true;
}
}

View File

@@ -0,0 +1,127 @@
package com.swmansion.reanimated;
import android.util.Log;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.NativeViewHierarchyManager;
import com.facebook.react.uimanager.UIBlock;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.UIManagerModuleListener;
import java.util.ArrayList;
import javax.annotation.Nullable;
@ReactModule(name = ReanimatedModule.NAME)
public class ReanimatedModule extends NativeReanimatedModuleSpec
implements LifecycleEventListener, UIManagerModuleListener {
public static final String NAME = "ReanimatedModule";
private interface UIThreadOperation {
void execute(NodesManager nodesManager);
}
private ArrayList<UIThreadOperation> mOperations = new ArrayList<>();
private @Nullable NodesManager mNodesManager;
public ReanimatedModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public void initialize() {
ReactApplicationContext reactCtx = getReactApplicationContext();
UIManagerModule uiManager = reactCtx.getNativeModule(UIManagerModule.class);
reactCtx.addLifecycleEventListener(this);
uiManager.addUIManagerListener(this);
}
@Override
public void onHostPause() {
if (mNodesManager != null) {
mNodesManager.onHostPause();
}
}
@Override
public void onHostResume() {
if (mNodesManager != null) {
mNodesManager.onHostResume();
}
}
@Override
public void onHostDestroy() {
// do nothing
}
@Override
public void willDispatchViewUpdates(final UIManagerModule uiManager) {
if (mOperations.isEmpty()) {
return;
}
final ArrayList<UIThreadOperation> operations = mOperations;
mOperations = new ArrayList<>();
uiManager.addUIBlock(
new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
NodesManager nodesManager = getNodesManager();
for (UIThreadOperation operation : operations) {
operation.execute(nodesManager);
}
}
});
}
@Override
public String getName() {
return NAME;
}
/*package*/
public NodesManager getNodesManager() {
if (mNodesManager == null) {
mNodesManager = new NodesManager(getReactApplicationContext());
}
return mNodesManager;
}
@ReactMethod(isBlockingSynchronousMethod = true)
public boolean installTurboModule(String valueUnpackerCode) {
// When debugging in chrome the JS context is not available.
// https://github.com/facebook/react-native/blob/v0.67.0-rc.6/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java#L25
Utils.isChromeDebugger = getReactApplicationContext().getJavaScriptContextHolder().get() == 0;
if (!Utils.isChromeDebugger) {
this.getNodesManager().initWithContext(getReactApplicationContext(), valueUnpackerCode);
return true;
} else {
Log.w(
"[REANIMATED]",
"Unable to create Reanimated Native Module. You can ignore this message if you are using Chrome Debugger now.");
return false;
}
}
@ReactMethod
public void addListener(String eventName) {
// Keep: Required for RN built in Event Emitter Calls.
}
@ReactMethod
public void removeListeners(Integer count) {
// Keep: Required for RN built in Event Emitter Calls.
}
@Override
public void invalidate() {
super.invalidate();
if (mNodesManager != null) {
mNodesManager.invalidate();
}
}
}

View File

@@ -0,0 +1,271 @@
package com.facebook.react.uimanager;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.module.annotations.ReactModule;
import java.util.List;
@ReactModule(name = UIManagerModule.NAME)
public class ReanimatedUIManager extends UIManagerModule {
public ReanimatedUIManager(
ReactApplicationContext reactContext,
List<ViewManager> viewManagersList,
int minTimeLeftInFrameForNonBatchedOperationMs) {
super(reactContext, viewManagersList, minTimeLeftInFrameForNonBatchedOperationMs);
}
public void onBatchComplete() {
super.onBatchComplete();
}
@Override
public boolean canOverrideExistingModule() {
return true;
}
@ReactMethod(isBlockingSynchronousMethod = true)
public @Nullable WritableMap getConstantsForViewManager(@Nullable String viewManagerName) {
return super.getConstantsForViewManager(viewManagerName);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public WritableMap getDefaultEventTypes() {
return super.getDefaultEventTypes();
}
/** Unregisters a new root view. */
@ReactMethod
public void removeRootView(int rootViewTag) {
super.removeRootView(rootViewTag);
}
@ReactMethod
public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
super.createView(tag, className, rootViewTag, props);
}
@ReactMethod
public void updateView(final int tag, final String className, final ReadableMap props) {
super.updateView(tag, className, props);
}
/**
* Interface for adding/removing/moving views within a parent view from JS.
*
* @param viewTag the view tag of the parent view
* @param moveFrom a list of indices in the parent view to move views from
* @param moveTo parallel to moveFrom, a list of indices in the parent view to move views to
* @param addChildTags a list of tags of views to add to the parent
* @param addAtIndices parallel to addChildTags, a list of indices to insert those children at
* @param removeFrom a list of indices of views to permanently remove. The memory for the
* corresponding views and data structures should be reclaimed.
*/
@ReactMethod
public void manageChildren(
int viewTag,
@Nullable ReadableArray moveFrom,
@Nullable ReadableArray moveTo,
@Nullable ReadableArray addChildTags,
@Nullable ReadableArray addAtIndices,
@Nullable ReadableArray removeFrom) {
super.manageChildren(viewTag, moveFrom, moveTo, addChildTags, addAtIndices, removeFrom);
}
/**
* Interface for fast tracking the initial adding of views. Children view tags are assumed to be
* in order
*
* @param viewTag the view tag of the parent view
* @param childrenTags An array of tags to add to the parent in order
*/
@ReactMethod
public void setChildren(int viewTag, ReadableArray childrenTags) {
super.setChildren(viewTag, childrenTags);
}
/**
* Replaces the View specified by oldTag with the View specified by newTag within oldTag's parent.
* This resolves to a simple {@link #manageChildren} call, but React doesn't have enough info in
* JS to formulate it itself.
*
* @deprecated This method will not be available in Fabric UIManager class.
*/
@ReactMethod
@Deprecated
public void replaceExistingNonRootView(int oldTag, int newTag) {
super.replaceExistingNonRootView(oldTag, newTag);
}
/**
* Method which takes a container tag and then releases all subviews for that container upon
* receipt.
*
* @param containerTag the tag of the container for which the subviews must be removed
* @deprecated This method will not be available in Fabric UIManager class.
*/
@ReactMethod
@Deprecated
public void removeSubviewsFromContainerWithID(int containerTag) {
super.removeSubviewsFromContainerWithID(containerTag);
}
/**
* Determines the location on screen, width, and height of the given view and returns the values
* via an async callback.
*/
@ReactMethod
public void measure(int reactTag, Callback callback) {
super.measure(reactTag, callback);
}
/**
* Determines the location on screen, width, and height of the given view relative to the device
* screen and returns the values via an async callback. This is the absolute position including
* things like the status bar
*/
@ReactMethod
public void measureInWindow(int reactTag, Callback callback) {
super.measureInWindow(reactTag, callback);
}
/**
* Measures the view specified by tag relative to the given ancestorTag. This means that the
* returned x, y are relative to the origin x, y of the ancestor view. Results are stored in the
* given outputBuffer. We allow ancestor view and measured view to be the same, in which case the
* position always will be (0, 0) and method will only measure the view dimensions.
*
* <p>NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible
* window which can cause unexpected results when measuring relative to things like ScrollViews
* that can have offset content on the screen.
*/
@ReactMethod
public void measureLayout(
int tag, int ancestorTag, Callback errorCallback, Callback successCallback) {
super.measureLayout(tag, ancestorTag, errorCallback, successCallback);
}
/**
* Like {@link #measure} and {@link #measureLayout} but measures relative to the immediate parent.
*
* <p>NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible
* window which can cause unexpected results when measuring relative to things like ScrollViews
* that can have offset content on the screen.
*
* @deprecated this method will not be available in FabricUIManager class.
*/
@ReactMethod
@Deprecated
public void measureLayoutRelativeToParent(
int tag, Callback errorCallback, Callback successCallback) {
super.measureLayoutRelativeToParent(tag, errorCallback, successCallback);
}
/**
* Find the touch target child native view in the supplied root view hierarchy, given a react
* target location.
*
* <p>This method is currently used only by Element Inspector DevTool.
*
* @param reactTag the tag of the root view to traverse
* @param point an array containing both X and Y target location
* @param callback will be called if with the identified child view react ID, and measurement
* info. If no view was found, callback will be invoked with no data.
*/
@ReactMethod
public void findSubviewIn(
final int reactTag, final ReadableArray point, final Callback callback) {
super.findSubviewIn(reactTag, point, callback);
}
/**
* Check if the first shadow node is the descendant of the second shadow node
*
* @deprecated this method will not be available in FabricUIManager class.
*/
@ReactMethod
@Deprecated
public void viewIsDescendantOf(
final int reactTag, final int ancestorReactTag, final Callback callback) {
super.viewIsDescendantOf(reactTag, ancestorReactTag, callback);
}
@ReactMethod
public void setJSResponder(int reactTag, boolean blockNativeResponder) {
super.setJSResponder(reactTag, blockNativeResponder);
}
@ReactMethod
public void clearJSResponder() {
super.clearJSResponder();
}
@ReactMethod
public void dispatchViewManagerCommand(
int reactTag, Dynamic commandId, @Nullable ReadableArray commandArgs) {
super.dispatchViewManagerCommand(reactTag, commandId, commandArgs);
}
/**
* Show a PopupMenu.
*
* @param reactTag the tag of the anchor view (the PopupMenu is displayed next to this view); this
* needs to be the tag of a native view (shadow views can not be anchors)
* @param items the menu items as an array of strings
* @param error will be called if there is an error displaying the menu
* @param success will be called with the position of the selected item as the first argument, or
* no arguments if the menu is dismissed
*/
@ReactMethod
public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Callback success) {
super.showPopupMenu(reactTag, items, error, success);
}
@ReactMethod
public void dismissPopupMenu() {
super.dismissPopupMenu();
}
/**
* LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled
* explicitly in order to avoid regression in existing application written for iOS using this API.
*
* <p>Warning : This method will be removed in future version of React Native, and layout
* animation will be enabled by default, so always check for its existence before invoking it.
*
* <p>TODO(9139831) : remove this method once layout animation is fully stable.
*
* @param enabled whether layout animation is enabled or not
*/
@ReactMethod
public void setLayoutAnimationEnabledExperimental(boolean enabled) {
super.setLayoutAnimationEnabledExperimental(enabled);
}
/**
* Configure an animation to be used for the native layout changes, and native views creation. The
* animation will only apply during the current batch operations.
*
* <p>TODO(7728153) : animating view deletion is currently not supported.
*
* @param config the configuration of the animation for view addition/removal/update.
* @param success will be called when the animation completes, or when the animation get
* interrupted. In this case, callback parameter will be false.
* @param error will be called if there was an error processing the animation
*/
@ReactMethod
public void configureNextLayoutAnimation(ReadableMap config, Callback success, Callback error) {
super.configureNextLayoutAnimation(config, success, error);
}
@ReactMethod
public void sendAccessibilityEvent(int tag, int eventType) {
super.sendAccessibilityEvent(tag, eventType);
}
}

View File

@@ -0,0 +1,176 @@
package com.swmansion.reanimated;
import android.util.Log;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.UIManager;
import com.facebook.react.bridge.UIManagerListener;
import com.facebook.react.fabric.FabricUIManager;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.UIManagerModuleListener;
import java.util.ArrayList;
import javax.annotation.Nullable;
@ReactModule(name = ReanimatedModule.NAME)
public class ReanimatedModule extends NativeReanimatedModuleSpec
implements LifecycleEventListener, UIManagerModuleListener,
UIManagerListener {
public static final String NAME = "ReanimatedModule";
public void didDispatchMountItems(@NonNull UIManager uiManager) {
// Keep: Required for UIManagerListener
}
public void didMountItems(@NonNull UIManager uiManager) {
// Keep: Required for UIManagerListener
}
public void didScheduleMountItems(@NonNull UIManager uiManager) {
// Keep: Required for UIManagerListener
}
public void willDispatchViewUpdates(@NonNull UIManager uiManager) {
// This method is called for the interface of UIManagerListener on Fabric.
// The below function with the same name won't be called.
if (mOperations.isEmpty()) {
return;
}
final ArrayList<UIThreadOperation> operations = mOperations;
mOperations = new ArrayList<>();
if (uiManager instanceof FabricUIManager) {
((FabricUIManager)uiManager).addUIBlock(uiBlockViewResolver -> {
NodesManager nodesManager = getNodesManager();
for (UIThreadOperation operation : operations) {
operation.execute(nodesManager);
}
});
} else {
throw new RuntimeException(
"[Reanimated] Failed to obtain instance of FabricUIManager.");
}
}
public void willMountItems(@NonNull UIManager uiManager) {}
private interface UIThreadOperation {
void execute(NodesManager nodesManager);
}
private ArrayList<UIThreadOperation> mOperations = new ArrayList<>();
private @Nullable NodesManager mNodesManager;
public ReanimatedModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public void initialize() {
ReactApplicationContext reactCtx = getReactApplicationContext();
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
UIManager uiManager = reactCtx.getFabricUIManager();
if (uiManager instanceof FabricUIManager) {
((FabricUIManager)uiManager).addUIManagerEventListener(this);
} else {
throw new RuntimeException(
"[Reanimated] Failed to obtain instance of FabricUIManager.");
}
} else {
UIManagerModule uiManager =
reactCtx.getNativeModule(UIManagerModule.class);
uiManager.addUIManagerListener(this);
}
reactCtx.addLifecycleEventListener(this);
}
@Override
public void onHostPause() {
if (mNodesManager != null) {
mNodesManager.onHostPause();
}
}
@Override
public void onHostResume() {
if (mNodesManager != null) {
mNodesManager.onHostResume();
}
}
@Override
public void onHostDestroy() {
// do nothing
}
@Override
public void willDispatchViewUpdates(final UIManagerModule uiManager) {
// This method is called for the interface of UIManagerModuleListener on
// Paper. The below function with the same name won't be called.
if (mOperations.isEmpty()) {
return;
}
final ArrayList<UIThreadOperation> operations = mOperations;
mOperations = new ArrayList<>();
uiManager.addUIBlock(nativeViewHierarchyManager -> {
NodesManager nodesManager = getNodesManager();
for (UIThreadOperation operation : operations) {
operation.execute(nodesManager);
}
});
}
@Override
public String getName() {
return NAME;
}
/*package*/
public NodesManager getNodesManager() {
if (mNodesManager == null) {
mNodesManager = new NodesManager(getReactApplicationContext());
}
return mNodesManager;
}
@ReactMethod(isBlockingSynchronousMethod = true)
public boolean installTurboModule(String valueUnpackerCode) {
// When debugging in chrome the JS context is not available.
// https://github.com/facebook/react-native/blob/v0.67.0-rc.6/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java#L25
Utils.isChromeDebugger =
getReactApplicationContext().getJavaScriptContextHolder().get() == 0;
if (!Utils.isChromeDebugger) {
this.getNodesManager().initWithContext(
getReactApplicationContext(), valueUnpackerCode);
return true;
} else {
Log.w(
"[REANIMATED]",
"Unable to create Reanimated Native Module. You can ignore this message if you are using Chrome Debugger now.");
return false;
}
}
@ReactMethod
public void addListener(String eventName) {
// Keep: Required for RN built in Event Emitter Calls.
}
@ReactMethod
public void removeListeners(Integer count) {
// Keep: Required for RN built in Event Emitter Calls.
}
@Override
public void invalidate() {
super.invalidate();
if (mNodesManager != null) {
mNodesManager.invalidate();
}
}
}

View File

@@ -0,0 +1,245 @@
package com.facebook.react.uimanager;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.module.annotations.ReactModule;
import java.util.List;
@ReactModule(name = UIManagerModule.NAME)
public class ReanimatedUIManager extends UIManagerModule {
public ReanimatedUIManager(
ReactApplicationContext reactContext,
List<ViewManager> viewManagersList,
int minTimeLeftInFrameForNonBatchedOperationMs) {
super(reactContext, viewManagersList, minTimeLeftInFrameForNonBatchedOperationMs);
}
public void onBatchComplete() {
super.onBatchComplete();
}
@Override
public boolean canOverrideExistingModule() {
return true;
}
@ReactMethod(isBlockingSynchronousMethod = true)
public @Nullable WritableMap getConstantsForViewManager(@Nullable String viewManagerName) {
return super.getConstantsForViewManager(viewManagerName);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public WritableMap getDefaultEventTypes() {
return super.getDefaultEventTypes();
}
/** Unregisters a new root view. */
@ReactMethod
public void removeRootView(int rootViewTag) {
super.removeRootView(rootViewTag);
}
@ReactMethod
public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
super.createView(tag, className, rootViewTag, props);
}
@ReactMethod
public void updateView(final int tag, final String className, final ReadableMap props) {
super.updateView(tag, className, props);
}
/**
* Interface for adding/removing/moving views within a parent view from JS.
*
* @param viewTag the view tag of the parent view
* @param moveFrom a list of indices in the parent view to move views from
* @param moveTo parallel to moveFrom, a list of indices in the parent view to move views to
* @param addChildTags a list of tags of views to add to the parent
* @param addAtIndices parallel to addChildTags, a list of indices to insert those children at
* @param removeFrom a list of indices of views to permanently remove. The memory for the
* corresponding views and data structures should be reclaimed.
*/
@ReactMethod
public void manageChildren(
int viewTag,
@Nullable ReadableArray moveFrom,
@Nullable ReadableArray moveTo,
@Nullable ReadableArray addChildTags,
@Nullable ReadableArray addAtIndices,
@Nullable ReadableArray removeFrom) {
super.manageChildren(viewTag, moveFrom, moveTo, addChildTags, addAtIndices, removeFrom);
}
/**
* Interface for fast tracking the initial adding of views. Children view tags are assumed to be
* in order
*
* @param viewTag the view tag of the parent view
* @param childrenTags An array of tags to add to the parent in order
*/
@ReactMethod
public void setChildren(int viewTag, ReadableArray childrenTags) {
super.setChildren(viewTag, childrenTags);
}
/**
* Determines the location on screen, width, and height of the given view and returns the values
* via an async callback.
*/
@ReactMethod
public void measure(int reactTag, Callback callback) {
super.measure(reactTag, callback);
}
/**
* Determines the location on screen, width, and height of the given view relative to the device
* screen and returns the values via an async callback. This is the absolute position including
* things like the status bar
*/
@ReactMethod
public void measureInWindow(int reactTag, Callback callback) {
super.measureInWindow(reactTag, callback);
}
/**
* Measures the view specified by tag relative to the given ancestorTag. This means that the
* returned x, y are relative to the origin x, y of the ancestor view. Results are stored in the
* given outputBuffer. We allow ancestor view and measured view to be the same, in which case the
* position always will be (0, 0) and method will only measure the view dimensions.
*
* <p>NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible
* window which can cause unexpected results when measuring relative to things like ScrollViews
* that can have offset content on the screen.
*/
@ReactMethod
public void measureLayout(
int tag, int ancestorTag, Callback errorCallback, Callback successCallback) {
super.measureLayout(tag, ancestorTag, errorCallback, successCallback);
}
/**
* Like {@link #measure} and {@link #measureLayout} but measures relative to the immediate parent.
*
* <p>NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible
* window which can cause unexpected results when measuring relative to things like ScrollViews
* that can have offset content on the screen.
*
* @deprecated this method will not be available in FabricUIManager class.
*/
@ReactMethod
@Deprecated
public void measureLayoutRelativeToParent(
int tag, Callback errorCallback, Callback successCallback) {
super.measureLayoutRelativeToParent(tag, errorCallback, successCallback);
}
/**
* Find the touch target child native view in the supplied root view hierarchy, given a react
* target location.
*
* <p>This method is currently used only by Element Inspector DevTool.
*
* @param reactTag the tag of the root view to traverse
* @param point an array containing both X and Y target location
* @param callback will be called if with the identified child view react ID, and measurement
* info. If no view was found, callback will be invoked with no data.
*/
@ReactMethod
public void findSubviewIn(
final int reactTag, final ReadableArray point, final Callback callback) {
super.findSubviewIn(reactTag, point, callback);
}
/**
* Check if the first shadow node is the descendant of the second shadow node
*
* @deprecated this method will not be available in FabricUIManager class.
*/
@ReactMethod
@Deprecated
public void viewIsDescendantOf(
final int reactTag, final int ancestorReactTag, final Callback callback) {
super.viewIsDescendantOf(reactTag, ancestorReactTag, callback);
}
@ReactMethod
public void setJSResponder(int reactTag, boolean blockNativeResponder) {
super.setJSResponder(reactTag, blockNativeResponder);
}
@ReactMethod
public void clearJSResponder() {
super.clearJSResponder();
}
@ReactMethod
public void dispatchViewManagerCommand(
int reactTag, Dynamic commandId, @Nullable ReadableArray commandArgs) {
super.dispatchViewManagerCommand(reactTag, commandId, commandArgs);
}
/**
* Show a PopupMenu.
*
* @param reactTag the tag of the anchor view (the PopupMenu is displayed next to this view); this
* needs to be the tag of a native view (shadow views can not be anchors)
* @param items the menu items as an array of strings
* @param error will be called if there is an error displaying the menu
* @param success will be called with the position of the selected item as the first argument, or
* no arguments if the menu is dismissed
*/
@ReactMethod
public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Callback success) {
super.showPopupMenu(reactTag, items, error, success);
}
@ReactMethod
public void dismissPopupMenu() {
super.dismissPopupMenu();
}
/**
* LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled
* explicitly in order to avoid regression in existing application written for iOS using this API.
*
* <p>Warning : This method will be removed in future version of React Native, and layout
* animation will be enabled by default, so always check for its existence before invoking it.
*
* <p>TODO(9139831) : remove this method once layout animation is fully stable.
*
* @param enabled whether layout animation is enabled or not
*/
@ReactMethod
public void setLayoutAnimationEnabledExperimental(boolean enabled) {
super.setLayoutAnimationEnabledExperimental(enabled);
}
/**
* Configure an animation to be used for the native layout changes, and native views creation. The
* animation will only apply during the current batch operations.
*
* <p>TODO(7728153) : animating view deletion is currently not supported.
*
* @param config the configuration of the animation for view addition/removal/update.
* @param success will be called when the animation completes, or when the animation get
* interrupted. In this case, callback parameter will be false.
* @param error will be called if there was an error processing the animation
*/
@ReactMethod
public void configureNextLayoutAnimation(ReadableMap config, Callback success, Callback error) {
super.configureNextLayoutAnimation(config, success, error);
}
@ReactMethod
public void sendAccessibilityEvent(int tag, int eventType) {
super.sendAccessibilityEvent(tag, eventType);
}
}

View File

@@ -0,0 +1,116 @@
package com.swmansion.reanimated;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.queue.MessageQueueThread;
import com.facebook.react.fabric.FabricUIManager;
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.uimanager.common.UIManagerType;
import com.swmansion.reanimated.layoutReanimation.LayoutAnimations;
import com.swmansion.reanimated.layoutReanimation.NativeMethodsHolder;
import com.swmansion.reanimated.nativeProxy.NativeProxyCommon;
import java.util.HashMap;
public class NativeProxy extends NativeProxyCommon {
@DoNotStrip
@SuppressWarnings("unused")
private final HybridData mHybridData;
public NativeProxy(ReactApplicationContext context, String valueUnpackerCode) {
super(context);
ReactFeatureFlagsWrapper.enableMountHooks();
CallInvokerHolderImpl holder =
(CallInvokerHolderImpl) context.getCatalystInstance().getJSCallInvokerHolder();
FabricUIManager fabricUIManager =
(FabricUIManager) UIManagerHelper.getUIManager(context, UIManagerType.FABRIC);
LayoutAnimations LayoutAnimations = new LayoutAnimations(context);
ReanimatedMessageQueueThread messageQueueThread = new ReanimatedMessageQueueThread();
mHybridData =
initHybrid(
context.getJavaScriptContextHolder().get(),
holder,
mAndroidUIScheduler,
LayoutAnimations,
messageQueueThread,
fabricUIManager,
valueUnpackerCode);
prepareLayoutAnimations(LayoutAnimations);
installJSIBindings();
if (BuildConfig.DEBUG) {
checkCppVersion();
}
}
private native HybridData initHybrid(
long jsContext,
CallInvokerHolderImpl jsCallInvokerHolder,
AndroidUIScheduler androidUIScheduler,
LayoutAnimations LayoutAnimations,
MessageQueueThread messageQueueThread,
FabricUIManager fabricUIManager,
String valueUnpackerCode);
public native boolean isAnyHandlerWaitingForEvent(String eventName, int emitterReactTag);
public native void performOperations();
@Override
protected HybridData getHybridData() {
return mHybridData;
}
public static NativeMethodsHolder createNativeMethodsHolder(LayoutAnimations layoutAnimations) {
return new NativeMethodsHolder() {
@Override
public void startAnimation(int tag, int type, HashMap<String, Object> values) {
// NOT IMPLEMENTED
}
@Override
public boolean isLayoutAnimationEnabled() {
// NOT IMPLEMENTED
return false;
}
@Override
public int findPrecedingViewTagForTransition(int tag) {
// NOT IMPLEMENTED
return -1;
}
@Override
public boolean shouldAnimateExiting(int tag, boolean shouldAnimate) {
// NOT IMPLEMENTED
return false;
}
@Override
public boolean hasAnimation(int tag, int type) {
// NOT IMPLEMENTED
return false;
}
@Override
public void clearAnimationConfig(int tag) {
// NOT IMPLEMENTED
}
@Override
public void cancelAnimation(int tag) {
// NOT IMPLEMENTED
}
@Override
public void checkDuplicateSharedTag(int viewTag, int screenTag) {
// NOT IMPLEMENTED
}
};
}
}

View File

@@ -0,0 +1,143 @@
package com.swmansion.reanimated;
import androidx.annotation.OptIn;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.RuntimeExecutor;
import com.facebook.react.bridge.queue.MessageQueueThread;
import com.facebook.react.common.annotations.FrameworkAPI;
import com.facebook.react.fabric.FabricUIManager;
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.uimanager.common.UIManagerType;
import com.swmansion.reanimated.layoutReanimation.LayoutAnimations;
import com.swmansion.reanimated.layoutReanimation.NativeMethodsHolder;
import com.swmansion.reanimated.nativeProxy.NativeProxyCommon;
import java.util.HashMap;
import java.util.Objects;
public class NativeProxy extends NativeProxyCommon {
@DoNotStrip
@SuppressWarnings("unused")
private final HybridData mHybridData;
public @OptIn(markerClass = FrameworkAPI.class) NativeProxy(ReactApplicationContext context, String valueUnpackerCode) {
super(context);
ReactFeatureFlagsWrapper.enableMountHooks();
FabricUIManager fabricUIManager =
(FabricUIManager) UIManagerHelper.getUIManager(context, UIManagerType.FABRIC);
LayoutAnimations LayoutAnimations = new LayoutAnimations(context);
ReanimatedMessageQueueThread messageQueueThread = new ReanimatedMessageQueueThread();
if (context.isBridgeless()) {
RuntimeExecutor runtimeExecutor = context.getRuntimeExecutor();
mHybridData = initHybridBridgeless(
Objects.requireNonNull(context.getJavaScriptContextHolder()).get(),
runtimeExecutor,
mAndroidUIScheduler,
LayoutAnimations,
messageQueueThread,
fabricUIManager,
valueUnpackerCode
);
} else {
CallInvokerHolderImpl callInvokerHolder = (CallInvokerHolderImpl) context.getCatalystInstance().getJSCallInvokerHolder();
mHybridData =
initHybrid(
Objects.requireNonNull(context.getJavaScriptContextHolder()).get(),
callInvokerHolder,
mAndroidUIScheduler,
LayoutAnimations,
messageQueueThread,
fabricUIManager,
valueUnpackerCode);
}
prepareLayoutAnimations(LayoutAnimations);
installJSIBindings();
if (BuildConfig.DEBUG) {
checkCppVersion();
}
}
private native HybridData initHybrid(
long jsContext,
CallInvokerHolderImpl jsCallInvokerHolder,
AndroidUIScheduler androidUIScheduler,
LayoutAnimations LayoutAnimations,
MessageQueueThread messageQueueThread,
FabricUIManager fabricUIManager,
String valueUnpackerCode);
private native HybridData initHybridBridgeless(
long jsContext,
RuntimeExecutor runtimeExecutor,
AndroidUIScheduler androidUIScheduler,
LayoutAnimations LayoutAnimations,
MessageQueueThread messageQueueThread,
FabricUIManager fabricUIManager,
String valueUnpackerCode);
public native boolean isAnyHandlerWaitingForEvent(String eventName, int emitterReactTag);
public native void performOperations();
@Override
protected HybridData getHybridData() {
return mHybridData;
}
public static NativeMethodsHolder createNativeMethodsHolder(LayoutAnimations layoutAnimations) {
return new NativeMethodsHolder() {
@Override
public void startAnimation(int tag, int type, HashMap<String, Object> values) {
// NOT IMPLEMENTED
}
@Override
public boolean isLayoutAnimationEnabled() {
// NOT IMPLEMENTED
return false;
}
@Override
public int findPrecedingViewTagForTransition(int tag) {
// NOT IMPLEMENTED
return -1;
}
@Override
public boolean shouldAnimateExiting(int tag, boolean shouldAnimate) {
// NOT IMPLEMENTED
return false;
}
@Override
public boolean hasAnimation(int tag, int type) {
// NOT IMPLEMENTED
return false;
}
@Override
public void clearAnimationConfig(int tag) {
// NOT IMPLEMENTED
}
@Override
public void cancelAnimation(int tag) {
// NOT IMPLEMENTED
}
@Override
public void checkDuplicateSharedTag(int viewTag, int screenTag) {
// NOT IMPLEMENTED
}
};
}
}

View File

@@ -0,0 +1,12 @@
package com.swmansion.reanimated;
import com.facebook.proguard.annotations.DoNotStrip;
import com.swmansion.reanimated.ReanimatedMessageQueueThreadBase;
@DoNotStrip
public class ReanimatedMessageQueueThread extends ReanimatedMessageQueueThreadBase {
@Override
public boolean runOnQueue(Runnable runnable) {
return messageQueueThread.runOnQueue(runnable);
}
}

View File

@@ -0,0 +1,17 @@
package com.swmansion.reanimated;
import com.facebook.proguard.annotations.DoNotStrip;
import com.swmansion.reanimated.ReanimatedMessageQueueThreadBase;
@DoNotStrip
public class ReanimatedMessageQueueThread extends ReanimatedMessageQueueThreadBase {
@Override
public boolean runOnQueue(Runnable runnable) {
return messageQueueThread.runOnQueue(runnable);
}
@Override
public boolean isIdle() {
return messageQueueThread.isIdle();
}
}