Browse Source

Fix TopBar visibility and merge options issues

This commit started with a small fix to a TopBar visibility issue detailed in #3971 which unveiled
a few issues with how options are resolved and merged.

TopBar visibility
The initial TopBar visibility issue was a result of hide animators now being cancelled when pushing another screen.
Another issue was that if the TopBar was not measured (Initial stack child was shown with `TopBar.visible = false`),
the start value passed to the Y translation was 0. This commit makes sure the TopBar show animation starts after the TopBar is measured.

Options issues
When resolving current issues in ParentControllers, the options of the current child were wrongfully taken into account.
This commit changes options resolve logic so that initial options (and options dynamically merged to them via mergeOptions call) are merged.
Guy Carmeli 6 years ago
parent
commit
cbcdda075f
16 changed files with 108 additions and 75 deletions
  1. 12
    6
      lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarAnimator.java
  2. 14
    1
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/StackOptionsPresenter.java
  3. 16
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/UiUtils.java
  4. 8
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java
  5. 3
    4
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java
  6. 3
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java
  7. 3
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java
  8. 2
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/topbar/TopBar.java
  9. 3
    3
      lib/android/app/src/main/java/com/reactnativenavigation/views/toptabs/TopTabs.java
  10. 6
    0
      lib/android/app/src/test/java/com/reactnativenavigation/TestUtils.java
  11. 16
    16
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/BottomTabsControllerTest.java
  12. 3
    9
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java
  13. 3
    5
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackOptionsPresenterTest.java
  14. 10
    24
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java
  15. 5
    3
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerTest.java
  16. 1
    1
      playground/src/app.js

+ 12
- 6
lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarAnimator.java View File

12
 import android.view.animation.LinearInterpolator;
12
 import android.view.animation.LinearInterpolator;
13
 
13
 
14
 import com.reactnativenavigation.parse.AnimationOptions;
14
 import com.reactnativenavigation.parse.AnimationOptions;
15
+import com.reactnativenavigation.utils.UiUtils;
15
 import com.reactnativenavigation.views.topbar.TopBar;
16
 import com.reactnativenavigation.views.topbar.TopBar;
16
 
17
 
17
 import javax.annotation.Nullable;
18
 import javax.annotation.Nullable;
41
     }
42
     }
42
 
43
 
43
     public void show(AnimationOptions options) {
44
     public void show(AnimationOptions options) {
44
-        if (options.hasValue() && (!options.id.hasValue() || options.id.get().equals(stackId))) {
45
-            showAnimator = options.getAnimation(topBar);
46
-        } else {
47
-            showAnimator = getDefaultShowAnimator(-1 * topBar.getMeasuredHeight(), DECELERATE, DURATION);
48
-        }
49
-        show();
45
+        topBar.setVisibility(View.VISIBLE);
46
+        UiUtils.runOnMeasured(topBar, () -> {
47
+            if (options.hasValue() && (!options.id.hasValue() || options.id.get().equals(stackId))) {
48
+                showAnimator = options.getAnimation(topBar);
49
+            } else {
50
+                showAnimator = getDefaultShowAnimator(-1 * topBar.getHeight(), DECELERATE, DURATION);
51
+            }
52
+            show();
53
+        });
50
     }
54
     }
51
 
55
 
52
     public void show(float startTranslation) {
56
     public void show(float startTranslation) {
62
             }
66
             }
63
         });
67
         });
64
         topBar.resetAnimationOptions();
68
         topBar.resetAnimationOptions();
69
+        if (isAnimatingHide()) hideAnimator.cancel();
65
         showAnimator.start();
70
         showAnimator.start();
66
     }
71
     }
67
 
72
 
96
                 onAnimationEnd.run();
101
                 onAnimationEnd.run();
97
             }
102
             }
98
         });
103
         });
104
+        if (isAnimatingShow()) showAnimator.cancel();
99
         hideAnimator.start();
105
         hideAnimator.start();
100
     }
106
     }
101
 
107
 

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

113
                 ((Component) view).drawBelowTopBar(topBar);
113
                 ((Component) view).drawBelowTopBar(topBar);
114
             }
114
             }
115
         }
115
         }
116
-        applyTopBarVisibility(withDefault.topBar, withDefault.animations, options);
116
+    }
117
+
118
+    public void applyInitialChildLayoutOptions(Options options) {
119
+        Options withDefault = options.copy().withDefaultOptions(defaultOptions);
120
+        setInitialTopBarVisibility(withDefault.topBar);
117
     }
121
     }
118
 
122
 
119
     public void applyChildOptions(Options options, Component child) {
123
     public void applyChildOptions(Options options, Component child) {
203
         }
207
         }
204
     }
208
     }
205
 
209
 
210
+    private void setInitialTopBarVisibility(TopBarOptions options) {
211
+        if (options.visible.isFalse()) {
212
+            topBar.hide();
213
+        }
214
+        if (options.visible.isTrueOrUndefined()) {
215
+            topBar.show();
216
+        }
217
+    }
218
+
206
     private void applyTopBarVisibility(TopBarOptions options, AnimationsOptions animationOptions, Options componentOptions) {
219
     private void applyTopBarVisibility(TopBarOptions options, AnimationsOptions animationOptions, Options componentOptions) {
207
         if (options.visible.isFalse()) {
220
         if (options.visible.isFalse()) {
208
             if (options.animate.isTrueOrUndefined() && componentOptions.animations.push.enable.isTrueOrUndefined()) {
221
             if (options.animate.isTrueOrUndefined() && componentOptions.animations.push.enable.isTrueOrUndefined()) {

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

30
         });
30
         });
31
     }
31
     }
32
 
32
 
33
+    public static void runOnMeasured(View view, Runnable task) {
34
+        if (view.getHeight() > 0 && view.getWidth() > 0) {
35
+            task.run();
36
+        } else {
37
+            view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
38
+                @Override
39
+                public void onGlobalLayout() {
40
+                    if (view.getHeight() > 0 && view.getWidth() > 0) {
41
+                        view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
42
+                        task.run();
43
+                    }
44
+                }
45
+            });
46
+        }
47
+    }
48
+
33
 	public static void runOnMainThread(Runnable runnable) {
49
 	public static void runOnMainThread(Runnable runnable) {
34
 		new Handler(Looper.getMainLooper()).post(runnable);
50
 		new Handler(Looper.getMainLooper()).post(runnable);
35
 	}
51
 	}

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

4
 import android.support.annotation.Nullable;
4
 import android.support.annotation.Nullable;
5
 import android.view.View;
5
 import android.view.View;
6
 import android.view.ViewGroup;
6
 import android.view.ViewGroup;
7
+import android.view.ViewManager;
7
 import android.view.ViewParent;
8
 import android.view.ViewParent;
8
 
9
 
9
 import com.facebook.react.views.view.ReactViewBackgroundDrawable;
10
 import com.facebook.react.views.view.ReactViewBackgroundDrawable;
129
         }
130
         }
130
         throw new RuntimeException(view.getBackground().getClass().getSimpleName() + " is not ReactViewBackgroundDrawable");
131
         throw new RuntimeException(view.getBackground().getClass().getSimpleName() + " is not ReactViewBackgroundDrawable");
131
     }
132
     }
133
+
134
+    public static void removeFromParent(View view) {
135
+        ViewParent parent = view.getParent();
136
+        if (parent != null) {
137
+            ((ViewManager) parent).removeView(view);
138
+        }
139
+    }
132
 }
140
 }

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

42
     @Override
42
     @Override
43
     @CheckResult
43
     @CheckResult
44
     public Options resolveCurrentOptions() {
44
     public Options resolveCurrentOptions() {
45
-	    if (CollectionUtils.isNullOrEmpty(getChildControllers())) return options;
45
+	    if (CollectionUtils.isNullOrEmpty(getChildControllers())) return initialOptions;
46
         return getCurrentChild()
46
         return getCurrentChild()
47
                 .resolveCurrentOptions()
47
                 .resolveCurrentOptions()
48
-                .copy()
49
-                .mergeWith(options);
48
+                .mergeWith(initialOptions);
50
     }
49
     }
51
 
50
 
52
     @Override
51
     @Override
97
 
96
 
98
     @CallSuper
97
     @CallSuper
99
     public void applyChildOptions(Options options, Component child) {
98
     public void applyChildOptions(Options options, Component child) {
100
-        this.options = this.options.mergeWith(options);
99
+        this.options = this.initialOptions.mergeWith(options);
101
         if (isRoot()) {
100
         if (isRoot()) {
102
             presenter.applyRootOptions(getView(), options);
101
             presenter.applyRootOptions(getView(), options);
103
         }
102
         }

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

45
         boolean onViewDisappear(View view);
45
         boolean onViewDisappear(View view);
46
     }
46
     }
47
 
47
 
48
-    Options initialOptions;
48
+    protected Options initialOptions;
49
     public Options options;
49
     public Options options;
50
 
50
 
51
     private final Activity activity;
51
     private final Activity activity;
106
 
106
 
107
     @CallSuper
107
     @CallSuper
108
     public void mergeOptions(Options options) {
108
     public void mergeOptions(Options options) {
109
+        this.initialOptions = this.initialOptions.mergeWith(options);
109
         this.options = this.options.mergeWith(options);
110
         this.options = this.options.mergeWith(options);
110
         if (view != null) applyOptions(this.options);
111
         if (view != null) applyOptions(this.options);
111
         this.options.clearOneTimeOptions();
112
         this.options.clearOneTimeOptions();
113
+        initialOptions.clearOneTimeOptions();
112
     }
114
     }
113
 
115
 
114
     @CallSuper
116
     @CallSuper

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

131
 
131
 
132
     public void push(ViewController child, CommandListener listener) {
132
     public void push(ViewController child, CommandListener listener) {
133
         final ViewController toRemove = stack.peek();
133
         final ViewController toRemove = stack.peek();
134
-        backButtonHelper.addToPushedChild(child);
134
+        if (size() > 0) backButtonHelper.addToPushedChild(child);
135
         child.setParentController(this);
135
         child.setParentController(this);
136
         stack.push(child.getId(), child);
136
         stack.push(child.getId(), child);
137
         Options resolvedOptions = resolveCurrentOptions(presenter.getDefaultOptions());
137
         Options resolvedOptions = resolveCurrentOptions(presenter.getDefaultOptions());
166
         view.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
166
         view.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
167
         child.setWaitForRender(resolvedOptions.animations.push.waitForRender);
167
         child.setWaitForRender(resolvedOptions.animations.push.waitForRender);
168
         presenter.applyLayoutParamsOptions(resolvedOptions, view);
168
         presenter.applyLayoutParamsOptions(resolvedOptions, view);
169
+        if (size() == 1) presenter.applyInitialChildLayoutOptions(resolvedOptions);
169
         getView().addView(view, getView().getChildCount() - 1);
170
         getView().addView(view, getView().getChildCount() - 1);
170
     }
171
     }
171
 
172
 
310
         child.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
311
         child.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
311
         Options options = resolveCurrentOptions();
312
         Options options = resolveCurrentOptions();
312
         presenter.applyLayoutParamsOptions(options, child);
313
         presenter.applyLayoutParamsOptions(options, child);
314
+        presenter.applyInitialChildLayoutOptions(options);
313
         stackLayout.addView(child, 0);
315
         stackLayout.addView(child, 0);
314
     }
316
     }
315
 
317
 

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

265
     }
265
     }
266
 
266
 
267
     public void hideAnimate(AnimationOptions options, Runnable onAnimationEnd) {
267
     public void hideAnimate(AnimationOptions options, Runnable onAnimationEnd) {
268
+        if (!visible()) return;
268
         animator.hide(options, onAnimationEnd);
269
         animator.hide(options, onAnimationEnd);
269
     }
270
     }
270
 
271
 
275
     }
276
     }
276
 
277
 
277
     public void clearTopTabs() {
278
     public void clearTopTabs() {
278
-        topTabs.clear(this);
279
+        topTabs.clear();
279
     }
280
     }
280
 
281
 
281
     @VisibleForTesting
282
     @VisibleForTesting

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

4
 import android.graphics.Typeface;
4
 import android.graphics.Typeface;
5
 import android.support.design.widget.TabLayout;
5
 import android.support.design.widget.TabLayout;
6
 import android.support.v4.view.ViewPager;
6
 import android.support.v4.view.ViewPager;
7
-import android.view.ViewManager;
8
 
7
 
9
 import com.reactnativenavigation.parse.params.Colour;
8
 import com.reactnativenavigation.parse.params.Colour;
10
 import com.reactnativenavigation.parse.params.Number;
9
 import com.reactnativenavigation.parse.params.Number;
10
+import com.reactnativenavigation.utils.ViewUtils;
11
 import com.reactnativenavigation.views.topbar.TopBar;
11
 import com.reactnativenavigation.views.topbar.TopBar;
12
 
12
 
13
 public class TopTabs extends TabLayout {
13
 public class TopTabs extends TabLayout {
49
         }
49
         }
50
     }
50
     }
51
 
51
 
52
-    public void clear(ViewManager parent) {
52
+    public void clear() {
53
         setupWithViewPager(null);
53
         setupWithViewPager(null);
54
-        parent.removeView(this);
54
+        ViewUtils.removeFromParent(this);
55
     }
55
     }
56
 
56
 
57
     public void init(ViewPager viewPager) {
57
     public void init(ViewPager viewPager) {

+ 6
- 0
lib/android/app/src/test/java/com/reactnativenavigation/TestUtils.java View File

7
 import com.reactnativenavigation.mocks.TopBarBackgroundViewCreatorMock;
7
 import com.reactnativenavigation.mocks.TopBarBackgroundViewCreatorMock;
8
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
8
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
9
 import com.reactnativenavigation.parse.Options;
9
 import com.reactnativenavigation.parse.Options;
10
+import com.reactnativenavigation.parse.params.Bool;
10
 import com.reactnativenavigation.presentation.StackOptionsPresenter;
11
 import com.reactnativenavigation.presentation.StackOptionsPresenter;
11
 import com.reactnativenavigation.utils.ImageLoader;
12
 import com.reactnativenavigation.utils.ImageLoader;
12
 import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
13
 import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
14
+import com.reactnativenavigation.viewcontrollers.ViewController;
13
 import com.reactnativenavigation.viewcontrollers.stack.StackControllerBuilder;
15
 import com.reactnativenavigation.viewcontrollers.stack.StackControllerBuilder;
14
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarBackgroundViewController;
16
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarBackgroundViewController;
15
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarController;
17
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarController;
34
                 .setStackPresenter(new StackOptionsPresenter(activity, new TitleBarReactViewCreatorMock(), new TopBarButtonCreatorMock(), new ImageLoader(), new Options())                )
36
                 .setStackPresenter(new StackOptionsPresenter(activity, new TitleBarReactViewCreatorMock(), new TopBarButtonCreatorMock(), new ImageLoader(), new Options())                )
35
                 .setInitialOptions(new Options());
37
                 .setInitialOptions(new Options());
36
     }
38
     }
39
+
40
+    public static void hideBackButton(ViewController viewController) {
41
+        viewController.options.topBar.buttons.back.visible = new Bool(false);
42
+    }
37
 }
43
 }

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

26
 import com.reactnativenavigation.utils.CommandListenerAdapter;
26
 import com.reactnativenavigation.utils.CommandListenerAdapter;
27
 import com.reactnativenavigation.utils.ImageLoader;
27
 import com.reactnativenavigation.utils.ImageLoader;
28
 import com.reactnativenavigation.utils.OptionHelper;
28
 import com.reactnativenavigation.utils.OptionHelper;
29
+import com.reactnativenavigation.utils.ViewUtils;
29
 import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabsController;
30
 import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabsController;
30
 import com.reactnativenavigation.viewcontrollers.stack.StackController;
31
 import com.reactnativenavigation.viewcontrollers.stack.StackController;
31
 import com.reactnativenavigation.views.BottomTabs;
32
 import com.reactnativenavigation.views.BottomTabs;
38
 import java.util.Arrays;
39
 import java.util.Arrays;
39
 import java.util.List;
40
 import java.util.List;
40
 
41
 
42
+import static com.reactnativenavigation.TestUtils.hideBackButton;
41
 import static org.assertj.core.api.Java6Assertions.assertThat;
43
 import static org.assertj.core.api.Java6Assertions.assertThat;
42
 import static org.mockito.ArgumentMatchers.any;
44
 import static org.mockito.ArgumentMatchers.any;
43
 import static org.mockito.ArgumentMatchers.eq;
45
 import static org.mockito.ArgumentMatchers.eq;
80
         tabs = createTabs();
82
         tabs = createTabs();
81
         presenter = spy(new BottomTabsOptionsPresenter(tabs, new Options()));
83
         presenter = spy(new BottomTabsOptionsPresenter(tabs, new Options()));
82
         uut = createBottomTabs();
84
         uut = createBottomTabs();
85
+        activity.setContentView(uut.getView());
83
     }
86
     }
84
 
87
 
85
     @Test
88
     @Test
158
 
161
 
159
     @Test
162
     @Test
160
     public void applyOptions_bottomTabsOptionsAreClearedAfterApply() {
163
     public void applyOptions_bottomTabsOptionsAreClearedAfterApply() {
164
+        ViewUtils.removeFromParent(uut.getView());
165
+
161
         Options options = new Options();
166
         Options options = new Options();
162
         options.bottomTabsOptions.backgroundColor = new Colour(Color.RED);
167
         options.bottomTabsOptions.backgroundColor = new Colour(Color.RED);
163
         child1.mergeOptions(options);
168
         child1.mergeOptions(options);
235
 
240
 
236
         SimpleViewController stackChild = new SimpleViewController(activity, childRegistry, "stackChild", new Options());
241
         SimpleViewController stackChild = new SimpleViewController(activity, childRegistry, "stackChild", new Options());
237
         SimpleViewController stackChild2 = new SimpleViewController(activity, childRegistry, "stackChild", new Options());
242
         SimpleViewController stackChild2 = new SimpleViewController(activity, childRegistry, "stackChild", new Options());
243
+
238
         disablePushAnimation(stackChild, stackChild2);
244
         disablePushAnimation(stackChild, stackChild2);
245
+        hideBackButton(stackChild2);
239
 
246
 
240
         child4.push(stackChild, new CommandListenerAdapter());
247
         child4.push(stackChild, new CommandListenerAdapter());
241
         assertThat(child4.size()).isOne();
248
         assertThat(child4.size()).isOne();
245
 
252
 
246
     @Test
253
     @Test
247
     public void deepChildOptionsAreApplied() {
254
     public void deepChildOptionsAreApplied() {
248
-        BottomTabsController spy = spy(uut);
249
-        activity.setContentView(spy.getView());
250
-
251
         child6.options.topBar.drawBehind = new Bool(false);
255
         child6.options.topBar.drawBehind = new Bool(false);
252
         disablePushAnimation(child6);
256
         disablePushAnimation(child6);
253
         child4.push(child6, new CommandListenerAdapter());
257
         child4.push(child6, new CommandListenerAdapter());
254
         assertThat(child4.size()).isOne();
258
         assertThat(child4.size()).isOne();
255
 
259
 
256
-
257
-        verify(spy, times(1)).onViewAppeared();
258
-        assertThat(spy.getSelectedIndex()).isZero();
260
+        assertThat(uut.getSelectedIndex()).isZero();
259
         verify(child6, times(0)).onViewAppeared();
261
         verify(child6, times(0)).onViewAppeared();
260
         assertThat(child4.getTopBar().getHeight())
262
         assertThat(child4.getTopBar().getHeight())
261
                 .isNotZero()
263
                 .isNotZero()
264
 
266
 
265
     @Test
267
     @Test
266
     public void oneTimeOptionsAreAppliedOnce() {
268
     public void oneTimeOptionsAreAppliedOnce() {
267
-        initialOptions.bottomTabsOptions.currentTabIndex = new Number(1);
268
-        BottomTabsController spy = spy(createBottomTabs());
269
-        spy.onViewAppeared();
270
-
271
-        assertThat(spy.getSelectedIndex()).isOne();
272
-        spy.selectTab(0);
273
-        tabs.get(0).onViewAppeared();
274
-        verify(spy).clearOptions();
275
-        assertThat(spy.getSelectedIndex()).isZero();
276
-        assertThat(spy.options.bottomTabsOptions.currentTabIndex.hasValue()).isFalse();
269
+        Options options = new Options();
270
+        options.bottomTabsOptions.currentTabIndex = new Number(1);
271
+
272
+        assertThat(uut.getSelectedIndex()).isZero();
273
+        uut.mergeOptions(options);
274
+        assertThat(uut.getSelectedIndex()).isOne();
275
+        assertThat(uut.options.bottomTabsOptions.currentTabIndex.hasValue()).isFalse();
276
+        assertThat(uut.initialOptions.bottomTabsOptions.currentTabIndex.hasValue()).isFalse();
277
     }
277
     }
278
 
278
 
279
     @NonNull
279
     @NonNull

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

187
     @Test
187
     @Test
188
     public void resolveCurrentOptions_returnOptionsIfNoChildren() {
188
     public void resolveCurrentOptions_returnOptionsIfNoChildren() {
189
         assertThat(uut.getChildControllers().size()).isZero();
189
         assertThat(uut.getChildControllers().size()).isZero();
190
-        assertThat(uut.resolveCurrentOptions()).isEqualTo(uut.options);
190
+        assertThat(uut.resolveCurrentOptions()).isEqualTo(uut.initialOptions);
191
     }
191
     }
192
 
192
 
193
     @Test
193
     @Test
194
     public void resolveCurrentOptions_mergesWithCurrentChild() {
194
     public void resolveCurrentOptions_mergesWithCurrentChild() {
195
         ViewController child1 = Mockito.mock(ViewController.class);
195
         ViewController child1 = Mockito.mock(ViewController.class);
196
         when(child1.getView()).thenReturn(new FrameLayout(activity));
196
         when(child1.getView()).thenReturn(new FrameLayout(activity));
197
-        Options copiedChildOptions = spy(new Options());
198
-        Options childOptions = spy(new Options() {
199
-            @Override
200
-            public Options copy() {
201
-                return copiedChildOptions;
202
-            }
203
-        });
197
+        Options childOptions = spy(new Options());
204
         when(child1.resolveCurrentOptions()).thenReturn(childOptions);
198
         when(child1.resolveCurrentOptions()).thenReturn(childOptions);
205
 
199
 
206
         children.add(child1);
200
         children.add(child1);
209
         assertThat(uut.getCurrentChild()).isEqualTo(child1);
203
         assertThat(uut.getCurrentChild()).isEqualTo(child1);
210
         uut.resolveCurrentOptions();
204
         uut.resolveCurrentOptions();
211
         verify(child1).resolveCurrentOptions();
205
         verify(child1).resolveCurrentOptions();
212
-        verify(copiedChildOptions).mergeWith(uut.options);
206
+        verify(childOptions).mergeWith(uut.initialOptions);
213
     }
207
     }
214
 
208
 
215
     @Test
209
     @Test

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

34
 import org.json.JSONObject;
34
 import org.json.JSONObject;
35
 import org.junit.Test;
35
 import org.junit.Test;
36
 import org.mockito.ArgumentCaptor;
36
 import org.mockito.ArgumentCaptor;
37
-import org.mockito.Mockito;
38
 
37
 
39
 import java.util.ArrayList;
38
 import java.util.ArrayList;
40
 import java.util.Collections;
39
 import java.util.Collections;
279
     }
278
     }
280
 
279
 
281
     @Test
280
     @Test
282
-    public void applyLayoutParamsOptions() {
281
+    public void applyInitialChildLayoutOptions() {
283
         Options options = new Options();
282
         Options options = new Options();
284
         options.topBar.visible = new Bool(false);
283
         options.topBar.visible = new Bool(false);
285
-        options.topBar.animate = new Bool(false);
286
-        View view = Mockito.mock(View.class, Mockito.withSettings().extraInterfaces(com.reactnativenavigation.views.Component.class));
284
+        options.topBar.animate = new Bool(true);
287
 
285
 
288
-        uut.applyLayoutParamsOptions(options, view);
286
+        uut.applyInitialChildLayoutOptions(options);
289
         verify(topBar).hide();
287
         verify(topBar).hide();
290
     }
288
     }
291
 
289
 

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

6
 
6
 
7
 import com.reactnativenavigation.BaseTest;
7
 import com.reactnativenavigation.BaseTest;
8
 import com.reactnativenavigation.TestUtils;
8
 import com.reactnativenavigation.TestUtils;
9
+import com.reactnativenavigation.mocks.SimpleViewController;
9
 import com.reactnativenavigation.mocks.TestComponentViewCreator;
10
 import com.reactnativenavigation.mocks.TestComponentViewCreator;
10
 import com.reactnativenavigation.mocks.TestReactView;
11
 import com.reactnativenavigation.mocks.TestReactView;
11
 import com.reactnativenavigation.parse.Options;
12
 import com.reactnativenavigation.parse.Options;
65
 
66
 
66
         stack = spy(TestUtils.newStackController(activity).build());
67
         stack = spy(TestUtils.newStackController(activity).build());
67
         stack.ensureViewIsCreated();
68
         stack.ensureViewIsCreated();
68
-        stack.push(uut, new CommandListenerAdapter());
69
-        uut.setParentController(stack);
70
     }
69
     }
71
 
70
 
72
     @NonNull
71
     @NonNull
209
 
208
 
210
     @Test
209
     @Test
211
     public void applyOptions_tabsAreRemovedAfterViewDisappears() {
210
     public void applyOptions_tabsAreRemovedAfterViewDisappears() {
212
-        stack.getView().removeAllViews();
213
-
214
-        StackController stackController = spy(TestUtils.newStackController(activity).build());
211
+        StackController stackController = TestUtils.newStackController(activity).build();
215
         stackController.ensureViewIsCreated();
212
         stackController.ensureViewIsCreated();
216
-        ComponentViewController first = new ComponentViewController(
217
-                activity,
218
-                childRegistry,
219
-                "firstScreen",
220
-                "comp1",
221
-                new TestComponentViewCreator(),
222
-                new Options(),
223
-                new OptionsPresenter(activity, new Options())
224
-        );
225
-        first.options.animations.push.enable = new Bool(false);
226
-        uut.options.animations.push.enable = new Bool(false);
213
+        ViewController first = new SimpleViewController(activity, childRegistry, "first", Options.EMPTY);
214
+        disablePushAnimation(first, uut);
227
         stackController.push(first, new CommandListenerAdapter());
215
         stackController.push(first, new CommandListenerAdapter());
228
         stackController.push(uut, new CommandListenerAdapter());
216
         stackController.push(uut, new CommandListenerAdapter());
229
 
217
 
230
-        first.ensureViewIsCreated();
231
-        uut.ensureViewIsCreated();
232
         uut.onViewAppeared();
218
         uut.onViewAppeared();
233
 
219
 
234
         assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isTrue();
220
         assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isTrue();
235
-        stackController.pop(Options.EMPTY, new CommandListenerAdapter() {
236
-            @Override
237
-            public void onSuccess(String childId) {
238
-                assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isFalse();
239
-            }
240
-        });
221
+        disablePopAnimation(uut);
222
+        stackController.pop(Options.EMPTY, new CommandListenerAdapter());
223
+
224
+        first.onViewAppeared();
225
+
226
+        assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isFalse();
241
     }
227
     }
242
 
228
 
243
     @Test
229
     @Test

+ 5
- 3
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerTest.java View File

22
 import com.reactnativenavigation.utils.ImageLoader;
22
 import com.reactnativenavigation.utils.ImageLoader;
23
 import com.reactnativenavigation.utils.TitleBarHelper;
23
 import com.reactnativenavigation.utils.TitleBarHelper;
24
 import com.reactnativenavigation.utils.ViewHelper;
24
 import com.reactnativenavigation.utils.ViewHelper;
25
+import com.reactnativenavigation.utils.ViewUtils;
25
 import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
26
 import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
26
 import com.reactnativenavigation.viewcontrollers.ParentController;
27
 import com.reactnativenavigation.viewcontrollers.ParentController;
27
 import com.reactnativenavigation.viewcontrollers.ViewController;
28
 import com.reactnativenavigation.viewcontrollers.ViewController;
82
         child3 = spy(new SimpleViewController(activity, childRegistry, "child3", new Options()));
83
         child3 = spy(new SimpleViewController(activity, childRegistry, "child3", new Options()));
83
         child4 = spy(new SimpleViewController(activity, childRegistry, "child4", new Options()));
84
         child4 = spy(new SimpleViewController(activity, childRegistry, "child4", new Options()));
84
         uut = createStack();
85
         uut = createStack();
85
-        uut.ensureViewIsCreated();
86
+        activity.setContentView(uut.getView());
86
     }
87
     }
87
 
88
 
88
     @Test
89
     @Test
140
         child2.options.topBar.buttons.left = new ArrayList<>(Collections.singleton(TitleBarHelper.iconButton("someButton", "icon.png")));
141
         child2.options.topBar.buttons.left = new ArrayList<>(Collections.singleton(TitleBarHelper.iconButton("someButton", "icon.png")));
141
 
142
 
142
         uut.push(child2, new CommandListenerAdapter());
143
         uut.push(child2, new CommandListenerAdapter());
143
-        child2.onViewAppeared();
144
         assertThat(topBarController.getView().getTitleBar().getNavigationIcon()).isNotNull();
144
         assertThat(topBarController.getView().getTitleBar().getNavigationIcon()).isNotNull();
145
-        verify(topBarController.getView(), times(1)).setLeftButtons(any());
146
         verify(topBarController.getView(), times(0)).setBackButton(any());
145
         verify(topBarController.getView(), times(0)).setBackButton(any());
147
     }
146
     }
148
 
147
 
674
     @Test
673
     @Test
675
     public void pop_doesNotAnimateTopBarIfScreenIsPushedWithoutAnimation() {
674
     public void pop_doesNotAnimateTopBarIfScreenIsPushedWithoutAnimation() {
676
         uut.ensureViewIsCreated();
675
         uut.ensureViewIsCreated();
676
+        disablePushAnimation(child1, child2);
677
 
677
 
678
         child1.options.topBar.visible = new Bool(false);
678
         child1.options.topBar.visible = new Bool(false);
679
         child1.options.topBar.animate = new Bool(false);
679
         child1.options.topBar.animate = new Bool(false);
720
 
720
 
721
     @Test
721
     @Test
722
     public void stackCanBePushed() {
722
     public void stackCanBePushed() {
723
+        ViewUtils.removeFromParent(uut.getView());
723
         StackController parent = createStack("someStack");
724
         StackController parent = createStack("someStack");
724
         parent.ensureViewIsCreated();
725
         parent.ensureViewIsCreated();
725
         parent.push(uut, new CommandListenerAdapter());
726
         parent.push(uut, new CommandListenerAdapter());
729
 
730
 
730
     @Test
731
     @Test
731
     public void applyOptions_applyOnlyOnFirstStack() {
732
     public void applyOptions_applyOnlyOnFirstStack() {
733
+        ViewUtils.removeFromParent(uut.getView());
732
         StackController parent = spy(createStack("someStack"));
734
         StackController parent = spy(createStack("someStack"));
733
         parent.ensureViewIsCreated();
735
         parent.ensureViewIsCreated();
734
         parent.push(uut, new CommandListenerAdapter());
736
         parent.push(uut, new CommandListenerAdapter());

+ 1
- 1
playground/src/app.js View File

38
         }
38
         }
39
       },
39
       },
40
       _animations: {
40
       _animations: {
41
-        startApp: {
41
+        setRoot: {
42
           y: {
42
           y: {
43
             from: 1000,
43
             from: 1000,
44
             to: 0,
44
             to: 0,