Browse Source

Refactor options (#3962)

* Refactred options and added tests

* fixes tabBarItem

* tests fix

* Better namings

* Clean overlay creation
Yogev Ben David 6 years ago
parent
commit
29faa36ddf
No account linked to committer's email address
34 changed files with 285 additions and 214 deletions
  1. 17
    7
      lib/ios/RNNBottomTabOptions.m
  2. 31
    31
      lib/ios/RNNCommandsHandler.m
  3. 2
    3
      lib/ios/RNNControllerFactory.h
  4. 26
    46
      lib/ios/RNNControllerFactory.m
  5. 14
    0
      lib/ios/RNNLayoutInfo.h
  6. 16
    0
      lib/ios/RNNLayoutInfo.m
  7. 2
    2
      lib/ios/RNNModalManager.m
  8. 3
    3
      lib/ios/RNNNavigationController.h
  9. 5
    15
      lib/ios/RNNNavigationController.m
  10. 0
    2
      lib/ios/RNNNavigationOptions.h
  11. 0
    1
      lib/ios/RNNNavigationOptions.m
  12. 10
    0
      lib/ios/RNNOptionsManager.h
  13. 12
    0
      lib/ios/RNNOptionsManager.m
  14. 1
    0
      lib/ios/RNNOverlayManager.m
  15. 3
    7
      lib/ios/RNNRootViewController.h
  16. 41
    59
      lib/ios/RNNRootViewController.m
  17. 4
    1
      lib/ios/RNNRootViewProtocol.h
  18. 2
    0
      lib/ios/RNNSideMenuChildVC.h
  19. 2
    0
      lib/ios/RNNSideMenuController.h
  20. 0
    3
      lib/ios/RNNSideMenuController.m
  21. 1
    0
      lib/ios/RNNSplitViewController.h
  22. 0
    4
      lib/ios/RNNSplitViewController.m
  23. 1
    1
      lib/ios/RNNStore.h
  24. 3
    3
      lib/ios/RNNStore.m
  25. 2
    0
      lib/ios/RNNTabBarController.h
  26. 2
    6
      lib/ios/RNNTabBarController.m
  27. 1
    0
      lib/ios/RNNTopTabsViewController.h
  28. 1
    1
      lib/ios/RNNTopTabsViewController.m
  29. 16
    0
      lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj
  30. 5
    6
      lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m
  31. 49
    7
      lib/ios/ReactNativeNavigationTests/RNNControllerFactoryTest.m
  32. 8
    1
      lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m
  33. 4
    3
      lib/ios/ReactNativeNavigationTests/RNNStoreTest.m
  34. 1
    2
      playground/ios/playground.xcodeproj/xcshareddata/xcschemes/playground.xcscheme

+ 17
- 7
lib/ios/RNNBottomTabOptions.m View File

@@ -13,8 +13,9 @@
13 13
 }
14 14
 
15 15
 - (void)applyOn:(UIViewController *)viewController {
16
+	UIViewController* topViewController = [self getTabControllerFirstChild:viewController];
16 17
 	if (self.text || self.icon || self.selectedIcon) {
17
-		UITabBarItem* tabItem = viewController.tabBarItem;
18
+		UITabBarItem* tabItem = topViewController.tabBarItem;
18 19
 		
19 20
 		tabItem.selectedImage = [self getSelectedIconImage];
20 21
 		tabItem.image = [self getIconImage];
@@ -38,7 +39,7 @@
38 39
 		
39 40
 		[self appendTitleAttributes:tabItem];
40 41
 		
41
-		[viewController setTabBarItem:tabItem];
42
+		[topViewController setTabBarItem:tabItem];
42 43
 	}
43 44
 	
44 45
 	if (self.badge) {
@@ -46,10 +47,7 @@
46 47
 		if (self.badge != nil && ![self.badge isEqual:[NSNull null]]) {
47 48
 			badge = [RCTConvert NSString:self.badge];
48 49
 		}
49
-		UITabBarItem *tabBarItem = viewController.tabBarItem;
50
-		if (viewController.navigationController) {
51
-			tabBarItem = viewController.navigationController.tabBarItem;
52
-		}
50
+		UITabBarItem *tabBarItem = topViewController.tabBarItem;
53 51
 		tabBarItem.badgeValue = badge;
54 52
 		if (self.badgeColor) {
55 53
 			tabBarItem.badgeColor = [RCTConvert UIColor:self.badgeColor];
@@ -61,7 +59,7 @@
61 59
 	}
62 60
 	
63 61
 	if (self.visible) {
64
-		[viewController.tabBarController setSelectedIndex:[viewController.tabBarController.viewControllers indexOfObject:viewController]];
62
+		[topViewController.tabBarController setSelectedIndex:[viewController.tabBarController.viewControllers indexOfObject:viewController]];
65 63
 	}
66 64
 	
67 65
 	[self resetOptions];
@@ -137,6 +135,18 @@
137 135
 	return self.fontSize ? [self.fontSize floatValue] : 10;
138 136
 }
139 137
 
138
+- (UIViewController *)getTabControllerFirstChild:(UIViewController *)viewController {
139
+	while (viewController != nil) {
140
+		if ([viewController.parentViewController isKindOfClass:[UITabBarController class]] || !viewController.parentViewController) {
141
+			return viewController;
142
+		}
143
+		
144
+		viewController = viewController.parentViewController;
145
+	}
146
+	
147
+	return nil;
148
+}
149
+
140 150
 -(void)resetOptions {
141 151
 	self.text = nil;
142 152
 	self.badge = nil;

+ 31
- 31
lib/ios/RNNCommandsHandler.m View File

@@ -70,17 +70,17 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
70 70
 	
71 71
 	UIViewController<RNNRootViewProtocol>* vc = (UIViewController<RNNRootViewProtocol>*)[_store findComponentForId:componentId];
72 72
 	if ([vc conformsToProtocol:@protocol(RNNRootViewProtocol)] || [vc isKindOfClass:[RNNRootViewController class]]) {
73
-		[vc.getLeafViewController.options mergeWith:options];
73
+		[vc.getLeafViewController.layoutInfo.options mergeWith:options];
74 74
 		[CATransaction begin];
75 75
 		[CATransaction setCompletionBlock:completion];
76
-		[vc.getLeafViewController.options applyOn:vc.getLeafViewController];
76
+		[vc.getLeafViewController.layoutInfo.options applyOn:vc.getLeafViewController];
77 77
 		[CATransaction commit];
78 78
 	}
79 79
 }
80 80
 
81 81
 - (void)setDefaultOptions:(NSDictionary*)optionsDict completion:(RNNTransitionCompletionBlock)completion {
82 82
 	[self assertReady];
83
-	[_controllerFactory setDefaultOptionsDict:optionsDict];
83
+	[_controllerFactory.optionsManager setDefaultOptionsDict:optionsDict];
84 84
 }
85 85
 
86 86
 - (void)push:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
@@ -89,7 +89,7 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
89 89
 	RNNRootViewController *newVc = (RNNRootViewController *)[_controllerFactory createLayoutAndSaveToStore:layout];
90 90
 	UIViewController *fromVC = [_store findComponentForId:componentId];
91 91
 	
92
-	if ([newVc.options.preview.reactTag floatValue] > 0) {
92
+	if ([newVc.layoutInfo.options.preview.reactTag floatValue] > 0) {
93 93
 		UIViewController* vc = [_store findComponentForId:componentId];
94 94
 		
95 95
 		if([vc isKindOfClass:[RNNRootViewController class]]) {
@@ -98,8 +98,8 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
98 98
 
99 99
       rootVc.previewCallback = ^(UIViewController *vcc) {
100 100
 				RNNRootViewController* rvc  = (RNNRootViewController*)vcc;
101
-				[self->_eventEmitter sendOnPreviewCompleted:componentId previewComponentId:newVc.componentId];
102
-				if ([newVc.options.preview.commit floatValue] > 0) {
101
+				[self->_eventEmitter sendOnPreviewCompleted:componentId previewComponentId:newVc.layoutInfo.componentId];
102
+				if ([newVc.layoutInfo.options.preview.commit floatValue] > 0) {
103 103
 					[CATransaction begin];
104 104
 					[CATransaction setCompletionBlock:^{
105 105
 						[self->_eventEmitter sendOnNavigationCommandCompletion:push params:@{@"componentId": componentId}];
@@ -112,27 +112,27 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
112 112
 			
113 113
 			CGSize size = CGSizeMake(rootVc.view.frame.size.width, rootVc.view.frame.size.height);
114 114
 			
115
-			if (newVc.options.preview.width) {
116
-				size.width = [newVc.options.preview.width floatValue];
115
+			if (newVc.layoutInfo.options.preview.width) {
116
+				size.width = [newVc.layoutInfo.options.preview.width floatValue];
117 117
 			}
118 118
 			
119
-			if (newVc.options.preview.height) {
120
-				size.height = [newVc.options.preview.height floatValue];
119
+			if (newVc.layoutInfo.options.preview.height) {
120
+				size.height = [newVc.layoutInfo.options.preview.height floatValue];
121 121
 			}
122 122
 			
123
-			if (newVc.options.preview.width || newVc.options.preview.height) {
123
+			if (newVc.layoutInfo.options.preview.width || newVc.layoutInfo.options.preview.height) {
124 124
 				newVc.preferredContentSize = size;
125 125
 			}
126 126
       
127 127
 			RCTExecuteOnMainQueue(^{
128
-				UIView *view = [[ReactNativeNavigation getBridge].uiManager viewForReactTag:newVc.options.preview.reactTag];
128
+				UIView *view = [[ReactNativeNavigation getBridge].uiManager viewForReactTag:newVc.layoutInfo.options.preview.reactTag];
129 129
 				[rootVc registerForPreviewingWithDelegate:(id)rootVc sourceView:view];
130 130
 			});
131 131
 		}
132 132
 	} else {
133
-		id animationDelegate = (newVc.options.animations.push.hasCustomAnimation || newVc.isCustomTransitioned) ? newVc : nil;
134
-		[newVc waitForReactViewRender:(newVc.options.animations.push.waitForRender || animationDelegate) perform:^{
135
-			[_stackManager push:newVc onTop:fromVC animated:newVc.options.animations.push.enable animationDelegate:animationDelegate completion:^{
133
+		id animationDelegate = (newVc.layoutInfo.options.animations.push.hasCustomAnimation || newVc.isCustomTransitioned) ? newVc : nil;
134
+		[newVc waitForReactViewRender:(newVc.layoutInfo.options.animations.push.waitForRender || animationDelegate) perform:^{
135
+			[_stackManager push:newVc onTop:fromVC animated:newVc.layoutInfo.options.animations.push.enable animationDelegate:animationDelegate completion:^{
136 136
 				[_eventEmitter sendOnNavigationCommandCompletion:push params:@{@"componentId": componentId}];
137 137
 				completion();
138 138
 			} rejection:rejection];
@@ -144,7 +144,7 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
144 144
 	[self assertReady];
145 145
 	
146 146
 	UIViewController<RNNRootViewProtocol> *newVC = [_controllerFactory createLayoutAndSaveToStore:layout];
147
-	RNNNavigationOptions* options = [newVC getLeafViewController].options;
147
+	RNNNavigationOptions* options = [newVC getLeafViewController].layoutInfo.options;
148 148
 	UIViewController *fromVC = [_store findComponentForId:componentId];
149 149
 	__weak typeof(RNNEventEmitter*) weakEventEmitter = _eventEmitter;
150 150
 	[_stackManager setStackRoot:newVC fromViewController:fromVC animated:options.animations.setStackRoot.enable completion:^{
@@ -157,12 +157,12 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
157 157
 	[self assertReady];
158 158
 	
159 159
 	RNNRootViewController *vc = (RNNRootViewController*)[_store findComponentForId:componentId];
160
-	[vc.options mergeWith:options];
160
+	[vc.layoutInfo.options mergeWith:options];
161 161
 	
162 162
 	UINavigationController *nvc = vc.navigationController;
163 163
 	
164 164
 	if ([nvc topViewController] == vc) {
165
-		if (vc.options.animations.pop) {
165
+		if (vc.layoutInfo.options.animations.pop) {
166 166
 			nvc.delegate = vc;
167 167
 		} else {
168 168
 			nvc.delegate = nil;
@@ -170,10 +170,10 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
170 170
 	} else {
171 171
 		NSMutableArray * vcs = nvc.viewControllers.mutableCopy;
172 172
 		[vcs removeObject:vc];
173
-		[nvc setViewControllers:vcs animated:vc.options.animations.pop.enable];
173
+		[nvc setViewControllers:vcs animated:vc.layoutInfo.options.animations.pop.enable];
174 174
 	}
175 175
 	
176
-	[_stackManager pop:vc animated:vc.options.animations.pop.enable completion:^{
176
+	[_stackManager pop:vc animated:vc.layoutInfo.options.animations.pop.enable completion:^{
177 177
 		[_store removeComponent:componentId];
178 178
 		[_eventEmitter sendOnNavigationCommandCompletion:pop params:@{@"componentId": componentId}];
179 179
 		completion();
@@ -185,9 +185,9 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
185 185
 - (void)popTo:(NSString*)componentId mergeOptions:(NSDictionary *)options completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
186 186
 	[self assertReady];
187 187
 	RNNRootViewController *vc = (RNNRootViewController*)[_store findComponentForId:componentId];
188
-	[vc.options mergeWith:options];
188
+	[vc.layoutInfo.options mergeWith:options];
189 189
 	
190
-	[_stackManager popTo:vc animated:vc.options.animations.pop.enable completion:^(NSArray *poppedViewControllers) {
190
+	[_stackManager popTo:vc animated:vc.layoutInfo.options.animations.pop.enable completion:^(NSArray *poppedViewControllers) {
191 191
 		[_eventEmitter sendOnNavigationCommandCompletion:popTo params:@{@"componentId": componentId}];
192 192
 		[self removePopedViewControllers:poppedViewControllers];
193 193
 		completion();
@@ -197,7 +197,7 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
197 197
 - (void)popToRoot:(NSString*)componentId mergeOptions:(NSDictionary *)options completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
198 198
 	[self assertReady];
199 199
 	RNNRootViewController *vc = (RNNRootViewController*)[_store findComponentForId:componentId];
200
-	[vc.options mergeWith:options];
200
+	[vc.layoutInfo.options mergeWith:options];
201 201
 	
202 202
 	[CATransaction begin];
203 203
 	[CATransaction setCompletionBlock:^{
@@ -205,7 +205,7 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
205 205
 		completion();
206 206
 	}];
207 207
 	
208
-	[_stackManager popToRoot:vc animated:vc.options.animations.pop.enable completion:^(NSArray *poppedViewControllers) {
208
+	[_stackManager popToRoot:vc animated:vc.layoutInfo.options.animations.pop.enable completion:^(NSArray *poppedViewControllers) {
209 209
 		[self removePopedViewControllers:poppedViewControllers];
210 210
 	} rejection:^(NSString *code, NSString *message, NSError *error) {
211 211
 		
@@ -223,8 +223,8 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
223 223
 		[newVc.getLeafViewController applyModalOptions];
224 224
 	}
225 225
 	
226
-	[newVc.getLeafViewController waitForReactViewRender:newVc.getLeafViewController.options.animations.showModal.waitForRender perform:^{
227
-		[_modalManager showModal:newVc animated:newVc.getLeafViewController.options.animations.showModal.enable hasCustomAnimation:newVc.getLeafViewController.options.animations.showModal.hasCustomAnimation completion:^(NSString *componentId) {
226
+	[newVc.getLeafViewController waitForReactViewRender:newVc.getLeafViewController.layoutInfo.options.animations.showModal.waitForRender perform:^{
227
+		[_modalManager showModal:newVc animated:newVc.getLeafViewController.layoutInfo.options.animations.showModal.enable hasCustomAnimation:newVc.getLeafViewController.layoutInfo.options.animations.showModal.hasCustomAnimation completion:^(NSString *componentId) {
228 228
 			[_eventEmitter sendOnNavigationCommandCompletion:showModal params:@{@"layout": layout}];
229 229
 			completion(componentId);
230 230
 		}];
@@ -239,7 +239,7 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
239 239
 		[_eventEmitter sendOnNavigationCommandCompletion:dismissModal params:@{@"componentId": componentId}];
240 240
 	}];
241 241
 	UIViewController<RNNRootViewProtocol> *modalToDismiss = (UIViewController<RNNRootViewProtocol>*)[_store findComponentForId:componentId];
242
-	[modalToDismiss.getLeafViewController.options mergeWith:options];
242
+	[modalToDismiss.getLeafViewController.layoutInfo.options mergeWith:options];
243 243
 	
244 244
 	[self removePopedViewControllers:modalToDismiss.navigationController.viewControllers];
245 245
 	
@@ -265,7 +265,7 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
265 265
 - (void)showOverlay:(NSDictionary *)layout completion:(RNNTransitionCompletionBlock)completion {
266 266
 	[self assertReady];
267 267
 	
268
-	UIViewController<RNNRootViewProtocol>* overlayVC = [_controllerFactory createOverlay:layout];
268
+	UIViewController<RNNRootViewProtocol>* overlayVC = [_controllerFactory createLayoutAndSaveToStore:layout];
269 269
 	[_overlayManager showOverlay:overlayVC];
270 270
 	[_eventEmitter sendOnNavigationCommandCompletion:showOverlay params:@{@"layout": layout}];
271 271
 	completion();
@@ -302,13 +302,13 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
302 302
 
303 303
 #pragma mark - RNNModalManagerDelegate
304 304
 
305
-- (void)dismissedModal:(UIViewController *)viewController {
306
-	[_eventEmitter sendModalsDismissedEvent:((RNNRootViewController *)viewController).componentId numberOfModalsDismissed:@(1)];
305
+- (void)dismissedModal:(UIViewController<RNNRootViewProtocol> *)viewController {
306
+	[_eventEmitter sendModalsDismissedEvent:viewController.layoutInfo.componentId numberOfModalsDismissed:@(1)];
307 307
 }
308 308
 
309 309
 - (void)dismissedMultipleModals:(NSArray *)viewControllers {
310 310
 	if (viewControllers && viewControllers.count) {
311
-		[_eventEmitter sendModalsDismissedEvent:((RNNRootViewController *)viewControllers.lastObject).componentId numberOfModalsDismissed:@(viewControllers.count)];
311
+		[_eventEmitter sendModalsDismissedEvent:((UIViewController<RNNRootViewProtocol> *)viewControllers.lastObject).layoutInfo.componentId numberOfModalsDismissed:@(viewControllers.count)];
312 312
 	}
313 313
 }
314 314
 

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

@@ -5,6 +5,7 @@
5 5
 #import "RNNStore.h"
6 6
 #import "RNNEventEmitter.h"
7 7
 #import "RNNRootViewProtocol.h"
8
+#import "RNNOptionsManager.h"
8 9
 
9 10
 @interface RNNControllerFactory : NSObject
10 11
 
@@ -15,9 +16,7 @@
15 16
 
16 17
 -(UIViewController<RNNRootViewProtocol, UIViewControllerPreviewingDelegate> *)createLayoutAndSaveToStore:(NSDictionary*)layout;
17 18
 
18
-- (UIViewController<RNNRootViewProtocol> *)createOverlay:(NSDictionary*)layout;
19
-
20
-@property (nonatomic, strong) NSDictionary* defaultOptionsDict;
21 19
 @property (nonatomic, strong) RNNEventEmitter *eventEmitter;
20
+@property (nonatomic, strong) RNNOptionsManager *optionsManager;
22 21
 
23 22
 @end

+ 26
- 46
lib/ios/RNNControllerFactory.m View File

@@ -1,14 +1,14 @@
1
-
2 1
 #import "RNNControllerFactory.h"
3 2
 #import "RNNLayoutNode.h"
4 3
 #import "RNNSplitViewController.h"
5 4
 #import "RNNSplitViewOptions.h"
6 5
 #import "RNNSideMenuController.h"
7 6
 #import "RNNSideMenuChildVC.h"
8
-#import "RNNNavigationOptions.h"
9 7
 #import "RNNNavigationController.h"
10 8
 #import "RNNTabBarController.h"
11 9
 #import "RNNTopTabsViewController.h"
10
+#import "RNNLayoutInfo.h"
11
+#import "RNNOptionsManager.h"
12 12
 
13 13
 @implementation RNNControllerFactory {
14 14
 	id<RNNRootViewCreator> _creator;
@@ -25,10 +25,12 @@
25 25
 							  andBridge:(RCTBridge *)bridge {
26 26
 	
27 27
 	self = [super init];
28
+	
28 29
 	_creator = creator;
29 30
 	_store = store;
30 31
 	_eventEmitter = eventEmitter;
31 32
 	_bridge = bridge;
33
+	_optionsManager = [RNNOptionsManager new];
32 34
 	
33 35
 	return self;
34 36
 }
@@ -94,11 +96,10 @@
94 96
 }
95 97
 
96 98
 - (UIViewController<RNNRootViewProtocol> *)createComponent:(RNNLayoutNode*)node {
97
-	NSString* name = node.data[@"name"];
98
-	RNNNavigationOptions* options = [self createOptions:node.data[@"options"]];
99
+	RNNLayoutInfo* layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node optionsManager:_optionsManager];
100
+
101
+	RNNRootViewController* component = [[RNNRootViewController alloc] initWithLayoutInfo:layoutInfo rootViewCreator:_creator eventEmitter:_eventEmitter isExternalComponent:NO];
99 102
 
100
-	NSString* componentId = node.nodeId;
101
-	RNNRootViewController* component = [[RNNRootViewController alloc] initWithName:name withOptions:options withComponentId:componentId rootViewCreator:_creator eventEmitter:_eventEmitter isExternalComponent:NO];
102 103
 	if (!component.isCustomViewController) {
103 104
 		CGSize availableSize = UIApplication.sharedApplication.delegate.window.bounds.size;
104 105
 		[_bridge.uiManager setAvailableSize:availableSize forRootView:component.view];
@@ -107,14 +108,11 @@
107 108
 }
108 109
 
109 110
 - (UIViewController<RNNRootViewProtocol> *)createExternalComponent:(RNNLayoutNode*)node {
110
-	NSString* name = node.data[@"name"];
111
-	NSDictionary* props = node.data[@"passProps"];
111
+	RNNLayoutInfo* layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node optionsManager:_optionsManager];
112
+
113
+	UIViewController* externalVC = [_store getExternalComponent:layoutInfo bridge:_bridge];
112 114
 	
113
-	UIViewController* externalVC = [_store getExternalComponent:name props:props bridge:_bridge];
114
-	RNNNavigationOptions* options = [self createOptions:node.data[@"options"]];
115
-	
116
-	NSString* componentId = node.nodeId;
117
-	RNNRootViewController* component = [[RNNRootViewController alloc] initWithName:name withOptions:options withComponentId:componentId rootViewCreator:_creator eventEmitter:_eventEmitter isExternalComponent:YES];
115
+	RNNRootViewController* component = [[RNNRootViewController alloc] initWithLayoutInfo:layoutInfo rootViewCreator:_creator eventEmitter:_eventEmitter isExternalComponent:YES];
118 116
 	
119 117
 	[component addChildViewController:externalVC];
120 118
 	[component.view addSubview:externalVC.view];
@@ -125,43 +123,44 @@
125 123
 
126 124
 
127 125
 - (UIViewController<RNNRootViewProtocol> *)createStack:(RNNLayoutNode*)node {
128
-	RNNNavigationOptions* options = [self createOptions:node.data[@"options"]];
129
-	RNNNavigationController* vc = [[RNNNavigationController alloc] initWithOptions:options];
130
-	[vc setComponentId:node.nodeId];
126
+	RNNLayoutInfo* layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node optionsManager:_optionsManager];
127
+	
128
+	RNNNavigationController* vc = [[RNNNavigationController alloc] initWithLayoutInfo:layoutInfo];
129
+
131 130
 	NSMutableArray* controllers = [NSMutableArray new];
132 131
 	for (NSDictionary* child in node.children) {
133 132
 		[controllers addObject:[self fromTree:child]];
134 133
 	}
134
+	
135 135
 	[vc setViewControllers:controllers];
136
-	[vc.getLeafViewController mergeOptions:options];
137 136
 	
138 137
 	return vc;
139 138
 }
140 139
 
141 140
 -(UIViewController<RNNRootViewProtocol> *)createTabs:(RNNLayoutNode*)node {
142 141
 	RNNTabBarController* vc = [[RNNTabBarController alloc] initWithEventEmitter:_eventEmitter];
143
-	RNNNavigationOptions* options = [self createOptions:node.data[@"options"]];
144
-
142
+	vc.layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node optionsManager:_optionsManager];
143
+	
145 144
 	NSMutableArray* controllers = [NSMutableArray new];
146 145
 	for (NSDictionary *child in node.children) {
147 146
 		UIViewController<RNNRootViewProtocol>* childVc = [self fromTree:child];
148
-		[childVc applyTabBarItem];
147
+		[childVc.layoutInfo.options applyOn:childVc];
148
+		[childVc.getLeafViewController.layoutInfo.options applyOn:childVc.getLeafViewController];
149 149
 		
150 150
 		[controllers addObject:childVc];
151 151
 	}
152 152
 	[vc setViewControllers:controllers];
153
-	[vc.getLeafViewController mergeOptions:options];
154 153
 	
155 154
 	return vc;
156 155
 }
157 156
 
158 157
 - (UIViewController<RNNRootViewProtocol> *)createTopTabs:(RNNLayoutNode*)node {
159 158
 	RNNTopTabsViewController* vc = [[RNNTopTabsViewController alloc] init];
159
+	vc.layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node optionsManager:_optionsManager];
160 160
 	
161 161
 	NSMutableArray* controllers = [NSMutableArray new];
162 162
 	for (NSDictionary *child in node.children) {
163 163
 		RNNRootViewController* childVc = (RNNRootViewController*)[self fromTree:child];
164
-//		childVc.topTabsViewController = vc;
165 164
 		[controllers addObject:childVc];
166 165
 		[_bridge.uiManager setAvailableSize:vc.contentView.bounds.size forRootView:childVc.view];
167 166
 	}
@@ -172,6 +171,8 @@
172 171
 }
173 172
 
174 173
 - (UIViewController<RNNRootViewProtocol> *)createSideMenu:(RNNLayoutNode*)node {
174
+	RNNLayoutInfo* layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node optionsManager:_optionsManager];
175
+
175 176
 	NSMutableArray* childrenVCs = [NSMutableArray new];
176 177
 	
177 178
 	for (NSDictionary *child in node.children) {
@@ -179,7 +180,8 @@
179 180
 		[childrenVCs addObject:vc];
180 181
 	}
181 182
 	RNNSideMenuController *sideMenu = [[RNNSideMenuController alloc] initWithControllers:childrenVCs];
182
-	[sideMenu.getLeafViewController mergeOptions:[self createOptions:node.data[@"options"]]];
183
+	sideMenu.layoutInfo = layoutInfo;
184
+	
183 185
 	return sideMenu;
184 186
 }
185 187
 
@@ -191,26 +193,11 @@
191 193
 	return sideMenuChild;
192 194
 }
193 195
 
194
-- (UIViewController<RNNRootViewProtocol> *)createOverlay:(NSDictionary*)layout {
195
-	UIViewController<RNNRootViewProtocol> *vc = [self fromTree:layout];
196
-	__block RCTRootView* rootView = (RCTRootView*)vc.view;
197
-	[vc performOnRotation:^{
198
-		CGSize availableSize = UIApplication.sharedApplication.delegate.window.bounds.size;
199
-		[_bridge.uiManager setSize:availableSize forView:rootView];
200
-	}];
201
-	rootView.backgroundColor = [UIColor clearColor];
202
-	CGSize availableSize = UIApplication.sharedApplication.delegate.window.bounds.size;
203
-	rootView.frame = CGRectMake(0, 0, availableSize.width, availableSize.height);
204
-	[_bridge.uiManager setAvailableSize:availableSize forRootView:vc.view];
205
-	
206
-	return vc;
207
-}
208
-
209 196
 - (UIViewController<RNNRootViewProtocol> *)createSplitView:(RNNLayoutNode*)node {
210 197
 
211 198
 	NSString* componentId = node.nodeId;
212 199
 	
213
-	RNNSplitViewOptions* options = [[RNNSplitViewOptions alloc] initWithDict:_defaultOptionsDict];
200
+	RNNSplitViewOptions* options = [[RNNSplitViewOptions alloc] initWithDict:_optionsManager.defaultOptionsDict];
214 201
 	[options mergeWith:node.data[@"options"]];
215 202
 
216 203
 	RNNSplitViewController* svc = [[RNNSplitViewController alloc] initWithOptions:options withComponentId:componentId rootViewCreator:_creator eventEmitter:_eventEmitter];
@@ -230,11 +217,4 @@
230 217
 	return svc;
231 218
 }
232 219
 
233
-- (RNNNavigationOptions *)createOptions:(NSDictionary *)optionsDict {
234
-	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:optionsDict];
235
-	options.defaultOptions = [[RNNNavigationOptions alloc] initWithDict:_defaultOptionsDict];
236
-	
237
-	return options;
238
-}
239
-
240 220
 @end

+ 14
- 0
lib/ios/RNNLayoutInfo.h View File

@@ -0,0 +1,14 @@
1
+#import <Foundation/Foundation.h>
2
+#import "RNNOptionsManager.h"
3
+#import "RNNLayoutNode.h"
4
+
5
+@interface RNNLayoutInfo : NSObject
6
+
7
+- (instancetype)initWithNode:(RNNLayoutNode *)node optionsManager:(RNNOptionsManager *)optionsManager;
8
+
9
+@property (nonatomic, strong) NSString* componentId;
10
+@property (nonatomic, strong) NSString* name;
11
+@property (nonatomic, strong) NSDictionary* props;
12
+@property (nonatomic, strong) RNNNavigationOptions* options;
13
+
14
+@end

+ 16
- 0
lib/ios/RNNLayoutInfo.m View File

@@ -0,0 +1,16 @@
1
+#import "RNNLayoutInfo.h"
2
+
3
+@implementation RNNLayoutInfo
4
+
5
+- (instancetype)initWithNode:(RNNLayoutNode *)node optionsManager:(RNNOptionsManager *)optionsManager {
6
+	self = [super init];
7
+	
8
+	self.componentId = node.nodeId;
9
+	self.name = node.data[@"name"];
10
+	self.props = node.data[@"passProps"];
11
+	self.options = [optionsManager createOptions:node.data[@"options"]];
12
+	
13
+	return self;
14
+}
15
+
16
+@end

+ 2
- 2
lib/ios/RNNModalManager.m View File

@@ -60,7 +60,7 @@
60 60
 
61 61
 -(void)removePendingNextModalIfOnTop:(RNNTransitionCompletionBlock)completion {
62 62
 	UIViewController<RNNRootViewProtocol> *modalToDismiss = [_pendingModalIdsToDismiss lastObject];
63
-	RNNNavigationOptions* options = modalToDismiss.getLeafViewController.options;
63
+	RNNNavigationOptions* options = modalToDismiss.getLeafViewController.layoutInfo.options;
64 64
 
65 65
 	if(!modalToDismiss) {
66 66
 		return;
@@ -88,7 +88,7 @@
88 88
 	} else {
89 89
 		[modalToDismiss.view removeFromSuperview];
90 90
 		modalToDismiss.view = nil;
91
-		modalToDismiss.getLeafViewController.options.animations.dismissModal.enable = NO;
91
+		modalToDismiss.getLeafViewController.layoutInfo.options.animations.dismissModal.enable = NO;
92 92
 		[self dismissedModal:modalToDismiss];
93 93
 		
94 94
 		if (completion) {

+ 3
- 3
lib/ios/RNNNavigationController.h View File

@@ -3,9 +3,9 @@
3 3
 
4 4
 @interface RNNNavigationController : UINavigationController <RNNRootViewProtocol>
5 5
 
6
-- (instancetype)initWithOptions:(RNNNavigationOptions *)options;
6
+- (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo;
7
+
8
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
7 9
 
8
-@property (nonatomic, strong) NSString* componentId;
9
-@property (nonatomic, strong) RNNNavigationOptions* options;
10 10
 
11 11
 @end

+ 5
- 15
lib/ios/RNNNavigationController.m View File

@@ -4,10 +4,10 @@
4 4
 
5 5
 @implementation RNNNavigationController
6 6
 
7
-- (instancetype)initWithOptions:(RNNNavigationOptions *)options {
7
+- (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo {
8 8
 	self = [super init];
9 9
 	if (self) {
10
-		_options = options;
10
+		_layoutInfo = layoutInfo;
11 11
 	}
12 12
 	
13 13
 	return self;
@@ -34,23 +34,19 @@
34 34
 		UIViewController *controller = self.viewControllers[self.viewControllers.count - 2];
35 35
 		if ([controller isKindOfClass:[RNNRootViewController class]]) {
36 36
 			RNNRootViewController *rnnController = (RNNRootViewController *)controller;
37
-			[rnnController.options applyOn:rnnController];
37
+			[rnnController.layoutInfo.options applyOn:rnnController];
38 38
 		}
39 39
 	}
40 40
 	
41 41
 	return [super popViewControllerAnimated:animated];
42 42
 }
43 43
 
44
-- (NSString *)componentId {
45
-	return _componentId ? _componentId : self.getLeafViewController.componentId;
46
-}
47
-
48 44
 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
49
-	return [[RNNModalAnimation alloc] initWithScreenTransition:self.getLeafViewController.options.animations.showModal isDismiss:NO];
45
+	return [[RNNModalAnimation alloc] initWithScreenTransition:self.getLeafViewController.layoutInfo.options.animations.showModal isDismiss:NO];
50 46
 }
51 47
 
52 48
 - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
53
-	return [[RNNModalAnimation alloc] initWithScreenTransition:self.getLeafViewController.options.animations.dismissModal isDismiss:YES];
49
+	return [[RNNModalAnimation alloc] initWithScreenTransition:self.getLeafViewController.layoutInfo.options.animations.dismissModal isDismiss:YES];
54 50
 }
55 51
 
56 52
 - (UIViewController *)getLeafViewController {
@@ -61,11 +57,5 @@
61 57
 	return self.topViewController;
62 58
 }
63 59
 
64
-- (void)applyTabBarItem {
65
-	[self.options.bottomTab mergeOptions:((RNNNavigationOptions *)self.options.defaultOptions).bottomTab overrideOptions:NO];
66
-	[self.options.bottomTab applyOn:self];
67
-	[self.getLeafViewController.options.bottomTab mergeOptions:((RNNNavigationOptions *)self.getLeafViewController.options.defaultOptions).bottomTab overrideOptions:NO];
68
-	[self.getLeafViewController.options.bottomTab applyOn:self];
69
-}
70 60
 
71 61
 @end

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

@@ -30,8 +30,6 @@ extern const NSInteger TOP_BAR_TRANSPARENT_TAG;
30 30
 @property (nonatomic, strong) RNNPreviewOptions* preview;
31 31
 @property (nonatomic, strong) RNNLayoutOptions* layout;
32 32
 
33
-@property (nonatomic, strong) RNNOptions* defaultOptions;
34
-
35 33
 @property (nonatomic, strong) NSMutableDictionary* originalTopBarImages;
36 34
 @property (nonatomic, strong) NSNumber* popGesture;
37 35
 @property (nonatomic, strong) NSDictionary* backgroundImage;

+ 0
- 1
lib/ios/RNNNavigationOptions.m View File

@@ -43,7 +43,6 @@ RCT_ENUM_CONVERTER(UIModalTransitionStyle,
43 43
 
44 44
 
45 45
 -(void)applyOn:(UIViewController<RNNRootViewProtocol> *)viewController {
46
-	[self mergeOptions:_defaultOptions overrideOptions:NO];
47 46
 	[self.topBar applyOn:viewController];
48 47
 	[self.bottomTabs applyOn:viewController];
49 48
 	[self.topTab applyOn:viewController];

+ 10
- 0
lib/ios/RNNOptionsManager.h View File

@@ -0,0 +1,10 @@
1
+#import <Foundation/Foundation.h>
2
+#import "RNNNavigationOptions.h"
3
+
4
+@interface RNNOptionsManager : NSObject
5
+
6
+- (RNNNavigationOptions *)createOptions:(NSDictionary *)optionsDict;
7
+
8
+@property (nonatomic, strong) NSDictionary* defaultOptionsDict;
9
+
10
+@end

+ 12
- 0
lib/ios/RNNOptionsManager.m View File

@@ -0,0 +1,12 @@
1
+#import "RNNOptionsManager.h"
2
+
3
+@implementation RNNOptionsManager
4
+
5
+- (RNNNavigationOptions *)createOptions:(NSDictionary *)optionsDict {
6
+	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:optionsDict];
7
+	
8
+	[options mergeOptions:[[RNNNavigationOptions alloc] initWithDict:_defaultOptionsDict] overrideOptions:NO];
9
+	
10
+	return options;
11
+}
12
+@end

+ 1
- 0
lib/ios/RNNOverlayManager.m View File

@@ -14,6 +14,7 @@
14 14
 - (void)showOverlay:(UIViewController *)viewController {
15 15
 	UIWindow* overlayWindow = [[RNNOverlayWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
16 16
 	[_overlayWindows addObject:overlayWindow];
17
+	viewController.view.backgroundColor = [UIColor clearColor];
17 18
 	[overlayWindow setWindowLevel:UIWindowLevelNormal];
18 19
 	[overlayWindow setRootViewController:viewController];
19 20
 	[overlayWindow makeKeyAndVisible];

+ 3
- 7
lib/ios/RNNRootViewController.h View File

@@ -6,32 +6,28 @@
6 6
 #import "RNNNavigationOptions.h"
7 7
 #import "RNNAnimator.h"
8 8
 #import "RNNUIBarButtonItem.h"
9
+#import "RNNLayoutInfo.h"
9 10
 
10 11
 typedef void (^RNNReactViewReadyCompletionBlock)(void);
11 12
 typedef void (^PreviewCallback)(UIViewController *vc);
12 13
 
13 14
 @interface RNNRootViewController : UIViewController	<UIViewControllerPreviewingDelegate, UISearchResultsUpdating, UISearchBarDelegate, UINavigationControllerDelegate, UISplitViewControllerDelegate>
14 15
 
15
-@property (nonatomic, strong) RNNNavigationOptions* options;
16 16
 @property (nonatomic, strong) RNNEventEmitter *eventEmitter;
17
-@property (nonatomic, strong) NSString* componentId;
17
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
18 18
 @property (nonatomic) id<RNNRootViewCreator> creator;
19 19
 @property (nonatomic, strong) RNNAnimator* animator;
20 20
 @property (nonatomic, strong) UIViewController* previewController;
21 21
 @property (nonatomic, copy) PreviewCallback previewCallback;
22 22
 
23
-- (instancetype)initWithName:(NSString*)name
24
-				 withOptions:(RNNNavigationOptions*)options
25
-			 withComponentId:(NSString*)componentId
23
+- (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo
26 24
 			 rootViewCreator:(id<RNNRootViewCreator>)creator
27 25
 				eventEmitter:(RNNEventEmitter*)eventEmitter
28 26
 		 isExternalComponent:(BOOL)isExternalComponent;
29 27
 
30
-- (void)applyTopTabsOptions;
31 28
 - (BOOL)isCustomViewController;
32 29
 - (BOOL)isCustomTransitioned;
33 30
 - (void)waitForReactViewRender:(BOOL)wait perform:(RNNReactViewReadyCompletionBlock)readyBlock;
34
-- (void)mergeOptions:(RNNOptions*)options;
35 31
 - (void)applyModalOptions;
36 32
 - (void)optionsUpdated;
37 33
 

+ 41
- 59
lib/ios/RNNRootViewController.m View File

@@ -12,7 +12,6 @@
12 12
 	BOOL _isBeingPresented;
13 13
 }
14 14
 
15
-@property (nonatomic, strong) NSString* componentName;
16 15
 @property (nonatomic) BOOL _statusBarHidden;
17 16
 @property (nonatomic) BOOL isExternalComponent;
18 17
 @property (nonatomic) BOOL _optionsApplied;
@@ -25,23 +24,19 @@
25 24
 
26 25
 @synthesize previewCallback;
27 26
 
28
--(instancetype)initWithName:(NSString*)name
29
-				withOptions:(RNNNavigationOptions*)options
30
-			withComponentId:(NSString*)componentId
31
-			rootViewCreator:(id<RNNRootViewCreator>)creator
32
-			   eventEmitter:(RNNEventEmitter*)eventEmitter
33
-		isExternalComponent:(BOOL)isExternalComponent {
27
+- (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo
28
+				   rootViewCreator:(id<RNNRootViewCreator>)creator
29
+					  eventEmitter:(RNNEventEmitter*)eventEmitter
30
+			   isExternalComponent:(BOOL)isExternalComponent {
34 31
 	self = [super init];
35
-	self.componentId = componentId;
36
-	self.componentName = name;
37
-	self.options = options;
38 32
 	self.eventEmitter = eventEmitter;
39
-	self.animator = [[RNNAnimator alloc] initWithTransitionOptions:self.options.customTransition];
33
+	self.animator = [[RNNAnimator alloc] initWithTransitionOptions:self.layoutInfo.options.customTransition];
40 34
 	self.creator = creator;
41 35
 	self.isExternalComponent = isExternalComponent;
36
+	self.layoutInfo = layoutInfo;
42 37
 	
43 38
 	if (!self.isExternalComponent) {
44
-		self.view = [creator createRootView:self.componentName rootViewId:self.componentId];
39
+		self.view = [creator createRootView:self.layoutInfo.name rootViewId:self.layoutInfo.componentId];
45 40
 		[[NSNotificationCenter defaultCenter] addObserver:self
46 41
 												 selector:@selector(reactViewReady)
47 42
 													 name: @"RCTContentDidAppearNotification"
@@ -63,12 +58,12 @@
63 58
 -(void)viewWillAppear:(BOOL)animated{
64 59
 	[super viewWillAppear:animated];
65 60
 	_isBeingPresented = YES;
66
-	[self.options applyOn:self];
61
+	[self.layoutInfo.options applyOn:self];
67 62
 }
68 63
 
69 64
 -(void)viewDidAppear:(BOOL)animated {
70 65
 	[super viewDidAppear:animated];
71
-	[self.eventEmitter sendComponentDidAppear:self.componentId componentName:self.componentName];
66
+	[self.eventEmitter sendComponentDidAppear:self.layoutInfo.componentId componentName:self.layoutInfo.name];
72 67
 }
73 68
 
74 69
 - (void)viewWillDisappear:(BOOL)animated {
@@ -78,7 +73,7 @@
78 73
 
79 74
 -(void)viewDidDisappear:(BOOL)animated {
80 75
 	[super viewDidDisappear:animated];
81
-	[self.eventEmitter sendComponentDidDisappear:self.componentId componentName:self.componentName];
76
+	[self.eventEmitter sendComponentDidDisappear:self.layoutInfo.componentId componentName:self.layoutInfo.name];
82 77
 }
83 78
 
84 79
 - (void)reactViewReady {
@@ -111,13 +106,13 @@
111 106
 }
112 107
 
113 108
 -(void)updateSearchResultsForSearchController:(UISearchController *)searchController {
114
-	[self.eventEmitter sendOnSearchBarUpdated:self.componentId
109
+	[self.eventEmitter sendOnSearchBarUpdated:self.layoutInfo.componentId
115 110
 										 text:searchController.searchBar.text
116 111
 									isFocused:searchController.searchBar.isFirstResponder];
117 112
 }
118 113
 
119 114
 - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
120
-	[self.eventEmitter sendOnSearchBarCancelPressed:self.componentId];
115
+	[self.eventEmitter sendOnSearchBarCancelPressed:self.layoutInfo.componentId];
121 116
 }
122 117
 
123 118
 - (void)viewDidLoad {
@@ -131,21 +126,17 @@
131 126
 }
132 127
 
133 128
 - (void)applyModalOptions {
134
-	[self.options applyOn:self];
135
-	[self.options applyModalOptions:self];
136
-}
137
-
138
-- (void)mergeOptions:(RNNOptions *)options {
139
-	[self.options mergeOptions:options overrideOptions:NO];
129
+	[self.layoutInfo.options applyOn:self];
130
+	[self.layoutInfo.options applyModalOptions:self];
140 131
 }
141 132
 
142 133
 - (void)setCustomNavigationTitleView {
143 134
 	if (!_customTitleView && _isBeingPresented) {
144
-		if (self.options.topBar.title.component.name) {
145
-			_customTitleView = (RNNReactView*)[_creator createRootViewFromComponentOptions:self.options.topBar.title.component];
135
+		if (self.layoutInfo.options.topBar.title.component.name) {
136
+			_customTitleView = (RNNReactView*)[_creator createRootViewFromComponentOptions:self.layoutInfo.options.topBar.title.component];
146 137
 			_customTitleView.backgroundColor = UIColor.clearColor;
147
-			[_customTitleView setAlignment:self.options.topBar.title.component.alignment];
148
-			BOOL isCenter = [self.options.topBar.title.component.alignment isEqualToString:@"center"];
138
+			[_customTitleView setAlignment:self.layoutInfo.options.topBar.title.component.alignment];
139
+			BOOL isCenter = [self.layoutInfo.options.topBar.title.component.alignment isEqualToString:@"center"];
149 140
 			__weak RNNReactView *weakTitleView = _customTitleView;
150 141
 			CGRect frame = self.navigationController.navigationBar.bounds;
151 142
 			[_customTitleView setFrame:frame];
@@ -169,8 +160,8 @@
169 160
 
170 161
 - (void)setCustomNavigationBarView {
171 162
 	if (!_customTopBar) {
172
-		if (self.options.topBar.component.name) {
173
-			RCTRootView *reactView = (RCTRootView*)[_creator createRootViewFromComponentOptions:self.options.topBar.component];
163
+		if (self.layoutInfo.options.topBar.component.name) {
164
+			RCTRootView *reactView = (RCTRootView*)[_creator createRootViewFromComponentOptions:self.layoutInfo.options.topBar.component];
174 165
 			
175 166
 			_customTopBar = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:@"fill"];
176 167
 			reactView.backgroundColor = UIColor.clearColor;
@@ -189,8 +180,8 @@
189 180
 
190 181
 - (void)setCustomNavigationComponentBackground {
191 182
 	if (!_customTopBarBackground) {
192
-		if (self.options.topBar.background.component.name) {
193
-			RCTRootView *reactView = (RCTRootView*)[_creator createRootViewFromComponentOptions:self.options.topBar.background.component];
183
+		if (self.layoutInfo.options.topBar.background.component.name) {
184
+			RCTRootView *reactView = (RCTRootView*)[_creator createRootViewFromComponentOptions:self.layoutInfo.options.topBar.background.component];
194 185
 			
195 186
 			_customTopBarBackground = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:@"fill"];
196 187
 			[self.navigationController.navigationBar insertSubview:_customTopBarBackground atIndex:1];
@@ -198,7 +189,7 @@
198 189
 			[[self.navigationController.navigationBar.subviews objectAtIndex:1] removeFromSuperview];
199 190
 		}
200 191
 		
201
-		if (self.options.topBar.background.clipToBounds) {
192
+		if (self.layoutInfo.options.topBar.background.clipToBounds) {
202 193
 			self.navigationController.navigationBar.clipsToBounds = YES;
203 194
 		} else {
204 195
 			self.navigationController.navigationBar.clipsToBounds = NO;
@@ -213,7 +204,7 @@
213 204
 }
214 205
 
215 206
 -(BOOL)isCustomTransitioned {
216
-	return self.options.customTransition.animations != nil;
207
+	return self.layoutInfo.options.customTransition.animations != nil;
217 208
 }
218 209
 
219 210
 - (BOOL)isCustomViewController {
@@ -221,9 +212,9 @@
221 212
 }
222 213
 
223 214
 - (BOOL)prefersStatusBarHidden {
224
-	if (self.options.statusBar.visible) {
225
-		return ![self.options.statusBar.visible boolValue];
226
-	} else if ([self.options.statusBar.hideWithTopBar boolValue]) {
215
+	if (self.layoutInfo.options.statusBar.visible) {
216
+		return ![self.layoutInfo.options.statusBar.visible boolValue];
217
+	} else if ([self.layoutInfo.options.statusBar.hideWithTopBar boolValue]) {
227 218
 		return self.navigationController.isNavigationBarHidden;
228 219
 	}
229 220
 	
@@ -231,7 +222,7 @@
231 222
 }
232 223
 
233 224
 - (UIStatusBarStyle)preferredStatusBarStyle {
234
-	if (self.options.statusBar.style && [self.options.statusBar.style isEqualToString:@"light"]) {
225
+	if (self.layoutInfo.options.statusBar.style && [self.layoutInfo.options.statusBar.style isEqualToString:@"light"]) {
235 226
 		return UIStatusBarStyleLightContent;
236 227
 	} else {
237 228
 		return UIStatusBarStyleDefault;
@@ -239,20 +230,20 @@
239 230
 }
240 231
 
241 232
 - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
242
-	return self.options.layout.supportedOrientations;
233
+	return self.layoutInfo.options.layout.supportedOrientations;
243 234
 }
244 235
 
245 236
 - (BOOL)hidesBottomBarWhenPushed
246 237
 {
247
-	if (self.options.bottomTabs && self.options.bottomTabs.visible) {
248
-		return ![self.options.bottomTabs.visible boolValue];
238
+	if (self.layoutInfo.options.bottomTabs && self.layoutInfo.options.bottomTabs.visible) {
239
+		return ![self.layoutInfo.options.bottomTabs.visible boolValue];
249 240
 	}
250 241
 	return NO;
251 242
 }
252 243
 
253 244
 - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
254 245
 	RNNRootViewController* vc =  (RNNRootViewController*)viewController;
255
-	if (![vc.options.topBar.backButton.transition isEqualToString:@"custom"]){
246
+	if (![vc.layoutInfo.options.topBar.backButton.transition isEqualToString:@"custom"]){
256 247
 		navigationController.delegate = nil;
257 248
 	}
258 249
 }
@@ -264,10 +255,10 @@
264 255
 	{
265 256
 		if (self.animator) {
266 257
 			return self.animator;
267
-		} else if (operation == UINavigationControllerOperationPush && self.options.animations.push.hasCustomAnimation) {
268
-			return [[RNNPushAnimation alloc] initWithScreenTransition:self.options.animations.push];
269
-		} else if (operation == UINavigationControllerOperationPop && self.options.animations.pop.hasCustomAnimation) {
270
-			return [[RNNPushAnimation alloc] initWithScreenTransition:self.options.animations.pop];
258
+		} else if (operation == UINavigationControllerOperationPush && self.layoutInfo.options.animations.push.hasCustomAnimation) {
259
+			return [[RNNPushAnimation alloc] initWithScreenTransition:self.layoutInfo.options.animations.push];
260
+		} else if (operation == UINavigationControllerOperationPop && self.layoutInfo.options.animations.pop.hasCustomAnimation) {
261
+			return [[RNNPushAnimation alloc] initWithScreenTransition:self.layoutInfo.options.animations.pop];
271 262
 		} else {
272 263
 			return nil;
273 264
 		}
@@ -276,20 +267,11 @@
276 267
 }
277 268
 
278 269
 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
279
-	return [[RNNModalAnimation alloc] initWithScreenTransition:self.options.animations.showModal isDismiss:NO];
270
+	return [[RNNModalAnimation alloc] initWithScreenTransition:self.layoutInfo.options.animations.showModal isDismiss:NO];
280 271
 }
281 272
 
282 273
 - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
283
-	return [[RNNModalAnimation alloc] initWithScreenTransition:self.options.animations.dismissModal isDismiss:YES];
284
-}
285
-
286
--(void)applyTabBarItem {
287
-	[self.options.bottomTab mergeOptions:((RNNNavigationOptions *)self.options.defaultOptions).bottomTab overrideOptions:NO];
288
-	[self.options.bottomTab applyOn:self];
289
-}
290
-
291
--(void)applyTopTabsOptions {
292
-	[self.options.topTab applyOn:self];
274
+	return [[RNNModalAnimation alloc] initWithScreenTransition:self.layoutInfo.options.animations.dismissModal isDismiss:YES];
293 275
 }
294 276
 
295 277
 - (void)performOnRotation:(void (^)(void))block {
@@ -314,7 +296,7 @@
314 296
 }
315 297
 
316 298
 - (void)onActionPress:(NSString *)id {
317
-	[_eventEmitter sendOnNavigationButtonPressed:self.componentId buttonId:id];
299
+	[_eventEmitter sendOnNavigationButtonPressed:self.layoutInfo.componentId buttonId:id];
318 300
 }
319 301
 
320 302
 - (UIPreviewAction *) convertAction:(NSDictionary *)action {
@@ -334,7 +316,7 @@
334 316
 
335 317
 - (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
336 318
 	NSMutableArray *actions = [[NSMutableArray alloc] init];
337
-	for (NSDictionary *previewAction in self.options.preview.actions) {
319
+	for (NSDictionary *previewAction in self.layoutInfo.options.preview.actions) {
338 320
 		UIPreviewAction *action = [self convertAction:previewAction];
339 321
 		NSDictionary *actionActions = previewAction[@"actions"];
340 322
 		if (actionActions.count > 0) {
@@ -352,7 +334,7 @@
352 334
 }
353 335
 
354 336
 -(void)onButtonPress:(RNNUIBarButtonItem *)barButtonItem {
355
-	[self.eventEmitter sendOnNavigationButtonPressed:self.componentId buttonId:barButtonItem.buttonId];
337
+	[self.eventEmitter sendOnNavigationButtonPressed:self.layoutInfo.componentId buttonId:barButtonItem.buttonId];
356 338
 }
357 339
 
358 340
 /**

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

@@ -1,16 +1,19 @@
1 1
 #import "RNNNavigationOptions.h"
2 2
 #import "RNNRootViewController.h"
3
+#import "RNNLayoutInfo.h"
3 4
 
4 5
 @protocol RNNRootViewProtocol <NSObject, UINavigationControllerDelegate, UIViewControllerTransitioningDelegate, UISplitViewControllerDelegate>
5 6
 
6 7
 @optional
7 8
 
8 9
 - (void)performOnRotation:(void (^)(void))block;
9
-- (void)applyTabBarItem;
10 10
 
11 11
 @required
12
+
12 13
 - (RNNRootViewController *)getLeafViewController;
13 14
 
15
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
16
+
14 17
 @end
15 18
 
16 19
 

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

@@ -21,6 +21,8 @@ typedef NS_ENUM(NSInteger, RNNSideMenuChildType) {
21 21
 @property (readonly) RNNSideMenuChildType type;
22 22
 @property (readonly) UIViewController<RNNRootViewProtocol> *child;
23 23
 
24
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
25
+
24 26
 -(instancetype) initWithChild:(UIViewController<RNNRootViewProtocol>*)child type:(RNNSideMenuChildType)type;
25 27
 
26 28
 @end

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

@@ -18,6 +18,8 @@
18 18
 @property (readonly) RNNSideMenuChildVC *right;
19 19
 @property (readonly) MMDrawerController *sideMenu;
20 20
 
21
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
22
+
21 23
 -(instancetype)initWithControllers:(NSArray*)controllers;
22 24
 
23 25
 -(void)showSideMenu:(MMDrawerSide)side animated:(BOOL)animated;

+ 0
- 3
lib/ios/RNNSideMenuController.m View File

@@ -93,8 +93,5 @@
93 93
 	return [self.center getLeafViewController];
94 94
 }
95 95
 
96
-- (void)mergeOptions:(RNNOptions *)options {
97
-	[self.center.getLeafViewController mergeOptions:options];
98
-}
99 96
 
100 97
 @end

+ 1
- 0
lib/ios/RNNSplitViewController.h View File

@@ -15,6 +15,7 @@
15 15
 @property (nonatomic, strong) RNNSplitViewOptions* options;
16 16
 @property (nonatomic, strong) RNNEventEmitter *eventEmitter;
17 17
 @property (nonatomic, strong) NSString* componentId;
18
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
18 19
 @property (nonatomic) id<RNNRootViewCreator> creator;
19 20
 
20 21
 -(instancetype)initWithOptions:(RNNSplitViewOptions*)options

+ 0
- 4
lib/ios/RNNSplitViewController.m View File

@@ -35,8 +35,4 @@
35 35
 	readyBlock();
36 36
 }
37 37
 
38
-- (void)mergeOptions:(RNNOptions *)options {
39
-	[self.options mergeOptions:options];
40
-}
41
-
42 38
 @end

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

@@ -17,7 +17,7 @@ typedef void (^RNNTransitionRejectionBlock)(NSString *code, NSString *message, N
17 17
 - (void)removeAllComponents;
18 18
 
19 19
 - (void)registerExternalComponent:(NSString *)name callback:(RNNExternalViewCreator)callback;
20
-- (UIViewController *)getExternalComponent:(NSString *)name props:(NSDictionary*)props bridge:(RCTBridge*)bridge;
20
+- (UIViewController *)getExternalComponent:(RNNLayoutInfo *)layoutInfo bridge:(RCTBridge *)bridge;
21 21
 
22 22
 - (NSString*)componentKeyForInstance:(UIViewController*)instance;
23 23
 

+ 3
- 3
lib/ios/RNNStore.m View File

@@ -75,9 +75,9 @@
75 75
 	[_externalComponentCreators setObject:[callback copy] forKey:name];
76 76
 }
77 77
 
78
-- (UIViewController *)getExternalComponent:(NSString *)name props:(NSDictionary*)props bridge:(RCTBridge *)bridge {
79
-	RNNExternalViewCreator creator = [_externalComponentCreators objectForKey:name];
80
-	return creator(props, bridge);
78
+- (UIViewController *)getExternalComponent:(RNNLayoutInfo *)layoutInfo bridge:(RCTBridge *)bridge {
79
+	RNNExternalViewCreator creator = [_externalComponentCreators objectForKey:layoutInfo.name];
80
+	return creator(layoutInfo.props, bridge);
81 81
 }
82 82
 
83 83
 @end

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

@@ -9,4 +9,6 @@
9 9
 
10 10
 - (void)setSelectedIndexByComponentID:(NSString *)componentID;
11 11
 
12
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
13
+
12 14
 @end

+ 2
- 6
lib/ios/RNNTabBarController.m View File

@@ -21,9 +21,9 @@
21 21
 
22 22
 - (void)setSelectedIndexByComponentID:(NSString *)componentID {
23 23
 	for (id child in self.childViewControllers) {
24
-		RNNRootViewController* vc = child;
24
+		UIViewController<RNNRootViewProtocol>* vc = child;
25 25
 
26
-		if ([vc.componentId isEqualToString:componentID]) {
26
+		if ([vc.layoutInfo.componentId isEqualToString:componentID]) {
27 27
 			[self setSelectedIndex:[self.childViewControllers indexOfObject:child]];
28 28
 		}
29 29
 	}
@@ -34,10 +34,6 @@
34 34
 	[super setSelectedIndex:selectedIndex];
35 35
 }
36 36
 
37
-- (void)mergeOptions:(RNNOptions *)options {
38
-	[self.getLeafViewController mergeOptions:options];
39
-}
40
-
41 37
 - (UIViewController *)getLeafViewController {
42 38
 	return ((UIViewController<RNNRootViewProtocol>*)self.selectedViewController).getLeafViewController;
43 39
 }

+ 1
- 0
lib/ios/RNNTopTabsViewController.h View File

@@ -6,6 +6,7 @@
6 6
 @interface RNNTopTabsViewController : UIViewController <RNNRootViewProtocol>
7 7
 
8 8
 @property (nonatomic, retain) UIView* contentView;
9
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
9 10
 
10 11
 - (void)setViewControllers:(NSArray*)viewControllers;
11 12
 - (void)viewController:(UIViewController*)vc changedTitle:(NSString*)title;

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

@@ -56,7 +56,7 @@
56 56
 	_viewControllers = viewControllers;
57 57
 	for (RNNRootViewController* childVc in viewControllers) {
58 58
 		[childVc.view setFrame:_contentView.bounds];
59
-		[childVc applyTopTabsOptions];
59
+		[childVc.layoutInfo.options.topTab applyOn:childVc];
60 60
 	}
61 61
 	
62 62
 	[self setSelectedViewControllerIndex:0];

+ 16
- 0
lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj View File

@@ -67,6 +67,10 @@
67 67
 		5016E8F020209690009D4F7C /* RNNCustomTitleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5016E8EE2020968F009D4F7C /* RNNCustomTitleView.m */; };
68 68
 		50175CD1207A2AA1004FE91B /* RNNComponentOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50175CCF207A2AA1004FE91B /* RNNComponentOptions.h */; };
69 69
 		50175CD2207A2AA1004FE91B /* RNNComponentOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50175CD0207A2AA1004FE91B /* RNNComponentOptions.m */; };
70
+		501CD31F214A5B6900A6E225 /* RNNLayoutInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 501CD31D214A5B6900A6E225 /* RNNLayoutInfo.h */; };
71
+		501CD320214A5B6900A6E225 /* RNNLayoutInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 501CD31E214A5B6900A6E225 /* RNNLayoutInfo.m */; };
72
+		501CD323214A5CA900A6E225 /* RNNOptionsManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 501CD321214A5CA900A6E225 /* RNNOptionsManager.h */; };
73
+		501CD324214A5CA900A6E225 /* RNNOptionsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 501CD322214A5CA900A6E225 /* RNNOptionsManager.m */; };
70 74
 		501E0217213E7EA3003365C5 /* RNNReactView.h in Headers */ = {isa = PBXBuildFile; fileRef = 501E0215213E7EA3003365C5 /* RNNReactView.h */; };
71 75
 		501E0218213E7EA3003365C5 /* RNNReactView.m in Sources */ = {isa = PBXBuildFile; fileRef = 501E0216213E7EA3003365C5 /* RNNReactView.m */; };
72 76
 		50220F48212ABDFD004C2B0A /* RNNReactRootView.h in Headers */ = {isa = PBXBuildFile; fileRef = 50220F46212ABDFD004C2B0A /* RNNReactRootView.h */; };
@@ -295,6 +299,10 @@
295 299
 		5016E8EE2020968F009D4F7C /* RNNCustomTitleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNCustomTitleView.m; sourceTree = "<group>"; };
296 300
 		50175CCF207A2AA1004FE91B /* RNNComponentOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNComponentOptions.h; sourceTree = "<group>"; };
297 301
 		50175CD0207A2AA1004FE91B /* RNNComponentOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNComponentOptions.m; sourceTree = "<group>"; };
302
+		501CD31D214A5B6900A6E225 /* RNNLayoutInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNLayoutInfo.h; sourceTree = "<group>"; };
303
+		501CD31E214A5B6900A6E225 /* RNNLayoutInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNLayoutInfo.m; sourceTree = "<group>"; };
304
+		501CD321214A5CA900A6E225 /* RNNOptionsManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNOptionsManager.h; sourceTree = "<group>"; };
305
+		501CD322214A5CA900A6E225 /* RNNOptionsManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNOptionsManager.m; sourceTree = "<group>"; };
298 306
 		501E0215213E7EA3003365C5 /* RNNReactView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNReactView.h; sourceTree = "<group>"; };
299 307
 		501E0216213E7EA3003365C5 /* RNNReactView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNReactView.m; sourceTree = "<group>"; };
300 308
 		50220F46212ABDFD004C2B0A /* RNNReactRootView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNReactRootView.h; sourceTree = "<group>"; };
@@ -638,6 +646,8 @@
638 646
 				261F0E691E6F028A00989DE2 /* RNNNavigationStackManager.m */,
639 647
 				50D031322005149000386B3D /* RNNOverlayManager.h */,
640 648
 				50D031332005149000386B3D /* RNNOverlayManager.m */,
649
+				501CD321214A5CA900A6E225 /* RNNOptionsManager.h */,
650
+				501CD322214A5CA900A6E225 /* RNNOptionsManager.m */,
641 651
 			);
642 652
 			name = Managers;
643 653
 			sourceTree = "<group>";
@@ -650,6 +660,8 @@
650 660
 				504AFE611FFE52EF0076E904 /* Options */,
651 661
 				50D031312005146C00386B3D /* Managers */,
652 662
 				50570BE82063E09B006A1B5C /* RNNTitleViewHelper.h */,
663
+				501CD31D214A5B6900A6E225 /* RNNLayoutInfo.h */,
664
+				501CD31E214A5B6900A6E225 /* RNNLayoutInfo.m */,
653 665
 				50220F46212ABDFD004C2B0A /* RNNReactRootView.h */,
654 666
 				50220F47212ABDFD004C2B0A /* RNNReactRootView.m */,
655 667
 				501E0215213E7EA3003365C5 /* RNNReactView.h */,
@@ -844,6 +856,7 @@
844 856
 				263905BB1E4C6F440023D7D3 /* RCCDrawerHelper.h in Headers */,
845 857
 				263905CC1E4C6F440023D7D3 /* SidebarWunderlistAnimation.h in Headers */,
846 858
 				507F43F41FF4FCFE00D9425B /* HMSegmentedControl.h in Headers */,
859
+				501CD31F214A5B6900A6E225 /* RNNLayoutInfo.h in Headers */,
847 860
 				50A00C37200F84D6000F01A6 /* RNNOverlayOptions.h in Headers */,
848 861
 				7B4928081E70415400555040 /* RNNCommandsHandler.h in Headers */,
849 862
 				263905AE1E4C6F440023D7D3 /* MMDrawerBarButtonItem.h in Headers */,
@@ -864,6 +877,7 @@
864 877
 				261F0E641E6EC94900989DE2 /* RNNModalManager.h in Headers */,
865 878
 				263905C01E4C6F440023D7D3 /* SidebarAirbnbAnimation.h in Headers */,
866 879
 				50644A2020E11A720026709C /* Constants.h in Headers */,
880
+				501CD323214A5CA900A6E225 /* RNNOptionsManager.h in Headers */,
867 881
 				E8367B801F7A8A4700675C05 /* VICMAImageView.h in Headers */,
868 882
 				263905E61E4CAC950023D7D3 /* RNNSideMenuChildVC.h in Headers */,
869 883
 				263905C41E4C6F440023D7D3 /* SidebarFacebookAnimation.h in Headers */,
@@ -1032,7 +1046,9 @@
1032 1046
 				263905C51E4C6F440023D7D3 /* SidebarFacebookAnimation.m in Sources */,
1033 1047
 				50451D0E2042F70900695F00 /* RNNTransition.m in Sources */,
1034 1048
 				5048862E20BE976D000908DE /* RNNLayoutOptions.m in Sources */,
1049
+				501CD320214A5B6900A6E225 /* RNNLayoutInfo.m in Sources */,
1035 1050
 				7BEF0D191E437684003E96B0 /* RNNRootViewController.m in Sources */,
1051
+				501CD324214A5CA900A6E225 /* RNNOptionsManager.m in Sources */,
1036 1052
 				50415CBB20553B8E00BB682E /* RNNScreenTransition.m in Sources */,
1037 1053
 				263905C31E4C6F440023D7D3 /* SidebarAnimation.m in Sources */,
1038 1054
 				E8A5CD531F464F0400E89D0D /* RNNAnimator.m in Sources */,

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

@@ -95,12 +95,11 @@
95 95
 -(void)testDynamicStylesMergeWithStaticStyles {
96 96
 	RNNNavigationOptions* initialOptions = [[RNNNavigationOptions alloc] initWithDict:@{}];
97 97
 	initialOptions.topBar.title.text = @"the title";
98
-	RNNRootViewController* vc = [[RNNRootViewController alloc] initWithName:@"name"
99
-																withOptions:initialOptions
100
-															withComponentId:@"componentId"
101
-															rootViewCreator:[[RNNTestRootViewCreator alloc] init]
102
-															   eventEmitter:nil
103
-														  isExternalComponent:NO];
98
+	RNNLayoutInfo* layoutInfo = [RNNLayoutInfo new];
99
+	layoutInfo.options = initialOptions;
100
+	
101
+	RNNRootViewController* vc = [[RNNRootViewController alloc] initWithLayoutInfo:layoutInfo rootViewCreator:[[RNNTestRootViewCreator alloc] init] eventEmitter:nil isExternalComponent:NO];
102
+	
104 103
 	UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:vc];
105 104
 	[vc viewWillAppear:false];
106 105
 	XCTAssertTrue([vc.navigationItem.title isEqual:@"the title"]);

+ 49
- 7
lib/ios/ReactNativeNavigationTests/RNNControllerFactoryTest.m View File

@@ -6,6 +6,7 @@
6 6
 #import "RNNSideMenuChildVC.h"
7 7
 #import "RNNNavigationController.h"
8 8
 #import "RNNTabBarController.h"
9
+#import "RNNSplitViewController.h"
9 10
 
10 11
 @interface RNNControllerFactoryTest : XCTestCase
11 12
 
@@ -32,7 +33,6 @@
32 33
 	XCTAssertThrows([self.factory createLayoutAndSaveToStore:@{}]);
33 34
 }
34 35
 
35
-
36 36
 - (void)testCreateLayout_ComponentLayout {
37 37
 	
38 38
 	id ans = [self.factory createLayoutAndSaveToStore:
@@ -43,6 +43,19 @@
43 43
 	XCTAssertTrue([ans isMemberOfClass:[RNNRootViewController class]]);
44 44
 }
45 45
 
46
+- (void)testCreateLayout_ExternalComponentLayout {
47
+	[_store registerExternalComponent:@"externalComponent" callback:^UIViewController *(NSDictionary *props, RCTBridge *bridge) {
48
+		return [UIViewController new];
49
+	}];
50
+	
51
+	id ans = [self.factory createLayoutAndSaveToStore:
52
+			  @{@"id": @"cntId",
53
+				@"type": @"ExternalComponent",
54
+				@"data": @{@"name": @"externalComponent"},
55
+				@"children": @[]}];
56
+	XCTAssertTrue([ans isMemberOfClass:[RNNRootViewController class]]);
57
+}
58
+
46 59
 - (void)testCreateLayout_ComponentStackLayout {
47 60
 	id ans = [self.factory createLayoutAndSaveToStore:
48 61
 			  @{@"id": @"cntId",
@@ -52,6 +65,23 @@
52 65
 	XCTAssertTrue([ans isMemberOfClass:[RNNNavigationController class]]);
53 66
 }
54 67
 
68
+- (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": @[]}]}];
82
+	XCTAssertTrue([ans isMemberOfClass:[RNNSplitViewController class]]);
83
+}
84
+
55 85
 - (void)testCreateLayout_ComponentStackLayoutRecursive {
56 86
 	RNNNavigationController* ans = (RNNNavigationController*) [self.factory createLayoutAndSaveToStore:
57 87
 															 @{@"id": @"cntId",
@@ -91,10 +121,26 @@
91 121
 	UINavigationController *navController = tabBar.childViewControllers[0];
92 122
 	XCTAssertTrue(navController.childViewControllers.count == 1);
93 123
 	XCTAssertTrue([navController.childViewControllers[0] isMemberOfClass:[RNNRootViewController class]]);
94
-	
95
-	
96 124
 }
97 125
 
126
+- (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": @[]}]}]}];
141
+	
142
+	XCTAssertTrue([tabBar isMemberOfClass:[RNNTopTabsViewController class]]);
143
+}
98 144
 
99 145
 - (void)testCreateLayout_ComponentSideMenuLayoutCenterLeftRight {
100 146
 	RNNSideMenuController *ans = (RNNSideMenuController*) [self.factory createLayoutAndSaveToStore:
@@ -142,9 +188,6 @@
142 188
 	XCTAssertTrue([right.child isMemberOfClass:[RNNRootViewController class]]);
143 189
 }
144 190
 
145
-
146
-
147
-
148 191
 - (void)testCreateLayout_addComponentToStore {
149 192
 	NSString *componentId = @"cntId";
150 193
 	UIViewController *ans = [self.factory createLayoutAndSaveToStore:
@@ -158,5 +201,4 @@
158 201
 }
159 202
 
160 203
 
161
-
162 204
 @end

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

@@ -30,6 +30,7 @@
30 30
 @property (nonatomic, strong) NSString* componentId;
31 31
 @property (nonatomic, strong) id emitter;
32 32
 @property (nonatomic, strong) RNNNavigationOptions* options;
33
+@property (nonatomic, strong) RNNLayoutInfo* layoutInfo;
33 34
 @property (nonatomic, strong) RNNRootViewController* uut;
34 35
 @end
35 36
 
@@ -42,7 +43,13 @@
42 43
 	self.componentId = @"cntId";
43 44
 	self.emitter = nil;
44 45
 	self.options = [[RNNNavigationOptions alloc] initWithDict:@{}];
45
-	self.uut = [[RNNRootViewController alloc] initWithName:self.pageName withOptions:self.options withComponentId:self.componentId rootViewCreator:self.creator eventEmitter:self.emitter isExternalComponent:NO];
46
+	
47
+	RNNLayoutInfo* layoutInfo = [RNNLayoutInfo new];
48
+	layoutInfo.componentId = self.componentId;
49
+	layoutInfo.name = self.pageName;
50
+	layoutInfo.options = self.options;
51
+	
52
+	self.uut = [[RNNRootViewController alloc] initWithLayoutInfo:layoutInfo rootViewCreator:self.creator eventEmitter:self.emitter isExternalComponent:NO];
46 53
 }
47 54
 
48 55
 -(void)testTopBarBackgroundColor_validColor{

+ 4
- 3
lib/ios/ReactNativeNavigationTests/RNNStoreTest.m View File

@@ -89,12 +89,13 @@
89 89
 
90 90
 - (void)testGetExternalComponentShouldRetrunSavedComponent {
91 91
 	UIViewController* testVC = [UIViewController new];
92
-	NSString *externalComponentId = @"extId1";
93
-	[self.store registerExternalComponent:externalComponentId callback:^UIViewController *(NSDictionary *props, RCTBridge *bridge) {
92
+	RNNLayoutInfo* layoutInfo = [[RNNLayoutInfo alloc] init];
93
+	layoutInfo.name = @"extId1";
94
+	[self.store registerExternalComponent:layoutInfo.name callback:^UIViewController *(NSDictionary *props, RCTBridge *bridge) {
94 95
 		return testVC;
95 96
 	}];
96 97
 	
97
-	UIViewController* savedComponent = [self.store getExternalComponent:externalComponentId props:nil bridge:nil];
98
+	UIViewController* savedComponent = [self.store getExternalComponent:layoutInfo bridge:nil];
98 99
 	XCTAssertEqual(testVC, savedComponent);
99 100
 }
100 101
 

+ 1
- 2
playground/ios/playground.xcodeproj/xcshareddata/xcschemes/playground.xcscheme View File

@@ -68,7 +68,7 @@
68 68
       buildConfiguration = "Debug"
69 69
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
70 70
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
71
-      language = ""
71
+      codeCoverageEnabled = "YES"
72 72
       shouldUseLaunchSchemeArgsEnv = "NO">
73 73
       <Testables>
74 74
          <TestableReference
@@ -105,7 +105,6 @@
105 105
       buildConfiguration = "Debug"
106 106
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
107 107
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
108
-      language = ""
109 108
       launchStyle = "0"
110 109
       useCustomWorkingDirectory = "NO"
111 110
       ignoresPersistentStateOnLaunch = "NO"