Browse Source

Fixes detached overlays on setRoot (#4204)

Yogev Ben David 5 years ago
parent
commit
7811baa00a
No account linked to committer's email address

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

23
 	RCTBridge* _bridge;
23
 	RCTBridge* _bridge;
24
 
24
 
25
 	RNNStore* _store;
25
 	RNNStore* _store;
26
+	RNNStore* _overlayStore;
26
 
27
 
27
 	RNNCommandsHandler* _commandsHandler;
28
 	RNNCommandsHandler* _commandsHandler;
28
 }
29
 }
34
 		_delegate = delegate;
35
 		_delegate = delegate;
35
 		
36
 		
36
 		_store = [RNNStore new];
37
 		_store = [RNNStore new];
38
+		_overlayStore = [RNNStore new];
37
 		_bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:_launchOptions];
39
 		_bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:_launchOptions];
38
 
40
 
39
 		[[NSNotificationCenter defaultCenter] addObserver:self
41
 		[[NSNotificationCenter defaultCenter] addObserver:self
74
 	RNNEventEmitter *eventEmitter = [[RNNEventEmitter alloc] init];
76
 	RNNEventEmitter *eventEmitter = [[RNNEventEmitter alloc] init];
75
 
77
 
76
 	id<RNNRootViewCreator> rootViewCreator = [[RNNReactRootViewCreator alloc] initWithBridge:bridge];
78
 	id<RNNRootViewCreator> rootViewCreator = [[RNNReactRootViewCreator alloc] initWithBridge:bridge];
77
-	RNNControllerFactory *controllerFactory = [[RNNControllerFactory alloc] initWithRootViewCreator:rootViewCreator store:_store eventEmitter:eventEmitter andBridge:bridge];
78
-	_commandsHandler = [[RNNCommandsHandler alloc] initWithStore:_store controllerFactory:controllerFactory eventEmitter:eventEmitter];
79
+	RNNControllerFactory *controllerFactory = [[RNNControllerFactory alloc] initWithRootViewCreator:rootViewCreator eventEmitter:eventEmitter andBridge:bridge];
80
+	
81
+	_commandsHandler = [[RNNCommandsHandler alloc] initWithStore:_store overlayStore:_overlayStore controllerFactory:controllerFactory eventEmitter:eventEmitter stackManager:[RNNNavigationStackManager new] modalManager:[RNNModalManager new] overlayManager:[RNNOverlayManager new]];
79
 	RNNBridgeModule *bridgeModule = [[RNNBridgeModule alloc] initWithCommandsHandler:_commandsHandler];
82
 	RNNBridgeModule *bridgeModule = [[RNNBridgeModule alloc] initWithCommandsHandler:_commandsHandler];
80
 
83
 
81
 	return [@[bridgeModule,eventEmitter] arrayByAddingObjectsFromArray:[self extraModulesFromDelegate]];
84
 	return [@[bridgeModule,eventEmitter] arrayByAddingObjectsFromArray:[self extraModulesFromDelegate]];
85
 
88
 
86
 - (void)onJavaScriptWillLoad {
89
 - (void)onJavaScriptWillLoad {
87
 	[_store clean];
90
 	[_store clean];
91
+	[_overlayStore clean];
88
 }
92
 }
89
 
93
 
90
 - (void)onJavaScriptLoaded {
94
 - (void)onJavaScriptLoaded {
91
 	[_store setReadyToReceiveCommands:true];
95
 	[_store setReadyToReceiveCommands:true];
96
+	[_overlayStore setReadyToReceiveCommands:true];
92
 	[[_bridge moduleForClass:[RNNEventEmitter class]] sendOnAppLaunched];
97
 	[[_bridge moduleForClass:[RNNEventEmitter class]] sendOnAppLaunched];
93
 }
98
 }
94
 
99
 

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

3
 
3
 
4
 #import "RNNControllerFactory.h"
4
 #import "RNNControllerFactory.h"
5
 #import "RNNStore.h"
5
 #import "RNNStore.h"
6
+#import "RNNModalManager.h"
7
+#import "RNNNavigationStackManager.h"
8
+#import "RNNOverlayManager.h"
6
 
9
 
7
 @interface RNNCommandsHandler : NSObject
10
 @interface RNNCommandsHandler : NSObject
8
 
11
 
9
-- (instancetype)initWithStore:(RNNStore*)store controllerFactory:(RNNControllerFactory*)controllerFactory eventEmitter:(RNNEventEmitter*)eventEmitter;
12
+- (instancetype)initWithStore:(RNNStore*)store overlayStore:(RNNStore*)overlayStore controllerFactory:(RNNControllerFactory*)controllerFactory eventEmitter:(RNNEventEmitter *)eventEmitter stackManager:(RNNNavigationStackManager *)stackManager modalManager:(RNNModalManager *)modalManager overlayManager:(RNNOverlayManager *)overlayManager;
10
 
13
 
11
 - (void)setRoot:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion;
14
 - (void)setRoot:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion;
12
 
15
 

+ 12
- 13
lib/ios/RNNCommandsHandler.m View File

1
 #import "RNNCommandsHandler.h"
1
 #import "RNNCommandsHandler.h"
2
-#import "RNNModalManager.h"
3
-#import "RNNNavigationStackManager.h"
4
-#import "RNNOverlayManager.h"
5
 #import "RNNNavigationOptions.h"
2
 #import "RNNNavigationOptions.h"
6
 #import "RNNRootViewController.h"
3
 #import "RNNRootViewController.h"
7
 #import "RNNSplitViewController.h"
4
 #import "RNNSplitViewController.h"
33
 @implementation RNNCommandsHandler {
30
 @implementation RNNCommandsHandler {
34
 	RNNControllerFactory *_controllerFactory;
31
 	RNNControllerFactory *_controllerFactory;
35
 	RNNStore *_store;
32
 	RNNStore *_store;
33
+	RNNStore *_overlayStore;
36
 	RNNModalManager* _modalManager;
34
 	RNNModalManager* _modalManager;
37
 	RNNOverlayManager* _overlayManager;
35
 	RNNOverlayManager* _overlayManager;
38
 	RNNNavigationStackManager* _stackManager;
36
 	RNNNavigationStackManager* _stackManager;
39
 	RNNEventEmitter* _eventEmitter;
37
 	RNNEventEmitter* _eventEmitter;
40
 }
38
 }
41
 
39
 
42
-- (instancetype)initWithStore:(RNNStore*)store controllerFactory:(RNNControllerFactory*)controllerFactory eventEmitter:(RNNEventEmitter *)eventEmitter {
40
+- (instancetype)initWithStore:(RNNStore*)store overlayStore:(RNNStore*)overlayStore controllerFactory:(RNNControllerFactory*)controllerFactory eventEmitter:(RNNEventEmitter *)eventEmitter stackManager:(RNNNavigationStackManager *)stackManager modalManager:(RNNModalManager *)modalManager overlayManager:(RNNOverlayManager *)overlayManager {
43
 	self = [super init];
41
 	self = [super init];
44
 	_store = store;
42
 	_store = store;
43
+	_overlayStore = overlayStore;
45
 	_controllerFactory = controllerFactory;
44
 	_controllerFactory = controllerFactory;
46
 	_eventEmitter = eventEmitter;
45
 	_eventEmitter = eventEmitter;
47
-	_modalManager = [[RNNModalManager alloc] init];
46
+	_modalManager = modalManager;
48
 	_modalManager.delegate = self;
47
 	_modalManager.delegate = self;
49
-	_stackManager = [[RNNNavigationStackManager alloc] init];
50
-	_overlayManager = [[RNNOverlayManager alloc] init];
48
+	_stackManager = stackManager;
49
+	_overlayManager = overlayManager;
51
 	return self;
50
 	return self;
52
 }
51
 }
53
 
52
 
59
 	[_modalManager dismissAllModalsAnimated:NO];
58
 	[_modalManager dismissAllModalsAnimated:NO];
60
 	[_store removeAllComponents];
59
 	[_store removeAllComponents];
61
 	
60
 	
62
-	UIViewController *vc = [_controllerFactory createLayoutAndSaveToStore:layout[@"root"]];
61
+	UIViewController *vc = [_controllerFactory createLayout:layout[@"root"] saveToStore:_store];
63
 	
62
 	
64
 	UIApplication.sharedApplication.delegate.window.rootViewController = vc;
63
 	UIApplication.sharedApplication.delegate.window.rootViewController = vc;
65
 	[UIApplication.sharedApplication.delegate.window makeKeyWindow];
64
 	[UIApplication.sharedApplication.delegate.window makeKeyWindow];
97
 - (void)push:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
96
 - (void)push:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
98
 	[self assertReady];
97
 	[self assertReady];
99
 	
98
 	
100
-	UIViewController<RNNLayoutProtocol> *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];
99
+	UIViewController<RNNLayoutProtocol> *newVc = [_controllerFactory createLayout:layout saveToStore:_store];
101
 	UIViewController *fromVC = [_store findComponentForId:componentId];
100
 	UIViewController *fromVC = [_store findComponentForId:componentId];
102
 	
101
 	
103
 	if ([newVc.options.preview.reactTag floatValue] > 0) {
102
 	if ([newVc.options.preview.reactTag floatValue] > 0) {
154
 - (void)setStackRoot:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
153
 - (void)setStackRoot:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
155
 	[self assertReady];
154
 	[self assertReady];
156
 	
155
 	
157
-	UIViewController<RNNParentProtocol> *newVC = [_controllerFactory createLayoutAndSaveToStore:layout];
156
+	UIViewController<RNNParentProtocol> *newVC = [_controllerFactory createLayout:layout saveToStore:_store];
158
 	RNNNavigationOptions* options = [newVC getCurrentChild].options;
157
 	RNNNavigationOptions* options = [newVC getCurrentChild].options;
159
 	UIViewController *fromVC = [_store findComponentForId:componentId];
158
 	UIViewController *fromVC = [_store findComponentForId:componentId];
160
 	__weak typeof(RNNEventEmitter*) weakEventEmitter = _eventEmitter;
159
 	__weak typeof(RNNEventEmitter*) weakEventEmitter = _eventEmitter;
229
 - (void)showModal:(NSDictionary*)layout completion:(RNNTransitionWithComponentIdCompletionBlock)completion {
228
 - (void)showModal:(NSDictionary*)layout completion:(RNNTransitionWithComponentIdCompletionBlock)completion {
230
 	[self assertReady];
229
 	[self assertReady];
231
 	
230
 	
232
-	UIViewController<RNNParentProtocol> *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];
231
+	UIViewController<RNNParentProtocol> *newVc = [_controllerFactory createLayout:layout saveToStore:_store];
233
 	
232
 	
234
 	[newVc.getCurrentChild waitForReactViewRender:newVc.getCurrentChild.options.animations.showModal.waitForRender perform:^{
233
 	[newVc.getCurrentChild waitForReactViewRender:newVc.getCurrentChild.options.animations.showModal.waitForRender perform:^{
235
 		[_modalManager showModal:newVc animated:newVc.getCurrentChild.options.animations.showModal.enable hasCustomAnimation:newVc.getCurrentChild.options.animations.showModal.hasCustomAnimation completion:^(NSString *componentId) {
234
 		[_modalManager showModal:newVc animated:newVc.getCurrentChild.options.animations.showModal.enable hasCustomAnimation:newVc.getCurrentChild.options.animations.showModal.hasCustomAnimation completion:^(NSString *componentId) {
281
 - (void)showOverlay:(NSDictionary *)layout completion:(RNNTransitionCompletionBlock)completion {
280
 - (void)showOverlay:(NSDictionary *)layout completion:(RNNTransitionCompletionBlock)completion {
282
 	[self assertReady];
281
 	[self assertReady];
283
 	
282
 	
284
-	UIViewController<RNNParentProtocol>* overlayVC = [_controllerFactory createLayoutAndSaveToStore:layout];
283
+	UIViewController<RNNParentProtocol>* overlayVC = [_controllerFactory createLayout:layout saveToStore:_overlayStore];
285
 	[_overlayManager showOverlay:overlayVC];
284
 	[_overlayManager showOverlay:overlayVC];
286
 	[_eventEmitter sendOnNavigationCommandCompletion:showOverlay params:@{@"layout": layout}];
285
 	[_eventEmitter sendOnNavigationCommandCompletion:showOverlay params:@{@"layout": layout}];
287
 	completion();
286
 	completion();
289
 
288
 
290
 - (void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject {
289
 - (void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject {
291
 	[self assertReady];
290
 	[self assertReady];
292
-	UIViewController* viewController = [_store findComponentForId:componentId];
291
+	UIViewController* viewController = [_overlayStore findComponentForId:componentId];
293
 	if (viewController) {
292
 	if (viewController) {
294
 		[_overlayManager dismissOverlay:viewController];
293
 		[_overlayManager dismissOverlay:viewController];
295
 		[_eventEmitter sendOnNavigationCommandCompletion:dismissOverlay params:@{@"componentId": componentId}];
294
 		[_eventEmitter sendOnNavigationCommandCompletion:dismissOverlay params:@{@"componentId": componentId}];

+ 1
- 2
lib/ios/RNNControllerFactory.h View File

9
 @interface RNNControllerFactory : NSObject
9
 @interface RNNControllerFactory : NSObject
10
 
10
 
11
 -(instancetype)initWithRootViewCreator:(id <RNNRootViewCreator>)creator
11
 -(instancetype)initWithRootViewCreator:(id <RNNRootViewCreator>)creator
12
-								 store:(RNNStore*)store
13
 						  eventEmitter:(RNNEventEmitter*)eventEmitter
12
 						  eventEmitter:(RNNEventEmitter*)eventEmitter
14
 							 andBridge:(RCTBridge*)bridge;
13
 							 andBridge:(RCTBridge*)bridge;
15
 
14
 
16
--(UIViewController<RNNParentProtocol, UIViewControllerPreviewingDelegate> *)createLayoutAndSaveToStore:(NSDictionary*)layout;
15
+- (UIViewController<RNNParentProtocol> *)createLayout:(NSDictionary*)layout saveToStore:(RNNStore *)store;
17
 
16
 
18
 @property (nonatomic, strong) RNNEventEmitter *eventEmitter;
17
 @property (nonatomic, strong) RNNEventEmitter *eventEmitter;
19
 
18
 

+ 5
- 4
lib/ios/RNNControllerFactory.m View File

25
 
25
 
26
 
26
 
27
 - (instancetype)initWithRootViewCreator:(id <RNNRootViewCreator>)creator
27
 - (instancetype)initWithRootViewCreator:(id <RNNRootViewCreator>)creator
28
-								  store:(RNNStore *)store
29
 						   eventEmitter:(RNNEventEmitter*)eventEmitter
28
 						   eventEmitter:(RNNEventEmitter*)eventEmitter
30
 							  andBridge:(RCTBridge *)bridge {
29
 							  andBridge:(RCTBridge *)bridge {
31
 	
30
 	
32
 	self = [super init];
31
 	self = [super init];
33
 	
32
 	
34
 	_creator = creator;
33
 	_creator = creator;
35
-	_store = store;
36
 	_eventEmitter = eventEmitter;
34
 	_eventEmitter = eventEmitter;
37
 	_bridge = bridge;
35
 	_bridge = bridge;
38
 	
36
 	
39
 	return self;
37
 	return self;
40
 }
38
 }
41
 
39
 
42
-- (UIViewController<RNNParentProtocol> *)createLayoutAndSaveToStore:(NSDictionary*)layout {
43
-	return [self fromTree:layout];
40
+- (UIViewController<RNNParentProtocol> *)createLayout:(NSDictionary*)layout saveToStore:(RNNStore *)store {
41
+	_store = store;
42
+	UIViewController<RNNParentProtocol>* layoutViewController = [self fromTree:layout];
43
+	_store = nil;
44
+	return layoutViewController;
44
 }
45
 }
45
 
46
 
46
 # pragma mark private
47
 # pragma mark private

+ 0
- 7
lib/ios/RNNOverlayOptions.m View File

11
 	return self;
11
 	return self;
12
 }
12
 }
13
 
13
 
14
-- (void)applyOn:(UIViewController *)viewController {
15
-//	if (self.interceptTouchOutside) {
16
-//		RCTRootView* rootView = (RCTRootView*)viewController.view;
17
-//		rootView.passThroughTouches = ![self.interceptTouchOutside boolValue];
18
-//	}
19
-}
20
-
21
 @end
14
 @end

+ 7
- 0
lib/ios/RNNViewControllerPresenter.m View File

3
 #import "UITabBarController+RNNOptions.h"
3
 #import "UITabBarController+RNNOptions.h"
4
 #import "RNNNavigationButtons.h"
4
 #import "RNNNavigationButtons.h"
5
 #import "RCTConvert+Modal.h"
5
 #import "RCTConvert+Modal.h"
6
+#import "RNNReactView.h"
6
 
7
 
7
 @interface RNNViewControllerPresenter()
8
 @interface RNNViewControllerPresenter()
8
 @property (nonatomic, strong) RNNNavigationButtons* navigationButtons;
9
 @property (nonatomic, strong) RNNNavigationButtons* navigationButtons;
23
 	[viewController rnn_setStatusBarBlur:[options.statusBar.blur getWithDefaultValue:NO]];
24
 	[viewController rnn_setStatusBarBlur:[options.statusBar.blur getWithDefaultValue:NO]];
24
 	[viewController rnn_setStatusBarStyle:[options.statusBar.style getWithDefaultValue:@"default"] animated:[options.statusBar.animate getWithDefaultValue:YES]];
25
 	[viewController rnn_setStatusBarStyle:[options.statusBar.style getWithDefaultValue:@"default"] animated:[options.statusBar.animate getWithDefaultValue:YES]];
25
 	[viewController rnn_setBackButtonVisible:[options.topBar.backButton.visible getWithDefaultValue:YES]];
26
 	[viewController rnn_setBackButtonVisible:[options.topBar.backButton.visible getWithDefaultValue:YES]];
27
+	[viewController rnn_setInterceptTouchOutside:[options.overlay.interceptTouchOutside getWithDefaultValue:YES]];
26
 
28
 
27
 	if (options.layout.backgroundColor.hasValue) {
29
 	if (options.layout.backgroundColor.hasValue) {
28
 		[viewController rnn_setBackgroundColor:options.layout.backgroundColor.get];
30
 		[viewController rnn_setBackgroundColor:options.layout.backgroundColor.get];
117
 		_navigationButtons = [[RNNNavigationButtons alloc] initWithViewController:(RNNRootViewController*)viewController];
119
 		_navigationButtons = [[RNNNavigationButtons alloc] initWithViewController:(RNNRootViewController*)viewController];
118
 		[_navigationButtons applyLeftButtons:options.topBar.leftButtons rightButtons:options.topBar.rightButtons defaultLeftButtonStyle:buttonsResolvedOptions.topBar.leftButtonStyle defaultRightButtonStyle:buttonsResolvedOptions.topBar.rightButtonStyle];
120
 		[_navigationButtons applyLeftButtons:options.topBar.leftButtons rightButtons:options.topBar.rightButtons defaultLeftButtonStyle:buttonsResolvedOptions.topBar.leftButtonStyle defaultRightButtonStyle:buttonsResolvedOptions.topBar.rightButtonStyle];
119
 	}
121
 	}
122
+	
123
+	if (options.overlay.interceptTouchOutside.hasValue) {
124
+		RCTRootView* rootView = (RCTRootView*)viewController.view;
125
+		rootView.passThroughTouches = !options.overlay.interceptTouchOutside.get;
126
+	}
120
 }
127
 }
121
 
128
 
122
 @end
129
 @end

+ 96
- 3
lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m View File

4
 #import "RNNNavigationOptions.h"
4
 #import "RNNNavigationOptions.h"
5
 #import "RNNTestRootViewCreator.h"
5
 #import "RNNTestRootViewCreator.h"
6
 #import "RNNRootViewController.h"
6
 #import "RNNRootViewController.h"
7
-#import "RNNNavigationStackManager.h"
8
 #import "RNNNavigationController.h"
7
 #import "RNNNavigationController.h"
8
+#import "RNNErrorHandler.h"
9
+#import <OCMock/OCMock.h>
9
 
10
 
10
 @interface MockUINavigationController : RNNNavigationController
11
 @interface MockUINavigationController : RNNNavigationController
11
 @property (nonatomic, strong) NSArray* willReturnVCs;
12
 @property (nonatomic, strong) NSArray* willReturnVCs;
26
 @interface RNNCommandsHandlerTest : XCTestCase
27
 @interface RNNCommandsHandlerTest : XCTestCase
27
 
28
 
28
 @property (nonatomic, strong) RNNStore* store;
29
 @property (nonatomic, strong) RNNStore* store;
30
+@property (nonatomic, strong) id overlayStore;
29
 @property (nonatomic, strong) RNNCommandsHandler* uut;
31
 @property (nonatomic, strong) RNNCommandsHandler* uut;
30
 @property (nonatomic, strong) RNNRootViewController* vc1;
32
 @property (nonatomic, strong) RNNRootViewController* vc1;
31
 @property (nonatomic, strong) RNNRootViewController* vc2;
33
 @property (nonatomic, strong) RNNRootViewController* vc2;
32
 @property (nonatomic, strong) RNNRootViewController* vc3;
34
 @property (nonatomic, strong) RNNRootViewController* vc3;
33
 @property (nonatomic, strong) MockUINavigationController* nvc;
35
 @property (nonatomic, strong) MockUINavigationController* nvc;
36
+@property (nonatomic, strong) id controllerFactory;
37
+@property (nonatomic, strong) id overlayManager;
38
+@property (nonatomic, strong) id eventEmmiter;
34
 
39
 
35
 @end
40
 @end
36
 
41
 
40
 	[super setUp];
45
 	[super setUp];
41
 //	[self.store setReadyToReceiveCommands:true];
46
 //	[self.store setReadyToReceiveCommands:true];
42
 	self.store = [[RNNStore alloc] init];
47
 	self.store = [[RNNStore alloc] init];
43
-	self.uut = [[RNNCommandsHandler alloc] initWithStore:self.store controllerFactory:[[RNNControllerFactory alloc] initWithRootViewCreator:nil store:self.store eventEmitter:nil andBridge:nil] eventEmitter:nil];
48
+	self.overlayStore = [OCMockObject partialMockForObject:[[RNNStore alloc] init]];
49
+	self.eventEmmiter = [OCMockObject partialMockForObject:[RNNEventEmitter new]];
50
+	self.overlayManager = [OCMockObject partialMockForObject:[RNNOverlayManager new]];
51
+	self.controllerFactory = [OCMockObject partialMockForObject:[[RNNControllerFactory alloc] initWithRootViewCreator:nil eventEmitter:self.eventEmmiter andBridge:nil]];
52
+	self.uut = [[RNNCommandsHandler alloc] initWithStore:self.store overlayStore:self.overlayStore controllerFactory:self.controllerFactory eventEmitter:self.eventEmmiter stackManager:[RNNNavigationStackManager new] modalManager:[RNNModalManager new] overlayManager:self.overlayManager];
44
 	self.vc1 = [RNNRootViewController new];
53
 	self.vc1 = [RNNRootViewController new];
45
 	self.vc2 = [RNNRootViewController new];
54
 	self.vc2 = [RNNRootViewController new];
46
 	self.vc3 = [RNNRootViewController new];
55
 	self.vc3 = [RNNRootViewController new];
67
 -(NSArray*) getPublicMethodNamesForObject:(NSObject*)obj{
76
 -(NSArray*) getPublicMethodNamesForObject:(NSObject*)obj{
68
 	NSMutableArray* skipMethods = [NSMutableArray new];
77
 	NSMutableArray* skipMethods = [NSMutableArray new];
69
 
78
 
70
-	[skipMethods addObject:@"initWithStore:controllerFactory:eventEmitter:"];
79
+	[skipMethods addObject:@"initWithStore:overlayStore:controllerFactory:eventEmitter:stackManager:modalManager:overlayManager:"];
71
 	[skipMethods addObject:@"assertReady"];
80
 	[skipMethods addObject:@"assertReady"];
72
 	[skipMethods addObject:@"removePopedViewControllers:"];
81
 	[skipMethods addObject:@"removePopedViewControllers:"];
73
 	[skipMethods addObject:@".cxx_destruct"];
82
 	[skipMethods addObject:@".cxx_destruct"];
184
 	[self waitForExpectationsWithTimeout:1 handler:nil];
193
 	[self waitForExpectationsWithTimeout:1 handler:nil];
185
 }
194
 }
186
 
195
 
196
+- (void)testShowOverlay_createLayout {
197
+	[self.store setReadyToReceiveCommands:true];
198
+	OCMStub([self.overlayManager showOverlay:[OCMArg any]]);
199
+	NSDictionary* layout = @{};
200
+	
201
+	[[self.controllerFactory expect] createLayout:layout saveToStore:self.overlayStore];
202
+	[self.uut showOverlay:layout completion:^{}];
203
+	[self.controllerFactory verify];
204
+}
205
+
206
+- (void)testShowOverlay_saveToOverlayStore {
207
+	[self.store setReadyToReceiveCommands:true];
208
+	OCMStub([self.overlayManager showOverlay:[OCMArg any]]);
209
+	OCMStub([self.controllerFactory createLayout:[OCMArg any] saveToStore:[OCMArg any]]);
210
+	
211
+	[[self.controllerFactory expect] createLayout:[OCMArg any] saveToStore:self.overlayStore];
212
+	[self.uut showOverlay:@{} completion:^{}];
213
+	[self.overlayManager verify];
214
+}
215
+
216
+- (void)testShowOverlay_withCreatedLayout {
217
+	[self.store setReadyToReceiveCommands:true];
218
+	UIViewController* layoutVC = [RNNRootViewController new];
219
+	OCMStub([self.controllerFactory createLayout:[OCMArg any] saveToStore:[OCMArg any]]).andReturn(layoutVC);
220
+	
221
+	[[self.overlayManager expect] showOverlay:layoutVC];
222
+	[self.uut showOverlay:@{} completion:^{}];
223
+	[self.overlayManager verify];
224
+}
225
+
226
+- (void)testShowOverlay_invokeNavigationCommandEventWithLayout {
227
+	[self.store setReadyToReceiveCommands:true];
228
+	OCMStub([self.overlayManager showOverlay:[OCMArg any]]);
229
+	OCMStub([self.controllerFactory createLayout:[OCMArg any] saveToStore:[OCMArg any]]);
230
+
231
+	NSDictionary* layout = @{};
232
+	
233
+	[[self.eventEmmiter expect] sendOnNavigationCommandCompletion:@"showOverlay" params:[OCMArg any]];
234
+	[self.uut showOverlay:layout completion:^{}];
235
+	[self.eventEmmiter verify];
236
+}
237
+
238
+- (void)testDismissOverlay_findComponentFromOverlayStore {
239
+	[self.store setReadyToReceiveCommands:true];
240
+	NSString* componentId = @"componentId";
241
+	[[self.overlayStore expect] findComponentForId:componentId];
242
+	[self.uut dismissOverlay:componentId completion:^{} rejection:^(NSString *code, NSString *message, NSError *error) {}];
243
+	[self.overlayStore verify];
244
+}
245
+
246
+- (void)testDismissOverlay_dismissReturnedViewController {
247
+	[self.store setReadyToReceiveCommands:true];
248
+	NSString* componentId = @"componentId";
249
+	UIViewController* returnedView = [UIViewController new];
250
+	OCMStub([self.overlayStore findComponentForId:componentId]).andReturn(returnedView);
251
+	
252
+	[[self.overlayManager expect] dismissOverlay:returnedView];
253
+	[self.uut dismissOverlay:componentId completion:^{} rejection:^(NSString *code, NSString *message, NSError *error) {}];
254
+	[self.overlayManager verify];
255
+}
256
+
257
+- (void)testDismissOverlay_handleErrorIfNoOverlayExists {
258
+	[self.store setReadyToReceiveCommands:true];
259
+	NSString* componentId = @"componentId";
260
+    id errorHandlerMockClass = [OCMockObject mockForClass:[RNNErrorHandler class]];
261
+	
262
+    [[errorHandlerMockClass expect] reject:[OCMArg any] withErrorCode:1010 errorDescription:[OCMArg any]];
263
+    [self.uut dismissOverlay:componentId completion:[OCMArg any] rejection:[OCMArg any]];
264
+    [errorHandlerMockClass verify];
265
+}
266
+
267
+- (void)testDismissOverlay_invokeNavigationCommandEvent {
268
+	[self.store setReadyToReceiveCommands:true];
269
+	NSString* componentId = @"componentId";
270
+	OCMStub([self.overlayStore findComponentForId:componentId]).andReturn([UIViewController new]);
271
+	
272
+	[[self.eventEmmiter expect] sendOnNavigationCommandCompletion:@"dismissOverlay" params:[OCMArg any]];
273
+	[self.uut dismissOverlay:componentId completion:^{
274
+		
275
+	} rejection:^(NSString *code, NSString *message, NSError *error) {}];
276
+	 
277
+	[self.eventEmmiter verify];
278
+}
279
+
187
 @end
280
 @end

+ 101
- 102
lib/ios/ReactNativeNavigationTests/RNNControllerFactoryTest.m View File

22
 	[super setUp];
22
 	[super setUp];
23
 	self.creator = nil;
23
 	self.creator = nil;
24
 	self.store = [RNNStore new];
24
 	self.store = [RNNStore new];
25
-	self.factory = [[RNNControllerFactory alloc] initWithRootViewCreator:self.creator store:self.store eventEmitter:nil andBridge:nil];
25
+	self.factory = [[RNNControllerFactory alloc] initWithRootViewCreator:self.creator eventEmitter:nil andBridge:nil];
26
 }
26
 }
27
 
27
 
28
 - (void)tearDown {
28
 - (void)tearDown {
30
 }
30
 }
31
 
31
 
32
 - (void)testCreateLayout_EmptyLayout {
32
 - (void)testCreateLayout_EmptyLayout {
33
-	XCTAssertThrows([self.factory createLayoutAndSaveToStore:@{}]);
33
+	XCTAssertThrows([self.factory createLayout:@{} saveToStore:self.store]);
34
 }
34
 }
35
 
35
 
36
 - (void)testCreateLayout_ComponentLayout {
36
 - (void)testCreateLayout_ComponentLayout {
37
-	
38
-	id ans = [self.factory createLayoutAndSaveToStore:
39
-			  @{@"id": @"cntId",
40
-				@"type": @"Component",
41
-				@"data": @{},
42
-				@"children": @[]}];
37
+	NSDictionary* layout = @{@"id": @"cntId",
38
+							 @"type": @"Component",
39
+							 @"data": @{},
40
+							 @"children": @[]};
41
+	id ans = [self.factory createLayout:layout saveToStore:self.store];
43
 	XCTAssertTrue([ans isMemberOfClass:[RNNRootViewController class]]);
42
 	XCTAssertTrue([ans isMemberOfClass:[RNNRootViewController class]]);
44
 }
43
 }
45
 
44
 
48
 		return [UIViewController new];
47
 		return [UIViewController new];
49
 	}];
48
 	}];
50
 	
49
 	
51
-	id ans = [self.factory createLayoutAndSaveToStore:
52
-			  @{@"id": @"cntId",
53
-				@"type": @"ExternalComponent",
54
-				@"data": @{@"name": @"externalComponent"},
55
-				@"children": @[]}];
50
+	NSDictionary* layout =  @{@"id": @"cntId",
51
+							  @"type": @"ExternalComponent",
52
+							  @"data": @{@"name": @"externalComponent"},
53
+							  @"children": @[]};
54
+	id ans = [self.factory createLayout:layout saveToStore:self.store];
56
 	XCTAssertTrue([ans isMemberOfClass:[RNNRootViewController class]]);
55
 	XCTAssertTrue([ans isMemberOfClass:[RNNRootViewController class]]);
57
 }
56
 }
58
 
57
 
59
 - (void)testCreateLayout_ComponentStackLayout {
58
 - (void)testCreateLayout_ComponentStackLayout {
60
-	id ans = [self.factory createLayoutAndSaveToStore:
61
-			  @{@"id": @"cntId",
62
-				@"type": @"Stack",
63
-				@"data": @{},
64
-				@"children": @[]}];
59
+	NSDictionary* layout = @{@"id": @"cntId",
60
+							 @"type": @"Stack",
61
+							 @"data": @{},
62
+							 @"children": @[]};
63
+	id ans = [self.factory createLayout:layout saveToStore:self.store];
65
 	XCTAssertTrue([ans isMemberOfClass:[RNNNavigationController class]]);
64
 	XCTAssertTrue([ans isMemberOfClass:[RNNNavigationController class]]);
66
 }
65
 }
67
 
66
 
68
 - (void)testCreateLayout_SplitViewLayout {
67
 - (void)testCreateLayout_SplitViewLayout {
69
-	id ans = [self.factory createLayoutAndSaveToStore:
70
-			  @{@"id": @"cntId",
71
-				@"type": @"SplitView",
72
-				@"data": @{},
73
-				@"children": @[
74
-						@{@"id": @"cntId_2",
75
-						  @"type": @"Component",
76
-						  @"data": @{},
77
-						  @"children": @[]},
78
-			  @{@"id": @"cntId_3",
79
-				@"type": @"Component",
80
-				@"data": @{},
81
-				@"children": @[]}]}];
68
+	NSDictionary* layout = @{@"id": @"cntId",
69
+							 @"type": @"SplitView",
70
+							 @"data": @{},
71
+							 @"children": @[
72
+									 @{@"id": @"cntId_2",
73
+									   @"type": @"Component",
74
+									   @"data": @{},
75
+									   @"children": @[]},
76
+									 @{@"id": @"cntId_3",
77
+									   @"type": @"Component",
78
+									   @"data": @{},
79
+									   @"children": @[]}]};
80
+	id ans = [self.factory createLayout:layout saveToStore:self.store];
82
 	XCTAssertTrue([ans isMemberOfClass:[RNNSplitViewController class]]);
81
 	XCTAssertTrue([ans isMemberOfClass:[RNNSplitViewController class]]);
83
 }
82
 }
84
 
83
 
85
 - (void)testCreateLayout_ComponentStackLayoutRecursive {
84
 - (void)testCreateLayout_ComponentStackLayoutRecursive {
86
-	RNNNavigationController* ans = (RNNNavigationController*) [self.factory createLayoutAndSaveToStore:
87
-															 @{@"id": @"cntId",
88
-															   @"type": @"Stack",
89
-															   @"data": @{},
90
-															   @"children": @[
91
-																	   @{@"id": @"cntId_2",
92
-																		 @"type": @"Component",
93
-																		 @"data": @{},
94
-																		 @"children": @[]}]}];
85
+	NSDictionary* layout = @{@"id": @"cntId",
86
+							 @"type": @"Stack",
87
+							 @"data": @{},
88
+							 @"children": @[
89
+									 @{@"id": @"cntId_2",
90
+									   @"type": @"Component",
91
+									   @"data": @{},
92
+									   @"children": @[]}]};
93
+	RNNNavigationController* ans = (RNNNavigationController*) [self.factory createLayout:layout saveToStore:self.store];
95
 	
94
 	
96
 	XCTAssertTrue([ans isMemberOfClass:[RNNNavigationController class]]);
95
 	XCTAssertTrue([ans isMemberOfClass:[RNNNavigationController class]]);
97
 	XCTAssertTrue(ans.childViewControllers.count == 1);
96
 	XCTAssertTrue(ans.childViewControllers.count == 1);
99
 }
98
 }
100
 
99
 
101
 - (void)testCreateLayout_BottomTabsLayout {
100
 - (void)testCreateLayout_BottomTabsLayout {
102
-	RNNTabBarController* tabBar = (RNNTabBarController*) [self.factory createLayoutAndSaveToStore:
103
-														@{
104
-														  @"id": @"cntId",
105
-														  @"type": @"BottomTabs",
106
-														  @"data": @{},
107
-														  @"children": @[
108
-																  @{@"id": @"cntId_2",
109
-																	@"type": @"Stack",
110
-																	@"data": @{},
111
-																	@"children": @[
112
-																			@{@"id": @"cntId_3",
113
-																			  @"type": @"Component",
114
-																			  @"data": @{},
115
-																			  @"children": @[]}]}]}];
101
+	NSDictionary* layout = @{
102
+							 @"id": @"cntId",
103
+							 @"type": @"BottomTabs",
104
+							 @"data": @{},
105
+							 @"children": @[
106
+									 @{@"id": @"cntId_2",
107
+									   @"type": @"Stack",
108
+									   @"data": @{},
109
+									   @"children": @[
110
+											   @{@"id": @"cntId_3",
111
+												 @"type": @"Component",
112
+												 @"data": @{},
113
+												 @"children": @[]}]}]};
114
+	RNNTabBarController* tabBar = (RNNTabBarController*) [self.factory createLayout:layout saveToStore:self.store];
116
 	
115
 	
117
 	XCTAssertTrue([tabBar isMemberOfClass:[RNNTabBarController class]]);
116
 	XCTAssertTrue([tabBar isMemberOfClass:[RNNTabBarController class]]);
118
 	XCTAssertTrue(tabBar.childViewControllers.count == 1);
117
 	XCTAssertTrue(tabBar.childViewControllers.count == 1);
124
 }
123
 }
125
 
124
 
126
 - (void)testCreateLayout_TopTabsLayout {
125
 - (void)testCreateLayout_TopTabsLayout {
127
-	RNNTopTabsViewController* tabBar = (RNNTopTabsViewController*) [self.factory createLayoutAndSaveToStore:
128
-														  @{
129
-															@"id": @"cntId",
130
-															@"type": @"TopTabs",
131
-															@"data": @{},
132
-															@"children": @[
133
-																	@{@"id": @"cntId_2",
134
-																	  @"type": @"Stack",
135
-																	  @"data": @{},
136
-																	  @"children": @[
137
-																			  @{@"id": @"cntId_3",
138
-																				@"type": @"Component",
139
-																				@"data": @{},
140
-																				@"children": @[]}]}]}];
126
+	NSDictionary* layout = @{
127
+							 @"id": @"cntId",
128
+							 @"type": @"TopTabs",
129
+							 @"data": @{},
130
+							 @"children": @[
131
+									 @{@"id": @"cntId_2",
132
+									   @"type": @"Stack",
133
+									   @"data": @{},
134
+									   @"children": @[
135
+											   @{@"id": @"cntId_3",
136
+												 @"type": @"Component",
137
+												 @"data": @{},
138
+												 @"children": @[]}]}]};
139
+	RNNTopTabsViewController* tabBar = (RNNTopTabsViewController*) [self.factory createLayout:layout saveToStore:self.store];
141
 	
140
 	
142
 	XCTAssertTrue([tabBar isMemberOfClass:[RNNTopTabsViewController class]]);
141
 	XCTAssertTrue([tabBar isMemberOfClass:[RNNTopTabsViewController class]]);
143
 }
142
 }
144
 
143
 
145
 - (void)testCreateLayout_ComponentSideMenuLayoutCenterLeftRight {
144
 - (void)testCreateLayout_ComponentSideMenuLayoutCenterLeftRight {
146
-	RNNSideMenuController *ans = (RNNSideMenuController*) [self.factory createLayoutAndSaveToStore:
147
-														   @{@"id": @"cntId",
148
-															 @"type": @"SideMenuRoot",
149
-															 @"data": @{},
150
-															 @"children": @[
151
-																	 @{@"id": @"cntI_2",
152
-																	   @"type": @"SideMenuCenter",
153
-																	   @"data": @{},
154
-																	   @"children": @[
155
-																			   @{@"id": @"cntId_3",
156
-																				 @"type": @"Component",
157
-																				 @"data": @{},
158
-																				 @"children": @[]}]},
159
-																	 @{@"id": @"cntI_4",
160
-																	   @"type": @"SideMenuLeft",
161
-																	   @"data": @{},
162
-																	   @"children": @[
163
-																			   @{@"id": @"cntId_5",
164
-																				 @"type": @"Component",
165
-																				 @"data": @{},
166
-																				 @"children": @[]}]},
167
-																	 @{@"id": @"cntI_6",
168
-																	   @"type": @"SideMenuRight",
169
-																	   @"data": @{},
170
-																	   @"children": @[
171
-																			   @{@"id": @"cntId_7",
172
-																				 @"type": @"Component",
173
-																				 @"data": @{},
174
-																				 @"children": @[]}]}]}];
145
+	NSDictionary* layout = @{@"id": @"cntId",
146
+							 @"type": @"SideMenuRoot",
147
+							 @"data": @{},
148
+							 @"children": @[
149
+									 @{@"id": @"cntI_2",
150
+									   @"type": @"SideMenuCenter",
151
+									   @"data": @{},
152
+									   @"children": @[
153
+											   @{@"id": @"cntId_3",
154
+												 @"type": @"Component",
155
+												 @"data": @{},
156
+												 @"children": @[]}]},
157
+									 @{@"id": @"cntI_4",
158
+									   @"type": @"SideMenuLeft",
159
+									   @"data": @{},
160
+									   @"children": @[
161
+											   @{@"id": @"cntId_5",
162
+												 @"type": @"Component",
163
+												 @"data": @{},
164
+												 @"children": @[]}]},
165
+									 @{@"id": @"cntI_6",
166
+									   @"type": @"SideMenuRight",
167
+									   @"data": @{},
168
+									   @"children": @[
169
+											   @{@"id": @"cntId_7",
170
+												 @"type": @"Component",
171
+												 @"data": @{},
172
+												 @"children": @[]}]}]};
173
+	RNNSideMenuController *ans = (RNNSideMenuController*) [self.factory createLayout:layout saveToStore:self.store];
175
 	XCTAssertTrue([ans isMemberOfClass:[RNNSideMenuController class]]);
174
 	XCTAssertTrue([ans isMemberOfClass:[RNNSideMenuController class]]);
176
 	XCTAssertTrue([ans isKindOfClass:[UIViewController class]]);
175
 	XCTAssertTrue([ans isKindOfClass:[UIViewController class]]);
177
 	XCTAssertTrue([ans.center isMemberOfClass:[RNNSideMenuChildVC class]]);
176
 	XCTAssertTrue([ans.center isMemberOfClass:[RNNSideMenuChildVC class]]);
190
 
189
 
191
 - (void)testCreateLayout_addComponentToStore {
190
 - (void)testCreateLayout_addComponentToStore {
192
 	NSString *componentId = @"cntId";
191
 	NSString *componentId = @"cntId";
193
-	UIViewController *ans = [self.factory createLayoutAndSaveToStore:
194
-							 @{@"id": componentId,
195
-							   @"type": @"Component",
196
-							   @"data": @{},
197
-							   @"children": @[]}];
192
+	NSDictionary* layout = @{@"id": componentId,
193
+							 @"type": @"Component",
194
+							 @"data": @{},
195
+							 @"children": @[]};
196
+	UIViewController *ans = [self.factory createLayout:layout saveToStore:self.store];
198
 	
197
 	
199
 	UIViewController *storeAns = [self.store findComponentForId:componentId];
198
 	UIViewController *storeAns = [self.store findComponentForId:componentId];
200
 	XCTAssertEqualObjects(ans, storeAns);
199
 	XCTAssertEqualObjects(ans, storeAns);

+ 8
- 0
lib/ios/ReactNativeNavigationTests/RNNViewControllerPresenterTest.m View File

2
 #import <OCMock/OCMock.h>
2
 #import <OCMock/OCMock.h>
3
 #import "RNNViewControllerPresenter.h"
3
 #import "RNNViewControllerPresenter.h"
4
 #import "UIViewController+RNNOptions.h"
4
 #import "UIViewController+RNNOptions.h"
5
+#import "RNNReactView.h"
5
 
6
 
6
 @interface RNNViewControllerPresenterTest : XCTestCase
7
 @interface RNNViewControllerPresenterTest : XCTestCase
7
 
8
 
59
 	[(id)self.bindedViewController verify];
60
 	[(id)self.bindedViewController verify];
60
 }
61
 }
61
 
62
 
63
+- (void)testApplyOptions_setOverlayTouchOutsideIfHasValue {
64
+    self.options.overlay.interceptTouchOutside = [[Bool alloc] initWithBOOL:YES];
65
+    [[(id)self.bindedViewController expect] rnn_setInterceptTouchOutside:YES];
66
+    [self.uut applyOptions:self.options];
67
+    [(id)self.bindedViewController verify];
68
+}
69
+
62
 - (void)testApplyOptionsOnInit_shouldSetModalPresentetionStyleWithDefault {
70
 - (void)testApplyOptionsOnInit_shouldSetModalPresentetionStyleWithDefault {
63
 	[[(id)self.bindedViewController expect] rnn_setModalPresentationStyle:UIModalPresentationFullScreen];
71
 	[[(id)self.bindedViewController expect] rnn_setModalPresentationStyle:UIModalPresentationFullScreen];
64
 	[self.uut applyOptionsOnInit:self.options];
72
 	[self.uut applyOptionsOnInit:self.options];

+ 4
- 4
lib/ios/ReactNativeNavigationTests/UIViewController+RNNOptionsTest.m View File

84
 }
84
 }
85
 
85
 
86
 - (void)testSetBackgroundImageShouldAddUIImageViewSubviewWithImage {
86
 - (void)testSetBackgroundImageShouldAddUIImageViewSubviewWithImage {
87
-	UIImage* image = [UIImage new];
88
-	[self.uut rnn_setBackgroundImage:image];
89
-	UIImageView* imageView = [[[self.uut view] subviews] firstObject];
90
-	XCTAssertEqual(imageView.image, image);
87
+    UIImage* image = [UIImage new];
88
+    [self.uut rnn_setBackgroundImage:image];
89
+    UIImageView* imageView = [[[self.uut view] subviews] firstObject];
90
+    XCTAssertEqual(imageView.image, image);
91
 }
91
 }
92
 
92
 
93
 @end
93
 @end

+ 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
+- (void)rnn_setInterceptTouchOutside:(BOOL)interceptTouchOutside;
36
+
35
 - (BOOL)isModal;
37
 - (BOOL)isModal;
36
 
38
 
37
 @end
39
 @end

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

1
 #import "UIViewController+RNNOptions.h"
1
 #import "UIViewController+RNNOptions.h"
2
+#import <React/RCTRootView.h>
3
+
2
 #define kStatusBarAnimationDuration 0.35
4
 #define kStatusBarAnimationDuration 0.35
3
 const NSInteger BLUR_STATUS_TAG = 78264801;
5
 const NSInteger BLUR_STATUS_TAG = 78264801;
4
 
6
 
148
 	return NO;
150
 	return NO;
149
 }
151
 }
150
 
152
 
153
+- (void)rnn_setInterceptTouchOutside:(BOOL)interceptTouchOutside {
154
+	if ([self.view isKindOfClass:[RCTRootView class]]) {
155
+		RCTRootView* rootView = (RCTRootView*)self.view;
156
+		rootView.passThroughTouches = !interceptTouchOutside;
157
+	}
158
+}
151
 
159
 
152
 @end
160
 @end