Browse Source

Fix mergeOptions

Merging TopBar title, buttons and status bar options is broken on iOS in 3.1.1.
Parent options aren't resolved properly and default options aren't regarded when they should be.
Guy Carmeli 5 years ago
parent
commit
5409a625d9

+ 4
- 0
lib/ios/RNNBasePresenter.h View File

31
 - (void)renderComponents:(RNNNavigationOptions *)options perform:(RNNReactViewReadyCompletionBlock)readyBlock;
31
 - (void)renderComponents:(RNNNavigationOptions *)options perform:(RNNReactViewReadyCompletionBlock)readyBlock;
32
 
32
 
33
 - (void)viewDidLayoutSubviews;
33
 - (void)viewDidLayoutSubviews;
34
+
35
+- (UIStatusBarStyle)getStatusBarStyle:(RNNNavigationOptions *)resolvedOptions;
36
+
37
+- (BOOL)isStatusBarVisibility:(UINavigationController *)stack resolvedOptions:(RNNNavigationOptions *)resolvedOptions;
34
 @end
38
 @end

+ 21
- 0
lib/ios/RNNBasePresenter.m View File

164
 - (void)applyDotIndicator:(UIViewController *)child {
164
 - (void)applyDotIndicator:(UIViewController *)child {
165
     [[self dotIndicatorPresenter] apply:child:[child resolveOptions].bottomTab.dotIndicator];
165
     [[self dotIndicatorPresenter] apply:child:[child resolveOptions].bottomTab.dotIndicator];
166
 }
166
 }
167
+
168
+- (UIStatusBarStyle)getStatusBarStyle:(RNNNavigationOptions *)resolvedOptions {
169
+    RNNNavigationOptions *withDefault = [resolvedOptions withDefault:[self defaultOptions]];
170
+    if ([[withDefault.statusBar.style getWithDefaultValue:@"default"] isEqualToString:@"light"]) {
171
+        return UIStatusBarStyleLightContent;
172
+    } else {
173
+        return UIStatusBarStyleDefault;
174
+    }
175
+}
176
+
177
+- (BOOL)isStatusBarVisibility:(UINavigationController *)stack resolvedOptions:(RNNNavigationOptions *)resolvedOptions {
178
+    RNNNavigationOptions *withDefault = [resolvedOptions withDefault:[self defaultOptions]];
179
+    if (withDefault.statusBar.visible.hasValue) {
180
+        return ![withDefault.statusBar.visible get];
181
+    } else if ([withDefault.statusBar.hideWithTopBar getWithDefaultValue:NO]) {
182
+        return stack.isNavigationBarHidden;
183
+    }
184
+    return NO;
185
+}
186
+
187
+
167
 @end
188
 @end

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

32
 }
32
 }
33
 
33
 
34
 - (UIStatusBarStyle)preferredStatusBarStyle {
34
 - (UIStatusBarStyle)preferredStatusBarStyle {
35
-	return self.getCurrentChild.preferredStatusBarStyle;
35
+	return [_presenter getStatusBarStyle:self.resolveOptions];
36
 }
36
 }
37
 
37
 
38
 - (UIModalPresentationStyle)modalPresentationStyle {
38
 - (UIModalPresentationStyle)modalPresentationStyle {

+ 7
- 4
lib/ios/RNNNavigationControllerPresenter.m View File

120
 	}
120
 	}
121
 	
121
 	
122
 
122
 
123
-	RNNLargeTitleOptions *largteTitleOptions = newOptions.topBar.largeTitle;
124
-	if (largteTitleOptions.color.hasValue || largteTitleOptions.fontSize.hasValue || largteTitleOptions.fontFamily.hasValue) {
123
+	RNNLargeTitleOptions *largeTitleOptions = newOptions.topBar.largeTitle;
124
+	if (largeTitleOptions.color.hasValue || largeTitleOptions.fontSize.hasValue || largeTitleOptions.fontFamily.hasValue) {
125
 		[navigationController rnn_setNavigationBarLargeTitleFontFamily:[newOptions.topBar.largeTitle.fontFamily getWithDefaultValue:nil] fontSize:[newOptions.topBar.largeTitle.fontSize getWithDefaultValue:nil] color:[newOptions.topBar.largeTitle.color getWithDefaultValue:nil]];
125
 		[navigationController rnn_setNavigationBarLargeTitleFontFamily:[newOptions.topBar.largeTitle.fontFamily getWithDefaultValue:nil] fontSize:[newOptions.topBar.largeTitle.fontSize getWithDefaultValue:nil] color:[newOptions.topBar.largeTitle.color getWithDefaultValue:nil]];
126
 	}
126
 	}
127
-	
128
-	[navigationController rnn_setNavigationBarFontFamily:[newOptions.topBar.title.fontFamily getWithDefaultValue:nil] fontSize:[newOptions.topBar.title.fontSize getWithDefaultValue:nil] color:[newOptions.topBar.title.color getWithDefaultValue:nil]];
127
+
128
+	RNNNavigationOptions * withDefault = (RNNNavigationOptions *) [[newOptions mergeInOptions:currentOptions] withDefault:[self defaultOptions]];
129
+	[navigationController rnn_setNavigationBarFontFamily:[withDefault.topBar.title.fontFamily getWithDefaultValue:nil]
130
+												fontSize:[withDefault.topBar.title.fontSize getWithDefaultValue:nil]
131
+												   color:[withDefault.topBar.title.color getWithDefaultValue:nil]];
129
 	
132
 	
130
 	if (newOptions.topBar.component.name.hasValue) {
133
 	if (newOptions.topBar.component.name.hasValue) {
131
 		[self setCustomNavigationBarView:newOptions perform:nil];
134
 		[self setCustomNavigationBarView:newOptions perform:nil];

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

116
 }
116
 }
117
 
117
 
118
 - (BOOL)prefersStatusBarHidden {
118
 - (BOOL)prefersStatusBarHidden {
119
-	if (self.resolveOptions.statusBar.visible.hasValue) {
120
-		return ![self.resolveOptions.statusBar.visible get];
121
-	} else if ([self.resolveOptions.statusBar.hideWithTopBar getWithDefaultValue:NO]) {
122
-		return self.navigationController.isNavigationBarHidden;
123
-	}
124
-	
125
-	return NO;
119
+	return [_presenter isStatusBarVisibility:self.navigationController resolvedOptions:self.resolveOptions];
126
 }
120
 }
127
 
121
 
128
 - (UIStatusBarStyle)preferredStatusBarStyle {
122
 - (UIStatusBarStyle)preferredStatusBarStyle {
129
-	if ([[self.resolveOptions.statusBar.style getWithDefaultValue:@"default"] isEqualToString:@"light"]) {
130
-		return UIStatusBarStyleLightContent;
131
-	} else {
132
-		return UIStatusBarStyleDefault;
133
-	}
123
+	return [_presenter getStatusBarStyle:[self resolveOptions]];
134
 }
124
 }
135
 
125
 
136
 - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
126
 - (UIInterfaceOrientationMask)supportedInterfaceOrientations {

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

40
 }
40
 }
41
 
41
 
42
 - (UIStatusBarStyle)preferredStatusBarStyle {
42
 - (UIStatusBarStyle)preferredStatusBarStyle {
43
-	return self.child.preferredStatusBarStyle;
43
+	return [[self presenter] getStatusBarStyle:[self resolveOptions]];
44
 }
44
 }
45
 
45
 
46
 - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
46
 - (UIInterfaceOrientationMask)supportedInterfaceOrientations {

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

44
 }
44
 }
45
 
45
 
46
 - (UIStatusBarStyle)preferredStatusBarStyle {
46
 - (UIStatusBarStyle)preferredStatusBarStyle {
47
-	return self.selectedViewController.preferredStatusBarStyle;
47
+	return [[self presenter] getStatusBarStyle:self.resolveOptions];
48
 }
48
 }
49
 
49
 
50
 #pragma mark UITabBarControllerDelegate
50
 #pragma mark UITabBarControllerDelegate

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

79
 
79
 
80
 - (void)mergeOptions:(RNNNavigationOptions *)newOptions currentOptions:(RNNNavigationOptions *)currentOptions {
80
 - (void)mergeOptions:(RNNNavigationOptions *)newOptions currentOptions:(RNNNavigationOptions *)currentOptions {
81
 	[super mergeOptions:newOptions currentOptions:currentOptions];
81
 	[super mergeOptions:newOptions currentOptions:currentOptions];
82
-	
82
+	RNNNavigationOptions * withDefault	= (RNNNavigationOptions *) [[currentOptions overrideOptions:newOptions] withDefault:[self defaultOptions]];
83
+
83
 	UIViewController* viewController = self.boundViewController;
84
 	UIViewController* viewController = self.boundViewController;
84
 	
85
 	
85
 	if (newOptions.backgroundImage.hasValue) {
86
 	if (newOptions.backgroundImage.hasValue) {
135
 	}
136
 	}
136
 	
137
 	
137
 	if (newOptions.statusBar.style.hasValue) {
138
 	if (newOptions.statusBar.style.hasValue) {
138
-		[viewController rnn_setStatusBarStyle:newOptions.statusBar.style.get animated:[newOptions.statusBar.animate getWithDefaultValue:YES]];
139
+		[viewController rnn_setStatusBarStyle:newOptions.statusBar.style.get animated:[withDefault.statusBar.animate getWithDefaultValue:YES]];
139
 	}
140
 	}
140
 	
141
 	
141
 	if (newOptions.topBar.backButton.visible.hasValue) {
142
 	if (newOptions.topBar.backButton.visible.hasValue) {
143
 	}
144
 	}
144
 	
145
 	
145
 	if (newOptions.topBar.leftButtons || newOptions.topBar.rightButtons) {
146
 	if (newOptions.topBar.leftButtons || newOptions.topBar.rightButtons) {
146
-		RNNNavigationOptions* buttonsResolvedOptions = (RNNNavigationOptions *)[currentOptions overrideOptions:newOptions];
147
-		[_navigationButtons applyLeftButtons:newOptions.topBar.leftButtons rightButtons:newOptions.topBar.rightButtons defaultLeftButtonStyle:buttonsResolvedOptions.topBar.leftButtonStyle defaultRightButtonStyle:buttonsResolvedOptions.topBar.rightButtonStyle];
147
+		[_navigationButtons applyLeftButtons:newOptions.topBar.leftButtons rightButtons:newOptions.topBar.rightButtons defaultLeftButtonStyle:withDefault.topBar.leftButtonStyle defaultRightButtonStyle:withDefault.topBar.rightButtonStyle];
148
 	}
148
 	}
149
 	
149
 	
150
+
150
 	if (newOptions.overlay.interceptTouchOutside.hasValue) {
151
 	if (newOptions.overlay.interceptTouchOutside.hasValue) {
151
 		RCTRootView* rootView = (RCTRootView*)viewController.view;
152
 		RCTRootView* rootView = (RCTRootView*)viewController.view;
152
 		rootView.passThroughTouches = !newOptions.overlay.interceptTouchOutside.get;
153
 		rootView.passThroughTouches = !newOptions.overlay.interceptTouchOutside.get;
153
 	}
154
 	}
154
-	
155
-	[self setTitleViewWithSubtitle:(RNNNavigationOptions *)[currentOptions overrideOptions:newOptions]];
156
-	
155
+
156
+	[self setTitleViewWithSubtitle:withDefault];
157
+
157
 	if (newOptions.topBar.title.component.name.hasValue) {
158
 	if (newOptions.topBar.title.component.name.hasValue) {
158
 		[self setCustomNavigationTitleView:newOptions perform:nil];
159
 		[self setCustomNavigationTitleView:newOptions perform:nil];
159
 	} else {
160
 	} else {

+ 30
- 0
lib/ios/ReactNativeNavigationTests/RNNBasePresenterTest.m View File

60
     [self.mockBoundViewController verify];
60
     [self.mockBoundViewController verify];
61
 }
61
 }
62
 
62
 
63
+- (void)testGetPreferredStatusBarStyle_returnLightIfLight {
64
+    RNNNavigationOptions * lightOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
65
+    lightOptions.statusBar.style = [[Text alloc] initWithValue:@"light"];
66
+
67
+    XCTAssertEqual([_uut getStatusBarStyle:lightOptions], UIStatusBarStyleLightContent);
68
+}
69
+
70
+- (void)testGetPreferredStatusBarStyle_returnDefaultIfDark {
71
+    RNNNavigationOptions * darkOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
72
+    darkOptions.statusBar.style = [[Text alloc] initWithValue:@"dark"];
73
+
74
+    XCTAssertEqual([_uut getStatusBarStyle:darkOptions], UIStatusBarStyleDefault);
75
+}
76
+
77
+- (void)testGetPreferredStatusBarStyle_returnDefaultIfNil {
78
+    RNNNavigationOptions * options = [[RNNNavigationOptions alloc] initEmptyOptions];
79
+
80
+    XCTAssertEqual([_uut getStatusBarStyle:options], UIStatusBarStyleDefault);
81
+}
82
+
83
+- (void)testGetPreferredStatusBarStyle_considersDefaultOptions {
84
+    RNNNavigationOptions * options = [[RNNNavigationOptions alloc] initEmptyOptions];
85
+    RNNNavigationOptions * lightOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
86
+    lightOptions.statusBar.style = [[Text alloc] initWithValue:@"light"];
87
+    [_uut setDefaultOptions:lightOptions];
88
+
89
+    XCTAssertEqual([_uut getStatusBarStyle:options], UIStatusBarStyleLightContent);
90
+}
91
+
92
+
63
 @end
93
 @end

+ 2
- 8
lib/ios/ReactNativeNavigationTests/RNNTabBarControllerTest.m View File

126
 }
126
 }
127
 
127
 
128
 - (void)testPreferredStatusBarStyle_shouldInvokeSelectedViewControllerPreferredStatusBarStyle {
128
 - (void)testPreferredStatusBarStyle_shouldInvokeSelectedViewControllerPreferredStatusBarStyle {
129
-    [[self.mockChildViewController expect] preferredStatusBarStyle];
129
+    [[self.mockTabBarPresenter expect] getStatusBarStyle:[OCMArg any]];
130
     [self.uut preferredStatusBarStyle];
130
     [self.uut preferredStatusBarStyle];
131
-    [self.mockChildViewController verify];
132
-}
133
-
134
-- (void)testPreferredStatusBarStyle_shouldInvokeOnSelectedViewController {
135
-    [[self.mockChildViewController expect] preferredStatusBarStyle];
136
-    [self.uut preferredStatusBarStyle];
137
-    [self.mockChildViewController verify];
131
+    [self.mockTabBarPresenter verify];
138
 }
132
 }
139
 
133
 
140
 - (void)testTabBarControllerDidSelectViewControllerDelegate_shouldInvokeSendBottomTabSelectedEvent {
134
 - (void)testTabBarControllerDidSelectViewControllerDelegate_shouldInvokeSendBottomTabSelectedEvent {

+ 44
- 7
lib/ios/ReactNativeNavigationTests/UIViewController+LayoutProtocolTest.m View File

9
 
9
 
10
 @interface UIViewController_LayoutProtocolTest : XCTestCase
10
 @interface UIViewController_LayoutProtocolTest : XCTestCase
11
 
11
 
12
-@property (nonatomic, retain) UIViewController* uut;
12
+@property (nonatomic, retain) UIViewController * uut;
13
 
13
 
14
 @end
14
 @end
15
 
15
 
18
 - (void)setUp {
18
 - (void)setUp {
19
 	[super setUp];
19
 	[super setUp];
20
 	self.uut = [OCMockObject partialMockForObject:[UIViewController new]];
20
 	self.uut = [OCMockObject partialMockForObject:[UIViewController new]];
21
-    self.uut.layoutInfo = [[RNNLayoutInfo alloc] init];
22
-    self.uut.layoutInfo.componentId = @"componentId";
21
+    _uut.layoutInfo = [[RNNLayoutInfo alloc] init];
22
+    _uut.layoutInfo.componentId = @"componentId";
23
 }
23
 }
24
 
24
 
25
 - (void)testInitWithLayoutApplyDefaultOptions {
25
 - (void)testInitWithLayoutApplyDefaultOptions {
53
 
53
 
54
 - (void)testSetBackButtonIcon_withColor_shouldSetTitle {
54
 - (void)testSetBackButtonIcon_withColor_shouldSetTitle {
55
 	UIViewController* uut = [UIViewController new];
55
 	UIViewController* uut = [UIViewController new];
56
-	UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:uut];
57
-	NSString* title = @"Title";
56
+    UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:uut];
57
+    NSString* title = @"Title";
58
 	
58
 	
59
 	[uut rnn_setBackButtonIcon:nil withColor:nil title:title];
59
 	[uut rnn_setBackButtonIcon:nil withColor:nil title:title];
60
 	XCTAssertEqual(title, uut.navigationItem.backBarButtonItem.title);
60
 	XCTAssertEqual(title, uut.navigationItem.backBarButtonItem.title);
62
 
62
 
63
 - (void)testSetBackButtonIcon_withColor_shouldSetIcon {
63
 - (void)testSetBackButtonIcon_withColor_shouldSetIcon {
64
 	UIViewController* uut = [UIViewController new];
64
 	UIViewController* uut = [UIViewController new];
65
-	UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:uut];
66
-	UIImage* icon = [UIImage new];
65
+    UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:uut];
66
+    UIImage* icon = [UIImage new];
67
 	
67
 	
68
 	[uut rnn_setBackButtonIcon:icon withColor:nil title:nil];
68
 	[uut rnn_setBackButtonIcon:icon withColor:nil title:nil];
69
 	XCTAssertEqual(icon, uut.navigationItem.backBarButtonItem.image);
69
 	XCTAssertEqual(icon, uut.navigationItem.backBarButtonItem.image);
99
 	XCTAssertEqual([[parent resolveOptions].bottomTab.selectedIconColor get], UIColor.redColor);
99
 	XCTAssertEqual([[parent resolveOptions].bottomTab.selectedIconColor get], UIColor.redColor);
100
 }
100
 }
101
 
101
 
102
+- (void)testMergeOptions_invokedOnParentViewController {
103
+    id parent = [OCMockObject partialMockForObject:[RNNNavigationController new]];
104
+    RNNNavigationOptions * toMerge = [[RNNNavigationOptions alloc] initEmptyOptions];
105
+    [(UIViewController *) [parent expect] mergeOptions:toMerge];
106
+
107
+    RNNNavigationController* uut = [[RNNNavigationController alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:nil eventEmitter:nil childViewControllers:nil];
108
+    [parent addChildViewController:uut];
109
+
110
+    [uut mergeOptions:toMerge];
111
+    [parent verify];
112
+}
113
+
114
+- (void)testMergeOptions_presenterIsInvokedWithResolvedOptions {
115
+    id parent = [OCMockObject partialMockForObject:[RNNNavigationController new]];
116
+    id presenter = [OCMockObject partialMockForObject:[RNNNavigationControllerPresenter new]];
117
+    RNNNavigationOptions * toMerge = [[RNNNavigationOptions alloc] initEmptyOptions];
118
+    toMerge.topBar.title.color = [[Color alloc] initWithValue:[UIColor redColor]];
119
+
120
+    [[presenter expect] mergeOptions:toMerge currentOptions:[OCMArg checkWithBlock:^(id value) {
121
+        RNNNavigationOptions * options = (RNNNavigationOptions *) value;
122
+        XCTAssertEqual([options.topBar.title.text get], @"Initial title");
123
+        XCTAssertEqual([options.bottomTab.text get], @"Child tab text");
124
+        return YES;
125
+    }]];
126
+
127
+    RNNNavigationOptions * childOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
128
+    childOptions.bottomTab.text = [[Text alloc] initWithValue:@"Child tab text"];
129
+    UIViewController* child = [[UIViewController alloc] initWithLayoutInfo:nil creator:nil options:childOptions defaultOptions:nil presenter:presenter eventEmitter:nil childViewControllers:nil];
130
+    RNNNavigationOptions * initialOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
131
+    initialOptions.topBar.title.text = [[Text alloc] initWithValue:@"Initial title"];
132
+    RNNNavigationController* uut = [[RNNNavigationController alloc] initWithLayoutInfo:nil creator:nil options:initialOptions defaultOptions:nil presenter:presenter eventEmitter:nil childViewControllers:@[child]];
133
+    [parent addChildViewController:uut];
134
+
135
+	[uut mergeOptions:toMerge];
136
+    [presenter verify];
137
+}
138
+
102
 @end
139
 @end

+ 5
- 5
lib/ios/UIViewController+LayoutProtocol.m View File

28
 	return self;
28
 	return self;
29
 }
29
 }
30
 
30
 
31
-- (RNNNavigationOptions *)resolveOptions {
32
-    return (RNNNavigationOptions *) [self.options mergeInOptions:self.getCurrentChild.resolveOptions.copy];
33
-}
34
-
35
 - (void)mergeOptions:(RNNNavigationOptions *)options {
31
 - (void)mergeOptions:(RNNNavigationOptions *)options {
36
-	[self.presenter mergeOptions:options currentOptions:self.options];
32
+	[self.presenter mergeOptions:options currentOptions:self.resolveOptions];
37
 	[self.parentViewController mergeOptions:options];
33
 	[self.parentViewController mergeOptions:options];
38
 }
34
 }
39
 
35
 
36
+- (RNNNavigationOptions *)resolveOptions {
37
+    return (RNNNavigationOptions *) [self.options mergeInOptions:self.getCurrentChild.resolveOptions.copy];
38
+}
39
+
40
 - (void)overrideOptions:(RNNNavigationOptions *)options {
40
 - (void)overrideOptions:(RNNNavigationOptions *)options {
41
 	[self.options overrideOptions:options];
41
 	[self.options overrideOptions:options];
42
 }
42
 }