chore: update map

This commit is contained in:
2026-02-19 08:55:45 +01:00
parent 3308adf1ea
commit 900c54c20b
1845 changed files with 3677 additions and 84269 deletions
@@ -1,11 +0,0 @@
#if TARGET_OS_OSX
#import <React/RCTUIKit.h>
@interface RCTUIView (Reanimated)
@property CGPoint center;
@end
#endif
@@ -1,26 +0,0 @@
#if TARGET_OS_OSX
#import <React/RCTUIKit.h>
#import <reanimated/apple/RCTUIView+Reanimated.h>
@implementation RCTUIView (Reanimated)
- (CGPoint)center
{
NSRect frameRect = self.frame;
CGFloat xCenter = frameRect.origin.x + frameRect.size.width / 2;
CGFloat yCenter = frameRect.origin.y + frameRect.size.height / 2;
return CGPointMake(xCenter, yCenter);
}
- (void)setCenter:(CGPoint)point
{
NSRect frameRect = self.frame;
CGFloat xOrigin = point.x - frameRect.size.width / 2;
CGFloat yOrigin = point.y - frameRect.size.height / 2;
self.frame = CGRectMake(xOrigin, yOrigin, frameRect.size.width, frameRect.size.height);
}
@end
#endif
@@ -1,14 +0,0 @@
#import <react/debug/react_native_assert.h>
// Copied from RCTJSThreadManager.mm
static NSString *const RCTJSThreadName = @"com.facebook.react.runtime.JavaScript";
static BOOL REAIsJavaScriptQueue()
{
return [NSThread.currentThread.name isEqualToString:RCTJSThreadName];
}
static void REAAssertJavaScriptQueue()
{
react_native_assert(REAIsJavaScriptQueue() && "This function must be called on the JavaScript queue");
}
@@ -1,16 +0,0 @@
#import <react/debug/react_native_assert.h>
constexpr auto turboModuleManagerQueueLabel =
"com.meta.react.turbomodulemanager.queue";
static bool REAIsTurboModuleManagerQueue() {
const auto currentQueueLabel =
dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
return strcmp(currentQueueLabel, turboModuleManagerQueueLabel) == 0;
}
static void REAAssertTurboModuleManagerQueue() {
react_native_assert(
REAIsTurboModuleManagerQueue() &&
"This function must be called on the TurboModuleManager queue");
}
@@ -1,21 +0,0 @@
#if !TARGET_OS_OSX
#import <QuartzCore/CADisplayLink.h>
typedef CADisplayLink READisplayLink;
#else // TARGET_OS_OSX [
#ifdef __cplusplus
extern "C" {
#endif
#import <React/RCTPlatformDisplayLink.h>
#ifdef __cplusplus
}
#endif
typedef RCTPlatformDisplayLink READisplayLink;
#endif // ] TARGET_OS_OSX
@@ -1,22 +0,0 @@
#import <React/RCTEventDispatcherProtocol.h>
#import <reanimated/apple/READisplayLink.h>
typedef void (^REAOnAnimationCallback)(READisplayLink *displayLink);
typedef void (^REAEventHandler)(id<RCTEvent> event);
typedef void (^CADisplayLinkOperation)(READisplayLink *displayLink);
typedef void (^REAPerformOperations)();
@interface REANodesManager : NSObject
- (nonnull instancetype)init;
- (void)invalidate;
- (void)postOnAnimation:(REAOnAnimationCallback)clb;
- (void)registerEventHandler:(REAEventHandler)eventHandler;
- (void)dispatchEvent:(id<RCTEvent>)event;
- (void)registerPerformOperations:(REAPerformOperations)performOperations;
- (void)maybeFlushUIUpdatesQueue;
@end
@@ -1,154 +0,0 @@
#import <reanimated/apple/REAAssertJavaScriptQueue.h>
#import <reanimated/apple/REAAssertTurboModuleManagerQueue.h>
#import <reanimated/apple/REANodesManager.h>
#import <React/RCTUtils.h>
@implementation REANodesManager {
READisplayLink *_displayLink;
NSMutableArray<REAOnAnimationCallback> *_onAnimationCallbacks;
REAEventHandler _eventHandler;
REAPerformOperations _performOperations;
}
- (READisplayLink *)getDisplayLink
{
RCTAssertMainQueue();
if (!_displayLink) {
_displayLink = [READisplayLink displayLinkWithTarget:self selector:@selector(onAnimationFrame:)];
#if !TARGET_OS_OSX
_displayLink.preferredFramesPerSecond = 120; // will fallback to 60 fps for devices without Pro Motion display
#endif // TARGET_OS_OSX
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
return _displayLink;
}
- (void)useDisplayLinkOnMainQueue:(CADisplayLinkOperation)displayLinkOperation
{
// This method is called on the JavaScript queue during initialization or on the ShadowQueue during invalidation.
react_native_assert(REAIsJavaScriptQueue() || REAIsTurboModuleManagerQueue());
__weak __typeof__(self) weakSelf = self;
RCTExecuteOnMainQueue(^{
__typeof__(self) strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
displayLinkOperation([strongSelf getDisplayLink]);
});
}
- (nonnull instancetype)init
{
REAAssertJavaScriptQueue();
if ((self = [super init])) {
_onAnimationCallbacks = [NSMutableArray new];
_eventHandler = ^(id<RCTEvent> event) {
// no-op
};
}
[self useDisplayLinkOnMainQueue:^(READisplayLink *displayLink) {
[displayLink setPaused:YES];
}];
return self;
}
- (void)invalidate
{
REAAssertTurboModuleManagerQueue();
_eventHandler = nil;
[self useDisplayLinkOnMainQueue:^(READisplayLink *displayLink) {
[displayLink invalidate];
}];
}
- (void)postOnAnimation:(REAOnAnimationCallback)clb
{
RCTAssertMainQueue();
[_onAnimationCallbacks addObject:clb];
[self startUpdatingOnAnimationFrame];
}
- (void)registerEventHandler:(REAEventHandler)eventHandler
{
REAAssertJavaScriptQueue();
_eventHandler = eventHandler;
}
- (void)registerPerformOperations:(REAPerformOperations)performOperations
{
REAAssertJavaScriptQueue();
_performOperations = performOperations;
}
- (void)startUpdatingOnAnimationFrame
{
RCTAssertMainQueue();
[[self getDisplayLink] setPaused:NO];
}
- (void)stopUpdatingOnAnimationFrame
{
RCTAssertMainQueue();
[[self getDisplayLink] setPaused:YES];
}
- (void)onAnimationFrame:(READisplayLink *)displayLink
{
RCTAssertMainQueue();
NSArray<REAOnAnimationCallback> *callbacks = _onAnimationCallbacks;
_onAnimationCallbacks = [NSMutableArray new];
// When one of the callbacks would postOnAnimation callback we don't want
// to process it until the next frame. This is why we cpy the array before
// we iterate over it
for (REAOnAnimationCallback block in callbacks) {
block(displayLink);
}
[self performOperations];
if (_onAnimationCallbacks.count == 0) {
[self stopUpdatingOnAnimationFrame];
}
}
- (void)performOperations
{
RCTAssertMainQueue();
_performOperations(); // calls ReanimatedModuleProxy::performOperations
}
- (void)dispatchEvent:(id<RCTEvent>)event
{
RCTAssertMainQueue();
__weak REAEventHandler eventHandler = _eventHandler;
__weak __typeof__(self) weakSelf = self;
RCTExecuteOnMainQueue(^void() {
__typeof__(self) strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
if (eventHandler == nil) {
return;
}
eventHandler(event);
[strongSelf performOperations];
});
}
- (void)maybeFlushUIUpdatesQueue
{
RCTAssertMainQueue();
if ([[self getDisplayLink] isPaused]) {
[self performOperations];
}
}
@end
@@ -1,13 +0,0 @@
#import <Foundation/Foundation.h>
namespace reanimated {
static inline bool getIsReducedMotion() {
#if __has_include(<UIKit/UIAccessibility.h>)
return UIAccessibilityIsReduceMotionEnabled();
#else
return NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceMotion;
#endif // __has_include(<UIKit/UIAccessibility.h>)
}
} // namespace reanimated
@@ -1,8 +0,0 @@
#import <Foundation/Foundation.h>
namespace reanimated {
CGFloat getUIAnimationDragCoefficient(void);
CFTimeInterval calculateTimestampWithSlowAnimations(CFTimeInterval currentTimestamp);
} // namespace reanimated
@@ -1,46 +0,0 @@
#import <QuartzCore/QuartzCore.h>
#import <reanimated/apple/REASlowAnimations.h>
#if TARGET_IPHONE_SIMULATOR
#import <dlfcn.h>
#endif
namespace reanimated {
CGFloat getUIAnimationDragCoefficient(void)
{
static float (*UIAnimationDragCoefficient)(void) = NULL;
#if TARGET_IPHONE_SIMULATOR
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
UIAnimationDragCoefficient = (float (*)(void))dlsym(RTLD_DEFAULT, "UIAnimationDragCoefficient");
});
#endif
return UIAnimationDragCoefficient ? UIAnimationDragCoefficient() : 1.f;
}
CFTimeInterval calculateTimestampWithSlowAnimations(CFTimeInterval currentTimestamp)
{
#if TARGET_IPHONE_SIMULATOR
static CFTimeInterval dragCoefChangedTimestamp = CACurrentMediaTime();
static CGFloat previousDragCoef = getUIAnimationDragCoefficient();
const CGFloat dragCoef = getUIAnimationDragCoefficient();
if (previousDragCoef != dragCoef) {
previousDragCoef = dragCoef;
dragCoefChangedTimestamp = CACurrentMediaTime();
}
const bool areSlowAnimationsEnabled = dragCoef != 1.f;
if (areSlowAnimationsEnabled) {
return (dragCoefChangedTimestamp + (currentTimestamp - dragCoefChangedTimestamp) / dragCoef);
} else {
return currentTimestamp;
}
#else
return currentTimestamp;
#endif
}
} // namespace reanimated
@@ -1,13 +0,0 @@
#if !TARGET_OS_OSX
#import <UIKit/UIKit.h>
typedef UIView REAUIView;
#else // TARGET_OS_OSX [
#import <reanimated/apple/RCTUIView+Reanimated.h>
typedef RCTUIView REAUIView;
#endif // ] TARGET_OS_OSX
@@ -1,5 +0,0 @@
@protocol RNGestureHandlerStateManager
- (void)setGestureState:(int)state forHandler:(int)handlerTag;
@end
@@ -1,15 +0,0 @@
#import <React/RCTCallInvokerModule.h>
#import <React/RCTEventEmitter.h>
#import <React/RCTInvalidating.h>
#import <React/RCTUIManagerObserverCoordinator.h>
#import <rnreanimated/rnreanimated.h>
#import <reanimated/apple/REANodesManager.h>
@interface ReanimatedModule
: RCTEventEmitter <NativeReanimatedModuleSpec, RCTCallInvokerModule, RCTEventDispatcherObserver, RCTInvalidating>
@property (nonatomic, readonly) REANodesManager *nodesManager;
@end
@@ -1,183 +0,0 @@
#import <React/RCTBridge+Private.h>
#import <React/RCTCallInvoker.h>
#import <React/RCTScheduler.h>
#import <React/RCTSurfacePresenter.h>
#import <reanimated/RuntimeDecorators/RNRuntimeDecorator.h>
#import <reanimated/apple/REAAssertJavaScriptQueue.h>
#import <reanimated/apple/REAAssertTurboModuleManagerQueue.h>
#import <reanimated/apple/REANodesManager.h>
#import <reanimated/apple/ReanimatedModule.h>
#import <reanimated/apple/native/NativeProxy.h>
#import <worklets/Tools/SingleInstanceChecker.h>
#import <worklets/apple/WorkletsModule.h>
using namespace facebook::react;
using namespace reanimated;
@interface RCTBridge (JSIRuntime)
- (void *)runtime;
@end
@implementation ReanimatedModule {
__weak RCTSurfacePresenter *_surfacePresenter;
#ifndef NDEBUG
SingleInstanceChecker<ReanimatedModule> singleInstanceChecker_;
#endif // NDEBUG
bool hasListeners;
}
@synthesize moduleRegistry = _moduleRegistry;
@synthesize callInvoker = _callInvoker;
RCT_EXPORT_MODULE(ReanimatedModule);
- (void)invalidate
{
REAAssertTurboModuleManagerQueue();
[_nodesManager invalidate];
[super invalidate];
}
- (void)attachReactEventListener:(const std::shared_ptr<ReanimatedModuleProxy>)reanimatedModuleProxy
{
REAAssertJavaScriptQueue();
std::weak_ptr<ReanimatedModuleProxy> reanimatedModuleProxyWeak = reanimatedModuleProxy;
RCTScheduler *scheduler = [_surfacePresenter scheduler];
__weak __typeof__(self) weakSelf = self;
_surfacePresenter.runtimeExecutor(^(jsi::Runtime &runtime) {
__typeof__(self) strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
auto eventListener =
std::make_shared<facebook::react::EventListener>([reanimatedModuleProxyWeak](const RawEvent &rawEvent) {
if (!RCTIsMainQueue()) {
// event listener called on the JS thread, let's ignore this event
// as we cannot safely access worklet runtime here
// and also we don't care about topLayout events
return false;
}
if (const auto reanimatedModuleProxy = reanimatedModuleProxyWeak.lock()) {
return reanimatedModuleProxy->handleRawEvent(rawEvent, CACurrentMediaTime() * 1000);
}
return false;
});
[scheduler addEventListener:eventListener];
});
}
#pragma mark-- Bridgeless methods
/*
* Taken from RCTNativeAnimatedTurboModule:
* This selector is invoked via BridgelessTurboModuleSetup.
*/
- (void)setSurfacePresenter:(id<RCTSurfacePresenterStub>)surfacePresenter
{
REAAssertJavaScriptQueue();
_surfacePresenter = surfacePresenter;
}
- (void)setBridge:(RCTBridge *)bridge
{
REAAssertJavaScriptQueue();
[super setBridge:bridge];
_nodesManager = [[REANodesManager alloc] init];
[[self.moduleRegistry moduleForName:"EventDispatcher"] addDispatchObserver:self];
}
#pragma mark-- Events
- (NSArray<NSString *> *)supportedEvents
{
return @[ @"onReanimatedCall", @"onReanimatedPropsChange" ];
}
- (void)eventDispatcherWillDispatchEvent:(id<RCTEvent>)event
{
// Events can be dispatched from any queue
[_nodesManager dispatchEvent:event];
}
- (void)startObserving
{
hasListeners = YES;
}
- (void)stopObserving
{
hasListeners = NO;
}
- (void)sendEventWithName:(NSString *)eventName body:(id)body
{
if (hasListeners) {
[super sendEventWithName:eventName body:body];
}
}
/**
* Currently on iOS React Native can go into a non-fatal race condition
* on a double reload. Double reload can happen during an OTA update,
* when an app is reloaded immediately after evaluating the bundle.
* We need to bail on it without throwing exceptions.
*/
- (BOOL)hasReactNativeFailedReload
{
return ![_moduleRegistry moduleIsInitialized:WorkletsModule.class];
}
- (void)checkBridgeless
{
auto isBridgeless = ![self.bridge isKindOfClass:[RCTCxxBridge class]];
react_native_assert(isBridgeless && "[Reanimated] react-native-reanimated only supports bridgeless mode");
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(installTurboModule)
{
REAAssertJavaScriptQueue();
if ([self hasReactNativeFailedReload]) {
return @NO;
}
WorkletsModule *workletsModule = [_moduleRegistry moduleForName:"WorkletsModule"];
auto jsCallInvoker = _callInvoker.callInvoker;
react_native_assert(self.bridge != nullptr);
[self checkBridgeless];
react_native_assert(self.bridge.runtime != nullptr);
jsi::Runtime &rnRuntime = *reinterpret_cast<facebook::jsi::Runtime *>(self.bridge.runtime);
auto reanimatedModuleProxy =
reanimated::createReanimatedModuleProxy(_nodesManager, _moduleRegistry, rnRuntime, jsCallInvoker, workletsModule);
auto &uiRuntime = [workletsModule getWorkletsModuleProxy]->getUIWorkletRuntime() -> getJSIRuntime();
RNRuntimeDecorator::decorate(rnRuntime, uiRuntime, reanimatedModuleProxy);
[self attachReactEventListener:reanimatedModuleProxy];
react_native_assert(_surfacePresenter != nil && "_surfacePresenter is nil");
RCTScheduler *scheduler = [_surfacePresenter scheduler];
react_native_assert(scheduler != nil && "_surfacePresenter.scheduler is nil");
react_native_assert(scheduler.uiManager != nil && "_surfacePresenter.scheduler.uiManager is nil");
const auto &uiManager = scheduler.uiManager;
react_native_assert(uiManager.get() != nil);
reanimatedModuleProxy->initializeFabric(uiManager);
return @YES;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
[self checkBridgeless];
REAAssertJavaScriptQueue();
return std::make_shared<facebook::react::NativeReanimatedModuleSpecJSI>(params);
}
@end
@@ -1,9 +0,0 @@
typedef void (^KeyboardEventListenerBlock)(int keyboardState, int height);
@interface REAKeyboardEventObserver : NSObject
- (instancetype)init;
- (int)subscribeForKeyboardEvents:(KeyboardEventListenerBlock)listener;
- (void)unsubscribeFromKeyboardEvents:(int)listenerId;
@end
@@ -1,427 +0,0 @@
#import <Foundation/Foundation.h>
#import <React/RCTAssert.h>
#import <React/RCTBridgeConstants.h>
#import <React/RCTUtils.h>
#import <reanimated/apple/READisplayLink.h>
#import <reanimated/apple/REASlowAnimations.h>
#import <reanimated/apple/REAUIView.h>
#import <reanimated/apple/keyboardObserver/REAKeyboardEventObserver.h>
typedef NS_ENUM(NSUInteger, KeyboardState) {
UNKNOWN = 0,
OPENING = 1,
OPEN = 2,
CLOSING = 3,
CLOSED = 4,
};
@implementation REAKeyboardEventObserver {
REAUIView *_measuringView;
NSNumber *_nextListenerId;
NSMutableDictionary *_listeners;
READisplayLink *_displayLink;
KeyboardState _state;
CFTimeInterval _animationStartTimestamp;
float _initialKeyboardHeight;
float _targetKeyboardHeight;
REAUIView *_keyboardView;
bool _isKeyboardObserverAttached;
bool _isInteractiveDismissalCanceled;
}
- (instancetype)init
{
self = [super init];
_listeners = [[NSMutableDictionary alloc] init];
_nextListenerId = @0;
_state = UNKNOWN;
_animationStartTimestamp = 0;
_isKeyboardObserverAttached = false;
_isInteractiveDismissalCanceled = false;
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(cleanupListeners)
name:RCTBridgeDidInvalidateModulesNotification
object:nil];
return self;
}
- (READisplayLink *)getDisplayLink
{
RCTAssertMainQueue();
if (!_displayLink) {
_displayLink = [READisplayLink displayLinkWithTarget:self selector:@selector(updateKeyboardFrame)];
#if !TARGET_OS_OSX
_displayLink.preferredFramesPerSecond = 120; // will fallback to 60 fps for devices without Pro Motion display
#endif
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
return _displayLink;
}
#if TARGET_OS_TV
- (int)subscribeForKeyboardEvents:(KeyboardEventListenerBlock)listener
{
NSLog(@"Keyboard handling is not supported on tvOS");
return 0;
}
- (void)unsubscribeFromKeyboardEvents:(int)listenerId
{
NSLog(@"Keyboard handling is not supported on tvOS");
}
#elif TARGET_OS_OSX
- (int)subscribeForKeyboardEvents:(KeyboardEventListenerBlock)listener
{
NSLog(@"Keyboard handling is not supported on macOS");
return 0;
}
- (void)unsubscribeFromKeyboardEvents:(int)listenerId
{
NSLog(@"Keyboard handling is not supported on macOS");
}
#else
- (void)runListeners:(float)keyboardHeight
{
for (NSString *key in _listeners.allKeys) {
((KeyboardEventListenerBlock)_listeners[key])(_state, keyboardHeight);
}
}
- (void)runUpdater
{
[[self getDisplayLink] setPaused:NO];
_animationStartTimestamp = 0;
}
- (float)getTargetTimestamp
{
float targetTimestamp = _displayLink.targetTimestamp;
return reanimated::calculateTimestampWithSlowAnimations(targetTimestamp) * 1000;
}
- (float)estimateProgressForDuration:(float)keyboardAnimationDuration
a1:(float)a1
a2:(float)a2
b1:(float)b1
b2:(float)b2
c1:(float)c1
c2:(float)c2
{
CFTimeInterval elapsedTime = _displayLink.targetTimestamp - _animationStartTimestamp;
float timeProgress = elapsedTime / keyboardAnimationDuration;
timeProgress = fmax(fmin(timeProgress, 1), 0);
float x = timeProgress;
float progress = 1 - a1 * pow(1 - x, a2) - b1 * x * pow(1 - x, b2) - c1 * pow(x, 2) * pow(1 - x, c2);
return progress;
}
- (CGFloat)estimateOpeningKeyboardHeight
{
/*
Curve parameters come from estimation: https://www.desmos.com/calculator/ufy5rbucpd
Animation takes 30 frames, which is 0.48 seconds at 60 fps.
*/
float progress = [self estimateProgressForDuration:0.48 a1:1 a2:4.62 b1:2.44 b2:9.82 c1:0.22 c2:2.09];
float animationDistance = _targetKeyboardHeight - _initialKeyboardHeight;
float currentKeyboardHeight = _initialKeyboardHeight + animationDistance * progress;
return currentKeyboardHeight;
}
- (CGFloat)estimateClosingKeyboardHeight
{
/*
Curve parameters come from estimation: https://www.desmos.com/calculator/vhrhdaopyq
Animation takes 31 frames, which is 0.496 seconds at 60 fps.
*/
float progress = [self estimateProgressForDuration:0.496 a1:1 a2:5.65 b1:2.74 b2:8.38 c1:0.93 c2:3.29];
float currentKeyboardHeight = _initialKeyboardHeight * (1 - progress);
return currentKeyboardHeight;
}
- (float)getAnimatingKeyboardHeight
{
if (_animationStartTimestamp == 0) {
// DisplayLink animations usually start later than CAAnimations.
_animationStartTimestamp = _displayLink.targetTimestamp - _displayLink.duration;
}
CAAnimation *positionAnimation = [_measuringView.layer animationForKey:@"position"];
float caAnimationBeginTime = [[positionAnimation valueForKey:@"beginTime"] floatValue];
if (caAnimationBeginTime != 0) {
/*
CAAnimations have their own timers, and synchronizing with their timer produces
better visual effects. The CAAnimation timer is only available from the second
frame of the animation.
*/
_animationStartTimestamp = caAnimationBeginTime;
}
CGFloat keyboardHeight = 0;
if (_state == OPENING) {
keyboardHeight = [self estimateOpeningKeyboardHeight];
} else if (_state == CLOSING) {
keyboardHeight = [self estimateClosingKeyboardHeight];
}
return keyboardHeight;
}
- (void)updateKeyboardFrame
{
bool isKeyboardAnimationRunning = [self hasAnyAnimation:_measuringView];
if (isKeyboardAnimationRunning) {
CGFloat keyboardHeight = [self getAnimatingKeyboardHeight];
[self runListeners:keyboardHeight];
}
}
- (void)keyboardWillChangeFrame:(NSNotification *)notification
{
NSDictionary *userInfo = [notification userInfo];
CGRect beginFrame = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect endFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval animationDuration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
auto window = [[[UIApplication sharedApplication] delegate] window];
/*
The keyboard frame is in the screen's coordinate space and must first be converted
to the window coordinate space in order to support Slide Over and Stage Manager on
iPadOS.
*/
beginFrame = [window convertRect:beginFrame fromCoordinateSpace:window.screen.coordinateSpace];
endFrame = [window convertRect:endFrame fromCoordinateSpace:window.screen.coordinateSpace];
/*
In some cases, such as when the user has enabled "prefer cross-fade transitions" or
when the keyboard is floating, the begin or end frame is an empty rectangle. In
such cases we should treat the keyboard as closed, rather than at (0, 0).
*/
CGRect beginFrameIntersection = CGRectIntersection(window.bounds, beginFrame);
_initialKeyboardHeight =
CGRectIsEmpty(beginFrameIntersection) ? 0 : CGRectGetMaxY(window.bounds) - CGRectGetMinY(beginFrameIntersection);
CGRect endFrameIntersection = CGRectIntersection(window.bounds, endFrame);
_targetKeyboardHeight =
CGRectIsEmpty(endFrameIntersection) ? 0 : CGRectGetMaxY(window.bounds) - CGRectGetMinY(endFrameIntersection);
bool forceAnimation = false;
auto keyboardView = [self getKeyboardView];
if (_state == CLOSING) {
_targetKeyboardHeight = 0;
} else if (_isInteractiveDismissalCanceled && keyboardView) {
// Prefer the keyboard view frame over notification frame which may not be current.
beginFrameIntersection = CGRectIntersection(window.bounds, keyboardView.frame);
_initialKeyboardHeight = CGRectIsEmpty(beginFrameIntersection)
? 0
: CGRectGetMaxY(window.bounds) - CGRectGetMinY(beginFrameIntersection);
forceAnimation = true;
}
_isInteractiveDismissalCanceled = false;
bool hasKeyboardAnimation = [self hasAnyAnimation:keyboardView];
if (hasKeyboardAnimation || forceAnimation) {
_measuringView.frame = CGRectMake(0, -1, 0, _initialKeyboardHeight);
[UIView animateWithDuration:animationDuration
animations:^{
self->_measuringView.frame = CGRectMake(0, -1, 0, self->_targetKeyboardHeight);
}];
[self runUpdater];
}
}
- (int)subscribeForKeyboardEvents:(KeyboardEventListenerBlock)listener
{
NSNumber *listenerId = [_nextListenerId copy];
_nextListenerId = [NSNumber numberWithInt:[_nextListenerId intValue] + 1];
RCTExecuteOnMainQueue(^() {
if (!self->_measuringView) {
self->_measuringView = [[UIView alloc] initWithFrame:CGRectMake(0, -1, 0, 0)];
UIWindow *keyWindow = [[[UIApplication sharedApplication] delegate] window];
[keyWindow addSubview:self->_measuringView];
}
if ([self->_listeners count] == 0) {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[notificationCenter addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[notificationCenter addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
[notificationCenter addObserver:self
selector:@selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
}
[self->_listeners setObject:listener forKey:listenerId];
});
return [listenerId intValue];
}
- (void)unsubscribeFromKeyboardEvents:(int)listenerId
{
RCTExecuteOnMainQueue(^() {
NSNumber *_listenerId = [NSNumber numberWithInt:listenerId];
[self->_listeners removeObjectForKey:_listenerId];
if ([self->_listeners count] == 0) {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[notificationCenter removeObserver:self name:UIKeyboardDidShowNotification object:nil];
[notificationCenter removeObserver:self name:UIKeyboardWillHideNotification object:nil];
[notificationCenter removeObserver:self name:UIKeyboardDidHideNotification object:nil];
}
});
}
- (void)cleanupListeners
{
RCTUnsafeExecuteOnMainQueueSync(^() {
[self->_listeners removeAllObjects];
[[self getDisplayLink] invalidate];
self->_displayLink = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
});
}
- (void)keyboardWillShow:(NSNotification *)notification
{
_state = OPENING;
[self keyboardWillChangeFrame:notification];
}
- (void)keyboardDidShow:(NSNotification *)notification
{
[[self getDisplayLink] setPaused:YES];
auto window = [[[UIApplication sharedApplication] delegate] window];
auto keyboardView = [self getKeyboardView];
if (keyboardView) {
CGRect frameIntersection = CGRectIntersection(window.bounds, keyboardView.frame);
_targetKeyboardHeight =
CGRectIsEmpty(frameIntersection) ? 0 : CGRectGetMaxY(window.bounds) - CGRectGetMinY(frameIntersection);
}
_state = OPEN;
[self runListeners:_targetKeyboardHeight];
if (_isKeyboardObserverAttached) {
return;
}
if (keyboardView) {
[_keyboardView addObserver:self
forKeyPath:@"center"
options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
context:nil];
_isKeyboardObserverAttached = true;
}
}
- (void)keyboardWillHide:(NSNotification *)notification
{
if (_isKeyboardObserverAttached) {
[_keyboardView removeObserver:self forKeyPath:@"center"];
_isKeyboardObserverAttached = false;
}
_state = CLOSING;
[self keyboardWillChangeFrame:notification];
}
- (void)keyboardDidHide:(NSNotification *)notification
{
[[self getDisplayLink] setPaused:YES];
_targetKeyboardHeight = 0;
_state = CLOSED;
[self runListeners:_targetKeyboardHeight];
}
- (void)updateKeyboardHeightDuringInteractiveDismiss:(CGPoint)oldKeyboardFrame
newKeyboardFrame:(CGPoint)newKeyboardFrame
{
auto keyboardView = [self getKeyboardView];
if (!keyboardView) {
return;
}
bool hasKeyboardAnimation = [self hasAnyAnimation:keyboardView];
float keyboardHeight = keyboardView.frame.size.height;
/*
If the keyboard is animating, height will be updated by the notification observers.
If the keyboard state is CLOSED, height is 0, or the keyboard is floating (keyboard
width != window width), don't update to prevent jumping to intermediate state.
*/
if (hasKeyboardAnimation || _state == CLOSED || keyboardHeight == 0 ||
CGRectGetWidth(keyboardView.frame) != CGRectGetWidth(keyboardView.window.bounds)) {
return;
}
float windowHeight = keyboardView.window.bounds.size.height;
float visibleKeyboardHeight = windowHeight - (newKeyboardFrame.y - keyboardHeight / 2);
if (oldKeyboardFrame.y > newKeyboardFrame.y) {
_state = OPENING;
_isInteractiveDismissalCanceled = true;
} else if (oldKeyboardFrame.y < newKeyboardFrame.y) {
_state = CLOSING;
_isInteractiveDismissalCanceled = false;
}
[self runListeners:visibleKeyboardHeight];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change
context:(void *)context
{
if ([keyPath isEqualToString:@"center"]) {
CGPoint oldKeyboardFrame = [change[NSKeyValueChangeOldKey] CGPointValue];
CGPoint newKeyboardFrame = [change[NSKeyValueChangeNewKey] CGPointValue];
[self updateKeyboardHeightDuringInteractiveDismiss:oldKeyboardFrame newKeyboardFrame:newKeyboardFrame];
}
}
- (bool)hasAnyAnimation:(REAUIView *)view
{
return view.layer.presentationLayer.animationKeys.count != 0;
;
}
- (REAUIView *_Nullable)findClass:(NSString *)className inViewsList:(NSArray<REAUIView *> *)viewList
{
for (UIWindow *view in viewList) {
if ([NSStringFromClass([view class]) isEqual:className]) {
return view;
}
}
return nil;
}
// Inspired by: https://stackoverflow.com/questions/32598490
- (REAUIView *_Nullable)getKeyboardView
{
if (_keyboardView) {
return _keyboardView;
}
NSArray<UIWindow *> *windows = [UIApplication sharedApplication].windows;
auto window = [self findClass:@"UITextEffectsWindow" inViewsList:windows];
auto keyboardContainer = [self findClass:@"UIInputSetContainerView" inViewsList:window.subviews];
_keyboardView = [self findClass:@"UIInputSetHostView" inViewsList:keyboardContainer.subviews];
return _keyboardView;
}
#endif
@end
@@ -1,19 +0,0 @@
#if __cplusplus
#import <reanimated/NativeModules/ReanimatedModuleProxy.h>
#import <reanimated/apple/REANodesManager.h>
#import <worklets/apple/WorkletsModule.h>
namespace reanimated {
std::shared_ptr<reanimated::ReanimatedModuleProxy> createReanimatedModuleProxy(
REANodesManager *nodesManager,
RCTModuleRegistry *moduleRegistry,
jsi::Runtime &rnRuntime,
const std::shared_ptr<facebook::react::CallInvoker> &jsInvoker,
WorkletsModule *workletsModule);
} // namespace reanimated
#endif //__cplusplus
@@ -1,56 +0,0 @@
#import <reanimated/Tools/PlatformDepMethodsHolder.h>
#import <reanimated/apple/REAAssertJavaScriptQueue.h>
#import <reanimated/apple/REAReducedMotion.h>
#import <reanimated/apple/native/NativeProxy.h>
#import <reanimated/apple/native/PlatformDepMethodsHolderImpl.h>
#import <reanimated/apple/native/REAJSIUtils.h>
@interface RCTBridge (JSIRuntime)
- (void *)runtime;
@end
namespace reanimated {
using namespace facebook;
using namespace react;
std::shared_ptr<ReanimatedModuleProxy> createReanimatedModuleProxy(
REANodesManager *nodesManager,
RCTModuleRegistry *moduleRegistry,
jsi::Runtime &rnRuntime,
const std::shared_ptr<CallInvoker> &jsInvoker,
WorkletsModule *workletsModule)
{
REAAssertJavaScriptQueue();
PlatformDepMethodsHolder platformDepMethodsHolder = makePlatformDepMethodsHolder(moduleRegistry, nodesManager);
const auto workletsModuleProxy = [workletsModule getWorkletsModuleProxy];
auto reanimatedModuleProxy = std::make_shared<ReanimatedModuleProxy>(
workletsModuleProxy, rnRuntime, jsInvoker, platformDepMethodsHolder, getIsReducedMotion());
reanimatedModuleProxy->init(platformDepMethodsHolder);
jsi::Runtime &uiRuntime = workletsModuleProxy->getUIWorkletRuntime()->getJSIRuntime();
[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::Value payload = convertObjCObjectToJSIValue(uiRuntime, eventData);
double currentTime = CACurrentMediaTime() * 1000;
reanimatedModuleProxy->handleEvent(eventName, emitterReactTag, payload, currentTime);
}];
std::weak_ptr<ReanimatedModuleProxy> weakReanimatedModuleProxy = reanimatedModuleProxy; // to avoid retain cycle
[nodesManager registerPerformOperations:^() {
if (auto reanimatedModuleProxy = weakReanimatedModuleProxy.lock()) {
reanimatedModuleProxy->performOperations();
}
}];
return reanimatedModuleProxy;
}
} // namespace reanimated
@@ -1,30 +0,0 @@
#if __cplusplus
#import <reanimated/apple/REANodesManager.h>
#import <reanimated/apple/ReanimatedModule.h>
#import <reanimated/apple/keyboardObserver/REAKeyboardEventObserver.h>
#import <reanimated/apple/sensor/ReanimatedSensorContainer.h>
namespace reanimated {
PlatformDepMethodsHolder makePlatformDepMethodsHolder(
RCTModuleRegistry *moduleRegistry,
REANodesManager *nodesManager);
SetGestureStateFunction makeSetGestureStateFunction(
RCTModuleRegistry *moduleRegistry);
RequestRenderFunction makeRequestRender(REANodesManager *nodesManager);
GetAnimationTimestampFunction makeGetAnimationTimestamp();
MaybeFlushUIUpdatesQueueFunction makeMaybeFlushUIUpdatesQueueFunction(
REANodesManager *nodesManager);
RegisterSensorFunction makeRegisterSensorFunction(
ReanimatedSensorContainer *reanimatedSensorContainer);
UnregisterSensorFunction makeUnregisterSensorFunction(
ReanimatedSensorContainer *reanimatedSensorContainer);
KeyboardEventSubscribeFunction makeSubscribeForKeyboardEventsFunction(
REAKeyboardEventObserver *keyboardObserver);
KeyboardEventUnsubscribeFunction makeUnsubscribeFromKeyboardEventsFunction(
REAKeyboardEventObserver *keyboardObserver);
} // namespace reanimated
#endif //__cplusplus
@@ -1,134 +0,0 @@
#import <reanimated/Tools/PlatformDepMethodsHolder.h>
#import <reanimated/apple/READisplayLink.h>
#import <reanimated/apple/REANodesManager.h>
#import <reanimated/apple/REASlowAnimations.h>
#import <reanimated/apple/RNGestureHandlerStateManager.h>
#import <reanimated/apple/keyboardObserver/REAKeyboardEventObserver.h>
#import <reanimated/apple/native/SetGestureState.h>
#import <reanimated/apple/sensor/ReanimatedSensorContainer.h>
namespace reanimated {
using namespace facebook;
using namespace react;
SetGestureStateFunction makeSetGestureStateFunction(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;
}
RequestRenderFunction makeRequestRender(REANodesManager *nodesManager)
{
auto requestRender = [nodesManager](std::function<void(double)> onRender) {
[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
const double frameTimestamp = calculateTimestampWithSlowAnimations(targetTimestamp) * 1000;
onRender(frameTimestamp);
}];
};
return requestRender;
}
GetAnimationTimestampFunction makeGetAnimationTimestamp()
{
auto getAnimationTimestamp = []() { return calculateTimestampWithSlowAnimations(CACurrentMediaTime()) * 1000; };
return getAnimationTimestamp;
}
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,
bool isNavigationBarTranslucent) {
// ignore isStatusBarTranslucent and isNavigationBarTranslucent - those are 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(RCTModuleRegistry *moduleRegistry, REANodesManager *nodesManager)
{
auto requestRender = makeRequestRender(nodesManager);
auto getAnimationTimestamp = makeGetAnimationTimestamp();
ReanimatedSensorContainer *reanimatedSensorContainer = [[ReanimatedSensorContainer alloc] init];
auto registerSensorFunction = makeRegisterSensorFunction(reanimatedSensorContainer);
auto unregisterSensorFunction = makeUnregisterSensorFunction(reanimatedSensorContainer);
auto setGestureStateFunction = makeSetGestureStateFunction(moduleRegistry);
REAKeyboardEventObserver *keyboardObserver = [[REAKeyboardEventObserver alloc] init];
auto subscribeForKeyboardEventsFunction = makeSubscribeForKeyboardEventsFunction(keyboardObserver);
auto unsubscribeFromKeyboardEventsFunction = makeUnsubscribeFromKeyboardEventsFunction(keyboardObserver);
auto maybeFlushUIUpdatesQueueFunction = makeMaybeFlushUIUpdatesQueueFunction(nodesManager);
PlatformDepMethodsHolder platformDepMethodsHolder = {
requestRender,
getAnimationTimestamp,
registerSensorFunction,
unregisterSensorFunction,
setGestureStateFunction,
subscribeForKeyboardEventsFunction,
unsubscribeFromKeyboardEventsFunction,
maybeFlushUIUpdatesQueueFunction,
};
return platformDepMethodsHolder;
}
} // namespace reanimated
@@ -1,64 +0,0 @@
#pragma once
#import <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, convertNSStringToJSIString(runtime, k), 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();
}
@@ -1,10 +0,0 @@
#import <reanimated/apple/RNGestureHandlerStateManager.h>
namespace reanimated {
void setGestureState(
id<RNGestureHandlerStateManager> gestureHandlerStateManager,
int handlerTag,
int newState);
} // namespace reanimated
@@ -1,12 +0,0 @@
#import <reanimated/apple/native/SetGestureState.h>
namespace reanimated {
void setGestureState(id<RNGestureHandlerStateManager> gestureHandlerStateManager, int handlerTag, int newState)
{
if (gestureHandlerStateManager != nil) {
[gestureHandlerStateManager setGestureState:newState forHandler:handlerTag];
}
}
} // namespace reanimated
@@ -1,30 +0,0 @@
#if !TARGET_OS_TV && !TARGET_OS_OSX
#import <CoreMotion/CoreMotion.h>
#endif
#import <reanimated/apple/sensor/ReanimatedSensorType.h>
@interface ReanimatedSensor : NSObject {
ReanimatedSensorType _sensorType;
double _interval;
double _lastTimestamp;
int _referenceFrame;
#if !TARGET_OS_TV && !TARGET_OS_OSX
CMMotionManager *_motionManager;
#endif
void (^_setter)(double[], int);
}
- (instancetype)init:(ReanimatedSensorType)sensorType
interval:(int)interval
iosReferenceFrame:(int)iosReferenceFrame
setter:(void (^)(double[], int))setter;
- (bool)initialize;
- (bool)initializeGyroscope;
- (bool)initializeAccelerometer;
- (bool)initializeGravity;
- (bool)initializeMagnetometer;
- (bool)initializeOrientation;
- (void)cancel;
@end
@@ -1,265 +0,0 @@
#import <reanimated/apple/sensor/ReanimatedSensor.h>
#if !TARGET_OS_TV && !TARGET_OS_OSX && !TARGET_OS_VISION
@implementation ReanimatedSensor
- (instancetype)init:(ReanimatedSensorType)sensorType
interval:(int)interval
iosReferenceFrame:(int)iosReferenceFrame
setter:(void (^)(double[], int))setter
{
self = [super init];
_sensorType = sensorType;
if (interval == -1) {
_interval = 1.0 / UIScreen.mainScreen.maximumFramesPerSecond;
} else {
_interval = interval / 1000.0; // in seconds
}
_referenceFrame = iosReferenceFrame;
_setter = setter;
_motionManager = [[CMMotionManager alloc] init];
return self;
}
- (bool)initialize
{
if (_sensorType == ACCELEROMETER) {
return [self initializeAccelerometer];
} else if (_sensorType == GYROSCOPE) {
return [self initializeGyroscope];
} else if (_sensorType == GRAVITY) {
return [self initializeGravity];
} else if (_sensorType == MAGNETIC_FIELD) {
return [self initializeMagnetometer];
} else if (_sensorType == ROTATION_VECTOR) {
return [self initializeOrientation];
}
return false;
}
- (bool)initializeGyroscope
{
if (![_motionManager isGyroAvailable]) {
return false;
}
[_motionManager setGyroUpdateInterval:_interval];
[_motionManager startGyroUpdates];
[_motionManager
startGyroUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler:^(CMGyroData *sensorData, NSError *error) {
double currentTime = CACurrentMediaTime() * 1000;
if (currentTime - self->_lastTimestamp < self->_interval) {
return;
}
double data[] = {sensorData.rotationRate.x, sensorData.rotationRate.y, sensorData.rotationRate.z};
self->_setter(data, [self getInterfaceOrientation]);
self->_lastTimestamp = currentTime;
}];
return true;
}
- (bool)initializeAccelerometer
{
if (![_motionManager isAccelerometerAvailable]) {
return false;
}
[_motionManager setAccelerometerUpdateInterval:_interval];
[_motionManager startAccelerometerUpdates];
[_motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler:^(CMAccelerometerData *sensorData, NSError *error) {
double currentTime = CACurrentMediaTime() * 1000;
if (currentTime - self->_lastTimestamp < self->_interval) {
return;
}
double G = 9.81;
// convert G to m/s^2
double data[] = {
sensorData.acceleration.x * G,
sensorData.acceleration.y * G,
sensorData.acceleration.z * G};
self->_setter(data, [self getInterfaceOrientation]);
self->_lastTimestamp = currentTime;
}];
return true;
}
- (bool)initializeGravity
{
if (![_motionManager isDeviceMotionAvailable]) {
return false;
}
[_motionManager setDeviceMotionUpdateInterval:_interval];
[_motionManager setShowsDeviceMovementDisplay:YES];
[_motionManager
startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler:^(CMDeviceMotion *sensorData, NSError *error) {
double currentTime = CACurrentMediaTime() * 1000;
if (currentTime - self->_lastTimestamp < self->_interval) {
return;
}
double G = 9.81;
// convert G to m/s^2
double data[] = {
sensorData.gravity.x * G, sensorData.gravity.y * G, sensorData.gravity.z * G};
self->_setter(data, [self getInterfaceOrientation]);
self->_lastTimestamp = currentTime;
}];
return true;
}
- (bool)initializeMagnetometer
{
if (![_motionManager isMagnetometerAvailable]) {
return false;
}
[_motionManager setMagnetometerUpdateInterval:_interval];
[_motionManager startMagnetometerUpdates];
[_motionManager
startMagnetometerUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler:^(CMMagnetometerData *sensorData, NSError *error) {
double currentTime = CACurrentMediaTime() * 1000;
if (currentTime - self->_lastTimestamp < self->_interval) {
return;
}
double data[] = {
sensorData.magneticField.x, sensorData.magneticField.y, sensorData.magneticField.z};
self->_setter(data, [self getInterfaceOrientation]);
self->_lastTimestamp = currentTime;
}];
return true;
}
- (bool)initializeOrientation
{
if (![_motionManager isDeviceMotionAvailable]) {
return false;
}
[_motionManager setDeviceMotionUpdateInterval:_interval];
[_motionManager setShowsDeviceMovementDisplay:YES];
// _referenceFrame = Auto, on devices without magnetometer fall back to `XArbitraryZVertical`,
// `XArbitraryCorrectedZVertical` otherwise
if (_referenceFrame == 4) {
if (![_motionManager isMagnetometerAvailable]) {
_referenceFrame = 0;
} else {
_referenceFrame = 1;
}
}
// the binary shift works here because of the definition of CMAttitudeReferenceFrame
[_motionManager startDeviceMotionUpdatesUsingReferenceFrame:(1 << _referenceFrame)
toQueue:[NSOperationQueue mainQueue]
withHandler:^(CMDeviceMotion *sensorData, NSError *error) {
double currentTime = CACurrentMediaTime() * 1000;
if (currentTime - self->_lastTimestamp < self->_interval) {
return;
}
CMAttitude *attitude = sensorData.attitude;
double data[] = {
attitude.quaternion.x,
attitude.quaternion.y,
attitude.quaternion.z,
attitude.quaternion.w,
attitude.yaw,
attitude.pitch,
attitude.roll};
self->_setter(data, [self getInterfaceOrientation]);
self->_lastTimestamp = currentTime;
}];
return true;
}
- (void)cancel
{
if (_sensorType == ACCELEROMETER) {
[_motionManager stopAccelerometerUpdates];
} else if (_sensorType == GYROSCOPE) {
[_motionManager stopGyroUpdates];
} else if (_sensorType == GRAVITY) {
[_motionManager stopDeviceMotionUpdates];
} else if (_sensorType == MAGNETIC_FIELD) {
[_motionManager stopMagnetometerUpdates];
} else if (_sensorType == ROTATION_VECTOR) {
[_motionManager stopDeviceMotionUpdates];
}
}
- (int)getInterfaceOrientation
{
UIInterfaceOrientation orientation = UIInterfaceOrientationPortrait;
if (@available(iOS 13.0, *)) {
orientation = UIApplication.sharedApplication.windows.firstObject.windowScene.interfaceOrientation;
} else {
orientation = UIApplication.sharedApplication.statusBarOrientation;
}
switch (orientation) {
case UIInterfaceOrientationLandscapeLeft:
return 270;
case UIInterfaceOrientationLandscapeRight:
return 90;
case UIInterfaceOrientationPortraitUpsideDown:
return 180;
default:
return 0;
}
}
@end
#else
@implementation ReanimatedSensor
- (instancetype)init:(ReanimatedSensorType)sensorType
interval:(int)interval
iosReferenceFrame:(int)iosReferenceFrame
setter:(void (^)(double[], int))setter
{
self = [super init];
return self;
}
- (bool)initialize
{
return false;
}
- (bool)initializeGyroscope
{
return false;
}
- (bool)initializeAccelerometer
{
return false;
}
- (bool)initializeGravity
{
return false;
}
- (bool)initializeMagnetometer
{
return false;
}
- (bool)initializeOrientation
{
return false;
}
- (void)cancel
{
}
@end
#endif
@@ -1,15 +0,0 @@
#import <reanimated/apple/sensor/ReanimatedSensorType.h>
@interface ReanimatedSensorContainer : NSObject {
NSNumber *_nextSensorId;
NSMutableDictionary *_sensors;
}
- (instancetype)init;
- (int)registerSensor:(ReanimatedSensorType)sensorType
interval:(int)interval
iosReferenceFrame:(int)iosReferenceFrame
setter:(void (^)(double[], int))setter;
- (void)unregisterSensor:(int)sensorId;
@end
@@ -1,46 +0,0 @@
#import <Foundation/Foundation.h>
#import <reanimated/apple/sensor/ReanimatedSensor.h>
#import <reanimated/apple/sensor/ReanimatedSensorContainer.h>
static NSNumber *_nextSensorId = nil;
@implementation ReanimatedSensorContainer
- (instancetype)init
{
self = [super init];
_sensors = [[NSMutableDictionary alloc] init];
_nextSensorId = @0;
return self;
}
- (int)registerSensor:(ReanimatedSensorType)sensorType
interval:(int)interval
iosReferenceFrame:(int)iosReferenceFrame
setter:(void (^)(double[], int))setter
{
ReanimatedSensor *sensor = [[ReanimatedSensor alloc] init:sensorType
interval:interval
iosReferenceFrame:iosReferenceFrame
setter:setter];
if ([sensor initialize]) {
NSNumber *sensorId = [_nextSensorId copy];
_nextSensorId = [NSNumber numberWithInt:[_nextSensorId intValue] + 1];
[_sensors setObject:sensor forKey:sensorId];
return [sensorId intValue];
} else {
return -1;
}
}
- (void)unregisterSensor:(int)sensorId
{
NSNumber *_sensorId = [NSNumber numberWithInt:sensorId];
if (_sensors[_sensorId] == nil) {
return;
}
[_sensors[_sensorId] cancel];
[_sensors removeObjectForKey:_sensorId];
}
@end
@@ -1,7 +0,0 @@
typedef NS_ENUM(NSUInteger, ReanimatedSensorType) {
ACCELEROMETER = 1,
GYROSCOPE = 2,
GRAVITY = 3,
MAGNETIC_FIELD = 4,
ROTATION_VECTOR = 5,
};