Browse Source

MergeOptions only applies passed options

Previously, all options were cleared and reapplied whenever mergeOptions was called
Guy Carmeli 6 years ago
parent
commit
eaabff943b
22 changed files with 419 additions and 47 deletions
  1. 10
    0
      lib/android/app/src/main/java/com/reactnativenavigation/anim/NavigationAnimator.java
  2. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/AnimationsOptions.java
  3. 4
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/FabOptions.java
  4. 10
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/Options.java
  5. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/OrientationOptions.java
  6. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TitleOptions.java
  7. 58
    1
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java
  8. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java
  9. 4
    3
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java
  10. 27
    4
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java
  11. 4
    5
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TitleBarReactViewController.java
  12. 0
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java
  13. 11
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java
  14. 3
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentLayout.java
  15. 4
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/StackLayout.java
  16. 6
    2
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java
  17. 0
    2
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsStyleHelper.java
  18. 7
    7
      lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBar.java
  19. 155
    0
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsMergingTest.java
  20. 85
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java
  21. 24
    12
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TitleBarTest.java
  22. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/views/TopBarTest.java

+ 10
- 0
lib/android/app/src/main/java/com/reactnativenavigation/anim/NavigationAnimator.java View File

7
 import android.support.annotation.Nullable;
7
 import android.support.annotation.Nullable;
8
 import android.view.View;
8
 import android.view.View;
9
 
9
 
10
+import com.reactnativenavigation.parse.AnimationsOptions;
11
+
10
 @SuppressWarnings("ResourceType")
12
 @SuppressWarnings("ResourceType")
11
 public class NavigationAnimator extends BaseAnimator {
13
 public class NavigationAnimator extends BaseAnimator {
12
 
14
 
55
         });
57
         });
56
         set.start();
58
         set.start();
57
     }
59
     }
60
+
61
+    public void setOptions(AnimationsOptions options) {
62
+        this.options = options;
63
+    }
64
+
65
+    public void mergeOptions(AnimationsOptions options) {
66
+        this.options.mergeWith(options);
67
+    }
58
 }
68
 }

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

26
     public AnimationOptions showModal = new AnimationOptions();
26
     public AnimationOptions showModal = new AnimationOptions();
27
     public AnimationOptions dismissModal = new AnimationOptions();
27
     public AnimationOptions dismissModal = new AnimationOptions();
28
 
28
 
29
-    void mergeWith(AnimationsOptions other) {
29
+    public void mergeWith(AnimationsOptions other) {
30
         push.mergeWith(other.push);
30
         push.mergeWith(other.push);
31
         pop.mergeWith(other.pop);
31
         pop.mergeWith(other.pop);
32
         startApp.mergeWith(other.startApp);
32
         startApp.mergeWith(other.startApp);

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

127
             size = defaultOptions.size;
127
             size = defaultOptions.size;
128
         }
128
         }
129
     }
129
     }
130
+
131
+    public boolean hasValue() {
132
+        return id.hasValue() || icon.hasValue();
133
+    }
130
 }
134
 }

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

121
         sideMenuRootOptions = new SideMenuRootOptions();
121
         sideMenuRootOptions = new SideMenuRootOptions();
122
         return this;
122
         return this;
123
     }
123
     }
124
+
125
+    public Options clearAnimationOptions() {
126
+        animationsOptions = new AnimationsOptions();
127
+        return this;
128
+    }
129
+
130
+    public Options clearFabOptions() {
131
+        fabOptions = new FabOptions();
132
+        return this;
133
+    }
124
 }
134
 }

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

52
         if (other.hasValue()) orientations = other.orientations;
52
         if (other.hasValue()) orientations = other.orientations;
53
     }
53
     }
54
 
54
 
55
-    private boolean hasValue() {
55
+    public boolean hasValue() {
56
         return !orientations.isEmpty();
56
         return !orientations.isEmpty();
57
     }
57
     }
58
 
58
 

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

82
     private static void validate(TitleOptions options) {
82
     private static void validate(TitleOptions options) {
83
         if (options.component.hasValue() && options.text.hasValue()) {
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.");
84
             if (BuildConfig.DEBUG) Log.w("RNN", "A screen can't use both text and component - clearing text.");
85
-            options.text = new Text("");
85
+            options.text = new NullText();
86
         }
86
         }
87
     }
87
     }
88
 }
88
 }

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

75
     }
75
     }
76
 
76
 
77
     private void applyButtons(ArrayList<Button> leftButtons, ArrayList<Button> rightButtons) {
77
     private void applyButtons(ArrayList<Button> leftButtons, ArrayList<Button> rightButtons) {
78
-        topBar.setButtons(leftButtons, rightButtons);
78
+        topBar.setLeftButtons(leftButtons);
79
+        topBar.setRightButtons(rightButtons);
79
     }
80
     }
80
 
81
 
81
     private void applyTopTabsOptions(TopTabsOptions options) {
82
     private void applyTopTabsOptions(TopTabsOptions options) {
102
             childDisappearListener.childDisappear();
103
             childDisappearListener.childDisappear();
103
         }
104
         }
104
     }
105
     }
106
+
107
+    public void mergeChildOptions(Options options, Component child) {
108
+        mergeOrientation(options.orientationOptions);
109
+        mergeButtons(options.topBarOptions.leftButtons, options.topBarOptions.rightButtons);
110
+        mergeTopBarOptions(options.topBarOptions, child);
111
+        mergeTopTabsOptions(options.topTabsOptions);
112
+        mergeTopTabOptions(options.topTabOptions);
113
+    }
114
+
115
+    private void mergeOrientation(OrientationOptions orientationOptions) {
116
+        if (orientationOptions.hasValue()) applyOrientation(orientationOptions);
117
+    }
118
+
119
+    private void mergeButtons(ArrayList<Button> leftButtons, ArrayList<Button> rightButtons) {
120
+        if (leftButtons != null) topBar.setLeftButtons(leftButtons);
121
+        if (rightButtons != null) topBar.setRightButtons(rightButtons);
122
+    }
123
+
124
+    private void mergeTopBarOptions(TopBarOptions options, Component component) {
125
+        if (options.title.text.hasValue()) topBar.setTitle(options.title.text.get());
126
+        if (options.title.component.hasValue()) topBar.setComponent(options.title.component.get(), options.title.alignment);
127
+        if (options.background.color.hasValue()) topBar.setBackgroundColor(options.background.color);
128
+        if (options.title.color.hasValue()) topBar.setTitleTextColor(options.title.color);
129
+        if (options.title.fontSize.hasValue()) topBar.setTitleFontSize(options.title.fontSize);
130
+        if (options.testId.hasValue()) topBar.setTestId(options.testId.get());
131
+
132
+        if (options.title.fontFamily != null) topBar.setTitleTypeface(options.title.fontFamily);
133
+        if (options.visible.isFalse()) {
134
+            topBar.hide(options.animate);
135
+        }
136
+        if (options.visible.isTrue()) {
137
+            topBar.show(options.animate);
138
+        }
139
+        if (options.drawBehind.isTrue()) {
140
+            component.drawBehindTopBar();
141
+        }
142
+        if (options.drawBehind.isFalse()) {
143
+            component.drawBelowTopBar(topBar);
144
+        }
145
+        if (options.hideOnScroll.isTrue() && component instanceof IReactView) {
146
+            topBar.enableCollapse(((IReactView) component).getScrollEventListener());
147
+        }
148
+        if (options.hideOnScroll.isFalse()) {
149
+            topBar.disableCollapse();
150
+        }
151
+    }
152
+
153
+    private void mergeTopTabsOptions(TopTabsOptions options) {
154
+        if (options.selectedTabColor.hasValue() && options.unselectedTabColor.hasValue()) topBar.applyTopTabsColors(options.selectedTabColor, options.unselectedTabColor);
155
+        if (options.fontSize.hasValue()) topBar.applyTopTabsFontSize(options.fontSize);
156
+        if (options.visible.hasValue()) topBar.setTopTabsVisible(options.visible.isTrue());
157
+    }
158
+
159
+    private void mergeTopTabOptions(TopTabOptions topTabOptions) {
160
+        if (topTabOptions.fontFamily != null) topBar.setTopTabFontFamily(topTabOptions.tabIndex, topTabOptions.fontFamily);
161
+    }
105
 }
162
 }

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

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

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

58
 
58
 
59
     @CallSuper
59
     @CallSuper
60
     public void applyChildOptions(Options options, Component child) {
60
     public void applyChildOptions(Options options, Component child) {
61
-        mergeChildOptions(options);
61
+        this.options = this.options.mergeWith(options);
62
     }
62
     }
63
 
63
 
64
-    private void mergeChildOptions(Options options) {
65
-        this.options = this.options.mergeWith(options);
64
+    @CallSuper
65
+    public void mergeChildOptions(Options options, Component child) {
66
+
66
     }
67
     }
67
 
68
 
68
 	@Override
69
 	@Override

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

31
 
31
 
32
     public StackController(final Activity activity, ReactViewCreator topBarButtonCreator, TitleBarReactViewCreator titleBarReactViewCreator, String id, Options initialOptions) {
32
     public StackController(final Activity activity, ReactViewCreator topBarButtonCreator, TitleBarReactViewCreator titleBarReactViewCreator, String id, Options initialOptions) {
33
         super(activity, id, initialOptions);
33
         super(activity, id, initialOptions);
34
-        animator = new NavigationAnimator(activity);
34
+        animator = createAnimator();
35
         this.topBarButtonCreator = topBarButtonCreator;
35
         this.topBarButtonCreator = topBarButtonCreator;
36
         this.titleBarReactViewCreator = titleBarReactViewCreator;
36
         this.titleBarReactViewCreator = titleBarReactViewCreator;
37
     }
37
     }
45
     public void applyChildOptions(Options options, Component child) {
45
     public void applyChildOptions(Options options, Component child) {
46
         super.applyChildOptions(options, child);
46
         super.applyChildOptions(options, child);
47
         getView().applyChildOptions(this.options, child);
47
         getView().applyChildOptions(this.options, child);
48
+        if (child instanceof ReactComponent) {
49
+            fabOptionsPresenter.applyOptions(this.options.fabOptions, (ReactComponent) child, getView());
50
+        }
48
         applyOnParentController(parentController ->
51
         applyOnParentController(parentController ->
49
-                ((ParentController) parentController).applyChildOptions(this.options.copy().clearTopBarOptions(), child)
52
+                ((ParentController) parentController).applyChildOptions(
53
+                        this.options.copy().clearTopBarOptions().clearAnimationOptions().clearFabOptions(),
54
+                        child
55
+                )
50
         );
56
         );
51
-        if (child instanceof ReactComponent) {
57
+        animator.setOptions(options.animationsOptions);
58
+    }
59
+
60
+    @Override
61
+    public void mergeChildOptions(Options options, Component child) {
62
+        super.mergeChildOptions(options, child);
63
+        getView().mergeChildOptions(options, child);
64
+        animator.mergeOptions(options.animationsOptions);
65
+        if (options.fabOptions.hasValue() && child instanceof ReactComponent) {
52
             fabOptionsPresenter.applyOptions(options.fabOptions, (ReactComponent) child, getView());
66
             fabOptionsPresenter.applyOptions(options.fabOptions, (ReactComponent) child, getView());
53
         }
67
         }
54
-        animator.setOptions(options.animationsOptions);
68
+        applyOnParentController(parentController ->
69
+                ((ParentController) parentController).mergeChildOptions(
70
+                        options.copy().clearTopBarOptions().clearAnimationOptions().clearFabOptions(),
71
+                        child
72
+                )
73
+        );
55
     }
74
     }
56
 
75
 
57
     @Override
76
     @Override
226
         getView().clearTopTabs();
245
         getView().clearTopTabs();
227
     }
246
     }
228
 
247
 
248
+     NavigationAnimator createAnimator() {
249
+        return new NavigationAnimator(getActivity());
250
+    }
251
+
229
     @RestrictTo(RestrictTo.Scope.TESTS)
252
     @RestrictTo(RestrictTo.Scope.TESTS)
230
     TopBar getTopBar() {
253
     TopBar getTopBar() {
231
         return getView().getTopBar();
254
         return getView().getTopBar();

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

12
     private final TitleBarReactViewCreator reactViewCreator;
12
     private final TitleBarReactViewCreator reactViewCreator;
13
     private String componentName;
13
     private String componentName;
14
 
14
 
15
+    public TitleBarReactViewController(TitleBarReactViewController reactViewController) {
16
+        this(reactViewController.getActivity(), reactViewController.reactViewCreator);
17
+    }
18
+
15
     public TitleBarReactViewController(Activity activity, TitleBarReactViewCreator reactViewCreator) {
19
     public TitleBarReactViewController(Activity activity, TitleBarReactViewCreator reactViewCreator) {
16
         super(activity, CompatUtils.generateViewId() + "", new Options());
20
         super(activity, CompatUtils.generateViewId() + "", new Options());
17
         this.reactViewCreator = reactViewCreator;
21
         this.reactViewCreator = reactViewCreator;
18
     }
22
     }
19
 
23
 
20
-    public TitleBarReactViewController(TitleBarReactViewController reactViewController) {
21
-        super(reactViewController.getActivity(), CompatUtils.generateViewId() + "", new Options());
22
-        this.reactViewCreator = reactViewController.reactViewCreator;
23
-    }
24
-
25
     @Override
24
     @Override
26
     protected TitleBarReactView createView() {
25
     protected TitleBarReactView createView() {
27
         return reactViewCreator.create(getActivity(), getId(), componentName);
26
         return reactViewCreator.create(getActivity(), getId(), componentName);

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

58
         this.viewVisibilityListener = viewVisibilityListener;
58
         this.viewVisibilityListener = viewVisibilityListener;
59
     }
59
     }
60
 
60
 
61
-    @SuppressWarnings("WeakerAccess")
62
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
61
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
63
     public void ensureViewIsCreated() {
62
     public void ensureViewIsCreated() {
64
         getView();
63
         getView();
107
         }
106
         }
108
     }
107
     }
109
 
108
 
110
-    @NonNull
111
     public T getView() {
109
     public T getView() {
112
         if (view == null) {
110
         if (view == null) {
113
             if (isDestroyed) {
111
             if (isDestroyed) {

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

59
     @Override
59
     @Override
60
     public void applyChildOptions(Options options, Component child) {
60
     public void applyChildOptions(Options options, Component child) {
61
         super.applyChildOptions(options, child);
61
         super.applyChildOptions(options, child);
62
-        int tabIndex = bottomTabFinder.findByComponent(child);
62
+        final 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).applyChildOptions(this.options.copy().clearBottomTabsOptions().clearBottomTabOptions(), child)
65
                 ((ParentController) parentController).applyChildOptions(this.options.copy().clearBottomTabsOptions().clearBottomTabOptions(), child)
66
         );
66
         );
67
     }
67
     }
68
 
68
 
69
+    @Override
70
+    public void mergeChildOptions(Options options, Component child) {
71
+        super.mergeChildOptions(options, child);
72
+        final int tabIndex = bottomTabFinder.findByComponent(child);
73
+        new BottomTabsOptionsPresenter(bottomTabs, bottomTabFinder).present(options, tabIndex);
74
+        applyOnParentController(parentController ->
75
+                ((ParentController) parentController).mergeChildOptions(options.copy().clearBottomTabsOptions(), child)
76
+        );
77
+    }
78
+
69
     @Override
79
     @Override
70
 	public boolean handleBack() {
80
 	public boolean handleBack() {
71
 		return !tabs.isEmpty() && tabs.get(bottomTabs.getCurrentItem()).handleBack();
81
 		return !tabs.isEmpty() && tabs.get(bottomTabs.getCurrentItem()).handleBack();

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

22
 
22
 
23
     private IReactView reactView;
23
     private IReactView reactView;
24
     private final OverlayTouchDelegate touchDelegate;
24
     private final OverlayTouchDelegate touchDelegate;
25
+    private final ComponentOptionsPresenter optionsPresenter;
25
 
26
 
26
     public ComponentLayout(Context context, IReactView reactView) {
27
     public ComponentLayout(Context context, IReactView reactView) {
27
 		super(context);
28
 		super(context);
29
         addView(reactView.asView(), MATCH_PARENT, MATCH_PARENT);
30
         addView(reactView.asView(), MATCH_PARENT, MATCH_PARENT);
30
         setContentDescription("ComponentLayout");
31
         setContentDescription("ComponentLayout");
31
         touchDelegate = new OverlayTouchDelegate(reactView);
32
         touchDelegate = new OverlayTouchDelegate(reactView);
33
+        optionsPresenter = new ComponentOptionsPresenter(this);
32
     }
34
     }
33
 
35
 
34
     @Override
36
     @Override
58
 
60
 
59
     @Override
61
     @Override
60
     public void applyOptions(Options options) {
62
     public void applyOptions(Options options) {
61
-        new ComponentOptionsPresenter(this).present(options);
63
+        optionsPresenter.present(options);
62
         touchDelegate.setInterceptTouchOutside(options.overlayOptions.interceptTouchOutside.isTrue());
64
         touchDelegate.setInterceptTouchOutside(options.overlayOptions.interceptTouchOutside.isTrue());
63
     }
65
     }
64
 
66
 

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

63
     public TopBar getTopBar() {
63
     public TopBar getTopBar() {
64
         return topBar;
64
         return topBar;
65
     }
65
     }
66
+
67
+    public void mergeChildOptions(Options options, Component child) {
68
+        optionsPresenter.mergeChildOptions(options, child);
69
+    }
66
 }
70
 }

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

105
         topTabs.setVisibility(this, visible);
105
         topTabs.setVisibility(this, visible);
106
     }
106
     }
107
 
107
 
108
-    public void setButtons(List<Button> leftButtons, List<Button> rightButtons) {
109
-        titleBar.setButtons(leftButtons, rightButtons);
108
+    public void setLeftButtons(List<Button> leftButtons) {
109
+        titleBar.setLeftButtons(leftButtons);
110
+    }
111
+
112
+    public void setRightButtons(List<Button> rightButtons) {
113
+        titleBar.setRightButtons(rightButtons);
110
     }
114
     }
111
 
115
 
112
     @RestrictTo(RestrictTo.Scope.TESTS)
116
     @RestrictTo(RestrictTo.Scope.TESTS)

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

25
     }
25
     }
26
 
26
 
27
     void applyTopTabsColors(Color selected, Color unselected) {
27
     void applyTopTabsColors(Color selected, Color unselected) {
28
-        if (!selected.hasValue() && !unselected.hasValue()) return;
29
-
30
         ColorStateList originalColors = topTabs.getTabTextColors();
28
         ColorStateList originalColors = topTabs.getTabTextColors();
31
         int selectedTabColor = originalColors != null ? originalColors.getColorForState(topTabs.getSelectedTabColors(), -1) : -1;
29
         int selectedTabColor = originalColors != null ? originalColors.getColorForState(topTabs.getSelectedTabColors(), -1) : -1;
32
         int tabTextColor = originalColors != null ? originalColors.getColorForState(topTabs.getDefaultTabColors(), -1) : -1;
30
         int tabTextColor = originalColors != null ? originalColors.getColorForState(topTabs.getDefaultTabColors(), -1) : -1;

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

52
     }
52
     }
53
 
53
 
54
     public void setComponent(String componentName, TitleOptions.Alignment alignment) {
54
     public void setComponent(String componentName, TitleOptions.Alignment alignment) {
55
+        clearTitle();
55
         reactViewController.setComponent(componentName);
56
         reactViewController.setComponent(componentName);
56
         addView(reactViewController.getView(), getComponentLayoutParams(alignment));
57
         addView(reactViewController.getView(), getComponentLayoutParams(alignment));
57
     }
58
     }
79
     }
80
     }
80
 
81
 
81
     public void clear() {
82
     public void clear() {
82
-        setTitle(null);
83
+        clearTitle();
83
         clearRightButtons();
84
         clearRightButtons();
84
         clearLeftButton();
85
         clearLeftButton();
85
         clearComponent();
86
         clearComponent();
86
     }
87
     }
87
 
88
 
89
+    private void clearTitle() {
90
+        setTitle(null);
91
+    }
92
+
88
     private void clearComponent() {
93
     private void clearComponent() {
89
         reactViewController.destroy();
94
         reactViewController.destroy();
90
         reactViewController = new TitleBarReactViewController(reactViewController);
95
         reactViewController = new TitleBarReactViewController(reactViewController);
106
         getMenu().clear();
111
         getMenu().clear();
107
     }
112
     }
108
 
113
 
109
-    public void setButtons(List<Button> leftButtons, List<Button> rightButtons) {
110
-        setLeftButtons(leftButtons);
111
-        setRightButtons(rightButtons);
112
-    }
113
-
114
-    private void setLeftButtons(List<Button> leftButtons) {
114
+    public void setLeftButtons(List<Button> leftButtons) {
115
         if (leftButtons == null) return;
115
         if (leftButtons == null) return;
116
         if (leftButtons.isEmpty()) {
116
         if (leftButtons.isEmpty()) {
117
             clearLeftButton();
117
             clearLeftButton();

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

1
+package com.reactnativenavigation.viewcontrollers;
2
+
3
+import android.app.Activity;
4
+import android.graphics.Typeface;
5
+
6
+import com.reactnativenavigation.BaseTest;
7
+import com.reactnativenavigation.mocks.TestComponentLayout;
8
+import com.reactnativenavigation.mocks.TestReactView;
9
+import com.reactnativenavigation.parse.Options;
10
+import com.reactnativenavigation.parse.OrientationOptions;
11
+import com.reactnativenavigation.parse.TitleOptions;
12
+import com.reactnativenavigation.parse.params.Bool;
13
+import com.reactnativenavigation.parse.params.Color;
14
+import com.reactnativenavigation.parse.params.Fraction;
15
+import com.reactnativenavigation.parse.params.Number;
16
+import com.reactnativenavigation.parse.params.Text;
17
+import com.reactnativenavigation.presentation.OptionsPresenter;
18
+import com.reactnativenavigation.views.TopBar;
19
+
20
+import org.json.JSONObject;
21
+import org.junit.Test;
22
+
23
+import java.util.ArrayList;
24
+
25
+import static org.mockito.ArgumentMatchers.any;
26
+import static org.mockito.ArgumentMatchers.anyBoolean;
27
+import static org.mockito.ArgumentMatchers.anyInt;
28
+import static org.mockito.Mockito.mock;
29
+import static org.mockito.Mockito.spy;
30
+import static org.mockito.Mockito.times;
31
+import static org.mockito.Mockito.verify;
32
+import static org.mockito.Mockito.when;
33
+
34
+public class OptionsMergingTest extends BaseTest {
35
+
36
+    private OptionsPresenter uut;
37
+    private TestComponentLayout child;
38
+    private Activity activity;
39
+    private TopBar topBar;
40
+
41
+    @Override
42
+    public void beforeEach() {
43
+        activity = spy(newActivity());
44
+        topBar = mockTopBar();
45
+        uut = spy(new OptionsPresenter(topBar));
46
+        child = spy(new TestComponentLayout(activity, new TestReactView(activity)));
47
+    }
48
+
49
+    @Test
50
+    public void mergeOrientation() throws Exception {
51
+        Options options = new Options();
52
+        uut.mergeChildOptions(options, child);
53
+        verify(uut, times(0)).applyOrientation(any());
54
+
55
+        JSONObject orientation = new JSONObject().put("orientation", "landscape");
56
+        options.orientationOptions = OrientationOptions.parse(orientation);
57
+        uut.mergeChildOptions(options, child);
58
+        verify(uut, times(1)).applyOrientation(options.orientationOptions);
59
+    }
60
+
61
+    @Test
62
+    public void mergeButtons() throws Exception {
63
+        Options options = new Options();
64
+        uut.mergeChildOptions(options, child);
65
+        verify(topBar, times(0)).setRightButtons(any());
66
+        verify(topBar, times(0)).setLeftButtons(any());
67
+
68
+        options.topBarOptions.rightButtons = new ArrayList<>();
69
+        uut.mergeChildOptions(options, child);
70
+        verify(topBar, times(1)).setRightButtons(any());
71
+
72
+        options.topBarOptions.leftButtons = new ArrayList<>();
73
+        uut.mergeChildOptions(options, child);
74
+        verify(topBar, times(1)).setLeftButtons(any());
75
+    }
76
+
77
+    @Test
78
+    public void mergeTopBarOptions() throws Exception {
79
+        Options options = new Options();
80
+        uut.mergeChildOptions(options, child);
81
+        assertTopBarOptions(0);
82
+
83
+        TitleOptions titleOptions = new TitleOptions();
84
+        titleOptions.text = new Text("abc");
85
+        titleOptions.component = new Text("someComponent");
86
+        titleOptions.color = new Color(0);
87
+        titleOptions.fontSize = new Fraction(1.0f);
88
+        titleOptions.fontFamily = Typeface.DEFAULT_BOLD;
89
+        options.topBarOptions.title = titleOptions;
90
+        options.topBarOptions.background.color = new Color(0);
91
+        options.topBarOptions.testId = new Text("test123");
92
+        options.topBarOptions.visible = new Bool(false);
93
+        options.topBarOptions.drawBehind = new Bool(false);
94
+        options.topBarOptions.hideOnScroll = new Bool(false);
95
+        uut.mergeChildOptions(options, child);
96
+
97
+        assertTopBarOptions(1);
98
+
99
+        options.topBarOptions.drawBehind = new Bool(true);
100
+        uut.mergeChildOptions(options, child);
101
+        verify(child, times(1)).drawBehindTopBar();
102
+    }
103
+
104
+    @Test
105
+    public void mergeTopTabsOptions() throws Exception {
106
+        Options options = new Options();
107
+        uut.mergeChildOptions(options, child);
108
+        verify(topBar, times(0)).applyTopTabsColors(any(), any());
109
+        verify(topBar, times(0)).applyTopTabsFontSize(any());
110
+        verify(topBar, times(0)).setTopTabsVisible(anyBoolean());
111
+
112
+        options.topTabsOptions.selectedTabColor = new Color(1);
113
+        options.topTabsOptions.unselectedTabColor = new Color(1);
114
+        options.topTabsOptions.fontSize = new Number(1);
115
+        options.topTabsOptions.visible = new Bool(true);
116
+        uut.mergeChildOptions(options, child);
117
+        verify(topBar, times(1)).applyTopTabsColors(options.topTabsOptions.selectedTabColor, options.topTabsOptions.unselectedTabColor);
118
+        verify(topBar, times(1)).applyTopTabsFontSize(options.topTabsOptions.fontSize);
119
+        verify(topBar, times(1)).setTopTabsVisible(anyBoolean());
120
+    }
121
+
122
+    @Test
123
+    public void mergeTopTabOptions() throws Exception {
124
+        Options options = new Options();
125
+        uut.mergeChildOptions(options, child);
126
+
127
+        verify(topBar, times(0)).setTopTabFontFamily(anyInt(), any());
128
+
129
+        options.topTabOptions.tabIndex = 1;
130
+        options.topTabOptions.fontFamily = Typeface.DEFAULT_BOLD;
131
+        uut.mergeChildOptions(options, child);
132
+
133
+        verify(topBar, times(1)).setTopTabFontFamily(1, Typeface.DEFAULT_BOLD);
134
+    }
135
+
136
+
137
+    private void assertTopBarOptions(int t) {
138
+        verify(topBar, times(t)).setTitle(any());
139
+        verify(topBar, times(t)).setComponent(any(), any());
140
+        verify(topBar, times(t)).setBackgroundColor(any());
141
+        verify(topBar, times(t)).setTitleTextColor(any());
142
+        verify(topBar, times(t)).setTitleFontSize(any());
143
+        verify(topBar, times(t)).setTestId(any());
144
+        verify(topBar, times(t)).setTitleTypeface(any());
145
+        verify(topBar, times(t)).hide(any());
146
+        verify(child, times(t)).drawBelowTopBar(topBar);
147
+        verify(child, times(0)).drawBehindTopBar();
148
+    }
149
+
150
+    private TopBar mockTopBar() {
151
+        TopBar topBar = mock(TopBar.class);
152
+        when(topBar.getContext()).then(invocation -> activity);
153
+        return topBar;
154
+    }
155
+}

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

5
 import android.view.View;
5
 import android.view.View;
6
 
6
 
7
 import com.reactnativenavigation.BaseTest;
7
 import com.reactnativenavigation.BaseTest;
8
+import com.reactnativenavigation.anim.NavigationAnimator;
8
 import com.reactnativenavigation.mocks.MockPromise;
9
 import com.reactnativenavigation.mocks.MockPromise;
9
 import com.reactnativenavigation.mocks.SimpleViewController;
10
 import com.reactnativenavigation.mocks.SimpleViewController;
10
 import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11
 import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
13
+import com.reactnativenavigation.parse.AnimationOptions;
12
 import com.reactnativenavigation.parse.Options;
14
 import com.reactnativenavigation.parse.Options;
13
 import com.reactnativenavigation.parse.params.Bool;
15
 import com.reactnativenavigation.parse.params.Bool;
14
 import com.reactnativenavigation.parse.params.Text;
16
 import com.reactnativenavigation.parse.params.Text;
15
 import com.reactnativenavigation.utils.ViewHelper;
17
 import com.reactnativenavigation.utils.ViewHelper;
18
+import com.reactnativenavigation.views.Component;
16
 import com.reactnativenavigation.views.ReactComponent;
19
 import com.reactnativenavigation.views.ReactComponent;
17
 import com.reactnativenavigation.views.StackLayout;
20
 import com.reactnativenavigation.views.StackLayout;
18
 
21
 
19
 import org.assertj.core.api.iterable.Extractor;
22
 import org.assertj.core.api.iterable.Extractor;
23
+import org.json.JSONObject;
20
 import org.junit.Test;
24
 import org.junit.Test;
21
 import org.mockito.ArgumentCaptor;
25
 import org.mockito.ArgumentCaptor;
26
+import org.mockito.Mockito;
22
 
27
 
23
 import javax.annotation.Nullable;
28
 import javax.annotation.Nullable;
24
 
29
 
25
 import static org.assertj.core.api.Java6Assertions.assertThat;
30
 import static org.assertj.core.api.Java6Assertions.assertThat;
26
 import static org.mockito.ArgumentMatchers.eq;
31
 import static org.mockito.ArgumentMatchers.eq;
32
+import static org.mockito.Mockito.mock;
27
 import static org.mockito.Mockito.spy;
33
 import static org.mockito.Mockito.spy;
28
 import static org.mockito.Mockito.times;
34
 import static org.mockito.Mockito.times;
29
 import static org.mockito.Mockito.verify;
35
 import static org.mockito.Mockito.verify;
35
     private ViewController child1;
41
     private ViewController child1;
36
     private ViewController child2;
42
     private ViewController child2;
37
     private ViewController child3;
43
     private ViewController child3;
44
+    private NavigationAnimator animator;
38
 
45
 
39
     @Override
46
     @Override
40
     public void beforeEach() {
47
     public void beforeEach() {
453
         verify(child1, times(1)).sendOnNavigationButtonPressed("btn1");
460
         verify(child1, times(1)).sendOnNavigationButtonPressed("btn1");
454
     }
461
     }
455
 
462
 
463
+    @Test
464
+    public void mergeChildOptions_updatesViewWithNewOptions() throws Exception {
465
+        final StackLayout[] stackLayout = new StackLayout[1];
466
+        StackController uut = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack", new Options()) {
467
+            @NonNull
468
+            @Override
469
+            protected StackLayout createView() {
470
+                stackLayout[0] = spy(super.createView());
471
+                return stackLayout[0];
472
+            }
473
+        };
474
+        Options optionsToMerge = new Options();
475
+        Component component = mock(Component.class);
476
+        uut.mergeChildOptions(optionsToMerge, component);
477
+        verify(stackLayout[0], times(1)).mergeChildOptions(optionsToMerge, component);
478
+    }
479
+
480
+    @Test
481
+    public void mergeChildOptions_updatesParentControllerWithNewOptions() throws Exception {
482
+        final StackLayout[] stackLayout = new StackLayout[1];
483
+        StackController uut = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack", new Options()) {
484
+            @NonNull
485
+            @Override
486
+            protected StackLayout createView() {
487
+                stackLayout[0] = spy(super.createView());
488
+                return stackLayout[0];
489
+            }
490
+        };
491
+        ParentController parentController = Mockito.mock(ParentController.class);
492
+        uut.setParentController(parentController);
493
+        Options optionsToMerge = new Options();
494
+        optionsToMerge.topBarOptions.testId = new Text("topBarID");
495
+        optionsToMerge.bottomTabsOptions.testId = new Text("bottomTabsID");
496
+        Component component = mock(Component.class);
497
+        uut.mergeChildOptions(optionsToMerge, component);
498
+
499
+        ArgumentCaptor<Options> captor = ArgumentCaptor.forClass(Options.class);
500
+        verify(parentController, times(1)).mergeChildOptions(captor.capture(), eq(component));
501
+        assertThat(captor.getValue().topBarOptions.testId.hasValue()).isFalse();
502
+        assertThat(captor.getValue().bottomTabsOptions.testId.get()).isEqualTo(optionsToMerge.bottomTabsOptions.testId.get());
503
+    }
504
+
505
+    @Test
506
+    public void mergeChildOptions_mergeAnimationOptions() throws Exception {
507
+        Options options = new Options();
508
+        Component component = mock(Component.class);
509
+
510
+        uut.mergeChildOptions(options, component);
511
+        verify(animator, times(0)).setOptions(options.animationsOptions);
512
+        verify(animator, times(1)).mergeOptions(options.animationsOptions);
513
+    }
514
+
515
+    @Test
516
+    public void mergeChildOptions_StackRelatedOptionsAreCleared() throws Exception {
517
+        ParentController parentController = Mockito.mock(ParentController.class);
518
+        uut.setParentController(parentController);
519
+        Options options = new Options();
520
+        options.animationsOptions.push = AnimationOptions.parse(new JSONObject());
521
+        options.topBarOptions.testId = new Text("id");
522
+        options.fabOptions.id = new Text("fabId");
523
+        Component component = mock(Component.class);
524
+
525
+        assertThat(options.fabOptions.hasValue()).isTrue();
526
+        uut.mergeChildOptions(options, component);
527
+        ArgumentCaptor<Options> captor = ArgumentCaptor.forClass(Options.class);
528
+        verify(parentController, times(1)).mergeChildOptions(captor.capture(), eq(component));
529
+        assertThat(captor.getValue().animationsOptions.push.hasValue()).isFalse();
530
+        assertThat(captor.getValue().topBarOptions.testId.hasValue()).isFalse();
531
+        assertThat(captor.getValue().fabOptions.hasValue()).isFalse();
532
+    }
533
+
456
     private void assertContainsOnlyId(String... ids) {
534
     private void assertContainsOnlyId(String... ids) {
457
         assertThat(uut.size()).isEqualTo(ids.length);
535
         assertThat(uut.size()).isEqualTo(ids.length);
458
         assertThat(uut.getChildControllers()).extracting((Extractor<ViewController, String>) ViewController::getId).containsOnly(ids);
536
         assertThat(uut.getChildControllers()).extracting((Extractor<ViewController, String>) ViewController::getId).containsOnly(ids);
459
     }
537
     }
460
 
538
 
461
     private StackController createStackController(String id) {
539
     private StackController createStackController(String id) {
462
-        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), id, new Options());
540
+        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), id, new Options()) {
541
+            @Override
542
+            NavigationAnimator createAnimator() {
543
+                animator = Mockito.mock(NavigationAnimator.class);
544
+                return animator;
545
+            }
546
+        };
463
     }
547
     }
464
 }
548
 }

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

73
 
73
 
74
     @Test
74
     @Test
75
     public void setButton_setsTextButton() {
75
     public void setButton_setsTextButton() {
76
-        uut.setButtons(leftButton(leftButton), rightButtons(textButton));
76
+        uut.setRightButtons(rightButtons(textButton));
77
+        uut.setLeftButtons(leftButton(leftButton));
77
         assertThat(uut.getMenu().getItem(0).getTitle()).isEqualTo(textButton.title.get());
78
         assertThat(uut.getMenu().getItem(0).getTitle()).isEqualTo(textButton.title.get());
78
     }
79
     }
79
 
80
 
80
     @Test
81
     @Test
81
     public void setButton_setsCustomButton() {
82
     public void setButton_setsCustomButton() {
82
-        uut.setButtons(leftButton(leftButton), rightButtons(customButton));
83
+        uut.setLeftButtons(leftButton(leftButton));
84
+        uut.setRightButtons(rightButtons(customButton));
83
         ReactView btnView = (ReactView) uut.getMenu().getItem(0).getActionView();
85
         ReactView btnView = (ReactView) uut.getMenu().getItem(0).getActionView();
84
         assertThat(btnView.getComponentName()).isEqualTo(customButton.component.get());
86
         assertThat(btnView.getComponentName()).isEqualTo(customButton.component.get());
85
     }
87
     }
86
 
88
 
87
     @Test
89
     @Test
88
     public void destroy_destroysButtonControllers() throws Exception {
90
     public void destroy_destroysButtonControllers() throws Exception {
89
-        uut.setButtons(leftButton(leftButton), rightButtons(customButton, textButton));
91
+        uut.setLeftButtons(leftButton(leftButton));
92
+        uut.setRightButtons(rightButtons(customButton, textButton));
90
         uut.clear();
93
         uut.clear();
91
         for (TopBarButtonController controller : buttonControllers.values()) {
94
         for (TopBarButtonController controller : buttonControllers.values()) {
92
             verify(controller, times(1)).destroy();
95
             verify(controller, times(1)).destroy();
95
 
98
 
96
     @Test
99
     @Test
97
     public void setRightButtons_destroysRightButtons() throws Exception {
100
     public void setRightButtons_destroysRightButtons() throws Exception {
98
-        uut.setButtons(leftButton(leftButton), rightButtons(customButton));
99
-        uut.setButtons(leftButton(leftButton), rightButtons(textButton));
101
+        uut.setLeftButtons(leftButton(leftButton));
102
+        uut.setRightButtons(rightButtons(customButton));
103
+        uut.setLeftButtons(leftButton(leftButton));
104
+        uut.setRightButtons(rightButtons(textButton));
100
         verify(buttonControllers.get(customButton.id), times(1)).destroy();
105
         verify(buttonControllers.get(customButton.id), times(1)).destroy();
101
     }
106
     }
102
 
107
 
103
     @Test
108
     @Test
104
     public void setRightButtons_onlyDestroysRightButtons() throws Exception {
109
     public void setRightButtons_onlyDestroysRightButtons() throws Exception {
105
-        uut.setButtons(leftButton(leftButton), rightButtons(customButton));
106
-        uut.setButtons(null, rightButtons(textButton));
110
+        uut.setLeftButtons(leftButton(leftButton));
111
+        uut.setRightButtons(rightButtons(customButton));
112
+        uut.setLeftButtons(null);
113
+        uut.setRightButtons(rightButtons(textButton));
107
         verify(buttonControllers.get(leftButton.id), times(0)).destroy();
114
         verify(buttonControllers.get(leftButton.id), times(0)).destroy();
108
     }
115
     }
109
 
116
 
110
     @Test
117
     @Test
111
     public void setRightButtons_emptyButtonsListClearsRightButtons() throws Exception {
118
     public void setRightButtons_emptyButtonsListClearsRightButtons() throws Exception {
112
-        uut.setButtons(new ArrayList<>(), rightButtons(customButton, textButton));
113
-        uut.setButtons(new ArrayList<>(), new ArrayList<>());
119
+        uut.setLeftButtons(new ArrayList<>());
120
+        uut.setRightButtons(rightButtons(customButton, textButton));
121
+        uut.setLeftButtons(new ArrayList<>());
122
+        uut.setRightButtons(new ArrayList<>());
114
         for (TopBarButtonController controller : buttonControllers.values()) {
123
         for (TopBarButtonController controller : buttonControllers.values()) {
115
             verify(controller, times(1)).destroy();
124
             verify(controller, times(1)).destroy();
116
         }
125
         }
119
 
128
 
120
     @Test
129
     @Test
121
     public void setLeftButtons_emptyButtonsListClearsLeftButton() throws Exception {
130
     public void setLeftButtons_emptyButtonsListClearsLeftButton() throws Exception {
122
-        uut.setButtons(leftButton(leftButton), rightButtons(customButton));
123
-        uut.setButtons(new ArrayList<>(), rightButtons(textButton));
131
+        uut.setLeftButtons(leftButton(leftButton));
132
+        uut.setRightButtons(rightButtons(customButton));
133
+        uut.setLeftButtons(new ArrayList<>());
134
+        uut.setRightButtons(rightButtons(textButton));
124
         verify(buttonControllers.get(leftButton.id), times(1)).destroy();
135
         verify(buttonControllers.get(leftButton.id), times(1)).destroy();
125
     }
136
     }
126
 
137
 
127
     @Test
138
     @Test
128
     public void setRightButtons_buttonsAreAddedInReverseOrderToMatchOrderOnIOs() throws Exception {
139
     public void setRightButtons_buttonsAreAddedInReverseOrderToMatchOrderOnIOs() throws Exception {
129
-        uut.setButtons(new ArrayList<>(), rightButtons(textButton, customButton));
140
+        uut.setLeftButtons(new ArrayList<>());
141
+        uut.setRightButtons(rightButtons(textButton, customButton));
130
         assertThat(uut.getMenu().getItem(1).getTitle()).isEqualTo(textButton.title.get());
142
         assertThat(uut.getMenu().getItem(1).getTitle()).isEqualTo(textButton.title.get());
131
     }
143
     }
132
 
144
 

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

92
 
92
 
93
     @Test
93
     @Test
94
     public void button_TitleBarButtonOnClickInvoked() throws Exception {
94
     public void button_TitleBarButtonOnClickInvoked() throws Exception {
95
-        uut.setButtons(new ArrayList<>(), rightButtons);
95
+        uut.setLeftButtons(new ArrayList<>());
96
+        uut.setRightButtons(rightButtons);
96
         for (int i = 0; i < rightButtons.size(); i++) {
97
         for (int i = 0; i < rightButtons.size(); i++) {
97
             Button rightButton = rightButtons.get(i);
98
             Button rightButton = rightButtons.get(i);
98
             TitleBarHelper.getRightButton(uut.getTitleBar(), i).callOnClick();
99
             TitleBarHelper.getRightButton(uut.getTitleBar(), i).callOnClick();