Browse Source

Handle rejections - pop and dismissModal (#4168)

* Handle pop and dismissModal rejections - #3914

* Added e2e

* Update TextScreen.js
Yogev Ben David 6 years ago
parent
commit
55ef525f6a
No account linked to committer's email address

+ 7
- 0
e2e/Modals.test.js View File

131
     await elementById(testIDs.DISMISS_MODAL_BUTTON).tap();
131
     await elementById(testIDs.DISMISS_MODAL_BUTTON).tap();
132
     await expect(elementByLabel('Modal Stack Position: 1')).toBeVisible();
132
     await expect(elementByLabel('Modal Stack Position: 1')).toBeVisible();
133
   });
133
   });
134
+
135
+  test('dismiss modal on non-modal component should not deatch component', async () => {
136
+    await elementById(testIDs.TAB_BASED_APP_BUTTON).tap();
137
+    await elementById(testIDs.DISMISS_MODAL_BUTTON).tap();
138
+    await elementById(testIDs.PUSH_BUTTON).tap();
139
+    await expect(elementById(testIDs.PUSHED_SCREEN_HEADER)).toBeVisible();
140
+  });
134
 });
141
 });

+ 7
- 0
e2e/ScreenStack.test.js View File

96
     await elementById(testIDs.POP_BUTTON).tap();
96
     await elementById(testIDs.POP_BUTTON).tap();
97
     await expect(elementByLabel('This is a side menu center screen tab 1')).toBeVisible();
97
     await expect(elementByLabel('This is a side menu center screen tab 1')).toBeVisible();
98
   });
98
   });
99
+
100
+  test('pop component should not deatch component if can`t pop', async () => {
101
+    await elementById(testIDs.TAB_BASED_APP_BUTTON).tap();
102
+    await elementById(testIDs.POP_BUTTON).tap();
103
+    await elementById(testIDs.PUSH_BUTTON).tap();
104
+    await expect(elementById(testIDs.PUSHED_SCREEN_HEADER)).toBeVisible();
105
+  });
99
 });
106
 });

+ 1
- 1
lib/ios/RNNBridgeModule.m View File

76
 RCT_EXPORT_METHOD(dismissModal:(NSString*)commandId componentId:(NSString*)componentId mergeOptions:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
76
 RCT_EXPORT_METHOD(dismissModal:(NSString*)commandId componentId:(NSString*)componentId mergeOptions:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
77
 	[_commandsHandler dismissModal:componentId mergeOptions:options completion:^{
77
 	[_commandsHandler dismissModal:componentId mergeOptions:options completion:^{
78
 		resolve(componentId);
78
 		resolve(componentId);
79
-	}];
79
+	} rejection:reject];
80
 }
80
 }
81
 
81
 
82
 RCT_EXPORT_METHOD(dismissAllModals:(NSString*)commandId mergeOptions:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
82
 RCT_EXPORT_METHOD(dismissAllModals:(NSString*)commandId mergeOptions:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {

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

26
 
26
 
27
 - (void)showModal:(NSDictionary*)layout completion:(RNNTransitionWithComponentIdCompletionBlock)completion;
27
 - (void)showModal:(NSDictionary*)layout completion:(RNNTransitionWithComponentIdCompletionBlock)completion;
28
 
28
 
29
-- (void)dismissModal:(NSString*)componentId mergeOptions:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion;
29
+- (void)dismissModal:(NSString*)componentId mergeOptions:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject;
30
 
30
 
31
 - (void)dismissAllModals:(NSDictionary *)options completion:(RNNTransitionCompletionBlock)completion;
31
 - (void)dismissAllModals:(NSDictionary *)options completion:(RNNTransitionCompletionBlock)completion;
32
 
32
 

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

9
 #import "React/RCTUIManager.h"
9
 #import "React/RCTUIManager.h"
10
 #import "RNNErrorHandler.h"
10
 #import "RNNErrorHandler.h"
11
 #import "RNNDefaultOptionsHelper.h"
11
 #import "RNNDefaultOptionsHelper.h"
12
+#import "UIViewController+RNNOptions.h"
12
 
13
 
13
 static NSString* const setRoot	= @"setRoot";
14
 static NSString* const setRoot	= @"setRoot";
14
 static NSString* const setStackRoot	= @"setStackRoot";
15
 static NSString* const setStackRoot	= @"setStackRoot";
188
 		[_store removeComponent:componentId];
189
 		[_store removeComponent:componentId];
189
 		[_eventEmitter sendOnNavigationCommandCompletion:pop params:@{@"componentId": componentId}];
190
 		[_eventEmitter sendOnNavigationCommandCompletion:pop params:@{@"componentId": componentId}];
190
 		completion();
191
 		completion();
191
-	} rejection:^(NSString *code, NSString *message, NSError *error) {
192
-		
193
-	}];
192
+	} rejection:rejection];
194
 }
193
 }
195
 
194
 
196
 - (void)popTo:(NSString*)componentId mergeOptions:(NSDictionary *)mergeOptions completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
195
 - (void)popTo:(NSString*)componentId mergeOptions:(NSDictionary *)mergeOptions completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
240
 	}];
239
 	}];
241
 }
240
 }
242
 
241
 
243
-- (void)dismissModal:(NSString*)componentId mergeOptions:(NSDictionary *)mergeOptions completion:(RNNTransitionCompletionBlock)completion {
242
+- (void)dismissModal:(NSString*)componentId mergeOptions:(NSDictionary *)mergeOptions completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject {
244
 	[self assertReady];
243
 	[self assertReady];
245
 	
244
 	
246
-	[CATransaction begin];
247
-	[CATransaction setCompletionBlock:^{
248
-		[_eventEmitter sendOnNavigationCommandCompletion:dismissModal params:@{@"componentId": componentId}];
249
-	}];
250
 	UIViewController<RNNParentProtocol> *modalToDismiss = (UIViewController<RNNParentProtocol>*)[_store findComponentForId:componentId];
245
 	UIViewController<RNNParentProtocol> *modalToDismiss = (UIViewController<RNNParentProtocol>*)[_store findComponentForId:componentId];
246
+	
247
+	if (!modalToDismiss.isModal) {
248
+		[RNNErrorHandler reject:reject withErrorCode:1013 errorDescription:@"component is not a modal"];
249
+		return;
250
+	}
251
+	
251
 	RNNNavigationOptions *options = [[RNNNavigationOptions alloc] initWithDict:mergeOptions];
252
 	RNNNavigationOptions *options = [[RNNNavigationOptions alloc] initWithDict:mergeOptions];
252
 	[modalToDismiss.getCurrentChild.options overrideOptions:options];
253
 	[modalToDismiss.getCurrentChild.options overrideOptions:options];
253
 	
254
 	
254
 	[self removePopedViewControllers:modalToDismiss.navigationController.viewControllers];
255
 	[self removePopedViewControllers:modalToDismiss.navigationController.viewControllers];
255
 	
256
 	
257
+	[CATransaction begin];
258
+	[CATransaction setCompletionBlock:^{
259
+		[_eventEmitter sendOnNavigationCommandCompletion:dismissModal params:@{@"componentId": componentId}];
260
+	}];
261
+	
256
 	[_modalManager dismissModal:modalToDismiss completion:completion];
262
 	[_modalManager dismissModal:modalToDismiss completion:completion];
257
 	
263
 	
258
 	[CATransaction commit];
264
 	[CATransaction commit];

+ 9
- 2
lib/ios/RNNNavigationStackManager.m View File

25
 		animated = NO;
25
 		animated = NO;
26
 	}
26
 	}
27
 	
27
 	
28
+	__block UIViewController *poppedVC = nil;
28
 	[self performAnimationBlock:^{
29
 	[self performAnimationBlock:^{
29
-		[viewController.navigationController popViewControllerAnimated:animated];
30
-	} completion:completion];
30
+		poppedVC = [viewController.navigationController popViewControllerAnimated:animated];
31
+	} completion:^{
32
+		if (poppedVC) {
33
+			completion();
34
+		} else {
35
+			[RNNErrorHandler reject:rejection withErrorCode:1012 errorDescription:@"popping component failed"];
36
+		}
37
+	}];
31
 }
38
 }
32
 
39
 
33
 - (void)popTo:(UIViewController *)viewController animated:(BOOL)animated completion:(RNNPopCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)rejection; {
40
 - (void)popTo:(UIViewController *)viewController animated:(BOOL)animated completion:(RNNPopCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)rejection; {

+ 2
- 0
lib/ios/UIViewController+RNNOptions.h View File

32
 
32
 
33
 - (void)rnn_setBackgroundColor:(UIColor *)backgroundColor;
33
 - (void)rnn_setBackgroundColor:(UIColor *)backgroundColor;
34
 
34
 
35
+- (BOOL)isModal;
36
+
35
 @end
37
 @end

+ 11
- 0
lib/ios/UIViewController+RNNOptions.m View File

134
 	return animated ? kStatusBarAnimationDuration : CGFLOAT_MIN;
134
 	return animated ? kStatusBarAnimationDuration : CGFLOAT_MIN;
135
 }
135
 }
136
 
136
 
137
+- (BOOL)isModal {
138
+	if([self presentingViewController])
139
+		return YES;
140
+	if([[[self navigationController] presentingViewController] presentedViewController] == [self navigationController])
141
+		return YES;
142
+	if([[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]])
143
+		return YES;
144
+	
145
+	return NO;
146
+}
147
+
137
 
148
 
138
 @end
149
 @end

+ 5
- 0
playground/src/screens/TextScreen.js View File

37
           <Button title='Show Right Side Menu' testID={testIDs.SHOW_RIGHT_SIDE_MENU_BUTTON} onPress={() => this.showSideMenu('right')} />
37
           <Button title='Show Right Side Menu' testID={testIDs.SHOW_RIGHT_SIDE_MENU_BUTTON} onPress={() => this.showSideMenu('right')} />
38
           <Button title='Push' testID={testIDs.PUSH_BUTTON} onPress={this.onClickPush} />
38
           <Button title='Push' testID={testIDs.PUSH_BUTTON} onPress={this.onClickPush} />
39
           <Button title='Pop' testID={testIDs.POP_BUTTON} onPress={this.onClickPop} />
39
           <Button title='Pop' testID={testIDs.POP_BUTTON} onPress={this.onClickPop} />
40
+          <Button title='Dismiss modal' testID={testIDs.DISMISS_MODAL_BUTTON} onPress={this.onClickDismissModal} />
40
         </View>
41
         </View>
41
       </Bounds>
42
       </Bounds>
42
     );
43
     );
58
     });
59
     });
59
   }
60
   }
60
 
61
 
62
+  onClickDismissModal = () => {
63
+    Navigation.dismissModal(this.props.componentId);
64
+  }
65
+
61
   onClickPop = async () => {
66
   onClickPop = async () => {
62
     await Navigation.pop(this.props.componentId);
67
     await Navigation.pop(this.props.componentId);
63
   }
68
   }