1/* 2 * Copyright (c) Meta Platforms, Inc. and affiliates. 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 */ 7 8#import <ABI48_0_0FBReactNativeSpec/ABI48_0_0FBReactNativeSpec.h> 9#import <ABI48_0_0React/ABI48_0_0RCTInitializing.h> 10#import <ABI48_0_0React/ABI48_0_0RCTLog.h> 11#import <ABI48_0_0React/ABI48_0_0RCTNativeAnimatedModule.h> 12#import <ABI48_0_0React/ABI48_0_0RCTNativeAnimatedNodesManager.h> 13 14#import <ABI48_0_0RCTTypeSafety/ABI48_0_0RCTConvertHelpers.h> 15 16#import "ABI48_0_0RCTAnimationPlugins.h" 17 18typedef void (^AnimatedOperation)(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager); 19 20@interface ABI48_0_0RCTNativeAnimatedModule () <ABI48_0_0RCTInitializing> 21@end 22 23@implementation ABI48_0_0RCTNativeAnimatedModule { 24 ABI48_0_0RCTNativeAnimatedNodesManager *_nodesManager; 25 26 // Operations called after views have been updated. 27 NSMutableArray<AnimatedOperation> *_operations; 28 // Operations called before views have been updated. 29 NSMutableArray<AnimatedOperation> *_preOperations; 30 NSMutableDictionary<NSNumber *, NSNumber *> *_animIdIsManagedByFabric; 31} 32 33ABI48_0_0RCT_EXPORT_MODULE(); 34 35+ (BOOL)requiresMainQueueSetup 36{ 37 return NO; 38} 39 40- (instancetype)init 41{ 42 if (self = [super init]) { 43 _operations = [NSMutableArray new]; 44 _preOperations = [NSMutableArray new]; 45 _animIdIsManagedByFabric = [NSMutableDictionary new]; 46 } 47 return self; 48} 49 50- (void)invalidate 51{ 52 [super invalidate]; 53 [_nodesManager stopAnimationLoop]; 54 [[self.moduleRegistry moduleForName:"EventDispatcher"] removeDispatchObserver:self]; 55 [self.bridge.uiManager.observerCoordinator removeObserver:self]; 56 [self.bridge.surfacePresenter removeObserver:self]; 57} 58 59- (dispatch_queue_t)methodQueue 60{ 61 // This module needs to be on the same queue as the UIManager to avoid 62 // having to lock `_operations` and `_preOperations` since `uiManagerWillPerformMounting` 63 // will be called from that queue. 64 return ABI48_0_0RCTGetUIManagerQueue(); 65} 66 67- (void)setBridge:(ABI48_0_0RCTBridge *)bridge 68{ 69 [super setBridge:bridge]; 70 _nodesManager = [[ABI48_0_0RCTNativeAnimatedNodesManager alloc] initWithBridge:self.bridge 71 surfacePresenter:bridge.surfacePresenter]; 72 [bridge.uiManager.observerCoordinator addObserver:self]; 73 [bridge.surfacePresenter addObserver:self]; 74} 75 76- (void)initialize 77{ 78 [[self.moduleRegistry moduleForName:"EventDispatcher"] addDispatchObserver:self]; 79} 80 81/* 82 * This selector should only be invoked in bridgeless mode, which is not compatible with this non turbo module. 83 */ 84- (void)setSurfacePresenter:(id<ABI48_0_0RCTSurfacePresenterStub>)surfacePresenter 85{ 86 ABI48_0_0RCTLogWarn(@"setSurfacePresenter should only be invoked in ABI48_0_0RCTNativeAnimatedTurboModule"); 87} 88 89#pragma mark-- API 90 91ABI48_0_0RCT_EXPORT_METHOD(createAnimatedNode : (double)tag config : (NSDictionary<NSString *, id> *)config) 92{ 93 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 94 [nodesManager createAnimatedNode:[NSNumber numberWithDouble:tag] config:config]; 95 }]; 96} 97 98ABI48_0_0RCT_EXPORT_METHOD(updateAnimatedNodeConfig : (double)tag config : (NSDictionary<NSString *, id> *)config) 99{ 100 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 101 [nodesManager updateAnimatedNodeConfig:[NSNumber numberWithDouble:tag] config:config]; 102 }]; 103} 104 105ABI48_0_0RCT_EXPORT_METHOD(connectAnimatedNodes : (double)parentTag childTag : (double)childTag) 106{ 107 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 108 [nodesManager connectAnimatedNodes:[NSNumber numberWithDouble:parentTag] 109 childTag:[NSNumber numberWithDouble:childTag]]; 110 }]; 111} 112 113ABI48_0_0RCT_EXPORT_METHOD(disconnectAnimatedNodes : (double)parentTag childTag : (double)childTag) 114{ 115 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 116 [nodesManager disconnectAnimatedNodes:[NSNumber numberWithDouble:parentTag] 117 childTag:[NSNumber numberWithDouble:childTag]]; 118 }]; 119} 120 121ABI48_0_0RCT_EXPORT_METHOD(startAnimatingNode 122 : (double)animationId nodeTag 123 : (double)nodeTag config 124 : (NSDictionary<NSString *, id> *)config endCallback 125 : (ABI48_0_0RCTResponseSenderBlock)callBack) 126{ 127 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 128 [nodesManager startAnimatingNode:[NSNumber numberWithDouble:animationId] 129 nodeTag:[NSNumber numberWithDouble:nodeTag] 130 config:config 131 endCallback:callBack]; 132 }]; 133 134 ABI48_0_0RCTExecuteOnMainQueue(^{ 135 if (![self->_nodesManager isNodeManagedByFabric:[NSNumber numberWithDouble:nodeTag]]) { 136 return; 137 } 138 139 ABI48_0_0RCTExecuteOnUIManagerQueue(^{ 140 self->_animIdIsManagedByFabric[[NSNumber numberWithDouble:animationId]] = @YES; 141 [self flushOperationQueues]; 142 }); 143 }); 144} 145 146ABI48_0_0RCT_EXPORT_METHOD(stopAnimation : (double)animationId) 147{ 148 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 149 [nodesManager stopAnimation:[NSNumber numberWithDouble:animationId]]; 150 }]; 151 if ([_animIdIsManagedByFabric[[NSNumber numberWithDouble:animationId]] boolValue]) { 152 [self flushOperationQueues]; 153 } 154} 155 156ABI48_0_0RCT_EXPORT_METHOD(setAnimatedNodeValue : (double)nodeTag value : (double)value) 157{ 158 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 159 [nodesManager setAnimatedNodeValue:[NSNumber numberWithDouble:nodeTag] value:[NSNumber numberWithDouble:value]]; 160 }]; 161} 162 163ABI48_0_0RCT_EXPORT_METHOD(setAnimatedNodeOffset : (double)nodeTag offset : (double)offset) 164{ 165 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 166 [nodesManager setAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag] offset:[NSNumber numberWithDouble:offset]]; 167 }]; 168} 169 170ABI48_0_0RCT_EXPORT_METHOD(flattenAnimatedNodeOffset : (double)nodeTag) 171{ 172 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 173 [nodesManager flattenAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag]]; 174 }]; 175} 176 177ABI48_0_0RCT_EXPORT_METHOD(extractAnimatedNodeOffset : (double)nodeTag) 178{ 179 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 180 [nodesManager extractAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag]]; 181 }]; 182} 183 184ABI48_0_0RCT_EXPORT_METHOD(connectAnimatedNodeToView : (double)nodeTag viewTag : (double)viewTag) 185{ 186 NSString *viewName = [self.bridge.uiManager viewNameForABI48_0_0ReactTag:[NSNumber numberWithDouble:viewTag]]; 187 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 188 [nodesManager connectAnimatedNodeToView:[NSNumber numberWithDouble:nodeTag] 189 viewTag:[NSNumber numberWithDouble:viewTag] 190 viewName:viewName]; 191 }]; 192} 193 194ABI48_0_0RCT_EXPORT_METHOD(disconnectAnimatedNodeFromView : (double)nodeTag viewTag : (double)viewTag) 195{ 196 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 197 [nodesManager disconnectAnimatedNodeFromView:[NSNumber numberWithDouble:nodeTag] 198 viewTag:[NSNumber numberWithDouble:viewTag]]; 199 }]; 200} 201 202ABI48_0_0RCT_EXPORT_METHOD(restoreDefaultValues : (double)nodeTag) 203{ 204 [self addPreOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 205 [nodesManager restoreDefaultValues:[NSNumber numberWithDouble:nodeTag]]; 206 }]; 207} 208 209ABI48_0_0RCT_EXPORT_METHOD(dropAnimatedNode : (double)tag) 210{ 211 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 212 [nodesManager dropAnimatedNode:[NSNumber numberWithDouble:tag]]; 213 }]; 214} 215 216ABI48_0_0RCT_EXPORT_METHOD(startListeningToAnimatedNodeValue : (double)tag) 217{ 218 __weak id<ABI48_0_0RCTValueAnimatedNodeObserver> valueObserver = self; 219 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 220 [nodesManager startListeningToAnimatedNodeValue:[NSNumber numberWithDouble:tag] valueObserver:valueObserver]; 221 }]; 222} 223 224ABI48_0_0RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue : (double)tag) 225{ 226 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 227 [nodesManager stopListeningToAnimatedNodeValue:[NSNumber numberWithDouble:tag]]; 228 }]; 229} 230 231ABI48_0_0RCT_EXPORT_METHOD(addAnimatedEventToView 232 : (double)viewTag eventName 233 : (nonnull NSString *)eventName eventMapping 234 : (ABI48_0_0JS::NativeAnimatedModule::EventMapping &)eventMapping) 235{ 236 NSMutableDictionary *eventMappingDict = [NSMutableDictionary new]; 237 eventMappingDict[@"nativeEventPath"] = ABI48_0_0RCTConvertVecToArray(eventMapping.nativeEventPath()); 238 239 if (eventMapping.animatedValueTag()) { 240 eventMappingDict[@"animatedValueTag"] = @(*eventMapping.animatedValueTag()); 241 } 242 243 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 244 [nodesManager addAnimatedEventToView:[NSNumber numberWithDouble:viewTag] 245 eventName:eventName 246 eventMapping:eventMappingDict]; 247 }]; 248} 249 250ABI48_0_0RCT_EXPORT_METHOD(removeAnimatedEventFromView 251 : (double)viewTag eventName 252 : (nonnull NSString *)eventName animatedNodeTag 253 : (double)animatedNodeTag) 254{ 255 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 256 [nodesManager removeAnimatedEventFromView:[NSNumber numberWithDouble:viewTag] 257 eventName:eventName 258 animatedNodeTag:[NSNumber numberWithDouble:animatedNodeTag]]; 259 }]; 260} 261 262ABI48_0_0RCT_EXPORT_METHOD(getValue : (double)nodeTag saveValueCallback : (ABI48_0_0RCTResponseSenderBlock)saveValueCallback) 263{ 264 [self addOperationBlock:^(ABI48_0_0RCTNativeAnimatedNodesManager *nodesManager) { 265 [nodesManager getValue:[NSNumber numberWithDouble:nodeTag] saveCallback:saveValueCallback]; 266 }]; 267} 268 269ABI48_0_0RCT_EXPORT_METHOD(queueAndExecuteBatchedOperations : (NSArray *)operationsAndArgs) 270{ 271 // TODO: implement in the future if we want the same optimization here as on Android 272} 273 274#pragma mark-- Batch handling 275 276- (void)addOperationBlock:(AnimatedOperation)operation 277{ 278 [_operations addObject:operation]; 279} 280 281- (void)addPreOperationBlock:(AnimatedOperation)operation 282{ 283 [_preOperations addObject:operation]; 284} 285 286- (void)flushOperationQueues 287{ 288 if (_preOperations.count == 0 && _operations.count == 0) { 289 return; 290 } 291 NSArray<AnimatedOperation> *preOperations = _preOperations; 292 NSArray<AnimatedOperation> *operations = _operations; 293 _preOperations = [NSMutableArray new]; 294 _operations = [NSMutableArray new]; 295 296 ABI48_0_0RCTExecuteOnMainQueue(^{ 297 for (AnimatedOperation operation in preOperations) { 298 operation(self->_nodesManager); 299 } 300 for (AnimatedOperation operation in operations) { 301 operation(self->_nodesManager); 302 } 303 [self->_nodesManager updateAnimations]; 304 }); 305} 306 307#pragma mark - ABI48_0_0RCTSurfacePresenterObserver 308 309- (void)willMountComponentsWithRootTag:(NSInteger)rootTag 310{ 311 ABI48_0_0RCTAssertMainQueue(); 312 ABI48_0_0RCTExecuteOnUIManagerQueue(^{ 313 NSArray<AnimatedOperation> *preOperations = self->_preOperations; 314 self->_preOperations = [NSMutableArray new]; 315 316 ABI48_0_0RCTExecuteOnMainQueue(^{ 317 for (AnimatedOperation preOperation in preOperations) { 318 preOperation(self->_nodesManager); 319 } 320 }); 321 }); 322} 323 324- (void)didMountComponentsWithRootTag:(NSInteger)rootTag 325{ 326 ABI48_0_0RCTAssertMainQueue(); 327 ABI48_0_0RCTExecuteOnUIManagerQueue(^{ 328 NSArray<AnimatedOperation> *operations = self->_operations; 329 self->_operations = [NSMutableArray new]; 330 331 ABI48_0_0RCTExecuteOnMainQueue(^{ 332 for (AnimatedOperation operation in operations) { 333 operation(self->_nodesManager); 334 } 335 }); 336 }); 337} 338 339#pragma mark - ABI48_0_0RCTUIManagerObserver 340 341- (void)uiManagerWillPerformMounting:(ABI48_0_0RCTUIManager *)uiManager 342{ 343 if (_preOperations.count == 0 && _operations.count == 0) { 344 return; 345 } 346 347 NSArray<AnimatedOperation> *preOperations = _preOperations; 348 NSArray<AnimatedOperation> *operations = _operations; 349 _preOperations = [NSMutableArray new]; 350 _operations = [NSMutableArray new]; 351 352 [uiManager 353 prependUIBlock:^(__unused ABI48_0_0RCTUIManager *manager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) { 354 for (AnimatedOperation operation in preOperations) { 355 operation(self->_nodesManager); 356 } 357 }]; 358 [uiManager addUIBlock:^(__unused ABI48_0_0RCTUIManager *manager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) { 359 for (AnimatedOperation operation in operations) { 360 operation(self->_nodesManager); 361 } 362 363 [self->_nodesManager updateAnimations]; 364 }]; 365} 366 367#pragma mark-- Events 368 369- (NSArray<NSString *> *)supportedEvents 370{ 371 return @[ @"onAnimatedValueUpdate" ]; 372} 373 374- (void)animatedNode:(ABI48_0_0RCTValueAnimatedNode *)node didUpdateValue:(CGFloat)value 375{ 376 [self sendEventWithName:@"onAnimatedValueUpdate" body:@{@"tag" : node.nodeTag, @"value" : @(value)}]; 377} 378 379- (void)eventDispatcherWillDispatchEvent:(id<ABI48_0_0RCTEvent>)event 380{ 381 // Events can be dispatched from any queue so we have to make sure handleAnimatedEvent 382 // is run from the main queue. 383 ABI48_0_0RCTExecuteOnMainQueue(^{ 384 [self->_nodesManager handleAnimatedEvent:event]; 385 }); 386} 387 388@end 389 390Class ABI48_0_0RCTNativeAnimatedModuleCls(void) 391{ 392 return ABI48_0_0RCTNativeAnimatedModule.class; 393} 394