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,6 +7,8 @@ import android.content.Context;
7 7
 import android.support.annotation.Nullable;
8 8
 import android.view.View;
9 9
 
10
+import com.reactnativenavigation.parse.AnimationsOptions;
11
+
10 12
 @SuppressWarnings("ResourceType")
11 13
 public class NavigationAnimator extends BaseAnimator {
12 14
 
@@ -55,4 +57,12 @@ public class NavigationAnimator extends BaseAnimator {
55 57
         });
56 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,7 +26,7 @@ public class AnimationsOptions {
26 26
     public AnimationOptions showModal = new AnimationOptions();
27 27
     public AnimationOptions dismissModal = new AnimationOptions();
28 28
 
29
-    void mergeWith(AnimationsOptions other) {
29
+    public void mergeWith(AnimationsOptions other) {
30 30
         push.mergeWith(other.push);
31 31
         pop.mergeWith(other.pop);
32 32
         startApp.mergeWith(other.startApp);

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

@@ -127,4 +127,8 @@ public class FabOptions implements DEFAULT_VALUES {
127 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,4 +121,14 @@ public class Options implements DEFAULT_VALUES {
121 121
         sideMenuRootOptions = new SideMenuRootOptions();
122 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,7 +52,7 @@ public class OrientationOptions {
52 52
         if (other.hasValue()) orientations = other.orientations;
53 53
     }
54 54
 
55
-    private boolean hasValue() {
55
+    public boolean hasValue() {
56 56
         return !orientations.isEmpty();
57 57
     }
58 58
 

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

@@ -82,7 +82,7 @@ public class TitleOptions {
82 82
     private static void validate(TitleOptions options) {
83 83
         if (options.component.hasValue() && options.text.hasValue()) {
84 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,7 +75,8 @@ public class OptionsPresenter {
75 75
     }
76 76
 
77 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 82
     private void applyTopTabsOptions(TopTabsOptions options) {
@@ -102,4 +103,60 @@ public class OptionsPresenter {
102 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,9 +60,9 @@ public class ComponentViewController extends ViewController<ComponentLayout> imp
60 60
 
61 61
     @Override
62 62
     public void mergeOptions(Options options) {
63
+        view.applyOptions(options);
64
+        applyOnParentController(parentController -> parentController.mergeChildOptions(options, view));
63 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 68
     ReactComponent getComponent() {

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

@@ -58,11 +58,12 @@ public abstract class ParentController<T extends ViewGroup> extends ViewControll
58 58
 
59 59
     @CallSuper
60 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 69
 	@Override

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

@@ -31,7 +31,7 @@ public class StackController extends ParentController<StackLayout> {
31 31
 
32 32
     public StackController(final Activity activity, ReactViewCreator topBarButtonCreator, TitleBarReactViewCreator titleBarReactViewCreator, String id, Options initialOptions) {
33 33
         super(activity, id, initialOptions);
34
-        animator = new NavigationAnimator(activity);
34
+        animator = createAnimator();
35 35
         this.topBarButtonCreator = topBarButtonCreator;
36 36
         this.titleBarReactViewCreator = titleBarReactViewCreator;
37 37
     }
@@ -45,13 +45,32 @@ public class StackController extends ParentController<StackLayout> {
45 45
     public void applyChildOptions(Options options, Component child) {
46 46
         super.applyChildOptions(options, child);
47 47
         getView().applyChildOptions(this.options, child);
48
+        if (child instanceof ReactComponent) {
49
+            fabOptionsPresenter.applyOptions(this.options.fabOptions, (ReactComponent) child, getView());
50
+        }
48 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 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 76
     @Override
@@ -226,6 +245,10 @@ public class StackController extends ParentController<StackLayout> {
226 245
         getView().clearTopTabs();
227 246
     }
228 247
 
248
+     NavigationAnimator createAnimator() {
249
+        return new NavigationAnimator(getActivity());
250
+    }
251
+
229 252
     @RestrictTo(RestrictTo.Scope.TESTS)
230 253
     TopBar getTopBar() {
231 254
         return getView().getTopBar();

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

@@ -12,16 +12,15 @@ public class TitleBarReactViewController extends ViewController<TitleBarReactVie
12 12
     private final TitleBarReactViewCreator reactViewCreator;
13 13
     private String componentName;
14 14
 
15
+    public TitleBarReactViewController(TitleBarReactViewController reactViewController) {
16
+        this(reactViewController.getActivity(), reactViewController.reactViewCreator);
17
+    }
18
+
15 19
     public TitleBarReactViewController(Activity activity, TitleBarReactViewCreator reactViewCreator) {
16 20
         super(activity, CompatUtils.generateViewId() + "", new Options());
17 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 24
     @Override
26 25
     protected TitleBarReactView createView() {
27 26
         return reactViewCreator.create(getActivity(), getId(), componentName);

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

@@ -58,7 +58,6 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
58 58
         this.viewVisibilityListener = viewVisibilityListener;
59 59
     }
60 60
 
61
-    @SuppressWarnings("WeakerAccess")
62 61
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
63 62
     public void ensureViewIsCreated() {
64 63
         getView();
@@ -107,7 +106,6 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
107 106
         }
108 107
     }
109 108
 
110
-    @NonNull
111 109
     public T getView() {
112 110
         if (view == null) {
113 111
             if (isDestroyed) {

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

@@ -59,13 +59,23 @@ public class BottomTabsController extends ParentController implements AHBottomNa
59 59
     @Override
60 60
     public void applyChildOptions(Options options, Component child) {
61 61
         super.applyChildOptions(options, child);
62
-        int tabIndex = bottomTabFinder.findByComponent(child);
62
+        final int tabIndex = bottomTabFinder.findByComponent(child);
63 63
         if (tabIndex >= 0) new BottomTabsOptionsPresenter(bottomTabs, bottomTabFinder).present(this.options, tabIndex);
64 64
         applyOnParentController(parentController ->
65 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 79
     @Override
70 80
 	public boolean handleBack() {
71 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,6 +22,7 @@ public class ComponentLayout extends FrameLayout implements ReactComponent, TopB
22 22
 
23 23
     private IReactView reactView;
24 24
     private final OverlayTouchDelegate touchDelegate;
25
+    private final ComponentOptionsPresenter optionsPresenter;
25 26
 
26 27
     public ComponentLayout(Context context, IReactView reactView) {
27 28
 		super(context);
@@ -29,6 +30,7 @@ public class ComponentLayout extends FrameLayout implements ReactComponent, TopB
29 30
         addView(reactView.asView(), MATCH_PARENT, MATCH_PARENT);
30 31
         setContentDescription("ComponentLayout");
31 32
         touchDelegate = new OverlayTouchDelegate(reactView);
33
+        optionsPresenter = new ComponentOptionsPresenter(this);
32 34
     }
33 35
 
34 36
     @Override
@@ -58,7 +60,7 @@ public class ComponentLayout extends FrameLayout implements ReactComponent, TopB
58 60
 
59 61
     @Override
60 62
     public void applyOptions(Options options) {
61
-        new ComponentOptionsPresenter(this).present(options);
63
+        optionsPresenter.present(options);
62 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,4 +63,8 @@ public class StackLayout extends RelativeLayout {
63 63
     public TopBar getTopBar() {
64 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,8 +105,12 @@ public class TopBar extends AppBarLayout implements ScrollEventListener.ScrollAw
105 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 116
     @RestrictTo(RestrictTo.Scope.TESTS)

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

@@ -25,8 +25,6 @@ class TopTabsStyleHelper {
25 25
     }
26 26
 
27 27
     void applyTopTabsColors(Color selected, Color unselected) {
28
-        if (!selected.hasValue() && !unselected.hasValue()) return;
29
-
30 28
         ColorStateList originalColors = topTabs.getTabTextColors();
31 29
         int selectedTabColor = originalColors != null ? originalColors.getColorForState(topTabs.getSelectedTabColors(), -1) : -1;
32 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,6 +52,7 @@ public class TitleBar extends Toolbar {
52 52
     }
53 53
 
54 54
     public void setComponent(String componentName, TitleOptions.Alignment alignment) {
55
+        clearTitle();
55 56
         reactViewController.setComponent(componentName);
56 57
         addView(reactViewController.getView(), getComponentLayoutParams(alignment));
57 58
     }
@@ -79,12 +80,16 @@ public class TitleBar extends Toolbar {
79 80
     }
80 81
 
81 82
     public void clear() {
82
-        setTitle(null);
83
+        clearTitle();
83 84
         clearRightButtons();
84 85
         clearLeftButton();
85 86
         clearComponent();
86 87
     }
87 88
 
89
+    private void clearTitle() {
90
+        setTitle(null);
91
+    }
92
+
88 93
     private void clearComponent() {
89 94
         reactViewController.destroy();
90 95
         reactViewController = new TitleBarReactViewController(reactViewController);
@@ -106,12 +111,7 @@ public class TitleBar extends Toolbar {
106 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 115
         if (leftButtons == null) return;
116 116
         if (leftButtons.isEmpty()) {
117 117
             clearLeftButton();

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

@@ -0,0 +1,155 @@
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,25 +5,31 @@ import android.support.annotation.NonNull;
5 5
 import android.view.View;
6 6
 
7 7
 import com.reactnativenavigation.BaseTest;
8
+import com.reactnativenavigation.anim.NavigationAnimator;
8 9
 import com.reactnativenavigation.mocks.MockPromise;
9 10
 import com.reactnativenavigation.mocks.SimpleViewController;
10 11
 import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11 12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
13
+import com.reactnativenavigation.parse.AnimationOptions;
12 14
 import com.reactnativenavigation.parse.Options;
13 15
 import com.reactnativenavigation.parse.params.Bool;
14 16
 import com.reactnativenavigation.parse.params.Text;
15 17
 import com.reactnativenavigation.utils.ViewHelper;
18
+import com.reactnativenavigation.views.Component;
16 19
 import com.reactnativenavigation.views.ReactComponent;
17 20
 import com.reactnativenavigation.views.StackLayout;
18 21
 
19 22
 import org.assertj.core.api.iterable.Extractor;
23
+import org.json.JSONObject;
20 24
 import org.junit.Test;
21 25
 import org.mockito.ArgumentCaptor;
26
+import org.mockito.Mockito;
22 27
 
23 28
 import javax.annotation.Nullable;
24 29
 
25 30
 import static org.assertj.core.api.Java6Assertions.assertThat;
26 31
 import static org.mockito.ArgumentMatchers.eq;
32
+import static org.mockito.Mockito.mock;
27 33
 import static org.mockito.Mockito.spy;
28 34
 import static org.mockito.Mockito.times;
29 35
 import static org.mockito.Mockito.verify;
@@ -35,6 +41,7 @@ public class StackControllerTest extends BaseTest {
35 41
     private ViewController child1;
36 42
     private ViewController child2;
37 43
     private ViewController child3;
44
+    private NavigationAnimator animator;
38 45
 
39 46
     @Override
40 47
     public void beforeEach() {
@@ -453,12 +460,89 @@ public class StackControllerTest extends BaseTest {
453 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 534
     private void assertContainsOnlyId(String... ids) {
457 535
         assertThat(uut.size()).isEqualTo(ids.length);
458 536
         assertThat(uut.getChildControllers()).extracting((Extractor<ViewController, String>) ViewController::getId).containsOnly(ids);
459 537
     }
460 538
 
461 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,20 +73,23 @@ public class TitleBarTest extends BaseTest {
73 73
 
74 74
     @Test
75 75
     public void setButton_setsTextButton() {
76
-        uut.setButtons(leftButton(leftButton), rightButtons(textButton));
76
+        uut.setRightButtons(rightButtons(textButton));
77
+        uut.setLeftButtons(leftButton(leftButton));
77 78
         assertThat(uut.getMenu().getItem(0).getTitle()).isEqualTo(textButton.title.get());
78 79
     }
79 80
 
80 81
     @Test
81 82
     public void setButton_setsCustomButton() {
82
-        uut.setButtons(leftButton(leftButton), rightButtons(customButton));
83
+        uut.setLeftButtons(leftButton(leftButton));
84
+        uut.setRightButtons(rightButtons(customButton));
83 85
         ReactView btnView = (ReactView) uut.getMenu().getItem(0).getActionView();
84 86
         assertThat(btnView.getComponentName()).isEqualTo(customButton.component.get());
85 87
     }
86 88
 
87 89
     @Test
88 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 93
         uut.clear();
91 94
         for (TopBarButtonController controller : buttonControllers.values()) {
92 95
             verify(controller, times(1)).destroy();
@@ -95,22 +98,28 @@ public class TitleBarTest extends BaseTest {
95 98
 
96 99
     @Test
97 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 105
         verify(buttonControllers.get(customButton.id), times(1)).destroy();
101 106
     }
102 107
 
103 108
     @Test
104 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 114
         verify(buttonControllers.get(leftButton.id), times(0)).destroy();
108 115
     }
109 116
 
110 117
     @Test
111 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 123
         for (TopBarButtonController controller : buttonControllers.values()) {
115 124
             verify(controller, times(1)).destroy();
116 125
         }
@@ -119,14 +128,17 @@ public class TitleBarTest extends BaseTest {
119 128
 
120 129
     @Test
121 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 135
         verify(buttonControllers.get(leftButton.id), times(1)).destroy();
125 136
     }
126 137
 
127 138
     @Test
128 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 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,7 +92,8 @@ public class TopBarTest extends BaseTest {
92 92
 
93 93
     @Test
94 94
     public void button_TitleBarButtonOnClickInvoked() throws Exception {
95
-        uut.setButtons(new ArrayList<>(), rightButtons);
95
+        uut.setLeftButtons(new ArrayList<>());
96
+        uut.setRightButtons(rightButtons);
96 97
         for (int i = 0; i < rightButtons.size(); i++) {
97 98
             Button rightButton = rightButtons.get(i);
98 99
             TitleBarHelper.getRightButton(uut.getTitleBar(), i).callOnClick();