Skip to content

Commit

Permalink
Create new UITabBarItem instance on each bottomTab update (#6018)
Browse files Browse the repository at this point in the history
Fix an issue where bottomTab.testID doesn't get updated on mergeOptions unless a new UITabBarItem is created. Look like an issue in iOS where tabBarItem.accessibilityIdentifier doesn't get updated unless a new tabBarItem is created.
  • Loading branch information
yogevbd authored Mar 9, 2020
1 parent 6d61ec0 commit 3757ff7
Show file tree
Hide file tree
Showing 16 changed files with 42 additions and 26 deletions.
2 changes: 0 additions & 2 deletions lib/ios/BottomTabAppearancePresenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,4 @@
API_AVAILABLE(ios(13.0))
@interface BottomTabAppearancePresenter : BottomTabPresenter

- (instancetype)initWithDefaultOptions:(RNNNavigationOptions *)defaultOptions children:(NSArray<UIViewController *> *)children;

@end
10 changes: 1 addition & 9 deletions lib/ios/BottomTabAppearancePresenter.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,8 @@

@implementation BottomTabAppearancePresenter

- (instancetype)initWithDefaultOptions:(RNNNavigationOptions *)defaultOptions children:(NSArray<UIViewController *> *)children {
self = [super initWithDefaultOptions:defaultOptions];
for (UIViewController* child in children) {
child.tabBarItem.standardAppearance = [[UITabBarAppearance alloc] init];
}
return self;
}

- (void)createTabBarItem:(UIViewController *)child bottomTabOptions:(RNNBottomTabOptions *)bottomTabOptions {
child.tabBarItem = [TabBarItemAppearanceCreator updateTabBarItem:child.tabBarItem bottomTabOptions:bottomTabOptions];
child.tabBarItem = [TabBarItemAppearanceCreator createTabBarItem:bottomTabOptions mergeItem:child.tabBarItem];
}

@end
6 changes: 3 additions & 3 deletions lib/ios/BottomTabPresenter.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@ - (void)applyOptions:(RNNNavigationOptions *)options child:(UIViewController *)c
- (void)applyOptionsOnWillMoveToParentViewController:(RNNNavigationOptions *)options child:(UIViewController *)child {
RNNNavigationOptions * withDefault = [options withDefault:self.defaultOptions];

[self createTabBarItem:child bottomTabOptions:withDefault.bottomTab];
[child setTabBarItemBadge:[withDefault.bottomTab.badge getWithDefaultValue:[NSNull null]]];
[child setTabBarItemBadgeColor:[withDefault.bottomTab.badgeColor getWithDefaultValue:nil]];
[self createTabBarItem:child bottomTabOptions:withDefault.bottomTab];
}

- (void)mergeOptions:(RNNNavigationOptions *)options resolvedOptions:(RNNNavigationOptions *)resolvedOptions child:(UIViewController *)child {
RNNNavigationOptions* withDefault = (RNNNavigationOptions *) [[resolvedOptions withDefault:self.defaultOptions] overrideOptions:options];

if (options.bottomTab.hasValue) [self createTabBarItem:child bottomTabOptions:withDefault.bottomTab];
if (options.bottomTab.badge.hasValue) [child setTabBarItemBadge:options.bottomTab.badge.get];
if (options.bottomTab.badgeColor.hasValue) [child setTabBarItemBadgeColor:options.bottomTab.badgeColor.get];
if (options.bottomTab.hasValue) [self createTabBarItem:child bottomTabOptions:withDefault.bottomTab];
}

- (void)createTabBarItem:(UIViewController *)child bottomTabOptions:(RNNBottomTabOptions *)bottomTabOptions {
child.tabBarItem = [RNNTabBarItemCreator updateTabBarItem:child.tabBarItem bottomTabOptions:bottomTabOptions];
child.tabBarItem = [RNNTabBarItemCreator createTabBarItem:bottomTabOptions mergeItem:child.tabBarItem];
}

@end
2 changes: 1 addition & 1 deletion lib/ios/BottomTabPresenterCreator.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@

@interface BottomTabPresenterCreator : NSObject

+ (BottomTabPresenter *)createWithDefaultOptions:(RNNNavigationOptions *)defaultOptions children:(NSArray<UIViewController *> *)children;
+ (BottomTabPresenter *)createWithDefaultOptions:(RNNNavigationOptions *)defaultOptions;

@end
4 changes: 2 additions & 2 deletions lib/ios/BottomTabPresenterCreator.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

@implementation BottomTabPresenterCreator

+ (BottomTabPresenter *)createWithDefaultOptions:(RNNNavigationOptions *)defaultOptions children:(NSArray<UIViewController *> *)children {
+ (BottomTabPresenter *)createWithDefaultOptions:(RNNNavigationOptions *)defaultOptions {
if (@available(iOS 13.0, *)) {
return [[BottomTabAppearancePresenter alloc] initWithDefaultOptions:defaultOptions children:children];
return [[BottomTabAppearancePresenter alloc] initWithDefaultOptions:defaultOptions];
} else {
return [[BottomTabPresenter alloc] initWithDefaultOptions:defaultOptions];
}
Expand Down
2 changes: 1 addition & 1 deletion lib/ios/RNNControllerFactory.m
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ - (UIViewController *)createBottomTabs:(RNNLayoutNode*)node {
RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"options"]];
RNNBottomTabsPresenter* presenter = [BottomTabsPresenterCreator createWithDefaultOptions:_defaultOptions];
NSArray *childViewControllers = [self extractChildrenViewControllersFromNode:node];
BottomTabPresenter* bottomTabPresenter = [BottomTabPresenterCreator createWithDefaultOptions:_defaultOptions children:childViewControllers];;
BottomTabPresenter* bottomTabPresenter = [BottomTabPresenterCreator createWithDefaultOptions:_defaultOptions];
RNNDotIndicatorPresenter* dotIndicatorPresenter = [[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:_defaultOptions];
BottomTabsBaseAttacher* bottomTabsAttacher = [_bottomTabsAttachModeFactory fromOptions:options];

Expand Down
4 changes: 3 additions & 1 deletion lib/ios/RNNTabBarItemCreator.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

@interface RNNTabBarItemCreator : NSObject

+ (UITabBarItem *)updateTabBarItem:(UITabBarItem *)tabItem bottomTabOptions:(RNNBottomTabOptions *)bottomTabOptions;
+ (UITabBarItem *)createTabBarItem:(RNNBottomTabOptions *)bottomTabOptions mergeItem:(UITabBarItem *)mergeItem;

+ (UITabBarItem *)createTabBarItem:(UITabBarItem *)mergeItem;

+ (void)setTitleAttributes:(UITabBarItem *)tabItem titleAttributes:(NSDictionary *)titleAttributes;

Expand Down
7 changes: 6 additions & 1 deletion lib/ios/RNNTabBarItemCreator.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@

@implementation RNNTabBarItemCreator

+ (UITabBarItem *)updateTabBarItem:(UITabBarItem *)tabItem bottomTabOptions:(RNNBottomTabOptions *)bottomTabOptions {
+ (UITabBarItem *)createTabBarItem:(UITabBarItem *)mergeItem {
return [UITabBarItem new];
}

+ (UITabBarItem *)createTabBarItem:(RNNBottomTabOptions *)bottomTabOptions mergeItem:(UITabBarItem *)mergeItem {
UITabBarItem* tabItem = [self createTabBarItem:mergeItem];
UIImage* icon = [bottomTabOptions.icon getWithDefaultValue:nil];
UIImage* selectedIcon = [bottomTabOptions.selectedIcon getWithDefaultValue:icon];
UIColor* iconColor = [bottomTabOptions.iconColor getWithDefaultValue:nil];
Expand Down
1 change: 1 addition & 0 deletions lib/ios/TabBarItemAppearanceCreator.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#import "RNNTabBarItemCreator.h"

API_AVAILABLE(ios(13.0))
@interface TabBarItemAppearanceCreator : RNNTabBarItemCreator

@end
6 changes: 6 additions & 0 deletions lib/ios/TabBarItemAppearanceCreator.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

@implementation TabBarItemAppearanceCreator

+ (UITabBarItem *)createTabBarItem:(UITabBarItem *)mergeItem {
UITabBarItem* tabBarItem = [super createTabBarItem:mergeItem];
tabBarItem.standardAppearance = mergeItem.standardAppearance ?: [[UITabBarAppearance alloc] init];
return tabBarItem;
}

+ (void)setTitleAttributes:(UITabBarItem *)tabItem titleAttributes:(NSDictionary *)titleAttributes {
tabItem.standardAppearance.stackedLayoutAppearance.normal.titleTextAttributes = titleAttributes;
}
Expand Down
14 changes: 14 additions & 0 deletions playground/ios/NavigationTests/BottomTabPresenterTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,18 @@ - (void)testMergeOptions_shouldSetTabBarItemColorWithDefaultOptions {
XCTAssertEqual(self.componentViewController.tabBarItem.title, @"title");
}

- (void)testMergeOptions_shouldCreateNewTabBarItemInstance {
RNNNavigationOptions* defaultOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
defaultOptions.bottomTab.selectedIconColor = [Color withColor:UIColor.greenColor];
self.uut.defaultOptions = defaultOptions;

RNNNavigationOptions* mergeOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
mergeOptions.bottomTab.text = [[Text alloc] initWithValue:@"title"];

UITabBarItem* currentTabBarItem = self.componentViewController.tabBarItem;
[self.uut mergeOptions:mergeOptions resolvedOptions:self.options child:self.componentViewController];
UITabBarItem* newTabBarItem = self.componentViewController.tabBarItem;
XCTAssertNotEqual(currentTabBarItem, newTabBarItem);
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ - (void)setUp {
self.children = @[[[RNNComponentViewController alloc] initWithLayoutInfo:nil rootViewCreator:nil eventEmitter:nil presenter:[[RNNComponentPresenter alloc] initWithDefaultOptions:nil] options:nil defaultOptions:nil]];
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 children:self.children] dotIndicatorPresenter:self.dotIndicatorPresenter eventEmitter:nil childViewControllers:self.children bottomTabsAttacher: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.uut bindViewController:self.boundViewController];
self.options = [[RNNNavigationOptions alloc] initEmptyOptions];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ + (RNNBottomTabsController *)create {

+ (RNNBottomTabsController *)createWithChildren:(NSArray *)children {
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 children:children] dotIndicatorPresenter:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:defaultOptions] eventEmitter:nil childViewControllers:children bottomTabsAttacher:nil];
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];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ @implementation RNNDotIndicatorPresenterTest
- (void)setUp {
[super setUp];
self.child = [self createChild];
self.bottomTabPresenter = [BottomTabPresenterCreator createWithDefaultOptions:nil children:@[self.child]];
self.bottomTabPresenter = [BottomTabPresenterCreator createWithDefaultOptions:nil];
self.uut = [OCMockObject partialMockForObject:[RNNDotIndicatorPresenter new]];
self.bottomTabs = [OCMockObject partialMockForObject:[RNNBottomTabsController createWithChildren:@[self.child]]];

Expand Down
2 changes: 0 additions & 2 deletions playground/ios/NavigationTests/RNNRootViewControllerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,6 @@ - (void)testTabBadge {
NSString* tabBadgeInput = @"5";
self.options.bottomTab.badge = [[Text alloc] initWithValue:tabBadgeInput];
NSMutableArray* controllers = [NSMutableArray new];
UITabBarItem* item = [[UITabBarItem alloc] initWithTitle:@"A Tab" image:nil tag:1];
[self.uut setTabBarItem:item];
[controllers addObject:self.uut];
__unused RNNBottomTabsController* vc = [RNNBottomTabsController createWithChildren:controllers];
[self.uut willMoveToParentViewController:vc];
Expand Down
2 changes: 1 addition & 1 deletion playground/ios/NavigationTests/RNNTabBarControllerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ - (void)setUp {
self.mockTabBarPresenter = [OCMockObject partialMockForObject:[[RNNBottomTabsPresenter alloc] init]];
self.mockChildViewController = [OCMockObject partialMockForObject:[RNNComponentViewController new]];
self.mockEventEmitter = [OCMockObject partialMockForObject:[RNNEventEmitter new]];
self.originalUut = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initWithDict:@{}] defaultOptions:nil presenter:self.mockTabBarPresenter bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:nil children:children] dotIndicatorPresenter:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:nil] eventEmitter:self.mockEventEmitter childViewControllers:children bottomTabsAttacher:nil];
self.originalUut = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initWithDict:@{}] defaultOptions:nil presenter:self.mockTabBarPresenter bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:nil] dotIndicatorPresenter:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:nil] eventEmitter:self.mockEventEmitter childViewControllers:children bottomTabsAttacher:nil];
self.uut = [OCMockObject partialMockForObject:self.originalUut];
OCMStub([self.uut selectedViewController]).andReturn(self.mockChildViewController);
}
Expand Down

0 comments on commit 3757ff7

Please sign in to comment.