Daniel Zlotin 6 years ago
parent
commit
8d6b0a7881
66 changed files with 843 additions and 374 deletions
  1. 4
    1
      e2e/Orientations.test.js
  2. 7
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java
  3. 88
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TitleOptions.java
  4. 30
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarBackground.java
  5. 22
    71
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarOptions.java
  6. 9
    15
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java
  7. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java
  8. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java
  9. 3
    3
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/SideMenuController.java
  10. 13
    10
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java
  11. 38
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TitleBarReactViewController.java
  12. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TopBarButtonController.java
  13. 6
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java
  14. 4
    4
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java
  15. 3
    3
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java
  16. 14
    12
      lib/android/app/src/main/java/com/reactnativenavigation/views/StackLayout.java
  17. 17
    4
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java
  18. 0
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBarButtonCreator.java
  19. 2
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBarReactButtonView.java
  20. 36
    7
      lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBar.java
  21. 23
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBarReactView.java
  22. 20
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBarReactViewCreator.java
  23. 20
    0
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TitleBarReactViewCreatorMock.java
  24. 1
    1
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TopBarButtonCreatorMock.java
  25. 31
    21
      lib/android/app/src/test/java/com/reactnativenavigation/parse/OptionsTest.java
  26. 8
    3
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/BottomTabsControllerTest.java
  27. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ComponentViewControllerTest.java
  28. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/FloatingActionButtonTest.java
  29. 7
    6
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java
  30. 16
    15
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java
  31. 13
    8
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java
  32. 15
    11
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java
  33. 46
    2
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TitleBarTest.java
  34. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopBarButtonControllerTest.java
  35. 17
    11
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java
  36. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ViewControllerTest.java
  37. 3
    2
      lib/android/app/src/test/java/com/reactnativenavigation/views/TopBarTest.java
  38. 6
    0
      lib/ios/RNNBottomTabsOptions.m
  39. 5
    2
      lib/ios/RNNCustomTitleView.h
  40. 41
    33
      lib/ios/RNNCustomTitleView.m
  41. 6
    0
      lib/ios/RNNNavigationButtons.m
  42. 1
    0
      lib/ios/RNNNavigationOptions.h
  43. 3
    3
      lib/ios/RNNNavigationOptions.m
  44. 6
    1
      lib/ios/RNNOptions.m
  45. 25
    6
      lib/ios/RNNRootViewController.m
  46. 13
    0
      lib/ios/RNNTitleOptions.h
  47. 32
    0
      lib/ios/RNNTitleOptions.m
  48. 8
    6
      lib/ios/RNNTopBarOptions.h
  49. 37
    28
      lib/ios/RNNTopBarOptions.m
  50. 8
    0
      lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj
  51. 1
    1
      lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m
  52. 2
    2
      lib/ios/ReactNativeNavigationTests/RNNNavigationOptionsTest.m
  53. 12
    12
      lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m
  54. 4
    2
      lib/src/commands/LayoutTreeParser.test.ts
  55. 3
    1
      playground/src/screens/BackHandlerModalScreen.js
  56. 5
    3
      playground/src/screens/BackHandlerScreen.js
  57. 4
    8
      playground/src/screens/CustomTopBar.js
  58. 4
    2
      playground/src/screens/CustomTransitionDestination.js
  59. 4
    2
      playground/src/screens/CustomTransitionOrigin.js
  60. 33
    18
      playground/src/screens/OptionsScreen.js
  61. 3
    1
      playground/src/screens/PushedScreen.js
  62. 5
    3
      playground/src/screens/ScrollViewScreen.js
  63. 11
    7
      playground/src/screens/TopTabOptionsScreen.js
  64. 5
    3
      playground/src/screens/TopTabScreen.js
  65. 28
    9
      playground/src/screens/WelcomeScreen.js
  66. 1
    0
      playground/src/testIDs.js

+ 4
- 1
e2e/Orientations.test.js View File

8
 
8
 
9
   beforeEach(async () => {
9
   beforeEach(async () => {
10
     await device.relaunchApp();
10
     await device.relaunchApp();
11
-    waitForDeviceToSettleAfterOrientationChangeAndroid = ms => new Promise(res => setTimeout(res, device.getPlatform() === 'ios' ? 0 : 150));
11
+    waitForDeviceToSettleAfterOrientationChangeAndroid = ms => new Promise(res => setTimeout(res, device.getPlatform() === 'ios' ? 0 : 400));
12
   });
12
   });
13
 
13
 
14
   it('default allows all', async () => {
14
   it('default allows all', async () => {
15
     await elementById(testIDs.ORIENTATION_BUTTON).tap();
15
     await elementById(testIDs.ORIENTATION_BUTTON).tap();
16
     await elementById(testIDs.DEFAULT_ORIENTATION_BUTTON).tap();
16
     await elementById(testIDs.DEFAULT_ORIENTATION_BUTTON).tap();
17
+    waitForDeviceToSettleAfterOrientationChangeAndroid();
17
     await expect(elementById(testIDs.PORTRAIT_ELEMENT)).toBeVisible();
18
     await expect(elementById(testIDs.PORTRAIT_ELEMENT)).toBeVisible();
18
     await device.setOrientation('landscape');
19
     await device.setOrientation('landscape');
20
+    waitForDeviceToSettleAfterOrientationChangeAndroid();
19
     await expect(elementById(testIDs.LANDSCAPE_ELEMENT)).toBeVisible();
21
     await expect(elementById(testIDs.LANDSCAPE_ELEMENT)).toBeVisible();
20
     await device.setOrientation('portrait');
22
     await device.setOrientation('portrait');
21
     waitForDeviceToSettleAfterOrientationChangeAndroid();
23
     waitForDeviceToSettleAfterOrientationChangeAndroid();
28
     await elementById(testIDs.LANDSCAPE_PORTRAIT_ORIENTATION_BUTTON).tap();
30
     await elementById(testIDs.LANDSCAPE_PORTRAIT_ORIENTATION_BUTTON).tap();
29
     await expect(element(by.id(testIDs.PORTRAIT_ELEMENT))).toBeVisible();
31
     await expect(element(by.id(testIDs.PORTRAIT_ELEMENT))).toBeVisible();
30
     await device.setOrientation('landscape');
32
     await device.setOrientation('landscape');
33
+    waitForDeviceToSettleAfterOrientationChangeAndroid();
31
     await expect(element(by.id(testIDs.LANDSCAPE_ELEMENT))).toBeVisible();
34
     await expect(element(by.id(testIDs.LANDSCAPE_ELEMENT))).toBeVisible();
32
     await device.setOrientation('portrait');
35
     await device.setOrientation('portrait');
33
     waitForDeviceToSettleAfterOrientationChangeAndroid();
36
     waitForDeviceToSettleAfterOrientationChangeAndroid();

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

15
 import com.reactnativenavigation.viewcontrollers.externalcomponent.ExternalComponentViewController;
15
 import com.reactnativenavigation.viewcontrollers.externalcomponent.ExternalComponentViewController;
16
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsController;
16
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsController;
17
 import com.reactnativenavigation.views.ComponentViewCreator;
17
 import com.reactnativenavigation.views.ComponentViewCreator;
18
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
18
 import com.reactnativenavigation.views.TopBarButtonCreator;
19
 import com.reactnativenavigation.views.TopBarButtonCreator;
19
 import com.reactnativenavigation.views.TopTabsLayoutCreator;
20
 import com.reactnativenavigation.views.TopTabsLayoutCreator;
20
 
21
 
118
     }
119
     }
119
 
120
 
120
 	private ViewController createStack(LayoutNode node) {
121
 	private ViewController createStack(LayoutNode node) {
121
-        StackController stackController = new StackController(activity, new TopBarButtonCreator(reactInstanceManager), node.id, getOptions(node));
122
+        StackController stackController = new StackController(activity,
123
+                new TopBarButtonCreator(reactInstanceManager),
124
+                new TitleBarReactViewCreator(reactInstanceManager),
125
+                node.id,
126
+                getOptions(node)
127
+        );
122
         addChildrenToStack(node.children, stackController);
128
         addChildrenToStack(node.children, stackController);
123
         return stackController;
129
         return stackController;
124
 	}
130
 	}

+ 88
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/TitleOptions.java View File

1
+package com.reactnativenavigation.parse;
2
+
3
+import android.graphics.Typeface;
4
+import android.support.annotation.Nullable;
5
+import android.util.Log;
6
+
7
+import com.reactnativenavigation.BuildConfig;
8
+import com.reactnativenavigation.parse.params.Color;
9
+import com.reactnativenavigation.parse.params.Fraction;
10
+import com.reactnativenavigation.parse.params.NullColor;
11
+import com.reactnativenavigation.parse.params.NullFraction;
12
+import com.reactnativenavigation.parse.params.NullText;
13
+import com.reactnativenavigation.parse.params.Text;
14
+import com.reactnativenavigation.parse.parsers.ColorParser;
15
+import com.reactnativenavigation.parse.parsers.FractionParser;
16
+import com.reactnativenavigation.parse.parsers.TextParser;
17
+import com.reactnativenavigation.utils.TypefaceLoader;
18
+
19
+import org.json.JSONObject;
20
+
21
+public class TitleOptions {
22
+    public enum Alignment {
23
+        Center, Fill, Default;
24
+
25
+        public static Alignment fromString(String alignment) {
26
+            switch (alignment) {
27
+                case "center":
28
+                    return Center;
29
+                case "fill":
30
+                    return Fill;
31
+                default:
32
+                    return Default;
33
+            }
34
+        }
35
+    }
36
+
37
+    public static TitleOptions parse(TypefaceLoader typefaceManager, JSONObject json) {
38
+        final TitleOptions options = new TitleOptions();
39
+        if (json == null) {
40
+            return options;
41
+        }
42
+
43
+        options.text = TextParser.parse(json, "text");
44
+        options.color = ColorParser.parse(json, "color");
45
+        options.fontSize = FractionParser.parse(json, "fontSize");
46
+        options.fontFamily = typefaceManager.getTypeFace(json.optString("fontFamily", ""));
47
+        options.component = TextParser.parse(json, "component");
48
+        options.alignment = Alignment.fromString(TextParser.parse(json, "alignment").get(""));
49
+
50
+        validate(options);
51
+
52
+        return options;
53
+    }
54
+
55
+    public Text text = new NullText();
56
+    public Color color = new NullColor();
57
+    public Fraction fontSize = new NullFraction();
58
+    @Nullable public Typeface fontFamily;
59
+    public Text component = new NullText();
60
+    public Alignment alignment = Alignment.Default;
61
+
62
+    void mergeWith(final TitleOptions other) {
63
+        if (other.text.hasValue()) text = other.text;
64
+        if (other.color.hasValue()) color = other.color;
65
+        if (other.fontSize.hasValue()) fontSize = other.fontSize;
66
+        if (other.fontFamily != null) fontFamily = other.fontFamily;
67
+        if (other.component.hasValue()) component = other.component;
68
+        if (other.alignment != Alignment.Default) alignment = other.alignment;
69
+        validate(this);
70
+    }
71
+
72
+    void mergeWithDefault(TitleOptions defaultOptions) {
73
+        if (!text.hasValue()) text = defaultOptions.text;
74
+        if (!color.hasValue()) color = defaultOptions.color;
75
+        if (!fontSize.hasValue()) fontSize = defaultOptions.fontSize;
76
+        if (fontFamily == null) fontFamily = defaultOptions.fontFamily;
77
+        if (!component.hasValue()) component = defaultOptions.component;
78
+        if (alignment == Alignment.Default) alignment = defaultOptions.alignment;
79
+        validate(this);
80
+    }
81
+
82
+    private static void validate(TitleOptions options) {
83
+        if (options.component.hasValue() && options.text.hasValue()) {
84
+            if (BuildConfig.DEBUG) Log.w("RNN", "A screen can't use both text and component - clearing text.");
85
+            options.text = new Text("");
86
+        }
87
+    }
88
+}

+ 30
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarBackground.java View File

1
+package com.reactnativenavigation.parse;
2
+
3
+import com.reactnativenavigation.parse.params.Color;
4
+import com.reactnativenavigation.parse.params.NullColor;
5
+import com.reactnativenavigation.parse.parsers.ColorParser;
6
+
7
+import org.json.JSONObject;
8
+
9
+public class TopBarBackground {
10
+    public static TopBarBackground parse(JSONObject json) {
11
+        TopBarBackground options = new TopBarBackground();
12
+        if (json == null) {
13
+            return options;
14
+        }
15
+
16
+        options.color = ColorParser.parse(json, "color");
17
+
18
+        return options;
19
+    }
20
+
21
+    public Color color = new NullColor();
22
+
23
+    void mergeWith(final TopBarBackground other) {
24
+        if (other.color.hasValue()) color = other.color;
25
+    }
26
+
27
+    void mergeWithDefault(TopBarBackground defaultOptions) {
28
+        if (!color.hasValue()) color = defaultOptions.color;
29
+    }
30
+}

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

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
 
3
 
4
-import android.graphics.Typeface;
5
 import android.support.annotation.Nullable;
4
 import android.support.annotation.Nullable;
6
 
5
 
7
 import com.reactnativenavigation.parse.params.Bool;
6
 import com.reactnativenavigation.parse.params.Bool;
8
 import com.reactnativenavigation.parse.params.Button;
7
 import com.reactnativenavigation.parse.params.Button;
9
-import com.reactnativenavigation.parse.params.Color;
10
-import com.reactnativenavigation.parse.params.Fraction;
11
 import com.reactnativenavigation.parse.params.NullBool;
8
 import com.reactnativenavigation.parse.params.NullBool;
12
-import com.reactnativenavigation.parse.params.NullColor;
13
-import com.reactnativenavigation.parse.params.NullFraction;
14
 import com.reactnativenavigation.parse.params.NullText;
9
 import com.reactnativenavigation.parse.params.NullText;
15
 import com.reactnativenavigation.parse.params.Text;
10
 import com.reactnativenavigation.parse.params.Text;
16
 import com.reactnativenavigation.parse.parsers.BoolParser;
11
 import com.reactnativenavigation.parse.parsers.BoolParser;
17
-import com.reactnativenavigation.parse.parsers.ColorParser;
18
-import com.reactnativenavigation.parse.parsers.FractionParser;
19
 import com.reactnativenavigation.parse.parsers.TextParser;
12
 import com.reactnativenavigation.parse.parsers.TextParser;
20
 import com.reactnativenavigation.utils.TypefaceLoader;
13
 import com.reactnativenavigation.utils.TypefaceLoader;
21
 
14
 
29
         TopBarOptions options = new TopBarOptions();
22
         TopBarOptions options = new TopBarOptions();
30
         if (json == null) return options;
23
         if (json == null) return options;
31
 
24
 
32
-        options.title = TextParser.parse(json, "title");
33
-        options.backgroundColor = ColorParser.parse(json, "backgroundColor");
34
-        options.textColor = ColorParser.parse(json, "textColor");
35
-        options.textFontSize = FractionParser.parse(json, "textFontSize");
36
-        options.textFontFamily = typefaceManager.getTypeFace(json.optString("textFontFamily", ""));
25
+        options.title = TitleOptions.parse(typefaceManager, json.optJSONObject("title"));
26
+        options.background = TopBarBackground.parse(json.optJSONObject("background"));
37
         options.visible = BoolParser.parse(json, "visible");
27
         options.visible = BoolParser.parse(json, "visible");
38
         options.animate = BoolParser.parse(json,"animate");
28
         options.animate = BoolParser.parse(json,"animate");
39
         options.hideOnScroll = BoolParser.parse(json,"hideOnScroll");
29
         options.hideOnScroll = BoolParser.parse(json,"hideOnScroll");
45
         return options;
35
         return options;
46
     }
36
     }
47
 
37
 
48
-    public Text title = new NullText();
38
+    public TitleOptions title = new TitleOptions();
49
     public Text testId = new NullText();
39
     public Text testId = new NullText();
50
-    public Color backgroundColor = new NullColor();
51
-    public Color textColor = new NullColor();
52
-    public Fraction textFontSize = new NullFraction();
53
-    @Nullable public Typeface textFontFamily;
40
+    public TopBarBackground background = new TopBarBackground();
54
     public Bool visible = new NullBool();
41
     public Bool visible = new NullBool();
55
     public Bool animate = new NullBool();
42
     public Bool animate = new NullBool();
56
     public Bool hideOnScroll = new NullBool();
43
     public Bool hideOnScroll = new NullBool();
59
     @Nullable public ArrayList<Button> rightButtons;
46
     @Nullable public ArrayList<Button> rightButtons;
60
 
47
 
61
     void mergeWith(final TopBarOptions other) {
48
     void mergeWith(final TopBarOptions other) {
62
-        if (other.testId.hasValue()) {
63
-            testId = other.testId;
64
-        }
65
-        if (other.title.hasValue())
66
-            title = other.title;
67
-        if (other.backgroundColor.hasValue())
68
-            backgroundColor = other.backgroundColor;
69
-        if (other.textColor.hasValue())
70
-            textColor = other.textColor;
71
-        if (other.textFontSize.hasValue())
72
-            textFontSize = other.textFontSize;
73
-        if (other.textFontFamily != null)
74
-            textFontFamily = other.textFontFamily;
75
-        if (other.visible.hasValue()) {
76
-            visible = other.visible;
77
-        }
78
-        if (other.animate.hasValue()) {
79
-            animate = other.animate;
80
-        }
81
-        if (other.hideOnScroll.hasValue()) {
82
-            hideOnScroll = other.hideOnScroll;
83
-        }
84
-        if (other.drawBehind.hasValue()) {
85
-            drawBehind = other.drawBehind;
86
-        }
87
-        if (other.leftButtons != null)
88
-            leftButtons = other.leftButtons;
89
-        if (other.rightButtons != null)
90
-            rightButtons = other.rightButtons;
49
+        title.mergeWith(other.title);
50
+        background.mergeWith(other.background);
51
+        if (other.testId.hasValue()) testId = other.testId;
52
+        if (other.visible.hasValue()) visible = other.visible;
53
+        if (other.animate.hasValue()) animate = other.animate;
54
+        if (other.hideOnScroll.hasValue()) hideOnScroll = other.hideOnScroll;
55
+        if (other.drawBehind.hasValue()) drawBehind = other.drawBehind;
56
+        if (other.leftButtons != null) leftButtons = other.leftButtons;
57
+        if (other.rightButtons != null) rightButtons = other.rightButtons;
91
     }
58
     }
92
 
59
 
93
     void mergeWithDefault(TopBarOptions defaultOptions) {
60
     void mergeWithDefault(TopBarOptions defaultOptions) {
94
-        if (title == null)
95
-            title = defaultOptions.title;
96
-        if (!backgroundColor.hasValue())
97
-            backgroundColor = defaultOptions.backgroundColor;
98
-        if (!textColor.hasValue())
99
-            textColor = defaultOptions.textColor;
100
-        if (!textFontSize.hasValue())
101
-            textFontSize = defaultOptions.textFontSize;
102
-        if (textFontFamily == null)
103
-            textFontFamily = defaultOptions.textFontFamily;
104
-        if (!visible.hasValue())
105
-            visible = defaultOptions.visible;
106
-        if (!animate.hasValue())
107
-            animate = defaultOptions.animate;
108
-        if (!hideOnScroll.hasValue())
109
-            hideOnScroll = defaultOptions.hideOnScroll;
110
-        if (!drawBehind.hasValue())
111
-            drawBehind = defaultOptions.drawBehind;
112
-        if (leftButtons == null)
113
-            leftButtons = defaultOptions.leftButtons;
114
-        if (rightButtons == null)
115
-            rightButtons = defaultOptions.rightButtons;
116
-        if (!testId.hasValue()) {
117
-            testId = defaultOptions.testId;
118
-        }
61
+        title.mergeWithDefault(defaultOptions.title);
62
+        background.mergeWithDefault(defaultOptions.background);
63
+        if (!visible.hasValue()) visible = defaultOptions.visible;
64
+        if (!animate.hasValue()) animate = defaultOptions.animate;
65
+        if (!hideOnScroll.hasValue()) hideOnScroll = defaultOptions.hideOnScroll;
66
+        if (!drawBehind.hasValue()) drawBehind = defaultOptions.drawBehind;
67
+        if (leftButtons == null) leftButtons = defaultOptions.leftButtons;
68
+        if (rightButtons == null) rightButtons = defaultOptions.rightButtons;
69
+        if (!testId.hasValue()) testId = defaultOptions.testId;
119
     }
70
     }
120
 }
71
 }

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

16
 
16
 
17
 public class OptionsPresenter {
17
 public class OptionsPresenter {
18
     private TopBar topBar;
18
     private TopBar topBar;
19
-    private Component component;
20
-
21
-    public OptionsPresenter(TopBar topBar, Component component) {
22
-        this.topBar = topBar;
23
-        this.component = component;
24
-    }
25
 
19
 
26
     public OptionsPresenter(TopBar topBar) {
20
     public OptionsPresenter(TopBar topBar) {
27
         this.topBar = topBar;
21
         this.topBar = topBar;
28
     }
22
     }
29
 
23
 
30
-    public void applyOptions(Options options) {
24
+    public void applyChildOptions(Options options, Component child) {
31
         applyOrientation(options.orientationOptions);
25
         applyOrientation(options.orientationOptions);
32
         applyButtons(options.topBarOptions.leftButtons, options.topBarOptions.rightButtons);
26
         applyButtons(options.topBarOptions.leftButtons, options.topBarOptions.rightButtons);
33
-        applyTopBarOptions(options.topBarOptions);
27
+        applyTopBarOptions(options.topBarOptions, child);
34
         applyTopTabsOptions(options.topTabsOptions);
28
         applyTopTabsOptions(options.topTabsOptions);
35
         applyTopTabOptions(options.topTabOptions);
29
         applyTopTabOptions(options.topTabOptions);
36
     }
30
     }
39
         ((Activity) topBar.getContext()).setRequestedOrientation(options.getValue());
33
         ((Activity) topBar.getContext()).setRequestedOrientation(options.getValue());
40
     }
34
     }
41
 
35
 
42
-    private void applyTopBarOptions(TopBarOptions options) {
43
-        if (options.title.hasValue()) topBar.setTitle(options.title.get());
44
-        topBar.setBackgroundColor(options.backgroundColor);
45
-        topBar.setTitleTextColor(options.textColor);
46
-        topBar.setTitleFontSize(options.textFontSize);
36
+    private void applyTopBarOptions(TopBarOptions options, Component component) {
37
+        if (options.title.text.hasValue()) topBar.setTitle(options.title.text.get());
38
+        if (options.title.component.hasValue()) topBar.setComponent(options.title.component.get(), options.title.alignment);
39
+        topBar.setBackgroundColor(options.background.color);
40
+        topBar.setTitleTextColor(options.title.color);
41
+        topBar.setTitleFontSize(options.title.fontSize);
47
         if (options.testId.hasValue()) topBar.setTestId(options.testId.get());
42
         if (options.testId.hasValue()) topBar.setTestId(options.testId.get());
48
 
43
 
49
-        topBar.setTitleTypeface(options.textFontFamily);
44
+        topBar.setTitleTypeface(options.title.fontFamily);
50
         if (options.visible.isFalse()) {
45
         if (options.visible.isFalse()) {
51
             topBar.hide(options.animate);
46
             topBar.hide(options.animate);
52
         }
47
         }
58
         } else if (options.drawBehind.isFalseOrUndefined()) {
53
         } else if (options.drawBehind.isFalseOrUndefined()) {
59
             component.drawBelowTopBar(topBar);
54
             component.drawBelowTopBar(topBar);
60
         }
55
         }
61
-
62
         if (options.hideOnScroll.isTrue()) {
56
         if (options.hideOnScroll.isTrue()) {
63
             if (component instanceof IReactView) {
57
             if (component instanceof IReactView) {
64
                 topBar.enableCollapse(((IReactView) component).getScrollEventListener());
58
                 topBar.enableCollapse(((IReactView) component).getScrollEventListener());

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

62
     public void mergeOptions(Options options) {
62
     public void mergeOptions(Options options) {
63
         this.options = this.options.mergeWith(options);
63
         this.options = this.options.mergeWith(options);
64
         view.applyOptions(this.options);
64
         view.applyOptions(this.options);
65
-        applyOnParentController(parentController -> parentController.applyOptions(this.options, view));
65
+        applyOnParentController(parentController -> parentController.applyChildOptions(this.options, view));
66
     }
66
     }
67
 
67
 
68
     ReactComponent getComponent() {
68
     ReactComponent getComponent() {

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

57
     }
57
     }
58
 
58
 
59
     @CallSuper
59
     @CallSuper
60
-    public void applyOptions(Options options, Component childComponent) {
60
+    public void applyChildOptions(Options options, Component child) {
61
         mergeChildOptions(options);
61
         mergeChildOptions(options);
62
     }
62
     }
63
 
63
 

+ 3
- 3
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/SideMenuController.java View File

49
 	}
49
 	}
50
 
50
 
51
     @Override
51
     @Override
52
-    public void applyOptions(Options options, Component childComponent) {
53
-        super.applyOptions(options, childComponent);
52
+    public void applyChildOptions(Options options, Component child) {
53
+        super.applyChildOptions(options, child);
54
         applyOnParentController(parentController ->
54
         applyOnParentController(parentController ->
55
-                ((ParentController) parentController).applyOptions(this.options, childComponent)
55
+                ((ParentController) parentController).applyChildOptions(this.options, child)
56
         );
56
         );
57
     }
57
     }
58
 
58
 

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

14
 import com.reactnativenavigation.views.ReactComponent;
14
 import com.reactnativenavigation.views.ReactComponent;
15
 import com.reactnativenavigation.views.StackLayout;
15
 import com.reactnativenavigation.views.StackLayout;
16
 import com.reactnativenavigation.views.TopBar;
16
 import com.reactnativenavigation.views.TopBar;
17
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
17
 
18
 
18
 import java.util.Collection;
19
 import java.util.Collection;
19
 import java.util.Iterator;
20
 import java.util.Iterator;
25
     private static final NoOpPromise NO_OP = new NoOpPromise();
26
     private static final NoOpPromise NO_OP = new NoOpPromise();
26
     private final IdStack<ViewController> stack = new IdStack<>();
27
     private final IdStack<ViewController> stack = new IdStack<>();
27
     private final NavigationAnimator animator;
28
     private final NavigationAnimator animator;
28
-    private ReactViewCreator topBarButtonCreator;
29
+    private final ReactViewCreator topBarButtonCreator;
30
+    private final TitleBarReactViewCreator titleBarReactViewCreator;
29
 
31
 
30
-    public StackController(final Activity activity, ReactViewCreator topBarButtonCreator, String id, Options initialOptions) {
32
+    public StackController(final Activity activity, ReactViewCreator topBarButtonCreator, TitleBarReactViewCreator titleBarReactViewCreator, String id, Options initialOptions) {
31
         super(activity, id, initialOptions);
33
         super(activity, id, initialOptions);
32
         animator = new NavigationAnimator(activity);
34
         animator = new NavigationAnimator(activity);
33
         this.topBarButtonCreator = topBarButtonCreator;
35
         this.topBarButtonCreator = topBarButtonCreator;
36
+        this.titleBarReactViewCreator = titleBarReactViewCreator;
34
     }
37
     }
35
 
38
 
36
     public void applyOptions(Options options) {
39
     public void applyOptions(Options options) {
37
         super.applyOptions(options);
40
         super.applyOptions(options);
38
-        getView().applyOptions(options);
41
+        getView().applyChildOptions(options);
39
     }
42
     }
40
 
43
 
41
     @Override
44
     @Override
42
-    public void applyOptions(Options options, Component component) {
43
-        super.applyOptions(options, component);
44
-        getView().applyOptions(this.options, component);
45
+    public void applyChildOptions(Options options, Component child) {
46
+        super.applyChildOptions(options, child);
47
+        getView().applyChildOptions(this.options, child);
45
         applyOnParentController(parentController ->
48
         applyOnParentController(parentController ->
46
-                ((ParentController) parentController).applyOptions(this.options.copy().clearTopBarOptions(), component)
49
+                ((ParentController) parentController).applyChildOptions(this.options.copy().clearTopBarOptions(), child)
47
         );
50
         );
48
-        if (component instanceof ReactComponent) {
49
-            fabOptionsPresenter.applyOptions(options.fabOptions, (ReactComponent) component, getView());
51
+        if (child instanceof ReactComponent) {
52
+            fabOptionsPresenter.applyOptions(options.fabOptions, (ReactComponent) child, getView());
50
         }
53
         }
51
         animator.setOptions(options.animationsOptions);
54
         animator.setOptions(options.animationsOptions);
52
     }
55
     }
202
     @NonNull
205
     @NonNull
203
     @Override
206
     @Override
204
     protected StackLayout createView() {
207
     protected StackLayout createView() {
205
-        return new StackLayout(getActivity(), topBarButtonCreator, this::sendOnNavigationButtonPressed);
208
+        return new StackLayout(getActivity(), topBarButtonCreator, titleBarReactViewCreator, this::sendOnNavigationButtonPressed);
206
     }
209
     }
207
 
210
 
208
 	@NonNull
211
 	@NonNull

+ 38
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TitleBarReactViewController.java View File

1
+package com.reactnativenavigation.viewcontrollers;
2
+
3
+import android.app.Activity;
4
+
5
+import com.reactnativenavigation.parse.Options;
6
+import com.reactnativenavigation.utils.CompatUtils;
7
+import com.reactnativenavigation.views.titlebar.TitleBarReactView;
8
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
9
+
10
+public class TitleBarReactViewController extends ViewController<TitleBarReactView> {
11
+
12
+    private final TitleBarReactViewCreator reactViewCreator;
13
+    private String componentName;
14
+
15
+    public TitleBarReactViewController(Activity activity, TitleBarReactViewCreator reactViewCreator) {
16
+        super(activity, CompatUtils.generateViewId() + "", new Options());
17
+        this.reactViewCreator = reactViewCreator;
18
+    }
19
+
20
+    public TitleBarReactViewController(TitleBarReactViewController reactViewController) {
21
+        super(reactViewController.getActivity(), CompatUtils.generateViewId() + "", new Options());
22
+        this.reactViewCreator = reactViewController.reactViewCreator;
23
+    }
24
+
25
+    @Override
26
+    protected TitleBarReactView createView() {
27
+        return reactViewCreator.create(getActivity(), getId(), componentName);
28
+    }
29
+
30
+    @Override
31
+    public void sendOnNavigationButtonPressed(String buttonId) {
32
+
33
+    }
34
+
35
+    public void setComponent(String componentName) {
36
+        this.componentName = componentName;
37
+    }
38
+}

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

18
 import com.reactnativenavigation.parse.Options;
18
 import com.reactnativenavigation.parse.Options;
19
 import com.reactnativenavigation.parse.params.Button;
19
 import com.reactnativenavigation.parse.params.Button;
20
 import com.reactnativenavigation.parse.params.Text;
20
 import com.reactnativenavigation.parse.params.Text;
21
-import com.reactnativenavigation.react.TopBarReactButtonView;
21
+import com.reactnativenavigation.views.TopBarReactButtonView;
22
 import com.reactnativenavigation.utils.ArrayUtils;
22
 import com.reactnativenavigation.utils.ArrayUtils;
23
 import com.reactnativenavigation.utils.ImageLoader;
23
 import com.reactnativenavigation.utils.ImageLoader;
24
 import com.reactnativenavigation.utils.ImageLoadingListenerAdapter;
24
 import com.reactnativenavigation.utils.ImageLoadingListenerAdapter;

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

15
 import com.reactnativenavigation.utils.CompatUtils;
15
 import com.reactnativenavigation.utils.CompatUtils;
16
 import com.reactnativenavigation.utils.StringUtils;
16
 import com.reactnativenavigation.utils.StringUtils;
17
 import com.reactnativenavigation.utils.Task;
17
 import com.reactnativenavigation.utils.Task;
18
+import com.reactnativenavigation.utils.UiUtils;
18
 import com.reactnativenavigation.views.Component;
19
 import com.reactnativenavigation.views.Component;
19
 
20
 
20
 public abstract class ViewController<T extends ViewGroup> implements ViewTreeObserver.OnGlobalLayoutListener {
21
 public abstract class ViewController<T extends ViewGroup> implements ViewTreeObserver.OnGlobalLayoutListener {
155
         applyOptions(options);
156
         applyOptions(options);
156
         applyOnParentController(parentController -> {
157
         applyOnParentController(parentController -> {
157
             parentController.clearOptions();
158
             parentController.clearOptions();
158
-            if (getView() instanceof Component) parentController.applyOptions(options, (Component) getView());
159
+            if (getView() instanceof Component) parentController.applyChildOptions(options, (Component) getView());
159
         });
160
         });
160
     }
161
     }
161
 
162
 
201
         }
202
         }
202
     }
203
     }
203
 
204
 
205
+    public void runOnPreDraw(Task<T> task) {
206
+        UiUtils.runOnPreDrawOnce(getView(), () -> task.run(getView()));
207
+    }
208
+
204
     public abstract void sendOnNavigationButtonPressed(String buttonId);
209
     public abstract void sendOnNavigationButtonPressed(String buttonId);
205
 
210
 
206
     protected boolean isViewShown() {
211
     protected boolean isViewShown() {

+ 4
- 4
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java View File

57
     }
57
     }
58
 
58
 
59
     @Override
59
     @Override
60
-    public void applyOptions(Options options, Component childComponent) {
61
-        super.applyOptions(options, childComponent);
62
-        int tabIndex = bottomTabFinder.findByComponent(childComponent);
60
+    public void applyChildOptions(Options options, Component child) {
61
+        super.applyChildOptions(options, child);
62
+        int tabIndex = bottomTabFinder.findByComponent(child);
63
         if (tabIndex >= 0) new BottomTabsOptionsPresenter(bottomTabs, bottomTabFinder).present(this.options, tabIndex);
63
         if (tabIndex >= 0) new BottomTabsOptionsPresenter(bottomTabs, bottomTabFinder).present(this.options, tabIndex);
64
         applyOnParentController(parentController ->
64
         applyOnParentController(parentController ->
65
-                ((ParentController) parentController).applyOptions(this.options.copy().clearBottomTabsOptions().clearBottomTabOptions(), childComponent)
65
+                ((ParentController) parentController).applyChildOptions(this.options.copy().clearBottomTabsOptions().clearBottomTabOptions(), child)
66
         );
66
         );
67
     }
67
     }
68
 
68
 

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

79
     }
79
     }
80
 
80
 
81
     @Override
81
     @Override
82
-    public void applyOptions(Options options, Component childComponent) {
83
-        super.applyOptions(options, childComponent);
82
+    public void applyChildOptions(Options options, Component child) {
83
+        super.applyChildOptions(options, child);
84
         applyOnParentController(parentController -> {
84
         applyOnParentController(parentController -> {
85
                 Options opt = this.options.copy();
85
                 Options opt = this.options.copy();
86
-                ((ParentController) parentController).applyOptions(opt.clearTopTabOptions().clearTopTabsOptions(), childComponent);
86
+                ((ParentController) parentController).applyChildOptions(opt.clearTopTabOptions().clearTopTabsOptions(), child);
87
             }
87
             }
88
         );
88
         );
89
     }
89
     }

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

11
 import com.reactnativenavigation.utils.CompatUtils;
11
 import com.reactnativenavigation.utils.CompatUtils;
12
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
12
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
13
 import com.reactnativenavigation.viewcontrollers.TopBarButtonController;
13
 import com.reactnativenavigation.viewcontrollers.TopBarButtonController;
14
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
14
 
15
 
15
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
16
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
16
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
17
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
18
 @SuppressLint("ViewConstructor")
19
 @SuppressLint("ViewConstructor")
19
 public class StackLayout extends RelativeLayout {
20
 public class StackLayout extends RelativeLayout {
20
     private TopBar topBar;
21
     private TopBar topBar;
22
+    private final OptionsPresenter optionsPresenter;
21
 
23
 
22
-    public StackLayout(Context context, ReactViewCreator topBarButtonCreator, TopBarButtonController.OnClickListener topBarButtonClickListener) {
24
+    public StackLayout(Context context, ReactViewCreator topBarButtonCreator, TitleBarReactViewCreator titleBarReactViewCreator, TopBarButtonController.OnClickListener topBarButtonClickListener) {
23
         super(context);
25
         super(context);
24
-        topBar = new TopBar(context, topBarButtonCreator, topBarButtonClickListener, this);
26
+        createLayout(topBarButtonCreator, titleBarReactViewCreator, topBarButtonClickListener);
27
+        optionsPresenter = new OptionsPresenter(topBar);
28
+        setContentDescription("StackLayout");
29
+    }
30
+
31
+    private void createLayout(ReactViewCreator topBarButtonCreator, TitleBarReactViewCreator titleBarReactViewCreator, TopBarButtonController.OnClickListener topBarButtonClickListener) {
32
+        topBar = new TopBar(getContext(), topBarButtonCreator, titleBarReactViewCreator, topBarButtonClickListener, this);
25
         topBar.setId(CompatUtils.generateViewId());
33
         topBar.setId(CompatUtils.generateViewId());
26
         addView(topBar, MATCH_PARENT, WRAP_CONTENT);
34
         addView(topBar, MATCH_PARENT, WRAP_CONTENT);
27
-        setContentDescription("StackLayout");
28
     }
35
     }
29
 
36
 
30
-    public void applyOptions(Options options) {
31
-        new OptionsPresenter(topBar).applyOrientation(options.orientationOptions);
37
+    public void applyChildOptions(Options options) {
38
+        optionsPresenter.applyOrientation(options.orientationOptions);
32
     }
39
     }
33
 
40
 
34
-    public void applyOptions(Options options, Component component) {
35
-        new OptionsPresenter(topBar, component).applyOptions(options);
41
+    public void applyChildOptions(Options options, Component child) {
42
+        optionsPresenter.applyChildOptions(options, child);
36
     }
43
     }
37
 
44
 
38
     public void onChildWillDisappear(Options disappearing, Options appearing) {
45
     public void onChildWillDisappear(Options disappearing, Options appearing) {
55
     public TopBar getTopBar() {
62
     public TopBar getTopBar() {
56
         return topBar;
63
         return topBar;
57
     }
64
     }
58
-
59
-    @RestrictTo(RestrictTo.Scope.TESTS)
60
-    public void setTopBar(TopBar topBar) {
61
-        this.topBar = topBar;
62
-    }
63
 }
65
 }

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

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
 import android.annotation.SuppressLint;
3
 import android.annotation.SuppressLint;
4
+import android.app.Activity;
4
 import android.content.Context;
5
 import android.content.Context;
5
 import android.graphics.Typeface;
6
 import android.graphics.Typeface;
6
 import android.support.annotation.RestrictTo;
7
 import android.support.annotation.RestrictTo;
14
 import com.reactnativenavigation.anim.TopBarAnimator;
15
 import com.reactnativenavigation.anim.TopBarAnimator;
15
 import com.reactnativenavigation.anim.TopBarCollapseBehavior;
16
 import com.reactnativenavigation.anim.TopBarCollapseBehavior;
16
 import com.reactnativenavigation.interfaces.ScrollEventListener;
17
 import com.reactnativenavigation.interfaces.ScrollEventListener;
18
+import com.reactnativenavigation.parse.TitleOptions;
17
 import com.reactnativenavigation.parse.params.Bool;
19
 import com.reactnativenavigation.parse.params.Bool;
18
 import com.reactnativenavigation.parse.params.Button;
20
 import com.reactnativenavigation.parse.params.Button;
19
 import com.reactnativenavigation.parse.params.Color;
21
 import com.reactnativenavigation.parse.params.Color;
20
 import com.reactnativenavigation.parse.params.Fraction;
22
 import com.reactnativenavigation.parse.params.Fraction;
21
 import com.reactnativenavigation.parse.params.Number;
23
 import com.reactnativenavigation.parse.params.Number;
22
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
24
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
25
+import com.reactnativenavigation.viewcontrollers.TitleBarReactViewController;
23
 import com.reactnativenavigation.viewcontrollers.TopBarButtonController;
26
 import com.reactnativenavigation.viewcontrollers.TopBarButtonController;
27
+import com.reactnativenavigation.views.titlebar.TitleBar;
28
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
24
 
29
 
25
 import java.util.List;
30
 import java.util.List;
26
 
31
 
35
     private TopTabs topTabs;
40
     private TopTabs topTabs;
36
     private StackLayout parentView;
41
     private StackLayout parentView;
37
 
42
 
38
-    public TopBar(final Context context, ReactViewCreator buttonCreator, TopBarButtonController.OnClickListener onClickListener, StackLayout parentView) {
43
+    public TopBar(final Context context, ReactViewCreator buttonCreator, TitleBarReactViewCreator titleBarReactViewCreator, TopBarButtonController.OnClickListener onClickListener, StackLayout parentView) {
39
         super(context);
44
         super(context);
40
         collapsingBehavior = new TopBarCollapseBehavior(this);
45
         collapsingBehavior = new TopBarCollapseBehavior(this);
41
         topTabs = new TopTabs(getContext());
46
         topTabs = new TopTabs(getContext());
42
         animator = new TopBarAnimator(this);
47
         animator = new TopBarAnimator(this);
43
         this.parentView = parentView;
48
         this.parentView = parentView;
44
-        titleBar = createTitleBar(context, buttonCreator, onClickListener);
49
+        titleBar = createTitleBar(context, buttonCreator, titleBarReactViewCreator, onClickListener);
45
         addView(titleBar);
50
         addView(titleBar);
46
         setContentDescription("TopBar");
51
         setContentDescription("TopBar");
47
     }
52
     }
48
 
53
 
49
-    protected TitleBar createTitleBar(Context context, ReactViewCreator buttonCreator, TopBarButtonController.OnClickListener onClickListener) {
50
-        return new TitleBar(context, buttonCreator, onClickListener);
54
+    protected TitleBar createTitleBar(Context context, ReactViewCreator buttonCreator, TitleBarReactViewCreator reactViewCreator, TopBarButtonController.OnClickListener onClickListener) {
55
+        return new TitleBar(context,
56
+                buttonCreator,
57
+                new TitleBarReactViewController((Activity) context, reactViewCreator),
58
+                onClickListener
59
+        );
51
     }
60
     }
52
 
61
 
53
     public void setTitle(String title) {
62
     public void setTitle(String title) {
74
         titleBar.setTitleTypeface(typeface);
83
         titleBar.setTitleTypeface(typeface);
75
     }
84
     }
76
 
85
 
86
+    public void setComponent(String componentName, TitleOptions.Alignment alignment) {
87
+        titleBar.setComponent(componentName, alignment);
88
+    }
89
+
77
     public void setTopTabFontFamily(int tabIndex, Typeface fontFamily) {
90
     public void setTopTabFontFamily(int tabIndex, Typeface fontFamily) {
78
         topTabs.setFontFamily(tabIndex, fontFamily);
91
         topTabs.setFontFamily(tabIndex, fontFamily);
79
     }
92
     }

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

3
 import android.app.Activity;
3
 import android.app.Activity;
4
 
4
 
5
 import com.facebook.react.ReactInstanceManager;
5
 import com.facebook.react.ReactInstanceManager;
6
-import com.reactnativenavigation.react.TopBarReactButtonView;
7
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
6
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
8
 
7
 
9
 public class TopBarButtonCreator implements ReactViewCreator {
8
 public class TopBarButtonCreator implements ReactViewCreator {

lib/android/app/src/main/java/com/reactnativenavigation/react/TopBarReactButtonView.java → lib/android/app/src/main/java/com/reactnativenavigation/views/TopBarReactButtonView.java View File

1
-package com.reactnativenavigation.react;
1
+package com.reactnativenavigation.views;
2
 
2
 
3
 import android.annotation.SuppressLint;
3
 import android.annotation.SuppressLint;
4
 import android.content.Context;
4
 import android.content.Context;
5
 
5
 
6
 import com.facebook.react.ReactInstanceManager;
6
 import com.facebook.react.ReactInstanceManager;
7
+import com.reactnativenavigation.react.ReactView;
7
 
8
 
8
 @SuppressLint("ViewConstructor")
9
 @SuppressLint("ViewConstructor")
9
 public class TopBarReactButtonView extends ReactView {
10
 public class TopBarReactButtonView extends ReactView {

lib/android/app/src/main/java/com/reactnativenavigation/views/TitleBar.java → lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBar.java View File

1
-package com.reactnativenavigation.views;
1
+package com.reactnativenavigation.views.titlebar;
2
 
2
 
3
 import android.annotation.SuppressLint;
3
 import android.annotation.SuppressLint;
4
 import android.app.Activity;
4
 import android.app.Activity;
7
 import android.support.annotation.Nullable;
7
 import android.support.annotation.Nullable;
8
 import android.support.v7.widget.Toolbar;
8
 import android.support.v7.widget.Toolbar;
9
 import android.util.Log;
9
 import android.util.Log;
10
+import android.view.Gravity;
10
 import android.view.View;
11
 import android.view.View;
11
 import android.view.ViewGroup;
12
 import android.view.ViewGroup;
12
 import android.widget.TextView;
13
 import android.widget.TextView;
13
 
14
 
15
+import com.reactnativenavigation.parse.TitleOptions;
14
 import com.reactnativenavigation.parse.params.Button;
16
 import com.reactnativenavigation.parse.params.Button;
15
 import com.reactnativenavigation.parse.params.Color;
17
 import com.reactnativenavigation.parse.params.Color;
16
 import com.reactnativenavigation.parse.params.Fraction;
18
 import com.reactnativenavigation.parse.params.Fraction;
17
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
19
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
20
+import com.reactnativenavigation.viewcontrollers.TitleBarReactViewController;
18
 import com.reactnativenavigation.viewcontrollers.TopBarButtonController;
21
 import com.reactnativenavigation.viewcontrollers.TopBarButtonController;
19
 
22
 
20
 import java.util.ArrayList;
23
 import java.util.ArrayList;
21
 import java.util.List;
24
 import java.util.List;
22
 
25
 
26
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
27
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
28
+
23
 @SuppressLint("ViewConstructor")
29
 @SuppressLint("ViewConstructor")
24
 public class TitleBar extends Toolbar {
30
 public class TitleBar extends Toolbar {
25
     private final ReactViewCreator buttonCreator;
31
     private final ReactViewCreator buttonCreator;
32
+    private TitleBarReactViewController reactViewController;
26
     private final TopBarButtonController.OnClickListener onClickListener;
33
     private final TopBarButtonController.OnClickListener onClickListener;
27
     private final List<TopBarButtonController> rightButtonControllers = new ArrayList<>();
34
     private final List<TopBarButtonController> rightButtonControllers = new ArrayList<>();
28
     private TopBarButtonController leftButtonController;
35
     private TopBarButtonController leftButtonController;
29
 
36
 
30
-    public TitleBar(Context context, ReactViewCreator buttonCreator, TopBarButtonController.OnClickListener onClickListener) {
37
+    public TitleBar(Context context, ReactViewCreator buttonCreator, TitleBarReactViewController reactViewController, TopBarButtonController.OnClickListener onClickListener) {
31
         super(context);
38
         super(context);
32
         this.buttonCreator = buttonCreator;
39
         this.buttonCreator = buttonCreator;
40
+        this.reactViewController = reactViewController;
33
         this.onClickListener = onClickListener;
41
         this.onClickListener = onClickListener;
34
         getMenu();
42
         getMenu();
35
         setContentDescription("titleBar");
43
         setContentDescription("titleBar");
39
         return super.getTitle() == null ? "" : (String) super.getTitle();
47
         return super.getTitle() == null ? "" : (String) super.getTitle();
40
     }
48
     }
41
 
49
 
42
-    void setTitleTextColor(Color color) {
50
+    public void setTitleTextColor(Color color) {
43
         if (color.hasValue()) setTitleTextColor(color.get());
51
         if (color.hasValue()) setTitleTextColor(color.get());
44
     }
52
     }
45
 
53
 
46
-    void setBackgroundColor(Color color) {
54
+    public void setComponent(String componentName, TitleOptions.Alignment alignment) {
55
+        reactViewController.setComponent(componentName);
56
+        addView(reactViewController.getView(), getComponentLayoutParams(alignment));
57
+    }
58
+
59
+    public void setBackgroundColor(Color color) {
47
         if (color.hasValue()) setBackgroundColor(color.get());
60
         if (color.hasValue()) setBackgroundColor(color.get());
48
     }
61
     }
49
 
62
 
50
-    void setTitleFontSize(Fraction size) {
63
+    public void setTitleFontSize(Fraction size) {
51
         TextView titleTextView = getTitleTextView();
64
         TextView titleTextView = getTitleTextView();
52
         if (titleTextView != null && size.hasValue()) {
65
         if (titleTextView != null && size.hasValue()) {
53
             titleTextView.setTextSize(size.get());
66
             titleTextView.setTextSize(size.get());
54
         }
67
         }
55
     }
68
     }
56
 
69
 
57
-    void setTitleTypeface(Typeface typeface) {
70
+    public void setTitleTypeface(Typeface typeface) {
58
         TextView titleTextView = getTitleTextView();
71
         TextView titleTextView = getTitleTextView();
59
         if (titleTextView != null) {
72
         if (titleTextView != null) {
60
             titleTextView.setTypeface(typeface);
73
             titleTextView.setTypeface(typeface);
61
         }
74
         }
62
     }
75
     }
63
 
76
 
64
-    TextView getTitleTextView() {
77
+    public TextView getTitleTextView() {
65
         return findTextView(this);
78
         return findTextView(this);
66
     }
79
     }
67
 
80
 
69
         setTitle(null);
82
         setTitle(null);
70
         clearRightButtons();
83
         clearRightButtons();
71
         clearLeftButton();
84
         clearLeftButton();
85
+        clearComponent();
86
+    }
87
+
88
+    private void clearComponent() {
89
+        reactViewController.destroy();
90
+        reactViewController = new TitleBarReactViewController(reactViewController);
72
     }
91
     }
73
 
92
 
74
     private void clearLeftButton() {
93
     private void clearLeftButton() {
137
         }
156
         }
138
         return null;
157
         return null;
139
     }
158
     }
159
+
160
+    public Toolbar.LayoutParams getComponentLayoutParams(TitleOptions.Alignment alignment) {
161
+        if (alignment == TitleOptions.Alignment.Fill) {
162
+            return new LayoutParams(MATCH_PARENT, getHeight());
163
+        } else {
164
+            LayoutParams lp = new LayoutParams(WRAP_CONTENT, getHeight());
165
+            lp.gravity = Gravity.CENTER;
166
+            return lp;
167
+        }
168
+    }
140
 }
169
 }

+ 23
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBarReactView.java View File

1
+package com.reactnativenavigation.views.titlebar;
2
+
3
+import android.annotation.SuppressLint;
4
+import android.content.Context;
5
+
6
+import com.facebook.react.ReactInstanceManager;
7
+import com.reactnativenavigation.react.ReactView;
8
+
9
+@SuppressLint("ViewConstructor")
10
+public class TitleBarReactView extends ReactView {
11
+
12
+    public TitleBarReactView(Context context, ReactInstanceManager reactInstanceManager, String componentId, String componentName) {
13
+        super(context, reactInstanceManager, componentId, componentName);
14
+    }
15
+
16
+    @Override
17
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
18
+        super.onMeasure(
19
+                getChildCount() > 0 ? MeasureSpec.makeMeasureSpec(getChildAt(0).getWidth(), MeasureSpec.EXACTLY) : widthMeasureSpec,
20
+                heightMeasureSpec
21
+        );
22
+    }
23
+}

+ 20
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBarReactViewCreator.java View File

1
+package com.reactnativenavigation.views.titlebar;
2
+
3
+import android.app.Activity;
4
+
5
+import com.facebook.react.ReactInstanceManager;
6
+import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
7
+
8
+public class TitleBarReactViewCreator implements ReactViewCreator {
9
+
10
+    protected ReactInstanceManager instanceManager;
11
+
12
+    public TitleBarReactViewCreator(ReactInstanceManager instanceManager) {
13
+        this.instanceManager = instanceManager;
14
+	}
15
+
16
+	@Override
17
+	public TitleBarReactView create(Activity activity, String componentId, String componentName) {
18
+        return new TitleBarReactView(activity, instanceManager, componentId, componentName);
19
+    }
20
+}

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

1
+package com.reactnativenavigation.mocks;
2
+
3
+import android.app.Activity;
4
+
5
+import com.facebook.react.ReactInstanceManager;
6
+import com.reactnativenavigation.views.titlebar.TitleBarReactView;
7
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
8
+
9
+import static org.mockito.Mockito.mock;
10
+
11
+public class TitleBarReactViewCreatorMock extends TitleBarReactViewCreator {
12
+    public TitleBarReactViewCreatorMock() {
13
+        super(mock(ReactInstanceManager.class));
14
+    }
15
+
16
+    @Override
17
+    public TitleBarReactView create(Activity activity, String componentId, String componentName) {
18
+        return new TitleBarReactView(activity, instanceManager, componentId, componentName);
19
+    }
20
+}

+ 1
- 1
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TopBarButtonCreatorMock.java View File

3
 import android.app.Activity;
3
 import android.app.Activity;
4
 
4
 
5
 import com.facebook.react.ReactInstanceManager;
5
 import com.facebook.react.ReactInstanceManager;
6
-import com.reactnativenavigation.react.TopBarReactButtonView;
6
+import com.reactnativenavigation.views.TopBarReactButtonView;
7
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
7
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
8
 
8
 
9
 import static org.mockito.Mockito.mock;
9
 import static org.mockito.Mockito.mock;

+ 31
- 21
lib/android/app/src/test/java/com/reactnativenavigation/parse/OptionsTest.java View File

31
     private static final int TOP_BAR_FONT_SIZE = 18;
31
     private static final int TOP_BAR_FONT_SIZE = 18;
32
     private static final String TOP_BAR_FONT_FAMILY = "HelveticaNeue-CondensedBold";
32
     private static final String TOP_BAR_FONT_FAMILY = "HelveticaNeue-CondensedBold";
33
     private static final Typeface TOP_BAR_TYPEFACE = Typeface.create("HelveticaNeue-CondensedBold", Typeface.BOLD);
33
     private static final Typeface TOP_BAR_TYPEFACE = Typeface.create("HelveticaNeue-CondensedBold", Typeface.BOLD);
34
+    private static final String TITLE_ALIGNMENT = "center";
34
     private static final Bool TOP_BAR_VISIBLE = new Bool(true);
35
     private static final Bool TOP_BAR_VISIBLE = new Bool(true);
35
     private static final Bool TOP_BAR_DRAW_BEHIND = new Bool(true);
36
     private static final Bool TOP_BAR_DRAW_BEHIND = new Bool(true);
36
     private static final Bool TOP_BAR_HIDE_ON_SCROLL = new Bool(true);
37
     private static final Bool TOP_BAR_HIDE_ON_SCROLL = new Bool(true);
63
     }
64
     }
64
 
65
 
65
     private void assertResult(Options result) {
66
     private void assertResult(Options result) {
66
-        assertThat(result.topBarOptions.title.get()).isEqualTo(TITLE);
67
-        assertThat(result.topBarOptions.backgroundColor.get()).isEqualTo(TOP_BAR_BACKGROUND_COLOR);
68
-        assertThat(result.topBarOptions.textColor.get()).isEqualTo(TOP_BAR_TEXT_COLOR);
69
-        assertThat(result.topBarOptions.textFontSize.get()).isEqualTo(TOP_BAR_FONT_SIZE);
70
-        assertThat(result.topBarOptions.textFontFamily).isEqualTo(TOP_BAR_TYPEFACE);
67
+        assertThat(result.topBarOptions.title.text.get()).isEqualTo(TITLE);
68
+        assertThat(result.topBarOptions.background.color.get()).isEqualTo(TOP_BAR_BACKGROUND_COLOR);
69
+        assertThat(result.topBarOptions.title.color.get()).isEqualTo(TOP_BAR_TEXT_COLOR);
70
+        assertThat(result.topBarOptions.title.fontSize.get()).isEqualTo(TOP_BAR_FONT_SIZE);
71
+        assertThat(result.topBarOptions.title.fontFamily).isEqualTo(TOP_BAR_TYPEFACE);
71
         assertThat(result.topBarOptions.visible.get()).isEqualTo(TOP_BAR_VISIBLE.get());
72
         assertThat(result.topBarOptions.visible.get()).isEqualTo(TOP_BAR_VISIBLE.get());
72
         assertThat(result.topBarOptions.drawBehind.get()).isEqualTo(TOP_BAR_DRAW_BEHIND.get());
73
         assertThat(result.topBarOptions.drawBehind.get()).isEqualTo(TOP_BAR_DRAW_BEHIND.get());
73
         assertThat(result.topBarOptions.hideOnScroll.get()).isEqualTo(TOP_BAR_HIDE_ON_SCROLL.get());
74
         assertThat(result.topBarOptions.hideOnScroll.get()).isEqualTo(TOP_BAR_HIDE_ON_SCROLL.get());
83
         assertThat(result.fabOptions.hideOnScroll.get()).isEqualTo(FAB_HIDE_ON_SCROLL);
84
         assertThat(result.fabOptions.hideOnScroll.get()).isEqualTo(FAB_HIDE_ON_SCROLL);
84
         assertThat(result.fabOptions.alignVertically.get()).isEqualTo(FAB_ALIGN_VERTICALLY);
85
         assertThat(result.fabOptions.alignVertically.get()).isEqualTo(FAB_ALIGN_VERTICALLY);
85
         assertThat(result.fabOptions.alignHorizontally.get()).isEqualTo(FAB_ALIGN_HORIZONTALLY);
86
         assertThat(result.fabOptions.alignHorizontally.get()).isEqualTo(FAB_ALIGN_HORIZONTALLY);
87
+        assertThat(result.topBarOptions.title.alignment).isEqualTo(TitleOptions.Alignment.Center);
86
     }
88
     }
87
 
89
 
88
     @NonNull
90
     @NonNull
97
     @NonNull
99
     @NonNull
98
     private JSONObject createTopBar(boolean visible) throws JSONException {
100
     private JSONObject createTopBar(boolean visible) throws JSONException {
99
         return new JSONObject()
101
         return new JSONObject()
100
-                .put("title", "the title")
101
-                .put("backgroundColor", TOP_BAR_BACKGROUND_COLOR)
102
-                .put("textColor", TOP_BAR_TEXT_COLOR)
103
-                .put("textFontSize", TOP_BAR_FONT_SIZE)
104
-                .put("textFontFamily", TOP_BAR_FONT_FAMILY)
102
+                .put("title", createTitle())
103
+                .put("background", createBackground())
105
                 .put("visible", visible)
104
                 .put("visible", visible)
106
                 .put("drawBehind", TOP_BAR_DRAW_BEHIND.get())
105
                 .put("drawBehind", TOP_BAR_DRAW_BEHIND.get())
107
                 .put("hideOnScroll", TOP_BAR_HIDE_ON_SCROLL.get());
106
                 .put("hideOnScroll", TOP_BAR_HIDE_ON_SCROLL.get());
108
     }
107
     }
109
 
108
 
109
+    private JSONObject createBackground() throws JSONException {
110
+        return new JSONObject()
111
+                .put("color", TOP_BAR_BACKGROUND_COLOR);
112
+    }
113
+
114
+    private JSONObject createTitle() throws JSONException {
115
+        return new JSONObject()
116
+                .put("text", "the title")
117
+                .put("color", TOP_BAR_TEXT_COLOR)
118
+                .put("fontSize", TOP_BAR_FONT_SIZE)
119
+                .put("fontFamily", TOP_BAR_FONT_FAMILY)
120
+                .put("alignment", TITLE_ALIGNMENT);
121
+    }
122
+
110
     @NonNull
123
     @NonNull
111
     private JSONObject createFab() throws JSONException {
124
     private JSONObject createFab() throws JSONException {
112
         return new JSONObject()
125
         return new JSONObject()
136
     @NonNull
149
     @NonNull
137
     private JSONObject createOtherTopBar() throws JSONException {
150
     private JSONObject createOtherTopBar() throws JSONException {
138
         return new JSONObject()
151
         return new JSONObject()
139
-                .put("title", "the title")
140
-                .put("backgroundColor", TOP_BAR_BACKGROUND_COLOR)
141
-                .put("textColor", TOP_BAR_TEXT_COLOR)
142
-                .put("textFontSize", TOP_BAR_FONT_SIZE)
143
-                .put("textFontFamily", TOP_BAR_FONT_FAMILY)
152
+                .put("title", createTitle())
153
+                .put("background", createBackground())
144
                 .put("visible", TOP_BAR_VISIBLE);
154
                 .put("visible", TOP_BAR_VISIBLE);
145
     }
155
     }
146
 
156
 
159
         JSONObject json1 = new JSONObject();
169
         JSONObject json1 = new JSONObject();
160
         json1.put("topBar", createTopBar(true));
170
         json1.put("topBar", createTopBar(true));
161
         Options options1 = Options.parse(mockLoader, json1);
171
         Options options1 = Options.parse(mockLoader, json1);
162
-        options1.topBarOptions.title = new Text("some title");
172
+        options1.topBarOptions.title.text = new Text("some title");
163
 
173
 
164
         JSONObject json2 = new JSONObject();
174
         JSONObject json2 = new JSONObject();
165
         json2.put("topBar", createTopBar(false));
175
         json2.put("topBar", createTopBar(false));
166
         Options options2 = Options.parse(mockLoader, json2);
176
         Options options2 = Options.parse(mockLoader, json2);
167
-        options2.topBarOptions.title = new NullText();
177
+        options2.topBarOptions.title.text = new NullText();
168
 
178
 
169
         Options merged = options1.mergeWith(options2);
179
         Options merged = options1.mergeWith(options2);
170
         assertThat(options1.topBarOptions.visible.get()).isTrue();
180
         assertThat(options1.topBarOptions.visible.get()).isTrue();
171
         assertThat(merged.topBarOptions.visible.get()).isFalse();
181
         assertThat(merged.topBarOptions.visible.get()).isFalse();
172
-        assertThat(merged.topBarOptions.title.get()).isEqualTo("some title");
182
+        assertThat(merged.topBarOptions.title.text.get()).isEqualTo("some title");
173
     }
183
     }
174
 
184
 
175
     @Test
185
     @Test
203
     @Test
213
     @Test
204
     public void defaultEmptyOptions() throws Exception {
214
     public void defaultEmptyOptions() throws Exception {
205
         Options uut = new Options();
215
         Options uut = new Options();
206
-        assertThat(uut.topBarOptions.title.get("")).isEmpty();
216
+        assertThat(uut.topBarOptions.title.text.get("")).isEmpty();
207
     }
217
     }
208
 
218
 
209
     @Test
219
     @Test
216
     @Test
226
     @Test
217
     public void clear_topBarOptions() throws Exception {
227
     public void clear_topBarOptions() throws Exception {
218
         Options uut = new Options();
228
         Options uut = new Options();
219
-        uut.topBarOptions.title = new Text("some title");
229
+        uut.topBarOptions.title.text = new Text("some title");
220
         uut.clearTopBarOptions();
230
         uut.clearTopBarOptions();
221
-        assertThat(uut.topBarOptions.title.hasValue()).isFalse();
231
+        assertThat(uut.topBarOptions.title.text.hasValue()).isFalse();
222
     }
232
     }
223
 
233
 
224
     @Test
234
     @Test

+ 8
- 3
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/BottomTabsControllerTest.java View File

8
 import com.reactnativenavigation.mocks.ImageLoaderMock;
8
 import com.reactnativenavigation.mocks.ImageLoaderMock;
9
 import com.reactnativenavigation.mocks.MockPromise;
9
 import com.reactnativenavigation.mocks.MockPromise;
10
 import com.reactnativenavigation.mocks.SimpleViewController;
10
 import com.reactnativenavigation.mocks.SimpleViewController;
11
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12
 import com.reactnativenavigation.parse.Options;
13
 import com.reactnativenavigation.parse.Options;
13
 import com.reactnativenavigation.parse.params.Color;
14
 import com.reactnativenavigation.parse.params.Color;
100
     public void findControllerById_ReturnsSelfOrChildren() throws Exception {
101
     public void findControllerById_ReturnsSelfOrChildren() throws Exception {
101
         assertThat(uut.findControllerById("123")).isNull();
102
         assertThat(uut.findControllerById("123")).isNull();
102
         assertThat(uut.findControllerById(uut.getId())).isEqualTo(uut);
103
         assertThat(uut.findControllerById(uut.getId())).isEqualTo(uut);
103
-        StackController inner = new StackController(activity, new TopBarButtonCreatorMock(), "inner", tabOptions);
104
+        StackController inner = createStack("inner");
104
         inner.animatePush(child1, new MockPromise());
105
         inner.animatePush(child1, new MockPromise());
105
         assertThat(uut.findControllerById(child1.getId())).isNull();
106
         assertThat(uut.findControllerById(child1.getId())).isNull();
106
         uut.setTabs(Collections.singletonList(inner));
107
         uut.setTabs(Collections.singletonList(inner));
131
         uut.setTabs(tabs);
132
         uut.setTabs(tabs);
132
         uut.ensureViewIsCreated();
133
         uut.ensureViewIsCreated();
133
 
134
 
134
-        StackController stack = spy(new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options()));
135
+        StackController stack = spy(createStack("stack"));
135
         stack.ensureViewIsCreated();
136
         stack.ensureViewIsCreated();
136
         stack.push(uut, new MockPromise());
137
         stack.push(uut, new MockPromise());
137
 
138
 
138
         child1.onViewAppeared();
139
         child1.onViewAppeared();
139
         ArgumentCaptor<Options> optionsCaptor = ArgumentCaptor.forClass(Options.class);
140
         ArgumentCaptor<Options> optionsCaptor = ArgumentCaptor.forClass(Options.class);
140
         ArgumentCaptor<ReactComponent> viewCaptor = ArgumentCaptor.forClass(ReactComponent.class);
141
         ArgumentCaptor<ReactComponent> viewCaptor = ArgumentCaptor.forClass(ReactComponent.class);
141
-        verify(stack, times(1)).applyOptions(optionsCaptor.capture(), viewCaptor.capture());
142
+        verify(stack, times(1)).applyChildOptions(optionsCaptor.capture(), viewCaptor.capture());
142
         assertThat(viewCaptor.getValue()).isEqualTo(child1.getView());
143
         assertThat(viewCaptor.getValue()).isEqualTo(child1.getView());
143
         assertThat(optionsCaptor.getValue().bottomTabsOptions.tabColor.hasValue()).isFalse();
144
         assertThat(optionsCaptor.getValue().bottomTabsOptions.tabColor.hasValue()).isFalse();
144
     }
145
     }
169
     private List<ViewController> createTabs() {
170
     private List<ViewController> createTabs() {
170
         return Arrays.asList(child1, child2, child3, child4, child5);
171
         return Arrays.asList(child1, child2, child3, child4, child5);
171
     }
172
     }
173
+
174
+    private StackController createStack(String id) {
175
+        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), id, tabOptions);
176
+    }
172
 }
177
 }

+ 2
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ComponentViewControllerTest.java View File

5
 import com.reactnativenavigation.BaseTest;
5
 import com.reactnativenavigation.BaseTest;
6
 import com.reactnativenavigation.mocks.TestComponentLayout;
6
 import com.reactnativenavigation.mocks.TestComponentLayout;
7
 import com.reactnativenavigation.mocks.TestReactView;
7
 import com.reactnativenavigation.mocks.TestReactView;
8
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
8
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
9
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
9
 import com.reactnativenavigation.parse.Options;
10
 import com.reactnativenavigation.parse.Options;
10
 import com.reactnativenavigation.views.StackLayout;
11
 import com.reactnativenavigation.views.StackLayout;
26
         super.beforeEach();
27
         super.beforeEach();
27
         Activity activity = newActivity();
28
         Activity activity = newActivity();
28
         view = spy(new TestComponentLayout(activity, new TestReactView(activity)));
29
         view = spy(new TestComponentLayout(activity, new TestReactView(activity)));
29
-        ParentController<StackLayout> parentController = new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options());
30
+        ParentController<StackLayout> parentController = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack", new Options());
30
         uut = new ComponentViewController(activity, "componentId1", "componentName", (activity1, componentId, componentName) -> view, new Options());
31
         uut = new ComponentViewController(activity, "componentId1", "componentName", (activity1, componentId, componentName) -> view, new Options());
31
         uut.setParentController(parentController);
32
         uut.setParentController(parentController);
32
         parentController.ensureViewIsCreated();
33
         parentController.ensureViewIsCreated();

+ 2
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/FloatingActionButtonTest.java View File

8
 import com.reactnativenavigation.BaseTest;
8
 import com.reactnativenavigation.BaseTest;
9
 import com.reactnativenavigation.mocks.MockPromise;
9
 import com.reactnativenavigation.mocks.MockPromise;
10
 import com.reactnativenavigation.mocks.SimpleViewController;
10
 import com.reactnativenavigation.mocks.SimpleViewController;
11
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12
 import com.reactnativenavigation.parse.FabOptions;
13
 import com.reactnativenavigation.parse.FabOptions;
13
 import com.reactnativenavigation.parse.Options;
14
 import com.reactnativenavigation.parse.Options;
33
     public void beforeEach() {
34
     public void beforeEach() {
34
         super.beforeEach();
35
         super.beforeEach();
35
         activity = newActivity();
36
         activity = newActivity();
36
-        stackController = new StackController(activity, new TopBarButtonCreatorMock(), "stackController", new Options());
37
+        stackController = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stackController", new Options());
37
         Options options = getOptionsWithFab();
38
         Options options = getOptionsWithFab();
38
         childFab = new SimpleViewController(activity, "child1", options);
39
         childFab = new SimpleViewController(activity, "child1", options);
39
         childNoFab = new SimpleViewController(activity, "child2", new Options());
40
         childNoFab = new SimpleViewController(activity, "child2", new Options());

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

8
 import com.reactnativenavigation.mocks.MockPromise;
8
 import com.reactnativenavigation.mocks.MockPromise;
9
 import com.reactnativenavigation.mocks.SimpleComponentViewController;
9
 import com.reactnativenavigation.mocks.SimpleComponentViewController;
10
 import com.reactnativenavigation.mocks.SimpleViewController;
10
 import com.reactnativenavigation.mocks.SimpleViewController;
11
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12
 import com.reactnativenavigation.parse.Options;
13
 import com.reactnativenavigation.parse.Options;
13
 import com.reactnativenavigation.parse.params.Text;
14
 import com.reactnativenavigation.parse.params.Text;
46
         imageLoaderMock = ImageLoaderMock.mock();
47
         imageLoaderMock = ImageLoaderMock.mock();
47
         activity = newActivity();
48
         activity = newActivity();
48
         uut = new Navigator(activity);
49
         uut = new Navigator(activity);
49
-        parentController = spy(new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options()));
50
+        parentController = spy(newStack());
50
         parentController.ensureViewIsCreated();
51
         parentController.ensureViewIsCreated();
51
         child1 = new SimpleViewController(activity, "child1", tabOptions);
52
         child1 = new SimpleViewController(activity, "child1", tabOptions);
52
         child2 = new SimpleViewController(activity, "child2", tabOptions);
53
         child2 = new SimpleViewController(activity, "child2", tabOptions);
226
     public void setOptions_CallsApplyNavigationOptions() {
227
     public void setOptions_CallsApplyNavigationOptions() {
227
         ComponentViewController componentVc = new SimpleComponentViewController(activity, "theId", new Options());
228
         ComponentViewController componentVc = new SimpleComponentViewController(activity, "theId", new Options());
228
         componentVc.setParentController(parentController);
229
         componentVc.setParentController(parentController);
229
-        assertThat(componentVc.options.topBarOptions.title.get("")).isEmpty();
230
+        assertThat(componentVc.options.topBarOptions.title.text.get("")).isEmpty();
230
         uut.setRoot(componentVc, new MockPromise());
231
         uut.setRoot(componentVc, new MockPromise());
231
 
232
 
232
         Options options = new Options();
233
         Options options = new Options();
233
-        options.topBarOptions.title = new Text("new title");
234
+        options.topBarOptions.title.text = new Text("new title");
234
 
235
 
235
         uut.setOptions("theId", options);
236
         uut.setOptions("theId", options);
236
-        assertThat(componentVc.options.topBarOptions.title.get()).isEqualTo("new title");
237
+        assertThat(componentVc.options.topBarOptions.title.text.get()).isEqualTo("new title");
237
     }
238
     }
238
 
239
 
239
     @Test
240
     @Test
248
 
249
 
249
     @NonNull
250
     @NonNull
250
     private StackController newStack() {
251
     private StackController newStack() {
251
-        return new StackController(activity, new TopBarButtonCreatorMock(), "stack" + CompatUtils.generateViewId(), tabOptions);
252
+        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack" + CompatUtils.generateViewId(), tabOptions);
252
     }
253
     }
253
 
254
 
254
     @Test
255
     @Test
325
 
326
 
326
     @Test
327
     @Test
327
     public void pushedStackCanBePopped() throws Exception {
328
     public void pushedStackCanBePopped() throws Exception {
328
-        StackController parent = new StackController(activity, new TopBarButtonCreatorMock(), "someStack", new Options());
329
+        StackController parent = newStack();
329
         parent.ensureViewIsCreated();
330
         parent.ensureViewIsCreated();
330
         uut.setRoot(parent, new MockPromise());
331
         uut.setRoot(parent, new MockPromise());
331
         parent.push(parentController, new MockPromise());
332
         parent.push(parentController, new MockPromise());

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

10
 import com.reactnativenavigation.mocks.MockPromise;
10
 import com.reactnativenavigation.mocks.MockPromise;
11
 import com.reactnativenavigation.mocks.TestComponentLayout;
11
 import com.reactnativenavigation.mocks.TestComponentLayout;
12
 import com.reactnativenavigation.mocks.TestReactView;
12
 import com.reactnativenavigation.mocks.TestReactView;
13
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
13
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
14
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
14
 import com.reactnativenavigation.parse.Options;
15
 import com.reactnativenavigation.parse.Options;
15
 import com.reactnativenavigation.parse.params.Bool;
16
 import com.reactnativenavigation.parse.params.Bool;
45
                 (activity1, componentId, componentName) -> view,
46
                 (activity1, componentId, componentName) -> view,
46
                 initialNavigationOptions
47
                 initialNavigationOptions
47
         );
48
         );
48
-        stackController = new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options());
49
+        stackController = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack", new Options());
49
         stackController.ensureViewIsCreated();
50
         stackController.ensureViewIsCreated();
50
         uut.setParentController(stackController);
51
         uut.setParentController(stackController);
51
     }
52
     }
61
 
62
 
62
     @Test
63
     @Test
63
     public void initialOptionsAppliedOnAppear() throws Exception {
64
     public void initialOptionsAppliedOnAppear() throws Exception {
64
-        uut.options.topBarOptions.title = new Text("the title");
65
-        StackController stackController = new StackController(activity, new TopBarButtonCreatorMock(), "stackId", new Options());
65
+        uut.options.topBarOptions.title.text = new Text("the title");
66
+        StackController stackController = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stackId", new Options());
66
         stackController.animatePush(uut, new MockPromise() {});
67
         stackController.animatePush(uut, new MockPromise() {});
67
         assertThat(stackController.getTopBar().getTitle()).isEmpty();
68
         assertThat(stackController.getTopBar().getTitle()).isEmpty();
68
 
69
 
73
     @Test
74
     @Test
74
     public void mergeNavigationOptionsUpdatesCurrentOptions() throws Exception {
75
     public void mergeNavigationOptionsUpdatesCurrentOptions() throws Exception {
75
         uut.ensureViewIsCreated();
76
         uut.ensureViewIsCreated();
76
-        assertThat(uut.options.topBarOptions.title.get("")).isEmpty();
77
+        assertThat(uut.options.topBarOptions.title.text.get("")).isEmpty();
77
         Options options = new Options();
78
         Options options = new Options();
78
-        options.topBarOptions.title = new Text("new title");
79
+        options.topBarOptions.title.text = new Text("new title");
79
         uut.mergeOptions(options);
80
         uut.mergeOptions(options);
80
-        assertThat(uut.options.topBarOptions.title.get()).isEqualTo("new title");
81
+        assertThat(uut.options.topBarOptions.title.text.get()).isEqualTo("new title");
81
     }
82
     }
82
 
83
 
83
     @Test
84
     @Test
87
         assertThat(stackController.getTopBar().getTitle()).isEmpty();
88
         assertThat(stackController.getTopBar().getTitle()).isEmpty();
88
 
89
 
89
         Options opts = new Options();
90
         Options opts = new Options();
90
-        opts.topBarOptions.title = new Text("the new title");
91
+        opts.topBarOptions.title.text = new Text("the new title");
91
         uut.mergeOptions(opts);
92
         uut.mergeOptions(opts);
92
 
93
 
93
         assertThat(stackController.getTopBar().getTitle()).isEqualTo("the new title");
94
         assertThat(stackController.getTopBar().getTitle()).isEqualTo("the new title");
99
         uut.onViewAppeared();
100
         uut.onViewAppeared();
100
 
101
 
101
         Options opts = new Options();
102
         Options opts = new Options();
102
-        opts.topBarOptions.backgroundColor = new com.reactnativenavigation.parse.params.Color(Color.RED);
103
+        opts.topBarOptions.background.color = new com.reactnativenavigation.parse.params.Color(Color.RED);
103
         uut.mergeOptions(opts);
104
         uut.mergeOptions(opts);
104
 
105
 
105
         assertThat(((ColorDrawable) stackController.getTopBar().getTitleBar().getBackground()).getColor()).isEqualTo(Color.RED);
106
         assertThat(((ColorDrawable) stackController.getTopBar().getTitleBar().getBackground()).getColor()).isEqualTo(Color.RED);
112
             @Override
113
             @Override
113
             public void resolve(@Nullable Object value) {
114
             public void resolve(@Nullable Object value) {
114
                 Options opts = new Options();
115
                 Options opts = new Options();
115
-                opts.topBarOptions.title = new Text("the title");
116
-                opts.topBarOptions.textColor = new com.reactnativenavigation.parse.params.Color(Color.RED);
116
+                opts.topBarOptions.title.text = new Text("the title");
117
+                opts.topBarOptions.title.color = new com.reactnativenavigation.parse.params.Color(Color.RED);
117
                 uut.mergeOptions(opts);
118
                 uut.mergeOptions(opts);
118
 
119
 
119
                 assertThat(stackController.getTopBar().getTitleTextView()).isNotEqualTo(null);
120
                 assertThat(stackController.getTopBar().getTitleTextView()).isNotEqualTo(null);
125
     @Test
126
     @Test
126
     public void appliesTopBarTextSize() throws Exception {
127
     public void appliesTopBarTextSize() throws Exception {
127
         assertThat(uut.initialOptions).isSameAs(initialNavigationOptions);
128
         assertThat(uut.initialOptions).isSameAs(initialNavigationOptions);
128
-        initialNavigationOptions.topBarOptions.title = new Text("the title");
129
+        initialNavigationOptions.topBarOptions.title.text = new Text("the title");
129
         uut.ensureViewIsCreated();
130
         uut.ensureViewIsCreated();
130
         uut.onViewAppeared();
131
         uut.onViewAppeared();
131
 
132
 
132
         Options opts = new Options();
133
         Options opts = new Options();
133
-        opts.topBarOptions.title = new Text("the title");
134
-        opts.topBarOptions.textFontSize = new Fraction(18);
134
+        opts.topBarOptions.title.text = new Text("the title");
135
+        opts.topBarOptions.title.fontSize = new Fraction(18);
135
         uut.mergeOptions(opts);
136
         uut.mergeOptions(opts);
136
 
137
 
137
         assertThat(stackController.getTopBar().getTitleTextView()).isNotEqualTo(null);
138
         assertThat(stackController.getTopBar().getTitleTextView()).isNotEqualTo(null);
141
     @Test
142
     @Test
142
     public void appliesTopBarVisible() throws Exception {
143
     public void appliesTopBarVisible() throws Exception {
143
         assertThat(uut.initialOptions).isSameAs(initialNavigationOptions);
144
         assertThat(uut.initialOptions).isSameAs(initialNavigationOptions);
144
-        initialNavigationOptions.topBarOptions.title = new Text("the title");
145
+        initialNavigationOptions.topBarOptions.title.text = new Text("the title");
145
         uut.ensureViewIsCreated();
146
         uut.ensureViewIsCreated();
146
         uut.onViewAppeared();
147
         uut.onViewAppeared();
147
         assertThat(stackController.getTopBar().getVisibility()).isNotEqualTo(View.GONE);
148
         assertThat(stackController.getTopBar().getVisibility()).isNotEqualTo(View.GONE);
156
 
157
 
157
     @Test
158
     @Test
158
     public void appliesDrawUnder() throws Exception {
159
     public void appliesDrawUnder() throws Exception {
159
-        uut.options.topBarOptions.title = new Text("the title");
160
+        uut.options.topBarOptions.title.text = new Text("the title");
160
         uut.options.topBarOptions.drawBehind = new Bool(false);
161
         uut.options.topBarOptions.drawBehind = new Bool(false);
161
         uut.ensureViewIsCreated();
162
         uut.ensureViewIsCreated();
162
         stackController.animatePush(uut, new MockPromise() {
163
         stackController.animatePush(uut, new MockPromise() {

+ 13
- 8
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java View File

8
 import com.reactnativenavigation.BaseTest;
8
 import com.reactnativenavigation.BaseTest;
9
 import com.reactnativenavigation.mocks.MockPromise;
9
 import com.reactnativenavigation.mocks.MockPromise;
10
 import com.reactnativenavigation.mocks.SimpleViewController;
10
 import com.reactnativenavigation.mocks.SimpleViewController;
11
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12
 import com.reactnativenavigation.parse.Options;
13
 import com.reactnativenavigation.parse.Options;
13
 import com.reactnativenavigation.parse.params.Text;
14
 import com.reactnativenavigation.parse.params.Text;
38
         activity = newActivity();
39
         activity = newActivity();
39
         children = new ArrayList<>();
40
         children = new ArrayList<>();
40
         Options initialOptions = new Options();
41
         Options initialOptions = new Options();
41
-        initialOptions.topBarOptions.title = new Text(INITIAL_TITLE);
42
+        initialOptions.topBarOptions.title.text = new Text(INITIAL_TITLE);
42
         uut = spy(new ParentController(activity, "uut", initialOptions) {
43
         uut = spy(new ParentController(activity, "uut", initialOptions) {
43
 
44
 
44
             @NonNull
45
             @NonNull
88
 
89
 
89
     @Test
90
     @Test
90
     public void findControllerById_Recursive() throws Exception {
91
     public void findControllerById_Recursive() throws Exception {
91
-        StackController stackController = new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options());
92
+        StackController stackController = createStack();
92
         SimpleViewController child1 = new SimpleViewController(activity, "child1", new Options());
93
         SimpleViewController child1 = new SimpleViewController(activity, "child1", new Options());
93
         SimpleViewController child2 = new SimpleViewController(activity, "child2", new Options());
94
         SimpleViewController child2 = new SimpleViewController(activity, "child2", new Options());
94
         stackController.animatePush(child1, new MockPromise());
95
         stackController.animatePush(child1, new MockPromise());
110
 
111
 
111
     @Test
112
     @Test
112
     public void optionsAreClearedWhenChildIsAppeared() throws Exception {
113
     public void optionsAreClearedWhenChildIsAppeared() throws Exception {
113
-        StackController stackController = spy(new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options()));
114
+        StackController stackController = spy(createStack());
114
         SimpleViewController child1 = new SimpleViewController(activity, "child1", new Options());
115
         SimpleViewController child1 = new SimpleViewController(activity, "child1", new Options());
115
         stackController.animatePush(child1, new MockPromise());
116
         stackController.animatePush(child1, new MockPromise());
116
 
117
 
121
     @Test
122
     @Test
122
     public void mergeOptions_optionsAreMergedWhenChildAppears() throws Exception {
123
     public void mergeOptions_optionsAreMergedWhenChildAppears() throws Exception {
123
         Options options = new Options();
124
         Options options = new Options();
124
-        options.topBarOptions.title = new Text("new title");
125
+        options.topBarOptions.title.text = new Text("new title");
125
         ViewController child1 = spy(new SimpleViewController(activity, "child1", options));
126
         ViewController child1 = spy(new SimpleViewController(activity, "child1", options));
126
         children.add(child1);
127
         children.add(child1);
127
         uut.ensureViewIsCreated();
128
         uut.ensureViewIsCreated();
131
         ArgumentCaptor<Options> optionsCaptor = ArgumentCaptor.forClass(Options.class);
132
         ArgumentCaptor<Options> optionsCaptor = ArgumentCaptor.forClass(Options.class);
132
         ArgumentCaptor<ReactComponent> viewCaptor = ArgumentCaptor.forClass(ReactComponent.class);
133
         ArgumentCaptor<ReactComponent> viewCaptor = ArgumentCaptor.forClass(ReactComponent.class);
133
         verify(uut, times(1)).clearOptions();
134
         verify(uut, times(1)).clearOptions();
134
-        verify(uut, times(1)).applyOptions(optionsCaptor.capture(), viewCaptor.capture());
135
-        assertThat(optionsCaptor.getValue().topBarOptions.title.get()).isEqualTo("new title");
135
+        verify(uut, times(1)).applyChildOptions(optionsCaptor.capture(), viewCaptor.capture());
136
+        assertThat(optionsCaptor.getValue().topBarOptions.title.text.get()).isEqualTo("new title");
136
         assertThat(viewCaptor.getValue()).isEqualTo(child1.getView());
137
         assertThat(viewCaptor.getValue()).isEqualTo(child1.getView());
137
     }
138
     }
138
 
139
 
139
     @Test
140
     @Test
140
     public void mergeOptions_initialParentOptionsAreNotMutatedWhenChildAppears() throws Exception {
141
     public void mergeOptions_initialParentOptionsAreNotMutatedWhenChildAppears() throws Exception {
141
         Options options = new Options();
142
         Options options = new Options();
142
-        options.topBarOptions.title = new Text("new title");
143
+        options.topBarOptions.title.text = new Text("new title");
143
         ViewController child1 = spy(new SimpleViewController(activity, "child1", options));
144
         ViewController child1 = spy(new SimpleViewController(activity, "child1", options));
144
         children.add(child1);
145
         children.add(child1);
145
 
146
 
147
 
148
 
148
         child1.ensureViewIsCreated();
149
         child1.ensureViewIsCreated();
149
         child1.onViewAppeared();
150
         child1.onViewAppeared();
150
-        assertThat(uut.initialOptions.topBarOptions.title.get()).isEqualTo(INITIAL_TITLE);
151
+        assertThat(uut.initialOptions.topBarOptions.title.text.get()).isEqualTo(INITIAL_TITLE);
152
+    }
153
+
154
+    private StackController createStack() {
155
+        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack", new Options());
151
     }
156
     }
152
 }
157
 }

+ 15
- 11
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java View File

7
 import com.reactnativenavigation.BaseTest;
7
 import com.reactnativenavigation.BaseTest;
8
 import com.reactnativenavigation.mocks.MockPromise;
8
 import com.reactnativenavigation.mocks.MockPromise;
9
 import com.reactnativenavigation.mocks.SimpleViewController;
9
 import com.reactnativenavigation.mocks.SimpleViewController;
10
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
10
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
11
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
11
 import com.reactnativenavigation.parse.Options;
12
 import com.reactnativenavigation.parse.Options;
12
 import com.reactnativenavigation.parse.params.Bool;
13
 import com.reactnativenavigation.parse.params.Bool;
39
     public void beforeEach() {
40
     public void beforeEach() {
40
         super.beforeEach();
41
         super.beforeEach();
41
         activity = newActivity();
42
         activity = newActivity();
42
-        uut = new StackController(activity, new TopBarButtonCreatorMock(), "uut", new Options());
43
+        uut = createStackController("uut");
43
         child1 = spy(new SimpleViewController(activity, "child1", new Options()));
44
         child1 = spy(new SimpleViewController(activity, "child1", new Options()));
44
         child2 = spy(new SimpleViewController(activity, "child2", new Options()));
45
         child2 = spy(new SimpleViewController(activity, "child2", new Options()));
45
         child3 = spy(new SimpleViewController(activity, "child3", new Options()));
46
         child3 = spy(new SimpleViewController(activity, "child3", new Options()));
87
             @Override
88
             @Override
88
             public void resolve(@Nullable Object value) {
89
             public void resolve(@Nullable Object value) {
89
                 uut.pop(new MockPromise());
90
                 uut.pop(new MockPromise());
90
-                verify(uut, times(1)).applyOptions(uut.options, eq((ReactComponent) child1.getView()));
91
+                verify(uut, times(1)).applyChildOptions(uut.options, eq((ReactComponent) child1.getView()));
91
             }
92
             }
92
         });
93
         });
93
     }
94
     }
95
     @Test
96
     @Test
96
     public void pop_layoutHandlesChildWillDisappear() throws Exception {
97
     public void pop_layoutHandlesChildWillDisappear() throws Exception {
97
         final StackLayout[] stackLayout = new StackLayout[1];
98
         final StackLayout[] stackLayout = new StackLayout[1];
98
-        uut = new StackController(activity, new TopBarButtonCreatorMock(), "uut", new Options()) {
99
+        uut = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "uut", new Options()) {
99
             @NonNull
100
             @NonNull
100
             @Override
101
             @Override
101
             protected StackLayout createView() {
102
             protected StackLayout createView() {
134
         uut.animatePush(child1, new MockPromise());
135
         uut.animatePush(child1, new MockPromise());
135
         assertThat(child1.getParentController()).isEqualTo(uut);
136
         assertThat(child1.getParentController()).isEqualTo(uut);
136
 
137
 
137
-        StackController anotherNavController = new StackController(activity, new TopBarButtonCreatorMock(), "another", new Options());
138
+        StackController anotherNavController = createStackController("another");
138
         anotherNavController.animatePush(child2, new MockPromise());
139
         anotherNavController.animatePush(child2, new MockPromise());
139
         assertThat(child2.getParentController()).isEqualTo(anotherNavController);
140
         assertThat(child2.getParentController()).isEqualTo(anotherNavController);
140
     }
141
     }
314
 
315
 
315
     @Test
316
     @Test
316
     public void findControllerById_Deeply() throws Exception {
317
     public void findControllerById_Deeply() throws Exception {
317
-        StackController stack = new StackController(activity, new TopBarButtonCreatorMock(), "stack2", new Options());
318
+        StackController stack = createStackController("stack2");
318
         stack.animatePush(child2, new MockPromise());
319
         stack.animatePush(child2, new MockPromise());
319
         uut.animatePush(stack, new MockPromise());
320
         uut.animatePush(stack, new MockPromise());
320
         assertThat(uut.findControllerById(child2.getId())).isEqualTo(child2);
321
         assertThat(uut.findControllerById(child2.getId())).isEqualTo(child2);
351
     @Test
352
     @Test
352
     public void pop_animatesTopBarIfNeeded() throws Exception {
353
     public void pop_animatesTopBarIfNeeded() throws Exception {
353
         uut.ensureViewIsCreated();
354
         uut.ensureViewIsCreated();
354
-        uut.getView().setTopBar(spy(uut.getTopBar()));
355
 
355
 
356
         child1.options.topBarOptions.visible = new Bool(false);
356
         child1.options.topBarOptions.visible = new Bool(false);
357
         child1.options.topBarOptions.animate = new Bool(false);
357
         child1.options.topBarOptions.animate = new Bool(false);
409
 
409
 
410
     @Test
410
     @Test
411
     public void stackCanBePushed() throws Exception {
411
     public void stackCanBePushed() throws Exception {
412
-        StackController parent = new StackController(activity, new TopBarButtonCreatorMock(), "someStack", new Options());
412
+        StackController parent = createStackController("someStack");
413
         parent.ensureViewIsCreated();
413
         parent.ensureViewIsCreated();
414
         parent.push(uut, new MockPromise());
414
         parent.push(uut, new MockPromise());
415
         uut.onViewAppeared();
415
         uut.onViewAppeared();
418
 
418
 
419
     @Test
419
     @Test
420
     public void applyOptions_applyOnlyOnFirstStack() throws Exception {
420
     public void applyOptions_applyOnlyOnFirstStack() throws Exception {
421
-        StackController parent = spy(new StackController(activity, new TopBarButtonCreatorMock(), "someStack", new Options()));
421
+        StackController parent = spy(createStackController("someStack"));
422
         parent.ensureViewIsCreated();
422
         parent.ensureViewIsCreated();
423
         parent.push(uut, new MockPromise());
423
         parent.push(uut, new MockPromise());
424
 
424
 
425
         Options childOptions = new Options();
425
         Options childOptions = new Options();
426
-        childOptions.topBarOptions.title = new Text("Something");
426
+        childOptions.topBarOptions.title.text = new Text("Something");
427
         child1.options = childOptions;
427
         child1.options = childOptions;
428
         uut.push(child1, new MockPromise());
428
         uut.push(child1, new MockPromise());
429
         child1.ensureViewIsCreated();
429
         child1.ensureViewIsCreated();
431
 
431
 
432
         ArgumentCaptor<Options> optionsCaptor = ArgumentCaptor.forClass(Options.class);
432
         ArgumentCaptor<Options> optionsCaptor = ArgumentCaptor.forClass(Options.class);
433
         ArgumentCaptor<ReactComponent> viewCaptor = ArgumentCaptor.forClass(ReactComponent.class);
433
         ArgumentCaptor<ReactComponent> viewCaptor = ArgumentCaptor.forClass(ReactComponent.class);
434
-        verify(parent, times(1)).applyOptions(optionsCaptor.capture(), viewCaptor.capture());
435
-        assertThat(optionsCaptor.getValue().topBarOptions.title.hasValue()).isFalse();
434
+        verify(parent, times(1)).applyChildOptions(optionsCaptor.capture(), viewCaptor.capture());
435
+        assertThat(optionsCaptor.getValue().topBarOptions.title.text.hasValue()).isFalse();
436
     }
436
     }
437
 
437
 
438
     @Test
438
     @Test
456
         assertThat(uut.size()).isEqualTo(ids.length);
456
         assertThat(uut.size()).isEqualTo(ids.length);
457
         assertThat(uut.getChildControllers()).extracting((Extractor<ViewController, String>) ViewController::getId).containsOnly(ids);
457
         assertThat(uut.getChildControllers()).extracting((Extractor<ViewController, String>) ViewController::getId).containsOnly(ids);
458
     }
458
     }
459
+
460
+    private StackController createStackController(String id) {
461
+        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), id, new Options());
462
+    }
459
 }
463
 }

+ 46
- 2
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TitleBarTest.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
+import android.support.v7.widget.Toolbar;
5
+import android.view.Gravity;
6
+import android.view.ViewGroup;
4
 
7
 
5
 import com.reactnativenavigation.BaseTest;
8
 import com.reactnativenavigation.BaseTest;
9
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
6
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
10
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
11
+import com.reactnativenavigation.parse.TitleOptions;
7
 import com.reactnativenavigation.parse.params.Button;
12
 import com.reactnativenavigation.parse.params.Button;
8
 import com.reactnativenavigation.parse.params.Text;
13
 import com.reactnativenavigation.parse.params.Text;
9
 import com.reactnativenavigation.react.ReactView;
14
 import com.reactnativenavigation.react.ReactView;
10
-import com.reactnativenavigation.views.TitleBar;
15
+import com.reactnativenavigation.views.titlebar.TitleBar;
16
+import com.reactnativenavigation.views.titlebar.TitleBarReactView;
11
 
17
 
12
 import org.junit.Test;
18
 import org.junit.Test;
19
+import org.mockito.ArgumentCaptor;
13
 
20
 
14
 import java.util.ArrayList;
21
 import java.util.ArrayList;
15
 import java.util.Arrays;
22
 import java.util.Arrays;
19
 import java.util.Map;
26
 import java.util.Map;
20
 
27
 
21
 import static org.assertj.core.api.Java6Assertions.assertThat;
28
 import static org.assertj.core.api.Java6Assertions.assertThat;
29
+import static org.mockito.ArgumentMatchers.any;
22
 import static org.mockito.Mockito.spy;
30
 import static org.mockito.Mockito.spy;
23
 import static org.mockito.Mockito.times;
31
 import static org.mockito.Mockito.times;
24
 import static org.mockito.Mockito.verify;
32
 import static org.mockito.Mockito.verify;
30
     private Button textButton;
38
     private Button textButton;
31
     private Button customButton;
39
     private Button customButton;
32
     private Map<String, TopBarButtonController> buttonControllers;
40
     private Map<String, TopBarButtonController> buttonControllers;
41
+    private TitleBarReactViewController reactViewController;
33
 
42
 
34
     @Override
43
     @Override
35
     public void beforeEach() {
44
     public void beforeEach() {
36
         final TopBarButtonCreatorMock buttonCreator = new TopBarButtonCreatorMock();
45
         final TopBarButtonCreatorMock buttonCreator = new TopBarButtonCreatorMock();
37
         final Activity activity = newActivity();
46
         final Activity activity = newActivity();
47
+        reactViewController = spy(new TitleBarReactViewController(activity, new TitleBarReactViewCreatorMock()));
38
         createButtons();
48
         createButtons();
39
         buttonControllers = new HashMap<>();
49
         buttonControllers = new HashMap<>();
40
-        uut = spy(new TitleBar(activity, buttonCreator, (buttonId -> {})) {
50
+        uut = spy(new TitleBar(activity, buttonCreator, reactViewController, (buttonId -> {})) {
41
             @Override
51
             @Override
42
             public TopBarButtonController createButtonController(Button button) {
52
             public TopBarButtonController createButtonController(Button button) {
43
                 TopBarButtonController controller = spy(super.createButtonController(button));
53
                 TopBarButtonController controller = spy(super.createButtonController(button));
120
         assertThat(uut.getMenu().getItem(1).getTitle()).isEqualTo(textButton.title.get());
130
         assertThat(uut.getMenu().getItem(1).getTitle()).isEqualTo(textButton.title.get());
121
     }
131
     }
122
 
132
 
133
+    @Test
134
+    public void setComponent_addsComponentToTitleBar() throws Exception {
135
+        uut.setComponent("com.rnn.CustomView", TitleOptions.Alignment.Center);
136
+        verify(uut, times(1)).addView(any(TitleBarReactView.class), any(Toolbar.LayoutParams.class));
137
+    }
138
+
139
+    @Test
140
+    public void setComponent_alignFill() throws Exception {
141
+        uut.setComponent("com.rnn.CustomView", TitleOptions.Alignment.Fill);
142
+        verify(uut, times(1)).getComponentLayoutParams(TitleOptions.Alignment.Fill);
143
+        ArgumentCaptor<Toolbar.LayoutParams> lpCaptor = ArgumentCaptor.forClass(Toolbar.LayoutParams.class);
144
+        verify(uut, times(1)).addView(any(TitleBarReactView.class), lpCaptor.capture());
145
+        assertThat(lpCaptor.getValue().width == ViewGroup.LayoutParams.MATCH_PARENT);
146
+    }
147
+
148
+    @Test
149
+    public void setComponent_alignCenter() throws Exception {
150
+        uut.setComponent("com.rnn.CustomView", TitleOptions.Alignment.Center);
151
+        verify(uut, times(1)).getComponentLayoutParams(TitleOptions.Alignment.Center);
152
+        ArgumentCaptor<Toolbar.LayoutParams> lpCaptor = ArgumentCaptor.forClass(Toolbar.LayoutParams.class);
153
+        verify(uut, times(1)).addView(any(TitleBarReactView.class), lpCaptor.capture());
154
+        assertThat(lpCaptor.getValue().width == ViewGroup.LayoutParams.WRAP_CONTENT);
155
+        assertThat(lpCaptor.getValue().gravity == Gravity.CENTER);
156
+    }
157
+
158
+    @Test
159
+    public void clear() throws Exception {
160
+        uut.clear();
161
+        assertThat(uut.getTitle()).isNullOrEmpty();
162
+        assertThat(uut.getMenu().size()).isZero();
163
+        assertThat(uut.getNavigationIcon()).isNull();
164
+        verify(reactViewController, times(1)).destroy();
165
+    }
166
+
123
     private List<Button> leftButton(Button leftButton) {
167
     private List<Button> leftButton(Button leftButton) {
124
         return Collections.singletonList(leftButton);
168
         return Collections.singletonList(leftButton);
125
     }
169
     }

+ 2
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopBarButtonControllerTest.java View File

4
 import android.support.annotation.NonNull;
4
 import android.support.annotation.NonNull;
5
 
5
 
6
 import com.reactnativenavigation.BaseTest;
6
 import com.reactnativenavigation.BaseTest;
7
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
7
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
8
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
8
 import com.reactnativenavigation.parse.Options;
9
 import com.reactnativenavigation.parse.Options;
9
 import com.reactnativenavigation.parse.params.Button;
10
 import com.reactnativenavigation.parse.params.Button;
28
 
29
 
29
         TopBarButtonCreatorMock buttonCreatorMock = new TopBarButtonCreatorMock();
30
         TopBarButtonCreatorMock buttonCreatorMock = new TopBarButtonCreatorMock();
30
         uut = spy(new TopBarButtonController(activity, button, buttonCreatorMock, (buttonId) -> {}));
31
         uut = spy(new TopBarButtonController(activity, button, buttonCreatorMock, (buttonId) -> {}));
31
-        stackController = spy(new StackController(activity, buttonCreatorMock, "stack", new Options()));
32
+        stackController = spy(new StackController(activity, buttonCreatorMock, new TitleBarReactViewCreatorMock(), "stack", new Options()));
32
 
33
 
33
     }
34
     }
34
 
35
 

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

8
 import com.reactnativenavigation.mocks.MockPromise;
8
 import com.reactnativenavigation.mocks.MockPromise;
9
 import com.reactnativenavigation.mocks.TestComponentViewCreator;
9
 import com.reactnativenavigation.mocks.TestComponentViewCreator;
10
 import com.reactnativenavigation.mocks.TestReactView;
10
 import com.reactnativenavigation.mocks.TestReactView;
11
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12
 import com.reactnativenavigation.parse.Options;
13
 import com.reactnativenavigation.parse.Options;
13
 import com.reactnativenavigation.parse.params.Text;
14
 import com.reactnativenavigation.parse.params.Text;
60
         uut = spy(new TopTabsController(activity, "componentId", tabControllers, layoutCreator, options));
61
         uut = spy(new TopTabsController(activity, "componentId", tabControllers, layoutCreator, options));
61
         tabControllers.forEach(viewController -> viewController.setParentController(uut));
62
         tabControllers.forEach(viewController -> viewController.setParentController(uut));
62
 
63
 
63
-        parentController = spy(new StackController(activity, new TopBarButtonCreatorMock(), "stackId", new Options()));
64
+        parentController = spy(createStackController("stackId"));
64
         parentController.push(uut, new MockPromise());
65
         parentController.push(uut, new MockPromise());
65
         uut.setParentController(parentController);
66
         uut.setParentController(parentController);
66
     }
67
     }
67
 
68
 
69
+    @NonNull
70
+    private StackController createStackController(String id) {
71
+        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), id, new Options());
72
+    }
73
+
68
     @NonNull
74
     @NonNull
69
     private ArrayList<Options> createOptions() {
75
     private ArrayList<Options> createOptions() {
70
         ArrayList result = new ArrayList();
76
         ArrayList result = new ArrayList();
71
         for (int i = 0; i < SIZE; i++) {
77
         for (int i = 0; i < SIZE; i++) {
72
             final Options options = new Options();
78
             final Options options = new Options();
73
             options.topTabOptions.title = new Text("Tab " + i);
79
             options.topTabOptions.title = new Text("Tab " + i);
74
-            options.topBarOptions.title = new Text(createTabTopBarTitle(i));
80
+            options.topBarOptions.title.text = new Text(createTabTopBarTitle(i));
75
             result.add(options);
81
             result.add(options);
76
         }
82
         }
77
         return result;
83
         return result;
160
         verify(tabControllers.get(1), times(0)).onViewAppeared();
166
         verify(tabControllers.get(1), times(0)).onViewAppeared();
161
 
167
 
162
         ReactComponent comp = ((ComponentViewController) tabControllers.get(0)).getComponent();
168
         ReactComponent comp = ((ComponentViewController) tabControllers.get(0)).getComponent();
163
-        verify(uut, times(1)).applyOptions(any(Options.class), eq(comp));
169
+        verify(uut, times(1)).applyChildOptions(any(Options.class), eq(comp));
164
     }
170
     }
165
 
171
 
166
     @Test
172
     @Test
172
 
178
 
173
         uut.onViewAppeared();
179
         uut.onViewAppeared();
174
         ReactComponent currentTab = tabView(0);
180
         ReactComponent currentTab = tabView(0);
175
-        verify(uut, times(1)).applyOptions(any(Options.class), eq(currentTab));
176
-        assertThat(uut.options.topBarOptions.title.get()).isEqualTo(createTabTopBarTitle(0));
181
+        verify(uut, times(1)).applyChildOptions(any(Options.class), eq(currentTab));
182
+        assertThat(uut.options.topBarOptions.title.text.get()).isEqualTo(createTabTopBarTitle(0));
177
 
183
 
178
         uut.switchToTab(1);
184
         uut.switchToTab(1);
179
         currentTab = tabView(1);
185
         currentTab = tabView(1);
180
-        verify(uut, times(1)).applyOptions(any(Options.class), eq(currentTab));
181
-        assertThat(uut.options.topBarOptions.title.get()).isEqualTo(createTabTopBarTitle(1));
186
+        verify(uut, times(1)).applyChildOptions(any(Options.class), eq(currentTab));
187
+        assertThat(uut.options.topBarOptions.title.text.get()).isEqualTo(createTabTopBarTitle(1));
182
 
188
 
183
         uut.switchToTab(0);
189
         uut.switchToTab(0);
184
         currentTab = tabView(0);
190
         currentTab = tabView(0);
185
-        verify(uut, times(2)).applyOptions(any(Options.class), eq(currentTab));
186
-        assertThat(uut.options.topBarOptions.title.get()).isEqualTo(createTabTopBarTitle(0));
191
+        verify(uut, times(2)).applyChildOptions(any(Options.class), eq(currentTab));
192
+        assertThat(uut.options.topBarOptions.title.text.get()).isEqualTo(createTabTopBarTitle(0));
187
     }
193
     }
188
 
194
 
189
     private TestReactView getActualTabView(int index) {
195
     private TestReactView getActualTabView(int index) {
207
         tabControllers.get(0).onViewAppeared();
213
         tabControllers.get(0).onViewAppeared();
208
         ArgumentCaptor<Options> optionsCaptor = ArgumentCaptor.forClass(Options.class);
214
         ArgumentCaptor<Options> optionsCaptor = ArgumentCaptor.forClass(Options.class);
209
         ArgumentCaptor<ReactComponent> viewCaptor = ArgumentCaptor.forClass(ReactComponent.class);
215
         ArgumentCaptor<ReactComponent> viewCaptor = ArgumentCaptor.forClass(ReactComponent.class);
210
-        verify(parentController, times(1)).applyOptions(optionsCaptor.capture(), viewCaptor.capture());
216
+        verify(parentController, times(1)).applyChildOptions(optionsCaptor.capture(), viewCaptor.capture());
211
         assertThat(optionsCaptor.getValue().topTabOptions.title.hasValue()).isFalse();
217
         assertThat(optionsCaptor.getValue().topTabOptions.title.hasValue()).isFalse();
212
     }
218
     }
213
 
219
 
215
     public void applyOptions_tabsAreRemovedAfterViewDisappears() throws Exception {
221
     public void applyOptions_tabsAreRemovedAfterViewDisappears() throws Exception {
216
         parentController.getView().removeAllViews();
222
         parentController.getView().removeAllViews();
217
 
223
 
218
-        StackController stackController = spy(new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options()));
224
+        StackController stackController = spy(createStackController("stack"));
219
         ComponentViewController first = new ComponentViewController(
225
         ComponentViewController first = new ComponentViewController(
220
                 activity,
226
                 activity,
221
                 "firstScreen",
227
                 "firstScreen",

+ 2
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ViewControllerTest.java View File

9
 import com.reactnativenavigation.BaseTest;
9
 import com.reactnativenavigation.BaseTest;
10
 import com.reactnativenavigation.mocks.MockPromise;
10
 import com.reactnativenavigation.mocks.MockPromise;
11
 import com.reactnativenavigation.mocks.SimpleViewController;
11
 import com.reactnativenavigation.mocks.SimpleViewController;
12
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
13
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
13
 import com.reactnativenavigation.parse.Options;
14
 import com.reactnativenavigation.parse.Options;
14
 
15
 
66
     @Test
67
     @Test
67
     public void holdsAReferenceToStackControllerOrNull() throws Exception {
68
     public void holdsAReferenceToStackControllerOrNull() throws Exception {
68
         assertThat(uut.getParentController()).isNull();
69
         assertThat(uut.getParentController()).isNull();
69
-        StackController nav = new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options());
70
+        StackController nav = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack", new Options());
70
         nav.animatePush(uut, new MockPromise());
71
         nav.animatePush(uut, new MockPromise());
71
         assertThat(uut.getParentController()).isEqualTo(nav);
72
         assertThat(uut.getParentController()).isEqualTo(nav);
72
     }
73
     }

+ 3
- 2
lib/android/app/src/test/java/com/reactnativenavigation/views/TopBarTest.java View File

5
 
5
 
6
 import com.reactnativenavigation.BaseTest;
6
 import com.reactnativenavigation.BaseTest;
7
 import com.reactnativenavigation.anim.TopBarAnimator;
7
 import com.reactnativenavigation.anim.TopBarAnimator;
8
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
8
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
9
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
9
 import com.reactnativenavigation.parse.params.Bool;
10
 import com.reactnativenavigation.parse.params.Bool;
10
 import com.reactnativenavigation.parse.params.Button;
11
 import com.reactnativenavigation.parse.params.Button;
38
                 Log.i("TopBarTest", "onPress: " + buttonId);
39
                 Log.i("TopBarTest", "onPress: " + buttonId);
39
             }
40
             }
40
         });
41
         });
41
-        StackLayout parent = new StackLayout(newActivity(), new TopBarButtonCreatorMock(), this.onClickListener);
42
-        uut = new TopBar(newActivity(), new TopBarButtonCreatorMock(), this.onClickListener, parent);
42
+        StackLayout parent = new StackLayout(newActivity(), new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), this.onClickListener);
43
+        uut = new TopBar(newActivity(), new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), this.onClickListener, parent);
43
         animator = spy(new TopBarAnimator(uut));
44
         animator = spy(new TopBarAnimator(uut));
44
         uut.setAnimator(animator);
45
         uut.setAnimator(animator);
45
         leftButton = createLeftButton();
46
         leftButton = createLeftButton();

+ 6
- 0
lib/ios/RNNBottomTabsOptions.m View File

15
 	
15
 	
16
 	if (self.visible) {
16
 	if (self.visible) {
17
 		[((RNNTabBarController *)viewController.tabBarController) setTabBarHidden:![self.visible boolValue] animated:[self.animate boolValue]];
17
 		[((RNNTabBarController *)viewController.tabBarController) setTabBarHidden:![self.visible boolValue] animated:[self.animate boolValue]];
18
+	} else {
19
+		[((RNNTabBarController *)viewController.tabBarController) setTabBarHidden:NO animated:NO];
18
 	}
20
 	}
19
 	
21
 	
20
 	if (self.testID) {
22
 	if (self.testID) {
31
 	
33
 	
32
 	if (self.backgroundColor) {
34
 	if (self.backgroundColor) {
33
 		viewController.tabBarController.tabBar.barTintColor = [RCTConvert UIColor:self.backgroundColor];
35
 		viewController.tabBarController.tabBar.barTintColor = [RCTConvert UIColor:self.backgroundColor];
36
+	} else {
37
+		viewController.tabBarController.tabBar.barTintColor = nil;
34
 	}
38
 	}
35
 	
39
 	
36
 	if (self.translucent) {
40
 	if (self.translucent) {
37
 		viewController.tabBarController.tabBar.translucent = [self.translucent boolValue];
41
 		viewController.tabBarController.tabBar.translucent = [self.translucent boolValue];
42
+	} else {
43
+		viewController.tabBarController.tabBar.translucent = NO;
38
 	}
44
 	}
39
 	
45
 	
40
 	if (self.hideShadow) {
46
 	if (self.hideShadow) {

+ 5
- 2
lib/ios/RNNCustomTitleView.h View File

1
 #import <UIKit/UIKit.h>
1
 #import <UIKit/UIKit.h>
2
+#import <React/RCTRootView.h>
3
+#import <React/RCTRootViewDelegate.h>
2
 
4
 
3
-@interface RNNCustomTitleView : UIView
5
+@interface RNNCustomTitleView : UIView <RCTRootViewDelegate>
4
 
6
 
5
--(instancetype)initWithFrame:(CGRect)frame subView:(UIView*)subView alignment:(NSString*)alignment;
7
+- (instancetype)initWithFrame:(CGRect)frame subView:(RCTRootView*)subView alignment:(NSString*)alignment;
6
 
8
 
7
 @end
9
 @end
10
+

+ 41
- 33
lib/ios/RNNCustomTitleView.m View File

1
 #import "RNNCustomTitleView.h"
1
 #import "RNNCustomTitleView.h"
2
 
2
 
3
 @interface RNNCustomTitleView ()
3
 @interface RNNCustomTitleView ()
4
-@property (nonatomic, strong) UIView *subView;
5
-@property (nonatomic, strong) NSString *subViewAlign;
4
+
5
+@property (nonatomic, strong) RCTRootView *subView;
6
+@property (nonatomic, strong) NSString *alignment;
7
+
6
 @end
8
 @end
7
 
9
 
8
 @implementation RNNCustomTitleView
10
 @implementation RNNCustomTitleView
9
 
11
 
12
+- (instancetype)initWithFrame:(CGRect)frame subView:(RCTRootView*)subView alignment:(NSString*)alignment {
13
+	self = [super init];
14
+	
15
+	if (self) {
16
+		self.subView = subView;
17
+		self.alignment = alignment;
18
+		
19
+		self.backgroundColor = [UIColor clearColor];
20
+		self.subView.backgroundColor = [UIColor clearColor];
21
+		
22
+		if ([alignment isEqualToString:@"fill"]) {
23
+			self.frame = frame;
24
+			subView.sizeFlexibility = RCTRootViewSizeFlexibilityNone;
25
+		} else {
26
+			self.subView.delegate = self;
27
+			subView.sizeFlexibility = RCTRootViewSizeFlexibilityWidthAndHeight;
28
+		}
29
+		
30
+		[self addSubview:subView];
31
+	}
32
+	
33
+	return self;
34
+}
10
 
35
 
11
--(instancetype)initWithFrame:(CGRect)frame subView:(UIView*)subView alignment:(NSString*)alignment {
12
-    self = [super initWithFrame:frame];
13
-    
14
-    if (self) {
15
-        self.backgroundColor = [UIColor clearColor];
16
-        self.subView = subView;
17
-        self.subViewAlign = alignment;
18
-        
19
-        subView.frame = self.bounds;
20
-        [self addSubview:subView];
21
-    }
22
-    
23
-    return self;
36
+- (void)layoutSubviews {
37
+	[super layoutSubviews];
38
+	if ([self.alignment isEqualToString:@"fill"]) {
39
+		[self.subView setFrame:self.bounds];
40
+	}
24
 }
41
 }
25
 
42
 
43
+- (NSString *)alignment {
44
+	return _alignment ? _alignment : @"center";
45
+}
26
 
46
 
27
--(void)layoutSubviews {
28
-    [super layoutSubviews];
29
-    
30
-    if ([self.subViewAlign isEqualToString:@"fill"]) {
31
-        self.subView.frame = self.bounds;
32
-    }
33
-    else {
34
-        
35
-        CGFloat superViewWidth = self.superview.frame.size.width;
36
-        CGFloat paddingLeftFromCenter = (superViewWidth/2) - self.frame.origin.x;
37
-        CGFloat paddingRightFromCenter = self.frame.size.width - paddingLeftFromCenter;;
38
-        CGRect reactViewFrame = self.subView.bounds;
39
-        CGFloat minPadding = MIN(paddingLeftFromCenter, paddingRightFromCenter);
40
-        
41
-        reactViewFrame.size.width = minPadding*2;
42
-        reactViewFrame.origin.x = paddingLeftFromCenter - minPadding;
43
-        self.subView.frame = reactViewFrame;
44
-    }
47
+- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView {
48
+	if ([self.alignment isEqualToString:@"center"]) {
49
+		[self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, self.subView.intrinsicContentSize.width, self.subView.intrinsicContentSize.height)];
50
+		[self.subView setFrame:CGRectMake(0, 0, rootView.intrinsicContentSize.width, rootView.intrinsicContentSize.height)];
51
+	}
45
 }
52
 }
46
 
53
 
47
 @end
54
 @end
55
+

+ 6
- 0
lib/ios/RNNNavigationButtons.m View File

101
 		[barButtonItem setTintColor:[RCTConvert UIColor: tintColor]];
101
 		[barButtonItem setTintColor:[RCTConvert UIColor: tintColor]];
102
 	}
102
 	}
103
 	
103
 	
104
+	NSNumber* disabledColor = dictionary[@"disabledColor"];
105
+	if (disabledColor) {
106
+		UIColor *color = [RCTConvert UIColor:disabledColor];
107
+		[barButtonItem setTitleTextAttributes:@{NSForegroundColorAttributeName : color} forState:UIControlStateDisabled];
108
+	}
109
+	
104
 	NSString *testID = dictionary[@"testID"];
110
 	NSString *testID = dictionary[@"testID"];
105
 	if (testID)
111
 	if (testID)
106
 	{
112
 	{

+ 1
- 0
lib/ios/RNNNavigationOptions.h View File

34
 @property (nonatomic, strong) id orientation;
34
 @property (nonatomic, strong) id orientation;
35
 @property (nonatomic, strong) NSNumber* statusBarBlur;
35
 @property (nonatomic, strong) NSNumber* statusBarBlur;
36
 @property (nonatomic, strong) NSNumber* statusBarHideWithTopBar;
36
 @property (nonatomic, strong) NSNumber* statusBarHideWithTopBar;
37
+@property (nonatomic, strong) NSString* statusBarStyle;
37
 @property (nonatomic, strong) NSNumber* popGesture;
38
 @property (nonatomic, strong) NSNumber* popGesture;
38
 @property (nonatomic, strong) UIImage* backgroundImage;
39
 @property (nonatomic, strong) UIImage* backgroundImage;
39
 @property (nonatomic, strong) UIImage* rootBackgroundImage;
40
 @property (nonatomic, strong) UIImage* rootBackgroundImage;

+ 3
- 3
lib/ios/RNNNavigationOptions.m View File

20
 -(instancetype)initWithDict:(NSDictionary *)options {
20
 -(instancetype)initWithDict:(NSDictionary *)options {
21
 	self = [super init];
21
 	self = [super init];
22
 	self.statusBarHidden = [options objectForKey:@"statusBarHidden"];
22
 	self.statusBarHidden = [options objectForKey:@"statusBarHidden"];
23
+	self.statusBarBlur = [options objectForKey:@"statusBarBlur"];
24
+	self.statusBarStyle = [options objectForKey:@"statusBarStyle"];
23
 	self.screenBackgroundColor = [options objectForKey:@"screenBackgroundColor"];
25
 	self.screenBackgroundColor = [options objectForKey:@"screenBackgroundColor"];
24
 	self.backButtonTransition = [options objectForKey:@"backButtonTransition"];
26
 	self.backButtonTransition = [options objectForKey:@"backButtonTransition"];
25
 	self.orientation = [options objectForKey:@"orientation"];
27
 	self.orientation = [options objectForKey:@"orientation"];
51
 	}
53
 	}
52
 }
54
 }
53
 
55
 
54
--(void)applyOn:(UIViewController*)viewController {
55
-//	[_defaultOptions applyOn:viewController];
56
-	
56
+-(void)applyOn:(UIViewController*)viewController {	
57
 	[self.topBar applyOn:viewController];
57
 	[self.topBar applyOn:viewController];
58
 	[self.bottomTabs applyOn:viewController];
58
 	[self.bottomTabs applyOn:viewController];
59
 	[self.topTab applyOn:viewController];
59
 	[self.topTab applyOn:viewController];

+ 6
- 1
lib/ios/RNNOptions.m View File

17
 -(void)mergeWith:(NSDictionary *)otherOptions {
17
 -(void)mergeWith:(NSDictionary *)otherOptions {
18
 	for (id key in otherOptions) {
18
 	for (id key in otherOptions) {
19
 		if ([self hasProperty:key]) {
19
 		if ([self hasProperty:key]) {
20
-			[self setValue:[otherOptions objectForKey:key] forKey:key];
20
+			if ([[self valueForKey:key] isKindOfClass:[RNNOptions class]]) {
21
+				RNNOptions* options = [self valueForKey:key];
22
+				[options mergeWith:[otherOptions objectForKey:key]];
23
+			} else {
24
+				[self setValue:[otherOptions objectForKey:key] forKey:key];
25
+			}
21
 		}
26
 		}
22
 	}
27
 	}
23
 }
28
 }

+ 25
- 6
lib/ios/RNNRootViewController.m View File

44
 -(void)viewWillAppear:(BOOL)animated{
44
 -(void)viewWillAppear:(BOOL)animated{
45
 	[super viewWillAppear:animated];
45
 	[super viewWillAppear:animated];
46
 	[self.options applyOn:self];
46
 	[self.options applyOn:self];
47
+	
47
 	[self setCustomNavigationTitleView];
48
 	[self setCustomNavigationTitleView];
48
 	[self setCustomNavigationBarView];
49
 	[self setCustomNavigationBarView];
50
+	[self setCustomNavigationComponentBackground];
49
 }
51
 }
50
 
52
 
51
 -(void)viewDidAppear:(BOOL)animated {
53
 -(void)viewDidAppear:(BOOL)animated {
71
 }
73
 }
72
 
74
 
73
 - (void)setCustomNavigationTitleView {
75
 - (void)setCustomNavigationTitleView {
74
-	if (self.options.topBar.customTitleViewName) {
75
-		UIView *reactView = [_creator createRootView:self.options.topBar.customTitleViewName rootViewId:self.options.topBar.customTitleViewName];
76
+	if (self.options.topBar.title.component) {
77
+		RCTRootView *reactView = (RCTRootView*)[_creator createRootView:self.options.topBar.title.component rootViewId:self.options.topBar.title.component];
76
 		
78
 		
77
-		RNNCustomTitleView *titleView = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:nil];
79
+		RNNCustomTitleView *titleView = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:self.options.topBar.title.componentAlignment];
78
 		self.navigationItem.titleView = titleView;
80
 		self.navigationItem.titleView = titleView;
79
 	}
81
 	}
80
 }
82
 }
81
 
83
 
82
 - (void)setCustomNavigationBarView {
84
 - (void)setCustomNavigationBarView {
83
-	if (self.options.topBar.customViewName) {
84
-		UIView *reactView = [_creator createRootView:self.options.topBar.customViewName rootViewId:@"navBar"];
85
+	if (self.options.topBar.componentName) {
86
+		RCTRootView *reactView = (RCTRootView*)[_creator createRootView:self.options.topBar.componentName rootViewId:@"navBar"];
85
 		
87
 		
86
-		RNNCustomTitleView *titleView = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:nil];
88
+		RNNCustomTitleView *titleView = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:@"fill"];
87
 		[self.navigationController.navigationBar addSubview:titleView];
89
 		[self.navigationController.navigationBar addSubview:titleView];
88
 	}
90
 	}
89
 }
91
 }
90
 
92
 
93
+- (void)setCustomNavigationComponentBackground {
94
+	if (self.options.topBar.backgroundComponentName) {
95
+		RCTRootView *reactView = (RCTRootView*)[_creator createRootView:self.options.topBar.backgroundComponentName rootViewId:@"navBarBackground"];
96
+		
97
+		RNNCustomTitleView *titleView = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:@"fill"];
98
+		[self.navigationController.navigationBar insertSubview:titleView atIndex:1];
99
+	}
100
+}
101
+
91
 -(BOOL)isCustomTransitioned {
102
 -(BOOL)isCustomTransitioned {
92
 	return self.options.customTransition.animations != nil;
103
 	return self.options.customTransition.animations != nil;
93
 }
104
 }
109
 	return NO;
120
 	return NO;
110
 }
121
 }
111
 
122
 
123
+- (UIStatusBarStyle)preferredStatusBarStyle {
124
+	if (self.options.statusBarStyle && [self.options.statusBarStyle isEqualToString:@"light"]) {
125
+		return UIStatusBarStyleLightContent;
126
+	} else {
127
+		return UIStatusBarStyleDefault;
128
+	}
129
+}
130
+
112
 - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
131
 - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
113
 	return self.options.supportedOrientations;
132
 	return self.options.supportedOrientations;
114
 }
133
 }

+ 13
- 0
lib/ios/RNNTitleOptions.h View File

1
+#import "RNNOptions.h"
2
+
3
+@interface RNNTitleOptions : RNNOptions
4
+
5
+@property (nonatomic, strong) NSString* text;
6
+@property (nonatomic, strong) NSNumber* fontSize;
7
+@property (nonatomic, strong) NSNumber* color;
8
+@property (nonatomic, strong) NSString* fontFamily;
9
+@property (nonatomic, strong) NSString* component;
10
+@property (nonatomic, strong) NSString* componentAlignment;
11
+
12
+
13
+@end

+ 32
- 0
lib/ios/RNNTitleOptions.m View File

1
+#import "RNNTitleOptions.h"
2
+
3
+@implementation RNNTitleOptions
4
+
5
+- (void)applyOn:(UIViewController *)viewController {
6
+	if (self.text) {
7
+		viewController.navigationItem.title = self.text;
8
+	}
9
+	
10
+	if (self.fontFamily || self.fontSize || self.color) {
11
+		NSMutableDictionary* navigationBarTitleTextAttributes = [NSMutableDictionary new];
12
+		if (self.color) {
13
+			navigationBarTitleTextAttributes[NSForegroundColorAttributeName] = [RCTConvert UIColor:[self valueForKey:@"color"]];
14
+		}
15
+		if (self.fontFamily){
16
+			if(self.fontSize) {
17
+				navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont fontWithName:self.fontFamily size:[self.fontSize floatValue]];
18
+			} else {
19
+				navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont fontWithName:self.fontFamily size:20];
20
+			}
21
+		} else if (self.fontSize) {
22
+			navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont systemFontOfSize:[self.fontSize floatValue]];
23
+		}
24
+		viewController.navigationController.navigationBar.titleTextAttributes = navigationBarTitleTextAttributes;
25
+		if (@available(iOS 11.0, *)){
26
+			viewController.navigationController.navigationBar.largeTitleTextAttributes = navigationBarTitleTextAttributes;
27
+		}
28
+		
29
+	}
30
+}
31
+
32
+@end

+ 8
- 6
lib/ios/RNNTopBarOptions.h View File

1
 #import "RNNOptions.h"
1
 #import "RNNOptions.h"
2
+#import "RNNTitleOptions.h"
2
 
3
 
3
 @interface RNNTopBarOptions : RNNOptions
4
 @interface RNNTopBarOptions : RNNOptions
4
 
5
 
5
 @property (nonatomic, strong) NSArray* leftButtons;
6
 @property (nonatomic, strong) NSArray* leftButtons;
6
 @property (nonatomic, strong) NSArray* rightButtons;
7
 @property (nonatomic, strong) NSArray* rightButtons;
7
 @property (nonatomic, strong) NSNumber* backgroundColor;
8
 @property (nonatomic, strong) NSNumber* backgroundColor;
8
-@property (nonatomic, strong) NSNumber* textColor;
9
-@property (nonatomic, strong) NSString* title;
10
-@property (nonatomic, strong) NSString* textFontFamily;
11
 @property (nonatomic, strong) NSNumber* visible;
9
 @property (nonatomic, strong) NSNumber* visible;
12
 @property (nonatomic, strong) NSNumber* hideOnScroll;
10
 @property (nonatomic, strong) NSNumber* hideOnScroll;
13
 @property (nonatomic, strong) NSNumber* buttonColor;
11
 @property (nonatomic, strong) NSNumber* buttonColor;
14
 @property (nonatomic, strong) NSNumber* translucent;
12
 @property (nonatomic, strong) NSNumber* translucent;
15
 @property (nonatomic, strong) NSNumber* transparent;
13
 @property (nonatomic, strong) NSNumber* transparent;
16
 @property (nonatomic, strong) NSNumber* drawBehind;
14
 @property (nonatomic, strong) NSNumber* drawBehind;
17
-@property (nonatomic, strong) NSNumber* textFontSize;
18
 @property (nonatomic, strong) NSNumber* noBorder;
15
 @property (nonatomic, strong) NSNumber* noBorder;
19
 @property (nonatomic, strong) NSNumber* blur;
16
 @property (nonatomic, strong) NSNumber* blur;
20
 @property (nonatomic, strong) NSNumber* animate;
17
 @property (nonatomic, strong) NSNumber* animate;
21
 @property (nonatomic, strong) NSNumber* largeTitle;
18
 @property (nonatomic, strong) NSNumber* largeTitle;
22
 @property (nonatomic, strong) NSString* testID;
19
 @property (nonatomic, strong) NSString* testID;
20
+@property (nonatomic, strong) RNNTitleOptions* title;
21
+@property (nonatomic, strong) NSNumber* backButtonImage;
22
+@property (nonatomic, strong) NSNumber* backButtonHidden;
23
+@property (nonatomic, strong) NSString* backButtonTitle;
24
+@property (nonatomic, strong) NSNumber* hideBackButtonTitle;
23
 
25
 
24
-@property (nonatomic, strong) NSString* customTitleViewName;
25
-@property (nonatomic, strong) NSString* customViewName;
26
+@property (nonatomic, strong) NSString* componentName;
27
+@property (nonatomic, strong) NSString* backgroundComponentName;
26
 
28
 
27
 @end
29
 @end

+ 37
- 28
lib/ios/RNNTopBarOptions.m View File

13
 
13
 
14
 @implementation RNNTopBarOptions
14
 @implementation RNNTopBarOptions
15
 
15
 
16
+- (instancetype)initWithDict:(NSDictionary *)dict {
17
+	self = [super initWithDict:dict];
18
+	self.title = [RNNTitleOptions new];
19
+
20
+	return self;
21
+}
22
+
16
 - (void)applyOn:(UIViewController*)viewController {
23
 - (void)applyOn:(UIViewController*)viewController {
24
+	[self.title applyOn:viewController];
17
 	if (self.backgroundColor) {
25
 	if (self.backgroundColor) {
18
 		UIColor* backgroundColor = [RCTConvert UIColor:self.backgroundColor];
26
 		UIColor* backgroundColor = [RCTConvert UIColor:self.backgroundColor];
19
 		viewController.navigationController.navigationBar.barTintColor = backgroundColor;
27
 		viewController.navigationController.navigationBar.barTintColor = backgroundColor;
20
 	} else {
28
 	} else {
21
 		viewController.navigationController.navigationBar.barTintColor = nil;
29
 		viewController.navigationController.navigationBar.barTintColor = nil;
22
 	}
30
 	}
23
-	
24
-	if (self.title) {
25
-		viewController.navigationItem.title = self.title;
26
-	}
27
-	
31
+
28
 	if (@available(iOS 11.0, *)) {
32
 	if (@available(iOS 11.0, *)) {
29
 		if (self.largeTitle){
33
 		if (self.largeTitle){
30
 			if ([self.largeTitle boolValue]) {
34
 			if ([self.largeTitle boolValue]) {
39
 		}
43
 		}
40
 	}
44
 	}
41
 	
45
 	
42
-	
43
-	if (self.textFontFamily || self.textFontSize || self.textColor) {
44
-		NSMutableDictionary* navigationBarTitleTextAttributes = [NSMutableDictionary new];
45
-		if (self.textColor) {
46
-			navigationBarTitleTextAttributes[NSForegroundColorAttributeName] = [RCTConvert UIColor:[self valueForKey:@"textColor"]];
47
-		}
48
-		if (self.textFontFamily){
49
-			if(self.textFontSize) {
50
-				navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont fontWithName:self.textFontFamily size:[self.textFontSize floatValue]];
51
-			} else {
52
-				navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont fontWithName:self.textFontFamily size:20];
53
-			}
54
-		} else if (self.textFontSize) {
55
-			navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont systemFontOfSize:[self.textFontSize floatValue]];
56
-		}
57
-		viewController.navigationController.navigationBar.titleTextAttributes = navigationBarTitleTextAttributes;
58
-		if (@available(iOS 11.0, *)){
59
-			viewController.navigationController.navigationBar.largeTitleTextAttributes = navigationBarTitleTextAttributes;
60
-		}
61
-		
62
-	}
63
-	
64
-	
65
 	if (self.visible) {
46
 	if (self.visible) {
66
 		[viewController.navigationController setNavigationBarHidden:![self.visible boolValue] animated:[self.animate boolValue]];
47
 		[viewController.navigationController setNavigationBarHidden:![self.visible boolValue] animated:[self.animate boolValue]];
48
+	} else {
49
+		[viewController.navigationController setNavigationBarHidden:NO animated:NO];
67
 	}
50
 	}
68
 	
51
 	
69
 	if (self.hideOnScroll) {
52
 	if (self.hideOnScroll) {
70
 		viewController.navigationController.hidesBarsOnSwipe = [self.hideOnScroll boolValue];
53
 		viewController.navigationController.hidesBarsOnSwipe = [self.hideOnScroll boolValue];
54
+	} else {
55
+		viewController.navigationController.hidesBarsOnSwipe = NO;
71
 	}
56
 	}
72
 	
57
 	
73
 	if (self.buttonColor) {
58
 	if (self.buttonColor) {
128
 	
113
 	
129
 	if (self.translucent) {
114
 	if (self.translucent) {
130
 		viewController.navigationController.navigationBar.translucent = [self.translucent boolValue];
115
 		viewController.navigationController.navigationBar.translucent = [self.translucent boolValue];
116
+	} else {
117
+		viewController.navigationController.navigationBar.translucent = NO;
131
 	}
118
 	}
132
 	
119
 	
133
 	if (self.drawBehind) {
120
 	if (self.drawBehind) {
136
 		} else {
123
 		} else {
137
 			viewController.edgesForExtendedLayout &= ~UIRectEdgeTop;
124
 			viewController.edgesForExtendedLayout &= ~UIRectEdgeTop;
138
 		}
125
 		}
126
+	} else {
127
+		viewController.edgesForExtendedLayout = UIRectEdgeAll;
139
 	}
128
 	}
140
 	
129
 	
141
 	if (self.noBorder) {
130
 	if (self.noBorder) {
156
 		_navigationButtons = [[RNNNavigationButtons alloc] initWithViewController:(RNNRootViewController*)viewController];
145
 		_navigationButtons = [[RNNNavigationButtons alloc] initWithViewController:(RNNRootViewController*)viewController];
157
 		[_navigationButtons applyLeftButtons:self.leftButtons rightButtons:self.rightButtons];
146
 		[_navigationButtons applyLeftButtons:self.leftButtons rightButtons:self.rightButtons];
158
 	}
147
 	}
148
+	
149
+	UIImage *image = self.backButtonImage ? [RCTConvert UIImage:self.backButtonImage] : nil;
150
+	[[UINavigationBar appearance] setBackIndicatorImage:image];
151
+	[[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:image];
152
+	
153
+	if (self.hideBackButtonTitle) {
154
+		self.backButtonTitle = @"";
155
+	}
156
+	
157
+	if (self.backButtonTitle) {
158
+		UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:self.backButtonTitle
159
+																	 style:UIBarButtonItemStylePlain
160
+																	target:nil
161
+																	action:nil];
162
+		
163
+		viewController.navigationItem.backBarButtonItem = backItem;
164
+	}
165
+	
166
+	viewController.navigationItem.hidesBackButton = [self.backButtonHidden boolValue];
167
+	
159
 }
168
 }
160
 
169
 
161
 -(void)storeOriginalTopBarImages:(UIViewController*)viewController {
170
 -(void)storeOriginalTopBarImages:(UIViewController*)viewController {

+ 8
- 0
lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj View File

77
 		504AFE751FFFF0540076E904 /* RNNTopTabsOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 504AFE731FFFF0540076E904 /* RNNTopTabsOptions.m */; };
77
 		504AFE751FFFF0540076E904 /* RNNTopTabsOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 504AFE731FFFF0540076E904 /* RNNTopTabsOptions.m */; };
78
 		504AFE761FFFF1E00076E904 /* RNNNavigationOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = E83BAD691F27362500A9F3DD /* RNNNavigationOptions.h */; };
78
 		504AFE761FFFF1E00076E904 /* RNNNavigationOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = E83BAD691F27362500A9F3DD /* RNNNavigationOptions.h */; };
79
 		504AFE771FFFF1E20076E904 /* RNNTopBarOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */; };
79
 		504AFE771FFFF1E20076E904 /* RNNTopBarOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */; };
80
+		50570B262061473D006A1B5C /* RNNTitleOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50570B242061473D006A1B5C /* RNNTitleOptions.h */; };
81
+		50570B272061473D006A1B5C /* RNNTitleOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50570B252061473D006A1B5C /* RNNTitleOptions.m */; };
80
 		50762D08205E96C200E3D18A /* RNNModalAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 50762D06205E96C200E3D18A /* RNNModalAnimation.h */; };
82
 		50762D08205E96C200E3D18A /* RNNModalAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 50762D06205E96C200E3D18A /* RNNModalAnimation.h */; };
81
 		50762D09205E96C200E3D18A /* RNNModalAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 50762D07205E96C200E3D18A /* RNNModalAnimation.m */; };
83
 		50762D09205E96C200E3D18A /* RNNModalAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 50762D07205E96C200E3D18A /* RNNModalAnimation.m */; };
82
 		507E7D57201DDD3000444E6C /* RNNAnimationOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 507E7D55201DDD3000444E6C /* RNNAnimationOptions.h */; };
84
 		507E7D57201DDD3000444E6C /* RNNAnimationOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 507E7D55201DDD3000444E6C /* RNNAnimationOptions.h */; };
260
 		504AFE631FFE53070076E904 /* RNNOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNOptions.m; sourceTree = "<group>"; };
262
 		504AFE631FFE53070076E904 /* RNNOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNOptions.m; sourceTree = "<group>"; };
261
 		504AFE721FFFF0540076E904 /* RNNTopTabsOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTopTabsOptions.h; sourceTree = "<group>"; };
263
 		504AFE721FFFF0540076E904 /* RNNTopTabsOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTopTabsOptions.h; sourceTree = "<group>"; };
262
 		504AFE731FFFF0540076E904 /* RNNTopTabsOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTopTabsOptions.m; sourceTree = "<group>"; };
264
 		504AFE731FFFF0540076E904 /* RNNTopTabsOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTopTabsOptions.m; sourceTree = "<group>"; };
265
+		50570B242061473D006A1B5C /* RNNTitleOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTitleOptions.h; sourceTree = "<group>"; };
266
+		50570B252061473D006A1B5C /* RNNTitleOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTitleOptions.m; sourceTree = "<group>"; };
263
 		50762D06205E96C200E3D18A /* RNNModalAnimation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNModalAnimation.h; sourceTree = "<group>"; };
267
 		50762D06205E96C200E3D18A /* RNNModalAnimation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNModalAnimation.h; sourceTree = "<group>"; };
264
 		50762D07205E96C200E3D18A /* RNNModalAnimation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNModalAnimation.m; sourceTree = "<group>"; };
268
 		50762D07205E96C200E3D18A /* RNNModalAnimation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNModalAnimation.m; sourceTree = "<group>"; };
265
 		507E7D55201DDD3000444E6C /* RNNAnimationOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNAnimationOptions.h; sourceTree = "<group>"; };
269
 		507E7D55201DDD3000444E6C /* RNNAnimationOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNAnimationOptions.h; sourceTree = "<group>"; };
477
 				E83BAD6A1F27363A00A9F3DD /* RNNNavigationOptions.m */,
481
 				E83BAD6A1F27363A00A9F3DD /* RNNNavigationOptions.m */,
478
 				A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */,
482
 				A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */,
479
 				A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */,
483
 				A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */,
484
+				50570B242061473D006A1B5C /* RNNTitleOptions.h */,
485
+				50570B252061473D006A1B5C /* RNNTitleOptions.m */,
480
 				A7626BFF1FC578AB00492FB8 /* RNNBottomTabsOptions.h */,
486
 				A7626BFF1FC578AB00492FB8 /* RNNBottomTabsOptions.h */,
481
 				A7626C001FC5796200492FB8 /* RNNBottomTabsOptions.m */,
487
 				A7626C001FC5796200492FB8 /* RNNBottomTabsOptions.m */,
482
 				50EB933F1FE14A3E00BD8EEE /* RNNBottomTabOptions.h */,
488
 				50EB933F1FE14A3E00BD8EEE /* RNNBottomTabOptions.h */,
754
 				263905B31E4C6F440023D7D3 /* MMDrawerVisualState.h in Headers */,
760
 				263905B31E4C6F440023D7D3 /* MMDrawerVisualState.h in Headers */,
755
 				50451D092042E20600695F00 /* RNNTransitionsOptions.h in Headers */,
761
 				50451D092042E20600695F00 /* RNNTransitionsOptions.h in Headers */,
756
 				E8A5CD621F49114F00E89D0D /* RNNElement.h in Headers */,
762
 				E8A5CD621F49114F00E89D0D /* RNNElement.h in Headers */,
763
+				50570B262061473D006A1B5C /* RNNTitleOptions.h in Headers */,
757
 				504AFE741FFFF0540076E904 /* RNNTopTabsOptions.h in Headers */,
764
 				504AFE741FFFF0540076E904 /* RNNTopTabsOptions.h in Headers */,
758
 				E8E5182E1F83A48B000467AC /* RNNTransitionStateHolder.h in Headers */,
765
 				E8E5182E1F83A48B000467AC /* RNNTransitionStateHolder.h in Headers */,
759
 				507E7D57201DDD3000444E6C /* RNNAnimationOptions.h in Headers */,
766
 				507E7D57201DDD3000444E6C /* RNNAnimationOptions.h in Headers */,
888
 				261F0E6B1E6F028A00989DE2 /* RNNNavigationStackManager.m in Sources */,
895
 				261F0E6B1E6F028A00989DE2 /* RNNNavigationStackManager.m in Sources */,
889
 				5016E8F020209690009D4F7C /* RNNCustomTitleView.m in Sources */,
896
 				5016E8F020209690009D4F7C /* RNNCustomTitleView.m in Sources */,
890
 				E8DA24411F97459B00CD552B /* RNNElementFinder.m in Sources */,
897
 				E8DA24411F97459B00CD552B /* RNNElementFinder.m in Sources */,
898
+				50570B272061473D006A1B5C /* RNNTitleOptions.m in Sources */,
891
 				263905BF1E4C6F440023D7D3 /* RCCTheSideBarManagerViewController.m in Sources */,
899
 				263905BF1E4C6F440023D7D3 /* RCCTheSideBarManagerViewController.m in Sources */,
892
 				7B1126A01E2D263F00F9B03B /* RNNEventEmitter.m in Sources */,
900
 				7B1126A01E2D263F00F9B03B /* RNNEventEmitter.m in Sources */,
893
 				A7626BFD1FC2FB2C00492FB8 /* RNNTopBarOptions.m in Sources */,
901
 				A7626BFD1FC2FB2C00492FB8 /* RNNTopBarOptions.m in Sources */,

+ 1
- 1
lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m View File

63
 
63
 
64
 -(void)testDynamicStylesMergeWithStaticStyles {
64
 -(void)testDynamicStylesMergeWithStaticStyles {
65
 	RNNNavigationOptions* initialOptions = [[RNNNavigationOptions alloc] init];
65
 	RNNNavigationOptions* initialOptions = [[RNNNavigationOptions alloc] init];
66
-	[initialOptions.topBar setTitle:@"the title"];
66
+	initialOptions.topBar.title.text = @"the title";
67
 	RNNRootViewController* vc = [[RNNRootViewController alloc] initWithName:@"name"
67
 	RNNRootViewController* vc = [[RNNRootViewController alloc] initWithName:@"name"
68
 																withOptions:initialOptions
68
 																withOptions:initialOptions
69
 															withComponentId:@"componentId"
69
 															withComponentId:@"componentId"

+ 2
- 2
lib/ios/ReactNativeNavigationTests/RNNNavigationOptionsTest.m View File

22
 
22
 
23
 - (void)testChangeRNNNavigationOptionsDynamically {
23
 - (void)testChangeRNNNavigationOptionsDynamically {
24
 	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:@{@"topBar": @{@"backgroundColor" : @(0xff0000ff)}}];
24
 	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:@{@"topBar": @{@"backgroundColor" : @(0xff0000ff)}}];
25
-	NSDictionary* dynamicOptions = @{@"topBar": @{@"textColor" : @(0xffff00ff), @"title" : @"hello"}};
25
+	NSDictionary* dynamicOptions = @{@"topBar": @{@"textColor" : @(0xffff00ff), @"title" : @{@"text": @"hello"}}};
26
 	[options mergeWith:dynamicOptions];
26
 	[options mergeWith:dynamicOptions];
27
-	XCTAssertTrue([options.topBar.title isEqual:@"hello"]);
27
+	XCTAssertTrue([options.topBar.title.text isEqual:@"hello"]);
28
 }
28
 }
29
 
29
 
30
 - (void)testChangeRNNNavigationOptionsWithInvalidProperties {
30
 - (void)testChangeRNNNavigationOptionsWithInvalidProperties {

+ 12
- 12
lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m View File

106
 
106
 
107
 -(void)testTitle_string{
107
 -(void)testTitle_string{
108
 	NSString* title =@"some title";
108
 	NSString* title =@"some title";
109
-	self.options.topBar.title = title;
109
+	self.options.topBar.title.text = title;
110
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
110
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
111
 	
111
 	
112
 	[self.uut viewWillAppear:false];
112
 	[self.uut viewWillAppear:false];
122
 
122
 
123
 -(void)testTopBarTextColor_validColor{
123
 -(void)testTopBarTextColor_validColor{
124
 	NSNumber* inputColor = @(0xFFFF0000);
124
 	NSNumber* inputColor = @(0xFFFF0000);
125
-	self.options.topBar.textColor = inputColor;
125
+	self.options.topBar.title.color = inputColor;
126
 	__unused UINavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
126
 	__unused UINavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
127
 	[self.uut viewWillAppear:false];
127
 	[self.uut viewWillAppear:false];
128
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
128
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
156
 -(void)testTopBarTextFontFamily_validFont{
156
 -(void)testTopBarTextFontFamily_validFont{
157
 	NSString* inputFont = @"HelveticaNeue";
157
 	NSString* inputFont = @"HelveticaNeue";
158
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
158
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
159
-	self.options.topBar.textFontFamily = inputFont;
159
+	self.options.topBar.title.fontFamily = inputFont;
160
 	[self.uut viewWillAppear:false];
160
 	[self.uut viewWillAppear:false];
161
 	UIFont* expectedFont = [UIFont fontWithName:inputFont size:20];
161
 	UIFont* expectedFont = [UIFont fontWithName:inputFont size:20];
162
 	XCTAssertTrue([self.uut.navigationController.navigationBar.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
162
 	XCTAssertTrue([self.uut.navigationController.navigationBar.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
227
 
227
 
228
 -(void)testTopBarTextFontSize_withoutTextFontFamily_withoutTextColor {
228
 -(void)testTopBarTextFontSize_withoutTextFontFamily_withoutTextColor {
229
 	NSNumber* topBarTextFontSizeInput = @(15);
229
 	NSNumber* topBarTextFontSizeInput = @(15);
230
-	self.options.topBar.textFontSize = topBarTextFontSizeInput;
230
+	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
231
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
231
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
232
 	[self.uut viewWillAppear:false];
232
 	[self.uut viewWillAppear:false];
233
 	UIFont* expectedFont = [UIFont systemFontOfSize:15];
233
 	UIFont* expectedFont = [UIFont systemFontOfSize:15];
237
 -(void)testTopBarTextFontSize_withoutTextFontFamily_withTextColor {
237
 -(void)testTopBarTextFontSize_withoutTextFontFamily_withTextColor {
238
 	NSNumber* topBarTextFontSizeInput = @(15);
238
 	NSNumber* topBarTextFontSizeInput = @(15);
239
 	NSNumber* inputColor = @(0xFFFF0000);
239
 	NSNumber* inputColor = @(0xFFFF0000);
240
-	self.options.topBar.textFontSize = topBarTextFontSizeInput;
241
-	self.options.topBar.textColor = inputColor;
240
+	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
241
+	self.options.topBar.title.color = inputColor;
242
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
242
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
243
 	[self.uut viewWillAppear:false];
243
 	[self.uut viewWillAppear:false];
244
 	UIFont* expectedFont = [UIFont systemFontOfSize:15];
244
 	UIFont* expectedFont = [UIFont systemFontOfSize:15];
251
 	NSNumber* topBarTextFontSizeInput = @(15);
251
 	NSNumber* topBarTextFontSizeInput = @(15);
252
 	NSNumber* inputColor = @(0xFFFF0000);
252
 	NSNumber* inputColor = @(0xFFFF0000);
253
 	NSString* inputFont = @"HelveticaNeue";
253
 	NSString* inputFont = @"HelveticaNeue";
254
-	self.options.topBar.textFontSize = topBarTextFontSizeInput;
255
-	self.options.topBar.textColor = inputColor;
256
-	self.options.topBar.textFontFamily = inputFont;
254
+	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
255
+	self.options.topBar.title.color = inputColor;
256
+	self.options.topBar.title.fontFamily = inputFont;
257
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
257
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
258
 	[self.uut viewWillAppear:false];
258
 	[self.uut viewWillAppear:false];
259
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
259
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
265
 -(void)testTopBarTextFontSize_withTextFontFamily_withoutTextColor {
265
 -(void)testTopBarTextFontSize_withTextFontFamily_withoutTextColor {
266
 	NSNumber* topBarTextFontSizeInput = @(15);
266
 	NSNumber* topBarTextFontSizeInput = @(15);
267
 	NSString* inputFont = @"HelveticaNeue";
267
 	NSString* inputFont = @"HelveticaNeue";
268
-	self.options.topBar.textFontSize = topBarTextFontSizeInput;
269
-	self.options.topBar.textFontFamily = inputFont;
268
+	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
269
+	self.options.topBar.title.fontFamily = inputFont;
270
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
270
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
271
 	[self.uut viewWillAppear:false];
271
 	[self.uut viewWillAppear:false];
272
 	UIFont* expectedFont = [UIFont fontWithName:inputFont size:15];
272
 	UIFont* expectedFont = [UIFont fontWithName:inputFont size:15];
277
 -(void)testTopBarTextFontFamily_invalidFont{
277
 -(void)testTopBarTextFontFamily_invalidFont{
278
 	NSString* inputFont = @"HelveticaNeueeeee";
278
 	NSString* inputFont = @"HelveticaNeueeeee";
279
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
279
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
280
-	self.options.topBar.textFontFamily = inputFont;
280
+	self.options.topBar.title.fontFamily = inputFont;
281
 	//	XCTAssertThrows([self.uut viewWillAppear:false]);
281
 	//	XCTAssertThrows([self.uut viewWillAppear:false]);
282
 }
282
 }
283
 
283
 

+ 4
- 2
lib/src/commands/LayoutTreeParser.test.ts View File

124
       expect(result.children[1].children[0].children[2].children[0].type).toEqual('TopTabs');
124
       expect(result.children[1].children[0].children[2].children[0].type).toEqual('TopTabs');
125
       expect(result.children[1].children[0].children[2].children[0].children[2].type).toEqual('TopTabs');
125
       expect(result.children[1].children[0].children[2].children[0].children[2].type).toEqual('TopTabs');
126
       expect(result.children[1].children[0].children[2].children[0].children[2].children[4].type).toEqual('Stack');
126
       expect(result.children[1].children[0].children[2].children[0].children[2].children[4].type).toEqual('Stack');
127
-      expect(result.children[1].children[0].children[2].children[0].children[2].data).toEqual({ options: { topBar: { title: 'Hello1' } } });
127
+      expect(result.children[1].children[0].children[2].children[0].children[2].data).toEqual({ options: { topBar: { title: { text: 'Hello1'} } } });
128
     });
128
     });
129
   });
129
   });
130
 
130
 
163
 
163
 
164
 const options = {
164
 const options = {
165
   topBar: {
165
   topBar: {
166
-    title: 'Hello1'
166
+    title: {
167
+      text: 'Hello1'
168
+    }
167
   }
169
   }
168
 };
170
 };
169
 
171
 

+ 3
- 1
playground/src/screens/BackHandlerModalScreen.js View File

7
   static get options() {
7
   static get options() {
8
     return {
8
     return {
9
       topBar: {
9
       topBar: {
10
-        title: 'Back Handler'
10
+        title: {
11
+          text: 'Back Handler'
12
+        }
11
       }
13
       }
12
     };
14
     };
13
   }
15
   }

+ 5
- 3
playground/src/screens/BackHandlerScreen.js View File

7
   static get options() {
7
   static get options() {
8
     return {
8
     return {
9
       topBar: {
9
       topBar: {
10
-        title: 'Back Handler',
11
-        textColor: 'black',
12
-        textFontSize: 16
10
+        title: {
11
+          text: 'Back Handler',
12
+          color: 'black',
13
+          fontSize: 16
14
+        }
13
       }
15
       }
14
     };
16
     };
15
   }
17
   }

+ 4
- 8
playground/src/screens/CustomTopBar.js View File

19
   render() {
19
   render() {
20
     return (
20
     return (
21
       <View style={styles.container}>
21
       <View style={styles.container}>
22
-        <TouchableOpacity stye={styles.button} onPress={() => Alert.alert(this.props.title, 'Thanks for that :)')}>
22
+        <TouchableOpacity onPress={() => Alert.alert(this.props.title, 'Thanks for that :)')}>
23
           <Text style={styles.text}>Press Me</Text>
23
           <Text style={styles.text}>Press Me</Text>
24
         </TouchableOpacity>
24
         </TouchableOpacity>
25
       </View>
25
       </View>
32
 const styles = StyleSheet.create({
32
 const styles = StyleSheet.create({
33
   container: {
33
   container: {
34
     flex: 1,
34
     flex: 1,
35
+    flexDirection: 'column',
35
     justifyContent: 'center',
36
     justifyContent: 'center',
36
-    alignItems: 'center',
37
-    backgroundColor: 'white'
38
-  },
39
-  button: {
40
-    alignSelf: 'center',
41
-    backgroundColor: 'green'
37
+    alignSelf: 'center'
42
   },
38
   },
43
   text: {
39
   text: {
44
     alignSelf: 'center',
40
     alignSelf: 'center',
45
-    color: Platform.OS === 'ios' ? 'black' : 'white'
41
+    color: 'black',
46
   }
42
   }
47
 });
43
 });

+ 4
- 2
playground/src/screens/CustomTransitionDestination.js View File

14
     return {
14
     return {
15
       backButtonTransition: 'custom',
15
       backButtonTransition: 'custom',
16
       topBar: {
16
       topBar: {
17
-        title: 'ye babyyyyyy',
18
-        textFontFamily: 'HelveticaNeue-Italic',
17
+        title: {
18
+          text: 'ye babyyyyyy',
19
+          fontFamily: 'HelveticaNeue-Italic'
20
+        },
19
         largeTitle: true
21
         largeTitle: true
20
       }
22
       }
21
     };
23
     };

+ 4
- 2
playground/src/screens/CustomTransitionOrigin.js View File

11
   static get options() {
11
   static get options() {
12
     return {
12
     return {
13
       topBar: {
13
       topBar: {
14
-        textFontFamily: 'HelveticaNeue-Italic',
15
-        textFontSize: 16,
14
+        title: {
15
+          fontFamily: 'HelveticaNeue-Italic',
16
+          fontSize: 16
17
+        },
16
         largeTitle: false,
18
         largeTitle: false,
17
         translucent: true
19
         translucent: true
18
       }
20
       }

+ 33
- 18
playground/src/screens/OptionsScreen.js View File

17
   static get options() {
17
   static get options() {
18
     return {
18
     return {
19
       topBar: {
19
       topBar: {
20
-        title: 'Static Title',
21
-        textColor: 'black',
20
+        title: {
21
+          text: 'Static Title',
22
+          color: 'black',
23
+          fontSize: 16,
24
+          fontFamily: 'HelveticaNeue-Italic',
25
+          largeTitle: false
26
+        },
22
         ...Platform.select({
27
         ...Platform.select({
23
           android: { drawBehind: true },
28
           android: { drawBehind: true },
24
           ios: { drawBehind: false, }
29
           ios: { drawBehind: false, }
25
         }),
30
         }),
26
-        largeTitle: false,
27
         visible: true,
31
         visible: true,
28
-        textFontSize: 16,
29
-        textFontFamily: 'HelveticaNeue-Italic',
30
         testID: testIDs.TOP_BAR_ELEMENT,
32
         testID: testIDs.TOP_BAR_ELEMENT,
31
         rightButtons: [
33
         rightButtons: [
32
-          {
33
-            id: CUSTOM_BUTTON,
34
-            testID: CUSTOM_BUTTON,
35
-            component: 'CustomTextButton'
36
-          },
34
+          // {
35
+          //   id: CUSTOM_BUTTON,
36
+          //   testID: CUSTOM_BUTTON,
37
+          //   component: 'CustomTextButton'
38
+          // },
37
           {
39
           {
38
             id: CUSTOM_BUTTON2,
40
             id: CUSTOM_BUTTON2,
39
             testID: CUSTOM_BUTTON2,
41
             testID: CUSTOM_BUTTON2,
97
   render() {
99
   render() {
98
     return (
100
     return (
99
       <View style={styles.root}>
101
       <View style={styles.root}>
102
+        <View style={{width: 2, height: 2, backgroundColor: 'red', alignSelf: 'center'}}/>
100
         <Text style={styles.h1} testID={testIDs.OPTIONS_SCREEN_HEADER}>{`Options Screen`}</Text>
103
         <Text style={styles.h1} testID={testIDs.OPTIONS_SCREEN_HEADER}>{`Options Screen`}</Text>
101
         <Button title='Dynamic Options' testID={testIDs.DYNAMIC_OPTIONS_BUTTON} onPress={this.onClickDynamicOptions} />
104
         <Button title='Dynamic Options' testID={testIDs.DYNAMIC_OPTIONS_BUTTON} onPress={this.onClickDynamicOptions} />
102
         <Button title='Show Top Bar' testID={testIDs.SHOW_TOP_BAR_BUTTON} onPress={this.onClickShowTopBar} />
105
         <Button title='Show Top Bar' testID={testIDs.SHOW_TOP_BAR_BUTTON} onPress={this.onClickShowTopBar} />
105
         <Button title='Top Bar Opaque' onPress={this.onClickTopBarOpaque} />
108
         <Button title='Top Bar Opaque' onPress={this.onClickTopBarOpaque} />
106
         <Button title='scrollView Screen' testID={testIDs.SCROLLVIEW_SCREEN_BUTTON} onPress={this.onClickScrollViewScreen} />
109
         <Button title='scrollView Screen' testID={testIDs.SCROLLVIEW_SCREEN_BUTTON} onPress={this.onClickScrollViewScreen} />
107
         <Button title='Custom Transition' testID={testIDs.CUSTOM_TRANSITION_BUTTON} onPress={this.onClickCustomTranstition} />
110
         <Button title='Custom Transition' testID={testIDs.CUSTOM_TRANSITION_BUTTON} onPress={this.onClickCustomTranstition} />
108
-        {Platform.OS === 'android' ?
109
-          <Button title='Hide fab' testID={testIDs.HIDE_FAB} onPress={this.onClickFab} />
110
-          : null}
111
+        {Platform.OS === 'android' ? <Button title='Hide fab' testID={testIDs.HIDE_FAB} onPress={this.onClickFab} /> : null}
111
         <Button title='Show overlay' testID={testIDs.SHOW_OVERLAY_BUTTON} onPress={() => this.onClickShowOverlay(true)} />
112
         <Button title='Show overlay' testID={testIDs.SHOW_OVERLAY_BUTTON} onPress={() => this.onClickShowOverlay(true)} />
112
         <Button title='Show touch through overlay' testID={testIDs.SHOW_TOUCH_THROUGH_OVERLAY_BUTTON} onPress={() => this.onClickShowOverlay(false)} />
113
         <Button title='Show touch through overlay' testID={testIDs.SHOW_TOUCH_THROUGH_OVERLAY_BUTTON} onPress={() => this.onClickShowOverlay(false)} />
113
         <Button title='Push Default Options Screen' testID={testIDs.PUSH_DEFAULT_OPTIONS_BUTTON} onPress={this.onClickPushDefaultOptionsScreen} />
114
         <Button title='Push Default Options Screen' testID={testIDs.PUSH_DEFAULT_OPTIONS_BUTTON} onPress={this.onClickPushDefaultOptionsScreen} />
115
+        <Button title='Show TopBar react view' testID={testIDs.SHOW_TOPBAR_REACT_VIEW} onPress={this.onShowTopBarReactView} />
114
         <Text style={styles.footer}>{`this.props.containerId = ${this.props.containerId}`}</Text>
116
         <Text style={styles.footer}>{`this.props.containerId = ${this.props.containerId}`}</Text>
115
       </View>
117
       </View>
116
     );
118
     );
161
   onClickDynamicOptions() {
163
   onClickDynamicOptions() {
162
     Navigation.setOptions(this.props.componentId, {
164
     Navigation.setOptions(this.props.componentId, {
163
       topBar: {
165
       topBar: {
164
-        title: 'Dynamic Title',
165
-        textColor: '#00FFFF',
166
-        largeTitle: false,
166
+        title: {
167
+          text: 'Dynamic Title',
168
+          color: '#00FFFF',
169
+          largeTitle: false,
170
+          fontSize: 20,
171
+          fontFamily: 'HelveticaNeue-CondensedBold'
172
+        },
167
         buttonColor: 'red',
173
         buttonColor: 'red',
168
-        textFontSize: 20,
169
-        textFontFamily: 'HelveticaNeue-CondensedBold'
170
       }
174
       }
171
     });
175
     });
172
   }
176
   }
256
       }
260
       }
257
     });
261
     });
258
   }
262
   }
263
+
264
+  onShowTopBarReactView = () => {
265
+    Navigation.setOptions(this.props.componentId, {
266
+      topBar: {
267
+        title: {
268
+          component: 'navigation.playground.CustomTopBar',
269
+          alignment: 'center'
270
+        }
271
+      }
272
+    });
273
+  }
259
 }
274
 }
260
 
275
 
261
 const styles = {
276
 const styles = {

+ 3
- 1
playground/src/screens/PushedScreen.js View File

52
         },
52
         },
53
         options: {
53
         options: {
54
           topBar: {
54
           topBar: {
55
-            title: `Pushed ${this.getStackPosition() + 1}`
55
+            title: {
56
+              text: `Pushed ${this.getStackPosition() + 1}`
57
+            }
56
           }
58
           }
57
         }
59
         }
58
       }
60
       }

+ 5
- 3
playground/src/screens/ScrollViewScreen.js View File

12
   static get options() {
12
   static get options() {
13
     return {
13
     return {
14
       topBar: {
14
       topBar: {
15
-        title: 'Collapse',
15
+        title: {
16
+          text: 'Collapse',
17
+          color: 'black',
18
+          fontSize: 16
19
+        },
16
         drawBehind: true,
20
         drawBehind: true,
17
-        textColor: 'black',
18
-        textFontSize: 16,
19
         visible: true,
21
         visible: true,
20
         testID: testIDs.TOP_BAR_ELEMENT
22
         testID: testIDs.TOP_BAR_ELEMENT
21
       },
23
       },

+ 11
- 7
playground/src/screens/TopTabOptionsScreen.js View File

8
   static get options() {
8
   static get options() {
9
     return {
9
     return {
10
       topBar: {
10
       topBar: {
11
-        textColor: 'black',
12
-        textFontSize: 16,
13
-        textFontFamily: 'HelveticaNeue-Italic'
11
+        title: {
12
+          color: 'black',
13
+          fontSize: 16,
14
+          fontFamily: 'HelveticaNeue-Italic'
15
+        }
14
       }
16
       }
15
     };
17
     };
16
   }
18
   }
33
   onClickDynamicOptions() {
35
   onClickDynamicOptions() {
34
     Navigation.setOptions(this.props.componentId, {
36
     Navigation.setOptions(this.props.componentId, {
35
       topBar: {
37
       topBar: {
36
-        title: 'Dynamic Title',
37
-        textColor: '#00FFFF',
38
+        title: {
39
+          text: 'Dynamic Title',
40
+          color: '#00FFFF',
41
+          fontSize: 16,
42
+          fontFamily: 'HelveticaNeue-CondensedBold'
43
+        },
38
         largeTitle: false,
44
         largeTitle: false,
39
         buttonColor: 'red',
45
         buttonColor: 'red',
40
-        textFontSize: 20,
41
-        textFontFamily: 'HelveticaNeue-CondensedBold'
42
       }
46
       }
43
     });
47
     });
44
   }
48
   }

+ 5
- 3
playground/src/screens/TopTabScreen.js View File

8
   static get options() {
8
   static get options() {
9
     return {
9
     return {
10
       topBar: {
10
       topBar: {
11
-        textColor: 'black',
12
-        textFontSize: 16,
13
-        textFontFamily: 'HelveticaNeue-Italic'
11
+        title: {
12
+          color: 'black',
13
+          fontSize: 16,
14
+          fontFamily: 'HelveticaNeue-Italic'
15
+        }
14
       },
16
       },
15
       fab: {
17
       fab: {
16
         id: FAB,
18
         id: FAB,

+ 28
- 9
playground/src/screens/WelcomeScreen.js View File

10
   static get options() {
10
   static get options() {
11
     return {
11
     return {
12
       topBar: {
12
       topBar: {
13
-        largeTitle: false,
13
+        title: {
14
+          largeTitle: false,
15
+          title: 'My Screen'
16
+        },
14
         drawBehind: true,
17
         drawBehind: true,
15
         visible: false,
18
         visible: false,
16
         animate: false
19
         animate: false
57
                     options: {
60
                     options: {
58
                       topBar: {
61
                       topBar: {
59
                         visible: true,
62
                         visible: true,
60
-                        title: 'React Native Navigation!'
63
+                        title: {
64
+                          text: 'React Native Navigation!'
65
+                        }
61
                       }
66
                       }
62
                     }
67
                     }
63
                   }
68
                   }
216
         name: 'navigation.playground.PushedScreen',
221
         name: 'navigation.playground.PushedScreen',
217
         options: {
222
         options: {
218
           topBar: {
223
           topBar: {
219
-            title: 'pushed'
224
+            title: {
225
+              text: 'pushed'
226
+            }
220
           }
227
           }
221
         }
228
         }
222
       }
229
       }
232
         },
239
         },
233
         options: {
240
         options: {
234
           topBar: {
241
           topBar: {
235
-            title: 'pushed',
242
+            title: {
243
+              text: 'pushed'
244
+            },
236
             visible: true,
245
             visible: true,
237
             testID: testIDs.TOP_BAR_ELEMENT
246
             testID: testIDs.TOP_BAR_ELEMENT
238
           }
247
           }
299
               },
308
               },
300
               options: {
309
               options: {
301
                 topTab: {
310
                 topTab: {
302
-                  title: 'Tab 1'
311
+                  title: {
312
+                    text: 'Tab 1'
313
+                  }
303
                 },
314
                 },
304
                 topBar: {
315
                 topBar: {
305
-                  title: 'One'
316
+                  title: {
317
+                    text: 'One'
318
+                  }
306
                 }
319
                 }
307
               }
320
               }
308
             }
321
             }
320
                   titleFontFamily: 'HelveticaNeue-Italic'
333
                   titleFontFamily: 'HelveticaNeue-Italic'
321
                 },
334
                 },
322
                 topBar: {
335
                 topBar: {
323
-                  title: 'Two'
336
+                  title: {
337
+                    text: 'Two'
338
+                  }
324
                 }
339
                 }
325
               }
340
               }
326
             }
341
             }
337
                   title: 'Tab 3'
352
                   title: 'Tab 3'
338
                 },
353
                 },
339
                 topBar: {
354
                 topBar: {
340
-                  title: 'Three'
355
+                  title: {
356
+                    text: 'Three'
357
+                  }
341
                 }
358
                 }
342
               }
359
               }
343
             }
360
             }
385
     });
402
     });
386
     Navigation.setOptions('my unique id', {
403
     Navigation.setOptions('my unique id', {
387
       topBar: {
404
       topBar: {
388
-        title: 'User provided id'
405
+        title: {
406
+          text: 'User provided id'
407
+        }
389
       }
408
       }
390
     });
409
     });
391
   }
410
   }

+ 1
- 0
playground/src/testIDs.js View File

9
   PUSH_BUTTON: `PUSH_BUTTON`,
9
   PUSH_BUTTON: `PUSH_BUTTON`,
10
   PUSH_OPTIONS_BUTTON: `PUSH_OPTIONS_BUTTON`,
10
   PUSH_OPTIONS_BUTTON: `PUSH_OPTIONS_BUTTON`,
11
   PUSH_DEFAULT_OPTIONS_BUTTON: `PUSH_DEFAULT_OPTIONS_BUTTON`,
11
   PUSH_DEFAULT_OPTIONS_BUTTON: `PUSH_DEFAULT_OPTIONS_BUTTON`,
12
+  SHOW_TOPBAR_REACT_VIEW: `SHOW_TOPBAR_REACT_VIEW`,
12
   BACK_HANDLER_BUTTON: `BACK_HANDLER_BUTTON`,
13
   BACK_HANDLER_BUTTON: `BACK_HANDLER_BUTTON`,
13
   SHOW_MODAL_BUTTON: `SHOW_MODAL_BUTTON`,
14
   SHOW_MODAL_BUTTON: `SHOW_MODAL_BUTTON`,
14
   SHOW_REDBOX_BUTTON: `SHOW_REDBOX_BUTTON`,
15
   SHOW_REDBOX_BUTTON: `SHOW_REDBOX_BUTTON`,