diff --git a/lib/ios/RNNComponentPresenter.m b/lib/ios/RNNComponentPresenter.m index 66b511f50cf..1a0b9a8ced2 100644 --- a/lib/ios/RNNComponentPresenter.m +++ b/lib/ios/RNNComponentPresenter.m @@ -28,9 +28,6 @@ - (void)boundViewController:(UIViewController *)boundViewController { - (void)applyOptionsOnWillMoveToParentViewController:(RNNNavigationOptions *)options { [super applyOptionsOnWillMoveToParentViewController:options]; - UIViewController* viewController = self.boundViewController; - RNNNavigationOptions *withDefault = [options withDefault:[self defaultOptions]]; - [viewController setBackButtonIcon:[withDefault.topBar.backButton.icon getWithDefaultValue:nil] withColor:[withDefault.topBar.backButton.color getWithDefaultValue:nil] title:[withDefault.topBar.backButton.showTitle getWithDefaultValue:YES] ? [withDefault.topBar.backButton.title getWithDefaultValue:nil] : @""]; } - (void)applyOptions:(RNNNavigationOptions *)options { @@ -158,12 +155,6 @@ - (void)mergeOptions:(RNNNavigationOptions *)options resolvedOptions:(RNNNavigat } [self setTitleViewWithSubtitle:withDefault]; - - if (options.topBar.backButton.hasValue) { - UIViewController *lastViewControllerInStack = viewController.navigationController.viewControllers.count > 1 ? viewController.navigationController.viewControllers[viewController.navigationController.viewControllers.count - 2] : viewController.navigationController.topViewController; - RNNNavigationOptions * resolvedOptions = (RNNNavigationOptions *) [[currentOptions overrideOptions:options] withDefault:[self defaultOptions]]; - [lastViewControllerInStack applyBackButton:resolvedOptions.topBar.backButton]; - } } - (void)removeTitleComponentIfNeeded:(RNNNavigationOptions *)options { diff --git a/lib/ios/RNNStackPresenter.m b/lib/ios/RNNStackPresenter.m index 622d4448335..227a36234c9 100644 --- a/lib/ios/RNNStackPresenter.m +++ b/lib/ios/RNNStackPresenter.m @@ -44,6 +44,7 @@ - (void)applyOptions:(RNNNavigationOptions *)options { [stack setNavigationBarLargeTitleFontFamily:[withDefault.topBar.largeTitle.fontFamily getWithDefaultValue:nil] fontSize:[withDefault.topBar.largeTitle.fontSize getWithDefaultValue:nil] fontWeight:[withDefault.topBar.largeTitle.fontWeight getWithDefaultValue:nil] color:[withDefault.topBar.largeTitle.color getWithDefaultValue:nil]]; [stack setNavigationBarFontFamily:[withDefault.topBar.title.fontFamily getWithDefaultValue:nil] fontSize:[withDefault.topBar.title.fontSize getWithDefaultValue:nil] fontWeight:[withDefault.topBar.title.fontWeight getWithDefaultValue:nil] color:[withDefault.topBar.title.color getWithDefaultValue:nil]]; [stack setBackButtonColor:[withDefault.topBar.backButton.color getWithDefaultValue:nil]]; + [stack setBackButtonIcon:[withDefault.topBar.backButton.icon getWithDefaultValue:nil] withColor:[withDefault.topBar.backButton.color getWithDefaultValue:nil] title:[withDefault.topBar.backButton.title getWithDefaultValue:nil] showTitle:[withDefault.topBar.backButton.showTitle getWithDefaultValue:YES]]; } - (void)applyOptionsOnViewDidLayoutSubviews:(RNNNavigationOptions *)options { @@ -59,6 +60,7 @@ - (void)applyOptionsBeforePopping:(RNNNavigationOptions *)options { [navigationController setTopBarBackgroundColor:[withDefault.topBar.background.color getWithDefaultValue:nil]]; [navigationController setNavigationBarFontFamily:[withDefault.topBar.title.fontFamily getWithDefaultValue:nil] fontSize:[withDefault.topBar.title.fontSize getWithDefaultValue:nil] fontWeight:[withDefault.topBar.title.fontWeight getWithDefaultValue:nil] color:[withDefault.topBar.title.color getWithDefaultValue:nil]]; [navigationController setNavigationBarLargeTitleVisible:[withDefault.topBar.largeTitle.visible getWithDefaultValue:NO]]; + [navigationController setBackButtonIcon:[withDefault.topBar.backButton.icon getWithDefaultValue:nil] withColor:[withDefault.topBar.backButton.color getWithDefaultValue:nil] title:[withDefault.topBar.backButton.title getWithDefaultValue:nil] showTitle:[withDefault.topBar.backButton.showTitle getWithDefaultValue:YES]]; } - (void)mergeOptions:(RNNNavigationOptions *)options resolvedOptions:(RNNNavigationOptions *)resolvedOptions { @@ -135,6 +137,10 @@ - (void)mergeOptions:(RNNNavigationOptions *)options resolvedOptions:(RNNNavigat if (options.topBar.background.component.name.hasValue) { [self setCustomNavigationComponentBackground:options perform:nil]; } + + if (options.topBar.backButton.hasValue) { + [stack setBackButtonIcon:[withDefault.topBar.backButton.icon getWithDefaultValue:nil] withColor:[withDefault.topBar.backButton.color getWithDefaultValue:nil] title:[withDefault.topBar.backButton.title getWithDefaultValue:nil] showTitle:[withDefault.topBar.backButton.showTitle getWithDefaultValue:YES]]; + } } - (void)renderComponents:(RNNNavigationOptions *)options perform:(RNNReactViewReadyCompletionBlock)readyBlock { diff --git a/lib/ios/UINavigationBar+utils.h b/lib/ios/UINavigationBar+utils.h index 4531089f0e2..54d507f263c 100644 --- a/lib/ios/UINavigationBar+utils.h +++ b/lib/ios/UINavigationBar+utils.h @@ -6,4 +6,6 @@ - (void)rnn_setBackgroundColorTransparent; +- (void)rnn_setBackIndicatorImage:(UIImage *)image; + @end diff --git a/lib/ios/UINavigationBar+utils.m b/lib/ios/UINavigationBar+utils.m index e675689873b..46fc8fa5ddb 100644 --- a/lib/ios/UINavigationBar+utils.m +++ b/lib/ios/UINavigationBar+utils.m @@ -57,6 +57,16 @@ - (void)removeTransparentView { } } +- (void)rnn_setBackIndicatorImage:(UIImage *)image { + if (@available(iOS 13.0, *)) { + [[self getNavigaitonBarStandardAppearance] setBackIndicatorImage:image transitionMaskImage:image]; + [[self getNavigaitonBarCompactAppearance] setBackIndicatorImage:image transitionMaskImage:image]; + [[self getNavigaitonBarScrollEdgeAppearance] setBackIndicatorImage:image transitionMaskImage:image]; + } else { + [self setBackIndicatorImage:image]; + [self setBackIndicatorTransitionMaskImage:image]; + } +} - (UINavigationBarAppearance*)getNavigaitonBarStandardAppearance API_AVAILABLE(ios(13.0)) { if (!self.standardAppearance) { diff --git a/lib/ios/UINavigationController+RNNOptions.h b/lib/ios/UINavigationController+RNNOptions.h index 349cfa73cd8..b655742d277 100644 --- a/lib/ios/UINavigationController+RNNOptions.h +++ b/lib/ios/UINavigationController+RNNOptions.h @@ -30,4 +30,6 @@ - (void)setBackButtonColor:(UIColor *)color; +- (void)setBackButtonIcon:(UIImage *)icon withColor:(UIColor *)color title:(NSString *)title showTitle:(BOOL)showTitle; + @end diff --git a/lib/ios/UINavigationController+RNNOptions.m b/lib/ios/UINavigationController+RNNOptions.m index f0e48897012..9fdffb3bac6 100644 --- a/lib/ios/UINavigationController+RNNOptions.m +++ b/lib/ios/UINavigationController+RNNOptions.m @@ -1,5 +1,7 @@ #import "UINavigationController+RNNOptions.h" #import "RNNFontAttributesCreator.h" +#import "UIImage+tint.h" +#import "UINavigationBar+utils.h" const NSInteger BLUR_TOPBAR_TAG = 78264802; @@ -103,4 +105,24 @@ - (void)setNavigationBarClipsToBounds:(BOOL)clipsToBounds { self.navigationBar.clipsToBounds = clipsToBounds; } +- (void)setBackButtonIcon:(UIImage *)icon withColor:(UIColor *)color title:(NSString *)title showTitle:(BOOL)showTitle { + UIBarButtonItem *backItem = [[UIBarButtonItem alloc] init]; + if (icon) { + icon = color + ? [[icon withTintColor:color] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] + : icon; + } + + [self.navigationBar rnn_setBackIndicatorImage:icon]; + + UIViewController *lastViewControllerInStack = self.viewControllers.count > 1 ? self.viewControllers[self.viewControllers.count - 2] : self.topViewController; + + if (showTitle) { + backItem.title = title ? title : lastViewControllerInStack.navigationItem.title; + } + backItem.tintColor = color; + + lastViewControllerInStack.navigationItem.backBarButtonItem = backItem; +} + @end diff --git a/lib/ios/UIViewController+RNNOptions.h b/lib/ios/UIViewController+RNNOptions.h index bc9dc4c6180..1465ffb4043 100644 --- a/lib/ios/UIViewController+RNNOptions.h +++ b/lib/ios/UIViewController+RNNOptions.h @@ -34,8 +34,6 @@ - (void)setInterceptTouchOutside:(BOOL)interceptTouchOutside; -- (void)setBackButtonIcon:(UIImage *)icon withColor:(UIColor *)color title:(NSString *)title; - - (void)applyBackButton:(RNNBackButtonOptions *)backButton; - (BOOL)isModal; diff --git a/lib/ios/UIViewController+RNNOptions.m b/lib/ios/UIViewController+RNNOptions.m index 060424d0664..01bebea9150 100644 --- a/lib/ios/UIViewController+RNNOptions.m +++ b/lib/ios/UIViewController+RNNOptions.m @@ -1,6 +1,7 @@ #import "UIViewController+RNNOptions.h" #import #import "UIImage+tint.h" +#import "UINavigationBar+utils.h" #import "RNNBottomTabOptions.h" #import "RNNNavigationOptions.h" #import "RNNBackButtonOptions.h" @@ -160,25 +161,6 @@ - (void)setInterceptTouchOutside:(BOOL)interceptTouchOutside { } } -- (void)setBackButtonIcon:(UIImage *)icon withColor:(UIColor *)color title:(NSString *)title { - UIBarButtonItem *backItem = [[UIBarButtonItem alloc] init]; - if (icon) { - backItem.image = color - ? [[icon withTintColor:color] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] - : icon; - - [self.navigationController.navigationBar setBackIndicatorImage:[UIImage new]]; - [self.navigationController.navigationBar setBackIndicatorTransitionMaskImage:[UIImage new]]; - } - - UIViewController *lastViewControllerInStack = self.navigationController.viewControllers.count > 1 ? self.navigationController.viewControllers[self.navigationController.viewControllers.count - 2] : self.navigationController.topViewController; - - backItem.title = title ? title : lastViewControllerInStack.navigationItem.title; - backItem.tintColor = color; - - lastViewControllerInStack.navigationItem.backBarButtonItem = backItem; -} - - (void)applyBackButton:(RNNBackButtonOptions *)backButton { UIBarButtonItem *backItem = [UIBarButtonItem new]; if (backButton.icon.hasValue) { diff --git a/playground/ios/NavigationTests/RNNComponentPresenterTest.m b/playground/ios/NavigationTests/RNNComponentPresenterTest.m index 869be82653c..9cb4db0e50b 100644 --- a/playground/ios/NavigationTests/RNNComponentPresenterTest.m +++ b/playground/ios/NavigationTests/RNNComponentPresenterTest.m @@ -173,37 +173,6 @@ - (void)testRenderComponentsCreateReactViewWithBoundComponentId { XCTAssertEqual(self.uut.boundComponentId, @"componentId"); } -- (void)testApplyOptionsOnWillMoveToParent_shouldSetBackButtonOnBoundViewController_withTitle { - Text* title = [[Text alloc] initWithValue:@"Title"]; - self.options.topBar.backButton.title = title; - [[(id) self.boundViewController expect] setBackButtonIcon:nil withColor:nil title:title.get]; - [self.uut applyOptionsOnWillMoveToParentViewController:self.options]; - [(id)self.boundViewController verify]; -} - -- (void)testApplyOptionsOnWillMoveToParent_shouldSetBackButtonOnBoundViewController_withHideTitle { - Text* title = [[Text alloc] initWithValue:@"Title"]; - self.options.topBar.backButton.title = title; - self.options.topBar.backButton.showTitle = [[Bool alloc] initWithValue:@(0)]; - [[(id) self.boundViewController expect] setBackButtonIcon:nil withColor:nil title:@""]; - [self.uut applyOptionsOnWillMoveToParentViewController:self.options]; - [(id)self.boundViewController verify]; -} - -- (void)testApplyOptionsOnWillMoveToParent_shouldSetBackButtonOnBoundViewController_withIcon { - Image* image = [[Image alloc] initWithValue:[UIImage new]]; - self.options.topBar.backButton.icon = image; - [[(id) self.boundViewController expect] setBackButtonIcon:image.get withColor:nil title:nil]; - [self.uut applyOptionsOnWillMoveToParentViewController:self.options]; - [(id)self.boundViewController verify]; -} - -- (void)testApplyOptionsOnWillMoveToParent_shouldSetBackButtonOnBoundViewController_withDefaultValues { - [[(id) self.boundViewController expect] setBackButtonIcon:nil withColor:nil title:nil]; - [self.uut applyOptionsOnWillMoveToParentViewController:self.options]; - [(id)self.boundViewController verify]; -} - - (void)testRemoveTitleComponentIfNeeded_componentIsRemovedIfTitleTextIsDefined { id mockTitle = [OCMockObject niceMockForClass:[RNNReactView class]]; OCMStub([self.componentRegistry createComponentIfNotExists:[OCMArg any] parentComponentId:[OCMArg any] reactViewReadyBlock:nil]).andReturn(mockTitle); diff --git a/playground/ios/NavigationTests/RNNStackPresenterTest.m b/playground/ios/NavigationTests/RNNStackPresenterTest.m index 0b747d9de2e..3dc91f1b904 100644 --- a/playground/ios/NavigationTests/RNNStackPresenterTest.m +++ b/playground/ios/NavigationTests/RNNStackPresenterTest.m @@ -57,4 +57,35 @@ - (void)testApplyOptionsBeforePoppingShouldSetDefaultLargeTitleFalseForPoppingVi XCTAssertFalse([[self.uut.boundViewController navigationBar] prefersLargeTitles]); } +- (void)testApplyOptions_shouldSetBackButtonOnBoundViewController_withTitle { + Text* title = [[Text alloc] initWithValue:@"Title"]; + self.options.topBar.backButton.title = title; + [[_boundViewController expect] setBackButtonIcon:nil withColor:nil title:title.get showTitle:YES]; + [self.uut applyOptions:self.options]; + [_boundViewController verify]; +} + +- (void)testApplyOptions_shouldSetBackButtonOnBoundViewController_withHideTitle { + Text* title = [[Text alloc] initWithValue:@"Title"]; + self.options.topBar.backButton.title = title; + self.options.topBar.backButton.showTitle = [[Bool alloc] initWithValue:@(0)]; + [[(id) self.boundViewController expect] setBackButtonIcon:nil withColor:nil title:title.get showTitle:self.options.topBar.backButton.showTitle.get]; + [self.uut applyOptions:self.options]; + [(id)self.boundViewController verify]; +} + +- (void)testApplyOptions_shouldSetBackButtonOnBoundViewController_withIcon { + Image* image = [[Image alloc] initWithValue:[UIImage new]]; + self.options.topBar.backButton.icon = image; + [[(id) self.boundViewController expect] setBackButtonIcon:image.get withColor:nil title:nil showTitle:YES]; + [self.uut applyOptions:self.options]; + [(id)self.boundViewController verify]; +} + +- (void)testApplyOptions_shouldSetBackButtonOnBoundViewController_withDefaultValues { + [[(id) self.boundViewController expect] setBackButtonIcon:nil withColor:nil title:nil showTitle:YES]; + [self.uut applyOptions:self.options]; + [(id)self.boundViewController verify]; +} + @end diff --git a/playground/ios/NavigationTests/UINavigationController+RNNOptionsTest.m b/playground/ios/NavigationTests/UINavigationController+RNNOptionsTest.m index b6842fe3a98..1591adacb63 100644 --- a/playground/ios/NavigationTests/UINavigationController+RNNOptionsTest.m +++ b/playground/ios/NavigationTests/UINavigationController+RNNOptionsTest.m @@ -11,4 +11,42 @@ - (void)setUp { [super setUp]; } +- (void)testSetBackButtonIcon_withColor_shouldSetColor { + UIViewController* vc = [UIViewController new]; + UINavigationController* uut = [[UINavigationController alloc] initWithRootViewController:vc]; + UIColor* color = [UIColor blackColor]; + + [uut setBackButtonIcon:nil withColor:color title:nil showTitle:nil]; + XCTAssertEqual(color, vc.navigationItem.backBarButtonItem.tintColor); +} + +- (void)testSetBackButtonIcon_withColor_shouldSetTitle { + UIViewController* vc = [UIViewController new]; + UINavigationController* uut = [[UINavigationController alloc] initWithRootViewController:vc]; + NSString* title = @"Title"; + + [uut setBackButtonIcon:nil withColor:nil title:title showTitle:YES]; + XCTAssertEqual(title, vc.navigationItem.backBarButtonItem.title); +} + +//- (void)testSetBackButtonIcon_withColor_shouldSetIcon { +// UIViewController* vc = [UIViewController new]; +// UINavigationController* uut = [[UINavigationController alloc] initWithRootViewController:vc]; +// UIImage* icon = [UIImage new]; +// +// [uut setBackButtonIcon:icon withColor:nil title:nil showTitle:nil]; +// XCTAssertEqual(icon, vc.navigationItem.backBarButtonItem.image); +//} + +- (void)testSetBackButtonIcon_shouldSetTitleOnPreviousViewControllerIfExists { + UIViewController* viewController1 = [UIViewController new]; + UIViewController* viewController2 = [UIViewController new]; + UINavigationController* uut = [[UINavigationController alloc] init]; + [uut setViewControllers:@[viewController1, viewController2]]; + NSString* title = @"Title"; + + [uut setBackButtonIcon:nil withColor:nil title:title showTitle:YES]; + XCTAssertEqual(title, viewController1.navigationItem.backBarButtonItem.title); +} + @end diff --git a/playground/ios/NavigationTests/UIViewController+LayoutProtocolTest.m b/playground/ios/NavigationTests/UIViewController+LayoutProtocolTest.m index 8473908b390..3ebb8ff8ea4 100644 --- a/playground/ios/NavigationTests/UIViewController+LayoutProtocolTest.m +++ b/playground/ios/NavigationTests/UIViewController+LayoutProtocolTest.m @@ -42,44 +42,6 @@ - (void)testInitWithLayoutInfoShouldSetChildViewControllers { XCTAssertEqual(uut.viewControllers[1], child2); } -- (void)testSetBackButtonIcon_withColor_shouldSetColor { - UIViewController* uut = [UIViewController new]; - [[UINavigationController alloc] initWithRootViewController:uut]; - UIColor* color = [UIColor blackColor]; - - [uut setBackButtonIcon:nil withColor:color title:nil]; - XCTAssertEqual(color, uut.navigationItem.backBarButtonItem.tintColor); -} - -- (void)testSetBackButtonIcon_withColor_shouldSetTitle { - UIViewController* uut = [UIViewController new]; - UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:uut]; - NSString* title = @"Title"; - - [uut 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]; - - [uut setBackButtonIcon:icon withColor:nil title:nil]; - XCTAssertEqual(icon, uut.navigationItem.backBarButtonItem.image); -} - -- (void)testSetBackButtonIcon_shouldSetTitleOnPreviousViewControllerIfExists { - UIViewController* uut = [UIViewController new]; - UIViewController* viewController2 = [UIViewController new]; - UINavigationController* nav = [[UINavigationController alloc] init]; - [nav setViewControllers:@[uut, viewController2]]; - NSString* title = @"Title"; - - [uut setBackButtonIcon:nil withColor:nil title:title]; - XCTAssertEqual(title, uut.navigationItem.backBarButtonItem.title); -} - - (void)testResolveOptions { RNNComponentPresenter* presenter = [[RNNComponentPresenter alloc] init];