Преглед на файлове

Tab bar items (#2345)

* tabBarItem support

* apply tab items on tabController initialization

* e2e test

* refactored bottomTab item

* tests fix

* tabItem testID fix

* renamed tabBadge to badge

* fix merge

* BottomTab fix

* removed BottomTabs
yogevbd преди 6 години
родител
ревизия
2885c8d767
No account linked to committer's email address
променени са 32 файла, в които са добавени 196 реда и са изтрити 86 реда
  1. 1
    1
      docs/_sidebar.md
  2. 0
    8
      docs/docs/BottomTabs.md
  3. 1
    0
      docs/docs/Container.md
  4. 1
    1
      docs/docs/Root.md
  5. 12
    0
      docs/docs/options/BottomTab.md
  6. 0
    1
      docs/docs/options/BottomTabs.md
  7. 1
    0
      docs/docs/options/NavigationOptions.md
  8. 6
    0
      e2e/ScreenStyle.test.js
  9. 2
    2
      lib/ios/RNNControllerFactory.m
  10. 5
    0
      lib/ios/RNNNavigationOptions.h
  11. 31
    9
      lib/ios/RNNNavigationOptions.m
  12. 1
    0
      lib/ios/RNNRootViewController.h
  13. 5
    1
      lib/ios/RNNRootViewController.m
  14. 0
    1
      lib/ios/RNNTabBarOptions.h
  15. 0
    1
      lib/ios/RNNTabBarOptions.m
  16. 18
    0
      lib/ios/RNNTabItemOptions.h
  17. 32
    0
      lib/ios/RNNTabItemOptions.m
  18. 8
    0
      lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj
  19. 1
    1
      lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m
  20. 0
    17
      lib/src/params/containers/BottomTabs.js
  21. 0
    34
      lib/src/params/containers/BottomTabs.test.js
  22. 2
    0
      lib/src/params/containers/Container.js
  23. 5
    3
      lib/src/params/containers/Root.js
  24. 23
    0
      lib/src/params/options/BottomTab.js
  25. 18
    0
      lib/src/params/options/BottomTab.test.js
  26. 0
    2
      lib/src/params/options/BottomTabs.js
  27. 0
    2
      lib/src/params/options/BottomTabs.test.js
  28. 3
    0
      lib/src/params/options/NavigationOptions.js
  29. 4
    0
      lib/src/params/options/NavigationOptions.test.js
  30. 2
    2
      playground/src/containers/TextScreen.js
  31. 12
    0
      playground/src/containers/WelcomeScreen.js
  32. 2
    0
      playground/src/testIDs.js

+ 1
- 1
docs/_sidebar.md Целия файл

8
  - [Root](/docs/Root)
8
  - [Root](/docs/Root)
9
  - [Container](/docs/Container)
9
  - [Container](/docs/Container)
10
  - [SideMenu](/docs/SideMenu)
10
  - [SideMenu](/docs/SideMenu)
11
- - [BottomTabs](/docs/BottomTabs)
12
 - Options
11
 - Options
13
  - [NavigationOptions](/docs/options/NavigationOptions)
12
  - [NavigationOptions](/docs/options/NavigationOptions)
14
  - [TopBar](/docs/options/TopBar)
13
  - [TopBar](/docs/options/TopBar)
15
  - [Button](/docs/options/Button)
14
  - [Button](/docs/options/Button)
16
  - [BottomTabs](/docs/options/BottomTabs)
15
  - [BottomTabs](/docs/options/BottomTabs)
16
+ - [BottomTab](/docs/options/BottomTab)

+ 0
- 8
docs/docs/BottomTabs.md Целия файл

1
-<h1>BottomTabs</h1>
2
-
3
-**Properties**
4
-
5
-| Name | Type |
6
-| --- | --- |
7
-| tabs | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/Container">Container[]</a> | 
8
-

+ 1
- 0
docs/docs/Container.md Целия файл

6
 | --- | --- | --- |
6
 | --- | --- | --- |
7
 | name | <code>string</code> | The container's registered name |
7
 | name | <code>string</code> | The container's registered name |
8
 | passProps | <code>object</code> | props |
8
 | passProps | <code>object</code> | props |
9
+| navigationOptions | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/NavigationOptions">NavigationOptions</a> |  |
9
 
10
 

+ 1
- 1
docs/docs/Root.md Целия файл

6
 | --- | --- |
6
 | --- | --- |
7
 | container | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/Container">Container</a> | 
7
 | container | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/Container">Container</a> | 
8
 | sideMenu | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/SideMenu">SideMenu</a> | 
8
 | sideMenu | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/SideMenu">SideMenu</a> | 
9
-| bottomTabs | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/BottomTabs">BottomTabs</a> | 
9
+| bottomTabs | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/Container">Container[]</a> | 
10
 
10
 

+ 12
- 0
docs/docs/options/BottomTab.md Целия файл

1
+<h1>BottomTab</h1>
2
+
3
+**Properties**
4
+
5
+| Name | Type |
6
+| --- | --- |
7
+| title | <code>string</code> | 
8
+| tag | <code>number</code> | 
9
+| icon | <code>object</code> | 
10
+| visible | <code>boolean</code> | 
11
+| badge | <code>string</code> | 
12
+

+ 0
- 1
docs/docs/options/BottomTabs.md Целия файл

6
 | --- | --- |
6
 | --- | --- |
7
 | currentTabId | <code>string</code> | 
7
 | currentTabId | <code>string</code> | 
8
 | currentTabIndex | <code>number</code> | 
8
 | currentTabIndex | <code>number</code> | 
9
-| tabBadge | <code>number</code> | 
10
 | hidden | <code>boolean</code> | 
9
 | hidden | <code>boolean</code> | 
11
 | animateHide | <code>boolean</code> | 
10
 | animateHide | <code>boolean</code> | 
12
 
11
 

+ 1
- 0
docs/docs/options/NavigationOptions.md Целия файл

6
 | --- | --- |
6
 | --- | --- |
7
 | topBar | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/TopBar">TopBar</a> | 
7
 | topBar | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/TopBar">TopBar</a> | 
8
 | bottomTabs | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/BottomTabs">BottomTabs</a> | 
8
 | bottomTabs | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/BottomTabs">BottomTabs</a> | 
9
+| bottomTab | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/BottomTab">BottomTab</a> | 
9
 | orientation | <code>string</code> | 
10
 | orientation | <code>string</code> | 
10
 | rightButtons | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/Button">Button[]</a> | 
11
 | rightButtons | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/Button">Button[]</a> | 
11
 | leftButtons | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/Button">Button[]</a> | 
12
 | leftButtons | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/Button">Button[]</a> | 

+ 6
- 0
e2e/ScreenStyle.test.js Целия файл

104
     await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
104
     await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
105
     await expect(elementById('buttonLeft')).toBeVisible();
105
     await expect(elementById('buttonLeft')).toBeVisible();
106
   });
106
   });
107
+
108
+  it('tab bar items visibility', async () => {
109
+    await elementById(testIDs.TAB_BASED_APP_BUTTON).tap();
110
+    await expect(elementById(testIDs.FIRST_TAB_BAR_BUTTON)).toBeVisible();
111
+    await expect(elementById(testIDs.SECOND_TAB_BAR_BUTTON)).toBeVisible();
112
+  });
107
 });
113
 });

+ 2
- 2
lib/ios/RNNControllerFactory.m Целия файл

103
 	NSMutableArray* controllers = [NSMutableArray new];
103
 	NSMutableArray* controllers = [NSMutableArray new];
104
 	for (NSDictionary *child in node.children) {
104
 	for (NSDictionary *child in node.children) {
105
 		UIViewController* childVc = [self fromTree:child];
105
 		UIViewController* childVc = [self fromTree:child];
106
+		RNNRootViewController* rootView = (RNNRootViewController *)childVc.childViewControllers.firstObject;
107
+		[rootView applyTabBarItem];
106
 		
108
 		
107
-		UITabBarItem* item = [[UITabBarItem alloc] initWithTitle:@"A Tab" image:nil tag:1];
108
-		[childVc setTabBarItem:item];
109
 		[controllers addObject:childVc];
109
 		[controllers addObject:childVc];
110
 	}
110
 	}
111
 	[vc setViewControllers:controllers];
111
 	[vc setViewControllers:controllers];

+ 5
- 0
lib/ios/RNNNavigationOptions.h Целия файл

3
 #import "RNNTopBarOptions.h"
3
 #import "RNNTopBarOptions.h"
4
 #import "RNNTabBarOptions.h"
4
 #import "RNNTabBarOptions.h"
5
 #import "RNNSideMenuOptions.h"
5
 #import "RNNSideMenuOptions.h"
6
+#import "RNNTabItemOptions.h"
6
 
7
 
7
 extern const NSInteger BLUR_STATUS_TAG;
8
 extern const NSInteger BLUR_STATUS_TAG;
8
 extern const NSInteger BLUR_TOPBAR_TAG;
9
 extern const NSInteger BLUR_TOPBAR_TAG;
25
 @property (nonatomic, strong) RNNSideMenuOptions* sideMenu;
26
 @property (nonatomic, strong) RNNSideMenuOptions* sideMenu;
26
 @property (nonatomic, strong) UIImage* backgroundImage;
27
 @property (nonatomic, strong) UIImage* backgroundImage;
27
 @property (nonatomic, strong) UIImage* rootBackgroundImage;
28
 @property (nonatomic, strong) UIImage* rootBackgroundImage;
29
+@property (nonatomic, strong) RNNTabItemOptions* tabItem;
30
+
28
 
31
 
29
 - (UIInterfaceOrientationMask)supportedOrientations;
32
 - (UIInterfaceOrientationMask)supportedOrientations;
30
 
33
 
35
 -(void)mergeWith:(NSDictionary*)otherOptions;
38
 -(void)mergeWith:(NSDictionary*)otherOptions;
36
 -(void)storeOriginalTopBarImages:(UIViewController*)viewController;
39
 -(void)storeOriginalTopBarImages:(UIViewController*)viewController;
37
 
40
 
41
+- (void)applyTabBarItemOptions:(UIViewController*)viewController;
42
+
38
 @end
43
 @end

+ 31
- 9
lib/ios/RNNNavigationOptions.m Целия файл

30
 	self.sideMenu = [[RNNSideMenuOptions alloc] initWithDict:[navigationOptions objectForKey:@"sideMenu"]];
30
 	self.sideMenu = [[RNNSideMenuOptions alloc] initWithDict:[navigationOptions objectForKey:@"sideMenu"]];
31
 	self.backgroundImage = [RCTConvert UIImage:[navigationOptions objectForKey:@"backgroundImage"]];
31
 	self.backgroundImage = [RCTConvert UIImage:[navigationOptions objectForKey:@"backgroundImage"]];
32
 	self.rootBackgroundImage = [RCTConvert UIImage:[navigationOptions objectForKey:@"rootBackgroundImage"]];
32
 	self.rootBackgroundImage = [RCTConvert UIImage:[navigationOptions objectForKey:@"rootBackgroundImage"]];
33
-
33
+	self.tabItem = [[RNNTabItemOptions alloc] initWithDict:[navigationOptions objectForKey:@"bottomTab"]];
34
+    
34
 	return self;
35
 	return self;
35
 }
36
 }
36
 
37
 
42
 			[self.bottomTabs mergeWith:[otherOptions objectForKey:key]];
43
 			[self.bottomTabs mergeWith:[otherOptions objectForKey:key]];
43
 		} else if ([key isEqualToString:@"sideMenu"]) {
44
 		} else if ([key isEqualToString:@"sideMenu"]) {
44
 			[self.sideMenu mergeWith:[otherOptions objectForKey:@"sideMenu"]];
45
 			[self.sideMenu mergeWith:[otherOptions objectForKey:@"sideMenu"]];
46
+		} else if ([key isEqualToString:@"bottomTab"]) {
47
+			[self.tabItem mergeWith:[otherOptions objectForKey:key]];
45
 		} else {
48
 		} else {
46
 			[self setValue:[otherOptions objectForKey:key] forKey:key];
49
 			[self setValue:[otherOptions objectForKey:key] forKey:key];
47
 		}
50
 		}
195
 	}
198
 	}
196
 	
199
 	
197
 	if (self.bottomTabs) {
200
 	if (self.bottomTabs) {
198
-		if (self.bottomTabs.tabBadge) {
199
-			NSString *badge = [RCTConvert NSString:self.bottomTabs.tabBadge];
200
-			if (viewController.navigationController) {
201
-				viewController.navigationController.tabBarItem.badgeValue = badge;
202
-			} else {
203
-				viewController.tabBarItem.badgeValue = badge;
204
-			}
205
-		}
206
 		if (self.bottomTabs.currentTabIndex) {
201
 		if (self.bottomTabs.currentTabIndex) {
207
 			[viewController.tabBarController setSelectedIndex:[self.bottomTabs.currentTabIndex unsignedIntegerValue]];
202
 			[viewController.tabBarController setSelectedIndex:[self.bottomTabs.currentTabIndex unsignedIntegerValue]];
208
 		}
203
 		}
283
 		backgroundImageView.image = self.rootBackgroundImage;
278
 		backgroundImageView.image = self.rootBackgroundImage;
284
 		[backgroundImageView setContentMode:UIViewContentModeScaleAspectFill];
279
 		[backgroundImageView setContentMode:UIViewContentModeScaleAspectFill];
285
 	}
280
 	}
281
+	
282
+	[self applyTabBarItemOptions:viewController];
283
+}
284
+
285
+- (void)applyTabBarItemOptions:(UIViewController*)viewController {
286
+	if (self.tabItem) {
287
+		if (self.tabItem.title || self.tabItem.icon) {
288
+			UITabBarItem* tabItem = [[UITabBarItem alloc] initWithTitle:self.tabItem.title image:[RCTConvert UIImage:self.tabItem.icon] tag:self.tabItem.tag];
289
+			tabItem.accessibilityIdentifier = self.tabItem.testID;
290
+			[viewController.navigationController setTabBarItem:tabItem];
291
+		}
292
+		
293
+		if (self.tabItem.badge) {
294
+			NSString *badge = [RCTConvert NSString:self.tabItem.badge];
295
+			if (viewController.navigationController) {
296
+				viewController.navigationController.tabBarItem.badgeValue = badge;
297
+			} else {
298
+				viewController.tabBarItem.badgeValue = badge;
299
+			}
300
+		}
301
+		
302
+		if (self.tabItem.visible) {
303
+			[viewController.tabBarController setSelectedIndex:[viewController.tabBarController.viewControllers indexOfObject:viewController]];
304
+		}
305
+		
306
+		[self.tabItem resetOptions];
307
+	}
286
 }
308
 }
287
 
309
 
288
 - (UIInterfaceOrientationMask)supportedOrientations {
310
 - (UIInterfaceOrientationMask)supportedOrientations {

+ 1
- 0
lib/ios/RNNRootViewController.h Целия файл

23
 
23
 
24
 -(void)applyNavigationButtons;
24
 -(void)applyNavigationButtons;
25
 -(BOOL)isAnimated;
25
 -(BOOL)isAnimated;
26
+-(void)applyTabBarItem;
26
 
27
 
27
 @end
28
 @end

+ 5
- 1
lib/ios/RNNRootViewController.m Целия файл

108
 
108
 
109
 
109
 
110
 
110
 
111
--(void) applyNavigationButtons{
111
+-(void)applyNavigationButtons{
112
 	[self.navigationButtons applyLeftButtons:self.navigationOptions.leftButtons rightButtons:self.navigationOptions.rightButtons];
112
 	[self.navigationButtons applyLeftButtons:self.navigationOptions.leftButtons rightButtons:self.navigationOptions.rightButtons];
113
 }
113
 }
114
 
114
 
115
+-(void)applyTabBarItem {
116
+	[self.navigationOptions applyTabBarItemOptions:self];
117
+}
118
+
115
 /**
119
 /**
116
  *	fix for #877, #878
120
  *	fix for #877, #878
117
  */
121
  */

+ 0
- 1
lib/ios/RNNTabBarOptions.h Целия файл

6
 
6
 
7
 @property (nonatomic, strong) NSNumber* hidden;
7
 @property (nonatomic, strong) NSNumber* hidden;
8
 @property (nonatomic, strong) NSNumber* animateHide;
8
 @property (nonatomic, strong) NSNumber* animateHide;
9
-@property (nonatomic, strong) NSString* tabBadge;
10
 @property (nonatomic, strong) NSNumber* currentTabIndex;
9
 @property (nonatomic, strong) NSNumber* currentTabIndex;
11
 @property (nonatomic, strong) NSString* testID;
10
 @property (nonatomic, strong) NSString* testID;
12
 @property (nonatomic, strong) NSNumber* drawUnder;
11
 @property (nonatomic, strong) NSNumber* drawUnder;

+ 0
- 1
lib/ios/RNNTabBarOptions.m Целия файл

11
 	
11
 	
12
 	self.hidden = [tabBarOptions valueForKey:@"hidden"];
12
 	self.hidden = [tabBarOptions valueForKey:@"hidden"];
13
 	self.animateHide = [tabBarOptions valueForKey:@"animateHide"];
13
 	self.animateHide = [tabBarOptions valueForKey:@"animateHide"];
14
-	self.tabBadge = [tabBarOptions valueForKey:@"tabBadge"];
15
 	self.currentTabIndex = [tabBarOptions valueForKey:@"currentTabIndex"];
14
 	self.currentTabIndex = [tabBarOptions valueForKey:@"currentTabIndex"];
16
 	self.testID = [tabBarOptions valueForKey:@"testID"];
15
 	self.testID = [tabBarOptions valueForKey:@"testID"];
17
 	
16
 	

+ 18
- 0
lib/ios/RNNTabItemOptions.h Целия файл

1
+#import <Foundation/Foundation.h>
2
+
3
+@interface RNNTabItemOptions : NSObject
4
+
5
+@property (nonatomic) NSUInteger tag;
6
+@property (nonatomic, strong) NSString* title;
7
+@property (nonatomic, strong) NSString* badge;
8
+@property (nonatomic, strong) NSString* testID;
9
+@property (nonatomic, strong) NSNumber* visible;
10
+@property (nonatomic, strong) NSDictionary* icon;
11
+
12
+-(instancetype)initWithDict:(NSDictionary*)tabItemDict;
13
+
14
+-(void)mergeWith:(NSDictionary *)otherOptions;
15
+
16
+-(void)resetOptions;
17
+
18
+@end

+ 32
- 0
lib/ios/RNNTabItemOptions.m Целия файл

1
+#import "RNNTabItemOptions.h"
2
+
3
+@implementation RNNTabItemOptions
4
+
5
+-(instancetype)initWithDict:(NSDictionary *)tabItemDict {
6
+	self = [super init];
7
+	
8
+	self.title = tabItemDict[@"title"];
9
+	self.tag = [tabItemDict[@"tag"] integerValue];
10
+	self.badge = tabItemDict[@"badge"];
11
+	self.testID = tabItemDict[@"testID"];
12
+	self.visible = tabItemDict[@"visible"];
13
+	self.icon = tabItemDict[@"icon"];
14
+	
15
+	return self;
16
+}
17
+
18
+-(void)mergeWith:(NSDictionary *)otherOptions {
19
+	for (id key in otherOptions) {
20
+		[self setValue:[otherOptions objectForKey:key] forKey:key];
21
+	}
22
+}
23
+
24
+-(void)resetOptions {
25
+	self.title = nil;
26
+	self.badge = nil;
27
+	self.visible = nil;
28
+	self.icon = nil;
29
+	self.testID = nil;
30
+}
31
+
32
+@end

+ 8
- 0
lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj Целия файл

59
 		26916C991E4B9E7700D13680 /* RNNReactRootViewCreator.m in Sources */ = {isa = PBXBuildFile; fileRef = 26916C971E4B9E7700D13680 /* RNNReactRootViewCreator.m */; };
59
 		26916C991E4B9E7700D13680 /* RNNReactRootViewCreator.m in Sources */ = {isa = PBXBuildFile; fileRef = 26916C971E4B9E7700D13680 /* RNNReactRootViewCreator.m */; };
60
 		50CB3B691FDE911400AA153B /* RNNSideMenuOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */; };
60
 		50CB3B691FDE911400AA153B /* RNNSideMenuOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */; };
61
 		50CB3B6A1FDE911400AA153B /* RNNSideMenuOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50CB3B681FDE911400AA153B /* RNNSideMenuOptions.m */; };
61
 		50CB3B6A1FDE911400AA153B /* RNNSideMenuOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50CB3B681FDE911400AA153B /* RNNSideMenuOptions.m */; };
62
+		50EB93411FE14A3E00BD8EEE /* RNNTabItemOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50EB933F1FE14A3E00BD8EEE /* RNNTabItemOptions.h */; };
63
+		50EB93421FE14A3E00BD8EEE /* RNNTabItemOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50EB93401FE14A3E00BD8EEE /* RNNTabItemOptions.m */; };
62
 		50F5DFC11F407A8C001A00BC /* RNNTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 50F5DFBF1F407A8C001A00BC /* RNNTabBarController.h */; };
64
 		50F5DFC11F407A8C001A00BC /* RNNTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 50F5DFBF1F407A8C001A00BC /* RNNTabBarController.h */; };
63
 		50F5DFC21F407A8C001A00BC /* RNNTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F5DFC01F407A8C001A00BC /* RNNTabBarController.m */; };
65
 		50F5DFC21F407A8C001A00BC /* RNNTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F5DFC01F407A8C001A00BC /* RNNTabBarController.m */; };
64
 		50F5DFC51F407AA0001A00BC /* RNNNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 50F5DFC31F407AA0001A00BC /* RNNNavigationController.h */; };
66
 		50F5DFC51F407AA0001A00BC /* RNNNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 50F5DFC31F407AA0001A00BC /* RNNNavigationController.h */; };
207
 		26916C971E4B9E7700D13680 /* RNNReactRootViewCreator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNReactRootViewCreator.m; sourceTree = "<group>"; };
209
 		26916C971E4B9E7700D13680 /* RNNReactRootViewCreator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNReactRootViewCreator.m; sourceTree = "<group>"; };
208
 		50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSideMenuOptions.h; sourceTree = "<group>"; };
210
 		50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSideMenuOptions.h; sourceTree = "<group>"; };
209
 		50CB3B681FDE911400AA153B /* RNNSideMenuOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNSideMenuOptions.m; sourceTree = "<group>"; };
211
 		50CB3B681FDE911400AA153B /* RNNSideMenuOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNSideMenuOptions.m; sourceTree = "<group>"; };
212
+		50EB933F1FE14A3E00BD8EEE /* RNNTabItemOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTabItemOptions.h; sourceTree = "<group>"; };
213
+		50EB93401FE14A3E00BD8EEE /* RNNTabItemOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTabItemOptions.m; sourceTree = "<group>"; };
210
 		50F5DFBF1F407A8C001A00BC /* RNNTabBarController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTabBarController.h; sourceTree = "<group>"; };
214
 		50F5DFBF1F407A8C001A00BC /* RNNTabBarController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTabBarController.h; sourceTree = "<group>"; };
211
 		50F5DFC01F407A8C001A00BC /* RNNTabBarController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTabBarController.m; sourceTree = "<group>"; };
215
 		50F5DFC01F407A8C001A00BC /* RNNTabBarController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTabBarController.m; sourceTree = "<group>"; };
212
 		50F5DFC31F407AA0001A00BC /* RNNNavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNNavigationController.h; sourceTree = "<group>"; };
216
 		50F5DFC31F407AA0001A00BC /* RNNNavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNNavigationController.h; sourceTree = "<group>"; };
426
 				21B85E5C1F44480200B314B5 /* RNNNavigationButtons.m */,
430
 				21B85E5C1F44480200B314B5 /* RNNNavigationButtons.m */,
427
 				214545261F4DC164006E8DA1 /* RNNUIBarButtonItem.h */,
431
 				214545261F4DC164006E8DA1 /* RNNUIBarButtonItem.h */,
428
 				214545241F4DC125006E8DA1 /* RNNUIBarButtonItem.m */,
432
 				214545241F4DC125006E8DA1 /* RNNUIBarButtonItem.m */,
433
+				50EB933F1FE14A3E00BD8EEE /* RNNTabItemOptions.h */,
434
+				50EB93401FE14A3E00BD8EEE /* RNNTabItemOptions.m */,
429
 				A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */,
435
 				A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */,
430
 				A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */,
436
 				A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */,
431
 				A7626BFF1FC578AB00492FB8 /* RNNTabBarOptions.h */,
437
 				A7626BFF1FC578AB00492FB8 /* RNNTabBarOptions.h */,
603
 				E8E518321F83B3E0000467AC /* RNNUtils.h in Headers */,
609
 				E8E518321F83B3E0000467AC /* RNNUtils.h in Headers */,
604
 				263905CA1E4C6F440023D7D3 /* SidebarLuvocracyAnimation.h in Headers */,
610
 				263905CA1E4C6F440023D7D3 /* SidebarLuvocracyAnimation.h in Headers */,
605
 				263905B11E4C6F440023D7D3 /* MMDrawerController.h in Headers */,
611
 				263905B11E4C6F440023D7D3 /* MMDrawerController.h in Headers */,
612
+				50EB93411FE14A3E00BD8EEE /* RNNTabItemOptions.h in Headers */,
606
 				263905B91E4C6F440023D7D3 /* RCCDrawerController.h in Headers */,
613
 				263905B91E4C6F440023D7D3 /* RCCDrawerController.h in Headers */,
607
 				263905B31E4C6F440023D7D3 /* MMDrawerVisualState.h in Headers */,
614
 				263905B31E4C6F440023D7D3 /* MMDrawerVisualState.h in Headers */,
608
 				E8A5CD621F49114F00E89D0D /* RNNElement.h in Headers */,
615
 				E8A5CD621F49114F00E89D0D /* RNNElement.h in Headers */,
757
 				263905CD1E4C6F440023D7D3 /* SidebarWunderlistAnimation.m in Sources */,
764
 				263905CD1E4C6F440023D7D3 /* SidebarWunderlistAnimation.m in Sources */,
758
 				263905CF1E4C6F440023D7D3 /* TheSidebarController.m in Sources */,
765
 				263905CF1E4C6F440023D7D3 /* TheSidebarController.m in Sources */,
759
 				E8A430121F9CB87B00B61A20 /* RNNAnimatedView.m in Sources */,
766
 				E8A430121F9CB87B00B61A20 /* RNNAnimatedView.m in Sources */,
767
+				50EB93421FE14A3E00BD8EEE /* RNNTabItemOptions.m in Sources */,
760
 				E8367B811F7A8A4700675C05 /* VICMAImageView.m in Sources */,
768
 				E8367B811F7A8A4700675C05 /* VICMAImageView.m in Sources */,
761
 				A7626C011FC5796200492FB8 /* RNNTabBarOptions.m in Sources */,
769
 				A7626C011FC5796200492FB8 /* RNNTabBarOptions.m in Sources */,
762
 				263905AF1E4C6F440023D7D3 /* MMDrawerBarButtonItem.m in Sources */,
770
 				263905AF1E4C6F440023D7D3 /* MMDrawerBarButtonItem.m in Sources */,

+ 1
- 1
lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m Целия файл

174
 
174
 
175
 -(void)testTabBadge {
175
 -(void)testTabBadge {
176
 	NSString* tabBadgeInput = @"5";
176
 	NSString* tabBadgeInput = @"5";
177
-	self.options.bottomTabs.tabBadge = tabBadgeInput;
177
+	self.options.tabItem.badge = tabBadgeInput;
178
 	__unused RNNTabBarController* vc = [[RNNTabBarController alloc] init];
178
 	__unused RNNTabBarController* vc = [[RNNTabBarController alloc] init];
179
 	NSMutableArray* controllers = [NSMutableArray new];
179
 	NSMutableArray* controllers = [NSMutableArray new];
180
 	UITabBarItem* item = [[UITabBarItem alloc] initWithTitle:@"A Tab" image:nil tag:1];
180
 	UITabBarItem* item = [[UITabBarItem alloc] initWithTitle:@"A Tab" image:nil tag:1];

+ 0
- 17
lib/src/params/containers/BottomTabs.js Целия файл

1
-const { forEach } = require('lodash');
2
-const Container = require('./Container');
3
-
4
-class BottomTabs {
5
-  /**
6
-   * @property {Container[]} tabs
7
-   */
8
-  constructor(tabs) {
9
-    if (!tabs || tabs.length === 0) {
10
-      throw new Error('BottomTabs undefined');
11
-    }
12
-    this.tabs = [];
13
-    forEach(tabs, (tab) => this.tabs.push({ container: new Container(tab.container) }));
14
-  }
15
-}
16
-
17
-module.exports = BottomTabs;

+ 0
- 34
lib/src/params/containers/BottomTabs.test.js Целия файл

1
-const BottomTabs = require('./BottomTabs');
2
-
3
-const TAB1 = {
4
-  container: {
5
-    name: 'navigation.playground.TextScreen',
6
-    passProps: {
7
-      text: 'This is a side menu center screen tab 2'
8
-    }
9
-  }
10
-};
11
-const TAB2 = {
12
-  container: {
13
-    name: 'navigation.playground.TextScreen',
14
-    passProps: {
15
-      text: 'This is a side menu center screen tab 1'
16
-    }
17
-  }
18
-};
19
-const TABS = [TAB1, TAB2];
20
-
21
-describe('ContainerRegistry', () => {
22
-  it('parses tabs correctly', () => {
23
-    const uut = new BottomTabs(TABS);
24
-    expect(uut.tabs.length).toBe(2);
25
-  });
26
-
27
-  it('throws if tabs are undefined', () => {
28
-    expect(() => new BottomTabs()).toThrowError('BottomTabs undefined');
29
-  });
30
-
31
-  it('throws if zero tabs', () => {
32
-    expect(() => new BottomTabs([])).toThrowError('BottomTabs undefined');
33
-  });
34
-});

+ 2
- 0
lib/src/params/containers/Container.js Целия файл

2
   /**
2
   /**
3
    * @property {string} name The container's registered name
3
    * @property {string} name The container's registered name
4
    * @property {object} [passProps] props
4
    * @property {object} [passProps] props
5
+   * @property {NavigationOptions} navigationOptions
5
    */
6
    */
6
   constructor(params) {
7
   constructor(params) {
7
     if (!params || !params.name) {
8
     if (!params || !params.name) {
9
     }
10
     }
10
     this.name = params.name;
11
     this.name = params.name;
11
     this.passProps = params.passProps;
12
     this.passProps = params.passProps;
13
+    this.navigationOptions = params.navigationOptions;
12
   }
14
   }
13
 }
15
 }
14
 
16
 

+ 5
- 3
lib/src/params/containers/Root.js Целия файл

1
 const Container = require('./Container');
1
 const Container = require('./Container');
2
 const SideMenu = require('./SideMenu');
2
 const SideMenu = require('./SideMenu');
3
-const BottomTabs = require('./BottomTabs');
4
 
3
 
5
 class Root {
4
 class Root {
6
   /**
5
   /**
7
    * @property {Container} container
6
    * @property {Container} container
8
    * @property {SideMenu} [sideMenu]
7
    * @property {SideMenu} [sideMenu]
9
-   * @property {BottomTabs} [bottomTabs]
8
+   * @property {Container[]} [bottomTabs]
10
    */
9
    */
11
   constructor(root) {
10
   constructor(root) {
12
     this.container = root.container && new Container(root.container);
11
     this.container = root.container && new Container(root.container);
13
     this.sideMenu = root.sideMenu && new SideMenu(root.sideMenu);
12
     this.sideMenu = root.sideMenu && new SideMenu(root.sideMenu);
14
-    this.bottomTabs = root.bottomTabs && new BottomTabs(root.bottomTabs).tabs;
13
+    if (root.bottomTabs) {
14
+      root.bottomTabs.map((t) => new Container(t.container));
15
+      this.bottomTabs = root.bottomTabs;
16
+    }
15
   }
17
   }
16
 }
18
 }
17
 
19
 

+ 23
- 0
lib/src/params/options/BottomTab.js Целия файл

1
+const { isEmpty } = require('lodash');
2
+
3
+class BottomTab {
4
+  /**
5
+   * @property {string} [title]
6
+   * @property {number} [tag]
7
+   * @property {object} [icon]
8
+   * @property {boolean} [visible]
9
+   * @property {string} [badge]
10
+   */
11
+  constructor(params) {
12
+    if (isEmpty(params)) {
13
+      return;
14
+    }
15
+
16
+    this.badge = params.badge;
17
+    this.title = params.title;
18
+    this.icon = params.icon;
19
+    this.visible = params.visible;
20
+  }
21
+}
22
+
23
+module.exports = BottomTab;

+ 18
- 0
lib/src/params/options/BottomTab.test.js Целия файл

1
+const BottomTab = require('./BottomTab');
2
+
3
+const BOTTOM_TAB = {
4
+  title: 'title',
5
+  badge: 3,
6
+  visible: true,
7
+  icon: { uri: '' }
8
+};
9
+
10
+describe('BottomTab', () => {
11
+  it('parses BottomTab options', () => {
12
+    const uut = new BottomTab(BOTTOM_TAB);
13
+    expect(uut.title).toEqual('title');
14
+    expect(uut.badge).toEqual(3);
15
+    expect(uut.visible).toEqual(true);
16
+    expect(uut.icon).toEqual({ uri: '' });
17
+  });
18
+});

+ 0
- 2
lib/src/params/options/BottomTabs.js Целия файл

4
   /**
4
   /**
5
    * @property {string} [currentTabId]
5
    * @property {string} [currentTabId]
6
    * @property {number} [currentTabIndex]
6
    * @property {number} [currentTabIndex]
7
-   * @property {number} [tabBadge]
8
    * @property {boolean} [hidden]
7
    * @property {boolean} [hidden]
9
    * @property {boolean} [animateHide]
8
    * @property {boolean} [animateHide]
10
    */
9
    */
14
     }
13
     }
15
     this.currentTabId = params.currentTabId;
14
     this.currentTabId = params.currentTabId;
16
     this.currentTabIndex = params.currentTabIndex;
15
     this.currentTabIndex = params.currentTabIndex;
17
-    this.tabBadge = params.tabBadge;
18
     this.hidden = params.hidden;
16
     this.hidden = params.hidden;
19
     this.animateHide = params.animateHide;
17
     this.animateHide = params.animateHide;
20
   }
18
   }

+ 0
- 2
lib/src/params/options/BottomTabs.test.js Целия файл

3
 const BOTTOM_TABS = {
3
 const BOTTOM_TABS = {
4
   currentTabId: 1,
4
   currentTabId: 1,
5
   currentTabIndex: 2,
5
   currentTabIndex: 2,
6
-  tabBadge: 3,
7
   hidden: true,
6
   hidden: true,
8
   animateHide: true
7
   animateHide: true
9
 };
8
 };
13
     const uut = new BottomTabs(BOTTOM_TABS);
12
     const uut = new BottomTabs(BOTTOM_TABS);
14
     expect(uut.currentTabId).toEqual(1);
13
     expect(uut.currentTabId).toEqual(1);
15
     expect(uut.currentTabIndex).toEqual(2);
14
     expect(uut.currentTabIndex).toEqual(2);
16
-    expect(uut.tabBadge).toEqual(3);
17
     expect(uut.hidden).toEqual(true);
15
     expect(uut.hidden).toEqual(true);
18
     expect(uut.animateHide).toEqual(true);
16
     expect(uut.animateHide).toEqual(true);
19
   });
17
   });

+ 3
- 0
lib/src/params/options/NavigationOptions.js Целия файл

1
 const TopBar = require('./TopBar');
1
 const TopBar = require('./TopBar');
2
 const BottomTabs = require('./BottomTabs');
2
 const BottomTabs = require('./BottomTabs');
3
 const Button = require('./Button');
3
 const Button = require('./Button');
4
+const BottomTab = require('./BottomTab');
4
 
5
 
5
 class NavigationOptions {
6
 class NavigationOptions {
6
   /**
7
   /**
7
    * @property {options:TopBar} [topBar]
8
    * @property {options:TopBar} [topBar]
8
    * @property {options:BottomTabs} [bottomTabs]
9
    * @property {options:BottomTabs} [bottomTabs]
10
+   * @property {options:BottomTab} [bottomTab]
9
    * @property {string} [orientation]
11
    * @property {string} [orientation]
10
    * @property {options:Button[]} [rightButtons]
12
    * @property {options:Button[]} [rightButtons]
11
    * @property {options:Button[]} [leftButtons]
13
    * @property {options:Button[]} [leftButtons]
13
   constructor(options) {
15
   constructor(options) {
14
     this.topBar = options.topBar && new TopBar(options.topBar);
16
     this.topBar = options.topBar && new TopBar(options.topBar);
15
     this.bottomTabs = options.bottomTabs && new BottomTabs(options.bottomTabs);
17
     this.bottomTabs = options.bottomTabs && new BottomTabs(options.bottomTabs);
18
+    this.bottomTab = options.bottomTab && new BottomTab(options.bottomTab);
16
     this.orientation = options.orientation;
19
     this.orientation = options.orientation;
17
     this.rightButtons = options.rightButtons && options.rightButtons.map((button) => new Button(button));
20
     this.rightButtons = options.rightButtons && options.rightButtons.map((button) => new Button(button));
18
     this.leftButtons = options.leftButtons && options.leftButtons.map((button) => new Button(button));
21
     this.leftButtons = options.leftButtons && options.leftButtons.map((button) => new Button(button));

+ 4
- 0
lib/src/params/options/NavigationOptions.test.js Целия файл

1
 const NavigationOptions = require('./NavigationOptions');
1
 const NavigationOptions = require('./NavigationOptions');
2
 const BottomTabs = require('./BottomTabs');
2
 const BottomTabs = require('./BottomTabs');
3
 const TopBar = require('./TopBar');
3
 const TopBar = require('./TopBar');
4
+const BottomTab = require('./BottomTab');
4
 
5
 
5
 const TAB_BAR = {};
6
 const TAB_BAR = {};
6
 const TOP_BAR = {};
7
 const TOP_BAR = {};
8
+const TAB_ITEM = {};
7
 const RIGHT_BUTTONS = [
9
 const RIGHT_BUTTONS = [
8
   {
10
   {
9
     id: 'myBtn',
11
     id: 'myBtn',
23
 const NAVIGATION_OPTIONS = {
25
 const NAVIGATION_OPTIONS = {
24
   topBar: TOP_BAR,
26
   topBar: TOP_BAR,
25
   bottomTabs: TAB_BAR,
27
   bottomTabs: TAB_BAR,
28
+  bottomTab: TAB_ITEM,
26
   orientation: 'portrait',
29
   orientation: 'portrait',
27
   rightButtons: RIGHT_BUTTONS,
30
   rightButtons: RIGHT_BUTTONS,
28
   leftButtons: LEFT_BUTTONS
31
   leftButtons: LEFT_BUTTONS
33
     const uut = new NavigationOptions(NAVIGATION_OPTIONS);
36
     const uut = new NavigationOptions(NAVIGATION_OPTIONS);
34
     expect(uut.bottomTabs).toBeInstanceOf(BottomTabs);
37
     expect(uut.bottomTabs).toBeInstanceOf(BottomTabs);
35
     expect(uut.topBar).toBeInstanceOf(TopBar);
38
     expect(uut.topBar).toBeInstanceOf(TopBar);
39
+    expect(uut.bottomTab).toBeInstanceOf(BottomTab);
36
     expect(uut.orientation).toEqual('portrait');
40
     expect(uut.orientation).toEqual('portrait');
37
     expect(uut.rightButtons).toEqual(RIGHT_BUTTONS);
41
     expect(uut.rightButtons).toEqual(RIGHT_BUTTONS);
38
     expect(uut.leftButtons).toEqual(LEFT_BUTTONS);
42
     expect(uut.leftButtons).toEqual(LEFT_BUTTONS);

+ 2
- 2
playground/src/containers/TextScreen.js Целия файл

42
 
42
 
43
   onButtonPress() {
43
   onButtonPress() {
44
     Navigation.setOptions(this.props.containerId, {
44
     Navigation.setOptions(this.props.containerId, {
45
-      bottomTabs: {
46
-        tabBadge: `TeSt`
45
+      bottomTab: {
46
+        badge: `TeSt`
47
       }
47
       }
48
     });
48
     });
49
   }
49
   }

+ 12
- 0
playground/src/containers/WelcomeScreen.js Целия файл

53
             passProps: {
53
             passProps: {
54
               text: 'This is tab 1',
54
               text: 'This is tab 1',
55
               myFunction: () => 'Hello from a function!'
55
               myFunction: () => 'Hello from a function!'
56
+            },
57
+            navigationOptions: {
58
+              bottomTab: {
59
+                title: 'Tab 1',
60
+                testID: testIDs.FIRST_TAB_BAR_BUTTON
61
+              }
56
             }
62
             }
57
           }
63
           }
58
         },
64
         },
61
             name: 'navigation.playground.TextScreen',
67
             name: 'navigation.playground.TextScreen',
62
             passProps: {
68
             passProps: {
63
               text: 'This is tab 2'
69
               text: 'This is tab 2'
70
+            },
71
+            navigationOptions: {
72
+              bottomTab: {
73
+                title: 'Tab 2',
74
+                testID: testIDs.SECOND_TAB_BAR_BUTTON
75
+              }
64
             }
76
             }
65
           }
77
           }
66
         }
78
         }

+ 2
- 0
playground/src/testIDs.js Целия файл

42
   HIDE_RIGHT_SIDE_MENU_BUTTON: `HIDE_RIGHT_SIDE_MENU_BUTTON`,
42
   HIDE_RIGHT_SIDE_MENU_BUTTON: `HIDE_RIGHT_SIDE_MENU_BUTTON`,
43
   HIDE_BOTTOM_TABS_BUTTON: `HIDE_BOTTOM_TABS_BUTTON`,
43
   HIDE_BOTTOM_TABS_BUTTON: `HIDE_BOTTOM_TABS_BUTTON`,
44
   SHOW_BOTTOM_TABS_BUTTON: `SHOW_BOTTOM_TABS_BUTTON`,
44
   SHOW_BOTTOM_TABS_BUTTON: `SHOW_BOTTOM_TABS_BUTTON`,
45
+  FIRST_TAB_BAR_BUTTON: `FIRST_TAB_BAR_BUTTON`,
46
+  SECOND_TAB_BAR_BUTTON: `SECOND_TAB_BAR_BUTTON`,
45
 
47
 
46
   // Elements
48
   // Elements
47
   SCROLLVIEW_ELEMENT: `SCROLLVIEW_ELEMENT`,
49
   SCROLLVIEW_ELEMENT: `SCROLLVIEW_ELEMENT`,