Browse Source

Further work on TopTabs and some refactoring (#2362)

* Further work on TopTabs and some refactoring

* OptionsPresenter receives views as params
* Remove TopBar and style logic from ViewControllers, these are the OptionsPresenters concern
* StackAnimator isn't coupled to LinearLayout
* Convert Runnable to lambda
* ContainerLayout now implements ReactContainer interface
* Enable desugaring in playground app

* TopTabs unit tests
Guy Carmeli 6 years ago
parent
commit
138391502f
No account linked to committer's email address
32 changed files with 622 additions and 242 deletions
  1. 4
    0
      lib/android/app/build.gradle
  2. 17
    23
      lib/android/app/src/main/java/com/reactnativenavigation/anim/StackAnimator.java
  3. 22
    10
      lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java
  4. 5
    5
      lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutNode.java
  5. 22
    24
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java
  6. 5
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/Task.java
  7. 17
    46
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ContainerViewController.java
  8. 11
    30
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java
  9. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java
  10. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java
  11. 36
    10
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java
  12. 72
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabController.java
  13. 22
    5
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsAdapter.java
  14. 33
    7
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java
  15. 12
    31
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsViewPager.java
  16. 7
    2
      lib/android/app/src/main/java/com/reactnativenavigation/views/Container.java
  17. 17
    12
      lib/android/app/src/main/java/com/reactnativenavigation/views/ContainerLayout.java
  18. 6
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/ReactContainer.java
  19. 4
    10
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopTab.java
  20. 37
    3
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsLayout.java
  21. 16
    9
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestContainerLayout.java
  22. 38
    0
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TopTabLayoutMock.java
  23. 7
    7
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java
  24. 122
    0
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java
  25. 3
    3
      lib/src/commands/LayoutTreeParser.js
  26. 1
    1
      lib/src/commands/LayoutTreeParser.test.js
  27. 1
    1
      lib/src/commands/LayoutTypes.js
  28. 5
    0
      playground/android/app/build.gradle
  29. 52
    0
      playground/src/containers/TopTabOptionsScreen.js
  30. 20
    0
      playground/src/containers/TopTabScreen.js
  31. 4
    1
      playground/src/containers/WelcomeScreen.js
  32. 2
    0
      playground/src/containers/index.js

+ 4
- 0
lib/android/app/build.gradle View File

42
             }
42
             }
43
         }
43
         }
44
     }
44
     }
45
+    compileOptions {
46
+        sourceCompatibility JavaVersion.VERSION_1_8
47
+        targetCompatibility JavaVersion.VERSION_1_8
48
+    }
45
 }
49
 }
46
 
50
 
47
 allprojects { p ->
51
 allprojects { p ->

+ 17
- 23
lib/android/app/src/main/java/com/reactnativenavigation/anim/StackAnimator.java View File

8
 import android.support.annotation.Nullable;
8
 import android.support.annotation.Nullable;
9
 import android.util.DisplayMetrics;
9
 import android.util.DisplayMetrics;
10
 import android.view.View;
10
 import android.view.View;
11
+import android.view.ViewGroup;
11
 import android.view.WindowManager;
12
 import android.view.WindowManager;
12
 import android.view.animation.AccelerateInterpolator;
13
 import android.view.animation.AccelerateInterpolator;
13
 import android.view.animation.DecelerateInterpolator;
14
 import android.view.animation.DecelerateInterpolator;
14
-import android.widget.LinearLayout;
15
 
15
 
16
 import com.reactnativenavigation.views.TopBar;
16
 import com.reactnativenavigation.views.TopBar;
17
 
17
 
116
 		ValueAnimator containerHeightAnim = ValueAnimator.ofInt(container.getMeasuredHeight(), container.getMeasuredHeight() - topBar.getMeasuredHeight());
116
 		ValueAnimator containerHeightAnim = ValueAnimator.ofInt(container.getMeasuredHeight(), container.getMeasuredHeight() - topBar.getMeasuredHeight());
117
 		containerHeightAnim.setInterpolator(DECELERATE_INTERPOLATOR);
117
 		containerHeightAnim.setInterpolator(DECELERATE_INTERPOLATOR);
118
 		containerHeightAnim.setDuration(DURATION_TOPBAR);
118
 		containerHeightAnim.setDuration(DURATION_TOPBAR);
119
-		containerHeightAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
120
-			@Override
121
-			public void onAnimationUpdate(ValueAnimator valueAnimator) {
122
-				int val = (Integer) valueAnimator.getAnimatedValue();
123
-				LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) container.getLayoutParams();
124
-				layoutParams.height = val;
125
-				container.setLayoutParams(layoutParams);
126
-			}
127
-		});
119
+		containerHeightAnim.addUpdateListener(valueAnimator -> {
120
+            int val = (Integer) valueAnimator.getAnimatedValue();
121
+            ViewGroup.LayoutParams layoutParams = container.getLayoutParams();
122
+            layoutParams.height = val;
123
+            container.setLayoutParams(layoutParams);
124
+        });
128
 		ObjectAnimator containerTransitionAnim = ObjectAnimator.ofFloat(container, View.TRANSLATION_Y, -1 * topBar.getMeasuredHeight(), 0);
125
 		ObjectAnimator containerTransitionAnim = ObjectAnimator.ofFloat(container, View.TRANSLATION_Y, -1 * topBar.getMeasuredHeight(), 0);
129
 		containerTransitionAnim.setInterpolator(DECELERATE_INTERPOLATOR);
126
 		containerTransitionAnim.setInterpolator(DECELERATE_INTERPOLATOR);
130
 		containerTransitionAnim.setDuration(DURATION_TOPBAR);
127
 		containerTransitionAnim.setDuration(DURATION_TOPBAR);
142
 
139
 
143
 			@Override
140
 			@Override
144
 			public void onAnimationEnd(Animator animation) {
141
 			public void onAnimationEnd(Animator animation) {
145
-				LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) container.getLayoutParams();
146
-				layoutParams.height = LinearLayout.LayoutParams.MATCH_PARENT;
142
+                ViewGroup.LayoutParams layoutParams = container.getLayoutParams();
143
+				layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
147
 				container.setLayoutParams(layoutParams);
144
 				container.setLayoutParams(layoutParams);
148
 			}
145
 			}
149
 
146
 
165
 		ValueAnimator containerHeightAnim = ValueAnimator.ofInt(container.getMeasuredHeight(), container.getMeasuredHeight() + topBar.getMeasuredHeight());
162
 		ValueAnimator containerHeightAnim = ValueAnimator.ofInt(container.getMeasuredHeight(), container.getMeasuredHeight() + topBar.getMeasuredHeight());
166
 		containerHeightAnim.setInterpolator(ACCELERATE_INTERPOLATOR);
163
 		containerHeightAnim.setInterpolator(ACCELERATE_INTERPOLATOR);
167
 		containerHeightAnim.setDuration(DURATION_TOPBAR);
164
 		containerHeightAnim.setDuration(DURATION_TOPBAR);
168
-		containerHeightAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
169
-			@Override
170
-			public void onAnimationUpdate(ValueAnimator valueAnimator) {
171
-				int val = (Integer) valueAnimator.getAnimatedValue();
172
-				LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) container.getLayoutParams();
173
-				layoutParams.height = val;
174
-				container.setLayoutParams(layoutParams);
175
-			}
176
-		});
165
+		containerHeightAnim.addUpdateListener(valueAnimator -> {
166
+            int val = (Integer) valueAnimator.getAnimatedValue();
167
+            ViewGroup.LayoutParams layoutParams = container.getLayoutParams();
168
+            layoutParams.height = val;
169
+            container.setLayoutParams(layoutParams);
170
+        });
177
 		ObjectAnimator containerTransitionAnim = ObjectAnimator.ofFloat(container, View.TRANSLATION_Y, 0, -1 * topBar.getMeasuredHeight());
171
 		ObjectAnimator containerTransitionAnim = ObjectAnimator.ofFloat(container, View.TRANSLATION_Y, 0, -1 * topBar.getMeasuredHeight());
178
 		containerTransitionAnim.setInterpolator(ACCELERATE_INTERPOLATOR);
172
 		containerTransitionAnim.setInterpolator(ACCELERATE_INTERPOLATOR);
179
 		containerTransitionAnim.setDuration(DURATION_TOPBAR);
173
 		containerTransitionAnim.setDuration(DURATION_TOPBAR);
190
 
184
 
191
 			@Override
185
 			@Override
192
 			public void onAnimationEnd(Animator animation) {
186
 			public void onAnimationEnd(Animator animation) {
193
-				LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) container.getLayoutParams();
194
-				layoutParams.height = LinearLayout.LayoutParams.MATCH_PARENT;
187
+                ViewGroup.LayoutParams layoutParams = container.getLayoutParams();
188
+				layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
195
 				container.setLayoutParams(layoutParams);
189
 				container.setLayoutParams(layoutParams);
196
 				container.setTranslationY(0);
190
 				container.setTranslationY(0);
197
 
191
 

+ 22
- 10
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java View File

10
 import com.reactnativenavigation.viewcontrollers.StackController;
10
 import com.reactnativenavigation.viewcontrollers.StackController;
11
 import com.reactnativenavigation.viewcontrollers.ViewController;
11
 import com.reactnativenavigation.viewcontrollers.ViewController;
12
 import com.reactnativenavigation.viewcontrollers.overlay.DialogViewController;
12
 import com.reactnativenavigation.viewcontrollers.overlay.DialogViewController;
13
+import com.reactnativenavigation.viewcontrollers.toptabs.TopTabController;
13
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsController;
14
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsController;
14
 import com.reactnativenavigation.views.ContainerViewCreator;
15
 import com.reactnativenavigation.views.ContainerViewCreator;
15
-import com.reactnativenavigation.views.TopTabCreator;
16
 
16
 
17
 import java.util.ArrayList;
17
 import java.util.ArrayList;
18
 import java.util.List;
18
 import java.util.List;
32
 	public ViewController create(final LayoutNode node) {
32
 	public ViewController create(final LayoutNode node) {
33
 		switch (node.type) {
33
 		switch (node.type) {
34
 			case Container:
34
 			case Container:
35
-				return createContainer(node, new ContainerViewCreator(reactInstanceManager));
35
+				return createContainer(node);
36
 			case ContainerStack:
36
 			case ContainerStack:
37
 				return createContainerStack(node);
37
 				return createContainerStack(node);
38
 			case BottomTabs:
38
 			case BottomTabs:
47
 				return createSideMenuRight(node);
47
 				return createSideMenuRight(node);
48
 			case CustomDialog:
48
 			case CustomDialog:
49
 				return createDialogContainer(node);
49
 				return createDialogContainer(node);
50
-            case TopTabsContainer:
51
-                return createTopTabsContainer(node);
50
+            case TopTabs:
51
+                return createTopTabs(node);
52
             case TopTab:
52
             case TopTab:
53
-                return createContainer(node, new TopTabCreator(reactInstanceManager));
53
+                return createTopTab(node);
54
 			default:
54
 			default:
55
 				throw new IllegalArgumentException("Invalid node type: " + node.type);
55
 				throw new IllegalArgumentException("Invalid node type: " + node.type);
56
 		}
56
 		}
89
 		return create(node.children.get(0));
89
 		return create(node.children.get(0));
90
 	}
90
 	}
91
 
91
 
92
-	private ViewController createContainer(LayoutNode node, ContainerViewController.ReactViewCreator reactViewCreator) {
92
+	private ViewController createContainer(LayoutNode node) {
93
 		String id = node.id;
93
 		String id = node.id;
94
 		String name = node.data.optString("name");
94
 		String name = node.data.optString("name");
95
 		NavigationOptions navigationOptions = NavigationOptions.parse(node.data.optJSONObject("navigationOptions"), defaultOptions);
95
 		NavigationOptions navigationOptions = NavigationOptions.parse(node.data.optJSONObject("navigationOptions"), defaultOptions);
96
 		return new ContainerViewController(activity,
96
 		return new ContainerViewController(activity,
97
                 id,
97
                 id,
98
                 name,
98
                 name,
99
-                reactViewCreator,
99
+                new ContainerViewCreator(reactInstanceManager),
100
                 navigationOptions
100
                 navigationOptions
101
         );
101
         );
102
 	}
102
 	}
126
 		return new DialogViewController(activity, id, name, creator);
126
 		return new DialogViewController(activity, id, name, creator);
127
 	}
127
 	}
128
 
128
 
129
-    private ViewController createTopTabsContainer(LayoutNode node) {
130
-        final List<ViewController> tabs = new ArrayList<>();
129
+    private ViewController createTopTabs(LayoutNode node) {
130
+        final List<TopTabController> tabs = new ArrayList<>();
131
         for (LayoutNode child : node.children) {
131
         for (LayoutNode child : node.children) {
132
-            tabs.add(create(child));
132
+            tabs.add((TopTabController) create(child));
133
         }
133
         }
134
         return new TopTabsController(activity, node.id, tabs);
134
         return new TopTabsController(activity, node.id, tabs);
135
     }
135
     }
136
+
137
+    private ViewController createTopTab(LayoutNode node) {
138
+        String id = node.id;
139
+        String name = node.data.optString("name");
140
+        NavigationOptions navigationOptions = NavigationOptions.parse(node.data.optJSONObject("navigationOptions"), defaultOptions);
141
+        return new TopTabController(activity,
142
+                id,
143
+                name,
144
+                new ReactContainerViewCreator(reactInstanceManager),
145
+                navigationOptions
146
+        );
147
+    }
136
 }
148
 }

+ 5
- 5
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutNode.java View File

15
 		SideMenuLeft,
15
 		SideMenuLeft,
16
 		SideMenuRight,
16
 		SideMenuRight,
17
 		CustomDialog,
17
 		CustomDialog,
18
-        TopTabsContainer,
18
+        TopTabs,
19
         TopTab
19
         TopTab
20
 	}
20
 	}
21
 
21
 
23
 	public final Type type;
23
 	public final Type type;
24
 	public final JSONObject data;
24
 	public final JSONObject data;
25
 
25
 
26
-	public final List<LayoutNode> children;
26
+	final List<LayoutNode> children;
27
 
27
 
28
-	public LayoutNode(String id, Type type) {
29
-		this(id, type, new JSONObject(), new ArrayList<LayoutNode>());
28
+	LayoutNode(String id, Type type) {
29
+		this(id, type, new JSONObject(), new ArrayList<>());
30
 	}
30
 	}
31
 
31
 
32
-	public LayoutNode(String id, Type type, JSONObject data, List<LayoutNode> children) {
32
+	LayoutNode(String id, Type type, JSONObject data, List<LayoutNode> children) {
33
 		this.id = id;
33
 		this.id = id;
34
 		this.type = type;
34
 		this.type = type;
35
 		this.data = data;
35
 		this.data = data;

+ 22
- 24
lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java View File

7
 import com.reactnativenavigation.parse.TopBarOptions;
7
 import com.reactnativenavigation.parse.TopBarOptions;
8
 import com.reactnativenavigation.parse.TopTabsOptions;
8
 import com.reactnativenavigation.parse.TopTabsOptions;
9
 import com.reactnativenavigation.utils.TypefaceLoader;
9
 import com.reactnativenavigation.utils.TypefaceLoader;
10
-import com.reactnativenavigation.viewcontrollers.ContainerViewController;
11
-import com.reactnativenavigation.views.ContainerLayout;
10
+import com.reactnativenavigation.views.TopBar;
12
 
11
 
13
 public class OptionsPresenter {
12
 public class OptionsPresenter {
14
 
13
 
15
-	private ContainerViewController controller;
16
 	private final StackAnimator animator;
14
 	private final StackAnimator animator;
15
+    private View contentView;
16
+    private TopBar topBar;
17
 
17
 
18
-	public OptionsPresenter(ContainerViewController controller) {
19
-		this.controller = controller;
20
-		animator = new StackAnimator(controller.getActivity());
21
-	}
18
+    public OptionsPresenter(TopBar topBar, View contentView) {
19
+        this.topBar = topBar;
20
+        this.contentView = contentView;
21
+        animator = new StackAnimator(topBar.getContext());
22
+    }
22
 
23
 
23
 	public void applyOptions(NavigationOptions options) {
24
 	public void applyOptions(NavigationOptions options) {
24
-		if (controller != null && controller.getTopBar() != null) {
25
-            applyTopBarOptions(options.topBarOptions);
26
-            applyTopTabsOptions(options.topTabsOptions);
27
-		}
25
+        applyTopBarOptions(options.topBarOptions);
26
+        applyTopTabsOptions(options.topTabsOptions);
28
 	}
27
 	}
29
 
28
 
30
     private void applyTopBarOptions(TopBarOptions options) {
29
     private void applyTopBarOptions(TopBarOptions options) {
31
-        controller.setTitle(options.title);
32
-        controller.setBackgroundColor(options.backgroundColor);
33
-        controller.setTitleTextColor(options.textColor);
34
-        controller.setTitleFontSize(options.textFontSize);
30
+        topBar.setTitle(options.title);
31
+        topBar.setBackgroundColor(options.backgroundColor);
32
+        topBar.setTitleTextColor(options.textColor);
33
+        topBar.setTitleFontSize(options.textFontSize);
34
+
35
         TypefaceLoader typefaceLoader = new TypefaceLoader();
35
         TypefaceLoader typefaceLoader = new TypefaceLoader();
36
-        controller.getTopBar().setTitleTypeface(typefaceLoader.getTypeFace(controller.getActivity(), options.textFontFamily));
36
+        topBar.setTitleTypeface(typefaceLoader.getTypeFace(topBar.getContext(), options.textFontFamily));
37
         if (options.hidden == NavigationOptions.BooleanOptions.True) {
37
         if (options.hidden == NavigationOptions.BooleanOptions.True) {
38
             hideTopBar(options.animateHide);
38
             hideTopBar(options.animateHide);
39
         }
39
         }
43
     }
43
     }
44
 
44
 
45
 	private void showTopBar(NavigationOptions.BooleanOptions animated) {
45
 	private void showTopBar(NavigationOptions.BooleanOptions animated) {
46
-		if (controller.getTopBar().getVisibility() == View.VISIBLE) {
46
+		if (topBar.getVisibility() == View.VISIBLE) {
47
 			return;
47
 			return;
48
 		}
48
 		}
49
 		if (animated == NavigationOptions.BooleanOptions.True) {
49
 		if (animated == NavigationOptions.BooleanOptions.True) {
50
-			ContainerLayout topBarContainerView = (ContainerLayout) controller.getContainerView();
51
-			animator.animateShowTopBar(controller.getTopBar(), topBarContainerView.getReactView().asView());
50
+			animator.animateShowTopBar(topBar, contentView);
52
 		} else {
51
 		} else {
53
-			controller.getTopBar().setVisibility(View.VISIBLE);
52
+			topBar.setVisibility(View.VISIBLE);
54
 		}
53
 		}
55
 	}
54
 	}
56
 
55
 
57
 	private void hideTopBar(NavigationOptions.BooleanOptions animated) {
56
 	private void hideTopBar(NavigationOptions.BooleanOptions animated) {
58
-		if (controller.getTopBar().getVisibility() == View.GONE) {
57
+		if (topBar.getVisibility() == View.GONE) {
59
 			return;
58
 			return;
60
 		}
59
 		}
61
 		if (animated == NavigationOptions.BooleanOptions.True) {
60
 		if (animated == NavigationOptions.BooleanOptions.True) {
62
-			ContainerLayout topBarContainerView = (ContainerLayout) controller.getContainerView();
63
-			animator.animateHideTopBar(controller.getTopBar(), topBarContainerView.getReactView().asView());
61
+			animator.animateHideTopBar(topBar, contentView);
64
 		} else {
62
 		} else {
65
-			controller.getTopBar().setVisibility(View.GONE);
63
+			topBar.setVisibility(View.GONE);
66
 		}
64
 		}
67
 	}
65
 	}
68
 
66
 

+ 5
- 0
lib/android/app/src/main/java/com/reactnativenavigation/utils/Task.java View File

1
+package com.reactnativenavigation.utils;
2
+
3
+public interface Task<T> {
4
+    void run(T param);
5
+}

+ 17
- 46
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ContainerViewController.java View File

2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.support.annotation.NonNull;
4
 import android.support.annotation.NonNull;
5
+import android.support.annotation.RestrictTo;
5
 import android.view.View;
6
 import android.view.View;
6
 
7
 
7
 import com.reactnativenavigation.parse.NavigationOptions;
8
 import com.reactnativenavigation.parse.NavigationOptions;
8
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
9
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
9
-import com.reactnativenavigation.presentation.OptionsPresenter;
10
-import com.reactnativenavigation.views.Container;
10
+import com.reactnativenavigation.views.ReactContainer;
11
 import com.reactnativenavigation.views.TopBar;
11
 import com.reactnativenavigation.views.TopBar;
12
 
12
 
13
 public class ContainerViewController extends ViewController implements NavigationOptionsListener {
13
 public class ContainerViewController extends ViewController implements NavigationOptionsListener {
35
 
35
 
36
 	private final ReactViewCreator viewCreator;
36
 	private final ReactViewCreator viewCreator;
37
 	private NavigationOptions navigationOptions;
37
 	private NavigationOptions navigationOptions;
38
-	private IReactView containerView;
39
-
40
-	private TopBar topBar;
41
-
42
-    public void setTitle(String title) {
43
-        topBar.setTitle(title);
44
-    }
45
-
46
-    public void setBackgroundColor(int backgroundColor) {
47
-        topBar.setBackgroundColor(backgroundColor);
48
-    }
49
-
50
-    public void setTitleTextColor(int textColor) {
51
-        topBar.setTitleTextColor(textColor);
52
-    }
53
-
54
-    public void setTitleFontSize(float textFontSize) {
55
-        topBar.setTitleFontSize(textFontSize);
56
-    }
38
+	private ReactContainer container;
57
 
39
 
58
 	public ContainerViewController(final Activity activity,
40
 	public ContainerViewController(final Activity activity,
59
 								   final String id,
41
 								   final String id,
66
 		this.navigationOptions = initialNavigationOptions;
48
 		this.navigationOptions = initialNavigationOptions;
67
 	}
49
 	}
68
 
50
 
51
+    @RestrictTo(RestrictTo.Scope.TESTS)
52
+    TopBar getTopBar() {
53
+        return container.getTopBar();
54
+    }
55
+
69
 	@Override
56
 	@Override
70
 	public void destroy() {
57
 	public void destroy() {
71
 		super.destroy();
58
 		super.destroy();
72
-		if (containerView != null) containerView.destroy();
73
-		containerView = null;
59
+		if (container != null) container.destroy();
60
+		container = null;
74
 	}
61
 	}
75
 
62
 
76
 	@Override
63
 	@Override
77
 	public void onViewAppeared() {
64
 	public void onViewAppeared() {
78
 		super.onViewAppeared();
65
 		super.onViewAppeared();
79
 		ensureViewIsCreated();
66
 		ensureViewIsCreated();
80
-		applyOptions();
81
-		containerView.sendContainerStart();
67
+		container.applyOptions(navigationOptions);
68
+		container.sendContainerStart();
82
 	}
69
 	}
83
 
70
 
84
 	@Override
71
 	@Override
85
 	public void onViewDisappear() {
72
 	public void onViewDisappear() {
86
 		super.onViewDisappear();
73
 		super.onViewDisappear();
87
-		containerView.sendContainerStop();
74
+		container.sendContainerStop();
88
 	}
75
 	}
89
 
76
 
90
 	@Override
77
 	@Override
91
 	protected boolean isViewShown() {
78
 	protected boolean isViewShown() {
92
-		return super.isViewShown() && containerView.isReady();
79
+		return super.isViewShown() && container.isReady();
93
 	}
80
 	}
94
 
81
 
95
 	@NonNull
82
 	@NonNull
96
 	@Override
83
 	@Override
97
 	protected View createView() {
84
 	protected View createView() {
98
-		containerView = viewCreator.create(getActivity(), getId(), containerName);
99
-		if (containerView instanceof Container) {
100
-			topBar = ((Container) containerView).getTopBar();
101
-		}
102
-		return containerView.asView();
85
+		container = (ReactContainer) viewCreator.create(getActivity(), getId(), containerName);
86
+        return container.asView();
103
 	}
87
 	}
104
 
88
 
105
 	@Override
89
 	@Override
106
 	public void mergeNavigationOptions(NavigationOptions options) {
90
 	public void mergeNavigationOptions(NavigationOptions options) {
107
 		navigationOptions.mergeWith(options);
91
 		navigationOptions.mergeWith(options);
108
-		applyOptions();
92
+        container.applyOptions(options);
109
 	}
93
 	}
110
 
94
 
111
 	NavigationOptions getNavigationOptions() {
95
 	NavigationOptions getNavigationOptions() {
112
 		return navigationOptions;
96
 		return navigationOptions;
113
 	}
97
 	}
114
-
115
-	private void applyOptions() {
116
-		OptionsPresenter presenter = new OptionsPresenter(this);
117
-		presenter.applyOptions(navigationOptions);
118
-	}
119
-
120
-	public TopBar getTopBar() {
121
-		return topBar;
122
-	}
123
-
124
-	public IReactView getContainerView() {
125
-		return containerView;
126
-	}
127
 }
98
 }

+ 11
- 30
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java View File

53
 	 * Navigation methods
53
 	 * Navigation methods
54
 	 */
54
 	 */
55
 
55
 
56
-	public void setRoot(final ViewController viewController) {
56
+	void setRoot(final ViewController viewController) {
57
 		setRoot(viewController, null);
57
 		setRoot(viewController, null);
58
 	}
58
 	}
59
 
59
 
94
 	public void push(final String fromId, final ViewController viewController, Promise promise) {
94
 	public void push(final String fromId, final ViewController viewController, Promise promise) {
95
 		ViewController from = findControllerById(fromId);
95
 		ViewController from = findControllerById(fromId);
96
 		if (from != null) {
96
 		if (from != null) {
97
-			StackController parentStackController = from.getParentStackController();
98
-			if (parentStackController != null) {
99
-				parentStackController.push(viewController, promise);
100
-			}
97
+		    from.performOnParentStack(stack -> stack.push(viewController, promise));
101
 		}
98
 		}
102
 	}
99
 	}
103
 
100
 
104
-	public void pop(final String fromId) {
101
+	void pop(final String fromId) {
105
 		pop(fromId, null);
102
 		pop(fromId, null);
106
 	}
103
 	}
107
 
104
 
108
-	public void pop(final String fromId, Promise promise) {
105
+	void pop(final String fromId, Promise promise) {
109
 		ViewController from = findControllerById(fromId);
106
 		ViewController from = findControllerById(fromId);
110
 		if (from != null) {
107
 		if (from != null) {
111
-			StackController parentStackController = from.getParentStackController();
112
-			if (parentStackController != null) {
113
-				parentStackController.pop(promise);
114
-			}
108
+		    from.performOnParentStack(stack -> stack.pop(promise));
115
 		}
109
 		}
116
 	}
110
 	}
117
 
111
 
118
-	public void popSpecific(final String id) {
112
+	void popSpecific(final String id) {
119
 		popSpecific(id, null);
113
 		popSpecific(id, null);
120
 	}
114
 	}
121
 
115
 
122
 	public void popSpecific(final String id, Promise promise) {
116
 	public void popSpecific(final String id, Promise promise) {
123
 		ViewController from = findControllerById(id);
117
 		ViewController from = findControllerById(id);
124
 		if (from != null) {
118
 		if (from != null) {
125
-			StackController parentStackController = from.getParentStackController();
126
-			if (parentStackController != null) {
127
-				parentStackController.popSpecific(from, promise);
128
-			} else {
129
-				rejectPromise(promise);
130
-			}
119
+		    from.performOnParentStack(stack -> stack.popSpecific(from, promise), () -> rejectPromise(promise));
131
 		} else {
120
 		} else {
132
 			rejectPromise(promise);
121
 			rejectPromise(promise);
133
 		}
122
 		}
134
 	}
123
 	}
135
 
124
 
136
-	public void popToRoot(final String id) {
125
+	void popToRoot(final String id) {
137
 		popToRoot(id, null);
126
 		popToRoot(id, null);
138
 	}
127
 	}
139
 
128
 
140
 	public void popToRoot(final String id, Promise promise) {
129
 	public void popToRoot(final String id, Promise promise) {
141
 		ViewController from = findControllerById(id);
130
 		ViewController from = findControllerById(id);
142
 		if (from != null) {
131
 		if (from != null) {
143
-			StackController parentStackController = from.getParentStackController();
144
-			if (parentStackController != null) {
145
-				parentStackController.popToRoot(promise);
146
-			}
132
+		    from.performOnParentStack(stack -> stack.popToRoot(promise));
147
 		}
133
 		}
148
 	}
134
 	}
149
 
135
 
150
-	public void popTo(final String containerId) {
136
+	void popTo(final String containerId) {
151
 		popTo(containerId, null);
137
 		popTo(containerId, null);
152
 	}
138
 	}
153
 
139
 
154
 	public void popTo(final String containerId, Promise promise) {
140
 	public void popTo(final String containerId, Promise promise) {
155
 		ViewController target = findControllerById(containerId);
141
 		ViewController target = findControllerById(containerId);
156
 		if (target != null) {
142
 		if (target != null) {
157
-			StackController parentStackController = target.getParentStackController();
158
-			if (parentStackController != null) {
159
-				parentStackController.popTo(target, promise);
160
-			} else {
161
-				rejectPromise(promise);
162
-			}
143
+		    target.performOnParentStack(stack -> stack.popTo(target, promise), () -> rejectPromise(promise));
163
 		} else {
144
 		} else {
164
 			rejectPromise(promise);
145
 			rejectPromise(promise);
165
 		}
146
 		}

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java View File

24
 	protected abstract ViewGroup createView();
24
 	protected abstract ViewGroup createView();
25
 
25
 
26
 	@NonNull
26
 	@NonNull
27
-	public abstract Collection<ViewController> getChildControllers();
27
+	public abstract Collection<? extends ViewController> getChildControllers();
28
 
28
 
29
 	@Nullable
29
 	@Nullable
30
 	@Override
30
 	@Override

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java View File

33
 	public void push(final ViewController child, final Promise promise) {
33
 	public void push(final ViewController child, final Promise promise) {
34
 		final ViewController previousTop = peek();
34
 		final ViewController previousTop = peek();
35
 
35
 
36
-		child.setParentStackController(this);
36
+		child.setParentController(this);
37
 		stack.push(child.getId(), child);
37
 		stack.push(child.getId(), child);
38
 		View enteringView = child.getView();
38
 		View enteringView = child.getView();
39
 		getView().addView(enteringView);
39
 		getView().addView(enteringView);

+ 36
- 10
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java View File

3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.support.annotation.NonNull;
4
 import android.support.annotation.NonNull;
5
 import android.support.annotation.Nullable;
5
 import android.support.annotation.Nullable;
6
+import android.support.annotation.VisibleForTesting;
6
 import android.view.View;
7
 import android.view.View;
7
 import android.view.ViewGroup;
8
 import android.view.ViewGroup;
8
 import android.view.ViewManager;
9
 import android.view.ViewManager;
9
 import android.view.ViewTreeObserver;
10
 import android.view.ViewTreeObserver;
10
 
11
 
12
+import com.reactnativenavigation.parse.NavigationOptions;
11
 import com.reactnativenavigation.utils.CompatUtils;
13
 import com.reactnativenavigation.utils.CompatUtils;
12
 import com.reactnativenavigation.utils.StringUtils;
14
 import com.reactnativenavigation.utils.StringUtils;
15
+import com.reactnativenavigation.utils.Task;
13
 
16
 
14
 public abstract class ViewController implements ViewTreeObserver.OnGlobalLayoutListener {
17
 public abstract class ViewController implements ViewTreeObserver.OnGlobalLayoutListener {
15
 
18
 
17
 	private final String id;
20
 	private final String id;
18
 
21
 
19
 	private View view;
22
 	private View view;
20
-	private StackController parentStackController;
23
+	private ParentController parentController;
21
 	private boolean isShown = false;
24
 	private boolean isShown = false;
22
 
25
 
23
 	public ViewController(Activity activity, String id) {
26
 	public ViewController(Activity activity, String id) {
27
 
30
 
28
 	protected abstract View createView();
31
 	protected abstract View createView();
29
 
32
 
30
-	void ensureViewIsCreated() {
33
+	@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
34
+	public void ensureViewIsCreated() {
31
 		getView();
35
 		getView();
32
 	}
36
 	}
33
 
37
 
39
 		return activity;
43
 		return activity;
40
 	}
44
 	}
41
 
45
 
46
+    protected ViewController getParentController() {
47
+	    return parentController;
48
+    }
49
+
42
 	@Nullable
50
 	@Nullable
43
-    StackController getParentStackController() {
44
-		return parentStackController;
51
+    ParentController getParentStackController() {
52
+		return parentController;
45
 	}
53
 	}
46
 
54
 
47
-	void setParentStackController(final StackController parentStackController) {
48
-		this.parentStackController = parentStackController;
55
+	public void setParentController(final ParentController parentController) {
56
+		this.parentController = parentController;
49
 	}
57
 	}
50
 
58
 
59
+    void performOnParentStack(Task<StackController> task) {
60
+	    if (parentController instanceof StackController) {
61
+            task.run((StackController) parentController);
62
+        }
63
+    }
64
+
65
+    void performOnParentStack(Task<StackController> accept, Runnable  reject) {
66
+        if (parentController instanceof StackController) {
67
+            accept.run((StackController) parentController);
68
+        } else {
69
+            reject.run();
70
+        }
71
+    }
72
+
51
 	@NonNull
73
 	@NonNull
52
 	public View getView() {
74
 	public View getView() {
53
 		if (view == null) {
75
 		if (view == null) {
72
 	}
94
 	}
73
 
95
 
74
 	public void onViewAppeared() {
96
 	public void onViewAppeared() {
75
-		//
76
-	}
97
+        isShown = true;
98
+    }
77
 
99
 
78
 	public void onViewDisappear() {
100
 	public void onViewDisappear() {
79
-		//
80
-	}
101
+        isShown = false;
102
+    }
103
+
104
+    public void applyOptions(NavigationOptions options) {
105
+
106
+    }
81
 
107
 
82
 	public void destroy() {
108
 	public void destroy() {
83
 		if (isShown) {
109
 		if (isShown) {

+ 72
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabController.java View File

1
+package com.reactnativenavigation.viewcontrollers.toptabs;
2
+
3
+import android.app.Activity;
4
+import android.view.View;
5
+
6
+import com.reactnativenavigation.parse.NavigationOptions;
7
+import com.reactnativenavigation.presentation.NavigationOptionsListener;
8
+import com.reactnativenavigation.viewcontrollers.ContainerViewController;
9
+import com.reactnativenavigation.viewcontrollers.ViewController;
10
+import com.reactnativenavigation.views.TopTab;
11
+
12
+public class TopTabController extends ViewController implements NavigationOptionsListener {
13
+
14
+    private final String containerName;
15
+    private ContainerViewController.ReactViewCreator viewCreator;
16
+    private final NavigationOptions options;
17
+    private TopTab topTab;
18
+    private boolean isSelectedTab;
19
+
20
+    public TopTabController(Activity activity, String id, String name, ContainerViewController.ReactViewCreator viewCreator, NavigationOptions initialOptions) {
21
+        super(activity, id);
22
+        this.containerName = name;
23
+        this.viewCreator = viewCreator;
24
+        this.options = initialOptions;
25
+    }
26
+
27
+    @Override
28
+    public void onViewAppeared() {
29
+        super.onViewAppeared();
30
+        isSelectedTab = true;
31
+        applyOptions(options);
32
+        topTab.sendContainerStart();
33
+    }
34
+
35
+    @Override
36
+    public void applyOptions(NavigationOptions options) {
37
+        getParentController().applyOptions(options);
38
+    }
39
+
40
+    @Override
41
+    public void onViewDisappear() {
42
+        super.onViewDisappear();
43
+        isSelectedTab = false;
44
+        topTab.sendContainerStop();
45
+    }
46
+
47
+    @Override
48
+    protected boolean isViewShown() {
49
+        return super.isViewShown() && isSelectedTab;
50
+    }
51
+
52
+    @Override
53
+    public View createView() {
54
+        topTab = new TopTab(
55
+                getActivity(),
56
+                viewCreator.create(getActivity(), getId(), containerName)
57
+        );
58
+        return topTab;
59
+    }
60
+
61
+    @Override
62
+    public void destroy() {
63
+        super.destroy();
64
+        if (topTab != null) topTab.destroy();
65
+        topTab = null;
66
+    }
67
+
68
+    @Override
69
+    public void mergeNavigationOptions(NavigationOptions options) {
70
+        this.options.mergeWith(options);
71
+    }
72
+}

+ 22
- 5
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsAdapter.java View File

1
 package com.reactnativenavigation.viewcontrollers.toptabs;
1
 package com.reactnativenavigation.viewcontrollers.toptabs;
2
 
2
 
3
 import android.support.v4.view.PagerAdapter;
3
 import android.support.v4.view.PagerAdapter;
4
+import android.support.v4.view.ViewPager;
4
 import android.view.View;
5
 import android.view.View;
5
 import android.view.ViewGroup;
6
 import android.view.ViewGroup;
6
 
7
 
7
-import com.reactnativenavigation.viewcontrollers.ViewController;
8
-
9
 import java.util.List;
8
 import java.util.List;
10
 
9
 
11
-public class TopTabsAdapter extends PagerAdapter {
12
-    private List<ViewController> tabs;
10
+public class TopTabsAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener {
11
+    private List<TopTabController> tabs;
12
+    private int currentPage = 0;
13
 
13
 
14
-    TopTabsAdapter(List<ViewController> tabs) {
14
+    TopTabsAdapter(List<TopTabController> tabs) {
15
         this.tabs = tabs;
15
         this.tabs = tabs;
16
     }
16
     }
17
 
17
 
29
     public Object instantiateItem(ViewGroup container, int position) {
29
     public Object instantiateItem(ViewGroup container, int position) {
30
         return tabs.get(position).getView();
30
         return tabs.get(position).getView();
31
     }
31
     }
32
+
33
+    @Override
34
+    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
35
+
36
+    }
37
+
38
+    @Override
39
+    public void onPageSelected(int position) {
40
+        tabs.get(currentPage).onViewDisappear();
41
+        tabs.get(position).onViewAppeared();
42
+        currentPage = position;
43
+    }
44
+
45
+    @Override
46
+    public void onPageScrollStateChanged(int state) {
47
+
48
+    }
32
 }
49
 }

+ 33
- 7
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java View File

4
 import android.support.annotation.NonNull;
4
 import android.support.annotation.NonNull;
5
 import android.view.ViewGroup;
5
 import android.view.ViewGroup;
6
 
6
 
7
+import com.reactnativenavigation.parse.NavigationOptions;
8
+import com.reactnativenavigation.presentation.NavigationOptionsListener;
7
 import com.reactnativenavigation.viewcontrollers.ParentController;
9
 import com.reactnativenavigation.viewcontrollers.ParentController;
8
 import com.reactnativenavigation.viewcontrollers.ViewController;
10
 import com.reactnativenavigation.viewcontrollers.ViewController;
9
 import com.reactnativenavigation.views.TopTabsLayout;
11
 import com.reactnativenavigation.views.TopTabsLayout;
11
 import java.util.Collection;
13
 import java.util.Collection;
12
 import java.util.List;
14
 import java.util.List;
13
 
15
 
14
-public class TopTabsController extends ParentController {
16
+public class TopTabsController extends ParentController implements NavigationOptionsListener {
15
 
17
 
16
-    private List<ViewController> tabs;
18
+    private List<TopTabController> tabs;
19
+    private TopTabsLayout topTabsLayout;
17
 
20
 
18
-    public TopTabsController(Activity activity, String id, List<ViewController> tabs) {
21
+    public TopTabsController(Activity activity, String id, List<TopTabController> tabs) {
19
         super(activity, id);
22
         super(activity, id);
20
         this.tabs = tabs;
23
         this.tabs = tabs;
24
+        for (ViewController tab : tabs) {
25
+            tab.setParentController(this);
26
+        }
21
     }
27
     }
22
 
28
 
23
     @NonNull
29
     @NonNull
24
     @Override
30
     @Override
25
     protected ViewGroup createView() {
31
     protected ViewGroup createView() {
26
-        return new TopTabsLayout(getActivity(), tabs);
32
+        topTabsLayout = new TopTabsLayout(getActivity(), tabs);
33
+        return topTabsLayout;
27
     }
34
     }
28
 
35
 
29
     @NonNull
36
     @NonNull
30
     @Override
37
     @Override
31
-    public Collection<ViewController> getChildControllers() {
38
+    public Collection<? extends ViewController> getChildControllers() {
32
         return tabs;
39
         return tabs;
33
     }
40
     }
34
 
41
 
35
     @Override
42
     @Override
36
-    protected boolean isViewShown() {
37
-        return super.isViewShown();
43
+    public void onViewAppeared() {
44
+        topTabsLayout.performOnCurrentTab(TopTabController::onViewAppeared);
45
+    }
46
+
47
+    @Override
48
+    public void onViewDisappear() {
49
+        topTabsLayout.performOnCurrentTab(TopTabController::onViewDisappear);
50
+    }
51
+
52
+    @Override
53
+    public void applyOptions(NavigationOptions options) {
54
+        topTabsLayout.applyOptions(options);
55
+    }
56
+
57
+    @Override
58
+    public void mergeNavigationOptions(NavigationOptions options) {
59
+
60
+    }
61
+
62
+    public void switchToTab(int index) {
63
+        topTabsLayout.switchToTab(index);
38
     }
64
     }
39
 }
65
 }

+ 12
- 31
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsViewPager.java View File

3
 import android.annotation.SuppressLint;
3
 import android.annotation.SuppressLint;
4
 import android.content.Context;
4
 import android.content.Context;
5
 import android.support.v4.view.ViewPager;
5
 import android.support.v4.view.ViewPager;
6
-import android.view.View;
7
 import android.view.ViewGroup;
6
 import android.view.ViewGroup;
8
 
7
 
9
-import com.reactnativenavigation.viewcontrollers.ContainerViewController;
10
 import com.reactnativenavigation.viewcontrollers.ViewController;
8
 import com.reactnativenavigation.viewcontrollers.ViewController;
11
 
9
 
12
 import java.util.List;
10
 import java.util.List;
14
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
12
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
15
 
13
 
16
 @SuppressLint("ViewConstructor")
14
 @SuppressLint("ViewConstructor")
17
-public class TopTabsViewPager extends ViewPager implements ContainerViewController.IReactView {
15
+public class TopTabsViewPager extends ViewPager {
18
     private static final int OFFSCREEN_PAGE_LIMIT = 99;
16
     private static final int OFFSCREEN_PAGE_LIMIT = 99;
19
-    private final List<ViewController> tabs;
17
+    private List<TopTabController> tabs;
20
 
18
 
21
-    public TopTabsViewPager(Context context, List<ViewController> tabs) {
19
+    public TopTabsViewPager(Context context, List<TopTabController> tabs) {
22
         super(context);
20
         super(context);
23
         this.tabs = tabs;
21
         this.tabs = tabs;
24
-        init(tabs);
22
+        init();
25
     }
23
     }
26
 
24
 
27
-    private void init(List<ViewController> tabs) {
25
+    private void init() {
28
         setOffscreenPageLimit(OFFSCREEN_PAGE_LIMIT);
26
         setOffscreenPageLimit(OFFSCREEN_PAGE_LIMIT);
29
         for (ViewController tab : tabs) {
27
         for (ViewController tab : tabs) {
30
             addView(tab.getView(), new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
28
             addView(tab.getView(), new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
31
         }
29
         }
32
-        setAdapter(new TopTabsAdapter(tabs));
30
+        TopTabsAdapter adapter = new TopTabsAdapter(tabs);
31
+        setAdapter(adapter);
32
+        addOnPageChangeListener(adapter);
33
     }
33
     }
34
 
34
 
35
-    @Override
36
-    public boolean isReady() {
37
-        return false;
38
-    }
39
-
40
-    @Override
41
-    public View asView() {
42
-        return null;
43
-    }
44
-
45
-    @Override
46
     public void destroy() {
35
     public void destroy() {
47
-
48
-    }
49
-
50
-    @Override
51
-    public void sendContainerStart() {
52
-
53
-    }
54
-
55
-    @Override
56
-    public void sendContainerStop() {
57
-
36
+        for (ViewController tab : tabs) {
37
+            tab.destroy();
38
+        }
58
     }
39
     }
59
-}
40
+}

+ 7
- 2
lib/android/app/src/main/java/com/reactnativenavigation/views/Container.java View File

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
-import com.reactnativenavigation.viewcontrollers.ContainerViewController;
3
+import android.support.annotation.RestrictTo;
4
 
4
 
5
-public interface Container extends ContainerViewController.IReactView {
5
+import com.reactnativenavigation.parse.NavigationOptions;
6
+
7
+public interface Container {
8
+    void applyOptions(NavigationOptions options);
9
+
10
+    @RestrictTo(RestrictTo.Scope.TESTS)
6
     TopBar getTopBar();
11
     TopBar getTopBar();
7
 }
12
 }

+ 17
- 12
lib/android/app/src/main/java/com/reactnativenavigation/views/ContainerLayout.java View File

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
+import android.annotation.SuppressLint;
3
 import android.content.Context;
4
 import android.content.Context;
5
+import android.support.annotation.RestrictTo;
4
 import android.view.View;
6
 import android.view.View;
5
 import android.widget.LinearLayout;
7
 import android.widget.LinearLayout;
6
 
8
 
9
+import com.reactnativenavigation.parse.NavigationOptions;
10
+import com.reactnativenavigation.presentation.OptionsPresenter;
7
 import com.reactnativenavigation.viewcontrollers.ContainerViewController.IReactView;
11
 import com.reactnativenavigation.viewcontrollers.ContainerViewController.IReactView;
8
 
12
 
9
-public class ContainerLayout extends LinearLayout implements Container {
13
+@SuppressLint("ViewConstructor")
14
+public class ContainerLayout extends LinearLayout implements ReactContainer {
10
 
15
 
11
 	private TopBar topBar;
16
 	private TopBar topBar;
12
 	private IReactView reactView;
17
 	private IReactView reactView;
18
+	private final OptionsPresenter optionsPresenter;
13
 
19
 
14
 	public ContainerLayout(Context context, IReactView reactView) {
20
 	public ContainerLayout(Context context, IReactView reactView) {
15
 		super(context);
21
 		super(context);
16
 		this.topBar = new TopBar(context);
22
 		this.topBar = new TopBar(context);
17
 		this.reactView = reactView;
23
 		this.reactView = reactView;
18
-		initViews();
24
+        optionsPresenter = new OptionsPresenter(topBar, this);
25
+        initViews();
19
 	}
26
 	}
20
 
27
 
21
 	private void initViews() {
28
 	private void initViews() {
24
 		addView(reactView.asView());
31
 		addView(reactView.asView());
25
 	}
32
 	}
26
 
33
 
27
-	public ContainerLayout(Context context) {
28
-		super(context);
29
-	}
30
-
31
 	@Override
34
 	@Override
32
 	public boolean isReady() {
35
 	public boolean isReady() {
33
 		return reactView.isReady();
36
 		return reactView.isReady();
54
 	}
57
 	}
55
 
58
 
56
     @Override
59
     @Override
57
-	public TopBar getTopBar() {
58
-		return topBar;
59
-	}
60
+    public void applyOptions(NavigationOptions options) {
61
+        optionsPresenter.applyOptions(options);
62
+    }
60
 
63
 
61
-	public IReactView getReactView() {
62
-		return reactView;
63
-	}
64
+    @Override
65
+    @RestrictTo(RestrictTo.Scope.TESTS)
66
+    public TopBar getTopBar() {
67
+        return topBar;
68
+    }
64
 }
69
 }

+ 6
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/ReactContainer.java View File

1
+package com.reactnativenavigation.views;
2
+
3
+import com.reactnativenavigation.viewcontrollers.ContainerViewController;
4
+
5
+public interface ReactContainer extends Container, ContainerViewController.IReactView {
6
+}

+ 4
- 10
lib/android/app/src/main/java/com/reactnativenavigation/views/TopTab.java View File

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
+import android.annotation.SuppressLint;
3
 import android.content.Context;
4
 import android.content.Context;
4
 import android.view.View;
5
 import android.view.View;
5
 import android.widget.FrameLayout;
6
 import android.widget.FrameLayout;
6
 
7
 
7
 import com.reactnativenavigation.viewcontrollers.ContainerViewController.IReactView;
8
 import com.reactnativenavigation.viewcontrollers.ContainerViewController.IReactView;
8
 
9
 
10
+@SuppressLint("ViewConstructor")
9
 public class TopTab extends FrameLayout implements IReactView {
11
 public class TopTab extends FrameLayout implements IReactView {
10
 
12
 
11
-	private IReactView reactView;
13
+	private final IReactView reactView;
12
 
14
 
13
 	public TopTab(Context context, IReactView reactView) {
15
 	public TopTab(Context context, IReactView reactView) {
14
 		super(context);
16
 		super(context);
15
 		this.reactView = reactView;
17
 		this.reactView = reactView;
16
-		initViews();
17
-	}
18
-
19
-	private void initViews() {
20
-		addView(reactView.asView());
21
-	}
22
-
23
-	public TopTab(Context context) {
24
-		super(context);
18
+        addView(reactView.asView());
25
 	}
19
 	}
26
 
20
 
27
 	@Override
21
 	@Override

+ 37
- 3
lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsLayout.java View File

2
 
2
 
3
 import android.annotation.SuppressLint;
3
 import android.annotation.SuppressLint;
4
 import android.content.Context;
4
 import android.content.Context;
5
+import android.support.annotation.RestrictTo;
6
+import android.support.v4.view.ViewPager;
5
 import android.widget.LinearLayout;
7
 import android.widget.LinearLayout;
6
 
8
 
7
-import com.reactnativenavigation.viewcontrollers.ViewController;
9
+import com.reactnativenavigation.parse.NavigationOptions;
10
+import com.reactnativenavigation.presentation.OptionsPresenter;
11
+import com.reactnativenavigation.utils.Task;
12
+import com.reactnativenavigation.viewcontrollers.toptabs.TopTabController;
8
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsViewPager;
13
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsViewPager;
9
 
14
 
10
 import java.util.List;
15
 import java.util.List;
11
 
16
 
12
 @SuppressLint("ViewConstructor")
17
 @SuppressLint("ViewConstructor")
13
-public class TopTabsLayout extends LinearLayout {
18
+public class TopTabsLayout extends LinearLayout implements Container {
14
 
19
 
15
     private TopBar topBar;
20
     private TopBar topBar;
21
+    private List<TopTabController> tabs;
16
     private TopTabsViewPager viewPager;
22
     private TopTabsViewPager viewPager;
23
+    private final OptionsPresenter optionsPresenter;
17
 
24
 
18
-    public TopTabsLayout(Context context, List<ViewController> tabs) {
25
+    public TopTabsLayout(Context context, List<TopTabController> tabs) {
19
         super(context);
26
         super(context);
20
         topBar = new TopBar(context);
27
         topBar = new TopBar(context);
28
+        this.tabs = tabs;
21
         viewPager = new TopTabsViewPager(context, tabs);
29
         viewPager = new TopTabsViewPager(context, tabs);
30
+        optionsPresenter = new OptionsPresenter(topBar, this);
22
         initViews();
31
         initViews();
23
     }
32
     }
24
 
33
 
27
         addView(topBar);
36
         addView(topBar);
28
         addView(viewPager);
37
         addView(viewPager);
29
     }
38
     }
39
+
40
+    @Override
41
+    public void applyOptions(NavigationOptions options) {
42
+        optionsPresenter.applyOptions(options);
43
+    }
44
+
45
+    @Override
46
+    @RestrictTo(RestrictTo.Scope.TESTS)
47
+    public TopBar getTopBar() {
48
+        return topBar;
49
+    }
50
+
51
+    @RestrictTo(RestrictTo.Scope.TESTS)
52
+    public ViewPager getViewPager() {
53
+        return viewPager;
54
+    }
55
+
56
+
57
+    public void performOnCurrentTab(Task<TopTabController> task) {
58
+        task.run(tabs.get(viewPager.getCurrentItem()));
59
+    }
60
+
61
+    public void switchToTab(int index) {
62
+        viewPager.setCurrentItem(index);
63
+    }
30
 }
64
 }

+ 16
- 9
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestContainerLayout.java View File

3
 import android.content.Context;
3
 import android.content.Context;
4
 import android.view.View;
4
 import android.view.View;
5
 
5
 
6
-import com.reactnativenavigation.viewcontrollers.ContainerViewController;
7
-import com.reactnativenavigation.views.Container;
6
+import com.reactnativenavigation.parse.NavigationOptions;
7
+import com.reactnativenavigation.presentation.OptionsPresenter;
8
+import com.reactnativenavigation.views.ReactContainer;
8
 import com.reactnativenavigation.views.TopBar;
9
 import com.reactnativenavigation.views.TopBar;
9
 
10
 
10
-public class TestContainerLayout extends View implements ContainerViewController.IReactView, Container {
11
+public class TestContainerLayout extends View implements ReactContainer {
11
 
12
 
12
-	private TopBar topBar;
13
+    private final TopBar topBar;
14
+    private final OptionsPresenter optionsPresenter;
13
 
15
 
14
-	public TestContainerLayout(final Context context) {
16
+    public TestContainerLayout(final Context context) {
15
 		super(context);
17
 		super(context);
16
-		topBar = new TopBar(context);
17
-	}
18
+        topBar = new TopBar(context);
19
+        optionsPresenter = new OptionsPresenter(topBar, this);
20
+    }
21
+
22
+    public TopBar getTopBar() {
23
+        return topBar;
24
+    }
18
 
25
 
19
     @Override
26
     @Override
20
 	public boolean isReady() {
27
 	public boolean isReady() {
39
 	}
46
 	}
40
 
47
 
41
     @Override
48
     @Override
42
-    public TopBar getTopBar() {
43
-        return topBar;
49
+    public void applyOptions(NavigationOptions options) {
50
+        optionsPresenter.applyOptions(options);
44
     }
51
     }
45
 }
52
 }

+ 38
- 0
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TopTabLayoutMock.java View File

1
+package com.reactnativenavigation.mocks;
2
+
3
+import android.content.Context;
4
+import android.view.View;
5
+
6
+import com.reactnativenavigation.viewcontrollers.ContainerViewController;
7
+
8
+public class TopTabLayoutMock extends View implements ContainerViewController.IReactView {
9
+
10
+    public TopTabLayoutMock(Context context) {
11
+        super(context);
12
+    }
13
+
14
+    @Override
15
+    public boolean isReady() {
16
+        return false;
17
+    }
18
+
19
+    @Override
20
+    public View asView() {
21
+        return this;
22
+    }
23
+
24
+    @Override
25
+    public void destroy() {
26
+
27
+    }
28
+
29
+    @Override
30
+    public void sendContainerStart() {
31
+
32
+    }
33
+
34
+    @Override
35
+    public void sendContainerStop() {
36
+
37
+    }
38
+}

+ 7
- 7
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java View File

26
 		activity = newActivity();
26
 		activity = newActivity();
27
 		initialNavigationOptions = new NavigationOptions();
27
 		initialNavigationOptions = new NavigationOptions();
28
 		view = spy(new TestContainerLayout(activity));
28
 		view = spy(new TestContainerLayout(activity));
29
-		uut = new ContainerViewController(activity, "containerId1", "containerName",
30
-                new ContainerViewController.ReactViewCreator() {
31
-                    @Override
32
-                    public ContainerViewController.IReactView create(final Activity activity1, final String containerId, final String containerName) {
33
-                        return view;
34
-                    }
35
-                }, initialNavigationOptions);
29
+		uut = new ContainerViewController(activity,
30
+                "containerId1",
31
+                "containerName",
32
+                (activity1, containerId, containerName) -> view,
33
+                initialNavigationOptions
34
+        );
35
+		uut.ensureViewIsCreated();
36
 	}
36
 	}
37
 
37
 
38
 	@Test
38
 	@Test

+ 122
- 0
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java View File

1
+package com.reactnativenavigation.viewcontrollers;
2
+
3
+import android.app.Activity;
4
+import android.view.ViewGroup;
5
+
6
+import com.reactnativenavigation.BaseTest;
7
+import com.reactnativenavigation.mocks.TopTabLayoutMock;
8
+import com.reactnativenavigation.parse.NavigationOptions;
9
+import com.reactnativenavigation.viewcontrollers.ContainerViewController.IReactView;
10
+import com.reactnativenavigation.viewcontrollers.toptabs.TopTabController;
11
+import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsController;
12
+import com.reactnativenavigation.views.TopTabsLayout;
13
+
14
+import org.junit.Test;
15
+
16
+import java.util.ArrayList;
17
+import java.util.List;
18
+
19
+import static org.mockito.Mockito.spy;
20
+import static org.mockito.Mockito.times;
21
+import static org.mockito.Mockito.verify;
22
+
23
+public class TopTabsViewControllerTest extends BaseTest {
24
+
25
+    private static final int SIZE = 2;
26
+
27
+    private TopTabsController uut;
28
+    private List<TopTabLayoutMock> tabs = new ArrayList<>(SIZE);
29
+    private List<TopTabController> tabControllers = new ArrayList<>(SIZE);
30
+    private List<NavigationOptions> tabOptions = new ArrayList<>(SIZE);
31
+
32
+    @Override
33
+    public void beforeEach() {
34
+        super.beforeEach();
35
+        tabControllers.clear();
36
+        tabs.clear();
37
+        Activity activity = newActivity();
38
+        createTabs(activity);
39
+        uut = new TopTabsController(activity, "containerId", tabControllers);
40
+    }
41
+
42
+    private void createTabs(Activity activity) {
43
+        for (int i = 0; i < SIZE; i++) {
44
+            TopTabLayoutMock reactView = spy(new TopTabLayoutMock(activity));
45
+            tabs.add(reactView);
46
+            tabOptions.add(new NavigationOptions());
47
+            tabControllers.add(spy(new TopTabController(activity,
48
+                    "idTab" + i,
49
+                    "tab" + i,
50
+                    (activity1, containerId, containerName) -> reactView,
51
+                    tabOptions.get(i))
52
+            ));
53
+        }
54
+    }
55
+
56
+    @Test
57
+    public void createsViewFromContainerViewCreator() throws Exception {
58
+        uut.ensureViewIsCreated();
59
+        for (int i = 0; i < SIZE; i++) {
60
+            verify(tabControllers.get(i), times(1)).createView();
61
+        }
62
+    }
63
+
64
+    @Test
65
+    public void containerViewDestroyedOnDestroy() throws Exception {
66
+        uut.ensureViewIsCreated();
67
+        TopTabsLayout topTabs = (TopTabsLayout) uut.getView();
68
+        for (int i = 0; i < SIZE; i++) {
69
+            verify(tab(topTabs, i), times(0)).destroy();
70
+        }
71
+        uut.destroy();
72
+        for (ViewController tabController : tabControllers) {
73
+            verify(tabController, times(1)).destroy();
74
+        }
75
+    }
76
+
77
+    @Test
78
+    public void lifecycleMethodsSentWhenSelectedTabChanges() throws Exception {
79
+        uut.ensureViewIsCreated();
80
+        TopTabLayoutMock initialTab = tabs.get(0);
81
+        TopTabLayoutMock selectedTab = tabs.get(1);
82
+        uut.onViewAppeared();
83
+        uut.switchToTab(1);
84
+        verify(initialTab, times(1)).sendContainerStop();
85
+        verify(selectedTab, times(1)).sendContainerStart();
86
+        verify(selectedTab, times(0)).sendContainerStop();
87
+    }
88
+
89
+    @Test
90
+    public void lifecycleMethodsSentWhenSelectedPreviouslySelectedTab() throws Exception {
91
+        uut.ensureViewIsCreated();
92
+        uut.onViewAppeared();
93
+        uut.switchToTab(1);
94
+        uut.switchToTab(0);
95
+        verify(tabs.get(0), times(1)).sendContainerStop();
96
+        verify(tabs.get(0), times(2)).sendContainerStart();
97
+        verify(tabs.get(1), times(1)).sendContainerStart();
98
+        verify(tabs.get(1), times(1)).sendContainerStop();
99
+    }
100
+
101
+    @Test
102
+    public void setOptionsOfInitialTab() throws Exception {
103
+        uut.ensureViewIsCreated();
104
+        uut.onViewAppeared();
105
+        verify(tabControllers.get(0), times(1)).applyOptions(tabOptions.get(0));
106
+    }
107
+
108
+    @Test
109
+    public void setOptionsWhenTabChanges() throws Exception {
110
+        uut.ensureViewIsCreated();
111
+        uut.onViewAppeared();
112
+        verify(tabControllers.get(0), times(1)).applyOptions(tabOptions.get(0));
113
+        uut.switchToTab(1);
114
+        verify(tabControllers.get(1), times(1)).applyOptions(tabOptions.get(1));
115
+        uut.switchToTab(0);
116
+        verify(tabControllers.get(0), times(2)).applyOptions(tabOptions.get(0));
117
+    }
118
+
119
+    private IReactView tab(TopTabsLayout topTabs, final int index) {
120
+        return (IReactView) ((ViewGroup) topTabs.getViewPager().getChildAt(index)).getChildAt(0);
121
+    }
122
+}

+ 3
- 3
lib/src/commands/LayoutTreeParser.js View File

13
       return this._createTabs(simpleJsonApi.bottomTabs);
13
       return this._createTabs(simpleJsonApi.bottomTabs);
14
     }
14
     }
15
     if (simpleJsonApi.topTabs) {
15
     if (simpleJsonApi.topTabs) {
16
-      return this._createTopTabsContainer(simpleJsonApi.topTabs);
16
+      return this._createTopTabs(simpleJsonApi.topTabs);
17
     }
17
     }
18
     if (simpleJsonApi.name) {
18
     if (simpleJsonApi.name) {
19
       return this._createContainer(simpleJsonApi);
19
       return this._createContainer(simpleJsonApi);
36
     };
36
     };
37
   }
37
   }
38
 
38
 
39
-  _createTopTabsContainer(topTabs) {
39
+  _createTopTabs(topTabs) {
40
     return {
40
     return {
41
-      type: LayoutTypes.TopTabsContainer,
41
+      type: LayoutTypes.TopTabs,
42
       children: _.map(topTabs, (t) => this._createTopTab(t.container))
42
       children: _.map(topTabs, (t) => this._createTopTab(t.container))
43
     };
43
     };
44
   }
44
   }

+ 1
- 1
lib/src/commands/LayoutTreeParser.test.js View File

289
     it('parses bottomTabs with side menus', () => {
289
     it('parses bottomTabs with side menus', () => {
290
       expect(uut.parseFromSimpleJSON(SimpleLayouts.singleScreenWithTopTabs))
290
       expect(uut.parseFromSimpleJSON(SimpleLayouts.singleScreenWithTopTabs))
291
         .toEqual({
291
         .toEqual({
292
-          type: 'TopTabsContainer',
292
+          type: 'TopTabs',
293
           children: [
293
           children: [
294
             {
294
             {
295
               type: 'TopTab',
295
               type: 'TopTab',

+ 1
- 1
lib/src/commands/LayoutTypes.js View File

7
   SideMenuLeft: 'SideMenuLeft',
7
   SideMenuLeft: 'SideMenuLeft',
8
   SideMenuRight: 'SideMenuRight',
8
   SideMenuRight: 'SideMenuRight',
9
   CustomDialog: 'CustomDialog',
9
   CustomDialog: 'CustomDialog',
10
-  TopTabsContainer: 'TopTabsContainer',
10
+  TopTabs: 'TopTabs',
11
   TopTab: 'TopTab'
11
   TopTab: 'TopTab'
12
 };
12
 };

+ 5
- 0
playground/android/app/build.gradle View File

11
     compileSdkVersion 25
11
     compileSdkVersion 25
12
     buildToolsVersion "27.0.1"
12
     buildToolsVersion "27.0.1"
13
 
13
 
14
+    compileOptions {
15
+        sourceCompatibility JavaVersion.VERSION_1_8
16
+        targetCompatibility JavaVersion.VERSION_1_8
17
+    }
18
+
14
     defaultConfig {
19
     defaultConfig {
15
         applicationId "com.reactnativenavigation.playground"
20
         applicationId "com.reactnativenavigation.playground"
16
         minSdkVersion 19
21
         minSdkVersion 19

+ 52
- 0
playground/src/containers/TopTabOptionsScreen.js View File

1
+const React = require('react');
2
+const { PureComponent } = require('react');
3
+
4
+const { View, Text } = require('react-native');
5
+
6
+class TopTabOptionsScreen extends PureComponent {
7
+  static get navigationOptions() {
8
+    return {
9
+      topBar: {
10
+        title: 'Tab 1',
11
+        textColor: 'black',
12
+        textFontSize: 16,
13
+        textFontFamily: 'HelveticaNeue-Italic'
14
+      }
15
+    };
16
+  }
17
+
18
+  render() {
19
+    return (
20
+      <View style={styles.root}>
21
+        <Text style={styles.h1}>{this.props.text || 'Top Tab Screen'}</Text>
22
+        <Text style={styles.footer}>{`this.props.containerId = ${this.props.containerId}`}</Text>
23
+      </View>
24
+    );
25
+  }
26
+}
27
+
28
+const styles = {
29
+  root: {
30
+    flexGrow: 1,
31
+    justifyContent: 'center',
32
+    alignItems: 'center',
33
+    backgroundColor: '#f5fcff'
34
+  },
35
+  h1: {
36
+    fontSize: 24,
37
+    textAlign: 'center',
38
+    margin: 10
39
+  },
40
+  h2: {
41
+    fontSize: 12,
42
+    textAlign: 'center',
43
+    margin: 10
44
+  },
45
+  footer: {
46
+    fontSize: 10,
47
+    color: '#888',
48
+    marginTop: 10
49
+  }
50
+};
51
+
52
+module.exports = TopTabOptionsScreen;

+ 20
- 0
playground/src/containers/TopTabScreen.js View File

1
 const React = require('react');
1
 const React = require('react');
2
 const { PureComponent } = require('react');
2
 const { PureComponent } = require('react');
3
 const { View, Text } = require('react-native');
3
 const { View, Text } = require('react-native');
4
+const Navigation = require('react-native-navigation');
4
 
5
 
5
 class TopTabScreen extends PureComponent {
6
 class TopTabScreen extends PureComponent {
7
+  static get navigationOptions() {
8
+    return {
9
+      topBar: {
10
+        textColor: 'black',
11
+        textFontSize: 16,
12
+        textFontFamily: 'HelveticaNeue-Italic'
13
+      }
14
+    };
15
+  }
16
+
17
+  constructor(props) {
18
+    super(props);
19
+    Navigation.setOptions(this.props.containerId, {
20
+      topBar: {
21
+        title: this.props.title
22
+      }
23
+    });
24
+  }
25
+
6
   render() {
26
   render() {
7
     return (
27
     return (
8
       <View style={styles.root}>
28
       <View style={styles.root}>

+ 4
- 1
playground/src/containers/WelcomeScreen.js View File

152
       topTabs: [
152
       topTabs: [
153
         {
153
         {
154
           container: {
154
           container: {
155
-            name: 'navigation.playground.TopTabScreen',
155
+            name: 'navigation.playground.TopTabOptionsScreen',
156
             passProps: {
156
             passProps: {
157
+              title: 'Tab 1',
157
               text: 'This is top tab 1'
158
               text: 'This is top tab 1'
158
             }
159
             }
159
           }
160
           }
162
           container: {
163
           container: {
163
             name: 'navigation.playground.TopTabScreen',
164
             name: 'navigation.playground.TopTabScreen',
164
             passProps: {
165
             passProps: {
166
+              title: 'Tab 2',
165
               text: 'This is top tab 2'
167
               text: 'This is top tab 2'
166
             }
168
             }
167
           }
169
           }
170
           container: {
172
           container: {
171
             name: 'navigation.playground.TopTabScreen',
173
             name: 'navigation.playground.TopTabScreen',
172
             passProps: {
174
             passProps: {
175
+              title: 'Tab 3',
173
               text: 'This is top tab 3'
176
               text: 'This is top tab 3'
174
             }
177
             }
175
           }
178
           }

+ 2
- 0
playground/src/containers/index.js View File

14
 const BandHandlerScreen = require('./BackHandlerScreen');
14
 const BandHandlerScreen = require('./BackHandlerScreen');
15
 const SideMenuScreen = require('./SideMenuScreen');
15
 const SideMenuScreen = require('./SideMenuScreen');
16
 const TopTabScreen = require('./TopTabScreen');
16
 const TopTabScreen = require('./TopTabScreen');
17
+const TopTabOptionsScreen = require('./TopTabOptionsScreen');
17
 
18
 
18
 function registerContainers() {
19
 function registerContainers() {
19
   Navigation.registerContainer(`navigation.playground.CustomTransitionDestination`, () => CustomTransitionDestination);
20
   Navigation.registerContainer(`navigation.playground.CustomTransitionDestination`, () => CustomTransitionDestination);
31
   Navigation.registerContainer('navigation.playground.BackHandlerScreen', () => BandHandlerScreen);
32
   Navigation.registerContainer('navigation.playground.BackHandlerScreen', () => BandHandlerScreen);
32
   Navigation.registerContainer('navigation.playground.SideMenuScreen', () => SideMenuScreen);
33
   Navigation.registerContainer('navigation.playground.SideMenuScreen', () => SideMenuScreen);
33
   Navigation.registerContainer('navigation.playground.TopTabScreen', () => TopTabScreen);
34
   Navigation.registerContainer('navigation.playground.TopTabScreen', () => TopTabScreen);
35
+  Navigation.registerContainer('navigation.playground.TopTabOptionsScreen', () => TopTabOptionsScreen);
34
 }
36
 }
35
 
37
 
36
 module.exports = {
38
 module.exports = {