Просмотр исходного кода

Options rewrite (#3979)

* Renamed RNNRootViewProtocol to RNNParentProtocol and added RNNLeafProtocol

* fixed unit test

* Better options resolving

* Revert "Revert "Refactor options (#3962)""

This reverts commit c266041b85.

* Revert "Revert "Fixes shared element transition""

This reverts commit 005f039f7c.

* Revert "Revert "Adresses #3963 - stack options applied to children""

This reverts commit be09cb0e9a.

* Revert "Revert "Added unit test coverage for RNNNavigationController""

This reverts commit 199cebd221.

* Merge stack options

This commits adds support for merging stack options by the stack’s componentId

Also while I’m at it - use fade animation when setting root

* Merge BottomTabs options

Merge BottomTabs options when calling mergeOptions with BottomTabs componentId

* Fixes options
Yogev Ben David 6 лет назад
Родитель
Сommit
51c71ecafb
No account linked to committer's email address
66 измененных файлов: 965 добавлений и 552 удалений
  1. 1
    1
      e2e/ScreenStyle.test.js
  2. 4
    0
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsOptionsPresenter.java
  3. 8
    0
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/StackOptionsPresenter.java
  4. 6
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java
  5. 6
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java
  6. 28
    0
      lib/ios/RCTConvert+Modal.h
  7. 16
    12
      lib/ios/RNNBackButtonOptions.m
  8. 2
    2
      lib/ios/RNNBackgroundOptions.m
  9. 27
    0
      lib/ios/RNNBasePresenter.h
  10. 36
    0
      lib/ios/RNNBasePresenter.m
  11. 17
    7
      lib/ios/RNNBottomTabOptions.m
  12. 42
    45
      lib/ios/RNNCommandsHandler.m
  13. 4
    5
      lib/ios/RNNControllerFactory.h
  14. 51
    62
      lib/ios/RNNControllerFactory.m
  15. 13
    0
      lib/ios/RNNLayoutInfo.h
  16. 15
    0
      lib/ios/RNNLayoutInfo.m
  17. 11
    0
      lib/ios/RNNLayoutProtocol.h
  18. 11
    0
      lib/ios/RNNLeafProtocol.h
  19. 3
    3
      lib/ios/RNNModalManager.m
  20. 5
    6
      lib/ios/RNNNavigationController.h
  21. 23
    22
      lib/ios/RNNNavigationController.m
  22. 7
    0
      lib/ios/RNNNavigationControllerPresenter.h
  23. 9
    0
      lib/ios/RNNNavigationControllerPresenter.m
  24. 2
    3
      lib/ios/RNNNavigationOptions.h
  25. 40
    58
      lib/ios/RNNNavigationOptions.m
  26. 4
    0
      lib/ios/RNNOptions.h
  27. 14
    2
      lib/ios/RNNOptions.m
  28. 10
    0
      lib/ios/RNNOptionsManager.h
  29. 12
    0
      lib/ios/RNNOptionsManager.m
  30. 1
    0
      lib/ios/RNNOverlayManager.m
  31. 15
    0
      lib/ios/RNNParentProtocol.h
  32. 9
    13
      lib/ios/RNNRootViewController.h
  33. 55
    83
      lib/ios/RNNRootViewController.m
  34. 0
    16
      lib/ios/RNNRootViewProtocol.h
  35. 7
    4
      lib/ios/RNNSideMenuChildVC.h
  36. 3
    3
      lib/ios/RNNSideMenuChildVC.m
  37. 5
    2
      lib/ios/RNNSideMenuController.h
  38. 1
    4
      lib/ios/RNNSideMenuController.m
  39. 4
    2
      lib/ios/RNNSplitViewController.h
  40. 0
    13
      lib/ios/RNNSplitViewController.m
  41. 2
    2
      lib/ios/RNNSplitViewOptions.m
  42. 2
    0
      lib/ios/RNNStatusBarOptions.m
  43. 2
    2
      lib/ios/RNNStore.h
  44. 3
    3
      lib/ios/RNNStore.m
  45. 5
    2
      lib/ios/RNNTabBarController.h
  46. 15
    8
      lib/ios/RNNTabBarController.m
  47. 6
    0
      lib/ios/RNNTabBarPresenter.h
  48. 9
    0
      lib/ios/RNNTabBarPresenter.m
  49. 67
    61
      lib/ios/RNNTopBarOptions.m
  50. 4
    2
      lib/ios/RNNTopTabsViewController.h
  51. 5
    4
      lib/ios/RNNTopTabsViewController.m
  52. 8
    0
      lib/ios/RNNViewControllerPresenter.h
  53. 13
    0
      lib/ios/RNNViewControllerPresenter.m
  54. 74
    4
      lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj
  55. 31
    8
      lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m
  56. 49
    7
      lib/ios/ReactNativeNavigationTests/RNNControllerFactoryTest.m
  57. 1
    0
      lib/ios/ReactNativeNavigationTests/RNNModalManagerTest.m
  58. 43
    0
      lib/ios/ReactNativeNavigationTests/RNNNavigationControllerTest.m
  59. 4
    3
      lib/ios/ReactNativeNavigationTests/RNNNavigationStackManagerTest.m
  60. 78
    56
      lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m
  61. 4
    3
      lib/ios/ReactNativeNavigationTests/RNNStoreTest.m
  62. 1
    2
      playground/ios/playground.xcodeproj/xcshareddata/xcschemes/playground.xcscheme
  63. 4
    11
      playground/src/app.js
  64. 1
    1
      playground/src/screens/OptionsScreen.js
  65. 6
    5
      playground/src/screens/TextScreen.js
  66. 1
    0
      playground/src/screens/WelcomeScreen.js

+ 1
- 1
e2e/ScreenStyle.test.js Просмотреть файл

@@ -31,7 +31,7 @@ describe('screen style', () => {
31 31
   );
32 32
 
33 33
   test(
34
-    'hides Tab Bar when pressing on Hide Top Bar and shows it when pressing on Show Top Bar',
34
+    'hides TopBar when pressing on Hide TopBar and shows it when pressing on Show TopBar',
35 35
     async () => {
36 36
       await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
37 37
       await elementById(testIDs.HIDE_TOP_BAR_BUTTON).tap();

+ 4
- 0
lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsOptionsPresenter.java Просмотреть файл

@@ -48,6 +48,10 @@ public class BottomTabsOptionsPresenter {
48 48
         applyDrawBehind(withDefaultOptions.bottomTabsOptions, tabIndex);
49 49
     }
50 50
 
51
+    public void mergeOptions(Options options) {
52
+        mergeBottomTabsOptions(options.bottomTabsOptions, options.animations);
53
+    }
54
+
51 55
     public void present(Options options) {
52 56
         Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions);
53 57
         applyBottomTabsOptions(withDefaultOptions.bottomTabsOptions, withDefaultOptions.animations);

+ 8
- 0
lib/android/app/src/main/java/com/reactnativenavigation/presentation/StackOptionsPresenter.java Просмотреть файл

@@ -115,6 +115,14 @@ public class StackOptionsPresenter {
115 115
         }
116 116
     }
117 117
 
118
+    public void mergeOptions(Options options, Component currentChild) {
119
+        mergeOrientation(options.layout.orientation);
120
+//        mergeButtons(topBar, withDefault.topBar.buttons, child);
121
+        mergeTopBarOptions(options.topBar, options.animations, currentChild);
122
+        mergeTopTabsOptions(options.topTabs);
123
+        mergeTopTabOptions(options.topTabOptions);
124
+    }
125
+
118 126
     public void applyInitialChildLayoutOptions(Options options) {
119 127
         Options withDefault = options.copy().withDefaultOptions(defaultOptions);
120 128
         setInitialTopBarVisibility(withDefault.topBar);

+ 6
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java Просмотреть файл

@@ -80,6 +80,12 @@ public class BottomTabsController extends ParentController implements AHBottomNa
80 80
         tabPresenter.present();
81 81
     }
82 82
 
83
+    @Override
84
+    public void mergeOptions(Options options) {
85
+        presenter.mergeOptions(options);
86
+        super.mergeOptions(options);
87
+    }
88
+
83 89
     @Override
84 90
     public void applyChildOptions(Options options, Component child) {
85 91
         super.applyChildOptions(options, child);

+ 6
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java Просмотреть файл

@@ -68,6 +68,12 @@ public class StackController extends ParentController<StackLayout> {
68 68
         return stack.peek();
69 69
     }
70 70
 
71
+    @Override
72
+    public void mergeOptions(Options options) {
73
+        presenter.mergeOptions(options, (Component) getCurrentChild().getView());
74
+        super.mergeOptions(options);
75
+    }
76
+
71 77
     @Override
72 78
     public void applyChildOptions(Options options, Component child) {
73 79
         super.applyChildOptions(options, child);

+ 28
- 0
lib/ios/RCTConvert+Modal.h Просмотреть файл

@@ -0,0 +1,28 @@
1
+#import <React/RCTConvert.h>
2
+
3
+@interface RCTConvert (Modal)
4
+
5
+@end
6
+
7
+@implementation RCTConvert (Modal)
8
+
9
+RCT_ENUM_CONVERTER(UIModalTransitionStyle,
10
+				   (@{@"coverVertical": @(UIModalTransitionStyleCoverVertical),
11
+					  @"flipHorizontal": @(UIModalTransitionStyleFlipHorizontal),
12
+					  @"crossDissolve": @(UIModalTransitionStyleCrossDissolve),
13
+					  @"partialCurl": @(UIModalTransitionStylePartialCurl)
14
+					  }), UIModalTransitionStyleCoverVertical, integerValue)
15
+
16
+RCT_ENUM_CONVERTER(UIModalPresentationStyle,
17
+				   (@{@"fullScreen": @(UIModalPresentationFullScreen),
18
+					  @"pageSheet": @(UIModalPresentationPageSheet),
19
+					  @"formSheet": @(UIModalPresentationFormSheet),
20
+					  @"currentContext": @(UIModalPresentationCurrentContext),
21
+					  @"custom": @(UIModalPresentationCustom),
22
+					  @"overFullScreen": @(UIModalPresentationOverFullScreen),
23
+					  @"overCurrentContext": @(UIModalPresentationOverCurrentContext),
24
+					  @"popover": @(UIModalPresentationPopover),
25
+					  @"none": @(UIModalPresentationNone)
26
+					  }), UIModalPresentationFullScreen, integerValue)
27
+@end
28
+

+ 16
- 12
lib/ios/RNNBackButtonOptions.m Просмотреть файл

@@ -4,35 +4,39 @@
4 4
 @implementation RNNBackButtonOptions
5 5
 
6 6
 - (void)applyOn:(UIViewController *)viewController {
7
+	if (self.visible) {
8
+		viewController.navigationItem.hidesBackButton = ![self.visible boolValue];
9
+	}
10
+	
11
+	[self applyOnNavigationController:viewController.navigationController];
12
+}
13
+
14
+- (void)applyOnNavigationController:(UINavigationController *)navigationController {
7 15
 	if (self.showTitle && ![self.showTitle boolValue]) {
8 16
 		self.title = @"";
9 17
 	}
10 18
 	
11 19
 	if (self.icon) {
12 20
 		UIImage *image = self.tintedIcon;
13
-		[viewController.navigationController.navigationBar setBackIndicatorImage:[UIImage new]];
14
-		[viewController.navigationController.navigationBar setBackIndicatorTransitionMaskImage:[UIImage new]];
21
+		[navigationController.navigationBar setBackIndicatorImage:[UIImage new]];
22
+		[navigationController.navigationBar setBackIndicatorTransitionMaskImage:[UIImage new]];
15 23
 		
16 24
 		UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithImage:image style:UIBarButtonItemStylePlain target:nil action:nil];
17
-		[self setBackItem:backItem onViewController:viewController];
25
+		[self setBackItem:backItem onNavigationController:navigationController];
18 26
 	} else if (self.title) {
19 27
 		UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:self.title
20 28
 																	 style:UIBarButtonItemStylePlain
21 29
 																	target:nil
22 30
 																	action:nil];
23 31
 		
24
-		[self setBackItem:backItem onViewController:viewController];
25
-	}
26
-	
27
-	if (self.visible) {
28
-		viewController.navigationItem.hidesBackButton = ![self.visible boolValue];
32
+		[self setBackItem:backItem onNavigationController:navigationController];
33
+		
29 34
 	}
30 35
 }
31 36
 
32
-- (void)setBackItem:(UIBarButtonItem *)backItem onViewController:(UIViewController *)viewController {
33
-	UINavigationController* nvc = viewController.navigationController;
34
-	if (nvc.viewControllers.count >= 2) {
35
-		UIViewController* lastViewControllerInStack = nvc.viewControllers[nvc.viewControllers.count - 2];
37
+- (void)setBackItem:(UIBarButtonItem *)backItem onNavigationController:(UINavigationController *)navigationController {
38
+	if (navigationController.viewControllers.count >= 2) {
39
+		UIViewController* lastViewControllerInStack = navigationController.viewControllers[navigationController.viewControllers.count - 2];
36 40
 		lastViewControllerInStack.navigationItem.backBarButtonItem = backItem;
37 41
 	}
38 42
 }

+ 2
- 2
lib/ios/RNNBackgroundOptions.m Просмотреть файл

@@ -2,10 +2,10 @@
2 2
 
3 3
 @implementation RNNBackgroundOptions
4 4
 
5
-- (void)applyOn:(UIViewController *)viewController {
5
+- (void)applyOnNavigationController:(UINavigationController *)navigationController {
6 6
 	if (self.color && ![self.color isKindOfClass:[NSNull class]]) {
7 7
 		UIColor* backgroundColor = [RCTConvert UIColor:self.color];
8
-		viewController.navigationController.navigationBar.barTintColor = backgroundColor;
8
+		navigationController.navigationBar.barTintColor = backgroundColor;
9 9
 	}
10 10
 }
11 11
 

+ 27
- 0
lib/ios/RNNBasePresenter.h Просмотреть файл

@@ -0,0 +1,27 @@
1
+#import <Foundation/Foundation.h>
2
+#import "RNNNavigationOptions.h"
3
+
4
+@protocol RNNPresenterDelegate <NSObject>
5
+
6
+- (void)optionsUpdated;
7
+
8
+@end
9
+
10
+@interface RNNBasePresenter : NSObject
11
+
12
+@property (nonatomic, weak) id<RNNPresenterDelegate> delegate;
13
+@property (nonatomic, strong) RNNNavigationOptions* options;
14
+
15
+- (instancetype)initWithOptions:(RNNNavigationOptions *)options;
16
+
17
+- (RNNNavigationOptions *)presentWithChildOptions:(RNNNavigationOptions *)childOptions on:(UIViewController *)viewController;
18
+
19
+- (void)present:(RNNNavigationOptions *)options on:(UIViewController *)viewController;
20
+
21
+- (void)presentOn:(UIViewController *)viewController;
22
+
23
+- (void)presentOnLoad:(UIViewController *)viewController;
24
+
25
+- (void)overrideOptions:(RNNNavigationOptions *)options;
26
+
27
+@end

+ 36
- 0
lib/ios/RNNBasePresenter.m Просмотреть файл

@@ -0,0 +1,36 @@
1
+#import "RNNBasePresenter.h"
2
+
3
+@implementation RNNBasePresenter
4
+
5
+- (instancetype)initWithOptions:(RNNNavigationOptions *)options {
6
+	self = [super init];
7
+	if (self) {
8
+		self.options = options;
9
+	}
10
+	return self;
11
+}
12
+
13
+- (void)presentOn:(UIViewController *)viewController {
14
+	[self.options applyOn:viewController];
15
+}
16
+
17
+- (void)present:(RNNNavigationOptions *)options on:(UIViewController *)viewController {
18
+	
19
+}
20
+
21
+- (RNNNavigationOptions *)presentWithChildOptions:(RNNNavigationOptions *)childOptions on:(UIViewController *)viewController {
22
+	RNNNavigationOptions* options = [self.options combineWithOptions:childOptions];
23
+	[self present:options on:viewController];
24
+	
25
+	return options;
26
+}
27
+
28
+- (void)presentOnLoad:(UIViewController *)viewController {
29
+	
30
+}
31
+
32
+- (void)overrideOptions:(RNNNavigationOptions *)options {
33
+	[_options mergeOptions:options overrideOptions:YES];
34
+}
35
+
36
+@end

+ 17
- 7
lib/ios/RNNBottomTabOptions.m Просмотреть файл

@@ -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;

+ 42
- 45
lib/ios/RNNCommandsHandler.m Просмотреть файл

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

+ 4
- 5
lib/ios/RNNControllerFactory.h Просмотреть файл

@@ -4,7 +4,8 @@
4 4
 #import "RNNRootViewCreator.h"
5 5
 #import "RNNStore.h"
6 6
 #import "RNNEventEmitter.h"
7
-#import "RNNRootViewProtocol.h"
7
+#import "RNNParentProtocol.h"
8
+#import "RNNOptionsManager.h"
8 9
 
9 10
 @interface RNNControllerFactory : NSObject
10 11
 
@@ -13,11 +14,9 @@
13 14
 						  eventEmitter:(RNNEventEmitter*)eventEmitter
14 15
 							 andBridge:(RCTBridge*)bridge;
15 16
 
16
--(UIViewController<RNNRootViewProtocol, UIViewControllerPreviewingDelegate> *)createLayoutAndSaveToStore:(NSDictionary*)layout;
17
+-(UIViewController<RNNParentProtocol, 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

+ 51
- 62
lib/ios/RNNControllerFactory.m Просмотреть файл

@@ -1,14 +1,17 @@
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
+#import "RNNViewControllerPresenter.h"
13
+#import "RNNTabBarPresenter.h"
14
+#import "RNNRootViewController.h"
12 15
 
13 16
 @implementation RNNControllerFactory {
14 17
 	id<RNNRootViewCreator> _creator;
@@ -25,24 +28,26 @@
25 28
 							  andBridge:(RCTBridge *)bridge {
26 29
 	
27 30
 	self = [super init];
31
+	
28 32
 	_creator = creator;
29 33
 	_store = store;
30 34
 	_eventEmitter = eventEmitter;
31 35
 	_bridge = bridge;
36
+	_optionsManager = [RNNOptionsManager new];
32 37
 	
33 38
 	return self;
34 39
 }
35 40
 
36
-- (UIViewController<RNNRootViewProtocol> *)createLayoutAndSaveToStore:(NSDictionary*)layout {
41
+- (UIViewController<RNNParentProtocol> *)createLayoutAndSaveToStore:(NSDictionary*)layout {
37 42
 	return [self fromTree:layout];
38 43
 }
39 44
 
40 45
 # pragma mark private
41 46
 
42
-- (UIViewController<RNNRootViewProtocol> *)fromTree:(NSDictionary*)json {
47
+- (UIViewController<RNNParentProtocol> *)fromTree:(NSDictionary*)json {
43 48
 	RNNLayoutNode* node = [RNNLayoutNode create:json];
44 49
 	
45
-	UIViewController<RNNRootViewProtocol> *result;
50
+	UIViewController<RNNParentProtocol> *result;
46 51
 	
47 52
 	if (node.isComponent) {
48 53
 		result = [self createComponent:node];
@@ -93,75 +98,78 @@
93 98
 	return result;
94 99
 }
95 100
 
96
-- (UIViewController<RNNRootViewProtocol> *)createComponent:(RNNLayoutNode*)node {
97
-	NSString* name = node.data[@"name"];
98
-	RNNNavigationOptions* options = [self createOptions:node.data[@"options"]];
101
+- (UIViewController<RNNParentProtocol> *)createComponent:(RNNLayoutNode*)node {
102
+	RNNLayoutInfo* layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node];
103
+	
104
+	RNNNavigationOptions* options = [_optionsManager createOptions:node.data[@"options"]];
105
+	
106
+	RNNViewControllerPresenter* presenter = [[RNNViewControllerPresenter alloc] initWithOptions:options];
107
+	RNNRootViewController* component = [[RNNRootViewController alloc] initWithLayoutInfo:layoutInfo rootViewCreator:_creator eventEmitter:_eventEmitter isExternalComponent:NO presenter:presenter];
99 108
 
100
-	NSString* componentId = node.nodeId;
101
-	RNNRootViewController* component = [[RNNRootViewController alloc] initWithName:name withOptions:options withComponentId:componentId rootViewCreator:_creator eventEmitter:_eventEmitter isExternalComponent:NO];
102 109
 	if (!component.isCustomViewController) {
103 110
 		CGSize availableSize = UIApplication.sharedApplication.delegate.window.bounds.size;
104 111
 		[_bridge.uiManager setAvailableSize:availableSize forRootView:component.view];
105 112
 	}
106
-	return (UIViewController<RNNRootViewProtocol> *)component;
113
+	return (UIViewController<RNNParentProtocol> *)component;
107 114
 }
108 115
 
109
-- (UIViewController<RNNRootViewProtocol> *)createExternalComponent:(RNNLayoutNode*)node {
110
-	NSString* name = node.data[@"name"];
111
-	NSDictionary* props = node.data[@"passProps"];
112
-	
113
-	UIViewController* externalVC = [_store getExternalComponent:name props:props bridge:_bridge];
114
-	RNNNavigationOptions* options = [self createOptions:node.data[@"options"]];
116
+- (UIViewController<RNNParentProtocol> *)createExternalComponent:(RNNLayoutNode*)node {
117
+	RNNLayoutInfo* layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node];
118
+	RNNNavigationOptions* options = [_optionsManager createOptions:node.data[@"options"]];
119
+
120
+	UIViewController* externalVC = [_store getExternalComponent:layoutInfo bridge:_bridge];
115 121
 	
116
-	NSString* componentId = node.nodeId;
117
-	RNNRootViewController* component = [[RNNRootViewController alloc] initWithName:name withOptions:options withComponentId:componentId rootViewCreator:_creator eventEmitter:_eventEmitter isExternalComponent:YES];
122
+	RNNViewControllerPresenter* presenter = [[RNNViewControllerPresenter alloc] initWithOptions:options];
123
+	RNNRootViewController* component = [[RNNRootViewController alloc] initWithLayoutInfo:layoutInfo rootViewCreator:_creator eventEmitter:_eventEmitter isExternalComponent:YES presenter:presenter];
118 124
 	
119 125
 	[component addChildViewController:externalVC];
120 126
 	[component.view addSubview:externalVC.view];
121 127
 	[externalVC didMoveToParentViewController:component];
122 128
 	
123
-	return (UIViewController<RNNRootViewProtocol> *)component;
129
+	return (UIViewController<RNNParentProtocol> *)component;
124 130
 }
125 131
 
126 132
 
127
-- (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];
133
+- (UIViewController<RNNParentProtocol> *)createStack:(RNNLayoutNode*)node {
134
+	RNNNavigationController* vc = [[RNNNavigationController alloc] init];
135
+	RNNNavigationOptions* options = [_optionsManager createOptions:node.data[@"options"]];
136
+
137
+	vc.presenter = [[RNNNavigationControllerPresenter alloc] initWithOptions:options];
138
+	vc.layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node];
139
+	
131 140
 	NSMutableArray* controllers = [NSMutableArray new];
132 141
 	for (NSDictionary* child in node.children) {
133 142
 		[controllers addObject:[self fromTree:child]];
134 143
 	}
144
+	
135 145
 	[vc setViewControllers:controllers];
136
-	[vc.getLeafViewController mergeOptions:options];
137 146
 	
138 147
 	return vc;
139 148
 }
140 149
 
141
--(UIViewController<RNNRootViewProtocol> *)createTabs:(RNNLayoutNode*)node {
150
+-(UIViewController<RNNParentProtocol> *)createTabs:(RNNLayoutNode*)node {
142 151
 	RNNTabBarController* vc = [[RNNTabBarController alloc] initWithEventEmitter:_eventEmitter];
143
-	RNNNavigationOptions* options = [self createOptions:node.data[@"options"]];
144
-
152
+	vc.layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node];
153
+	RNNNavigationOptions* options = [_optionsManager createOptions:node.data[@"options"]];
154
+	vc.presenter = [[RNNTabBarPresenter alloc] initWithOptions:options];
155
+	
145 156
 	NSMutableArray* controllers = [NSMutableArray new];
146 157
 	for (NSDictionary *child in node.children) {
147
-		UIViewController<RNNRootViewProtocol>* childVc = [self fromTree:child];
148
-		[childVc applyTabBarItem];
149
-		
158
+		UIViewController<RNNParentProtocol>* childVc = [self fromTree:child];
150 159
 		[controllers addObject:childVc];
151 160
 	}
152 161
 	[vc setViewControllers:controllers];
153
-	[vc.getLeafViewController mergeOptions:options];
154 162
 	
155 163
 	return vc;
156 164
 }
157 165
 
158
-- (UIViewController<RNNRootViewProtocol> *)createTopTabs:(RNNLayoutNode*)node {
166
+- (UIViewController<RNNParentProtocol> *)createTopTabs:(RNNLayoutNode*)node {
159 167
 	RNNTopTabsViewController* vc = [[RNNTopTabsViewController alloc] init];
168
+	vc.layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node];
160 169
 	
161 170
 	NSMutableArray* controllers = [NSMutableArray new];
162 171
 	for (NSDictionary *child in node.children) {
163 172
 		RNNRootViewController* childVc = (RNNRootViewController*)[self fromTree:child];
164
-//		childVc.topTabsViewController = vc;
165 173
 		[controllers addObject:childVc];
166 174
 		[_bridge.uiManager setAvailableSize:vc.contentView.bounds.size forRootView:childVc.view];
167 175
 	}
@@ -171,7 +179,9 @@
171 179
 	return vc;
172 180
 }
173 181
 
174
-- (UIViewController<RNNRootViewProtocol> *)createSideMenu:(RNNLayoutNode*)node {
182
+- (UIViewController<RNNParentProtocol> *)createSideMenu:(RNNLayoutNode*)node {
183
+	RNNLayoutInfo* layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node];
184
+
175 185
 	NSMutableArray* childrenVCs = [NSMutableArray new];
176 186
 	
177 187
 	for (NSDictionary *child in node.children) {
@@ -179,38 +189,24 @@
179 189
 		[childrenVCs addObject:vc];
180 190
 	}
181 191
 	RNNSideMenuController *sideMenu = [[RNNSideMenuController alloc] initWithControllers:childrenVCs];
182
-	[sideMenu.getLeafViewController mergeOptions:[self createOptions:node.data[@"options"]]];
192
+	sideMenu.layoutInfo = layoutInfo;
193
+	
183 194
 	return sideMenu;
184 195
 }
185 196
 
186 197
 
187
-- (UIViewController<RNNRootViewProtocol> *)createSideMenuChild:(RNNLayoutNode*)node type:(RNNSideMenuChildType)type {
188
-	UIViewController<RNNRootViewProtocol>* child = [self fromTree:node.children[0]];
198
+- (UIViewController<RNNParentProtocol> *)createSideMenuChild:(RNNLayoutNode*)node type:(RNNSideMenuChildType)type {
199
+	UIViewController<RNNParentProtocol>* child = [self fromTree:node.children[0]];
189 200
 	RNNSideMenuChildVC *sideMenuChild = [[RNNSideMenuChildVC alloc] initWithChild: child type:type];
190 201
 	
191 202
 	return sideMenuChild;
192 203
 }
193 204
 
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
-- (UIViewController<RNNRootViewProtocol> *)createSplitView:(RNNLayoutNode*)node {
205
+- (UIViewController<RNNParentProtocol> *)createSplitView:(RNNLayoutNode*)node {
210 206
 
211 207
 	NSString* componentId = node.nodeId;
212 208
 	
213
-	RNNSplitViewOptions* options = [[RNNSplitViewOptions alloc] initWithDict:_defaultOptionsDict];
209
+	RNNSplitViewOptions* options = [[RNNSplitViewOptions alloc] initWithDict:_optionsManager.defaultOptionsDict];
214 210
 	[options mergeWith:node.data[@"options"]];
215 211
 
216 212
 	RNNSplitViewController* svc = [[RNNSplitViewController alloc] initWithOptions:options withComponentId:componentId rootViewCreator:_creator eventEmitter:_eventEmitter];
@@ -230,11 +226,4 @@
230 226
 	return svc;
231 227
 }
232 228
 
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 229
 @end

+ 13
- 0
lib/ios/RNNLayoutInfo.h Просмотреть файл

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

+ 15
- 0
lib/ios/RNNLayoutInfo.m Просмотреть файл

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

+ 11
- 0
lib/ios/RNNLayoutProtocol.h Просмотреть файл

@@ -0,0 +1,11 @@
1
+#import "RNNLayoutInfo.h"
2
+#import "RNNBasePresenter.h"
3
+
4
+@protocol RNNLayoutProtocol <NSObject, UINavigationControllerDelegate, UIViewControllerTransitioningDelegate, UISplitViewControllerDelegate>
5
+
6
+@required
7
+
8
+@property (nonatomic, retain) RNNBasePresenter* presenter;
9
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
10
+
11
+@end

+ 11
- 0
lib/ios/RNNLeafProtocol.h Просмотреть файл

@@ -0,0 +1,11 @@
1
+#import "RNNLayoutProtocol.h"
2
+
3
+typedef void (^RNNReactViewReadyCompletionBlock)(void);
4
+
5
+@protocol RNNLeafProtocol <RNNLayoutProtocol>
6
+
7
+- (UIViewController<RNNLeafProtocol> *)getLeafViewController;
8
+
9
+- (void)waitForReactViewRender:(BOOL)wait perform:(RNNReactViewReadyCompletionBlock)readyBlock;
10
+
11
+@end

+ 3
- 3
lib/ios/RNNModalManager.m Просмотреть файл

@@ -59,8 +59,8 @@
59 59
 
60 60
 
61 61
 -(void)removePendingNextModalIfOnTop:(RNNTransitionCompletionBlock)completion {
62
-	UIViewController<RNNRootViewProtocol> *modalToDismiss = [_pendingModalIdsToDismiss lastObject];
63
-	RNNNavigationOptions* options = modalToDismiss.getLeafViewController.options;
62
+	UIViewController<RNNParentProtocol> *modalToDismiss = [_pendingModalIdsToDismiss lastObject];
63
+	RNNNavigationOptions* options = modalToDismiss.getLeafViewController.presenter.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.presenter.options.animations.dismissModal.enable = NO;
92 92
 		[self dismissedModal:modalToDismiss];
93 93
 		
94 94
 		if (completion) {

+ 5
- 6
lib/ios/RNNNavigationController.h Просмотреть файл

@@ -1,11 +1,10 @@
1 1
 #import <UIKit/UIKit.h>
2
-#import "RNNRootViewProtocol.h"
2
+#import "RNNParentProtocol.h"
3
+#import "RNNNavigationControllerPresenter.h"
3 4
 
4
-@interface RNNNavigationController : UINavigationController <RNNRootViewProtocol>
5
+@interface RNNNavigationController : UINavigationController <RNNParentProtocol>
5 6
 
6
-- (instancetype)initWithOptions:(RNNNavigationOptions *)options;
7
-
8
-@property (nonatomic, strong) NSString* componentId;
9
-@property (nonatomic, strong) RNNNavigationOptions* options;
7
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
8
+@property (nonatomic, retain) RNNNavigationControllerPresenter* presenter;
10 9
 
11 10
 @end

+ 23
- 22
lib/ios/RNNNavigationController.m Просмотреть файл

@@ -1,18 +1,10 @@
1 1
 
2 2
 #import "RNNNavigationController.h"
3 3
 #import "RNNModalAnimation.h"
4
+#import "RNNRootViewController.h"
4 5
 
5 6
 @implementation RNNNavigationController
6 7
 
7
-- (instancetype)initWithOptions:(RNNNavigationOptions *)options {
8
-	self = [super init];
9
-	if (self) {
10
-		_options = options;
11
-	}
12
-	
13
-	return self;
14
-}
15
-
16 8
 - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
17 9
 	return self.viewControllers.lastObject.supportedInterfaceOrientations;
18 10
 }
@@ -34,38 +26,47 @@
34 26
 		UIViewController *controller = self.viewControllers[self.viewControllers.count - 2];
35 27
 		if ([controller isKindOfClass:[RNNRootViewController class]]) {
36 28
 			RNNRootViewController *rnnController = (RNNRootViewController *)controller;
37
-			[rnnController.options applyOn:rnnController];
29
+			[rnnController.presenter presentOn:rnnController];
38 30
 		}
39 31
 	}
40 32
 	
41 33
 	return [super popViewControllerAnimated:animated];
42 34
 }
43 35
 
44
-- (NSString *)componentId {
45
-	return _componentId ? _componentId : self.getLeafViewController.componentId;
46
-}
47
-
48 36
 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
49
-	return [[RNNModalAnimation alloc] initWithScreenTransition:self.getLeafViewController.options.animations.showModal isDismiss:NO];
37
+	return [[RNNModalAnimation alloc] initWithScreenTransition:self.getLeafViewController.presenter.options.animations.showModal isDismiss:NO];
50 38
 }
51 39
 
52 40
 - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
53
-	return [[RNNModalAnimation alloc] initWithScreenTransition:self.getLeafViewController.options.animations.dismissModal isDismiss:YES];
41
+	return [[RNNModalAnimation alloc] initWithScreenTransition:self.getLeafViewController.presenter.options.animations.dismissModal isDismiss:YES];
54 42
 }
55 43
 
56 44
 - (UIViewController *)getLeafViewController {
57
-	return ((UIViewController<RNNRootViewProtocol>*)self.topViewController);
45
+	return ((UIViewController<RNNParentProtocol>*)self.topViewController);
58 46
 }
59 47
 
60 48
 - (UIViewController *)childViewControllerForStatusBarStyle {
61 49
 	return self.topViewController;
62 50
 }
63 51
 
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];
52
+- (void)willMoveToParentViewController:(UIViewController *)parent {
53
+	if ([self.parentViewController respondsToSelector:@selector(performOnChildLoad:)]) {
54
+		[self.parentViewController performSelector:@selector(performOnChildLoad:) withObject:_presenter.options];
55
+	}
56
+}
57
+
58
+- (void)performOnChildWillAppear:(RNNNavigationOptions *)childOptions {
59
+	RNNNavigationOptions* combinedOptions = [_presenter presentWithChildOptions:childOptions on:self];
60
+	if ([self.parentViewController respondsToSelector:@selector(performOnChildWillAppear:)]) {
61
+		[self.parentViewController performSelector:@selector(performOnChildWillAppear:) withObject:combinedOptions];
62
+	}
63
+}
64
+
65
+- (void)performOnChildLoad:(RNNNavigationOptions *)childOptions {
66
+	RNNNavigationOptions* combinedOptions = [_presenter presentWithChildOptions:childOptions on:self];
67
+	if ([self.parentViewController respondsToSelector:@selector(performOnChildLoad:)]) {
68
+		[self.parentViewController performSelector:@selector(performOnChildLoad:) withObject:combinedOptions];
69
+	}
69 70
 }
70 71
 
71 72
 @end

+ 7
- 0
lib/ios/RNNNavigationControllerPresenter.h Просмотреть файл

@@ -0,0 +1,7 @@
1
+#import <Foundation/Foundation.h>
2
+#import "RNNBasePresenter.h"
3
+
4
+@interface RNNNavigationControllerPresenter : RNNBasePresenter
5
+
6
+
7
+@end

+ 9
- 0
lib/ios/RNNNavigationControllerPresenter.m Просмотреть файл

@@ -0,0 +1,9 @@
1
+#import "RNNNavigationControllerPresenter.h"
2
+
3
+@implementation RNNNavigationControllerPresenter
4
+
5
+- (void)present:(RNNOptions *)options on:(UINavigationController *)navigationController {
6
+	[options applyOnNavigationController:navigationController];
7
+}
8
+
9
+@end

+ 2
- 3
lib/ios/RNNNavigationOptions.h Просмотреть файл

@@ -11,6 +11,7 @@
11 11
 #import "RNNStatusBarOptions.h"
12 12
 #import "RNNPreviewOptions.h"
13 13
 #import "RNNLayoutOptions.h"
14
+#import "RCTConvert+Modal.h"
14 15
 
15 16
 extern const NSInteger BLUR_TOPBAR_TAG;
16 17
 extern const NSInteger TOP_BAR_TRANSPARENT_TAG;
@@ -30,8 +31,6 @@ extern const NSInteger TOP_BAR_TRANSPARENT_TAG;
30 31
 @property (nonatomic, strong) RNNPreviewOptions* preview;
31 32
 @property (nonatomic, strong) RNNLayoutOptions* layout;
32 33
 
33
-@property (nonatomic, strong) RNNOptions* defaultOptions;
34
-
35 34
 @property (nonatomic, strong) NSMutableDictionary* originalTopBarImages;
36 35
 @property (nonatomic, strong) NSNumber* popGesture;
37 36
 @property (nonatomic, strong) NSDictionary* backgroundImage;
@@ -39,6 +38,6 @@ extern const NSInteger TOP_BAR_TRANSPARENT_TAG;
39 38
 @property (nonatomic, strong) NSString* modalPresentationStyle;
40 39
 @property (nonatomic, strong) NSString* modalTransitionStyle;
41 40
 
42
-- (void)applyModalOptions:(UIViewController*)viewController;
41
+- (RNNNavigationOptions *)combineWithOptions:(RNNOptions *)options;
43 42
 
44 43
 @end

+ 40
- 58
lib/ios/RNNNavigationOptions.m Просмотреть файл

@@ -8,42 +8,17 @@
8 8
 #import "RNNSplitViewController.h"
9 9
 #import "RNNNavigationButtons.h"
10 10
 
11
-const NSInteger BLUR_STATUS_TAG = 78264801;
12
-const NSInteger BLUR_TOPBAR_TAG = 78264802;
13
-const NSInteger TOP_BAR_TRANSPARENT_TAG = 78264803;
14
-
15
-@implementation RCTConvert (UIModalPresentationStyle)
16
-
17
-RCT_ENUM_CONVERTER(UIModalPresentationStyle,
18
-				   (@{@"fullScreen": @(UIModalPresentationFullScreen),
19
-					  @"pageSheet": @(UIModalPresentationPageSheet),
20
-					  @"formSheet": @(UIModalPresentationFormSheet),
21
-					  @"currentContext": @(UIModalPresentationCurrentContext),
22
-					  @"custom": @(UIModalPresentationCustom),
23
-					  @"overFullScreen": @(UIModalPresentationOverFullScreen),
24
-					  @"overCurrentContext": @(UIModalPresentationOverCurrentContext),
25
-					  @"popover": @(UIModalPresentationPopover),
26
-					  @"none": @(UIModalPresentationNone)
27
-					  }), UIModalPresentationFullScreen, integerValue)
28
-
29
-@end
30
-
31
-@implementation RCTConvert (UIModalTransitionStyle)
32
-
33
-RCT_ENUM_CONVERTER(UIModalTransitionStyle,
34
-				   (@{@"coverVertical": @(UIModalTransitionStyleCoverVertical),
35
-					  @"flipHorizontal": @(UIModalTransitionStyleFlipHorizontal),
36
-					  @"crossDissolve": @(UIModalTransitionStyleCrossDissolve),
37
-					  @"partialCurl": @(UIModalTransitionStylePartialCurl)
38
-					  }), UIModalTransitionStyleCoverVertical, integerValue)
39
-
40
-@end
41
-
42 11
 @implementation RNNNavigationOptions
43 12
 
13
+- (RNNNavigationOptions *)combineWithOptions:(RNNOptions *)options {
14
+	RNNNavigationOptions *navigationOptions = [[RNNNavigationOptions alloc] initWithDict:@{}];
15
+	[navigationOptions mergeOptions:self overrideOptions:YES];
16
+	[navigationOptions mergeOptions:options overrideOptions:YES];
17
+	
18
+	return navigationOptions;
19
+}
44 20
 
45
--(void)applyOn:(UIViewController<RNNRootViewProtocol> *)viewController {
46
-	[self mergeOptions:_defaultOptions overrideOptions:NO];
21
+- (void)applyOn:(UIViewController *)viewController {
47 22
 	[self.topBar applyOn:viewController];
48 23
 	[self.bottomTabs applyOn:viewController];
49 24
 	[self.topTab applyOn:viewController];
@@ -52,52 +27,59 @@ RCT_ENUM_CONVERTER(UIModalTransitionStyle,
52 27
 	[self.overlay applyOn:viewController];
53 28
 	[self.statusBar applyOn:viewController];
54 29
 	[self.layout applyOn:viewController];
55
-	[self applyOtherOptionsOn:viewController];
56
-	
57
-	[viewController.getLeafViewController optionsUpdated];
30
+	[self applyOtherOptions:self on:viewController];
31
+}
32
+
33
+- (void)applyOnNavigationController:(UINavigationController *)navigationController {
34
+	[self.topBar applyOnNavigationController:navigationController];
35
+	[self.statusBar applyOn:navigationController];
36
+	[self.layout applyOn:navigationController];
37
+	[self.bottomTab applyOn:navigationController];
38
+	[self applyOtherOptions:self onNavigationController:navigationController];
58 39
 }
59 40
 
60
-- (void)applyOtherOptionsOn:(UIViewController*)viewController {
61
-	if (self.popGesture) {
62
-		viewController.navigationController.interactivePopGestureRecognizer.enabled = [self.popGesture boolValue];
41
+- (void)applyOnTabBarController:(UITabBarController *)tabBarController {
42
+	[self.bottomTabs applyOnTabBarController:tabBarController];
43
+}
44
+
45
+- (void)applyOtherOptions:(RNNNavigationOptions *)options onNavigationController:(UINavigationController*)navigationController {
46
+	if (options.popGesture) {
47
+		navigationController.interactivePopGestureRecognizer.enabled = [options.popGesture boolValue];
63 48
 	}
64 49
 	
65
-	if (self.backgroundImage) {
66
-		UIImageView* backgroundImageView = (viewController.view.subviews.count > 0) ? viewController.view.subviews[0] : nil;
50
+	if (options.rootBackgroundImage) {
51
+		UIImageView* backgroundImageView = (navigationController.view.subviews.count > 0) ? navigationController.view.subviews[0] : nil;
67 52
 		if (![backgroundImageView isKindOfClass:[UIImageView class]]) {
68
-			backgroundImageView = [[UIImageView alloc] initWithFrame:viewController.view.bounds];
69
-			[viewController.view insertSubview:backgroundImageView atIndex:0];
53
+			backgroundImageView = [[UIImageView alloc] initWithFrame:navigationController.view.bounds];
54
+			[navigationController.view insertSubview:backgroundImageView atIndex:0];
70 55
 		}
71 56
 		
72 57
 		backgroundImageView.layer.masksToBounds = YES;
73
-		backgroundImageView.image = [self.backgroundImage isKindOfClass:[UIImage class]] ? (UIImage*)self.backgroundImage : [RCTConvert UIImage:self.backgroundImage];
58
+		backgroundImageView.image = [options.rootBackgroundImage isKindOfClass:[UIImage class]] ? (UIImage*)options.rootBackgroundImage : [RCTConvert UIImage:options.rootBackgroundImage];
74 59
 		[backgroundImageView setContentMode:UIViewContentModeScaleAspectFill];
75 60
 	}
76
-	
77
-	if (self.rootBackgroundImage) {
78
-		UIImageView* backgroundImageView = (viewController.navigationController.view.subviews.count > 0) ? viewController.navigationController.view.subviews[0] : nil;
61
+}
62
+
63
+- (void)applyOtherOptions:(RNNNavigationOptions *)options on:(UIViewController*)viewController {
64
+	if (options.backgroundImage) {
65
+		UIImageView* backgroundImageView = (viewController.view.subviews.count > 0) ? viewController.view.subviews[0] : nil;
79 66
 		if (![backgroundImageView isKindOfClass:[UIImageView class]]) {
80 67
 			backgroundImageView = [[UIImageView alloc] initWithFrame:viewController.view.bounds];
81
-			[viewController.navigationController.view insertSubview:backgroundImageView atIndex:0];
68
+			[viewController.view insertSubview:backgroundImageView atIndex:0];
82 69
 		}
83 70
 		
84 71
 		backgroundImageView.layer.masksToBounds = YES;
85
-		backgroundImageView.image = [self.rootBackgroundImage isKindOfClass:[UIImage class]] ? (UIImage*)self.rootBackgroundImage : [RCTConvert UIImage:self.rootBackgroundImage];
72
+		backgroundImageView.image = [options.backgroundImage isKindOfClass:[UIImage class]] ? (UIImage*)options.backgroundImage : [RCTConvert UIImage:options.backgroundImage];
86 73
 		[backgroundImageView setContentMode:UIViewContentModeScaleAspectFill];
87 74
 	}
88
-	
89
-	[self applyModalOptions:viewController];
90
-}
91 75
 
92
-- (void)applyModalOptions:(UIViewController*)viewController {
93
-	if (self.modalPresentationStyle) {
94
-		viewController.modalPresentationStyle = [RCTConvert UIModalPresentationStyle:self.modalPresentationStyle];
76
+	if (options.modalPresentationStyle) {
77
+		viewController.modalPresentationStyle = [RCTConvert UIModalPresentationStyle:options.modalPresentationStyle];
95 78
 		[viewController.view setBackgroundColor:[UIColor clearColor]];
96 79
 	}
97
-	if (self.modalTransitionStyle) {
98
-		viewController.modalTransitionStyle = [RCTConvert UIModalTransitionStyle:self.modalTransitionStyle];
80
+	if (options.modalTransitionStyle) {
81
+		viewController.modalTransitionStyle = [RCTConvert UIModalTransitionStyle:options.modalTransitionStyle];
99 82
 	}
100 83
 }
101 84
 
102
-
103 85
 @end

+ 4
- 0
lib/ios/RNNOptions.h Просмотреть файл

@@ -8,7 +8,11 @@
8 8
 
9 9
 @optional
10 10
 - (void)resetOptions;
11
+
12
+@required
11 13
 - (void)applyOn:(UIViewController *)viewController;
14
+- (void)applyOnNavigationController:(UINavigationController *)navigationController;
15
+- (void)applyOnTabBarController:(UITabBarController *)tabBarController;
12 16
 
13 17
 @end
14 18
 

+ 14
- 2
lib/ios/RNNOptions.m Просмотреть файл

@@ -4,7 +4,7 @@
4 4
 
5 5
 @implementation RNNOptions
6 6
 
7
--(instancetype)	initWithDict:(NSDictionary *)dict {
7
+- (instancetype)initWithDict:(NSDictionary *)dict {
8 8
 	self = [super init];
9 9
 	[self initializeOptionsPropertiesWithDict:dict];
10 10
 	
@@ -17,7 +17,19 @@
17 17
 	[self applyOn:viewController];
18 18
 }
19 19
 
20
--(void)mergeWith:(NSDictionary *)otherOptions {
20
+- (void)applyOn:(UIViewController *)viewController {
21
+	
22
+}
23
+
24
+- (void)applyOnNavigationController:(UINavigationController *)navigationController {
25
+	
26
+}
27
+
28
+- (void)applyOnTabBarController:(UITabBarController *)tabBarController {
29
+	
30
+}
31
+
32
+- (void)mergeWith:(NSDictionary *)otherOptions {
21 33
 	for (id key in otherOptions) {
22 34
 		if ([self hasProperty:key]) {
23 35
 			if ([[self valueForKey:key] isKindOfClass:[RNNOptions class]]) {

+ 10
- 0
lib/ios/RNNOptionsManager.h Просмотреть файл

@@ -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 Просмотреть файл

@@ -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 Просмотреть файл

@@ -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];

+ 15
- 0
lib/ios/RNNParentProtocol.h Просмотреть файл

@@ -0,0 +1,15 @@
1
+#import "RNNLayoutProtocol.h"
2
+#import "RNNLeafProtocol.h"
3
+
4
+@protocol RNNParentProtocol <RNNLayoutProtocol, UINavigationControllerDelegate, UIViewControllerTransitioningDelegate, UISplitViewControllerDelegate>
5
+
6
+@required
7
+
8
+- (UIViewController<RNNLeafProtocol> *)getLeafViewController;
9
+
10
+@optional
11
+
12
+- (void)performOnChildWillAppear:(RNNNavigationOptions *)options;
13
+- (void)performOnChildLoad:(RNNNavigationOptions *)options;
14
+
15
+@end

+ 9
- 13
lib/ios/RNNRootViewController.h Просмотреть файл

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

+ 55
- 83
lib/ios/RNNRootViewController.m Просмотреть файл

@@ -4,6 +4,7 @@
4 4
 #import "RNNCustomTitleView.h"
5 5
 #import "RNNPushAnimation.h"
6 6
 #import "RNNReactView.h"
7
+#import "RNNParentProtocol.h"
7 8
 
8 9
 @interface RNNRootViewController() {
9 10
 	RNNReactView* _customTitleView;
@@ -12,11 +13,7 @@
12 13
 	BOOL _isBeingPresented;
13 14
 }
14 15
 
15
-@property (nonatomic, strong) NSString* componentName;
16
-@property (nonatomic) BOOL _statusBarHidden;
17 16
 @property (nonatomic) BOOL isExternalComponent;
18
-@property (nonatomic) BOOL _optionsApplied;
19
-@property (nonatomic, copy) void (^rotationBlock)(void);
20 17
 @property (nonatomic, copy) RNNReactViewReadyCompletionBlock reactViewReadyBlock;
21 18
 
22 19
 @end
@@ -25,23 +22,23 @@
25 22
 
26 23
 @synthesize previewCallback;
27 24
 
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 {
25
+- (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo
26
+				   rootViewCreator:(id<RNNRootViewCreator>)creator
27
+					  eventEmitter:(RNNEventEmitter*)eventEmitter
28
+			   isExternalComponent:(BOOL)isExternalComponent
29
+						 presenter:(RNNViewControllerPresenter *)presenter {
34 30
 	self = [super init];
35
-	self.componentId = componentId;
36
-	self.componentName = name;
37
-	self.options = options;
38 31
 	self.eventEmitter = eventEmitter;
39
-	self.animator = [[RNNAnimator alloc] initWithTransitionOptions:self.options.customTransition];
40 32
 	self.creator = creator;
41 33
 	self.isExternalComponent = isExternalComponent;
34
+	self.layoutInfo = layoutInfo;
35
+	self.presenter = presenter;
36
+	self.presenter.delegate = self;
37
+	
38
+	self.animator = [[RNNAnimator alloc] initWithTransitionOptions:self.presenter.options.customTransition];
42 39
 	
43 40
 	if (!self.isExternalComponent) {
44
-		self.view = [creator createRootView:self.componentName rootViewId:self.componentId];
41
+		self.view = [creator createRootView:self.layoutInfo.name rootViewId:self.layoutInfo.componentId];
45 42
 		[[NSNotificationCenter defaultCenter] addObserver:self
46 43
 												 selector:@selector(reactViewReady)
47 44
 													 name: @"RCTContentDidAppearNotification"
@@ -53,22 +50,22 @@
53 50
 												 name:RCTJavaScriptWillStartLoadingNotification
54 51
 											   object:nil];
55 52
 	self.navigationController.delegate = self;
56
-	[[NSNotificationCenter defaultCenter] addObserver:self
57
-											 selector:@selector(orientationDidChange:)
58
-												 name:UIDeviceOrientationDidChangeNotification
59
-											   object:nil];
53
+
60 54
 	return self;
61 55
 }
62 56
 
63 57
 -(void)viewWillAppear:(BOOL)animated{
64 58
 	[super viewWillAppear:animated];
65 59
 	_isBeingPresented = YES;
66
-	[self.options applyOn:self];
60
+	[_presenter presentOn:self];
61
+	if ([self.parentViewController respondsToSelector:@selector(performOnChildWillAppear:)]) {
62
+		[self.parentViewController performSelector:@selector(performOnChildWillAppear:) withObject:_presenter.options];
63
+	}
67 64
 }
68 65
 
69 66
 -(void)viewDidAppear:(BOOL)animated {
70 67
 	[super viewDidAppear:animated];
71
-	[self.eventEmitter sendComponentDidAppear:self.componentId componentName:self.componentName];
68
+	[self.eventEmitter sendComponentDidAppear:self.layoutInfo.componentId componentName:self.layoutInfo.name];
72 69
 }
73 70
 
74 71
 - (void)viewWillDisappear:(BOOL)animated {
@@ -78,7 +75,13 @@
78 75
 
79 76
 -(void)viewDidDisappear:(BOOL)animated {
80 77
 	[super viewDidDisappear:animated];
81
-	[self.eventEmitter sendComponentDidDisappear:self.componentId componentName:self.componentName];
78
+	[self.eventEmitter sendComponentDidDisappear:self.layoutInfo.componentId componentName:self.layoutInfo.name];
79
+}
80
+
81
+- (void)willMoveToParentViewController:(UIViewController *)parent {
82
+	if ([self.parentViewController respondsToSelector:@selector(performOnChildLoad:)]) {
83
+		[self.parentViewController performSelector:@selector(performOnChildLoad:) withObject:_presenter.options];
84
+	}
82 85
 }
83 86
 
84 87
 - (void)reactViewReady {
@@ -90,6 +93,7 @@
90 93
 	[[NSNotificationCenter defaultCenter] removeObserver:self name:@"RCTContentDidAppearNotification" object:nil];
91 94
 }
92 95
 
96
+
93 97
 - (void)waitForReactViewRender:(BOOL)wait perform:(RNNReactViewReadyCompletionBlock)readyBlock {
94 98
 	if (wait && !_isExternalComponent) {
95 99
 		[self onReactViewReady:readyBlock];
@@ -111,17 +115,13 @@
111 115
 }
112 116
 
113 117
 -(void)updateSearchResultsForSearchController:(UISearchController *)searchController {
114
-	[self.eventEmitter sendOnSearchBarUpdated:self.componentId
118
+	[self.eventEmitter sendOnSearchBarUpdated:self.layoutInfo.componentId
115 119
 										 text:searchController.searchBar.text
116 120
 									isFocused:searchController.searchBar.isFirstResponder];
117 121
 }
118 122
 
119 123
 - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
120
-	[self.eventEmitter sendOnSearchBarCancelPressed:self.componentId];
121
-}
122
-
123
-- (void)viewDidLoad {
124
-	[super viewDidLoad];
124
+	[self.eventEmitter sendOnSearchBarCancelPressed:self.layoutInfo.componentId];
125 125
 }
126 126
 
127 127
 - (void)optionsUpdated {
@@ -130,22 +130,13 @@
130 130
 	[self setCustomNavigationComponentBackground];
131 131
 }
132 132
 
133
-- (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];
140
-}
141
-
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.presenter.options.topBar.title.component.name) {
136
+			_customTitleView = (RNNReactView*)[_creator createRootViewFromComponentOptions:self.presenter.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.presenter.options.topBar.title.component.alignment];
139
+			BOOL isCenter = [self.presenter.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.presenter.options.topBar.component.name) {
164
+			RCTRootView *reactView = (RCTRootView*)[_creator createRootViewFromComponentOptions:self.presenter.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.presenter.options.topBar.background.component.name) {
184
+			RCTRootView *reactView = (RCTRootView*)[_creator createRootViewFromComponentOptions:self.presenter.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.presenter.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.presenter.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.presenter.options.statusBar.visible) {
216
+		return ![self.presenter.options.statusBar.visible boolValue];
217
+	} else if ([self.presenter.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.presenter.options.statusBar.style && [self.presenter.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.presenter.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.presenter.options.bottomTabs && self.presenter.options.bottomTabs.visible) {
239
+		return ![self.presenter.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.presenter.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.presenter.options.animations.push.hasCustomAnimation) {
259
+			return [[RNNPushAnimation alloc] initWithScreenTransition:self.presenter.options.animations.push];
260
+		} else if (operation == UINavigationControllerOperationPop && self.presenter.options.animations.pop.hasCustomAnimation) {
261
+			return [[RNNPushAnimation alloc] initWithScreenTransition:self.presenter.options.animations.pop];
271 262
 		} else {
272 263
 			return nil;
273 264
 		}
@@ -276,30 +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.presenter.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];
293
-}
294
-
295
-- (void)performOnRotation:(void (^)(void))block {
296
-	_rotationBlock = block;
297
-}
298
-
299
-- (void)orientationDidChange:(NSNotification*)notification {
300
-	if (_rotationBlock) {
301
-		_rotationBlock();
302
-	}
274
+	return [[RNNModalAnimation alloc] initWithScreenTransition:self.presenter.options.animations.dismissModal isDismiss:YES];
303 275
 }
304 276
 
305 277
 - (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location{
@@ -314,7 +286,7 @@
314 286
 }
315 287
 
316 288
 - (void)onActionPress:(NSString *)id {
317
-	[_eventEmitter sendOnNavigationButtonPressed:self.componentId buttonId:id];
289
+	[_eventEmitter sendOnNavigationButtonPressed:self.layoutInfo.componentId buttonId:id];
318 290
 }
319 291
 
320 292
 - (UIPreviewAction *) convertAction:(NSDictionary *)action {
@@ -334,7 +306,7 @@
334 306
 
335 307
 - (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
336 308
 	NSMutableArray *actions = [[NSMutableArray alloc] init];
337
-	for (NSDictionary *previewAction in self.options.preview.actions) {
309
+	for (NSDictionary *previewAction in self.presenter.options.preview.actions) {
338 310
 		UIPreviewAction *action = [self convertAction:previewAction];
339 311
 		NSDictionary *actionActions = previewAction[@"actions"];
340 312
 		if (actionActions.count > 0) {
@@ -352,7 +324,7 @@
352 324
 }
353 325
 
354 326
 -(void)onButtonPress:(RNNUIBarButtonItem *)barButtonItem {
355
-	[self.eventEmitter sendOnNavigationButtonPressed:self.componentId buttonId:barButtonItem.buttonId];
327
+	[self.eventEmitter sendOnNavigationButtonPressed:self.layoutInfo.componentId buttonId:barButtonItem.buttonId];
356 328
 }
357 329
 
358 330
 /**

+ 0
- 16
lib/ios/RNNRootViewProtocol.h Просмотреть файл

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

+ 7
- 4
lib/ios/RNNSideMenuChildVC.h Просмотреть файл

@@ -7,7 +7,7 @@
7 7
 //
8 8
 
9 9
 #import <UIKit/UIKit.h>
10
-#import "RNNRootViewProtocol.h"
10
+#import "RNNParentProtocol.h"
11 11
 
12 12
 typedef NS_ENUM(NSInteger, RNNSideMenuChildType) {
13 13
 	RNNSideMenuChildTypeCenter,
@@ -16,11 +16,14 @@ typedef NS_ENUM(NSInteger, RNNSideMenuChildType) {
16 16
 };
17 17
 
18 18
 
19
-@interface RNNSideMenuChildVC : UIViewController <RNNRootViewProtocol>
19
+@interface RNNSideMenuChildVC : UIViewController <RNNParentProtocol>
20 20
 
21 21
 @property (readonly) RNNSideMenuChildType type;
22
-@property (readonly) UIViewController<RNNRootViewProtocol> *child;
22
+@property (readonly) UIViewController<RNNParentProtocol> *child;
23 23
 
24
--(instancetype) initWithChild:(UIViewController<RNNRootViewProtocol>*)child type:(RNNSideMenuChildType)type;
24
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
25
+@property (nonatomic, retain) RNNBasePresenter* presenter;
26
+
27
+-(instancetype) initWithChild:(UIViewController<RNNParentProtocol>*)child type:(RNNSideMenuChildType)type;
25 28
 
26 29
 @end

+ 3
- 3
lib/ios/RNNSideMenuChildVC.m Просмотреть файл

@@ -11,13 +11,13 @@
11 11
 @interface RNNSideMenuChildVC ()
12 12
 
13 13
 @property (readwrite) RNNSideMenuChildType type;
14
-@property (readwrite) UIViewController<RNNRootViewProtocol> *child;
14
+@property (readwrite) UIViewController<RNNParentProtocol> *child;
15 15
 
16 16
 @end
17 17
 
18 18
 @implementation RNNSideMenuChildVC
19 19
 
20
--(instancetype) initWithChild:(UIViewController<RNNRootViewProtocol>*)child type:(RNNSideMenuChildType)type {
20
+-(instancetype) initWithChild:(UIViewController<RNNParentProtocol>*)child type:(RNNSideMenuChildType)type {
21 21
 	self = [super init];
22 22
 	
23 23
 	self.child = child;	
@@ -31,7 +31,7 @@
31 31
 	return self;
32 32
 }
33 33
 
34
-- (RNNRootViewController *)getLeafViewController {
34
+- (UIViewController *)getLeafViewController {
35 35
 	return [self.child getLeafViewController];
36 36
 }
37 37
 

+ 5
- 2
lib/ios/RNNSideMenuController.h Просмотреть файл

@@ -9,15 +9,18 @@
9 9
 #import <UIKit/UIKit.h>
10 10
 #import "RNNSideMenuChildVC.h"
11 11
 #import "MMDrawerController.h"
12
-#import "RNNRootViewProtocol.h"
12
+#import "RNNParentProtocol.h"
13 13
 
14
-@interface RNNSideMenuController : UIViewController <RNNRootViewProtocol>
14
+@interface RNNSideMenuController : UIViewController <RNNParentProtocol>
15 15
 
16 16
 @property (readonly) RNNSideMenuChildVC *center;
17 17
 @property (readonly) RNNSideMenuChildVC *left;
18 18
 @property (readonly) RNNSideMenuChildVC *right;
19 19
 @property (readonly) MMDrawerController *sideMenu;
20 20
 
21
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
22
+@property (nonatomic, retain) RNNBasePresenter* presenter;
23
+
21 24
 -(instancetype)initWithControllers:(NSArray*)controllers;
22 25
 
23 26
 -(void)showSideMenu:(MMDrawerSide)side animated:(BOOL)animated;

+ 1
- 4
lib/ios/RNNSideMenuController.m Просмотреть файл

@@ -89,12 +89,9 @@
89 89
 	}
90 90
 }
91 91
 
92
-- (RNNRootViewController *)getLeafViewController {
92
+- (UIViewController<RNNLayoutProtocol> *)getLeafViewController {
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

+ 4
- 2
lib/ios/RNNSplitViewController.h Просмотреть файл

@@ -8,13 +8,15 @@
8 8
 #import "RNNSplitViewOptions.h"
9 9
 #import "RNNAnimator.h"
10 10
 #import "RNNTopTabsViewController.h"
11
-#import "RNNRootViewProtocol.h"
11
+#import "RNNParentProtocol.h"
12 12
 
13
-@interface RNNSplitViewController : UISplitViewController	<RNNRootViewProtocol>
13
+@interface RNNSplitViewController : UISplitViewController	<RNNParentProtocol>
14 14
 
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;
19
+@property (nonatomic, retain) RNNBasePresenter* presenter;
18 20
 @property (nonatomic) id<RNNRootViewCreator> creator;
19 21
 
20 22
 -(instancetype)initWithOptions:(RNNSplitViewOptions*)options

+ 0
- 13
lib/ios/RNNSplitViewController.m Просмотреть файл

@@ -1,10 +1,5 @@
1 1
 #import "RNNSplitViewController.h"
2 2
 
3
-@interface RNNSplitViewController()
4
-@property (nonatomic) BOOL _optionsApplied;
5
-@property (nonatomic, copy) void (^rotationBlock)(void);
6
-@end
7
-
8 3
 @implementation RNNSplitViewController
9 4
 
10 5
 -(instancetype)initWithOptions:(RNNSplitViewOptions*)options
@@ -31,12 +26,4 @@
31 26
 	return self;
32 27
 }
33 28
 
34
-- (void)waitForReactViewRender:(BOOL)wait perform:(RNNReactViewReadyCompletionBlock)readyBlock {
35
-	readyBlock();
36
-}
37
-
38
-- (void)mergeOptions:(RNNOptions *)options {
39
-	[self.options mergeOptions:options];
40
-}
41
-
42 29
 @end

+ 2
- 2
lib/ios/RNNSplitViewOptions.m Просмотреть файл

@@ -1,9 +1,9 @@
1 1
 #import "RNNSplitViewOptions.h"
2
-#import "RNNRootViewProtocol.h"
2
+#import "RNNParentProtocol.h"
3 3
 
4 4
 @implementation RNNSplitViewOptions
5 5
 
6
--(void)applyOn:(UIViewController<RNNRootViewProtocol> *)viewController {
6
+-(void)applyOn:(UIViewController<RNNParentProtocol> *)viewController {
7 7
 	
8 8
 	UISplitViewController *svc = (UISplitViewController*) viewController;
9 9
 

+ 2
- 0
lib/ios/RNNStatusBarOptions.m Просмотреть файл

@@ -1,5 +1,7 @@
1 1
 #import "RNNStatusBarOptions.h"
2 2
 #define kStatusBarAnimationDuration 0.35
3
+const NSInteger BLUR_STATUS_TAG = 78264801;
4
+const NSInteger BLUR_TOPBAR_TAG = 78264802;
3 5
 
4 6
 @implementation RNNStatusBarOptions
5 7
 

+ 2
- 2
lib/ios/RNNStore.h Просмотреть файл

@@ -1,7 +1,7 @@
1 1
 
2 2
 #import <Foundation/Foundation.h>
3 3
 #import <UIKit/UIKit.h>
4
-#import "RNNRootViewProtocol.h"
4
+#import "RNNParentProtocol.h"
5 5
 #import "ReactNativeNavigation.h"
6 6
 
7 7
 typedef void (^RNNTransitionCompletionBlock)(void);
@@ -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 Просмотреть файл

@@ -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

+ 5
- 2
lib/ios/RNNTabBarController.h Просмотреть файл

@@ -1,12 +1,15 @@
1 1
 
2 2
 #import <UIKit/UIKit.h>
3
-#import "RNNRootViewProtocol.h"
3
+#import "RNNParentProtocol.h"
4 4
 #import "RNNEventEmitter.h"
5 5
 
6
-@interface RNNTabBarController : UITabBarController <RNNRootViewProtocol, UITabBarControllerDelegate>
6
+@interface RNNTabBarController : UITabBarController <RNNParentProtocol, UITabBarControllerDelegate>
7 7
 
8 8
 - (instancetype)initWithEventEmitter:(RNNEventEmitter*)eventEmitter;
9 9
 
10 10
 - (void)setSelectedIndexByComponentID:(NSString *)componentID;
11 11
 
12
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
13
+@property (nonatomic, retain) RNNBasePresenter* presenter;
14
+
12 15
 @end

+ 15
- 8
lib/ios/RNNTabBarController.m Просмотреть файл

@@ -15,15 +15,22 @@
15 15
 	return self;
16 16
 }
17 17
 
18
+- (void)performOnChildLoad:(RNNNavigationOptions *)childOptions {
19
+	[_presenter presentWithChildOptions:childOptions on:self];
20
+	if ([self.parentViewController respondsToSelector:@selector(performOnChildLoad:)]) {
21
+		[self.parentViewController performSelector:@selector(performOnChildLoad:) withObject:childOptions];
22
+	}
23
+}
24
+
18 25
 - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
19 26
 	return self.selectedViewController.supportedInterfaceOrientations;
20 27
 }
21 28
 
22 29
 - (void)setSelectedIndexByComponentID:(NSString *)componentID {
23 30
 	for (id child in self.childViewControllers) {
24
-		RNNRootViewController* vc = child;
31
+		UIViewController<RNNParentProtocol>* vc = child;
25 32
 
26
-		if ([vc.componentId isEqualToString:componentID]) {
33
+		if ([vc.layoutInfo.componentId isEqualToString:componentID]) {
27 34
 			[self setSelectedIndex:[self.childViewControllers indexOfObject:child]];
28 35
 		}
29 36
 	}
@@ -34,16 +41,16 @@
34 41
 	[super setSelectedIndex:selectedIndex];
35 42
 }
36 43
 
37
-- (void)mergeOptions:(RNNOptions *)options {
38
-	[self.getLeafViewController mergeOptions:options];
39
-}
40
-
41 44
 - (UIViewController *)getLeafViewController {
42
-	return ((UIViewController<RNNRootViewProtocol>*)self.selectedViewController).getLeafViewController;
45
+	return ((UIViewController<RNNParentProtocol>*)self.selectedViewController).getLeafViewController;
43 46
 }
44 47
 
45 48
 - (UIStatusBarStyle)preferredStatusBarStyle {
46
-	return ((UIViewController<RNNRootViewProtocol>*)self.selectedViewController).preferredStatusBarStyle;
49
+	return ((UIViewController<RNNParentProtocol>*)self.selectedViewController).preferredStatusBarStyle;
50
+}
51
+
52
+- (void)setViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers {
53
+	[super setViewControllers:viewControllers];
47 54
 }
48 55
 
49 56
 #pragma mark UITabBarControllerDelegate

+ 6
- 0
lib/ios/RNNTabBarPresenter.h Просмотреть файл

@@ -0,0 +1,6 @@
1
+#import <Foundation/Foundation.h>
2
+#import "RNNBasePresenter.h"
3
+
4
+@interface RNNTabBarPresenter : RNNBasePresenter
5
+
6
+@end

+ 9
- 0
lib/ios/RNNTabBarPresenter.m Просмотреть файл

@@ -0,0 +1,9 @@
1
+#import "RNNTabBarPresenter.h"
2
+
3
+@implementation RNNTabBarPresenter
4
+
5
+- (void)presentOn:(UITabBarController *)tabBarController {
6
+	[self.options applyOnTabBarController:tabBarController];
7
+}
8
+
9
+@end

+ 67
- 61
lib/ios/RNNTopBarOptions.m Просмотреть файл

@@ -3,6 +3,8 @@
3 3
 #import "RNNCustomTitleView.h"
4 4
 
5 5
 extern const NSInteger BLUR_TOPBAR_TAG;
6
+const NSInteger TOP_BAR_TRANSPARENT_TAG = 78264803;
7
+
6 8
 
7 9
 @interface RNNTopBarOptions ()
8 10
 
@@ -29,7 +31,6 @@ extern const NSInteger BLUR_TOPBAR_TAG;
29 31
 - (void)applyOn:(UIViewController*)viewController {
30 32
 	[self.title applyOn:viewController];
31 33
 	[self.largeTitle applyOn:viewController];
32
-	[self.background applyOn:viewController];
33 34
 	[self.backButton applyOn:viewController];
34 35
 	
35 36
 	if (@available(iOS 11.0, *)) {
@@ -52,59 +53,96 @@ extern const NSInteger BLUR_TOPBAR_TAG;
52 53
 		}
53 54
 	}
54 55
 	
56
+	if (self.drawBehind) {
57
+		if ([self.drawBehind boolValue]) {
58
+			viewController.edgesForExtendedLayout |= UIRectEdgeTop;
59
+		} else {
60
+			viewController.edgesForExtendedLayout &= ~UIRectEdgeTop;
61
+		}
62
+	} else {
63
+		viewController.edgesForExtendedLayout = UIRectEdgeAll;
64
+	}
65
+	
66
+	if (self.rightButtons || self.leftButtons) {
67
+		_navigationButtons = [[RNNNavigationButtons alloc] initWithViewController:(RNNRootViewController*)viewController];
68
+		[_navigationButtons applyLeftButtons:self.leftButtons rightButtons:self.rightButtons defaultLeftButtonStyle:self.leftButtonStyle defaultRightButtonStyle:self.rightButtonStyle];
69
+	}
70
+	
71
+	[self applyOnNavigationController:viewController.navigationController];
72
+	
73
+	self.rightButtons = nil;
74
+	self.leftButtons = nil;
75
+}
76
+
77
+- (void)applyOnNavigationController:(UINavigationController *)navigationController {
78
+	[self.background applyOnNavigationController:navigationController];
79
+	if (self.testID) {
80
+		navigationController.navigationBar.accessibilityIdentifier = self.testID;
81
+	}
82
+	
55 83
 	if (self.visible) {
56
-		[viewController.navigationController setNavigationBarHidden:![self.visible boolValue] animated:[self.animate boolValue]];
84
+		[navigationController setNavigationBarHidden:![self.visible boolValue] animated:[self.animate boolValue]];
57 85
 	} else {
58
-		[viewController.navigationController setNavigationBarHidden:NO animated:NO];
86
+		[navigationController setNavigationBarHidden:NO animated:NO];
59 87
 	}
60 88
 	
61 89
 	if (self.hideOnScroll) {
62
-		viewController.navigationController.hidesBarsOnSwipe = [self.hideOnScroll boolValue];
90
+		navigationController.hidesBarsOnSwipe = [self.hideOnScroll boolValue];
63 91
 	} else {
64
-		viewController.navigationController.hidesBarsOnSwipe = NO;
92
+		navigationController.hidesBarsOnSwipe = NO;
93
+	}
94
+	
95
+	if (self.noBorder) {
96
+		if ([self.noBorder boolValue]) {
97
+			navigationController.navigationBar
98
+			.shadowImage = [[UIImage alloc] init];
99
+		} else {
100
+			navigationController.navigationBar
101
+			.shadowImage = nil;
102
+		}
65 103
 	}
66 104
 	
67 105
 	if ([self.blur boolValue]) {
68
-		if (![viewController.navigationController.navigationBar viewWithTag:BLUR_TOPBAR_TAG]) {
106
+		if (![navigationController.navigationBar viewWithTag:BLUR_TOPBAR_TAG]) {
69 107
 			
70
-			[viewController.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
71
-			viewController.navigationController.navigationBar.shadowImage = [UIImage new];
108
+			[navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
109
+			navigationController.navigationBar.shadowImage = [UIImage new];
72 110
 			UIVisualEffectView *blur = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
73 111
 			CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
74
-			blur.frame = CGRectMake(0, -1 * statusBarFrame.size.height, viewController.navigationController.navigationBar.frame.size.width, viewController.navigationController.navigationBar.frame.size.height + statusBarFrame.size.height);
112
+			blur.frame = CGRectMake(0, -1 * statusBarFrame.size.height, navigationController.navigationBar.frame.size.width, navigationController.navigationBar.frame.size.height + statusBarFrame.size.height);
75 113
 			blur.userInteractionEnabled = NO;
76 114
 			blur.tag = BLUR_TOPBAR_TAG;
77
-			[viewController.navigationController.navigationBar insertSubview:blur atIndex:0];
78
-			[viewController.navigationController.navigationBar sendSubviewToBack:blur];
115
+			[navigationController.navigationBar insertSubview:blur atIndex:0];
116
+			[navigationController.navigationBar sendSubviewToBack:blur];
79 117
 		}
80 118
 	} else {
81
-		UIView *blur = [viewController.navigationController.navigationBar viewWithTag:BLUR_TOPBAR_TAG];
119
+		UIView *blur = [navigationController.navigationBar viewWithTag:BLUR_TOPBAR_TAG];
82 120
 		if (blur) {
83
-			[viewController.navigationController.navigationBar setBackgroundImage: nil forBarMetrics:UIBarMetricsDefault];
84
-			viewController.navigationController.navigationBar.shadowImage = nil;
121
+			[navigationController.navigationBar setBackgroundImage: nil forBarMetrics:UIBarMetricsDefault];
122
+			navigationController.navigationBar.shadowImage = nil;
85 123
 			[blur removeFromSuperview];
86 124
 		}
87 125
 	}
88 126
 	
89 127
 	void (^disableTopBarTransparent)(void) = ^ {
90
-		UIView *transparentView = [viewController.navigationController.navigationBar viewWithTag:TOP_BAR_TRANSPARENT_TAG];
128
+		UIView *transparentView = [navigationController.navigationBar viewWithTag:TOP_BAR_TRANSPARENT_TAG];
91 129
 		if (transparentView){
92 130
 			[transparentView removeFromSuperview];
93
-			[viewController.navigationController.navigationBar setBackgroundImage:self.originalTopBarImages[@"backgroundImage"] forBarMetrics:UIBarMetricsDefault];
94
-			viewController.navigationController.navigationBar.shadowImage = self.originalTopBarImages[@"shadowImage"];
131
+			[navigationController.navigationBar setBackgroundImage:self.originalTopBarImages[@"backgroundImage"] forBarMetrics:UIBarMetricsDefault];
132
+			navigationController.navigationBar.shadowImage = self.originalTopBarImages[@"shadowImage"];
95 133
 			self.originalTopBarImages = nil;
96 134
 		}
97 135
 	};
98 136
 	
99 137
 	if (self.transparent) {
100 138
 		if ([self.transparent boolValue]) {
101
-			if (![viewController.navigationController.navigationBar viewWithTag:TOP_BAR_TRANSPARENT_TAG]){
102
-				[self storeOriginalTopBarImages:viewController];
103
-				[viewController.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
104
-				viewController.navigationController.navigationBar.shadowImage = [UIImage new];
139
+			if (![navigationController.navigationBar viewWithTag:TOP_BAR_TRANSPARENT_TAG]){
140
+				[self storeOriginalTopBarImages:navigationController];
141
+				[navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
142
+				navigationController.navigationBar.shadowImage = [UIImage new];
105 143
 				UIView *transparentView = [[UIView alloc] initWithFrame:CGRectZero];
106 144
 				transparentView.tag = TOP_BAR_TRANSPARENT_TAG;
107
-				[viewController.navigationController.navigationBar insertSubview:transparentView atIndex:0];
145
+				[navigationController.navigationBar insertSubview:transparentView atIndex:0];
108 146
 			}
109 147
 		} else {
110 148
 			disableTopBarTransparent();
@@ -114,48 +152,16 @@ extern const NSInteger BLUR_TOPBAR_TAG;
114 152
 	}
115 153
 	
116 154
 	if (self.barStyle) {
117
-		viewController.navigationController.navigationBar.barStyle = [RCTConvert UIBarStyle:self.barStyle];
155
+		navigationController.navigationBar.barStyle = [RCTConvert UIBarStyle:self.barStyle];
118 156
 	} else {
119
-		viewController.navigationController.navigationBar.barStyle = UIBarStyleDefault;
157
+		navigationController.navigationBar.barStyle = UIBarStyleDefault;
120 158
 	}
121 159
 	
122 160
 	if (self.translucent) {
123
-		viewController.navigationController.navigationBar.translucent = [self.translucent boolValue];
161
+		navigationController.navigationBar.translucent = [self.translucent boolValue];
124 162
 	} else {
125
-		viewController.navigationController.navigationBar.translucent = NO;
126
-	}
127
-	
128
-	if (self.drawBehind) {
129
-		if ([self.drawBehind boolValue]) {
130
-			viewController.edgesForExtendedLayout |= UIRectEdgeTop;
131
-		} else {
132
-			viewController.edgesForExtendedLayout &= ~UIRectEdgeTop;
133
-		}
134
-	} else {
135
-		viewController.edgesForExtendedLayout = UIRectEdgeAll;
136
-	}
137
-	
138
-	if (self.noBorder) {
139
-		if ([self.noBorder boolValue]) {
140
-			viewController.navigationController.navigationBar
141
-			.shadowImage = [[UIImage alloc] init];
142
-		} else {
143
-			viewController.navigationController.navigationBar
144
-			.shadowImage = nil;
145
-		}
163
+		navigationController.navigationBar.translucent = NO;
146 164
 	}
147
-	
148
-	if (self.testID) {
149
-		viewController.navigationController.navigationBar.accessibilityIdentifier = self.testID;
150
-	}
151
-	
152
-	if (self.rightButtons || self.leftButtons) {
153
-		_navigationButtons = [[RNNNavigationButtons alloc] initWithViewController:(RNNRootViewController*)viewController];
154
-		[_navigationButtons applyLeftButtons:self.leftButtons rightButtons:self.rightButtons defaultLeftButtonStyle:self.leftButtonStyle defaultRightButtonStyle:self.rightButtonStyle];
155
-	}
156
-	
157
-	self.rightButtons = nil;
158
-	self.leftButtons = nil;
159 165
 }
160 166
 
161 167
 - (void)setRightButtonColor:(NSNumber *)rightButtonColor {
@@ -206,13 +212,13 @@ extern const NSInteger BLUR_TOPBAR_TAG;
206 212
 	}
207 213
 }
208 214
 
209
--(void)storeOriginalTopBarImages:(UIViewController*)viewController {
215
+-(void)storeOriginalTopBarImages:(UINavigationController *)navigationController {
210 216
 	NSMutableDictionary *originalTopBarImages = [@{} mutableCopy];
211
-	UIImage *bgImage = [viewController.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault];
217
+	UIImage *bgImage = [navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault];
212 218
 	if (bgImage != nil) {
213 219
 		originalTopBarImages[@"backgroundImage"] = bgImage;
214 220
 	}
215
-	UIImage *shadowImage = viewController.navigationController.navigationBar.shadowImage;
221
+	UIImage *shadowImage = navigationController.navigationBar.shadowImage;
216 222
 	if (shadowImage != nil) {
217 223
 		originalTopBarImages[@"shadowImage"] = shadowImage;
218 224
 	}

+ 4
- 2
lib/ios/RNNTopTabsViewController.h Просмотреть файл

@@ -1,11 +1,13 @@
1 1
 #import <Foundation/Foundation.h>
2 2
 #import <UIKit/UIKit.h>
3 3
 #import <React/RCTUIManager.h>
4
-#import "RNNRootViewProtocol.h"
4
+#import "RNNParentProtocol.h"
5 5
 
6
-@interface RNNTopTabsViewController : UIViewController <RNNRootViewProtocol>
6
+@interface RNNTopTabsViewController : UIViewController <RNNParentProtocol>
7 7
 
8 8
 @property (nonatomic, retain) UIView* contentView;
9
+@property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
10
+@property (nonatomic, retain) RNNBasePresenter* presenter;
9 11
 
10 12
 - (void)setViewControllers:(NSArray*)viewControllers;
11 13
 - (void)viewController:(UIViewController*)vc changedTitle:(NSString*)title;

+ 5
- 4
lib/ios/RNNTopTabsViewController.m Просмотреть файл

@@ -1,10 +1,11 @@
1 1
 #import "RNNTopTabsViewController.h"
2 2
 #import "RNNSegmentedControl.h"
3 3
 #import "ReactNativeNavigation.h"
4
+#import "RNNRootViewController.h"
4 5
 
5 6
 @interface RNNTopTabsViewController () {
6 7
 	NSArray* _viewControllers;
7
-	UIViewController<RNNRootViewProtocol>* _currentViewController;
8
+	UIViewController<RNNParentProtocol>* _currentViewController;
8 9
 	RNNSegmentedControl* _segmentedControl;
9 10
 }
10 11
 
@@ -46,7 +47,7 @@
46 47
 }
47 48
 
48 49
 - (void)setSelectedViewControllerIndex:(NSUInteger)index {
49
-	UIViewController<RNNRootViewProtocol> *toVC = _viewControllers[index];
50
+	UIViewController<RNNParentProtocol> *toVC = _viewControllers[index];
50 51
 	[_contentView addSubview:toVC.view];
51 52
 	[_currentViewController.view removeFromSuperview];
52 53
 	_currentViewController = toVC;
@@ -56,7 +57,7 @@
56 57
 	_viewControllers = viewControllers;
57 58
 	for (RNNRootViewController* childVc in viewControllers) {
58 59
 		[childVc.view setFrame:_contentView.bounds];
59
-		[childVc applyTopTabsOptions];
60
+		[childVc.presenter.options.topTab applyOn:childVc];
60 61
 	}
61 62
 	
62 63
 	[self setSelectedViewControllerIndex:0];
@@ -71,7 +72,7 @@
71 72
     [super viewDidLoad];
72 73
 }
73 74
 
74
-#pragma mark RNNRootViewProtocol
75
+#pragma mark RNNParentProtocol
75 76
 
76 77
 - (UIViewController *)getLeafViewController {
77 78
 	return _currentViewController;

+ 8
- 0
lib/ios/RNNViewControllerPresenter.h Просмотреть файл

@@ -0,0 +1,8 @@
1
+#import <Foundation/Foundation.h>
2
+#import "RNNBasePresenter.h"
3
+
4
+@interface RNNViewControllerPresenter : RNNBasePresenter
5
+
6
+- (void)presentOn:(UIViewController *)viewController;
7
+
8
+@end

+ 13
- 0
lib/ios/RNNViewControllerPresenter.m Просмотреть файл

@@ -0,0 +1,13 @@
1
+#import "RNNViewControllerPresenter.h"
2
+
3
+@implementation RNNViewControllerPresenter
4
+
5
+- (void)presentOn:(UIViewController *)viewController {
6
+	[self.options applyOn:viewController];
7
+	
8
+	if ([self.delegate respondsToSelector:@selector(optionsUpdated)]) {
9
+		[self.delegate optionsUpdated];
10
+	}
11
+}
12
+
13
+@end

+ 74
- 4
lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj Просмотреть файл

@@ -67,8 +67,14 @@
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 */; };
76
+		50215750214FE005000703F7 /* RNNTabBarPresenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 5021574E214FE005000703F7 /* RNNTabBarPresenter.h */; };
77
+		50215751214FE005000703F7 /* RNNTabBarPresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5021574F214FE005000703F7 /* RNNTabBarPresenter.m */; };
72 78
 		50220F48212ABDFD004C2B0A /* RNNReactRootView.h in Headers */ = {isa = PBXBuildFile; fileRef = 50220F46212ABDFD004C2B0A /* RNNReactRootView.h */; };
73 79
 		50220F49212ABDFD004C2B0A /* RNNReactRootView.m in Sources */ = {isa = PBXBuildFile; fileRef = 50220F47212ABDFD004C2B0A /* RNNReactRootView.m */; };
74 80
 		502CB43A20CBCA180019B2FE /* RNNBridgeManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 502CB43920CBCA140019B2FE /* RNNBridgeManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -94,6 +100,15 @@
94 100
 		50570B272061473D006A1B5C /* RNNTitleOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50570B252061473D006A1B5C /* RNNTitleOptions.m */; };
95 101
 		50570BEA2063E09B006A1B5C /* RNNTitleViewHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 50570BE82063E09B006A1B5C /* RNNTitleViewHelper.h */; };
96 102
 		50570BEB2063E09B006A1B5C /* RNNTitleViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 50570BE92063E09B006A1B5C /* RNNTitleViewHelper.m */; };
103
+		505EDD32214E4BE80071C7DE /* RNNNavigationControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 505EDD31214E4BE80071C7DE /* RNNNavigationControllerTest.m */; };
104
+		505EDD34214E7B7B0071C7DE /* RNNLeafProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 505EDD33214E7A6A0071C7DE /* RNNLeafProtocol.h */; };
105
+		505EDD3C214FA8000071C7DE /* RNNViewControllerPresenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 505EDD3A214FA8000071C7DE /* RNNViewControllerPresenter.h */; };
106
+		505EDD3D214FA8000071C7DE /* RNNViewControllerPresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 505EDD3B214FA8000071C7DE /* RNNViewControllerPresenter.m */; };
107
+		505EDD41214FBCBE0071C7DE /* RNNNavigationControllerPresenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 505EDD3F214FBCBE0071C7DE /* RNNNavigationControllerPresenter.h */; };
108
+		505EDD42214FBCBE0071C7DE /* RNNNavigationControllerPresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 505EDD40214FBCBE0071C7DE /* RNNNavigationControllerPresenter.m */; };
109
+		505EDD45214FBD3C0071C7DE /* RNNBasePresenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 505EDD43214FBD3C0071C7DE /* RNNBasePresenter.h */; };
110
+		505EDD46214FBD3C0071C7DE /* RNNBasePresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 505EDD44214FBD3C0071C7DE /* RNNBasePresenter.m */; };
111
+		505EDD4A214FDA800071C7DE /* RCTConvert+Modal.h in Headers */ = {isa = PBXBuildFile; fileRef = 505EDD48214FDA800071C7DE /* RCTConvert+Modal.h */; };
97 112
 		5064495D20DC62B90026709C /* RNNSideMenuSideOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 5064495B20DC62B90026709C /* RNNSideMenuSideOptions.h */; };
98 113
 		5064495E20DC62B90026709C /* RNNSideMenuSideOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5064495C20DC62B90026709C /* RNNSideMenuSideOptions.m */; };
99 114
 		50644A2020E11A720026709C /* Constants.h in Headers */ = {isa = PBXBuildFile; fileRef = 50644A1E20E11A720026709C /* Constants.h */; };
@@ -114,7 +129,7 @@
114 129
 		507F43F51FF4FCFE00D9425B /* HMSegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 507F43F31FF4FCFE00D9425B /* HMSegmentedControl.m */; };
115 130
 		507F43F81FF525B500D9425B /* RNNSegmentedControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 507F43F61FF525B500D9425B /* RNNSegmentedControl.h */; };
116 131
 		507F43F91FF525B500D9425B /* RNNSegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 507F43F71FF525B500D9425B /* RNNSegmentedControl.m */; };
117
-		507F44201FFA8A8800D9425B /* RNNRootViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 507F441F1FFA8A8800D9425B /* RNNRootViewProtocol.h */; };
132
+		507F44201FFA8A8800D9425B /* RNNParentProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 507F441F1FFA8A8800D9425B /* RNNParentProtocol.h */; };
118 133
 		50887C1520ECC5C200D06111 /* RNNButtonOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50887C1320ECC5C200D06111 /* RNNButtonOptions.h */; };
119 134
 		50887C1620ECC5C200D06111 /* RNNButtonOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50887C1420ECC5C200D06111 /* RNNButtonOptions.m */; };
120 135
 		50887CA920F26BFE00D06111 /* RNNOverlayWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 50887CA720F26BFD00D06111 /* RNNOverlayWindow.m */; };
@@ -295,8 +310,14 @@
295 310
 		5016E8EE2020968F009D4F7C /* RNNCustomTitleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNCustomTitleView.m; sourceTree = "<group>"; };
296 311
 		50175CCF207A2AA1004FE91B /* RNNComponentOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNComponentOptions.h; sourceTree = "<group>"; };
297 312
 		50175CD0207A2AA1004FE91B /* RNNComponentOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNComponentOptions.m; sourceTree = "<group>"; };
313
+		501CD31D214A5B6900A6E225 /* RNNLayoutInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNLayoutInfo.h; sourceTree = "<group>"; };
314
+		501CD31E214A5B6900A6E225 /* RNNLayoutInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNLayoutInfo.m; sourceTree = "<group>"; };
315
+		501CD321214A5CA900A6E225 /* RNNOptionsManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNOptionsManager.h; sourceTree = "<group>"; };
316
+		501CD322214A5CA900A6E225 /* RNNOptionsManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNOptionsManager.m; sourceTree = "<group>"; };
298 317
 		501E0215213E7EA3003365C5 /* RNNReactView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNReactView.h; sourceTree = "<group>"; };
299 318
 		501E0216213E7EA3003365C5 /* RNNReactView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNReactView.m; sourceTree = "<group>"; };
319
+		5021574E214FE005000703F7 /* RNNTabBarPresenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTabBarPresenter.h; sourceTree = "<group>"; };
320
+		5021574F214FE005000703F7 /* RNNTabBarPresenter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTabBarPresenter.m; sourceTree = "<group>"; };
300 321
 		50220F46212ABDFD004C2B0A /* RNNReactRootView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNReactRootView.h; sourceTree = "<group>"; };
301 322
 		50220F47212ABDFD004C2B0A /* RNNReactRootView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNReactRootView.m; sourceTree = "<group>"; };
302 323
 		502CB43920CBCA140019B2FE /* RNNBridgeManagerDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNBridgeManagerDelegate.h; sourceTree = "<group>"; };
@@ -321,6 +342,16 @@
321 342
 		50570B252061473D006A1B5C /* RNNTitleOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTitleOptions.m; sourceTree = "<group>"; };
322 343
 		50570BE82063E09B006A1B5C /* RNNTitleViewHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTitleViewHelper.h; sourceTree = "<group>"; };
323 344
 		50570BE92063E09B006A1B5C /* RNNTitleViewHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTitleViewHelper.m; sourceTree = "<group>"; };
345
+		505EDD31214E4BE80071C7DE /* RNNNavigationControllerTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNNavigationControllerTest.m; sourceTree = "<group>"; };
346
+		505EDD33214E7A6A0071C7DE /* RNNLeafProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNLeafProtocol.h; sourceTree = "<group>"; };
347
+		505EDD3A214FA8000071C7DE /* RNNViewControllerPresenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNViewControllerPresenter.h; sourceTree = "<group>"; };
348
+		505EDD3B214FA8000071C7DE /* RNNViewControllerPresenter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNViewControllerPresenter.m; sourceTree = "<group>"; };
349
+		505EDD3F214FBCBE0071C7DE /* RNNNavigationControllerPresenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNNavigationControllerPresenter.h; sourceTree = "<group>"; };
350
+		505EDD40214FBCBE0071C7DE /* RNNNavigationControllerPresenter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNNavigationControllerPresenter.m; sourceTree = "<group>"; };
351
+		505EDD43214FBD3C0071C7DE /* RNNBasePresenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNBasePresenter.h; sourceTree = "<group>"; };
352
+		505EDD44214FBD3C0071C7DE /* RNNBasePresenter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNBasePresenter.m; sourceTree = "<group>"; };
353
+		505EDD47214FC4A60071C7DE /* RNNLayoutProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNLayoutProtocol.h; sourceTree = "<group>"; };
354
+		505EDD48214FDA800071C7DE /* RCTConvert+Modal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+Modal.h"; sourceTree = "<group>"; };
324 355
 		5064495B20DC62B90026709C /* RNNSideMenuSideOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSideMenuSideOptions.h; sourceTree = "<group>"; };
325 356
 		5064495C20DC62B90026709C /* RNNSideMenuSideOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNSideMenuSideOptions.m; sourceTree = "<group>"; };
326 357
 		50644A1E20E11A720026709C /* Constants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = "<group>"; };
@@ -341,7 +372,7 @@
341 372
 		507F43F31FF4FCFE00D9425B /* HMSegmentedControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HMSegmentedControl.m; sourceTree = "<group>"; };
342 373
 		507F43F61FF525B500D9425B /* RNNSegmentedControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSegmentedControl.h; sourceTree = "<group>"; };
343 374
 		507F43F71FF525B500D9425B /* RNNSegmentedControl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNSegmentedControl.m; sourceTree = "<group>"; };
344
-		507F441F1FFA8A8800D9425B /* RNNRootViewProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNRootViewProtocol.h; sourceTree = "<group>"; };
375
+		507F441F1FFA8A8800D9425B /* RNNParentProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNParentProtocol.h; sourceTree = "<group>"; };
345 376
 		50887C1320ECC5C200D06111 /* RNNButtonOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNButtonOptions.h; sourceTree = "<group>"; };
346 377
 		50887C1420ECC5C200D06111 /* RNNButtonOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNButtonOptions.m; sourceTree = "<group>"; };
347 378
 		50887CA720F26BFD00D06111 /* RNNOverlayWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNOverlayWindow.m; sourceTree = "<group>"; };
@@ -492,6 +523,7 @@
492 523
 				50644A1F20E11A720026709C /* Constants.m */,
493 524
 				50706E6B20CE7CA5003345C3 /* UIImage+tint.h */,
494 525
 				50706E6C20CE7CA5003345C3 /* UIImage+tint.m */,
526
+				505EDD48214FDA800071C7DE /* RCTConvert+Modal.h */,
495 527
 			);
496 528
 			name = Helpers;
497 529
 			sourceTree = "<group>";
@@ -620,6 +652,21 @@
620 652
 			name = Options;
621 653
 			sourceTree = "<group>";
622 654
 		};
655
+		505EDD39214FA7E80071C7DE /* Presenters */ = {
656
+			isa = PBXGroup;
657
+			children = (
658
+				505EDD43214FBD3C0071C7DE /* RNNBasePresenter.h */,
659
+				505EDD44214FBD3C0071C7DE /* RNNBasePresenter.m */,
660
+				505EDD3A214FA8000071C7DE /* RNNViewControllerPresenter.h */,
661
+				505EDD3B214FA8000071C7DE /* RNNViewControllerPresenter.m */,
662
+				505EDD3F214FBCBE0071C7DE /* RNNNavigationControllerPresenter.h */,
663
+				505EDD40214FBCBE0071C7DE /* RNNNavigationControllerPresenter.m */,
664
+				5021574E214FE005000703F7 /* RNNTabBarPresenter.h */,
665
+				5021574F214FE005000703F7 /* RNNTabBarPresenter.m */,
666
+			);
667
+			name = Presenters;
668
+			sourceTree = "<group>";
669
+		};
623 670
 		507F43F11FF4FCD800D9425B /* HMSegmentControl */ = {
624 671
 			isa = PBXGroup;
625 672
 			children = (
@@ -638,6 +685,8 @@
638 685
 				261F0E691E6F028A00989DE2 /* RNNNavigationStackManager.m */,
639 686
 				50D031322005149000386B3D /* RNNOverlayManager.h */,
640 687
 				50D031332005149000386B3D /* RNNOverlayManager.m */,
688
+				501CD321214A5CA900A6E225 /* RNNOptionsManager.h */,
689
+				501CD322214A5CA900A6E225 /* RNNOptionsManager.m */,
641 690
 			);
642 691
 			name = Managers;
643 692
 			sourceTree = "<group>";
@@ -649,7 +698,10 @@
649 698
 				E8AEDB461F58414D000F5A6A /* Animations */,
650 699
 				504AFE611FFE52EF0076E904 /* Options */,
651 700
 				50D031312005146C00386B3D /* Managers */,
701
+				505EDD39214FA7E80071C7DE /* Presenters */,
652 702
 				50570BE82063E09B006A1B5C /* RNNTitleViewHelper.h */,
703
+				501CD31D214A5B6900A6E225 /* RNNLayoutInfo.h */,
704
+				501CD31E214A5B6900A6E225 /* RNNLayoutInfo.m */,
653 705
 				50220F46212ABDFD004C2B0A /* RNNReactRootView.h */,
654 706
 				50220F47212ABDFD004C2B0A /* RNNReactRootView.m */,
655 707
 				501E0215213E7EA3003365C5 /* RNNReactView.h */,
@@ -682,7 +734,9 @@
682 734
 				507F43C41FF4F17C00D9425B /* RNNTopTabsViewController.m */,
683 735
 				507F43F61FF525B500D9425B /* RNNSegmentedControl.h */,
684 736
 				507F43F71FF525B500D9425B /* RNNSegmentedControl.m */,
685
-				507F441F1FFA8A8800D9425B /* RNNRootViewProtocol.h */,
737
+				507F441F1FFA8A8800D9425B /* RNNParentProtocol.h */,
738
+				505EDD33214E7A6A0071C7DE /* RNNLeafProtocol.h */,
739
+				505EDD47214FC4A60071C7DE /* RNNLayoutProtocol.h */,
686 740
 				E33AC1FF20B5BA0B0090DB8A /* RNNSplitViewController.m */,
687 741
 				E33AC20120B5BA550090DB8A /* RNNSplitViewController.h */,
688 742
 				50887CA820F26BFE00D06111 /* RNNOverlayWindow.h */,
@@ -700,6 +754,7 @@
700 754
 				7B49FEC91E95098500DEB3EA /* RNNCommandsHandlerTest.m */,
701 755
 				7B49FECA1E95098500DEB3EA /* RNNNavigationStackManagerTest.m */,
702 756
 				504753772109C13C00FFFBE6 /* RNNOverlayManagerTest.m */,
757
+				505EDD31214E4BE80071C7DE /* RNNNavigationControllerTest.m */,
703 758
 				7B49FEBF1E95090800DEB3EA /* Info.plist */,
704 759
 				E83BAD671F2734B500A9F3DD /* RNNNavigationOptionsTest.m */,
705 760
 				E83BAD781F27416B00A9F3DD /* RNNRootViewControllerTest.m */,
@@ -832,6 +887,7 @@
832 887
 			buildActionMask = 2147483647;
833 888
 			files = (
834 889
 				261F0E6A1E6F028A00989DE2 /* RNNNavigationStackManager.h in Headers */,
890
+				505EDD45214FBD3C0071C7DE /* RNNBasePresenter.h in Headers */,
835 891
 				50EB4ED72068EBE000D6ED34 /* RNNBackgroundOptions.h in Headers */,
836 892
 				504AFE761FFFF1E00076E904 /* RNNNavigationOptions.h in Headers */,
837 893
 				504AFE771FFFF1E20076E904 /* RNNTopBarOptions.h in Headers */,
@@ -844,6 +900,7 @@
844 900
 				263905BB1E4C6F440023D7D3 /* RCCDrawerHelper.h in Headers */,
845 901
 				263905CC1E4C6F440023D7D3 /* SidebarWunderlistAnimation.h in Headers */,
846 902
 				507F43F41FF4FCFE00D9425B /* HMSegmentedControl.h in Headers */,
903
+				501CD31F214A5B6900A6E225 /* RNNLayoutInfo.h in Headers */,
847 904
 				50A00C37200F84D6000F01A6 /* RNNOverlayOptions.h in Headers */,
848 905
 				7B4928081E70415400555040 /* RNNCommandsHandler.h in Headers */,
849 906
 				263905AE1E4C6F440023D7D3 /* MMDrawerBarButtonItem.h in Headers */,
@@ -855,15 +912,18 @@
855 912
 				50415CBA20553B8E00BB682E /* RNNScreenTransition.h in Headers */,
856 913
 				263905C21E4C6F440023D7D3 /* SidebarAnimation.h in Headers */,
857 914
 				E8E518361F83B94A000467AC /* RNNViewLocation.h in Headers */,
915
+				505EDD34214E7B7B0071C7DE /* RNNLeafProtocol.h in Headers */,
858 916
 				263905B51E4C6F440023D7D3 /* MMExampleDrawerVisualStateManager.h in Headers */,
859 917
 				50451D052042DAEB00695F00 /* RNNPushAnimation.h in Headers */,
860 918
 				507F43C51FF4F17C00D9425B /* RNNTopTabsViewController.h in Headers */,
861 919
 				263905C61E4C6F440023D7D3 /* SidebarFeedlyAnimation.h in Headers */,
920
+				505EDD3C214FA8000071C7DE /* RNNViewControllerPresenter.h in Headers */,
862 921
 				502CB46E20CD1DDA0019B2FE /* RNNBackButtonOptions.h in Headers */,
863 922
 				7B1126A31E2D2B6C00F9B03B /* RNNSplashScreen.h in Headers */,
864 923
 				261F0E641E6EC94900989DE2 /* RNNModalManager.h in Headers */,
865 924
 				263905C01E4C6F440023D7D3 /* SidebarAirbnbAnimation.h in Headers */,
866 925
 				50644A2020E11A720026709C /* Constants.h in Headers */,
926
+				501CD323214A5CA900A6E225 /* RNNOptionsManager.h in Headers */,
867 927
 				E8367B801F7A8A4700675C05 /* VICMAImageView.h in Headers */,
868 928
 				263905E61E4CAC950023D7D3 /* RNNSideMenuChildVC.h in Headers */,
869 929
 				263905C41E4C6F440023D7D3 /* SidebarFacebookAnimation.h in Headers */,
@@ -875,15 +935,17 @@
875 935
 				263905BE1E4C6F440023D7D3 /* RCCTheSideBarManagerViewController.h in Headers */,
876 936
 				263905CE1E4C6F440023D7D3 /* TheSidebarController.h in Headers */,
877 937
 				50D031342005149000386B3D /* RNNOverlayManager.h in Headers */,
938
+				505EDD41214FBCBE0071C7DE /* RNNNavigationControllerPresenter.h in Headers */,
878 939
 				7B1126A71E2D2B6C00F9B03B /* RNNEventEmitter.h in Headers */,
879 940
 				E8A430111F9CB87B00B61A20 /* RNNAnimatedView.h in Headers */,
880 941
 				50887C1520ECC5C200D06111 /* RNNButtonOptions.h in Headers */,
881 942
 				50C4A496206BDDBB00DB292E /* RNNSubtitleOptions.h in Headers */,
882 943
 				268692821E5054F800E2C612 /* RNNStore.h in Headers */,
883 944
 				E8AEDB3C1F55A1C2000F5A6A /* RNNElementView.h in Headers */,
945
+				50215750214FE005000703F7 /* RNNTabBarPresenter.h in Headers */,
884 946
 				E8E518321F83B3E0000467AC /* RNNUtils.h in Headers */,
885 947
 				50BE951320B5A787004F5DF5 /* RNNStatusBarOptions.h in Headers */,
886
-				507F44201FFA8A8800D9425B /* RNNRootViewProtocol.h in Headers */,
948
+				507F44201FFA8A8800D9425B /* RNNParentProtocol.h in Headers */,
887 949
 				50570BEA2063E09B006A1B5C /* RNNTitleViewHelper.h in Headers */,
888 950
 				263905CA1E4C6F440023D7D3 /* SidebarLuvocracyAnimation.h in Headers */,
889 951
 				4534E72520CB6724009F8185 /* RNNLargeTitleOptions.h in Headers */,
@@ -913,6 +975,7 @@
913 975
 				50451D0D2042F70900695F00 /* RNNTransition.h in Headers */,
914 976
 				507F43F81FF525B500D9425B /* RNNSegmentedControl.h in Headers */,
915 977
 				50175CD1207A2AA1004FE91B /* RNNComponentOptions.h in Headers */,
978
+				505EDD4A214FDA800071C7DE /* RCTConvert+Modal.h in Headers */,
916 979
 				50706E6D20CE7CA5003345C3 /* UIImage+tint.h in Headers */,
917 980
 			);
918 981
 			runOnlyForDeploymentPostprocessing = 0;
@@ -1012,6 +1075,7 @@
1012 1075
 				504753782109C13C00FFFBE6 /* RNNOverlayManagerTest.m in Sources */,
1013 1076
 				7B49FECE1E95098500DEB3EA /* RNNCommandsHandlerTest.m in Sources */,
1014 1077
 				E83BAD681F2734B500A9F3DD /* RNNNavigationOptionsTest.m in Sources */,
1078
+				505EDD32214E4BE80071C7DE /* RNNNavigationControllerTest.m in Sources */,
1015 1079
 				7B49FECF1E95098500DEB3EA /* RNNNavigationStackManagerTest.m in Sources */,
1016 1080
 				7B49FECB1E95098500DEB3EA /* RNNControllerFactoryTest.m in Sources */,
1017 1081
 				7B49FECD1E95098500DEB3EA /* RNNModalManagerTest.m in Sources */,
@@ -1032,7 +1096,9 @@
1032 1096
 				263905C51E4C6F440023D7D3 /* SidebarFacebookAnimation.m in Sources */,
1033 1097
 				50451D0E2042F70900695F00 /* RNNTransition.m in Sources */,
1034 1098
 				5048862E20BE976D000908DE /* RNNLayoutOptions.m in Sources */,
1099
+				501CD320214A5B6900A6E225 /* RNNLayoutInfo.m in Sources */,
1035 1100
 				7BEF0D191E437684003E96B0 /* RNNRootViewController.m in Sources */,
1101
+				501CD324214A5CA900A6E225 /* RNNOptionsManager.m in Sources */,
1036 1102
 				50415CBB20553B8E00BB682E /* RNNScreenTransition.m in Sources */,
1037 1103
 				263905C31E4C6F440023D7D3 /* SidebarAnimation.m in Sources */,
1038 1104
 				E8A5CD531F464F0400E89D0D /* RNNAnimator.m in Sources */,
@@ -1082,7 +1148,9 @@
1082 1148
 				5064495E20DC62B90026709C /* RNNSideMenuSideOptions.m in Sources */,
1083 1149
 				214545251F4DC125006E8DA1 /* RNNUIBarButtonItem.m in Sources */,
1084 1150
 				263905B81E4C6F440023D7D3 /* UIViewController+MMDrawerController.m in Sources */,
1151
+				505EDD3D214FA8000071C7DE /* RNNViewControllerPresenter.m in Sources */,
1085 1152
 				263905CD1E4C6F440023D7D3 /* SidebarWunderlistAnimation.m in Sources */,
1153
+				505EDD42214FBCBE0071C7DE /* RNNNavigationControllerPresenter.m in Sources */,
1086 1154
 				E33AC20820B5C4F90090DB8A /* RNNSplitViewOptions.m in Sources */,
1087 1155
 				E33AC20020B5BA0B0090DB8A /* RNNSplitViewController.m in Sources */,
1088 1156
 				263905CF1E4C6F440023D7D3 /* TheSidebarController.m in Sources */,
@@ -1108,6 +1176,8 @@
1108 1176
 				263905B61E4C6F440023D7D3 /* MMExampleDrawerVisualStateManager.m in Sources */,
1109 1177
 				E8E518331F83B3E0000467AC /* RNNUtils.m in Sources */,
1110 1178
 				50451D062042DAEB00695F00 /* RNNPushAnimation.m in Sources */,
1179
+				50215751214FE005000703F7 /* RNNTabBarPresenter.m in Sources */,
1180
+				505EDD46214FBD3C0071C7DE /* RNNBasePresenter.m in Sources */,
1111 1181
 				50F5DFC61F407AA0001A00BC /* RNNNavigationController.m in Sources */,
1112 1182
 				21B85E5D1F44480200B314B5 /* RNNNavigationButtons.m in Sources */,
1113 1183
 				E8E518371F83B94A000467AC /* RNNViewLocation.m in Sources */,

+ 31
- 8
lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m Просмотреть файл

@@ -5,8 +5,9 @@
5 5
 #import "RNNTestRootViewCreator.h"
6 6
 #import "RNNRootViewController.h"
7 7
 #import "RNNNavigationStackManager.h"
8
+#import "RNNNavigationController.h"
8 9
 
9
-@interface MockUINavigationController : UINavigationController
10
+@interface MockUINavigationController : RNNNavigationController
10 11
 @property (nonatomic, strong) NSArray* willReturnVCs;
11 12
 @end
12 13
 
@@ -95,13 +96,14 @@
95 96
 -(void)testDynamicStylesMergeWithStaticStyles {
96 97
 	RNNNavigationOptions* initialOptions = [[RNNNavigationOptions alloc] initWithDict:@{}];
97 98
 	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];
104
-	UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:vc];
99
+	RNNLayoutInfo* layoutInfo = [RNNLayoutInfo new];
100
+	
101
+	RNNViewControllerPresenter* presenter = [[RNNViewControllerPresenter alloc] initWithOptions:initialOptions];
102
+	RNNRootViewController* vc = [[RNNRootViewController alloc] initWithLayoutInfo:layoutInfo rootViewCreator:[[RNNTestRootViewCreator alloc] init] eventEmitter:nil isExternalComponent:NO presenter:presenter];
103
+	
104
+	RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:vc];
105
+	nav.presenter = [[RNNNavigationControllerPresenter alloc] initWithOptions:initialOptions];
106
+	
105 107
 	[vc viewWillAppear:false];
106 108
 	XCTAssertTrue([vc.navigationItem.title isEqual:@"the title"]);
107 109
 
@@ -117,6 +119,27 @@
117 119
 	}];
118 120
 }
119 121
 
122
+- (void)testMergeOptions_shouldOverrideOptions {
123
+	RNNNavigationOptions* initialOptions = [[RNNNavigationOptions alloc] initWithDict:@{}];
124
+	initialOptions.topBar.title.text = @"the title";
125
+	
126
+	RNNViewControllerPresenter* presenter = [[RNNViewControllerPresenter alloc] initWithOptions:initialOptions];
127
+	RNNRootViewController* vc = [[RNNRootViewController alloc] initWithLayoutInfo:nil rootViewCreator:[[RNNTestRootViewCreator alloc] init] eventEmitter:nil isExternalComponent:NO presenter:presenter];
128
+	
129
+	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:vc];
130
+	[vc viewWillAppear:false];
131
+	XCTAssertTrue([vc.navigationItem.title isEqual:@"the title"]);
132
+	
133
+	[self.store setReadyToReceiveCommands:true];
134
+	[self.store setComponent:vc componentId:@"componentId"];
135
+	
136
+	NSDictionary* dictFromJs = @{@"topBar": @{@"title" : @{@"text" : @"new title"}}};
137
+	
138
+	[self.uut mergeOptions:@"componentId" options:dictFromJs completion:^{
139
+		XCTAssertTrue([vc.navigationItem.title isEqual:@"new title"]);
140
+	}];
141
+}
142
+
120 143
 - (void)testPop_removeTopVCFromStore {
121 144
 	[self.store setReadyToReceiveCommands:true];
122 145
 	XCTestExpectation *expectation = [self expectationWithDescription:@"Testing Async Method"];

+ 49
- 7
lib/ios/ReactNativeNavigationTests/RNNControllerFactoryTest.m Просмотреть файл

@@ -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

+ 1
- 0
lib/ios/ReactNativeNavigationTests/RNNModalManagerTest.m Просмотреть файл

@@ -1,5 +1,6 @@
1 1
 #import <XCTest/XCTest.h>
2 2
 #import "RNNModalManager.h"
3
+#import "RNNRootViewController.h"
3 4
 
4 5
 @interface MockViewController : UIViewController
5 6
 

+ 43
- 0
lib/ios/ReactNativeNavigationTests/RNNNavigationControllerTest.m Просмотреть файл

@@ -0,0 +1,43 @@
1
+#import <XCTest/XCTest.h>
2
+#import "RNNNavigationController.h"
3
+#import "RNNRootViewController.h"
4
+
5
+@interface RNNNavigationControllerTest : XCTestCase
6
+
7
+@property (nonatomic, strong) RNNNavigationController *uut;
8
+
9
+@end
10
+
11
+@implementation RNNNavigationControllerTest {
12
+	RNNRootViewController* _vc1;
13
+	RNNRootViewController* _vc2;
14
+	UIViewController* _vc3;
15
+	RNNViewControllerPresenter* _presenter;
16
+}
17
+
18
+- (void)setUp {
19
+    [super setUp];
20
+	
21
+	_presenter = [[RNNViewControllerPresenter alloc] initWithOptions:[[RNNNavigationOptions alloc] initWithDict:@{}]];
22
+	self.uut = [[RNNNavigationController alloc] init];
23
+	_vc1 = [[RNNRootViewController alloc] initWithLayoutInfo:nil rootViewCreator:nil eventEmitter:nil isExternalComponent:NO presenter:_presenter];
24
+	_vc2 = [[RNNRootViewController alloc] initWithLayoutInfo:nil rootViewCreator:nil eventEmitter:nil isExternalComponent:NO presenter:_presenter];
25
+	_vc3 = [UIViewController new];
26
+}
27
+
28
+- (void)testChildViewControllerForStatusBarStyle_shouldReturnTopViewController {
29
+	XCTAssertTrue(self.uut.childViewControllerForStatusBarStyle == self.uut.topViewController);
30
+}
31
+
32
+- (void)testGetLeafViewController_shouldReturnTopViewController {
33
+	XCTAssertTrue(self.uut.getLeafViewController == self.uut.topViewController);
34
+}
35
+
36
+- (void)testPreferredStatusBarStyle_shouldReturnLeafPreferredStatusBarStyle {
37
+	[self.uut setViewControllers:@[_vc1]];
38
+	self.uut.getLeafViewController.presenter.options.statusBar.style = @"light";
39
+	XCTAssertTrue(self.uut.preferredStatusBarStyle == self.uut.getLeafViewController.preferredStatusBarStyle);
40
+}
41
+
42
+
43
+@end

+ 4
- 3
lib/ios/ReactNativeNavigationTests/RNNNavigationStackManagerTest.m Просмотреть файл

@@ -1,11 +1,12 @@
1 1
 #import <XCTest/XCTest.h>
2 2
 #import "RNNStore.h"
3 3
 #import "RNNNavigationStackManager.h"
4
-
4
+#import "RNNRootViewController.h"
5
+#import "RNNNavigationController.h"
5 6
 
6 7
 @interface RNNNavigationStackManagerTest : XCTestCase
7 8
 
8
-@property (nonatomic, strong) UINavigationController *nvc;
9
+@property (nonatomic, strong) RNNNavigationController *nvc;
9 10
 @property (nonatomic, strong) UIViewController *vc1;
10 11
 @property (nonatomic, strong) UIViewController *vc2;
11 12
 @property (nonatomic, strong) UIViewController *vc3;
@@ -18,7 +19,7 @@
18 19
 - (void)setUp {
19 20
     [super setUp];
20 21
 	
21
-	self.nvc = [[UINavigationController alloc] init];
22
+	self.nvc = [[RNNNavigationController alloc] init];
22 23
 	self.vc1 = [RNNRootViewController new];
23 24
 	self.vc2 = [RNNRootViewController new];
24 25
 	self.vc3 = [RNNRootViewController new];

+ 78
- 56
lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m Просмотреть файл

@@ -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,13 +43,19 @@
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
+	
51
+	RNNViewControllerPresenter* presenter = [[RNNViewControllerPresenter alloc] initWithOptions:self.options];
52
+	self.uut = [[RNNRootViewController alloc] initWithLayoutInfo:layoutInfo rootViewCreator:self.creator eventEmitter:self.emitter isExternalComponent:NO presenter:presenter];
46 53
 }
47 54
 
48 55
 -(void)testTopBarBackgroundColor_validColor{
49 56
 	NSNumber* inputColor = @(0xFFFF0000);
50 57
 	self.options.topBar.background.color = inputColor;
51
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
58
+	__unused RNNNavigationController* nav = [self createNavigationController];
52 59
 	[self.uut viewWillAppear:false];
53 60
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
54 61
 
@@ -63,7 +70,7 @@
63 70
 }
64 71
 
65 72
 - (void)testStatusBarHidden_default {
66
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
73
+	__unused RNNNavigationController* nav = [self createNavigationController];
67 74
 	[self.uut viewWillAppear:false];
68 75
 
69 76
 	XCTAssertFalse([self.uut prefersStatusBarHidden]);
@@ -71,7 +78,7 @@
71 78
 
72 79
 - (void)testStatusBarVisible_false {
73 80
 	self.options.statusBar.visible = @(0);
74
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
81
+	__unused RNNNavigationController* nav = [self createNavigationController];
75 82
 	[self.uut viewWillAppear:false];
76 83
 
77 84
 	XCTAssertTrue([self.uut prefersStatusBarHidden]);
@@ -79,7 +86,7 @@
79 86
 
80 87
 - (void)testStatusBarVisible_true {
81 88
 	self.options.statusBar.visible = @(1);
82
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
89
+	__unused RNNNavigationController* nav = [self createNavigationController];
83 90
 	[self.uut viewWillAppear:false];
84 91
 	
85 92
 	XCTAssertFalse([self.uut prefersStatusBarHidden]);
@@ -88,7 +95,7 @@
88 95
 - (void)testStatusBarHideWithTopBar_false {
89 96
 	self.options.statusBar.hideWithTopBar = @(0);
90 97
 	self.options.topBar.visible = @(0);
91
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
98
+	__unused RNNNavigationController* nav = [self createNavigationController];
92 99
 	[self.uut viewWillAppear:false];
93 100
 
94 101
 	XCTAssertFalse([self.uut prefersStatusBarHidden]);
@@ -97,7 +104,7 @@
97 104
 - (void)testStatusBarHideWithTopBar_true {
98 105
 	self.options.statusBar.hideWithTopBar = @(1);
99 106
 	self.options.topBar.visible = @(0);
100
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
107
+	__unused RNNNavigationController* nav = [self createNavigationController];
101 108
 	[self.uut viewWillAppear:false];
102 109
 
103 110
 	XCTAssertTrue([self.uut prefersStatusBarHidden]);
@@ -106,14 +113,14 @@
106 113
 -(void)testTitle_string{
107 114
 	NSString* title =@"some title";
108 115
 	self.options.topBar.title.text = title;
109
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
116
+	__unused RNNNavigationController* nav = [self createNavigationController];
110 117
 
111 118
 	[self.uut viewWillAppear:false];
112 119
 	XCTAssertTrue([self.uut.navigationItem.title isEqual:title]);
113 120
 }
114 121
 
115 122
 -(void)testTitle_default{
116
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
123
+	__unused RNNNavigationController* nav = [self createNavigationController];
117 124
 
118 125
 	[self.uut viewWillAppear:false];
119 126
 	XCTAssertNil(self.uut.navigationItem.title);
@@ -122,7 +129,7 @@
122 129
 -(void)testTopBarTextColor_validColor{
123 130
 	NSNumber* inputColor = @(0xFFFF0000);
124 131
 	self.options.topBar.title.color = inputColor;
125
-	__unused UINavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
132
+	__unused RNNNavigationController* nav = [self createNavigationController];
126 133
 	[self.uut viewWillAppear:false];
127 134
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
128 135
 	XCTAssertTrue([self.uut.navigationController.navigationBar.titleTextAttributes[@"NSColor"] isEqual:expectedColor]);
@@ -139,7 +146,7 @@
139 146
 -(void)testPopGestureEnabled_true{
140 147
 	NSNumber* popGestureEnabled = @(1);
141 148
 	self.options.popGesture = popGestureEnabled;
142
-	__unused UINavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
149
+	__unused RNNNavigationController* nav = [self createNavigationController];
143 150
 	[self.uut viewWillAppear:false];
144 151
 	XCTAssertTrue(self.uut.navigationController.interactivePopGestureRecognizer.enabled);
145 152
 }
@@ -147,14 +154,15 @@
147 154
 -(void)testPopGestureEnabled_false{
148 155
 	NSNumber* popGestureEnabled = @(0);
149 156
 	self.options.popGesture = popGestureEnabled;
150
-	__unused UINavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
157
+	__unused RNNNavigationController* nav = [self createNavigationController];
158
+	
151 159
 	[self.uut viewWillAppear:false];
152 160
 	XCTAssertFalse(self.uut.navigationController.interactivePopGestureRecognizer.enabled);
153 161
 }
154 162
 
155 163
 -(void)testTopBarTextFontFamily_validFont{
156 164
 	NSString* inputFont = @"HelveticaNeue";
157
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
165
+	__unused RNNNavigationController* nav = [self createNavigationController];
158 166
 	self.options.topBar.title.fontFamily = inputFont;
159 167
 	[self.uut viewWillAppear:false];
160 168
 	UIFont* expectedFont = [UIFont fontWithName:inputFont size:17];
@@ -163,7 +171,7 @@
163 171
 
164 172
 -(void)testTopBarHideOnScroll_true {
165 173
 	NSNumber* hideOnScrollInput = @(1);
166
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
174
+	__unused RNNNavigationController* nav = [self createNavigationController];
167 175
 	self.options.topBar.hideOnScroll = hideOnScrollInput;
168 176
 	[self.uut viewWillAppear:false];
169 177
 	XCTAssertTrue(self.uut.navigationController.hidesBarsOnSwipe);
@@ -172,7 +180,7 @@
172 180
 -(void)testTopBarTranslucent {
173 181
 	NSNumber* topBarTranslucentInput = @(0);
174 182
 	self.options.topBar.translucent = topBarTranslucentInput;
175
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
183
+	__unused RNNNavigationController* nav = [self createNavigationController];
176 184
 	[self.uut viewWillAppear:false];
177 185
 	XCTAssertFalse(self.uut.navigationController.navigationBar.translucent);
178 186
 }
@@ -194,7 +202,7 @@
194 202
 -(void)testTopBarTransparent_BOOL_True {
195 203
 	NSNumber* topBarTransparentInput = @(1);
196 204
 	self.options.topBar.transparent = topBarTransparentInput;
197
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
205
+	__unused RNNNavigationController* nav = [self createNavigationController];
198 206
 	[self.uut viewWillAppear:false];
199 207
 	UIView* transparentView = [self.uut.navigationController.navigationBar viewWithTag:TOP_BAR_TRANSPARENT_TAG];
200 208
 	XCTAssertTrue(transparentView);
@@ -203,7 +211,7 @@
203 211
 
204 212
 -(void)testTopBarTransparent_BOOL_false {
205 213
 	NSNumber* topBarTransparentInput = @(0);
206
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
214
+	__unused RNNNavigationController* nav = [self createNavigationController];
207 215
 	self.options.topBar.transparent = topBarTransparentInput;
208 216
 	[self.uut viewWillAppear:false];
209 217
 	UIView* transparentView = [self.uut.navigationController.navigationBar viewWithTag:TOP_BAR_TRANSPARENT_TAG];
@@ -217,21 +225,21 @@
217 225
 
218 226
 
219 227
 -(void)testTopBarLargeTitle_default {
220
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
228
+	__unused RNNNavigationController* nav = [self createNavigationController];
221 229
 	[self.uut viewWillAppear:false];
222 230
 	
223 231
 	XCTAssertEqual(self.uut.navigationItem.largeTitleDisplayMode,  UINavigationItemLargeTitleDisplayModeNever);
224 232
 }
225 233
 -(void)testTopBarLargeTitle_true {
226 234
 	self.options.topBar.largeTitle.visible = @(1);
227
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
235
+	__unused RNNNavigationController* nav = [self createNavigationController];
228 236
 	[self.uut viewWillAppear:false];
229 237
 	
230 238
 	XCTAssertEqual(self.uut.navigationItem.largeTitleDisplayMode, UINavigationItemLargeTitleDisplayModeAlways);
231 239
 }
232 240
 -(void)testTopBarLargeTitle_false {
233 241
 	self.options.topBar.largeTitle.visible  = @(0);
234
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
242
+	__unused RNNNavigationController* nav = [self createNavigationController];
235 243
 	[self.uut viewWillAppear:false];
236 244
 	
237 245
 	XCTAssertEqual(self.uut.navigationItem.largeTitleDisplayMode, UINavigationItemLargeTitleDisplayModeNever);
@@ -241,7 +249,7 @@
241 249
 -(void)testTopBarLargeTitleFontSize_withoutTextFontFamily_withoutTextColor {
242 250
 	NSNumber* topBarTextFontSizeInput = @(15);
243 251
 	self.options.topBar.largeTitle.fontSize = topBarTextFontSizeInput;
244
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
252
+	__unused RNNNavigationController* nav = [self createNavigationController];
245 253
 	[self.uut viewWillAppear:false];
246 254
 	UIFont* expectedFont = [UIFont systemFontOfSize:15];
247 255
 	XCTAssertTrue([self.uut.navigationController.navigationBar.largeTitleTextAttributes[@"NSFont"] isEqual:expectedFont]);
@@ -252,7 +260,7 @@
252 260
 	NSNumber* inputColor = @(0xFFFF0000);
253 261
 	self.options.topBar.largeTitle.fontSize = topBarTextFontSizeInput;
254 262
 	self.options.topBar.largeTitle.color = inputColor;
255
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
263
+	__unused RNNNavigationController* nav = [self createNavigationController];
256 264
 	[self.uut viewWillAppear:false];
257 265
 	UIFont* expectedFont = [UIFont systemFontOfSize:15];
258 266
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
@@ -267,7 +275,7 @@
267 275
 	self.options.topBar.largeTitle.fontSize = topBarTextFontSizeInput;
268 276
 	self.options.topBar.largeTitle.color = inputColor;
269 277
 	self.options.topBar.largeTitle.fontFamily = inputFont;
270
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
278
+	__unused RNNNavigationController* nav = [self createNavigationController];
271 279
 	[self.uut viewWillAppear:false];
272 280
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
273 281
 	UIFont* expectedFont = [UIFont fontWithName:inputFont size:15];
@@ -280,7 +288,7 @@
280 288
 	NSString* inputFont = @"HelveticaNeue";
281 289
 	self.options.topBar.largeTitle.fontSize = topBarTextFontSizeInput;
282 290
 	self.options.topBar.largeTitle.fontFamily = inputFont;
283
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
291
+	__unused RNNNavigationController* nav = [self createNavigationController];
284 292
 	[self.uut viewWillAppear:false];
285 293
 	UIFont* expectedFont = [UIFont fontWithName:inputFont size:15];
286 294
 	XCTAssertTrue([self.uut.navigationController.navigationBar.largeTitleTextAttributes[@"NSFont"] isEqual:expectedFont]);
@@ -290,7 +298,7 @@
290 298
 -(void)testTopBarTextFontSize_withoutTextFontFamily_withoutTextColor {
291 299
 	NSNumber* topBarTextFontSizeInput = @(15);
292 300
 	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
293
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
301
+	__unused RNNNavigationController* nav = [self createNavigationController];
294 302
 	[self.uut viewWillAppear:false];
295 303
 	UIFont* expectedFont = [UIFont systemFontOfSize:15];
296 304
 	XCTAssertTrue([self.uut.navigationController.navigationBar.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
@@ -301,7 +309,7 @@
301 309
 	NSNumber* inputColor = @(0xFFFF0000);
302 310
 	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
303 311
 	self.options.topBar.title.color = inputColor;
304
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
312
+	__unused RNNNavigationController* nav = [self createNavigationController];
305 313
 	[self.uut viewWillAppear:false];
306 314
 	UIFont* expectedFont = [UIFont systemFontOfSize:15];
307 315
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
@@ -316,7 +324,7 @@
316 324
 	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
317 325
 	self.options.topBar.title.color = inputColor;
318 326
 	self.options.topBar.title.fontFamily = inputFont;
319
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
327
+	__unused RNNNavigationController* nav = [self createNavigationController];
320 328
 	[self.uut viewWillAppear:false];
321 329
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
322 330
 	UIFont* expectedFont = [UIFont fontWithName:inputFont size:15];
@@ -329,7 +337,7 @@
329 337
 	NSString* inputFont = @"HelveticaNeue";
330 338
 	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
331 339
 	self.options.topBar.title.fontFamily = inputFont;
332
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
340
+	__unused RNNNavigationController* nav = [self createNavigationController];
333 341
 	[self.uut viewWillAppear:false];
334 342
 	UIFont* expectedFont = [UIFont fontWithName:inputFont size:15];
335 343
 	XCTAssertTrue([self.uut.navigationController.navigationBar.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
@@ -338,7 +346,7 @@
338 346
 // TODO: Currently not passing
339 347
 -(void)testTopBarTextFontFamily_invalidFont{
340 348
 	NSString* inputFont = @"HelveticaNeueeeee";
341
-	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
349
+	__unused RNNNavigationController* nav = [self createNavigationController];
342 350
 	self.options.topBar.title.fontFamily = inputFont;
343 351
 	//	XCTAssertThrows([self.uut viewWillAppear:false]);
344 352
 }
@@ -346,7 +354,7 @@
346 354
 -(void)testOrientation_portrait {
347 355
 	NSArray* supportedOrientations = @[@"portrait"];
348 356
 	self.options.layout.orientation = supportedOrientations;
349
-	__unused UINavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
357
+	__unused RNNNavigationController* nav = [self createNavigationController];
350 358
 	[self.uut viewWillAppear:false];
351 359
 	UIInterfaceOrientationMask expectedOrientation = UIInterfaceOrientationMaskPortrait;
352 360
 	XCTAssertTrue(self.uut.navigationController.supportedInterfaceOrientations == expectedOrientation);
@@ -355,7 +363,7 @@
355 363
 -(void)testOrientation_portraitString {
356 364
 	NSString* supportedOrientation = @"portrait";
357 365
 	self.options.layout.orientation = supportedOrientation;
358
-	__unused UINavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
366
+	__unused RNNNavigationController* nav = [self createNavigationController];
359 367
 	[self.uut viewWillAppear:false];
360 368
 	UIInterfaceOrientationMask expectedOrientation = (UIInterfaceOrientationMaskPortrait);
361 369
 	XCTAssertTrue(self.uut.navigationController.supportedInterfaceOrientations == expectedOrientation);
@@ -364,7 +372,7 @@
364 372
 -(void)testOrientation_portraitAndLandscape {
365 373
 	NSArray* supportedOrientations = @[@"portrait", @"landscape"];
366 374
 	self.options.layout.orientation = supportedOrientations;
367
-	__unused UINavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
375
+	__unused RNNNavigationController* nav = [self createNavigationController];
368 376
 	[self.uut viewWillAppear:false];
369 377
 	UIInterfaceOrientationMask expectedOrientation = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape);
370 378
 	XCTAssertTrue(self.uut.navigationController.supportedInterfaceOrientations == expectedOrientation);
@@ -373,7 +381,7 @@
373 381
 -(void)testOrientation_all {
374 382
 	NSArray* supportedOrientations = @[@"all"];
375 383
 	self.options.layout.orientation = supportedOrientations;
376
-	__unused UINavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
384
+	__unused RNNNavigationController* nav = [self createNavigationController];
377 385
 	[self.uut viewWillAppear:false];
378 386
 	UIInterfaceOrientationMask expectedOrientation = UIInterfaceOrientationMaskAll;
379 387
 	XCTAssertTrue(self.uut.navigationController.supportedInterfaceOrientations == expectedOrientation);
@@ -382,7 +390,7 @@
382 390
 -(void)testOrientation_default {
383 391
 	NSString* supportedOrientations = @"default";
384 392
 	self.options.layout.orientation = supportedOrientations;
385
-	__unused UINavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
393
+	__unused RNNNavigationController* nav = [self createNavigationController];
386 394
 	[self.uut viewWillAppear:false];
387 395
 	UIInterfaceOrientationMask expectedOrientation = [[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:[[UIApplication sharedApplication] keyWindow]];
388 396
 	XCTAssertTrue(self.uut.navigationController.supportedInterfaceOrientations == expectedOrientation);
@@ -433,7 +441,7 @@
433 441
 
434 442
 -(void)testRightButtonsWithTitle_withoutStyle {
435 443
 	self.options.topBar.rightButtons = @[@{@"id": @"testId", @"text": @"test"}];
436
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
444
+	__unused RNNNavigationController* nav = [self createNavigationController];
437 445
 	[self.uut viewWillAppear:false];
438 446
 
439 447
 	RNNUIBarButtonItem* button = (RNNUIBarButtonItem*)[nav.topViewController.navigationItem.rightBarButtonItems objectAtIndex:0];
@@ -448,7 +456,7 @@
448 456
 	NSNumber* inputColor = @(0xFFFF0000);
449 457
 
450 458
 	self.options.topBar.rightButtons = @[@{@"id": @"testId", @"text": @"test", @"enabled": @false, @"buttonColor": inputColor, @"buttonFontSize": @22, @"buttonFontWeight": @"800"}];
451
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
459
+	__unused RNNNavigationController* nav = [self createNavigationController];
452 460
 	[self.uut viewWillAppear:false];
453 461
 
454 462
 	RNNUIBarButtonItem* button = (RNNUIBarButtonItem*)[nav.topViewController.navigationItem.rightBarButtonItems objectAtIndex:0];
@@ -464,7 +472,7 @@
464 472
 
465 473
 -(void)testLeftButtonsWithTitle_withoutStyle {
466 474
 	self.options.topBar.leftButtons = @[@{@"id": @"testId", @"text": @"test"}];
467
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
475
+	__unused RNNNavigationController* nav = [self createNavigationController];
468 476
 	[self.uut viewWillAppear:false];
469 477
 
470 478
 	RNNUIBarButtonItem* button = (RNNUIBarButtonItem*)[nav.topViewController.navigationItem.leftBarButtonItems objectAtIndex:0];
@@ -479,7 +487,7 @@
479 487
 	NSNumber* inputColor = @(0xFFFF0000);
480 488
 
481 489
 	self.options.topBar.leftButtons = @[@{@"id": @"testId", @"text": @"test", @"enabled": @false, @"buttonColor": inputColor, @"buttonFontSize": @22, @"buttonFontWeight": @"800"}];
482
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
490
+	__unused RNNNavigationController* nav = [self createNavigationController];
483 491
 	[self.uut viewWillAppear:false];
484 492
 
485 493
 	RNNUIBarButtonItem* button = (RNNUIBarButtonItem*)[nav.topViewController.navigationItem.leftBarButtonItems objectAtIndex:0];
@@ -495,7 +503,7 @@
495 503
 -(void)testTopBarNoBorderOn {
496 504
 	NSNumber* topBarNoBorderInput = @(1);
497 505
 	self.options.topBar.noBorder = topBarNoBorderInput;
498
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
506
+	__unused RNNNavigationController* nav = [self createNavigationController];
499 507
 	[self.uut viewWillAppear:false];
500 508
 	XCTAssertNotNil(self.uut.navigationController.navigationBar.shadowImage);
501 509
 }
@@ -503,7 +511,7 @@
503 511
 -(void)testTopBarNoBorderOff {
504 512
 	NSNumber* topBarNoBorderInput = @(0);
505 513
 	self.options.topBar.noBorder = topBarNoBorderInput;
506
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
514
+	__unused RNNNavigationController* nav = [self createNavigationController];
507 515
 	[self.uut viewWillAppear:false];
508 516
 	XCTAssertNil(self.uut.navigationController.navigationBar.shadowImage);
509 517
 }
@@ -511,7 +519,7 @@
511 519
 -(void)testStatusBarBlurOn {
512 520
 	NSNumber* statusBarBlurInput = @(1);
513 521
 	self.options.statusBar.blur = statusBarBlurInput;
514
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
522
+	__unused RNNNavigationController* nav = [self createNavigationController];
515 523
 	[self.uut viewWillAppear:false];
516 524
 	XCTAssertNotNil([self.uut.view viewWithTag:BLUR_STATUS_TAG]);
517 525
 }
@@ -519,13 +527,13 @@
519 527
 -(void)testStatusBarBlurOff {
520 528
 	NSNumber* statusBarBlurInput = @(0);
521 529
 	self.options.statusBar.blur = statusBarBlurInput;
522
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
530
+	__unused RNNNavigationController* nav = [self createNavigationController];
523 531
 	[self.uut viewWillAppear:false];
524 532
 	XCTAssertNil([self.uut.view viewWithTag:BLUR_STATUS_TAG]);
525 533
 }
526 534
 
527 535
 - (void)testTabBarHidden_default {
528
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
536
+	__unused RNNNavigationController* nav = [self createNavigationController];
529 537
 	[self.uut viewWillAppear:false];
530 538
 
531 539
 	XCTAssertFalse([self.uut hidesBottomBarWhenPushed]);
@@ -534,7 +542,7 @@
534 542
 
535 543
 - (void)testTabBarHidden_true {
536 544
 	self.options.bottomTabs.visible = @(0);
537
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
545
+	__unused RNNNavigationController* nav = [self createNavigationController];
538 546
 	[self.uut viewWillAppear:false];
539 547
 
540 548
 	XCTAssertTrue([self.uut hidesBottomBarWhenPushed]);
@@ -542,14 +550,14 @@
542 550
 
543 551
 - (void)testTabBarHidden_false {
544 552
 	self.options.bottomTabs.visible = @(1);
545
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
553
+	__unused RNNNavigationController* nav = [self createNavigationController];
546 554
 	[self.uut viewWillAppear:false];
547 555
 
548 556
 	XCTAssertFalse([self.uut hidesBottomBarWhenPushed]);
549 557
 }
550 558
 
551 559
 -(void)testTopBarBlur_default {
552
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
560
+	__unused RNNNavigationController* nav = [self createNavigationController];
553 561
 	[self.uut viewWillAppear:false];
554 562
 	XCTAssertNil([self.uut.navigationController.navigationBar viewWithTag:BLUR_TOPBAR_TAG]);
555 563
 }
@@ -557,7 +565,7 @@
557 565
 -(void)testTopBarBlur_false {
558 566
 	NSNumber* topBarBlurInput = @(0);
559 567
 	self.options.topBar.blur = topBarBlurInput;
560
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
568
+	__unused RNNNavigationController* nav = [self createNavigationController];
561 569
 	[self.uut viewWillAppear:false];
562 570
 	XCTAssertNil([self.uut.navigationController.navigationBar viewWithTag:BLUR_TOPBAR_TAG]);
563 571
 }
@@ -565,7 +573,7 @@
565 573
 -(void)testTopBarBlur_true {
566 574
 	NSNumber* topBarBlurInput = @(1);
567 575
 	self.options.topBar.blur = topBarBlurInput;
568
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
576
+	__unused RNNNavigationController* nav = [self createNavigationController];
569 577
 	[self.uut viewWillAppear:false];
570 578
 	XCTAssertNotNil([self.uut.navigationController.navigationBar viewWithTag:BLUR_TOPBAR_TAG]);
571 579
 }
@@ -573,7 +581,7 @@
573 581
 -(void)testBackgroundImage {
574 582
 	UIImage* backgroundImage = [[UIImage alloc] init];
575 583
 	self.options.backgroundImage = backgroundImage;
576
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
584
+	__unused RNNNavigationController* nav = [self createNavigationController];
577 585
 	[self.uut viewWillAppear:false];
578 586
 
579 587
 	XCTAssertTrue([[(UIImageView*)self.uut.view.subviews[0] image] isEqual:backgroundImage]);
@@ -582,14 +590,14 @@
582 590
 -(void)testRootBackgroundImage {
583 591
 	UIImage* rootBackgroundImage = [[UIImage alloc] init];
584 592
 	self.options.rootBackgroundImage = rootBackgroundImage;
585
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
593
+	__unused RNNNavigationController* nav = [self createNavigationController];
586 594
 	[self.uut viewWillAppear:false];
587 595
 	XCTAssertTrue([[(UIImageView*)self.uut.navigationController.view.subviews[0] image] isEqual:rootBackgroundImage]);
588 596
 }
589 597
 
590 598
 -(void)testTopBarDrawUnder_true {
591 599
 	self.options.topBar.drawBehind = @(1);
592
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
600
+	__unused RNNNavigationController* nav = [self createNavigationController];
593 601
 	[self.uut viewWillAppear:false];
594 602
 
595 603
 	XCTAssertTrue(self.uut.edgesForExtendedLayout & UIRectEdgeTop);
@@ -597,7 +605,7 @@
597 605
 
598 606
 -(void)testTopBarDrawUnder_false {
599 607
 	self.options.topBar.drawBehind = @(0);
600
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
608
+	__unused RNNNavigationController* nav = [self createNavigationController];
601 609
 	[self.uut viewWillAppear:false];
602 610
 
603 611
 	XCTAssertFalse(self.uut.edgesForExtendedLayout & UIRectEdgeTop);
@@ -605,7 +613,7 @@
605 613
 
606 614
 -(void)testBottomTabsDrawUnder_true {
607 615
 	self.options.bottomTabs.drawBehind = @(1);
608
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
616
+	__unused RNNNavigationController* nav = [self createNavigationController];
609 617
 	[self.uut viewWillAppear:false];
610 618
 
611 619
 	XCTAssertTrue(self.uut.edgesForExtendedLayout & UIRectEdgeBottom);
@@ -613,7 +621,7 @@
613 621
 
614 622
 -(void)testBottomTabsDrawUnder_false {
615 623
 	self.options.bottomTabs.drawBehind = @(0);
616
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
624
+	__unused RNNNavigationController* nav = [self createNavigationController];
617 625
 	[self.uut viewWillAppear:false];
618 626
 
619 627
 	XCTAssertFalse(self.uut.edgesForExtendedLayout & UIRectEdgeBottom);
@@ -714,17 +722,31 @@
714 722
 
715 723
 - (void)testTopBarBackgroundClipToBounds_true {
716 724
 	self.options.topBar.background.clipToBounds = @(1);
717
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
725
+	__unused RNNNavigationController* nav = [self createNavigationController];
718 726
 	[self.uut viewWillAppear:false];
719 727
 
720 728
 	XCTAssertTrue(self.uut.navigationController.navigationBar.clipsToBounds);
721 729
 }
722 730
 
723 731
 - (void)testTopBarBackgroundClipToBounds_false {
724
-	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
732
+	__unused RNNNavigationController* nav = [self createNavigationController];
725 733
 	[self.uut viewWillAppear:false];
726 734
 
727 735
 	XCTAssertFalse(self.uut.navigationController.navigationBar.clipsToBounds);
728 736
 }
729 737
 
738
+- (void)testWillMoveToParent_shouldPassOptionsToParent {
739
+	__unused RNNNavigationController* nav = [self createNavigationController];
740
+	self.uut.presenter.options.topBar.visible = @(0);
741
+	[self.uut willMoveToParentViewController:nav];
742
+	XCTAssertTrue(nav.navigationBarHidden);
743
+}
744
+
745
+- (RNNNavigationController *)createNavigationController {
746
+	RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
747
+	nav.presenter = [[RNNNavigationControllerPresenter alloc] initWithOptions:[[RNNNavigationOptions alloc] initWithDict:@{}]];
748
+	
749
+	return nav;
750
+}
751
+
730 752
 @end

+ 4
- 3
lib/ios/ReactNativeNavigationTests/RNNStoreTest.m Просмотреть файл

@@ -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 Просмотреть файл

@@ -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"

+ 4
- 11
playground/src/app.js Просмотреть файл

@@ -37,22 +37,15 @@ function start() {
37 37
           waitForRender: false,
38 38
         }
39 39
       },
40
-      _animations: {
40
+      animations: {
41 41
         setRoot: {
42
-          y: {
43
-            from: 1000,
44
-            to: 0,
45
-            duration: 500,
46
-            interpolation: 'accelerate',
47
-          },
48 42
           alpha: {
49 43
             from: 0,
50 44
             to: 1,
51
-            duration: 500,
52
-            interpolation: 'accelerate'
45
+            duration: 300
53 46
           }
54 47
         },
55
-        push: {
48
+        _push: {
56 49
           topBar: {
57 50
             id: 'TEST',
58 51
             alpha: {
@@ -91,7 +84,7 @@ function start() {
91 84
             }
92 85
           }
93 86
         },
94
-        pop: {
87
+        _pop: {
95 88
           topBar: {
96 89
             id: 'TEST',
97 90
             alpha: {

+ 1
- 1
playground/src/screens/OptionsScreen.js Просмотреть файл

@@ -233,7 +233,7 @@ class OptionsScreen extends Component {
233 233
   }
234 234
 
235 235
   onClickShowTopBar = () => {
236
-    Navigation.mergeOptions(this.props.componentId, {
236
+    Navigation.mergeOptions('TEST', {
237 237
       topBar: {
238 238
         visible: true,
239 239
         animate: true

+ 6
- 5
playground/src/screens/TextScreen.js Просмотреть файл

@@ -1,7 +1,7 @@
1 1
 const React = require('react');
2 2
 const { Component } = require('react');
3 3
 
4
-const { View, Text, Button } = require('react-native');
4
+const { View, Text, Button, Platform } = require('react-native');
5 5
 
6 6
 const { Navigation } = require('react-native-navigation');
7 7
 const testIDs = require('../testIDs');
@@ -28,8 +28,9 @@ class TextScreen extends Component {
28 28
         <Button title={'Set Tab Badge'} testID={testIDs.SET_TAB_BADGE_BUTTON} onPress={() => this.onClickSetBadge()} />
29 29
         <Button title={'Switch To Tab 2'} testID={testIDs.SWITCH_SECOND_TAB_BUTTON} onPress={() => this.onClickSwitchToTab()} />
30 30
         <Button title={'Switch To Tab 1 by componentID'} testID={testIDs.SWITCH_FIRST_TAB_BUTTON} onPress={() => this.onClickSwitchToTabByComponentID()} />
31
-        <Button title='Hide Tab Bar' testID={testIDs.HIDE_BOTTOM_TABS_BUTTON} onPress={() => this.hideTabBar(false)} />
32
-        <Button title='Show Tab Bar' testID={testIDs.SHOW_BOTTOM_TABS_BUTTON} onPress={() => this.hideTabBar(true)} />
31
+        {/* tslint:disable-next-line:max-line-length */}
32
+        { Platform.OS === 'android' && <Button title='Hide Tab Bar' testID={testIDs.HIDE_BOTTOM_TABS_BUTTON} onPress={() => this.toggleTabBarVisibility(this.props.componentId, false)} /> }
33
+        { Platform.OS === 'android' && <Button title='Show Tab Bar' testID={testIDs.SHOW_BOTTOM_TABS_BUTTON} onPress={() => this.toggleTabBarVisibility('BottomTabs', true)} /> }
33 34
         <Button title='Hide Tab Bar on Push' testID={testIDs.HIDE_BOTTOM_TABS_ON_PUSH_BUTTON} onPress={() => this.hideTabBarOnPush()} />
34 35
         <Button title='Show Left Side Menu' testID={testIDs.SHOW_LEFT_SIDE_MENU_BUTTON} onPress={() => this.showSideMenu('left')} />
35 36
         <Button title='Show Right Side Menu' testID={testIDs.SHOW_RIGHT_SIDE_MENU_BUTTON} onPress={() => this.showSideMenu('right')} />
@@ -87,8 +88,8 @@ class TextScreen extends Component {
87 88
     });
88 89
   }
89 90
 
90
-  hideTabBar(visible) {
91
-    Navigation.mergeOptions(this.props.componentId, {
91
+  toggleTabBarVisibility(componentId, visible) {
92
+    Navigation.mergeOptions(componentId, {
92 93
       bottomTabs: {
93 94
         visible,
94 95
         drawBehind: true,

+ 1
- 0
playground/src/screens/WelcomeScreen.js Просмотреть файл

@@ -63,6 +63,7 @@ class WelcomeScreen extends Component {
63 63
     Navigation.setRoot({
64 64
       root: {
65 65
         bottomTabs: {
66
+          id: 'BottomTabs',
66 67
           children: [
67 68
             {
68 69
               stack: {