ソースを参照

V2 current tab (#2205)

* readme

* WIP

* ios, tests

* refactoring

* current tab

* android tests

* readme

* current tab index ios

* fix tests

* readme

* test fix

* probabl test fix
Roman Kozlov 6 年 前
コミット
6cf4fe9bd8
共有27 個のファイルを変更した224 個の追加72 個の削除を含む
  1. 11
    0
      .gitignore
  2. 8
    0
      AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/TopLevelApiTest.java
  3. 2
    2
      README.md
  4. 44
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/BottomTabsOptions.java
  5. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/DEFAULT_VALUES.java
  6. 3
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/NavigationOptions.java
  7. 8
    0
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/NavigationOptionsListener.java
  8. 41
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/BottomTabsController.java
  9. 4
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ContainerViewController.java
  10. 6
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java
  11. 14
    0
      lib/android/app/src/test/java/com/reactnativenavigation/parse/NavigationOptionsTest.java
  12. 0
    4
      lib/ios/RNNBridgeModule.m
  13. 0
    2
      lib/ios/RNNCommandsHandler.h
  14. 0
    7
      lib/ios/RNNCommandsHandler.m
  15. 2
    2
      lib/ios/RNNNavigationOptions.h
  16. 19
    13
      lib/ios/RNNNavigationOptions.m
  17. 2
    2
      lib/ios/RNNRootViewController.m
  18. 16
    0
      lib/ios/RNNTabBarOptions.h
  19. 25
    0
      lib/ios/RNNTabBarOptions.m
  20. 0
    1
      lib/ios/RNNTopBarOptions.h
  21. 7
    0
      lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj
  22. 3
    3
      lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m
  23. 0
    4
      lib/src/Navigation.js
  24. 0
    5
      lib/src/adapters/NativeCommandsSender.js
  25. 0
    4
      lib/src/commands/Commands.js
  26. 0
    15
      lib/src/commands/Commands.test.js
  27. 8
    2
      playground/src/containers/TextScreen.js

+ 11
- 0
.gitignore ファイルの表示

212
 \.buckd/
212
 \.buckd/
213
 android/app/libs
213
 android/app/libs
214
 android/keystores/debug.keystore
214
 android/keystores/debug.keystore
215
+AndroidE2E/app/.settings
216
+AndroidE2E/.settings
217
+AndroidE2E/app/.project
218
+AndroidE2E/app/.classpath
219
+AndroidE2E/.project
220
+lib/android/.settings
221
+lib/android/.project
222
+lib/android/app/.settings
223
+playground/android/.settings
224
+playground/android/.project
225
+playground/android/app/.settings

+ 8
- 0
AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/TopLevelApiTest.java ファイルの表示

11
 		elementByText("SWITCH TO TAB BASED APP").click();
11
 		elementByText("SWITCH TO TAB BASED APP").click();
12
 		assertExists(By.text("This is tab 1"));
12
 		assertExists(By.text("This is tab 1"));
13
 		assertExists(By.text("Hello from a function!"));
13
 		assertExists(By.text("Hello from a function!"));
14
+  }
15
+  
16
+  @Test
17
+	public void switchToTabBasedApp_SwitchTab() throws Exception {
18
+		elementByText("SWITCH TO TAB BASED APP").click();
19
+		assertExists(By.text("This is tab 1"));
20
+    elementByText("SWITCH TO TAB 2").click();
21
+    assertExists(By.text("This is tab 2"));
14
 	}
22
 	}
15
 
23
 
16
 	@Test
24
 	@Test

+ 2
- 2
README.md ファイルの表示

99
 | drawUnder          |    WIP @gran33     |      [Contribute](/docs/docs/CONTRIBUTING.md)       | |
99
 | drawUnder          |    WIP @gran33     |      [Contribute](/docs/docs/CONTRIBUTING.md)       | |
100
 | hidden   |   ✅     |    [Contribute](/docs/docs/CONTRIBUTING.md)        | @gtchance|
100
 | hidden   |   ✅     |    [Contribute](/docs/docs/CONTRIBUTING.md)        | @gtchance|
101
 | tabBadge          |       ✅    | [Contribute](/docs/docs/CONTRIBUTING.md)| Wix|
101
 | tabBadge          |       ✅    | [Contribute](/docs/docs/CONTRIBUTING.md)| Wix|
102
-| currentTab by Index          |       [Contribute](/docs/docs/CONTRIBUTING.md)    | [Contribute](/docs/docs/CONTRIBUTING.md)| |
103
-| currentTab by cointainerId         |       [Contribute](/docs/docs/CONTRIBUTING.md)    | [Contribute](/docs/docs/CONTRIBUTING.md)| |
102
+| currentTab by Index          |       ✅    | ✅ | Wix |
103
+| currentTab by cointainerId         |       [Contribute](/docs/docs/CONTRIBUTING.md)    | ✅ | Wix |
104
 
104
 
105
 |       buttons        | iOS  | Android | contributors|
105
 |       buttons        | iOS  | Android | contributors|
106
 |--------------------|-----|----|-----|
106
 |--------------------|-----|----|-----|

+ 44
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/BottomTabsOptions.java ファイルの表示

1
+package com.reactnativenavigation.parse;
2
+
3
+
4
+import org.json.JSONObject;
5
+
6
+public class BottomTabsOptions implements DEFAULT_VALUES {
7
+
8
+	public static BottomTabsOptions parse(JSONObject json) {
9
+		BottomTabsOptions options = new BottomTabsOptions();
10
+		if (json == null) return options;
11
+
12
+		options.currentTabId = json.optString("currentTabId", NO_VALUE);
13
+		options.currentTabIndex = json.optInt("currentTabIndex", NO_INT_VALUE);
14
+		options.tabBadge = json.optInt("tabBadge", NO_INT_VALUE);
15
+		options.hidden = NavigationOptions.BooleanOptions.parse(json.optString("hidden"));
16
+		options.animateHide = NavigationOptions.BooleanOptions.parse(json.optString("animateHide"));
17
+
18
+		return options;
19
+	}
20
+
21
+	public int tabBadge = NO_INT_VALUE;
22
+	public NavigationOptions.BooleanOptions hidden = NavigationOptions.BooleanOptions.False;
23
+	public NavigationOptions.BooleanOptions animateHide = NavigationOptions.BooleanOptions.False;
24
+	public int currentTabIndex;
25
+	public String currentTabId;
26
+
27
+	void mergeWith(final BottomTabsOptions other) {
28
+		if (!NO_VALUE.equals(other.currentTabId)) {
29
+			currentTabId = other.currentTabId;
30
+		}
31
+		if(NO_INT_VALUE != other.currentTabIndex) {
32
+			currentTabId = other.currentTabId;
33
+		}
34
+		if(NO_INT_VALUE != other.tabBadge) {
35
+			tabBadge = other.tabBadge;
36
+		}
37
+		if (other.hidden != NavigationOptions.BooleanOptions.NoValue) {
38
+			hidden = other.hidden;
39
+		}
40
+		if (other.animateHide != NavigationOptions.BooleanOptions.NoValue) {
41
+			animateHide = other.animateHide;
42
+		}
43
+	}
44
+}

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/DEFAULT_VALUES.java ファイルの表示

3
 
3
 
4
 import android.graphics.Color;
4
 import android.graphics.Color;
5
 
5
 
6
-interface DEFAULT_VALUES {
6
+public interface DEFAULT_VALUES {
7
 	String NO_VALUE = "";
7
 	String NO_VALUE = "";
8
 	int NO_INT_VALUE = Integer.MIN_VALUE;
8
 	int NO_INT_VALUE = Integer.MIN_VALUE;
9
 	float NO_FLOAT_VALUE = Float.MIN_VALUE;
9
 	float NO_FLOAT_VALUE = Float.MIN_VALUE;

+ 3
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/NavigationOptions.java ファイルの表示

27
 		if (json == null) return result;
27
 		if (json == null) return result;
28
 
28
 
29
 		result.topBarOptions = TopBarOptions.parse(json.optJSONObject("topBar"));
29
 		result.topBarOptions = TopBarOptions.parse(json.optJSONObject("topBar"));
30
+		result.bottomTabsOptions = BottomTabsOptions.parse(json.optJSONObject("tabBar"));
30
 
31
 
31
 		return result;
32
 		return result;
32
 	}
33
 	}
33
 
34
 
34
 	public TopBarOptions topBarOptions = new TopBarOptions();
35
 	public TopBarOptions topBarOptions = new TopBarOptions();
36
+	public BottomTabsOptions bottomTabsOptions = new BottomTabsOptions();
35
 
37
 
36
 	public void mergeWith(final NavigationOptions other) {
38
 	public void mergeWith(final NavigationOptions other) {
37
 		topBarOptions.mergeWith(other.topBarOptions);
39
 		topBarOptions.mergeWith(other.topBarOptions);
40
+		bottomTabsOptions.mergeWith(other.bottomTabsOptions);
38
 	}
41
 	}
39
 }
42
 }

+ 8
- 0
lib/android/app/src/main/java/com/reactnativenavigation/presentation/NavigationOptionsListener.java ファイルの表示

1
+package com.reactnativenavigation.presentation;
2
+
3
+
4
+import com.reactnativenavigation.parse.NavigationOptions;
5
+
6
+public interface NavigationOptionsListener {
7
+	void mergeNavigationOptions(NavigationOptions options);
8
+}

+ 41
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/BottomTabsController.java ファイルの表示

10
 import android.view.ViewGroup;
10
 import android.view.ViewGroup;
11
 import android.widget.RelativeLayout;
11
 import android.widget.RelativeLayout;
12
 
12
 
13
+import com.reactnativenavigation.parse.NavigationOptions;
14
+import com.reactnativenavigation.presentation.NavigationOptionsListener;
13
 import com.reactnativenavigation.utils.CompatUtils;
15
 import com.reactnativenavigation.utils.CompatUtils;
14
 
16
 
15
 import java.util.ArrayList;
17
 import java.util.ArrayList;
20
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
22
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
21
 import static android.widget.RelativeLayout.ABOVE;
23
 import static android.widget.RelativeLayout.ABOVE;
22
 import static android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM;
24
 import static android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM;
25
+import static com.reactnativenavigation.parse.DEFAULT_VALUES.NO_INT_VALUE;
26
+import static com.reactnativenavigation.parse.DEFAULT_VALUES.NO_VALUE;
23
 
27
 
24
-public class BottomTabsController extends ParentController implements BottomNavigationView.OnNavigationItemSelectedListener {
28
+public class BottomTabsController extends ParentController
29
+		implements BottomNavigationView.OnNavigationItemSelectedListener, NavigationOptionsListener {
25
 	private BottomNavigationView bottomNavigationView;
30
 	private BottomNavigationView bottomNavigationView;
26
 	private List<ViewController> tabs = new ArrayList<>();
31
 	private List<ViewController> tabs = new ArrayList<>();
27
 	private int selectedIndex = 0;
32
 	private int selectedIndex = 0;
86
 		return selectedIndex;
91
 		return selectedIndex;
87
 	}
92
 	}
88
 
93
 
94
+	@NonNull
89
 	@Override
95
 	@Override
90
 	public Collection<ViewController> getChildControllers() {
96
 	public Collection<ViewController> getChildControllers() {
91
 		return tabs;
97
 		return tabs;
92
 	}
98
 	}
99
+
100
+	@Override
101
+	public void mergeNavigationOptions(NavigationOptions options) {
102
+		if (options.bottomTabsOptions != null) {
103
+			if (options.bottomTabsOptions.currentTabIndex != NO_INT_VALUE) {
104
+				selectTabAtIndex(options.bottomTabsOptions.currentTabIndex);
105
+			}
106
+			if (!NO_VALUE.equals(options.bottomTabsOptions.currentTabId)) {
107
+				String id = options.bottomTabsOptions.currentTabId;
108
+				for (ViewController controller : tabs) {
109
+					if (controller.getId().equals(id)) {
110
+						selectTabAtIndex(tabs.indexOf(controller));
111
+					}
112
+					if (controller instanceof StackController) {
113
+						if (hasControlWithId((StackController) controller, id)) {
114
+							selectTabAtIndex(tabs.indexOf(controller));
115
+						}
116
+					}
117
+				}
118
+			}
119
+		}
120
+	}
121
+
122
+	private boolean hasControlWithId(StackController controller, String id) {
123
+		for (ViewController child : controller.getChildControllers()) {
124
+			if (id.equals(child.getId())) {
125
+				return true;
126
+			}
127
+			if (child instanceof StackController) {
128
+				return hasControlWithId((StackController) child, id);
129
+			}
130
+		}
131
+		return false;
132
+	}
93
 }
133
 }

+ 4
- 2
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ContainerViewController.java ファイルの表示

7
 
7
 
8
 import com.reactnativenavigation.anim.StackAnimator;
8
 import com.reactnativenavigation.anim.StackAnimator;
9
 import com.reactnativenavigation.parse.NavigationOptions;
9
 import com.reactnativenavigation.parse.NavigationOptions;
10
+import com.reactnativenavigation.presentation.NavigationOptionsListener;
10
 import com.reactnativenavigation.presentation.OptionsPresenter;
11
 import com.reactnativenavigation.presentation.OptionsPresenter;
11
 import com.reactnativenavigation.views.TopBar;
12
 import com.reactnativenavigation.views.TopBar;
12
 import com.reactnativenavigation.views.TopbarContainerView;
13
 import com.reactnativenavigation.views.TopbarContainerView;
13
 
14
 
14
-public class ContainerViewController extends ViewController {
15
+public class ContainerViewController extends ViewController implements NavigationOptionsListener {
15
 
16
 
16
 	public interface ContainerViewCreator {
17
 	public interface ContainerViewCreator {
17
 
18
 
87
 		return containerView.asView();
88
 		return containerView.asView();
88
 	}
89
 	}
89
 
90
 
90
-	void mergeNavigationOptions(NavigationOptions options) {
91
+	@Override
92
+	public void mergeNavigationOptions(NavigationOptions options) {
91
 		navigationOptions.mergeWith(options);
93
 		navigationOptions.mergeWith(options);
92
 		applyOptions();
94
 		applyOptions();
93
 	}
95
 	}

+ 6
- 2
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java ファイルの表示

8
 import com.facebook.react.bridge.Promise;
8
 import com.facebook.react.bridge.Promise;
9
 import com.reactnativenavigation.parse.NavigationOptions;
9
 import com.reactnativenavigation.parse.NavigationOptions;
10
 import com.reactnativenavigation.parse.OverlayOptions;
10
 import com.reactnativenavigation.parse.OverlayOptions;
11
+import com.reactnativenavigation.presentation.NavigationOptionsListener;
11
 import com.reactnativenavigation.presentation.OverlayPresenter;
12
 import com.reactnativenavigation.presentation.OverlayPresenter;
12
 import com.reactnativenavigation.utils.CompatUtils;
13
 import com.reactnativenavigation.utils.CompatUtils;
13
 
14
 
70
 
71
 
71
 	public void setOptions(final String containerId, NavigationOptions options) {
72
 	public void setOptions(final String containerId, NavigationOptions options) {
72
 		ViewController target = findControllerById(containerId);
73
 		ViewController target = findControllerById(containerId);
73
-		if (target instanceof ContainerViewController) {
74
-			((ContainerViewController) target).mergeNavigationOptions(options);
74
+		if (target instanceof NavigationOptionsListener) {
75
+			((NavigationOptionsListener) target).mergeNavigationOptions(options);
76
+		}
77
+		if (root instanceof NavigationOptionsListener) {
78
+			((NavigationOptionsListener) root).mergeNavigationOptions(options);
75
 		}
79
 		}
76
 	}
80
 	}
77
 
81
 

+ 14
- 0
lib/android/app/src/test/java/com/reactnativenavigation/parse/NavigationOptionsTest.java ファイルの表示

29
 
29
 
30
 		json.put("topBar", topBarJson);
30
 		json.put("topBar", topBarJson);
31
 
31
 
32
+		JSONObject tabBarJson = new JSONObject();
33
+		tabBarJson.put("currentTabId", "ContainerId");
34
+		tabBarJson.put("currentTabIndex", 1);
35
+		tabBarJson.put("hidden", true);
36
+		tabBarJson.put("animateHide", true);
37
+		tabBarJson.put("tabBadge", 3);
38
+
39
+		json.put("tabBar", tabBarJson);
40
+
32
 		NavigationOptions result = NavigationOptions.parse(json);
41
 		NavigationOptions result = NavigationOptions.parse(json);
33
 		assertThat(result.topBarOptions.title).isEqualTo("the title");
42
 		assertThat(result.topBarOptions.title).isEqualTo("the title");
34
 		assertThat(result.topBarOptions.backgroundColor).isEqualTo(0xff123456);
43
 		assertThat(result.topBarOptions.backgroundColor).isEqualTo(0xff123456);
36
 		assertThat(result.topBarOptions.textFontSize).isEqualTo(18);
45
 		assertThat(result.topBarOptions.textFontSize).isEqualTo(18);
37
 		assertThat(result.topBarOptions.textFontFamily).isEqualTo("HelveticaNeue-CondensedBold");
46
 		assertThat(result.topBarOptions.textFontFamily).isEqualTo("HelveticaNeue-CondensedBold");
38
 		assertThat(result.topBarOptions.hidden).isEqualTo(True);
47
 		assertThat(result.topBarOptions.hidden).isEqualTo(True);
48
+		assertThat(result.bottomTabsOptions.animateHide).isEqualTo(True);
49
+		assertThat(result.bottomTabsOptions.hidden).isEqualTo(True);
50
+		assertThat(result.bottomTabsOptions.tabBadge).isEqualTo(3);
51
+		assertThat(result.bottomTabsOptions.currentTabId).isEqualTo("ContainerId");
52
+		assertThat(result.bottomTabsOptions.currentTabIndex).isEqualTo(1);
39
 	}
53
 	}
40
 
54
 
41
 	@Test
55
 	@Test

+ 0
- 4
lib/ios/RNNBridgeModule.m ファイルの表示

54
 	[_commandsHandler dismissAllModals];
54
 	[_commandsHandler dismissAllModals];
55
 }
55
 }
56
 
56
 
57
-RCT_EXPORT_METHOD(switchToTab:(NSString*)containerId tabIndex:(nonnull NSNumber*)tabIndex) {
58
-	[_commandsHandler switchToTab:containerId tabIndex:tabIndex];
59
-}
60
-
61
 @end
57
 @end
62
 
58
 

+ 0
- 2
lib/ios/RNNCommandsHandler.h ファイルの表示

26
 
26
 
27
 -(void) dismissAllModals;
27
 -(void) dismissAllModals;
28
 
28
 
29
--(void) switchToTab:(NSString*)containerId tabIndex:(NSNumber*)tabIndex;
30
-
31
 @end
29
 @end

+ 0
- 7
lib/ios/RNNCommandsHandler.m ファイルの表示

91
 	[_modalManager dismissAllModals];
91
 	[_modalManager dismissAllModals];
92
 }
92
 }
93
 
93
 
94
--(void) switchToTab:(NSString *)containerId tabIndex:(NSNumber *)tabIndex {
95
-	[self assertReady];
96
-	
97
-	UIViewController* vc = [_store findContainerForId:containerId];
98
-	[vc.tabBarController setSelectedIndex:[tabIndex unsignedIntegerValue]];
99
-}
100
-
101
 #pragma mark - private
94
 #pragma mark - private
102
 
95
 
103
 -(void) assertReady {
96
 -(void) assertReady {

+ 2
- 2
lib/ios/RNNNavigationOptions.h ファイルの表示

1
 #import <Foundation/Foundation.h>
1
 #import <Foundation/Foundation.h>
2
 #import <UIKit/UIKit.h>
2
 #import <UIKit/UIKit.h>
3
 #import "RNNTopBarOptions.h"
3
 #import "RNNTopBarOptions.h"
4
+#import "RNNTabBarOptions.h"
4
 
5
 
5
 extern const NSInteger BLUR_STATUS_TAG;
6
 extern const NSInteger BLUR_STATUS_TAG;
6
 extern const NSInteger BLUR_TOPBAR_TAG;
7
 extern const NSInteger BLUR_TOPBAR_TAG;
9
 
10
 
10
 @property (nonatomic, strong) NSNumber* statusBarHidden;
11
 @property (nonatomic, strong) NSNumber* statusBarHidden;
11
 @property (nonatomic, strong) NSNumber* screenBackgroundColor;
12
 @property (nonatomic, strong) NSNumber* screenBackgroundColor;
12
-@property (nonatomic, strong) NSString* tabBadge;
13
 @property (nonatomic, strong) id orientation;
13
 @property (nonatomic, strong) id orientation;
14
 @property (nonatomic, strong) NSArray* leftButtons;
14
 @property (nonatomic, strong) NSArray* leftButtons;
15
 @property (nonatomic, strong) NSArray* rightButtons;
15
 @property (nonatomic, strong) NSArray* rightButtons;
16
 @property (nonatomic, strong) NSNumber* statusBarBlur;
16
 @property (nonatomic, strong) NSNumber* statusBarBlur;
17
 @property (nonatomic, strong) NSNumber* statusBarHideWithTopBar;
17
 @property (nonatomic, strong) NSNumber* statusBarHideWithTopBar;
18
-@property (nonatomic, strong) NSNumber* tabBarHidden;
19
 @property (nonatomic, strong) RNNTopBarOptions* topBar;
18
 @property (nonatomic, strong) RNNTopBarOptions* topBar;
19
+@property (nonatomic, strong) RNNTabBarOptions* tabBar;
20
 
20
 
21
 
21
 
22
 - (UIInterfaceOrientationMask)supportedOrientations;
22
 - (UIInterfaceOrientationMask)supportedOrientations;

+ 19
- 13
lib/ios/RNNNavigationOptions.m ファイルの表示

17
 	self = [super init];
17
 	self = [super init];
18
 	self.statusBarHidden = [navigationOptions objectForKey:@"statusBarHidden"];
18
 	self.statusBarHidden = [navigationOptions objectForKey:@"statusBarHidden"];
19
 	self.screenBackgroundColor = [navigationOptions objectForKey:@"screenBackgroundColor"];
19
 	self.screenBackgroundColor = [navigationOptions objectForKey:@"screenBackgroundColor"];
20
-	self.tabBadge = [navigationOptions objectForKey:@"tabBadge"];
21
 	self.orientation = [navigationOptions objectForKey:@"orientation"];
20
 	self.orientation = [navigationOptions objectForKey:@"orientation"];
22
 	self.leftButtons = [navigationOptions objectForKey:@"leftButtons"];
21
 	self.leftButtons = [navigationOptions objectForKey:@"leftButtons"];
23
 	self.rightButtons = [navigationOptions objectForKey:@"rightButtons"];
22
 	self.rightButtons = [navigationOptions objectForKey:@"rightButtons"];
24
-	self.tabBarHidden = [navigationOptions objectForKey:@"tabBarHidden"];
25
 	self.topBar = [[RNNTopBarOptions alloc] initWithDict:[navigationOptions objectForKey:@"topBar"]];
23
 	self.topBar = [[RNNTopBarOptions alloc] initWithDict:[navigationOptions objectForKey:@"topBar"]];
24
+	self.tabBar = [[RNNTabBarOptions alloc] initWithDict:[navigationOptions objectForKey:@"tabBar"]];
26
 	
25
 	
27
 	return self;
26
 	return self;
28
 }
27
 }
30
 -(void)mergeWith:(NSDictionary *)otherOptions {
29
 -(void)mergeWith:(NSDictionary *)otherOptions {
31
 	for (id key in otherOptions) {
30
 	for (id key in otherOptions) {
32
 		if ([key isEqualToString:@"topBar"]) {
31
 		if ([key isEqualToString:@"topBar"]) {
33
-			[self.topBar mergeWith:[otherOptions objectForKey:@"topBar"]];
32
+			[self.topBar mergeWith:[otherOptions objectForKey:key]];
33
+		} else if ([key isEqualToString:@"tabBar"]) {
34
+			[self.tabBar mergeWith:[otherOptions objectForKey:key]];
34
 		} else {
35
 		} else {
35
 			[self setValue:[otherOptions objectForKey:key] forKey:key];
36
 			[self setValue:[otherOptions objectForKey:key] forKey:key];
36
 		}
37
 		}
66
 			}
67
 			}
67
 			viewController.navigationController.navigationBar.titleTextAttributes = navigationBarTitleTextAttributes;
68
 			viewController.navigationController.navigationBar.titleTextAttributes = navigationBarTitleTextAttributes;
68
 		}
69
 		}
69
-
70
-
70
+		
71
+		
71
 		if (self.topBar.hidden){
72
 		if (self.topBar.hidden){
72
 			[viewController.navigationController setNavigationBarHidden:[self.topBar.hidden boolValue] animated:[self.topBar.animateHide boolValue]];
73
 			[viewController.navigationController setNavigationBarHidden:[self.topBar.hidden boolValue] animated:[self.topBar.animateHide boolValue]];
73
 		}
74
 		}
74
-
75
+		
75
 		if (self.topBar.hideOnScroll) {
76
 		if (self.topBar.hideOnScroll) {
76
 			viewController.navigationController.hidesBarsOnSwipe = [self.topBar.hideOnScroll boolValue];
77
 			viewController.navigationController.hidesBarsOnSwipe = [self.topBar.hideOnScroll boolValue];
77
 		}
78
 		}
78
-
79
+		
79
 		if (self.topBar.buttonColor) {
80
 		if (self.topBar.buttonColor) {
80
 			UIColor* buttonColor = [RCTConvert UIColor:self.topBar.buttonColor];
81
 			UIColor* buttonColor = [RCTConvert UIColor:self.topBar.buttonColor];
81
 			viewController.navigationController.navigationBar.tintColor = buttonColor;
82
 			viewController.navigationController.navigationBar.tintColor = buttonColor;
125
 		viewController.view.backgroundColor = screenColor;
126
 		viewController.view.backgroundColor = screenColor;
126
 	}
127
 	}
127
 	
128
 	
128
-	if (self.tabBadge) {
129
-		NSString *badge = [RCTConvert NSString:self.tabBadge];
130
-		if (viewController.navigationController) {
131
-			viewController.navigationController.tabBarItem.badgeValue = badge;
132
-		} else {
133
-			viewController.tabBarItem.badgeValue = badge;
129
+	if (self.tabBar) {
130
+		if (self.tabBar.tabBadge) {
131
+			NSString *badge = [RCTConvert NSString:self.tabBar.tabBadge];
132
+			if (viewController.navigationController) {
133
+				viewController.navigationController.tabBarItem.badgeValue = badge;
134
+			} else {
135
+				viewController.tabBarItem.badgeValue = badge;
136
+			}
137
+		}
138
+		if (self.tabBar.currentTabIndex) {
139
+			[viewController.tabBarController setSelectedIndex:[self.tabBar.currentTabIndex unsignedIntegerValue]];
134
 		}
140
 		}
135
 	}
141
 	}
136
 	
142
 	

+ 2
- 2
lib/ios/RNNRootViewController.m ファイルの表示

55
 
55
 
56
 - (BOOL)hidesBottomBarWhenPushed
56
 - (BOOL)hidesBottomBarWhenPushed
57
 {
57
 {
58
-	if (self.navigationOptions.tabBarHidden) {
59
-		return [self.navigationOptions.tabBarHidden boolValue];
58
+	if (self.navigationOptions.tabBar && self.navigationOptions.tabBar.hidden) {
59
+		return [self.navigationOptions.tabBar.hidden boolValue];
60
 	}
60
 	}
61
 	return NO;
61
 	return NO;
62
 }
62
 }

+ 16
- 0
lib/ios/RNNTabBarOptions.h ファイルの表示

1
+#import <Foundation/Foundation.h>
2
+
3
+extern const NSInteger BLUR_TOPBAR_TAG;
4
+
5
+@interface RNNTabBarOptions : NSObject
6
+
7
+@property (nonatomic, strong) NSNumber* hidden;
8
+@property (nonatomic, strong) NSNumber* animateHide;
9
+@property (nonatomic, strong) NSString* tabBadge;
10
+@property (nonatomic, strong) NSNumber* currentTabIndex;
11
+
12
+-(instancetype)init;
13
+-(instancetype)initWithDict:(NSDictionary *)topBarOptions;
14
+-(void)mergeWith:(NSDictionary*)otherOptions;
15
+
16
+@end

+ 25
- 0
lib/ios/RNNTabBarOptions.m ファイルの表示

1
+#import "RNNTabBarOptions.h"
2
+
3
+@implementation RNNTabBarOptions
4
+
5
+-(instancetype)init {
6
+	return [self initWithDict:@{}];
7
+}
8
+
9
+-(instancetype)initWithDict:(NSDictionary *)tabBarOptions {
10
+	self = [super init];
11
+	
12
+	self.hidden = [tabBarOptions valueForKey:@"hidden"];
13
+	self.animateHide = [tabBarOptions valueForKey:@"animateHide"];
14
+	self.tabBadge = [tabBarOptions valueForKey:@"tabBadge"];
15
+	self.currentTabIndex = [tabBarOptions valueForKey:@"currentTabIndex"];
16
+	
17
+	return self;
18
+}
19
+
20
+-(void)mergeWith:(NSDictionary *)otherOptions {
21
+	for (id key in otherOptions) {
22
+		[self setValue:[otherOptions objectForKey:key] forKey:key];
23
+	}
24
+}
25
+@end

+ 0
- 1
lib/ios/RNNTopBarOptions.h ファイルの表示

1
 #import <Foundation/Foundation.h>
1
 #import <Foundation/Foundation.h>
2
 
2
 
3
-extern const NSInteger BLUR_STATUS_TAG;
4
 extern const NSInteger BLUR_TOPBAR_TAG;
3
 extern const NSInteger BLUR_TOPBAR_TAG;
5
 
4
 
6
 @interface RNNTopBarOptions : NSObject
5
 @interface RNNTopBarOptions : NSObject

+ 7
- 0
lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj ファイルの表示

98
 		7BEF0D1C1E43771B003E96B0 /* RNNLayoutNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BEF0D1A1E43771B003E96B0 /* RNNLayoutNode.h */; };
98
 		7BEF0D1C1E43771B003E96B0 /* RNNLayoutNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BEF0D1A1E43771B003E96B0 /* RNNLayoutNode.h */; };
99
 		7BEF0D1D1E43771B003E96B0 /* RNNLayoutNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */; };
99
 		7BEF0D1D1E43771B003E96B0 /* RNNLayoutNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */; };
100
 		A7626BFD1FC2FB2C00492FB8 /* RNNTopBarOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */; };
100
 		A7626BFD1FC2FB2C00492FB8 /* RNNTopBarOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */; };
101
+		A7626C011FC5796200492FB8 /* RNNTabBarOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = A7626C001FC5796200492FB8 /* RNNTabBarOptions.m */; };
102
+		A7626BFD1FC2FB2C00492FB8 /* RNNTopBarOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */; };
101
 		E83BAD681F2734B500A9F3DD /* RNNNavigationOptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E83BAD671F2734B500A9F3DD /* RNNNavigationOptionsTest.m */; };
103
 		E83BAD681F2734B500A9F3DD /* RNNNavigationOptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E83BAD671F2734B500A9F3DD /* RNNNavigationOptionsTest.m */; };
102
 		E83BAD6B1F27363A00A9F3DD /* RNNNavigationOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = E83BAD6A1F27363A00A9F3DD /* RNNNavigationOptions.m */; };
104
 		E83BAD6B1F27363A00A9F3DD /* RNNNavigationOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = E83BAD6A1F27363A00A9F3DD /* RNNNavigationOptions.m */; };
103
 		E83BAD791F27416B00A9F3DD /* RNNRootViewControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E83BAD781F27416B00A9F3DD /* RNNRootViewControllerTest.m */; };
105
 		E83BAD791F27416B00A9F3DD /* RNNRootViewControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E83BAD781F27416B00A9F3DD /* RNNRootViewControllerTest.m */; };
223
 		7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNLayoutNode.m; sourceTree = "<group>"; };
225
 		7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNLayoutNode.m; sourceTree = "<group>"; };
224
 		A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTopBarOptions.m; sourceTree = "<group>"; };
226
 		A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTopBarOptions.m; sourceTree = "<group>"; };
225
 		A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTopBarOptions.h; sourceTree = "<group>"; };
227
 		A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTopBarOptions.h; sourceTree = "<group>"; };
228
+		A7626BFF1FC578AB00492FB8 /* RNNTabBarOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTabBarOptions.h; sourceTree = "<group>"; };
229
+		A7626C001FC5796200492FB8 /* RNNTabBarOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTabBarOptions.m; sourceTree = "<group>"; };
226
 		D8AFADBD1BEE6F3F00A4592D /* libReactNativeNavigation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativeNavigation.a; sourceTree = BUILT_PRODUCTS_DIR; };
230
 		D8AFADBD1BEE6F3F00A4592D /* libReactNativeNavigation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativeNavigation.a; sourceTree = BUILT_PRODUCTS_DIR; };
227
 		E83BAD671F2734B500A9F3DD /* RNNNavigationOptionsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNNavigationOptionsTest.m; sourceTree = "<group>"; };
231
 		E83BAD671F2734B500A9F3DD /* RNNNavigationOptionsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNNavigationOptionsTest.m; sourceTree = "<group>"; };
228
 		E83BAD691F27362500A9F3DD /* RNNNavigationOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNNavigationOptions.h; sourceTree = "<group>"; };
232
 		E83BAD691F27362500A9F3DD /* RNNNavigationOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNNavigationOptions.h; sourceTree = "<group>"; };
373
 				214545241F4DC125006E8DA1 /* RNNUIBarButtonItem.m */,
377
 				214545241F4DC125006E8DA1 /* RNNUIBarButtonItem.m */,
374
 				A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */,
378
 				A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */,
375
 				A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */,
379
 				A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */,
380
+				A7626BFF1FC578AB00492FB8 /* RNNTabBarOptions.h */,
381
+				A7626C001FC5796200492FB8 /* RNNTabBarOptions.m */,
376
 			);
382
 			);
377
 			name = Controllers;
383
 			name = Controllers;
378
 			sourceTree = "<group>";
384
 			sourceTree = "<group>";
636
 				263905B81E4C6F440023D7D3 /* UIViewController+MMDrawerController.m in Sources */,
642
 				263905B81E4C6F440023D7D3 /* UIViewController+MMDrawerController.m in Sources */,
637
 				263905CD1E4C6F440023D7D3 /* SidebarWunderlistAnimation.m in Sources */,
643
 				263905CD1E4C6F440023D7D3 /* SidebarWunderlistAnimation.m in Sources */,
638
 				263905CF1E4C6F440023D7D3 /* TheSidebarController.m in Sources */,
644
 				263905CF1E4C6F440023D7D3 /* TheSidebarController.m in Sources */,
645
+				A7626C011FC5796200492FB8 /* RNNTabBarOptions.m in Sources */,
639
 				263905AF1E4C6F440023D7D3 /* MMDrawerBarButtonItem.m in Sources */,
646
 				263905AF1E4C6F440023D7D3 /* MMDrawerBarButtonItem.m in Sources */,
640
 				7B4928091E70415400555040 /* RNNCommandsHandler.m in Sources */,
647
 				7B4928091E70415400555040 /* RNNCommandsHandler.m in Sources */,
641
 				268692831E5054F800E2C612 /* RNNStore.m in Sources */,
648
 				268692831E5054F800E2C612 /* RNNStore.m in Sources */,

+ 3
- 3
lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m ファイルの表示

158
 
158
 
159
 -(void)testTabBadge {
159
 -(void)testTabBadge {
160
 	NSString* tabBadgeInput = @"5";
160
 	NSString* tabBadgeInput = @"5";
161
-	self.options.tabBadge = tabBadgeInput;
161
+	self.options.tabBar.tabBadge = tabBadgeInput;
162
 	__unused RNNTabBarController* vc = [[RNNTabBarController alloc] init];
162
 	__unused RNNTabBarController* vc = [[RNNTabBarController alloc] init];
163
 	NSMutableArray* controllers = [NSMutableArray new];
163
 	NSMutableArray* controllers = [NSMutableArray new];
164
 	UITabBarItem* item = [[UITabBarItem alloc] initWithTitle:@"A Tab" image:nil tag:1];
164
 	UITabBarItem* item = [[UITabBarItem alloc] initWithTitle:@"A Tab" image:nil tag:1];
417
 
417
 
418
 
418
 
419
 - (void)testTabBarHidden_true {
419
 - (void)testTabBarHidden_true {
420
-	self.options.tabBarHidden = @(1);
420
+	self.options.tabBar.hidden = @(1);
421
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
421
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
422
 	[self.uut viewWillAppear:false];
422
 	[self.uut viewWillAppear:false];
423
 
423
 
425
 }
425
 }
426
 
426
 
427
 - (void)testTabBarHidden_false {
427
 - (void)testTabBarHidden_false {
428
-	self.options.tabBarHidden = @(0);
428
+	self.options.tabBar.hidden = @(0);
429
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
429
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
430
 	[self.uut viewWillAppear:false];
430
 	[self.uut viewWillAppear:false];
431
 
431
 

+ 0
- 4
lib/src/Navigation.js ファイルの表示

64
     return this.commands.popToRoot(containerId);
64
     return this.commands.popToRoot(containerId);
65
   }
65
   }
66
 
66
 
67
-  switchToTab(onContainerId, tabIndex) {
68
-    return this.commands.switchToTab(onContainerId, tabIndex);
69
-  }
70
-
71
   events() {
67
   events() {
72
     return this.publicEventsRegistry;
68
     return this.publicEventsRegistry;
73
   }
69
   }

+ 0
- 5
lib/src/adapters/NativeCommandsSender.js ファイルの表示

41
     return this.nativeCommandsModule.dismissAllModals();
41
     return this.nativeCommandsModule.dismissAllModals();
42
   }
42
   }
43
 
43
 
44
-  switchToTab(containerId, tabIndex) {
45
-    this.nativeCommandsModule.switchToTab(containerId, tabIndex);
46
-    return Promise.resolve(containerId);
47
-  }
48
-
49
   showOverlay(type, options) {
44
   showOverlay(type, options) {
50
     return this.nativeCommandsModule.showOverlay(type, options);
45
     return this.nativeCommandsModule.showOverlay(type, options);
51
   }
46
   }

+ 0
- 4
lib/src/commands/Commands.js ファイルの表示

55
     return this.nativeCommandsSender.popToRoot(containerId);
55
     return this.nativeCommandsSender.popToRoot(containerId);
56
   }
56
   }
57
 
57
 
58
-  switchToTab(containerId, tabIndex) {
59
-    return this.nativeCommandsSender.switchToTab(containerId, tabIndex);
60
-  }
61
-
62
   showOverlay(type, options) {
58
   showOverlay(type, options) {
63
     const input = _.cloneDeep(options);
59
     const input = _.cloneDeep(options);
64
     OptionsProcessor.processOptions(input);
60
     OptionsProcessor.processOptions(input);

+ 0
- 15
lib/src/commands/Commands.test.js ファイルの表示

223
     });
223
     });
224
   });
224
   });
225
 
225
 
226
-  describe('switchToTab', () => {
227
-    it('switch tab in tabs controller', () => {
228
-      const tabIndex = 1;
229
-      uut.switchToTab('theContainerId', tabIndex);
230
-      expect(mockCommandsSender.switchToTab).toHaveBeenCalledTimes(1);
231
-      expect(mockCommandsSender.switchToTab).toHaveBeenCalledWith('theContainerId', tabIndex);
232
-    });
233
-
234
-    it('returns a promise that resolves to targetId', async () => {
235
-      mockCommandsSender.switchToTab.mockReturnValue(Promise.resolve('theContainerId', 1));
236
-      const result = await uut.switchToTab('theContainerId');
237
-      expect(result).toEqual('theContainerId');
238
-    });
239
-  });
240
-
241
   describe('showOverlay', () => {
226
   describe('showOverlay', () => {
242
     it('deep clones input to avoid mutation errors', () => {
227
     it('deep clones input to avoid mutation errors', () => {
243
       const obj = { title: 'test' };
228
       const obj = { title: 'test' };

+ 8
- 2
playground/src/containers/TextScreen.js ファイルの表示

30
 
30
 
31
   onButtonPress() {
31
   onButtonPress() {
32
     Navigation.setOptions(this.props.containerId, {
32
     Navigation.setOptions(this.props.containerId, {
33
-      tabBadge: `TeSt`
33
+      tabBar: {
34
+        tabBadge: `TeSt`
35
+      }
34
     });
36
     });
35
   }
37
   }
36
 
38
 
37
   onClickSwitchToTab() {
39
   onClickSwitchToTab() {
38
-    Navigation.switchToTab(this.props.containerId, 1);
40
+    Navigation.setOptions(this.props.containerId, {
41
+      tabBar: {
42
+        currentTabIndex: 1
43
+      }
44
+    });
39
   }
45
   }
40
 }
46
 }
41
 module.exports = TextScreen;
47
 module.exports = TextScreen;