Skip to content

Commit

Permalink
Fix mergeOptions
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
guyca committed Aug 27, 2019
1 parent 9f6e09a commit 8044b2d
Show file tree
Hide file tree
Showing 12 changed files with 126 additions and 46 deletions.
4 changes: 4 additions & 0 deletions lib/ios/RNNBasePresenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ typedef void (^RNNReactViewReadyCompletionBlock)(void);
- (void)renderComponents:(RNNNavigationOptions *)options perform:(RNNReactViewReadyCompletionBlock)readyBlock;

- (void)viewDidLayoutSubviews;

- (UIStatusBarStyle)getStatusBarStyle:(RNNNavigationOptions *)resolvedOptions;

- (BOOL)isStatusBarVisibility:(UINavigationController *)stack resolvedOptions:(RNNNavigationOptions *)resolvedOptions;
@end
21 changes: 21 additions & 0 deletions lib/ios/RNNBasePresenter.m
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,25 @@ - (void)viewDidLayoutSubviews {
- (void)applyDotIndicator:(UIViewController *)child {
[[self dotIndicatorPresenter] apply:child:[child resolveOptions].bottomTab.dotIndicator];
}

- (UIStatusBarStyle)getStatusBarStyle:(RNNNavigationOptions *)resolvedOptions {
RNNNavigationOptions *withDefault = [resolvedOptions withDefault:[self defaultOptions]];
if ([[withDefault.statusBar.style getWithDefaultValue:@"default"] isEqualToString:@"light"]) {
return UIStatusBarStyleLightContent;
} else {
return UIStatusBarStyleDefault;
}
}

- (BOOL)isStatusBarVisibility:(UINavigationController *)stack resolvedOptions:(RNNNavigationOptions *)resolvedOptions {
RNNNavigationOptions *withDefault = [resolvedOptions withDefault:[self defaultOptions]];
if (withDefault.statusBar.visible.hasValue) {
return ![withDefault.statusBar.visible get];
} else if ([withDefault.statusBar.hideWithTopBar getWithDefaultValue:NO]) {
return stack.isNavigationBarHidden;
}
return NO;
}


@end
2 changes: 1 addition & 1 deletion lib/ios/RNNNavigationController.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ - (UINavigationController *)navigationController {
}

- (UIStatusBarStyle)preferredStatusBarStyle {
return self.getCurrentChild.preferredStatusBarStyle;
return [_presenter getStatusBarStyle:self.resolveOptions];
}

- (UIModalPresentationStyle)modalPresentationStyle {
Expand Down
11 changes: 7 additions & 4 deletions lib/ios/RNNNavigationControllerPresenter.m
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,15 @@ - (void)mergeOptions:(RNNNavigationOptions *)newOptions currentOptions:(RNNNavig
}


RNNLargeTitleOptions *largteTitleOptions = newOptions.topBar.largeTitle;
if (largteTitleOptions.color.hasValue || largteTitleOptions.fontSize.hasValue || largteTitleOptions.fontFamily.hasValue) {
RNNLargeTitleOptions *largeTitleOptions = newOptions.topBar.largeTitle;
if (largeTitleOptions.color.hasValue || largeTitleOptions.fontSize.hasValue || largeTitleOptions.fontFamily.hasValue) {
[navigationController rnn_setNavigationBarLargeTitleFontFamily:[newOptions.topBar.largeTitle.fontFamily getWithDefaultValue:nil] fontSize:[newOptions.topBar.largeTitle.fontSize getWithDefaultValue:nil] color:[newOptions.topBar.largeTitle.color getWithDefaultValue:nil]];
}

[navigationController rnn_setNavigationBarFontFamily:[newOptions.topBar.title.fontFamily getWithDefaultValue:nil] fontSize:[newOptions.topBar.title.fontSize getWithDefaultValue:nil] color:[newOptions.topBar.title.color getWithDefaultValue:nil]];

RNNNavigationOptions * withDefault = (RNNNavigationOptions *) [[newOptions mergeInOptions:currentOptions] withDefault:[self defaultOptions]];
[navigationController rnn_setNavigationBarFontFamily:[withDefault.topBar.title.fontFamily getWithDefaultValue:nil]
fontSize:[withDefault.topBar.title.fontSize getWithDefaultValue:nil]
color:[withDefault.topBar.title.color getWithDefaultValue:nil]];

if (newOptions.topBar.component.name.hasValue) {
[self setCustomNavigationBarView:newOptions perform:nil];
Expand Down
14 changes: 2 additions & 12 deletions lib/ios/RNNRootViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -116,21 +116,11 @@ - (BOOL)isExternalViewController {
}

- (BOOL)prefersStatusBarHidden {
if (self.resolveOptions.statusBar.visible.hasValue) {
return ![self.resolveOptions.statusBar.visible get];
} else if ([self.resolveOptions.statusBar.hideWithTopBar getWithDefaultValue:NO]) {
return self.navigationController.isNavigationBarHidden;
}

return NO;
return [_presenter isStatusBarVisibility:self.navigationController resolvedOptions:self.resolveOptions];
}

- (UIStatusBarStyle)preferredStatusBarStyle {
if ([[self.resolveOptions.statusBar.style getWithDefaultValue:@"default"] isEqualToString:@"light"]) {
return UIStatusBarStyleLightContent;
} else {
return UIStatusBarStyleDefault;
}
return [_presenter getStatusBarStyle:[self resolveOptions]];
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
Expand Down
2 changes: 1 addition & 1 deletion lib/ios/RNNSideMenuChildVC.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ - (UIViewController *)getCurrentChild {
}

- (UIStatusBarStyle)preferredStatusBarStyle {
return self.child.preferredStatusBarStyle;
return [[self presenter] getStatusBarStyle:[self resolveOptions]];
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
Expand Down
2 changes: 1 addition & 1 deletion lib/ios/RNNTabBarController.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ - (void)setSelectedIndex:(NSUInteger)selectedIndex {
}

- (UIStatusBarStyle)preferredStatusBarStyle {
return self.selectedViewController.preferredStatusBarStyle;
return [[self presenter] getStatusBarStyle:self.resolveOptions];
}

#pragma mark UITabBarControllerDelegate
Expand Down
15 changes: 8 additions & 7 deletions lib/ios/RNNViewControllerPresenter.m
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ - (void)applyOptionsOnInit:(RNNNavigationOptions *)options {

- (void)mergeOptions:(RNNNavigationOptions *)newOptions currentOptions:(RNNNavigationOptions *)currentOptions {
[super mergeOptions:newOptions currentOptions:currentOptions];

RNNNavigationOptions * withDefault = (RNNNavigationOptions *) [[currentOptions overrideOptions:newOptions] withDefault:[self defaultOptions]];

UIViewController* viewController = self.boundViewController;

if (newOptions.backgroundImage.hasValue) {
Expand Down Expand Up @@ -135,25 +136,25 @@ - (void)mergeOptions:(RNNNavigationOptions *)newOptions currentOptions:(RNNNavig
}

if (newOptions.statusBar.style.hasValue) {
[viewController rnn_setStatusBarStyle:newOptions.statusBar.style.get animated:[newOptions.statusBar.animate getWithDefaultValue:YES]];
[viewController rnn_setStatusBarStyle:newOptions.statusBar.style.get animated:[withDefault.statusBar.animate getWithDefaultValue:YES]];
}

if (newOptions.topBar.backButton.visible.hasValue) {
[viewController rnn_setBackButtonVisible:newOptions.topBar.backButton.visible.get];
}

if (newOptions.topBar.leftButtons || newOptions.topBar.rightButtons) {
RNNNavigationOptions* buttonsResolvedOptions = (RNNNavigationOptions *)[currentOptions overrideOptions:newOptions];
[_navigationButtons applyLeftButtons:newOptions.topBar.leftButtons rightButtons:newOptions.topBar.rightButtons defaultLeftButtonStyle:buttonsResolvedOptions.topBar.leftButtonStyle defaultRightButtonStyle:buttonsResolvedOptions.topBar.rightButtonStyle];
[_navigationButtons applyLeftButtons:newOptions.topBar.leftButtons rightButtons:newOptions.topBar.rightButtons defaultLeftButtonStyle:withDefault.topBar.leftButtonStyle defaultRightButtonStyle:withDefault.topBar.rightButtonStyle];
}


if (newOptions.overlay.interceptTouchOutside.hasValue) {
RCTRootView* rootView = (RCTRootView*)viewController.view;
rootView.passThroughTouches = !newOptions.overlay.interceptTouchOutside.get;
}
[self setTitleViewWithSubtitle:(RNNNavigationOptions *)[currentOptions overrideOptions:newOptions]];

[self setTitleViewWithSubtitle:withDefault];

if (newOptions.topBar.title.component.name.hasValue) {
[self setCustomNavigationTitleView:newOptions perform:nil];
}
Expand Down
30 changes: 30 additions & 0 deletions lib/ios/ReactNativeNavigationTests/RNNBasePresenterTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,34 @@ - (void)testApplyOptions_setTabBarItemBadgeShouldWhenNoValue {
[self.mockBoundViewController verify];
}

- (void)testGetPreferredStatusBarStyle_returnLightIfLight {
RNNNavigationOptions * lightOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
lightOptions.statusBar.style = [[Text alloc] initWithValue:@"light"];

XCTAssertEqual([_uut getStatusBarStyle:lightOptions], UIStatusBarStyleLightContent);
}

- (void)testGetPreferredStatusBarStyle_returnDefaultIfDark {
RNNNavigationOptions * darkOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
darkOptions.statusBar.style = [[Text alloc] initWithValue:@"dark"];

XCTAssertEqual([_uut getStatusBarStyle:darkOptions], UIStatusBarStyleDefault);
}

- (void)testGetPreferredStatusBarStyle_returnDefaultIfNil {
RNNNavigationOptions * options = [[RNNNavigationOptions alloc] initEmptyOptions];

XCTAssertEqual([_uut getStatusBarStyle:options], UIStatusBarStyleDefault);
}

- (void)testGetPreferredStatusBarStyle_considersDefaultOptions {
RNNNavigationOptions * options = [[RNNNavigationOptions alloc] initEmptyOptions];
RNNNavigationOptions * lightOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
lightOptions.statusBar.style = [[Text alloc] initWithValue:@"light"];
[_uut setDefaultOptions:lightOptions];

XCTAssertEqual([_uut getStatusBarStyle:options], UIStatusBarStyleLightContent);
}


@end
10 changes: 2 additions & 8 deletions lib/ios/ReactNativeNavigationTests/RNNTabBarControllerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,9 @@ - (void)testGetCurrentChild_shouldReturnSelectedViewController {
}

- (void)testPreferredStatusBarStyle_shouldInvokeSelectedViewControllerPreferredStatusBarStyle {
[[self.mockChildViewController expect] preferredStatusBarStyle];
[[self.mockTabBarPresenter expect] getStatusBarStyle:[OCMArg any]];
[self.uut preferredStatusBarStyle];
[self.mockChildViewController verify];
}

- (void)testPreferredStatusBarStyle_shouldInvokeOnSelectedViewController {
[[self.mockChildViewController expect] preferredStatusBarStyle];
[self.uut preferredStatusBarStyle];
[self.mockChildViewController verify];
[self.mockTabBarPresenter verify];
}

- (void)testTabBarControllerDidSelectViewControllerDelegate_shouldInvokeSendBottomTabSelectedEvent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

@interface UIViewController_LayoutProtocolTest : XCTestCase

@property (nonatomic, retain) UIViewController* uut;
@property (nonatomic, retain) UIViewController * uut;

@end

Expand All @@ -18,8 +18,8 @@ @implementation UIViewController_LayoutProtocolTest
- (void)setUp {
[super setUp];
self.uut = [OCMockObject partialMockForObject:[UIViewController new]];
self.uut.layoutInfo = [[RNNLayoutInfo alloc] init];
self.uut.layoutInfo.componentId = @"componentId";
_uut.layoutInfo = [[RNNLayoutInfo alloc] init];
_uut.layoutInfo.componentId = @"componentId";
}

- (void)testInitWithLayoutApplyDefaultOptions {
Expand Down Expand Up @@ -53,17 +53,17 @@ - (void)testSetBackButtonIcon_withColor_shouldSetColor {

- (void)testSetBackButtonIcon_withColor_shouldSetTitle {
UIViewController* uut = [UIViewController new];
UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:uut];
NSString* title = @"Title";
UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:uut];
NSString* title = @"Title";

[uut rnn_setBackButtonIcon:nil withColor:nil title:title];
XCTAssertEqual(title, uut.navigationItem.backBarButtonItem.title);
}

- (void)testSetBackButtonIcon_withColor_shouldSetIcon {
UIViewController* uut = [UIViewController new];
UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:uut];
UIImage* icon = [UIImage new];
UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:uut];
UIImage* icon = [UIImage new];

[uut rnn_setBackButtonIcon:icon withColor:nil title:nil];
XCTAssertEqual(icon, uut.navigationItem.backBarButtonItem.image);
Expand Down Expand Up @@ -99,4 +99,41 @@ - (void)testResolveOptions {
XCTAssertEqual([[parent resolveOptions].bottomTab.selectedIconColor get], UIColor.redColor);
}

- (void)testMergeOptions_invokedOnParentViewController {
id parent = [OCMockObject partialMockForObject:[RNNNavigationController new]];
RNNNavigationOptions * toMerge = [[RNNNavigationOptions alloc] initEmptyOptions];
[(UIViewController *) [parent expect] mergeOptions:toMerge];

RNNNavigationController* uut = [[RNNNavigationController alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:nil eventEmitter:nil childViewControllers:nil];
[parent addChildViewController:uut];

[uut mergeOptions:toMerge];
[parent verify];
}

- (void)testMergeOptions_presenterIsInvokedWithResolvedOptions {
id parent = [OCMockObject partialMockForObject:[RNNNavigationController new]];
id presenter = [OCMockObject partialMockForObject:[RNNNavigationControllerPresenter new]];
RNNNavigationOptions * toMerge = [[RNNNavigationOptions alloc] initEmptyOptions];
toMerge.topBar.title.color = [[Color alloc] initWithValue:[UIColor redColor]];

[[presenter expect] mergeOptions:toMerge currentOptions:[OCMArg checkWithBlock:^(id value) {
RNNNavigationOptions * options = (RNNNavigationOptions *) value;
XCTAssertEqual([options.topBar.title.text get], @"Initial title");
XCTAssertEqual([options.bottomTab.text get], @"Child tab text");
return YES;
}]];

RNNNavigationOptions * childOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
childOptions.bottomTab.text = [[Text alloc] initWithValue:@"Child tab text"];
UIViewController* child = [[UIViewController alloc] initWithLayoutInfo:nil creator:nil options:childOptions defaultOptions:nil presenter:presenter eventEmitter:nil childViewControllers:nil];
RNNNavigationOptions * initialOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
initialOptions.topBar.title.text = [[Text alloc] initWithValue:@"Initial title"];
RNNNavigationController* uut = [[RNNNavigationController alloc] initWithLayoutInfo:nil creator:nil options:initialOptions defaultOptions:nil presenter:presenter eventEmitter:nil childViewControllers:@[child]];
[parent addChildViewController:uut];

[uut mergeOptions:toMerge];
[presenter verify];
}

@end
10 changes: 5 additions & 5 deletions lib/ios/UIViewController+LayoutProtocol.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ - (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo
return self;
}

- (RNNNavigationOptions *)resolveOptions {
return (RNNNavigationOptions *) [self.options mergeInOptions:self.getCurrentChild.resolveOptions.copy];
}

- (void)mergeOptions:(RNNNavigationOptions *)options {
[self.presenter mergeOptions:options currentOptions:self.options];
[self.presenter mergeOptions:options currentOptions:self.resolveOptions];
[self.parentViewController mergeOptions:options];
}

- (RNNNavigationOptions *)resolveOptions {
return (RNNNavigationOptions *) [self.options mergeInOptions:self.getCurrentChild.resolveOptions.copy];
}

- (void)overrideOptions:(RNNNavigationOptions *)options {
[self.options overrideOptions:options];
}
Expand Down

0 comments on commit 8044b2d

Please sign in to comment.