From 4fe0fab51fc9801d2dc5b7c85469ace0a8a969c9 Mon Sep 17 00:00:00 2001 From: yogevbd Date: Mon, 4 Dec 2017 11:54:31 +0200 Subject: [PATCH 1/4] async await for push and showModal --- lib/ios/RNNBridgeModule.m | 12 ++++++++---- lib/ios/RNNCommandsHandler.h | 4 ++-- lib/ios/RNNCommandsHandler.m | 8 ++++---- lib/ios/RNNModalManager.h | 2 +- lib/ios/RNNModalManager.m | 6 ++++-- lib/ios/RNNNavigationStackManager.h | 2 +- lib/ios/RNNNavigationStackManager.m | 11 ++++++++++- lib/ios/RNNStore.h | 2 ++ .../RNNCommandsHandlerTest.m | 8 ++++---- lib/src/adapters/NativeCommandsSender.js | 10 ++++++---- 10 files changed, 42 insertions(+), 23 deletions(-) diff --git a/lib/ios/RNNBridgeModule.m b/lib/ios/RNNBridgeModule.m index f3d8beec929..e9ee2dd3b4d 100644 --- a/lib/ios/RNNBridgeModule.m +++ b/lib/ios/RNNBridgeModule.m @@ -26,8 +26,10 @@ -(instancetype)initWithCommandsHandler:(RNNCommandsHandler *)commandsHandler { [_commandsHandler setOptions:containerId options:options]; } -RCT_EXPORT_METHOD(push:(NSString*)containerId layout:(NSDictionary*)layout) { - [_commandsHandler push:containerId layout:layout]; +RCT_EXPORT_METHOD(push:(NSString*)containerId layout:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { + [_commandsHandler push:containerId layout:layout completion:^(id result) { + resolve(result); + }]; } RCT_EXPORT_METHOD(pop:(NSString*)containerId) { @@ -42,8 +44,10 @@ -(instancetype)initWithCommandsHandler:(RNNCommandsHandler *)commandsHandler { [_commandsHandler popToRoot:containerId]; } -RCT_EXPORT_METHOD(showModal:(NSDictionary*)layout) { - [_commandsHandler showModal:layout]; +RCT_EXPORT_METHOD(showModal:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { + [_commandsHandler showModal:layout completion:^(id result) { + resolve(result); + }]; } RCT_EXPORT_METHOD(dismissModal:(NSString*)containerId) { diff --git a/lib/ios/RNNCommandsHandler.h b/lib/ios/RNNCommandsHandler.h index c8fa88be07c..3acae4cfbcb 100644 --- a/lib/ios/RNNCommandsHandler.h +++ b/lib/ios/RNNCommandsHandler.h @@ -12,7 +12,7 @@ -(void) setOptions:(NSString*)containerId options:(NSDictionary*)options; --(void) push:(NSString*)containerId layout:(NSDictionary*)layout; +-(void) push:(NSString*)containerId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion; -(void) pop:(NSString*)containerId; @@ -20,7 +20,7 @@ -(void) popToRoot:(NSString*)containerId; --(void) showModal:(NSDictionary*)layout; +-(void) showModal:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion; -(void) dismissModal:(NSString*)containerId; diff --git a/lib/ios/RNNCommandsHandler.m b/lib/ios/RNNCommandsHandler.m index 99a899cdd25..bf3d4b6f606 100644 --- a/lib/ios/RNNCommandsHandler.m +++ b/lib/ios/RNNCommandsHandler.m @@ -47,11 +47,11 @@ -(void) setOptions:(NSString*)containerId options:(NSDictionary*)options { } } --(void) push:(NSString*)containerId layout:(NSDictionary*)layout { +-(void) push:(NSString*)containerId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion { [self assertReady]; UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout]; - [_navigationStackManager push:newVc onTop:containerId]; + [_navigationStackManager push:newVc onTop:containerId completion:completion]; } -(void) pop:(NSString*)containerId { @@ -72,11 +72,11 @@ -(void) popToRoot:(NSString*)containerId { [_navigationStackManager popToRoot:containerId]; } --(void) showModal:(NSDictionary*)layout { +-(void) showModal:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion { [self assertReady]; UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout]; - [_modalManager showModal:newVc]; + [_modalManager showModal:newVc completion:completion]; } -(void) dismissModal:(NSString*)containerId { diff --git a/lib/ios/RNNModalManager.h b/lib/ios/RNNModalManager.h index 93e201718ee..71b4a80499d 100644 --- a/lib/ios/RNNModalManager.h +++ b/lib/ios/RNNModalManager.h @@ -6,7 +6,7 @@ -(instancetype)initWithStore:(RNNStore*)store; --(void)showModal:(UIViewController*)viewController; +-(void)showModal:(UIViewController*)viewController completion:(RNNTransitionCompletionBlock)completion; -(void)dismissModal:(NSString*)containerId; -(void)dismissAllModals; diff --git a/lib/ios/RNNModalManager.m b/lib/ios/RNNModalManager.m index a5bcdc31533..9e9c05c039c 100644 --- a/lib/ios/RNNModalManager.m +++ b/lib/ios/RNNModalManager.m @@ -12,9 +12,11 @@ -(instancetype)initWithStore:(RNNStore*)store { return self; } --(void)showModal:(UIViewController *)viewController { +-(void)showModal:(UIViewController *)viewController completion:(RNNTransitionCompletionBlock)completion { UIViewController *topVC = [self topPresentedVC]; - [topVC presentViewController:viewController animated:YES completion:nil]; + [topVC presentViewController:viewController animated:YES completion:^{ + completion(@(YES)); + }]; } -(void)dismissModal:(NSString *)containerId { diff --git a/lib/ios/RNNNavigationStackManager.h b/lib/ios/RNNNavigationStackManager.h index 677bf979bc1..929c1eb031b 100644 --- a/lib/ios/RNNNavigationStackManager.h +++ b/lib/ios/RNNNavigationStackManager.h @@ -6,7 +6,7 @@ -(instancetype)initWithStore:(RNNStore*)store; --(void)push:(UIViewController*)newTop onTop:(NSString*)containerId; +-(void)push:(UIViewController*)newTop onTop:(NSString*)containerId completion:(RNNTransitionCompletionBlock)completion; -(void)pop:(NSString*)containerId; -(void)popTo:(NSString*)containerId; -(void)popToRoot:(NSString*)containerId; diff --git a/lib/ios/RNNNavigationStackManager.m b/lib/ios/RNNNavigationStackManager.m index f440eb0d094..39125658d18 100644 --- a/lib/ios/RNNNavigationStackManager.m +++ b/lib/ios/RNNNavigationStackManager.m @@ -11,9 +11,18 @@ -(instancetype)initWithStore:(RNNStore*)store { return self; } --(void)push:(UIViewController *)newTop onTop:(NSString *)containerId { +-(void)push:(UIViewController *)newTop onTop:(NSString *)containerId completion:(RNNTransitionCompletionBlock)completion { UIViewController *vc = [_store findContainerForId:containerId]; + [CATransaction begin]; + [CATransaction setCompletionBlock:^{ + if (completion) { + completion(containerId); + } + }]; + [[vc navigationController] pushViewController:newTop animated:YES]; + + [CATransaction commit]; } -(void)pop:(NSString *)containerId { diff --git a/lib/ios/RNNStore.h b/lib/ios/RNNStore.h index b9d82a99756..910a8978137 100644 --- a/lib/ios/RNNStore.h +++ b/lib/ios/RNNStore.h @@ -3,6 +3,8 @@ #import #import "RNNRootViewController.h" +typedef void (^RNNTransitionCompletionBlock)(id result); + @interface RNNStore : NSObject -(UIViewController*) findContainerForId:(NSString*)containerId; diff --git a/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m b/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m index 580a04ba0c8..64453b10d4f 100644 --- a/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m +++ b/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m @@ -27,10 +27,10 @@ - (void)testAssertReadyForEachMethodThrowsExceptoins { for (NSString* methodName in methods) { SEL s = NSSelectorFromString(methodName); - NSMethodSignature* signature = [self.uut methodSignatureForSelector:s]; - NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; - invocation.selector = s; - XCTAssertThrowsSpecificNamed([invocation invokeWithTarget:self.uut], NSException, @"BridgeNotLoadedError"); + IMP imp = [uut methodForSelector:s]; + void (*func)(id, SEL, id, id, id) = (void *)imp; + + XCTAssertThrowsSpecificNamed(func(uut,s, nil, nil, nil), NSException, @"BridgeNotLoadedError"); } } diff --git a/lib/src/adapters/NativeCommandsSender.js b/lib/src/adapters/NativeCommandsSender.js index 8c493a287bf..c93a58047bb 100644 --- a/lib/src/adapters/NativeCommandsSender.js +++ b/lib/src/adapters/NativeCommandsSender.js @@ -13,8 +13,9 @@ class NativeCommandsSender { this.nativeCommandsModule.setOptions(containerId, options); } - push(onContainerId, layout) { - return this.nativeCommandsModule.push(onContainerId, layout); + async push(onContainerId, layout) { + const pushedContainerId = await this.nativeCommandsModule.push(onContainerId, layout); + return pushedContainerId; } pop(containerId) { @@ -29,8 +30,9 @@ class NativeCommandsSender { return this.nativeCommandsModule.popToRoot(containerId); } - showModal(layout) { - return this.nativeCommandsModule.showModal(layout); + async showModal(layout) { + const completed = await this.nativeCommandsModule.showModal(layout); + return completed; } dismissModal(containerId) { From e3c9b31df62b6ae31d0a5f0f8551728f3a26ba5c Mon Sep 17 00:00:00 2001 From: yogevbd Date: Mon, 4 Dec 2017 11:54:31 +0200 Subject: [PATCH 2/4] async await for push and showModal --- lib/ios/RNNBridgeModule.m | 12 +++++++---- lib/ios/RNNCommandsHandler.h | 4 ++-- lib/ios/RNNCommandsHandler.m | 10 +++++----- lib/ios/RNNModalManager.h | 2 +- lib/ios/RNNModalManager.m | 2 +- lib/ios/RNNNavigationStackManager.h | 2 +- lib/ios/RNNNavigationStackManager.m | 20 +++++++++++++++---- lib/ios/RNNStore.h | 2 ++ .../RNNCommandsHandlerTest.m | 8 ++++---- lib/src/adapters/NativeCommandsSender.js | 10 ++++++---- 10 files changed, 46 insertions(+), 26 deletions(-) diff --git a/lib/ios/RNNBridgeModule.m b/lib/ios/RNNBridgeModule.m index 533a0415f94..fb106f77190 100644 --- a/lib/ios/RNNBridgeModule.m +++ b/lib/ios/RNNBridgeModule.m @@ -26,8 +26,10 @@ -(instancetype)initWithCommandsHandler:(RNNCommandsHandler *)commandsHandler { [_commandsHandler setOptions:containerId options:options]; } -RCT_EXPORT_METHOD(push:(NSString*)containerId layout:(NSDictionary*)layout) { - [_commandsHandler push:containerId layout:layout]; +RCT_EXPORT_METHOD(push:(NSString*)containerId layout:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { + [_commandsHandler push:containerId layout:layout completion:^(id result) { + resolve(result); + }]; } RCT_EXPORT_METHOD(pop:(NSString*)containerId options:(NSDictionary*)options) { @@ -42,8 +44,10 @@ -(instancetype)initWithCommandsHandler:(RNNCommandsHandler *)commandsHandler { [_commandsHandler popToRoot:containerId]; } -RCT_EXPORT_METHOD(showModal:(NSDictionary*)layout) { - [_commandsHandler showModal:layout]; +RCT_EXPORT_METHOD(showModal:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { + [_commandsHandler showModal:layout completion:^(id result) { + resolve(result); + }]; } RCT_EXPORT_METHOD(dismissModal:(NSString*)containerId) { diff --git a/lib/ios/RNNCommandsHandler.h b/lib/ios/RNNCommandsHandler.h index 522208a3ae5..25013402bad 100644 --- a/lib/ios/RNNCommandsHandler.h +++ b/lib/ios/RNNCommandsHandler.h @@ -12,7 +12,7 @@ -(void) setOptions:(NSString*)containerId options:(NSDictionary*)options; --(void) push:(NSString*)containerId layout:(NSDictionary*)layout; +-(void) push:(NSString*)containerId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion; -(void) pop:(NSString*)containerId options:(NSDictionary*)options; @@ -20,7 +20,7 @@ -(void) popToRoot:(NSString*)containerId; --(void) showModal:(NSDictionary*)layout; +-(void) showModal:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion; -(void) dismissModal:(NSString*)containerId; diff --git a/lib/ios/RNNCommandsHandler.m b/lib/ios/RNNCommandsHandler.m index e6f62ff8eb4..afa6ec8e754 100644 --- a/lib/ios/RNNCommandsHandler.m +++ b/lib/ios/RNNCommandsHandler.m @@ -47,19 +47,19 @@ -(void) setOptions:(NSString*)containerId options:(NSDictionary*)options { } } --(void)push:(NSString*)containerId layout:(NSDictionary*)layout { +-(void) push:(NSString*)containerId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion { [self assertReady]; NSDictionary* customAnimation = layout[@"data"][@"customTransition"]; UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout]; RCTBridge* bridge = _bridge; if (customAnimation) { if ([customAnimation objectForKey:@"animations"]) { - [_navigationStackManager push:newVc onTop:containerId customAnimationData:(NSDictionary*)customAnimation bridge:bridge]; + [_navigationStackManager push:newVc onTop:containerId customAnimationData:(NSDictionary*)customAnimation bridge:bridge completion:completion]; } else { [[NSException exceptionWithName:NSInvalidArgumentException reason:@"unsupported transitionAnimation" userInfo:nil] raise]; } } else { - [_navigationStackManager push:newVc onTop:containerId customAnimationData:(NSDictionary*)nil bridge:bridge]; + [_navigationStackManager push:newVc onTop:containerId customAnimationData:(NSDictionary*)nil bridge:bridge completion:completion]; } } @@ -90,11 +90,11 @@ -(void) popToRoot:(NSString*)containerId { [_navigationStackManager popToRoot:containerId]; } --(void) showModal:(NSDictionary*)layout { +-(void) showModal:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion { [self assertReady]; UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout]; - [_modalManager showModal:newVc]; + [_modalManager showModal:newVc completion:completion]; } -(void) dismissModal:(NSString*)containerId { diff --git a/lib/ios/RNNModalManager.h b/lib/ios/RNNModalManager.h index b46233ff09c..e9d8635935d 100644 --- a/lib/ios/RNNModalManager.h +++ b/lib/ios/RNNModalManager.h @@ -7,7 +7,7 @@ @property (nonatomic, strong) UIViewController* toVC; -(instancetype)initWithStore:(RNNStore*)store; --(void)showModal:(UIViewController*)viewController; +-(void)showModal:(UIViewController*)viewController completion:(RNNTransitionCompletionBlock)completion; -(void)dismissModal:(NSString*)containerId; -(void)dismissAllModals; diff --git a/lib/ios/RNNModalManager.m b/lib/ios/RNNModalManager.m index 895be604aaf..db49ca1fdd1 100644 --- a/lib/ios/RNNModalManager.m +++ b/lib/ios/RNNModalManager.m @@ -28,7 +28,7 @@ -(void)showModalAfterLoad:(NSDictionary*)notif { // //} --(void)showModal:(UIViewController *)viewController { +-(void)showModal:(UIViewController *)viewController completion:(RNNTransitionCompletionBlock)completion { self.toVC = viewController; // [self prepareShowModal] [self waitForContentToAppearAndThen:@selector(showModalAfterLoad:)]; diff --git a/lib/ios/RNNNavigationStackManager.h b/lib/ios/RNNNavigationStackManager.h index aa2d695e9e2..d1a4da04599 100644 --- a/lib/ios/RNNNavigationStackManager.h +++ b/lib/ios/RNNNavigationStackManager.h @@ -10,7 +10,7 @@ -(instancetype)initWithStore:(RNNStore*)store; --(void)push:(UIViewController*)newTop onTop:(NSString*)containerId customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge; +-(void)push:(UIViewController*)newTop onTop:(NSString*)containerId customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge completion:(RNNTransitionCompletionBlock)completion; -(void)pop:(NSString*)containerId withAnimationData:(NSDictionary*)animationData; -(void)popTo:(NSString*)containerId; -(void)popToRoot:(NSString*)containerId; diff --git a/lib/ios/RNNNavigationStackManager.m b/lib/ios/RNNNavigationStackManager.m index b366243ff2a..fc8ab2ccd7a 100644 --- a/lib/ios/RNNNavigationStackManager.m +++ b/lib/ios/RNNNavigationStackManager.m @@ -7,6 +7,7 @@ dispatch_queue_t RCTGetUIManagerQueue(void); @implementation RNNNavigationStackManager { RNNStore *_store; + RNNTransitionCompletionBlock _completionBlock; } -(instancetype)initWithStore:(RNNStore*)store { @@ -15,14 +16,13 @@ -(instancetype)initWithStore:(RNNStore*)store { return self; } - --(void)push:(UIViewController *)newTop onTop:(NSString *)containerId customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge { +-(void)push:(UIViewController *)newTop onTop:(NSString *)containerId customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge completion:(RNNTransitionCompletionBlock)completion { UIViewController *vc = [_store findContainerForId:containerId]; - [self preparePush:newTop onTopVC:vc customAnimationData:customAnimationData bridge:bridge]; + [self preparePush:newTop onTopVC:vc customAnimationData:customAnimationData bridge:bridge completion:completion]; [self waitForContentToAppearAndThen:@selector(pushAfterLoad:)]; } --(void)preparePush:(UIViewController *)newTop onTopVC:(UIViewController*)vc customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge { +-(void)preparePush:(UIViewController *)newTop onTopVC:(UIViewController*)vc customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge completion:(RNNTransitionCompletionBlock)completion { if (customAnimationData) { RNNRootViewController* newTopRootView = (RNNRootViewController*)newTop; self.fromVC = vc; @@ -39,6 +39,8 @@ -(void)preparePush:(UIViewController *)newTop onTopVC:(UIViewController*)vc cust vc.navigationController.delegate = nil; self.fromVC.navigationController.interactivePopGestureRecognizer.delegate = nil; } + + _completionBlock = completion; } -(void)waitForContentToAppearAndThen:(SEL)nameOfSelector { @@ -50,7 +52,17 @@ -(void)waitForContentToAppearAndThen:(SEL)nameOfSelector { -(void)pushAfterLoad:(NSDictionary*)notif { [[NSNotificationCenter defaultCenter] removeObserver:self name:@"RCTContentDidAppearNotification" object:nil]; + [CATransaction begin]; + [CATransaction setCompletionBlock:^{ + if (_completionBlock) { + _completionBlock(self.toVC.containerId); + _completionBlock = nil; + } + }]; + [[self.fromVC navigationController] pushViewController:self.toVC animated:YES]; + [CATransaction commit]; + self.toVC = nil; self.fromVC.navigationController.interactivePopGestureRecognizer.delegate = nil; self.fromVC = nil; diff --git a/lib/ios/RNNStore.h b/lib/ios/RNNStore.h index b9d82a99756..910a8978137 100644 --- a/lib/ios/RNNStore.h +++ b/lib/ios/RNNStore.h @@ -3,6 +3,8 @@ #import #import "RNNRootViewController.h" +typedef void (^RNNTransitionCompletionBlock)(id result); + @interface RNNStore : NSObject -(UIViewController*) findContainerForId:(NSString*)containerId; diff --git a/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m b/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m index a3114b29d5e..47b998aaadf 100644 --- a/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m +++ b/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m @@ -30,10 +30,10 @@ - (void)testAssertReadyForEachMethodThrowsExceptoins { [self.store setReadyToReceiveCommands:false]; for (NSString* methodName in methods) { SEL s = NSSelectorFromString(methodName); - NSMethodSignature* signature = [self.uut methodSignatureForSelector:s]; - NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; - invocation.selector = s; - XCTAssertThrowsSpecificNamed([invocation invokeWithTarget:self.uut], NSException, @"BridgeNotLoadedError"); + IMP imp = [uut methodForSelector:s]; + void (*func)(id, SEL, id, id, id) = (void *)imp; + + XCTAssertThrowsSpecificNamed(func(uut,s, nil, nil, nil), NSException, @"BridgeNotLoadedError"); } } diff --git a/lib/src/adapters/NativeCommandsSender.js b/lib/src/adapters/NativeCommandsSender.js index a5b15d8076a..aedc958edd1 100644 --- a/lib/src/adapters/NativeCommandsSender.js +++ b/lib/src/adapters/NativeCommandsSender.js @@ -17,8 +17,9 @@ class NativeCommandsSender { this.nativeCommandsModule.setOptions(containerId, options); } - push(onContainerId, layout) { - return this.nativeCommandsModule.push(onContainerId, layout); + async push(onContainerId, layout) { + const pushedContainerId = await this.nativeCommandsModule.push(onContainerId, layout); + return pushedContainerId; } pop(containerId, options) { @@ -33,8 +34,9 @@ class NativeCommandsSender { return this.nativeCommandsModule.popToRoot(containerId); } - showModal(layout) { - return this.nativeCommandsModule.showModal(layout); + async showModal(layout) { + const completed = await this.nativeCommandsModule.showModal(layout); + return completed; } dismissModal(containerId) { From 53167f22043718d9190cfe1ccda770a5c1fcb266 Mon Sep 17 00:00:00 2001 From: yogevbd Date: Fri, 15 Dec 2017 02:09:22 +0200 Subject: [PATCH 3/4] refactored custom transitions --- lib/ios/RNNCommandsHandler.m | 15 ++++--------- lib/ios/RNNControllerFactory.m | 3 ++- lib/ios/RNNNavigationStackManager.h | 2 +- lib/ios/RNNNavigationStackManager.m | 21 +++++++------------ lib/ios/RNNRootViewController.h | 8 +++++-- lib/ios/RNNRootViewController.m | 21 +++++++++++++++++-- .../RNNCommandsHandlerTest.m | 7 ++++--- .../RNNRootViewControllerTest.m | 4 ++-- 8 files changed, 45 insertions(+), 36 deletions(-) diff --git a/lib/ios/RNNCommandsHandler.m b/lib/ios/RNNCommandsHandler.m index afa6ec8e754..99d0651c9f5 100644 --- a/lib/ios/RNNCommandsHandler.m +++ b/lib/ios/RNNCommandsHandler.m @@ -3,6 +3,7 @@ #import "RNNNavigationStackManager.h" #import "RNNNavigationOptions.h" #import "RNNRootViewController.h" +#import "React/RCTUIManager.h" @implementation RNNCommandsHandler { RNNControllerFactory *_controllerFactory; @@ -49,18 +50,10 @@ -(void) setOptions:(NSString*)containerId options:(NSDictionary*)options { -(void) push:(NSString*)containerId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion { [self assertReady]; - NSDictionary* customAnimation = layout[@"data"][@"customTransition"]; UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout]; - RCTBridge* bridge = _bridge; - if (customAnimation) { - if ([customAnimation objectForKey:@"animations"]) { - [_navigationStackManager push:newVc onTop:containerId customAnimationData:(NSDictionary*)customAnimation bridge:bridge completion:completion]; - } else { - [[NSException exceptionWithName:NSInvalidArgumentException reason:@"unsupported transitionAnimation" userInfo:nil] raise]; - } - } else { - [_navigationStackManager push:newVc onTop:containerId customAnimationData:(NSDictionary*)nil bridge:bridge completion:completion]; - } + UIViewController *fromVc = [_store findContainerForId:containerId]; + [_bridge.uiManager setAvailableSize:fromVc.view.bounds.size forRootView:newVc.view]; + [_navigationStackManager push:newVc onTop:containerId completion:completion]; } -(void)pop:(NSString*)containerId options:(NSDictionary*)options{ diff --git a/lib/ios/RNNControllerFactory.m b/lib/ios/RNNControllerFactory.m index bad4b0156c4..8d69ed107ed 100644 --- a/lib/ios/RNNControllerFactory.m +++ b/lib/ios/RNNControllerFactory.m @@ -78,9 +78,10 @@ - (UIViewController*)fromTree:(NSDictionary*)json { - (RNNRootViewController*)createContainer:(RNNLayoutNode*)node { NSString* name = node.data[@"name"]; + NSDictionary* customTransition = node.data[@"customTransition"]; RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"navigationOptions"]]; NSString* containerId = node.nodeId; - return [[RNNRootViewController alloc] initWithName:name withOptions:options withContainerId:containerId rootViewCreator:_creator eventEmitter:_eventEmitter]; + return [[RNNRootViewController alloc] initWithName:name withOptions:options withContainerId:containerId rootViewCreator:_creator eventEmitter:_eventEmitter customTransitionDict:customTransition]; } - (RNNNavigationController*)createContainerStack:(RNNLayoutNode*)node { diff --git a/lib/ios/RNNNavigationStackManager.h b/lib/ios/RNNNavigationStackManager.h index d1a4da04599..2f19e42f04f 100644 --- a/lib/ios/RNNNavigationStackManager.h +++ b/lib/ios/RNNNavigationStackManager.h @@ -10,7 +10,7 @@ -(instancetype)initWithStore:(RNNStore*)store; --(void)push:(UIViewController*)newTop onTop:(NSString*)containerId customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge completion:(RNNTransitionCompletionBlock)completion; +-(void)push:(UIViewController*)newTop onTop:(NSString*)containerId completion:(RNNTransitionCompletionBlock)completion; -(void)pop:(NSString*)containerId withAnimationData:(NSDictionary*)animationData; -(void)popTo:(NSString*)containerId; -(void)popToRoot:(NSString*)containerId; diff --git a/lib/ios/RNNNavigationStackManager.m b/lib/ios/RNNNavigationStackManager.m index fc8ab2ccd7a..9cae0549587 100644 --- a/lib/ios/RNNNavigationStackManager.m +++ b/lib/ios/RNNNavigationStackManager.m @@ -1,6 +1,5 @@ #import "RNNNavigationStackManager.h" #import "RNNRootViewController.h" -#import "React/RCTUIManager.h" #import "RNNAnimator.h" @@ -16,26 +15,20 @@ -(instancetype)initWithStore:(RNNStore*)store { return self; } --(void)push:(UIViewController *)newTop onTop:(NSString *)containerId customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge completion:(RNNTransitionCompletionBlock)completion { +-(void)push:(UIViewController *)newTop onTop:(NSString *)containerId completion:(RNNTransitionCompletionBlock)completion { UIViewController *vc = [_store findContainerForId:containerId]; - [self preparePush:newTop onTopVC:vc customAnimationData:customAnimationData bridge:bridge completion:completion]; + [self preparePush:newTop onTopVC:vc completion:completion]; [self waitForContentToAppearAndThen:@selector(pushAfterLoad:)]; } --(void)preparePush:(UIViewController *)newTop onTopVC:(UIViewController*)vc customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge completion:(RNNTransitionCompletionBlock)completion { - if (customAnimationData) { +-(void)preparePush:(UIViewController *)newTop onTopVC:(UIViewController*)vc completion:(RNNTransitionCompletionBlock)completion { + self.toVC = (RNNRootViewController*)newTop; + self.fromVC = vc; + + if (self.toVC.isAnimated) { RNNRootViewController* newTopRootView = (RNNRootViewController*)newTop; - self.fromVC = vc; - self.toVC = newTopRootView; vc.navigationController.delegate = newTopRootView; - [newTopRootView.animator setupTransition:customAnimationData]; - RCTUIManager *uiManager = bridge.uiManager; - CGRect screenBound = [vc.view bounds]; - CGSize screenSize = screenBound.size; - [uiManager setAvailableSize:screenSize forRootView:self.toVC.view]; } else { - self.fromVC = vc; - self.toVC = (RNNRootViewController*)newTop; vc.navigationController.delegate = nil; self.fromVC.navigationController.interactivePopGestureRecognizer.delegate = nil; } diff --git a/lib/ios/RNNRootViewController.h b/lib/ios/RNNRootViewController.h index 6b8c7876042..681a25efbee 100644 --- a/lib/ios/RNNRootViewController.h +++ b/lib/ios/RNNRootViewController.h @@ -6,19 +6,23 @@ #import "RNNEventEmitter.h" #import "RNNNavigationOptions.h" #import "RNNAnimator.h" + @interface RNNRootViewController : UIViewController @property (nonatomic, strong) RNNNavigationOptions* navigationOptions; @property (nonatomic, strong) RNNAnimator* animator; @property (nonatomic, strong) RNNEventEmitter *eventEmitter; +@property (nonatomic, strong) NSDictionary *customAnimationsDict; @property (nonatomic, strong) NSString* containerId; -(instancetype)initWithName:(NSString*)name withOptions:(RNNNavigationOptions*)options withContainerId:(NSString*)containerId rootViewCreator:(id)creator - eventEmitter:(RNNEventEmitter*)eventEmitter; + eventEmitter:(RNNEventEmitter*)eventEmitter + customTransitionDict:(NSDictionary*)customTransitionDict; --(void) applyNavigationButtons; +-(void)applyNavigationButtons; +-(BOOL)isAnimated; @end diff --git a/lib/ios/RNNRootViewController.m b/lib/ios/RNNRootViewController.m index 00775d5ae27..a92dc93bfd2 100644 --- a/lib/ios/RNNRootViewController.m +++ b/lib/ios/RNNRootViewController.m @@ -17,19 +17,21 @@ -(instancetype)initWithName:(NSString*)name withOptions:(RNNNavigationOptions*)options withContainerId:(NSString*)containerId rootViewCreator:(id)creator - eventEmitter:(RNNEventEmitter*)eventEmitter { + eventEmitter:(RNNEventEmitter*)eventEmitter + customTransitionDict:(NSDictionary *)customTransitionDict { self = [super init]; self.containerId = containerId; self.containerName = name; self.navigationOptions = options; self.eventEmitter = eventEmitter; + self.customAnimationsDict = customTransitionDict; self.view = [creator createRootView:self.containerName rootViewId:self.containerId]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onJsReload) name:RCTJavaScriptWillStartLoadingNotification object:nil]; - self.animator = [[RNNAnimator alloc] init]; + [self setupCustomTransitionAnimations]; self.navigationController.modalPresentationStyle = UIModalPresentationCustom; self.navigationController.delegate = self; self.navigationButtons = [[RNNNavigationButtons alloc] initWithViewController:self]; @@ -46,6 +48,21 @@ - (void)viewDidLoad { [super viewDidLoad]; } +-(void)setupCustomTransitionAnimations { + if (self.isAnimated) { + if (!self.customAnimationsDict[@"animations"]) { + [[NSException exceptionWithName:NSInvalidArgumentException reason:@"unsupported transitionAnimation" userInfo:nil] raise]; + } + + self.animator = [[RNNAnimator alloc] init]; + [self.animator setupTransition:self.customAnimationsDict]; + } +} + +-(BOOL)isAnimated { + return self.customAnimationsDict; +} + - (BOOL)prefersStatusBarHidden { if ([self.navigationOptions.statusBarHidden boolValue]) { return YES; diff --git a/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m b/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m index 47b998aaadf..2b6f3e604a9 100644 --- a/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m +++ b/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m @@ -30,10 +30,10 @@ - (void)testAssertReadyForEachMethodThrowsExceptoins { [self.store setReadyToReceiveCommands:false]; for (NSString* methodName in methods) { SEL s = NSSelectorFromString(methodName); - IMP imp = [uut methodForSelector:s]; + IMP imp = [self.uut methodForSelector:s]; void (*func)(id, SEL, id, id, id) = (void *)imp; - XCTAssertThrowsSpecificNamed(func(uut,s, nil, nil, nil), NSException, @"BridgeNotLoadedError"); + XCTAssertThrowsSpecificNamed(func(self.uut,s, nil, nil, nil), NSException, @"BridgeNotLoadedError"); } } @@ -70,7 +70,8 @@ -(void)testDynamicStylesMergeWithStaticStyles { withOptions:initialOptions withContainerId:@"containerId" rootViewCreator:[[RNNTestRootViewCreator alloc] init] - eventEmitter:nil]; + eventEmitter:nil + customTransitionDict:nil]; RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:vc]; [vc viewWillAppear:false]; XCTAssertTrue([vc.navigationItem.title isEqual:@"the title"]); diff --git a/lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m b/lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m index ce38e8fe3ac..3213e8c6c55 100644 --- a/lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m +++ b/lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m @@ -27,7 +27,7 @@ - (void)setUp { self.containerId = @"cntId"; self.emitter = nil; self.options = [RNNNavigationOptions new]; - self.uut = [[RNNRootViewController alloc] initWithName:self.pageName withOptions:self.options withContainerId:self.containerId rootViewCreator:self.creator eventEmitter:self.emitter]; + self.uut = [[RNNRootViewController alloc] initWithName:self.pageName withOptions:self.options withContainerId:self.containerId rootViewCreator:self.creator eventEmitter:self.emitter customTransitionDict:nil]; } -(void)testTopBarBackgroundColor_validColor{ @@ -491,7 +491,7 @@ -(void)testTopBarLargeTitle_true { XCTAssertEqual(self.uut.navigationItem.largeTitleDisplayMode, UINavigationItemLargeTitleDisplayModeAlways); } -(void)testTopBarLargeTitle_false { - self.options.tabBar.hidden = @(0); + self.options.bottomTabs.hidden = @(0); __unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut]; [self.uut viewWillAppear:false]; From 836d0131a6fbc82e201adb0ed22463dbf4d54cd2 Mon Sep 17 00:00:00 2001 From: yogevbd Date: Wed, 20 Dec 2017 13:52:17 +0200 Subject: [PATCH 4/4] refactored custom animations --- lib/ios/RNNAnimator.h | 2 ++ lib/ios/RNNAnimator.m | 11 +++++++++++ lib/ios/RNNControllerFactory.m | 3 ++- lib/ios/RNNRootViewController.h | 3 +-- lib/ios/RNNRootViewController.m | 18 +++--------------- .../RNNCommandsHandlerTest.m | 2 +- .../RNNRootViewControllerTest.m | 2 +- 7 files changed, 21 insertions(+), 20 deletions(-) diff --git a/lib/ios/RNNAnimator.h b/lib/ios/RNNAnimator.h index e2be02a208c..64c991f364c 100644 --- a/lib/ios/RNNAnimator.h +++ b/lib/ios/RNNAnimator.h @@ -3,6 +3,8 @@ #import "RNNElementView.h" @interface RNNAnimator : NSObject + +-(instancetype)initWithAnimationsDictionary:(NSDictionary *)animationsDic; -(void)setupTransition:(NSDictionary*)data; @end diff --git a/lib/ios/RNNAnimator.m b/lib/ios/RNNAnimator.m index 71438f252ee..51a94902a4d 100644 --- a/lib/ios/RNNAnimator.m +++ b/lib/ios/RNNAnimator.m @@ -21,6 +21,17 @@ @interface RNNAnimator() @implementation RNNAnimator +- (instancetype)initWithAnimationsDictionary:(NSDictionary *)animationsDic { + self = [super init]; + if (animationsDic) { + [self setupTransition:animationsDic]; + } else { + return nil; + } + + return self; +} + -(void)setupTransition:(NSDictionary*)data{ if ([data objectForKey:@"animations"]) { self.animations= [data objectForKey:@"animations"]; diff --git a/lib/ios/RNNControllerFactory.m b/lib/ios/RNNControllerFactory.m index 8d69ed107ed..c29e3e061ca 100644 --- a/lib/ios/RNNControllerFactory.m +++ b/lib/ios/RNNControllerFactory.m @@ -79,9 +79,10 @@ - (UIViewController*)fromTree:(NSDictionary*)json { - (RNNRootViewController*)createContainer:(RNNLayoutNode*)node { NSString* name = node.data[@"name"]; NSDictionary* customTransition = node.data[@"customTransition"]; + RNNAnimator* animator = [[RNNAnimator alloc] initWithAnimationsDictionary:customTransition]; RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"navigationOptions"]]; NSString* containerId = node.nodeId; - return [[RNNRootViewController alloc] initWithName:name withOptions:options withContainerId:containerId rootViewCreator:_creator eventEmitter:_eventEmitter customTransitionDict:customTransition]; + return [[RNNRootViewController alloc] initWithName:name withOptions:options withContainerId:containerId rootViewCreator:_creator eventEmitter:_eventEmitter animator:animator]; } - (RNNNavigationController*)createContainerStack:(RNNLayoutNode*)node { diff --git a/lib/ios/RNNRootViewController.h b/lib/ios/RNNRootViewController.h index 681a25efbee..2ef3ea4afe3 100644 --- a/lib/ios/RNNRootViewController.h +++ b/lib/ios/RNNRootViewController.h @@ -11,7 +11,6 @@ @property (nonatomic, strong) RNNNavigationOptions* navigationOptions; @property (nonatomic, strong) RNNAnimator* animator; @property (nonatomic, strong) RNNEventEmitter *eventEmitter; -@property (nonatomic, strong) NSDictionary *customAnimationsDict; @property (nonatomic, strong) NSString* containerId; -(instancetype)initWithName:(NSString*)name @@ -19,7 +18,7 @@ withContainerId:(NSString*)containerId rootViewCreator:(id)creator eventEmitter:(RNNEventEmitter*)eventEmitter - customTransitionDict:(NSDictionary*)customTransitionDict; + animator:(RNNAnimator*)animator; -(void)applyNavigationButtons; diff --git a/lib/ios/RNNRootViewController.m b/lib/ios/RNNRootViewController.m index a92dc93bfd2..f9eb3d948e7 100644 --- a/lib/ios/RNNRootViewController.m +++ b/lib/ios/RNNRootViewController.m @@ -18,20 +18,19 @@ -(instancetype)initWithName:(NSString*)name withContainerId:(NSString*)containerId rootViewCreator:(id)creator eventEmitter:(RNNEventEmitter*)eventEmitter - customTransitionDict:(NSDictionary *)customTransitionDict { + animator:(RNNAnimator *)animator { self = [super init]; self.containerId = containerId; self.containerName = name; self.navigationOptions = options; self.eventEmitter = eventEmitter; - self.customAnimationsDict = customTransitionDict; + self.animator = animator; self.view = [creator createRootView:self.containerName rootViewId:self.containerId]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onJsReload) name:RCTJavaScriptWillStartLoadingNotification object:nil]; - [self setupCustomTransitionAnimations]; self.navigationController.modalPresentationStyle = UIModalPresentationCustom; self.navigationController.delegate = self; self.navigationButtons = [[RNNNavigationButtons alloc] initWithViewController:self]; @@ -48,19 +47,8 @@ - (void)viewDidLoad { [super viewDidLoad]; } --(void)setupCustomTransitionAnimations { - if (self.isAnimated) { - if (!self.customAnimationsDict[@"animations"]) { - [[NSException exceptionWithName:NSInvalidArgumentException reason:@"unsupported transitionAnimation" userInfo:nil] raise]; - } - - self.animator = [[RNNAnimator alloc] init]; - [self.animator setupTransition:self.customAnimationsDict]; - } -} - -(BOOL)isAnimated { - return self.customAnimationsDict; + return self.animator; } - (BOOL)prefersStatusBarHidden { diff --git a/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m b/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m index 2b6f3e604a9..59ae3ac2b0d 100644 --- a/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m +++ b/lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m @@ -71,7 +71,7 @@ -(void)testDynamicStylesMergeWithStaticStyles { withContainerId:@"containerId" rootViewCreator:[[RNNTestRootViewCreator alloc] init] eventEmitter:nil - customTransitionDict:nil]; + animator:nil]; RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:vc]; [vc viewWillAppear:false]; XCTAssertTrue([vc.navigationItem.title isEqual:@"the title"]); diff --git a/lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m b/lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m index 01fb1a16948..eab35a51193 100644 --- a/lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m +++ b/lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m @@ -27,7 +27,7 @@ - (void)setUp { self.containerId = @"cntId"; self.emitter = nil; self.options = [RNNNavigationOptions new]; - self.uut = [[RNNRootViewController alloc] initWithName:self.pageName withOptions:self.options withContainerId:self.containerId rootViewCreator:self.creator eventEmitter:self.emitter customTransitionDict:nil]; + self.uut = [[RNNRootViewController alloc] initWithName:self.pageName withOptions:self.options withContainerId:self.containerId rootViewCreator:self.creator eventEmitter:self.emitter animator:nil]; } -(void)testTopBarBackgroundColor_validColor{