diff --git a/e2e/SetRoot.test.js b/e2e/SetRoot.test.js index e5b9192ab0e..c224cc39ec9 100644 --- a/e2e/SetRoot.test.js +++ b/e2e/SetRoot.test.js @@ -13,4 +13,18 @@ describe('SetRoot', () => { await elementById(TestIDs.SET_MULTIPLE_ROOTS_BTN).tap(); await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); }); + + it('set root hides bottomTabs', async () => { + await elementById(TestIDs.SET_ROOT_HIDES_BOTTOM_TABS_BTN).tap(); + await expect(elementById(TestIDs.LAYOUTS_TAB)).toBeNotVisible(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementById(TestIDs.LAYOUTS_TAB)).toBeVisible(); + }); + + it('set root with stack hides bottomTabs', async () => { + await elementById(TestIDs.SET_ROOT_WITH_STACK_HIDES_BOTTOM_TABS_BTN).tap(); + await expect(elementById(TestIDs.LAYOUTS_TAB)).toBeNotVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.LAYOUTS_TAB)).toBeVisible(); + }); }); diff --git a/lib/ios/BottomTabsBasePresenter.m b/lib/ios/BottomTabsBasePresenter.m index 118e14da164..2b5dfbbd07b 100644 --- a/lib/ios/BottomTabsBasePresenter.m +++ b/lib/ios/BottomTabsBasePresenter.m @@ -17,6 +17,7 @@ - (void)applyOptions:(RNNNavigationOptions *)options { RNNNavigationOptions *withDefault = [options withDefault:[self defaultOptions]]; [bottomTabs setTabBarTestID:[withDefault.bottomTabs.testID getWithDefaultValue:nil]]; + ![withDefault.bottomTabs.visible getWithDefaultValue:YES] ?: [bottomTabs setTabBarVisible:[withDefault.bottomTabs.visible getWithDefaultValue:YES] animated:[withDefault.bottomTabs.animate getWithDefaultValue:NO]]; [bottomTabs.view setBackgroundColor:[withDefault.layout.backgroundColor getWithDefaultValue:nil]]; [self applyBackgroundColor:[withDefault.bottomTabs.backgroundColor getWithDefaultValue:nil] translucent:[withDefault.bottomTabs.translucent getWithDefaultValue:NO]]; diff --git a/lib/ios/BottomTabsTogetherAttacher.m b/lib/ios/BottomTabsTogetherAttacher.m index 85264fb6e47..d94ac24d71e 100644 --- a/lib/ios/BottomTabsTogetherAttacher.m +++ b/lib/ios/BottomTabsTogetherAttacher.m @@ -1,9 +1,10 @@ #import "BottomTabsTogetherAttacher.h" +#import "RNNBottomTabsController.h" @implementation BottomTabsTogetherAttacher -- (void)attach:(UITabBarController *)bottomTabsController { - for (UIViewController* childViewController in bottomTabsController.childViewControllers) { +- (void)attach:(RNNBottomTabsController *)bottomTabsController { + for (UIViewController* childViewController in bottomTabsController.pendingChildViewControllers) { [childViewController render]; } diff --git a/lib/ios/RNNBottomTabsController.h b/lib/ios/RNNBottomTabsController.h index 2ee79c745cf..52d5dbb4469 100644 --- a/lib/ios/RNNBottomTabsController.h +++ b/lib/ios/RNNBottomTabsController.h @@ -21,4 +21,6 @@ - (void)setSelectedIndexByComponentID:(NSString *)componentID; +@property (nonatomic, strong) NSArray* pendingChildViewControllers; + @end diff --git a/lib/ios/RNNBottomTabsController.m b/lib/ios/RNNBottomTabsController.m index 455fb187cff..54419b51c7a 100644 --- a/lib/ios/RNNBottomTabsController.m +++ b/lib/ios/RNNBottomTabsController.m @@ -4,6 +4,7 @@ @interface RNNBottomTabsController () @property (nonatomic, strong) BottomTabPresenter* bottomTabPresenter; @property (nonatomic, strong) RNNDotIndicatorPresenter* dotIndicatorPresenter; +@property (nonatomic) BOOL viewWillAppearOnce; @end @implementation RNNBottomTabsController { @@ -25,6 +26,7 @@ - (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo _bottomTabsAttacher = bottomTabsAttacher; _bottomTabPresenter = bottomTabPresenter; _dotIndicatorPresenter = dotIndicatorPresenter; + _pendingChildViewControllers = childViewControllers; self = [super initWithLayoutInfo:layoutInfo creator:creator options:options defaultOptions:defaultOptions presenter:presenter eventEmitter:eventEmitter childViewControllers:childViewControllers]; if (@available(iOS 13.0, *)) { self.tabBar.standardAppearance = [UITabBarAppearance new]; @@ -32,6 +34,12 @@ - (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo return self; } +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + _viewWillAppearOnce = YES; + [self loadChildren:self.pendingChildViewControllers]; +} + - (void)onChildAddToParent:(UIViewController *)child options:(RNNNavigationOptions *)options { [_bottomTabPresenter applyOptionsOnWillMoveToParentViewController:options child:child]; } @@ -73,11 +81,14 @@ - (CGFloat)getBottomTabsHeight { } - (void)setSelectedIndexByComponentID:(NSString *)componentID { - for (id child in self.childViewControllers) { + NSArray* children = self.pendingChildViewControllers ?: self.childViewControllers; + for (id child in children) { UIViewController* vc = child; if ([vc conformsToProtocol:@protocol(RNNLayoutProtocol)] && [vc.layoutInfo.componentId isEqualToString:componentID]) { - [self setSelectedIndex:[self.childViewControllers indexOfObject:child]]; + NSUInteger selectedIndex = [children indexOfObject:child]; + [self setSelectedIndex:selectedIndex]; + _currentTabIndex = selectedIndex; } } } @@ -87,6 +98,18 @@ - (void)setSelectedIndex:(NSUInteger)selectedIndex { [super setSelectedIndex:selectedIndex]; } +- (UIViewController *)selectedViewController { + NSArray* children = self.pendingChildViewControllers ?: self.childViewControllers; + return children.count ? children[_currentTabIndex] : nil; +} + +- (void)loadChildren:(NSArray *)children { + if (self.viewWillAppearOnce) { + [super loadChildren:children]; + self.pendingChildViewControllers = nil; + } +} + #pragma mark UITabBarControllerDelegate - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController { diff --git a/lib/ios/RNNSplitViewController.m b/lib/ios/RNNSplitViewController.m index 98035729405..dbbb1d49921 100644 --- a/lib/ios/RNNSplitViewController.m +++ b/lib/ios/RNNSplitViewController.m @@ -10,7 +10,7 @@ - (void)setViewControllers:(NSArray<__kindof UIViewController *> *)viewControlle } - (UIViewController *)getCurrentChild { - return self.viewControllers[0]; + return self.viewControllers[0]; } # pragma mark - UIViewController overrides diff --git a/lib/ios/UIViewController+LayoutProtocol.h b/lib/ios/UIViewController+LayoutProtocol.h index 9efc78ffbc1..0f69a8feafb 100644 --- a/lib/ios/UIViewController+LayoutProtocol.h +++ b/lib/ios/UIViewController+LayoutProtocol.h @@ -42,6 +42,8 @@ typedef void (^RNNReactViewReadyCompletionBlock)(void); - (void)screenPopped; +- (void)loadChildren:(NSArray *)children; + @property (nonatomic, retain) RNNBasePresenter* presenter; @property (nonatomic, retain) RNNLayoutInfo* layoutInfo; @property (nonatomic, strong) RNNNavigationOptions* options; @@ -50,5 +52,6 @@ typedef void (^RNNReactViewReadyCompletionBlock)(void); @property (nonatomic) id creator; @property (nonatomic) RNNReactViewReadyCompletionBlock reactViewReadyCallback; @property (nonatomic) BOOL waitForRender; +@property (nonatomic) BOOL isChildViewControllersLoaded; @end diff --git a/lib/ios/UIViewController+LayoutProtocol.m b/lib/ios/UIViewController+LayoutProtocol.m index 02fb3eac910..804b8a93abd 100644 --- a/lib/ios/UIViewController+LayoutProtocol.m +++ b/lib/ios/UIViewController+LayoutProtocol.m @@ -12,7 +12,6 @@ - (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo eventEmitter:(RNNEventEmitter *)eventEmitter childViewControllers:(NSArray *)childViewControllers { self = [self init]; - self.options = options; self.defaultOptions = defaultOptions; self.layoutInfo = layoutInfo; @@ -21,9 +20,7 @@ - (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo self.presenter = presenter; [self.presenter bindViewController:self]; self.extendedLayoutIncludesOpaqueBars = YES; - if ([self respondsToSelector:@selector(setViewControllers:)]) { - [self performSelector:@selector(setViewControllers:) withObject:childViewControllers]; - } + [self loadChildren:childViewControllers]; [self.presenter applyOptionsOnInit:self.resolveOptions]; return self; @@ -74,6 +71,13 @@ - (void)render { [self.getCurrentChild render]; } +- (void)loadChildren:(NSArray *)children { + if (!self.isChildViewControllersLoaded && [self respondsToSelector:@selector(setViewControllers:)]) { + self.isChildViewControllersLoaded = YES; + [self performSelector:@selector(setViewControllers:) withObject:children]; + } +} + - (void)readyForPresentation { if (self.reactViewReadyCallback) { self.reactViewReadyCallback(); @@ -212,6 +216,14 @@ - (void)setEventEmitter:(RNNEventEmitter *)eventEmitter { objc_setAssociatedObject(self, @selector(eventEmitter), eventEmitter, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } +- (BOOL)isChildViewControllersLoaded { + return [objc_getAssociatedObject(self, @selector(isChildViewControllersLoaded)) boolValue]; +} + +- (void)setIsChildViewControllersLoaded:(BOOL)isChildViewControllersLoaded { + objc_setAssociatedObject(self, @selector(isChildViewControllersLoaded), [NSNumber numberWithBool:isChildViewControllersLoaded], OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + - (id)creator { return objc_getAssociatedObject(self, @selector(creator)); } diff --git a/playground/ios/NavigationIOS12Tests/RNNBottomTabsPresenterTest.m b/playground/ios/NavigationIOS12Tests/RNNBottomTabsPresenterTest.m index 35aa121337a..86d73182809 100644 --- a/playground/ios/NavigationIOS12Tests/RNNBottomTabsPresenterTest.m +++ b/playground/ios/NavigationIOS12Tests/RNNBottomTabsPresenterTest.m @@ -28,6 +28,7 @@ - (void)testApplyOptions_shouldSetDefaultEmptyOptions { [[(id)self.uut expect] applyBackgroundColor:nil translucent:NO]; [[self.boundViewController expect] setTabBarHideShadow:NO]; [[self.boundViewController expect] setTabBarStyle:UIBarStyleDefault]; + [[self.boundViewController expect] setTabBarVisible:YES animated:NO]; [self.uut applyOptions:emptyOptions]; [self.boundViewController verify]; } @@ -50,6 +51,16 @@ - (void)testApplyOptions_shouldApplyOptions { [self.boundViewController verify]; } +- (void)testApplyOptions_shouldRestoreHiddenTabBar { + RNNNavigationOptions *initialOptions = [[RNNNavigationOptions alloc] initEmptyOptions]; + initialOptions.bottomTabs.visible = [[Bool alloc] initWithValue:@(1)]; + + [[self.boundViewController expect] setTabBarVisible:YES animated:NO]; + + [self.uut applyOptions:initialOptions]; + [self.boundViewController verify]; +} + - (void)testApplyOptionsOnInit_alwaysShow_shouldNotCenterTabImages { RNNNavigationOptions *initialOptions = [[RNNNavigationOptions alloc] initEmptyOptions]; initialOptions.bottomTabs.titleDisplayMode = [[Text alloc] initWithValue:@"alwaysShow"]; diff --git a/playground/ios/NavigationIOS12Tests/RNNRootViewControllerTest.m b/playground/ios/NavigationIOS12Tests/RNNRootViewControllerTest.m index c4e24f49032..91c6f5f167a 100644 --- a/playground/ios/NavigationIOS12Tests/RNNRootViewControllerTest.m +++ b/playground/ios/NavigationIOS12Tests/RNNRootViewControllerTest.m @@ -172,6 +172,7 @@ -(void)testTabBadge { [self.uut setTabBarItem:item]; [controllers addObject:self.uut]; __unused RNNBottomTabsController* vc = [RNNBottomTabsController createWithChildren:controllers]; + [vc viewWillAppear:NO]; [self.uut willMoveToParentViewController:vc]; XCTAssertTrue([self.uut.tabBarItem.badgeValue isEqualToString:tabBadgeInput]); @@ -375,8 +376,8 @@ -(void)testOrientationTabsController_portrait { NSArray* supportedOrientations = @[@"portrait"]; self.options.layout.orientation = supportedOrientations; NSMutableArray* controllers = [[NSMutableArray alloc] initWithArray:@[self.uut]]; - __unused RNNBottomTabsController* vc = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:nil presenter:[RNNComponentPresenter new] eventEmitter:nil childViewControllers:controllers]; - + __unused RNNBottomTabsController* vc = [RNNBottomTabsController createWithChildren:controllers]; + [vc viewWillAppear:NO]; [self.uut viewWillAppear:false]; UIInterfaceOrientationMask expectedOrientation = UIInterfaceOrientationMaskPortrait; @@ -387,8 +388,8 @@ -(void)testOrientationTabsController_portraitAndLandscape { NSArray* supportedOrientations = @[@"portrait", @"landscape"]; self.options.layout.orientation = supportedOrientations; NSMutableArray* controllers = [[NSMutableArray alloc] initWithArray:@[self.uut]]; - __unused RNNBottomTabsController* vc = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:nil presenter:[RNNComponentPresenter new] eventEmitter:nil childViewControllers:controllers]; - + __unused RNNBottomTabsController* vc = [RNNBottomTabsController createWithChildren:controllers]; + [vc viewWillAppear:NO]; [self.uut viewWillAppear:false]; UIInterfaceOrientationMask expectedOrientation = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape); @@ -399,8 +400,8 @@ -(void)testOrientationTabsController_all { NSArray* supportedOrientations = @[@"all"]; self.options.layout.orientation = supportedOrientations; NSMutableArray* controllers = [[NSMutableArray alloc] initWithArray:@[self.uut]]; - __unused RNNBottomTabsController* vc = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:nil presenter:[RNNComponentPresenter new] eventEmitter:nil childViewControllers:controllers]; - + __unused RNNBottomTabsController* vc = [RNNBottomTabsController createWithChildren:controllers]; + [vc viewWillAppear:NO]; [self.uut viewWillAppear:false]; UIInterfaceOrientationMask expectedOrientation = UIInterfaceOrientationMaskAll; @@ -560,7 +561,7 @@ - (void)testOverrideOptions { - (RNNStackController *)createNavigationController { RNNStackController* nav = [[RNNStackController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:nil presenter:[[RNNStackPresenter alloc] init] eventEmitter:nil childViewControllers:@[self.uut]]; - + [nav viewWillAppear:NO]; return nav; } diff --git a/playground/ios/NavigationTests/BottomTabsControllerTest.m b/playground/ios/NavigationTests/BottomTabsControllerTest.m index 9948450f0ee..d1889243b2b 100644 --- a/playground/ios/NavigationTests/BottomTabsControllerTest.m +++ b/playground/ios/NavigationTests/BottomTabsControllerTest.m @@ -42,7 +42,8 @@ - (void)testInitWithLayoutInfo_shouldSetMultipleViewControllers { UIViewController *vc1 = [[UIViewController alloc] init]; UIViewController *vc2 = [[UIViewController alloc] init]; - RNNBottomTabsController *uut = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initWithDict:@{}] defaultOptions:nil presenter:[[RNNComponentPresenter alloc] init] eventEmitter:nil childViewControllers:@[vc1, vc2]]; + RNNBottomTabsController *uut = [RNNBottomTabsController createWithChildren:@[vc1, vc2]]; + [uut viewWillAppear:YES]; XCTAssertTrue(uut.viewControllers.count == 2); } @@ -51,32 +52,19 @@ - (void)testInitWithLayoutInfo_shouldInitializeDependencies { RNNNavigationOptions *options = [[RNNNavigationOptions alloc] initWithDict:@{}]; RNNBottomTabsPresenter *presenter = [[RNNBottomTabsPresenter alloc] init]; NSArray *childViewControllers = @[[UIViewController new]]; - - RNNBottomTabsController *uut = [[RNNBottomTabsController alloc] initWithLayoutInfo:layoutInfo creator:nil options:options defaultOptions:nil presenter:presenter eventEmitter:nil childViewControllers:childViewControllers]; - XCTAssertTrue(uut.layoutInfo == layoutInfo); - XCTAssertTrue(uut.options == options); - XCTAssertTrue(uut.presenter == presenter); - XCTAssertTrue(uut.childViewControllers.count == childViewControllers.count); -} - -- (void)testInitWithEventEmmiter_shouldInitializeDependencies { - RNNLayoutInfo *layoutInfo = [RNNLayoutInfo new]; - RNNNavigationOptions *options = [[RNNNavigationOptions alloc] initWithDict:@{}]; - RNNBottomTabsPresenter *presenter = [[RNNBottomTabsPresenter alloc] init]; - RNNEventEmitter *eventEmmiter = [RNNEventEmitter new]; - - NSArray *childViewControllers = @[[UIViewController new]]; - - RNNBottomTabsController *uut = [[RNNBottomTabsController alloc] initWithLayoutInfo:layoutInfo creator:nil options:options defaultOptions:nil presenter:presenter eventEmitter:eventEmmiter childViewControllers:childViewControllers]; + RNNEventEmitter *eventEmmiter = [RNNEventEmitter new]; + + RNNBottomTabsController *uut = [[RNNBottomTabsController alloc] initWithLayoutInfo:layoutInfo creator:nil options:options defaultOptions:nil presenter:presenter bottomTabPresenter:nil dotIndicatorPresenter:nil eventEmitter:eventEmmiter childViewControllers:childViewControllers bottomTabsAttacher:nil]; + [uut viewWillAppear:YES]; XCTAssertTrue(uut.layoutInfo == layoutInfo); XCTAssertTrue(uut.options == options); XCTAssertTrue(uut.presenter == presenter); XCTAssertTrue(uut.childViewControllers.count == childViewControllers.count); - XCTAssertTrue(uut.eventEmitter == eventEmmiter); + XCTAssertTrue(uut.eventEmitter == eventEmmiter); } - (void)testInitWithLayoutInfo_shouldSetDelegate { - RNNBottomTabsController *uut = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initWithDict:@{}] defaultOptions:nil presenter:[[RNNBasePresenter alloc] init] eventEmitter:nil childViewControllers:nil]; + RNNBottomTabsController *uut = [RNNBottomTabsController createWithChildren:@[]]; XCTAssertTrue(uut.delegate == uut); } @@ -179,7 +167,9 @@ - (void)testSetSelectedIndexByComponentID_ShouldSetSelectedIndexWithCorrectIndex RNNComponentViewController *vc = [[RNNComponentViewController alloc] initWithLayoutInfo:layoutInfo rootViewCreator:nil eventEmitter:nil presenter:nil options:nil defaultOptions:nil]; - RNNBottomTabsController *uut = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:[RNNBottomTabsPresenter new] eventEmitter:nil childViewControllers:@[[UIViewController new], vc]]; + RNNBottomTabsController *uut = [RNNBottomTabsController createWithChildren:@[[UIViewController new], vc]]; + [uut viewWillAppear:YES]; + [uut setSelectedIndexByComponentID:@"componentId"]; XCTAssertTrue(uut.selectedIndex == 1); } @@ -189,7 +179,8 @@ - (void)testSetSelectedIndex_ShouldSetSelectedIndexWithCurrentTabIndex { options.bottomTabs.currentTabIndex = [[IntNumber alloc] initWithValue:@(1)]; RNNComponentViewController *vc = [[RNNComponentViewController alloc] initWithLayoutInfo:nil rootViewCreator:nil eventEmitter:nil presenter:nil options:nil defaultOptions:nil]; - RNNBottomTabsController *uut = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:options defaultOptions:nil presenter:[RNNBottomTabsPresenter new] eventEmitter:nil childViewControllers:@[[UIViewController new], vc]]; + RNNBottomTabsController *uut = [RNNBottomTabsController createWithChildren:@[[UIViewController new], vc] options:options]; + [uut viewWillAppear:YES]; XCTAssertTrue(uut.selectedIndex == 1); } diff --git a/playground/ios/NavigationTests/RNNBottomTabsAppearancePresenterTest.m b/playground/ios/NavigationTests/RNNBottomTabsAppearancePresenterTest.m index 5ae801d08b2..a79a415bb3b 100644 --- a/playground/ios/NavigationTests/RNNBottomTabsAppearancePresenterTest.m +++ b/playground/ios/NavigationTests/RNNBottomTabsAppearancePresenterTest.m @@ -26,6 +26,7 @@ - (void)setUp { self.dotIndicatorPresenter = [OCMockObject partialMockForObject:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:nil]]; self.uut = [OCMockObject partialMockForObject:[BottomTabsPresenterCreator createWithDefaultOptions:nil]]; self.boundViewController = [OCMockObject partialMockForObject:[[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:self.uut bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:nil] dotIndicatorPresenter:self.dotIndicatorPresenter eventEmitter:nil childViewControllers:self.children bottomTabsAttacher:nil]]; + [self.boundViewController viewWillAppear:YES]; [self.uut bindViewController:self.boundViewController]; self.options = [[RNNNavigationOptions alloc] initEmptyOptions]; } @@ -35,7 +36,8 @@ - (void)testApplyOptions_shouldSetDefaultEmptyOptions { [[self.boundViewController expect] setTabBarTestID:nil]; [[(id)self.uut expect] applyBackgroundColor:nil translucent:NO]; [[self.boundViewController expect] setTabBarHideShadow:NO]; - [[self.boundViewController expect] setTabBarStyle:UIBarStyleDefault]; + [[self.boundViewController expect] setTabBarVisible:YES animated:NO]; + [[self.boundViewController expect] setTabBarStyle:UIBarStyleDefault]; [self.uut applyOptions:emptyOptions]; [self.boundViewController verify]; } @@ -58,6 +60,16 @@ - (void)testApplyOptions_shouldApplyOptions { [self.boundViewController verify]; } +- (void)testApplyOptions_shouldRestoreHiddenTabBar { + RNNNavigationOptions *initialOptions = [[RNNNavigationOptions alloc] initEmptyOptions]; + initialOptions.bottomTabs.visible = [[Bool alloc] initWithValue:@(1)]; + + [[self.boundViewController expect] setTabBarVisible:YES animated:NO]; + + [self.uut applyOptions:initialOptions]; + [self.boundViewController verify]; +} + - (void)testApplyOptionsOnInit_alwaysShow_shouldNotCenterTabImages { RNNNavigationOptions *initialOptions = [[RNNNavigationOptions alloc] initEmptyOptions]; initialOptions.bottomTabs.titleDisplayMode = [[Text alloc] initWithValue:@"alwaysShow"]; diff --git a/playground/ios/NavigationTests/RNNBottomTabsController+Helpers.h b/playground/ios/NavigationTests/RNNBottomTabsController+Helpers.h index 35f6c9937a9..f7ba0d56841 100644 --- a/playground/ios/NavigationTests/RNNBottomTabsController+Helpers.h +++ b/playground/ios/NavigationTests/RNNBottomTabsController+Helpers.h @@ -7,4 +7,6 @@ + (RNNBottomTabsController *)createWithChildren:(NSArray *)children; ++ (RNNBottomTabsController *)createWithChildren:(NSArray *)children options:(RNNNavigationOptions *)options; + @end diff --git a/playground/ios/NavigationTests/RNNBottomTabsController+Helpers.m b/playground/ios/NavigationTests/RNNBottomTabsController+Helpers.m index 58c099beffc..4d1b02fc541 100644 --- a/playground/ios/NavigationTests/RNNBottomTabsController+Helpers.m +++ b/playground/ios/NavigationTests/RNNBottomTabsController+Helpers.m @@ -5,13 +5,16 @@ @implementation RNNBottomTabsController (Helpers) + (RNNBottomTabsController *)create { - RNNNavigationOptions* defaultOptions = [[RNNNavigationOptions alloc] initEmptyOptions]; return [self createWithChildren:nil]; } + (RNNBottomTabsController *)createWithChildren:(NSArray *)children { + return [self createWithChildren:children options:[[RNNNavigationOptions alloc] initEmptyOptions]]; +} + ++ (RNNBottomTabsController *)createWithChildren:(NSArray *)children options:(RNNNavigationOptions *)options { RNNNavigationOptions* defaultOptions = [[RNNNavigationOptions alloc] initEmptyOptions]; - return [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:defaultOptions presenter:[BottomTabsPresenterCreator createWithDefaultOptions:defaultOptions] bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:defaultOptions] dotIndicatorPresenter:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:defaultOptions] eventEmitter:nil childViewControllers:children bottomTabsAttacher:nil]; + return [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:options defaultOptions:defaultOptions presenter:[BottomTabsPresenterCreator createWithDefaultOptions:defaultOptions] bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:defaultOptions] dotIndicatorPresenter:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:defaultOptions] eventEmitter:nil childViewControllers:children bottomTabsAttacher:nil]; } @end diff --git a/playground/ios/NavigationTests/RNNCommandsHandlerTest.m b/playground/ios/NavigationTests/RNNCommandsHandlerTest.m index d2ecf461c19..5703596bb7a 100644 --- a/playground/ios/NavigationTests/RNNCommandsHandlerTest.m +++ b/playground/ios/NavigationTests/RNNCommandsHandlerTest.m @@ -382,7 +382,7 @@ - (void)testSetRoot_withBottomTabsAttachModeOnSwitchToTab { BottomTabsBaseAttacher* attacher = [[[BottomTabsAttachModeFactory alloc] initWithDefaultOptions:nil] fromOptions:options]; RNNBottomTabsController* tabBarController = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:options defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:[RNNBasePresenter new] bottomTabPresenter:nil dotIndicatorPresenter:nil eventEmitter:_eventEmmiter childViewControllers:@[_vc1, _vc2] bottomTabsAttacher:attacher]; - + [tabBarController viewWillAppear:YES]; OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(tabBarController); [self.uut setRoot:@{} commandId:@"" completion:^{}]; @@ -400,7 +400,8 @@ - (void)testSetRoot_withBottomTabsAttachModeAfterInitialTab { BottomTabsBaseAttacher* attacher = [[[BottomTabsAttachModeFactory alloc] initWithDefaultOptions:nil] fromOptions:options]; RNNBottomTabsController* tabBarController = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:options defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:[RNNBasePresenter new] bottomTabPresenter:nil dotIndicatorPresenter:nil eventEmitter:_eventEmmiter childViewControllers:@[_vc1, _vc2] bottomTabsAttacher:attacher]; - + [tabBarController viewWillAppear:YES]; + OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(tabBarController); [self.uut setRoot:@{} commandId:@"" completion:^{ @@ -424,6 +425,7 @@ - (void)testMergeOptions_shouldMergeWithChildOnly { RNNComponentViewController* secondChild = [RNNComponentViewController createWithComponentId:@"second" initialOptions:secondChildOptions]; RNNBottomTabsController* tabBarController = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[RNNNavigationOptions emptyOptions] defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:[RNNBasePresenter new] bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:[RNNNavigationOptions emptyOptions]] dotIndicatorPresenter:nil eventEmitter:_eventEmmiter childViewControllers:@[firstChild, secondChild] bottomTabsAttacher:nil]; + [tabBarController viewWillAppear:YES]; OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(tabBarController); [self.mainWindow setRootViewController:tabBarController]; @@ -455,6 +457,7 @@ - (void)testMergeOptions_shouldResolveTreeOptions { RNNComponentViewController* secondChild = [RNNComponentViewController createWithComponentId:@"second" initialOptions:secondChildOptions]; RNNBottomTabsController* tabBarController = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[RNNNavigationOptions emptyOptions] defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:[RNNBasePresenter new] bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:[RNNNavigationOptions emptyOptions]] dotIndicatorPresenter:nil eventEmitter:_eventEmmiter childViewControllers:@[stack, secondChild] bottomTabsAttacher:nil]; + [tabBarController viewWillAppear:YES]; OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(tabBarController); [self.mainWindow setRootViewController:tabBarController]; diff --git a/playground/ios/NavigationTests/RNNControllerFactoryTest.m b/playground/ios/NavigationTests/RNNControllerFactoryTest.m index a674f45214f..77180948951 100644 --- a/playground/ios/NavigationTests/RNNControllerFactoryTest.m +++ b/playground/ios/NavigationTests/RNNControllerFactoryTest.m @@ -115,7 +115,7 @@ - (void)testCreateLayout_BottomTabsLayout { @"data": @{}, @"children": @[]}]}]}; RNNBottomTabsController* tabBar = (RNNBottomTabsController*) [self.factory createLayout:layout]; - + [tabBar viewWillAppear:YES]; XCTAssertTrue([tabBar isMemberOfClass:[RNNBottomTabsController class]]); XCTAssertTrue(tabBar.childViewControllers.count == 1); XCTAssertTrue([tabBar.childViewControllers[0] isMemberOfClass:[RNNStackController class]]); diff --git a/playground/ios/NavigationTests/RNNRootViewControllerTest.m b/playground/ios/NavigationTests/RNNRootViewControllerTest.m index 00ac960904e..27d791137e8 100644 --- a/playground/ios/NavigationTests/RNNRootViewControllerTest.m +++ b/playground/ios/NavigationTests/RNNRootViewControllerTest.m @@ -182,6 +182,7 @@ - (void)testTabBadge { NSMutableArray* controllers = [NSMutableArray new]; [controllers addObject:self.uut]; __unused RNNBottomTabsController* vc = [RNNBottomTabsController createWithChildren:controllers]; + [vc viewWillAppear:NO]; [self.uut willMoveToParentViewController:vc]; XCTAssertTrue([self.uut.tabBarItem.badgeValue isEqualToString:tabBadgeInput]); @@ -369,9 +370,8 @@ - (void)testOrientationTabsController_portrait { self.options.layout.orientation = supportedOrientations; NSMutableArray* controllers = [[NSMutableArray alloc] initWithArray:@[self.uut]]; __unused RNNBottomTabsController* vc = [RNNBottomTabsController createWithChildren:controllers]; - - [self.uut viewWillAppear:false]; - + [vc viewWillAppear:NO]; + [self.uut viewWillAppear:NO]; UIInterfaceOrientationMask expectedOrientation = UIInterfaceOrientationMaskPortrait; XCTAssertTrue(self.uut.tabBarController.supportedInterfaceOrientations == expectedOrientation); } @@ -381,8 +381,8 @@ - (void)testOrientationTabsController_portraitAndLandscape { self.options.layout.orientation = supportedOrientations; NSMutableArray* controllers = [[NSMutableArray alloc] initWithArray:@[self.uut]]; __unused RNNBottomTabsController* vc = [RNNBottomTabsController createWithChildren:controllers]; - - [self.uut viewWillAppear:false]; + [vc viewWillAppear:NO]; + [self.uut viewWillAppear:NO]; UIInterfaceOrientationMask expectedOrientation = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape); XCTAssertTrue(self.uut.tabBarController.supportedInterfaceOrientations == expectedOrientation); @@ -393,8 +393,8 @@ - (void)testOrientationTabsController_all { self.options.layout.orientation = supportedOrientations; NSMutableArray* controllers = [[NSMutableArray alloc] initWithArray:@[self.uut]]; __unused RNNBottomTabsController* vc = [RNNBottomTabsController createWithChildren:controllers]; - - [self.uut viewWillAppear:false]; + [vc viewWillAppear:NO]; + [self.uut viewWillAppear:NO]; UIInterfaceOrientationMask expectedOrientation = UIInterfaceOrientationMaskAll; XCTAssertTrue(self.uut.tabBarController.supportedInterfaceOrientations == expectedOrientation); @@ -553,7 +553,7 @@ - (void)testOverrideOptions { - (RNNStackController *)createNavigationController { RNNStackController* nav = [[RNNStackController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:nil presenter:[[RNNStackPresenter alloc] init] eventEmitter:nil childViewControllers:@[self.uut]]; - + return nav; } diff --git a/playground/ios/NavigationTests/UIViewController+LayoutProtocolTest.m b/playground/ios/NavigationTests/UIViewController+LayoutProtocolTest.m index f6ef159735a..c3432b79c4e 100644 --- a/playground/ios/NavigationTests/UIViewController+LayoutProtocolTest.m +++ b/playground/ios/NavigationTests/UIViewController+LayoutProtocolTest.m @@ -37,6 +37,24 @@ - (void)testInitWithLayoutInfoShouldSetChildViewControllers { NSArray* childViewControllers = @[child1, child2]; UINavigationController* uut = [[UINavigationController alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:nil eventEmitter:nil childViewControllers:childViewControllers]; + XCTAssertEqual(uut.viewControllers.count, 2); +} + +- (void)testInitBottomTabsWithLayoutInfoShouldNotSetChildViewControllers { + UIViewController* child1 = [UIViewController new]; + UIViewController* child2 = [UIViewController new]; + NSArray* childViewControllers = @[child1, child2]; + RNNBottomTabsController* uut = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:nil eventEmitter:nil childViewControllers:childViewControllers]; + + XCTAssertEqual(uut.viewControllers.count, 0); +} + +- (void)testLoadChildrenShouldSetChildViewControllers { + UIViewController* child1 = [UIViewController new]; + UIViewController* child2 = [UIViewController new]; + NSArray* childViewControllers = @[child1, child2]; + UINavigationController* uut = [[UINavigationController alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:nil eventEmitter:nil childViewControllers:childViewControllers]; + [uut loadChildren:childViewControllers]; XCTAssertEqual(uut.viewControllers[0], child1); XCTAssertEqual(uut.viewControllers[1], child2); } diff --git a/playground/src/screens/SetRootScreen.js b/playground/src/screens/SetRootScreen.js index 908ebab6125..3134923cc84 100644 --- a/playground/src/screens/SetRootScreen.js +++ b/playground/src/screens/SetRootScreen.js @@ -5,7 +5,10 @@ const Navigation = require('./../services/Navigation'); const { NAVIGATION_TAB, SET_MULTIPLE_ROOTS_BTN, - SET_ROOT_BTN + SET_ROOT_BTN, + LAYOUTS_TAB, + SET_ROOT_HIDES_BOTTOM_TABS_BTN, + SET_ROOT_WITH_STACK_HIDES_BOTTOM_TABS_BTN } = require('../testIDs'); const Screens = require('./Screens'); const { logLifecycleEvent } = require('./StaticLifecycleOverlay'); @@ -37,6 +40,8 @@ class SetRootScreen extends React.Component {