Browse Source

async await for push and showModal (#2270)

* async await for push and showModal

* async await for push and showModal

* refactored custom transitions

* refactored custom animations
yogevbd 6 years ago
parent
commit
290ff8dd3e

+ 2
- 0
lib/ios/RNNAnimator.h View File

@@ -3,6 +3,8 @@
3 3
 #import "RNNElementView.h"
4 4
 
5 5
 @interface RNNAnimator : NSObject <UIViewControllerAnimatedTransitioning>
6
+
7
+-(instancetype)initWithAnimationsDictionary:(NSDictionary *)animationsDic;
6 8
 -(void)setupTransition:(NSDictionary*)data;
7 9
 
8 10
 @end

+ 11
- 0
lib/ios/RNNAnimator.m View File

@@ -21,6 +21,17 @@
21 21
 
22 22
 @implementation RNNAnimator
23 23
 
24
+- (instancetype)initWithAnimationsDictionary:(NSDictionary *)animationsDic {
25
+	self = [super init];
26
+	if (animationsDic) {
27
+		[self setupTransition:animationsDic];
28
+	} else {
29
+		return nil;
30
+	}
31
+	
32
+	return self;
33
+}
34
+
24 35
 -(void)setupTransition:(NSDictionary*)data{
25 36
 	if ([data objectForKey:@"animations"]) {
26 37
 		self.animations= [data objectForKey:@"animations"];

+ 8
- 4
lib/ios/RNNBridgeModule.m View File

@@ -26,8 +26,10 @@ RCT_EXPORT_METHOD(setOptions:(NSString*)containerId options:(NSDictionary*)optio
26 26
 	[_commandsHandler setOptions:containerId options:options];
27 27
 }
28 28
 
29
-RCT_EXPORT_METHOD(push:(NSString*)containerId layout:(NSDictionary*)layout) {
30
-	[_commandsHandler push:containerId layout:layout];
29
+RCT_EXPORT_METHOD(push:(NSString*)containerId layout:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
30
+	[_commandsHandler push:containerId layout:layout completion:^(id result) {
31
+		resolve(result);
32
+	}];
31 33
 }
32 34
 
33 35
 RCT_EXPORT_METHOD(pop:(NSString*)containerId options:(NSDictionary*)options) {
@@ -42,8 +44,10 @@ RCT_EXPORT_METHOD(popToRoot:(NSString*)containerId) {
42 44
 	[_commandsHandler popToRoot:containerId];
43 45
 }
44 46
 
45
-RCT_EXPORT_METHOD(showModal:(NSDictionary*)layout) {
46
-	[_commandsHandler showModal:layout];
47
+RCT_EXPORT_METHOD(showModal:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
48
+	[_commandsHandler showModal:layout completion:^(id containerID) {
49
+		resolve(containerID);
50
+	}];
47 51
 }
48 52
 
49 53
 RCT_EXPORT_METHOD(dismissModal:(NSString*)containerId) {

+ 2
- 2
lib/ios/RNNCommandsHandler.h View File

@@ -12,7 +12,7 @@
12 12
 
13 13
 -(void) setOptions:(NSString*)containerId options:(NSDictionary*)options;
14 14
 
15
--(void) push:(NSString*)containerId layout:(NSDictionary*)layout;
15
+-(void) push:(NSString*)containerId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion;
16 16
 
17 17
 -(void) pop:(NSString*)containerId options:(NSDictionary*)options;
18 18
 
@@ -20,7 +20,7 @@
20 20
 
21 21
 -(void) popToRoot:(NSString*)containerId;
22 22
 
23
--(void) showModal:(NSDictionary*)layout;
23
+-(void) showModal:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion;
24 24
 
25 25
 -(void) dismissModal:(NSString*)containerId;
26 26
 

+ 7
- 14
lib/ios/RNNCommandsHandler.m View File

@@ -3,6 +3,7 @@
3 3
 #import "RNNNavigationStackManager.h"
4 4
 #import "RNNNavigationOptions.h"
5 5
 #import "RNNRootViewController.h"
6
+#import "React/RCTUIManager.h"
6 7
 
7 8
 @implementation RNNCommandsHandler {
8 9
 	RNNControllerFactory *_controllerFactory;
@@ -47,20 +48,12 @@
47 48
 	}
48 49
 }
49 50
 
50
--(void)push:(NSString*)containerId layout:(NSDictionary*)layout {
51
+-(void) push:(NSString*)containerId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion {
51 52
 	[self assertReady];
52
-	NSDictionary* customAnimation = layout[@"data"][@"customTransition"];
53 53
 	UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];
54
-	RCTBridge* bridge = _bridge;
55
-	if (customAnimation) {
56
-		if ([customAnimation objectForKey:@"animations"]) {
57
-			[_navigationStackManager push:newVc onTop:containerId customAnimationData:(NSDictionary*)customAnimation bridge:bridge];
58
-		} else {
59
-			[[NSException exceptionWithName:NSInvalidArgumentException reason:@"unsupported transitionAnimation" userInfo:nil] raise];
60
-		}
61
-	} else {
62
-		[_navigationStackManager push:newVc onTop:containerId customAnimationData:(NSDictionary*)nil bridge:bridge];
63
-	}
54
+	UIViewController *fromVc = [_store findContainerForId:containerId];
55
+	[_bridge.uiManager setAvailableSize:fromVc.view.bounds.size forRootView:newVc.view];
56
+	[_navigationStackManager push:newVc onTop:containerId completion:completion];
64 57
 }
65 58
 
66 59
 -(void)pop:(NSString*)containerId options:(NSDictionary*)options{
@@ -90,11 +83,11 @@
90 83
 	[_navigationStackManager popToRoot:containerId];
91 84
 }
92 85
 
93
--(void) showModal:(NSDictionary*)layout {
86
+-(void) showModal:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion {
94 87
 	[self assertReady];
95 88
 	
96 89
 	UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];
97
-	[_modalManager showModal:newVc];
90
+	[_modalManager showModal:newVc completion:completion];
98 91
 }
99 92
 
100 93
 -(void) dismissModal:(NSString*)containerId {

+ 3
- 1
lib/ios/RNNControllerFactory.m View File

@@ -78,9 +78,11 @@
78 78
 
79 79
 - (RNNRootViewController*)createContainer:(RNNLayoutNode*)node {
80 80
 	NSString* name = node.data[@"name"];
81
+	NSDictionary* customTransition = node.data[@"customTransition"];
82
+	RNNAnimator* animator = [[RNNAnimator alloc] initWithAnimationsDictionary:customTransition];
81 83
 	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"navigationOptions"]];
82 84
 	NSString* containerId = node.nodeId;
83
-	return [[RNNRootViewController alloc] initWithName:name withOptions:options withContainerId:containerId rootViewCreator:_creator eventEmitter:_eventEmitter];
85
+	return [[RNNRootViewController alloc] initWithName:name withOptions:options withContainerId:containerId rootViewCreator:_creator eventEmitter:_eventEmitter animator:animator];
84 86
 }
85 87
 
86 88
 - (RNNNavigationController*)createContainerStack:(RNNLayoutNode*)node {

+ 1
- 1
lib/ios/RNNModalManager.h View File

@@ -7,7 +7,7 @@
7 7
 @property (nonatomic, strong) UIViewController* toVC;
8 8
 
9 9
 -(instancetype)initWithStore:(RNNStore*)store;
10
--(void)showModal:(UIViewController*)viewController;
10
+-(void)showModal:(UIViewController*)viewController completion:(RNNTransitionCompletionBlock)completion;
11 11
 -(void)dismissModal:(NSString*)containerId;
12 12
 -(void)dismissAllModals;
13 13
 

+ 8
- 7
lib/ios/RNNModalManager.m View File

@@ -3,6 +3,7 @@
3 3
 
4 4
 @implementation RNNModalManager {
5 5
 	RNNStore *_store;
6
+	RNNTransitionCompletionBlock _completionBlock;
6 7
 }
7 8
 
8 9
 
@@ -21,16 +22,16 @@
21 22
 -(void)showModalAfterLoad:(NSDictionary*)notif {
22 23
 	[[NSNotificationCenter defaultCenter] removeObserver:self name:@"RCTContentDidAppearNotification" object:nil];
23 24
 	UIViewController *topVC = [self topPresentedVC];
24
-	[topVC presentViewController:self.toVC animated:YES completion:nil];
25
+	[topVC presentViewController:self.toVC animated:YES completion:^{
26
+		if (_completionBlock) {
27
+			_completionBlock([_store containerKeyForInstance:self.toVC]);
28
+		}
29
+	}];
25 30
 }
26 31
 
27
-//-(void)prepareShowModal{
28
-//
29
-//}
30
-
31
--(void)showModal:(UIViewController *)viewController {
32
+-(void)showModal:(UIViewController *)viewController completion:(RNNTransitionCompletionBlock)completion {
32 33
 	self.toVC = viewController;
33
-//	[self prepareShowModal]
34
+	_completionBlock = completion;
34 35
 	[self waitForContentToAppearAndThen:@selector(showModalAfterLoad:)];
35 36
 }
36 37
 

+ 1
- 1
lib/ios/RNNNavigationStackManager.h View File

@@ -10,7 +10,7 @@
10 10
 -(instancetype)initWithStore:(RNNStore*)store;
11 11
 
12 12
 
13
--(void)push:(UIViewController*)newTop onTop:(NSString*)containerId customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge;
13
+-(void)push:(UIViewController*)newTop onTop:(NSString*)containerId completion:(RNNTransitionCompletionBlock)completion;
14 14
 -(void)pop:(NSString*)containerId withAnimationData:(NSDictionary*)animationData;
15 15
 -(void)popTo:(NSString*)containerId;
16 16
 -(void)popToRoot:(NSString*)containerId;

+ 20
- 15
lib/ios/RNNNavigationStackManager.m View File

@@ -1,12 +1,12 @@
1 1
 #import "RNNNavigationStackManager.h"
2 2
 #import "RNNRootViewController.h"
3
-#import "React/RCTUIManager.h"
4 3
 #import "RNNAnimator.h"
5 4
 
6 5
 
7 6
 dispatch_queue_t RCTGetUIManagerQueue(void);
8 7
 @implementation RNNNavigationStackManager {
9 8
 	RNNStore *_store;
9
+	RNNTransitionCompletionBlock _completionBlock;
10 10
 }
11 11
 
12 12
 -(instancetype)initWithStore:(RNNStore*)store {
@@ -15,30 +15,25 @@ dispatch_queue_t RCTGetUIManagerQueue(void);
15 15
 	return self;
16 16
 }
17 17
 
18
-
19
--(void)push:(UIViewController *)newTop onTop:(NSString *)containerId customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge {
18
+-(void)push:(UIViewController *)newTop onTop:(NSString *)containerId completion:(RNNTransitionCompletionBlock)completion {
20 19
 	UIViewController *vc = [_store findContainerForId:containerId];
21
-	[self preparePush:newTop onTopVC:vc customAnimationData:customAnimationData bridge:bridge];
20
+	[self preparePush:newTop onTopVC:vc completion:completion];
22 21
 	[self waitForContentToAppearAndThen:@selector(pushAfterLoad:)];
23 22
 }
24 23
 
25
--(void)preparePush:(UIViewController *)newTop onTopVC:(UIViewController*)vc customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge {
26
-	if (customAnimationData) {
24
+-(void)preparePush:(UIViewController *)newTop onTopVC:(UIViewController*)vc completion:(RNNTransitionCompletionBlock)completion {
25
+	self.toVC = (RNNRootViewController*)newTop;
26
+	self.fromVC = vc;
27
+	
28
+	if (self.toVC.isAnimated) {
27 29
 		RNNRootViewController* newTopRootView = (RNNRootViewController*)newTop;
28
-		self.fromVC = vc;
29
-		self.toVC = newTopRootView;
30 30
 		vc.navigationController.delegate = newTopRootView;
31
-		[newTopRootView.animator setupTransition:customAnimationData];
32
-		RCTUIManager *uiManager = bridge.uiManager;
33
-		CGRect screenBound = [vc.view bounds];
34
-		CGSize screenSize = screenBound.size;
35
-		[uiManager setAvailableSize:screenSize forRootView:self.toVC.view];
36 31
 	} else {
37
-		self.fromVC = vc;
38
-		self.toVC = (RNNRootViewController*)newTop;
39 32
 		vc.navigationController.delegate = nil;
40 33
 		self.fromVC.navigationController.interactivePopGestureRecognizer.delegate = nil;
41 34
 	}
35
+	
36
+	_completionBlock = completion;
42 37
 }
43 38
 
44 39
 -(void)waitForContentToAppearAndThen:(SEL)nameOfSelector {
@@ -50,7 +45,17 @@ dispatch_queue_t RCTGetUIManagerQueue(void);
50 45
 
51 46
 -(void)pushAfterLoad:(NSDictionary*)notif {
52 47
 	[[NSNotificationCenter defaultCenter] removeObserver:self name:@"RCTContentDidAppearNotification" object:nil];
48
+	[CATransaction begin];
49
+	[CATransaction setCompletionBlock:^{
50
+		if (_completionBlock) {
51
+			_completionBlock(self.toVC.containerId);
52
+			_completionBlock = nil;
53
+		}
54
+	}];
55
+	
53 56
 	[[self.fromVC navigationController] pushViewController:self.toVC animated:YES];
57
+	[CATransaction commit];
58
+	
54 59
 	self.toVC = nil;
55 60
 	self.fromVC.navigationController.interactivePopGestureRecognizer.delegate = nil;
56 61
 	self.fromVC = nil;

+ 5
- 2
lib/ios/RNNRootViewController.h View File

@@ -6,6 +6,7 @@
6 6
 #import "RNNEventEmitter.h"
7 7
 #import "RNNNavigationOptions.h"
8 8
 #import "RNNAnimator.h"
9
+
9 10
 @interface RNNRootViewController : UIViewController	<UINavigationControllerDelegate>
10 11
 @property (nonatomic, strong) RNNNavigationOptions* navigationOptions;
11 12
 @property (nonatomic, strong) RNNAnimator* animator;
@@ -16,9 +17,11 @@
16 17
 				withOptions:(RNNNavigationOptions*)options
17 18
 			withContainerId:(NSString*)containerId
18 19
 			rootViewCreator:(id<RNNRootViewCreator>)creator
19
-			   eventEmitter:(RNNEventEmitter*)eventEmitter;
20
+			   eventEmitter:(RNNEventEmitter*)eventEmitter
21
+		   animator:(RNNAnimator*)animator;
20 22
 
21 23
 
22
--(void) applyNavigationButtons;
24
+-(void)applyNavigationButtons;
25
+-(BOOL)isAnimated;
23 26
 
24 27
 @end

+ 7
- 2
lib/ios/RNNRootViewController.m View File

@@ -17,19 +17,20 @@
17 17
 				withOptions:(RNNNavigationOptions*)options
18 18
 			withContainerId:(NSString*)containerId
19 19
 			rootViewCreator:(id<RNNRootViewCreator>)creator
20
-			   eventEmitter:(RNNEventEmitter*)eventEmitter {
20
+			   eventEmitter:(RNNEventEmitter*)eventEmitter
21
+				   animator:(RNNAnimator *)animator {
21 22
 	self = [super init];
22 23
 	self.containerId = containerId;
23 24
 	self.containerName = name;
24 25
 	self.navigationOptions = options;
25 26
 	self.eventEmitter = eventEmitter;
27
+	self.animator = animator;
26 28
 	self.view = [creator createRootView:self.containerName rootViewId:self.containerId];
27 29
 	
28 30
 	[[NSNotificationCenter defaultCenter] addObserver:self
29 31
 											 selector:@selector(onJsReload)
30 32
 												 name:RCTJavaScriptWillStartLoadingNotification
31 33
 											   object:nil];
32
-	self.animator = [[RNNAnimator alloc] init];
33 34
 	self.navigationController.modalPresentationStyle = UIModalPresentationCustom;
34 35
 	self.navigationController.delegate = self;
35 36
 	self.navigationButtons = [[RNNNavigationButtons alloc] initWithViewController:self];
@@ -46,6 +47,10 @@
46 47
 	[super viewDidLoad];
47 48
 }
48 49
 
50
+-(BOOL)isAnimated {
51
+	return self.animator;
52
+}
53
+
49 54
 - (BOOL)prefersStatusBarHidden {
50 55
 	if ([self.navigationOptions.statusBarHidden boolValue]) {
51 56
 		return YES;

+ 2
- 0
lib/ios/RNNStore.h View File

@@ -3,6 +3,8 @@
3 3
 #import <UIKit/UIKit.h>
4 4
 #import "RNNRootViewController.h"
5 5
 
6
+typedef void (^RNNTransitionCompletionBlock)(id result);
7
+
6 8
 @interface RNNStore : NSObject
7 9
 
8 10
 -(UIViewController*) findContainerForId:(NSString*)containerId;

+ 6
- 5
lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m View File

@@ -30,10 +30,10 @@
30 30
 	[self.store setReadyToReceiveCommands:false];
31 31
 	for (NSString* methodName in methods) {
32 32
 		SEL s = NSSelectorFromString(methodName);
33
-		NSMethodSignature* signature = [self.uut methodSignatureForSelector:s];
34
-		NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
35
-		invocation.selector = s;
36
-		XCTAssertThrowsSpecificNamed([invocation invokeWithTarget:self.uut], NSException, @"BridgeNotLoadedError");
33
+		IMP imp = [self.uut methodForSelector:s];
34
+		void (*func)(id, SEL, id, id, id) = (void *)imp;
35
+		
36
+		XCTAssertThrowsSpecificNamed(func(self.uut,s, nil, nil, nil), NSException, @"BridgeNotLoadedError");
37 37
 	}
38 38
 }
39 39
 
@@ -70,7 +70,8 @@
70 70
 																withOptions:initialOptions
71 71
 															withContainerId:@"containerId"
72 72
 															rootViewCreator:[[RNNTestRootViewCreator alloc] init]
73
-															   eventEmitter:nil];
73
+															   eventEmitter:nil
74
+																   animator:nil];
74 75
 	RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:vc];
75 76
 	[vc viewWillAppear:false];
76 77
 	XCTAssertTrue([vc.navigationItem.title isEqual:@"the title"]);

+ 1
- 1
lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m View File

@@ -27,7 +27,7 @@
27 27
 	self.containerId = @"cntId";
28 28
 	self.emitter = nil;
29 29
 	self.options = [RNNNavigationOptions new];
30
-	self.uut = [[RNNRootViewController alloc] initWithName:self.pageName withOptions:self.options withContainerId:self.containerId rootViewCreator:self.creator eventEmitter:self.emitter];
30
+	self.uut = [[RNNRootViewController alloc] initWithName:self.pageName withOptions:self.options withContainerId:self.containerId rootViewCreator:self.creator eventEmitter:self.emitter animator:nil];
31 31
 }
32 32
 
33 33
 -(void)testTopBarBackgroundColor_validColor{

+ 6
- 4
lib/src/adapters/NativeCommandsSender.js View File

@@ -17,8 +17,9 @@ class NativeCommandsSender {
17 17
     this.nativeCommandsModule.setOptions(containerId, options);
18 18
   }
19 19
 
20
-  push(onContainerId, layout) {
21
-    return this.nativeCommandsModule.push(onContainerId, layout);
20
+  async push(onContainerId, layout) {
21
+    const pushedContainerId = await this.nativeCommandsModule.push(onContainerId, layout);
22
+    return pushedContainerId;
22 23
   }
23 24
 
24 25
   pop(containerId, options) {
@@ -33,8 +34,9 @@ class NativeCommandsSender {
33 34
     return this.nativeCommandsModule.popToRoot(containerId);
34 35
   }
35 36
 
36
-  showModal(layout) {
37
-    return this.nativeCommandsModule.showModal(layout);
37
+  async showModal(layout) {
38
+    const completed = await this.nativeCommandsModule.showModal(layout);
39
+    return completed;
38 40
   }
39 41
 
40 42
   dismissModal(containerId) {