Browse Source

Top bar options changes (#2771)

* Rename TopBar.animateHide to animate

also fix some options in playground app

* Consolidate topBar visibility in childWillDisappear

* Rename BottomTabs.animateHide to animate
Guy Carmeli 6 years ago
parent
commit
e4ed6ca32f
No account linked to committer's email address
18 changed files with 155 additions and 100 deletions
  1. 3
    5
      lib/android/app/src/main/java/com/reactnativenavigation/anim/NavigationAnimator.java
  2. 16
    15
      lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarAnimator.java
  3. 7
    7
      lib/android/app/src/main/java/com/reactnativenavigation/parse/BottomTabsOptions.java
  4. 6
    6
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarOptions.java
  5. 12
    7
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java
  6. 22
    24
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java
  7. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java
  8. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java
  9. 13
    10
      lib/android/app/src/main/java/com/reactnativenavigation/views/StackLayout.java
  10. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java
  11. 7
    7
      lib/android/app/src/test/java/com/reactnativenavigation/parse/OptionsTest.java
  12. 1
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java
  13. 47
    0
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java
  14. 9
    3
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java
  15. 1
    7
      playground/src/app.js
  16. 2
    2
      playground/src/screens/OptionsScreen.js
  17. 1
    1
      playground/src/screens/TextScreen.js
  18. 4
    1
      playground/src/screens/WelcomeScreen.js

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

57
 
57
 
58
     public void animatePop(View view, @Nullable final NavigationAnimationListener animationListener) {
58
     public void animatePop(View view, @Nullable final NavigationAnimationListener animationListener) {
59
         ObjectAnimator alpha = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0);
59
         ObjectAnimator alpha = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0);
60
-        alpha.setInterpolator(ACCELERATE_INTERPOLATOR);
60
+        ObjectAnimator translationY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 0, this.translationY);
61
 
61
 
62
         AnimatorSet set = new AnimatorSet();
62
         AnimatorSet set = new AnimatorSet();
63
         set.addListener(new AnimatorListenerAdapter() {
63
         set.addListener(new AnimatorListenerAdapter() {
68
                 }
68
                 }
69
             }
69
             }
70
         });
70
         });
71
-        ObjectAnimator translationY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 0, this.translationY);
72
-        translationY.setInterpolator(ACCELERATE_INTERPOLATOR);
73
-        translationY.setDuration(DURATION);
74
-        alpha.setDuration(DURATION);
75
         set.playTogether(translationY, alpha);
71
         set.playTogether(translationY, alpha);
72
+        set.setDuration(DURATION);
73
+        set.setInterpolator(ACCELERATE_INTERPOLATOR);
76
         set.start();
74
         set.start();
77
     }
75
     }
78
 }
76
 }

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

20
 
20
 
21
     private TopBar topBar;
21
     private TopBar topBar;
22
     private View contentView;
22
     private View contentView;
23
+    private ObjectAnimator hideAnimator;
24
+    private ObjectAnimator showAnimator;
23
 
25
 
24
     public TopBarAnimator(TopBar topBar) {
26
     public TopBarAnimator(TopBar topBar) {
25
         this.topBar = topBar;
27
         this.topBar = topBar;
26
     }
28
     }
27
 
29
 
28
-    public TopBarAnimator(TopBar topBar, View contentView) {
29
-        this.topBar = topBar;
30
-        this.contentView = contentView;
31
-    }
32
-
33
     public void show() {
30
     public void show() {
34
         show(-1 * topBar.getMeasuredHeight(), decelerateInterpolator, DURATION_TOPBAR);
31
         show(-1 * topBar.getMeasuredHeight(), decelerateInterpolator, DURATION_TOPBAR);
35
     }
32
     }
36
 
33
 
37
     public void show(float startTranslation, TimeInterpolator interpolator, int duration) {
34
     public void show(float startTranslation, TimeInterpolator interpolator, int duration) {
38
-        ObjectAnimator topbarAnim = ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Y, startTranslation, 0);
39
-        topbarAnim.setInterpolator(interpolator);
40
-        topbarAnim.setDuration(duration);
35
+        showAnimator = ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Y, startTranslation, 0);
36
+        showAnimator.setInterpolator(interpolator);
37
+        showAnimator.setDuration(duration);
41
 
38
 
42
-        topbarAnim.addListener(new AnimatorListenerAdapter() {
39
+        showAnimator.addListener(new AnimatorListenerAdapter() {
43
 
40
 
44
             @Override
41
             @Override
45
             public void onAnimationStart(Animator animation) {
42
             public void onAnimationStart(Animator animation) {
55
                 }
52
                 }
56
             }
53
             }
57
         });
54
         });
58
-        topbarAnim.start();
55
+        showAnimator.start();
59
     }
56
     }
60
 
57
 
61
     public void hide() {
58
     public void hide() {
63
     }
60
     }
64
 
61
 
65
     void hide(float startTranslation, TimeInterpolator interpolator, int duration) {
62
     void hide(float startTranslation, TimeInterpolator interpolator, int duration) {
66
-        ObjectAnimator animator = ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Y, startTranslation, -1 * topBar.getMeasuredHeight());
67
-        animator.setInterpolator(interpolator);
68
-        animator.setDuration(duration);
63
+        hideAnimator = ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Y, startTranslation, -1 * topBar.getMeasuredHeight());
64
+        hideAnimator.setInterpolator(interpolator);
65
+        hideAnimator.setDuration(duration);
69
 
66
 
70
-        animator.addListener(new AnimatorListenerAdapter() {
67
+        hideAnimator.addListener(new AnimatorListenerAdapter() {
71
             @Override
68
             @Override
72
             public void onAnimationEnd(Animator animation) {
69
             public void onAnimationEnd(Animator animation) {
73
                 if (contentView != null) {
70
                 if (contentView != null) {
79
                 topBar.setVisibility(View.GONE);
76
                 topBar.setVisibility(View.GONE);
80
             }
77
             }
81
         });
78
         });
82
-        animator.start();
79
+        hideAnimator.start();
80
+    }
81
+
82
+    public boolean isRunning() {
83
+        return (hideAnimator != null && hideAnimator.isRunning()) || (showAnimator != null && showAnimator.isRunning());
83
     }
84
     }
84
 }
85
 }

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

18
         options.currentTabId = TextParser.parse(json, "currentTabId");
18
         options.currentTabId = TextParser.parse(json, "currentTabId");
19
 		options.currentTabIndex = NumberParser.parse(json,"currentTabIndex");
19
 		options.currentTabIndex = NumberParser.parse(json,"currentTabIndex");
20
 		options.visible = BoolParser.parse(json,"visible");
20
 		options.visible = BoolParser.parse(json,"visible");
21
-		options.animateHide = BoolParser.parse(json,"animateHide");
21
+		options.animate = BoolParser.parse(json,"animate");
22
         options.testId = TextParser.parse(json, "testID");
22
         options.testId = TextParser.parse(json, "testID");
23
 
23
 
24
 		return options;
24
 		return options;
27
     public Color backgroundColor = new NullColor();
27
     public Color backgroundColor = new NullColor();
28
     public Color tabColor = new NullColor();
28
     public Color tabColor = new NullColor();
29
     public Color selectedTabColor = new NullColor();
29
     public Color selectedTabColor = new NullColor();
30
-	Bool visible = new NullBool();
31
-	Bool animateHide = new NullBool();
30
+	public Bool visible = new NullBool();
31
+	public Bool animate = new NullBool();
32
 	public Number currentTabIndex = new NullNumber();
32
 	public Number currentTabIndex = new NullNumber();
33
 	public Text currentTabId = new NullText();
33
 	public Text currentTabId = new NullText();
34
     public Text testId = new NullText();
34
     public Text testId = new NullText();
43
 		if (other.visible.hasValue()) {
43
 		if (other.visible.hasValue()) {
44
 			visible = other.visible;
44
 			visible = other.visible;
45
 		}
45
 		}
46
-		if (other.animateHide.hasValue()) {
47
-			animateHide = other.animateHide;
46
+		if (other.animate.hasValue()) {
47
+			animate = other.animate;
48
 		}
48
 		}
49
         if (other.tabColor.hasValue()) {
49
         if (other.tabColor.hasValue()) {
50
             tabColor = other.tabColor;
50
             tabColor = other.tabColor;
67
         if (!visible.hasValue()) {
67
         if (!visible.hasValue()) {
68
             visible = defaultOptions.visible;
68
             visible = defaultOptions.visible;
69
         }
69
         }
70
-        if (!animateHide.hasValue()) {
71
-            animateHide = defaultOptions.animateHide;
70
+        if (!animate.hasValue()) {
71
+            animate = defaultOptions.animate;
72
         }
72
         }
73
         if (!tabColor.hasValue()) {
73
         if (!tabColor.hasValue()) {
74
             tabColor = defaultOptions.tabColor;
74
             tabColor = defaultOptions.tabColor;

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

25
         options.textFontSize = FractionParser.parse(json, "textFontSize");
25
         options.textFontSize = FractionParser.parse(json, "textFontSize");
26
         options.textFontFamily = typefaceManager.getTypeFace(json.optString("textFontFamily", ""));
26
         options.textFontFamily = typefaceManager.getTypeFace(json.optString("textFontFamily", ""));
27
         options.visible = BoolParser.parse(json, "visible");
27
         options.visible = BoolParser.parse(json, "visible");
28
-        options.animateHide = BoolParser.parse(json,"animateHide");
28
+        options.animate = BoolParser.parse(json,"animate");
29
         options.hideOnScroll = BoolParser.parse(json,"hideOnScroll");
29
         options.hideOnScroll = BoolParser.parse(json,"hideOnScroll");
30
         options.drawBehind = BoolParser.parse(json,"drawBehind");
30
         options.drawBehind = BoolParser.parse(json,"drawBehind");
31
         options.rightButtons = Button.parseJsonArray(json.optJSONArray("rightButtons"));
31
         options.rightButtons = Button.parseJsonArray(json.optJSONArray("rightButtons"));
42
     public Fraction textFontSize = new NullFraction();
42
     public Fraction textFontSize = new NullFraction();
43
     @Nullable public Typeface textFontFamily;
43
     @Nullable public Typeface textFontFamily;
44
     public Bool visible = new NullBool();
44
     public Bool visible = new NullBool();
45
-    public Bool animateHide = new NullBool();
45
+    public Bool animate = new NullBool();
46
     public Bool hideOnScroll = new NullBool();
46
     public Bool hideOnScroll = new NullBool();
47
     public Bool drawBehind = new NullBool();
47
     public Bool drawBehind = new NullBool();
48
     public ArrayList<Button> leftButtons;
48
     public ArrayList<Button> leftButtons;
62
         if (other.visible.hasValue()) {
62
         if (other.visible.hasValue()) {
63
             visible = other.visible;
63
             visible = other.visible;
64
         }
64
         }
65
-        if (other.animateHide.hasValue()) {
66
-            animateHide = other.animateHide;
65
+        if (other.animate.hasValue()) {
66
+            animate = other.animate;
67
         }
67
         }
68
         if (other.hideOnScroll.hasValue()) {
68
         if (other.hideOnScroll.hasValue()) {
69
             hideOnScroll = other.hideOnScroll;
69
             hideOnScroll = other.hideOnScroll;
90
             textFontFamily = defaultOptions.textFontFamily;
90
             textFontFamily = defaultOptions.textFontFamily;
91
         if (!visible.hasValue())
91
         if (!visible.hasValue())
92
             visible = defaultOptions.visible;
92
             visible = defaultOptions.visible;
93
-        if (!animateHide.hasValue())
94
-            animateHide = defaultOptions.animateHide;
93
+        if (!animate.hasValue())
94
+            animate = defaultOptions.animate;
95
         if (!hideOnScroll.hasValue())
95
         if (!hideOnScroll.hasValue())
96
             hideOnScroll = defaultOptions.hideOnScroll;
96
             hideOnScroll = defaultOptions.hideOnScroll;
97
         if (!drawBehind.hasValue())
97
         if (!drawBehind.hasValue())

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

1
 package com.reactnativenavigation.presentation;
1
 package com.reactnativenavigation.presentation;
2
 
2
 
3
-import android.view.View;
4
-
5
-import com.github.clans.fab.FloatingActionButton;
6
 import com.reactnativenavigation.parse.Button;
3
 import com.reactnativenavigation.parse.Button;
7
-import com.reactnativenavigation.parse.FabOptions;
8
 import com.reactnativenavigation.parse.Options;
4
 import com.reactnativenavigation.parse.Options;
9
 import com.reactnativenavigation.parse.TopBarOptions;
5
 import com.reactnativenavigation.parse.TopBarOptions;
10
 import com.reactnativenavigation.parse.TopTabOptions;
6
 import com.reactnativenavigation.parse.TopTabOptions;
11
 import com.reactnativenavigation.parse.TopTabsOptions;
7
 import com.reactnativenavigation.parse.TopTabsOptions;
12
-import com.reactnativenavigation.views.Fab;
13
 import com.reactnativenavigation.views.ReactComponent;
8
 import com.reactnativenavigation.views.ReactComponent;
14
 import com.reactnativenavigation.views.TopBar;
9
 import com.reactnativenavigation.views.TopBar;
15
 
10
 
24
         this.component = component;
19
         this.component = component;
25
     }
20
     }
26
 
21
 
22
+    public OptionsPresenter(TopBar topBar) {
23
+        this.topBar = topBar;
24
+    }
25
+
27
     public void applyOptions(Options options) {
26
     public void applyOptions(Options options) {
28
         applyButtons(options.topBarOptions.leftButtons, options.topBarOptions.rightButtons);
27
         applyButtons(options.topBarOptions.leftButtons, options.topBarOptions.rightButtons);
29
         applyTopBarOptions(options.topBarOptions);
28
         applyTopBarOptions(options.topBarOptions);
40
 
39
 
41
         topBar.setTitleTypeface(options.textFontFamily);
40
         topBar.setTitleTypeface(options.textFontFamily);
42
         if (options.visible.isFalse()) {
41
         if (options.visible.isFalse()) {
43
-            topBar.hide(options.animateHide);
42
+            topBar.hide(options.animate);
44
         }
43
         }
45
         if (options.visible.isTrueOrUndefined()) {
44
         if (options.visible.isTrueOrUndefined()) {
46
-            topBar.show(options.animateHide);
45
+            topBar.show(options.animate);
47
         }
46
         }
48
         if (options.drawBehind.isTrue()) {
47
         if (options.drawBehind.isTrue()) {
49
             component.drawBehindTopBar();
48
             component.drawBehindTopBar();
73
             topBar.setTopTabFontFamily(topTabOptions.tabIndex, topTabOptions.fontFamily);
72
             topBar.setTopTabFontFamily(topTabOptions.tabIndex, topTabOptions.fontFamily);
74
         }
73
         }
75
     }
74
     }
75
+
76
+    public void onChildWillDisappear(Options disappearing, Options appearing) {
77
+        if (disappearing.topBarOptions.visible.isTrueOrUndefined() && appearing.topBarOptions.visible.isFalse()) {
78
+            topBar.hide(disappearing.topBarOptions.animate);
79
+        }
80
+    }
76
 }
81
 }

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

24
     private static final NoOpPromise NO_OP = new NoOpPromise();
24
     private static final NoOpPromise NO_OP = new NoOpPromise();
25
     private final IdStack<ViewController> stack = new IdStack<>();
25
     private final IdStack<ViewController> stack = new IdStack<>();
26
     private final NavigationAnimator animator;
26
     private final NavigationAnimator animator;
27
-    private StackLayout stackLayout;
28
 
27
 
29
     public StackController(final Activity activity, String id, Options initialOptions) {
28
     public StackController(final Activity activity, String id, Options initialOptions) {
30
         super(activity, id, initialOptions);
29
         super(activity, id, initialOptions);
33
 
32
 
34
     @RestrictTo(RestrictTo.Scope.TESTS)
33
     @RestrictTo(RestrictTo.Scope.TESTS)
35
     TopBar getTopBar() {
34
     TopBar getTopBar() {
36
-        return stackLayout.getTopBar();
35
+        return getView().getTopBar();
37
     }
36
     }
38
 
37
 
39
     @RestrictTo(RestrictTo.Scope.TESTS)
38
     @RestrictTo(RestrictTo.Scope.TESTS)
40
-    StackLayout getStackLayout() {return stackLayout;}
39
+    StackLayout getStackLayout() {return getView();}
41
 
40
 
42
     @Override
41
     @Override
43
     public void applyOptions(Options options, ReactComponent component) {
42
     public void applyOptions(Options options, ReactComponent component) {
44
         super.applyOptions(options, component);
43
         super.applyOptions(options, component);
45
-        stackLayout.applyOptions(this.options, component);
44
+        getView().applyOptions(this.options, component);
46
         applyOnParentController(parentController ->
45
         applyOnParentController(parentController ->
47
                 ((ParentController) parentController).applyOptions(this.options.copy().clearTopBarOptions(), component)
46
                 ((ParentController) parentController).applyOptions(this.options.copy().clearTopBarOptions(), component)
48
         );
47
         );
49
-        fabOptionsPresenter.applyOptions(options.fabOptions, component, stackLayout);
48
+        fabOptionsPresenter.applyOptions(options.fabOptions, component, getView());
50
     }
49
     }
51
 
50
 
52
     @Override
51
     @Override
53
     void clearOptions() {
52
     void clearOptions() {
54
         super.clearOptions();
53
         super.clearOptions();
55
-        stackLayout.clearOptions();
54
+        getView().clearOptions();
56
     }
55
     }
57
 
56
 
58
     public void push(ViewController child, final Promise promise) {
57
     public void push(ViewController child, final Promise promise) {
93
             return;
92
             return;
94
         }
93
         }
95
 
94
 
96
-        final ViewController poppedTop = stack.pop();
97
-        final ViewController newTop = stack.peek();
98
-        popInternal(poppedTop, newTop);
95
+        final ViewController exitingController = stack.pop();
96
+        final ViewController enteringController = stack.peek();
97
+        popInternal(exitingController, enteringController);
99
 
98
 
100
-        finishPopping(poppedTop.getView(), poppedTop, promise);
99
+        finishPopping(exitingController.getView(), exitingController, promise);
101
     }
100
     }
102
 
101
 
103
-	private void animatePop(final Promise promise) {
102
+	void animatePop(final Promise promise) {
104
 		if (!canPop()) {
103
 		if (!canPop()) {
105
 			Navigator.rejectPromise(promise);
104
 			Navigator.rejectPromise(promise);
106
 			return;
105
 			return;
107
 		}
106
 		}
108
 
107
 
109
-		final ViewController poppedTop = stack.pop();
110
-        final ViewController newTop = stack.peek();
111
-        popInternal(poppedTop, newTop);
108
+		final ViewController exitingController = stack.pop();
109
+        final ViewController enteringController = stack.peek();
110
+        popInternal(exitingController, enteringController);
112
 
111
 
113
-        animator.animatePop(poppedTop.getView(), () -> finishPopping(poppedTop.getView(), poppedTop, promise));
112
+        animator.animatePop(exitingController.getView(), () -> finishPopping(exitingController.getView(), exitingController, promise));
114
 	}
113
 	}
115
 
114
 
116
-    private void popInternal(ViewController poppedTop, ViewController newTop) {
117
-        poppedTop.onViewWillDisappear();
118
-        newTop.onViewWillAppear();
119
-        View enteringView = newTop.getView();
120
-        getView().addView(enteringView, getView().getChildCount() - 1);
115
+    private void popInternal(ViewController disappearing, ViewController appearing) {
116
+        disappearing.onViewWillDisappear();
117
+        appearing.onViewWillAppear();
118
+        getView().onChildWillDisappear(disappearing.options, appearing.options);
119
+        getView().addView(appearing.getView(), getView().indexOfChild(disappearing.getView()));
121
     }
120
     }
122
 
121
 
123
     boolean canPop() {
122
     boolean canPop() {
200
     @NonNull
199
     @NonNull
201
     @Override
200
     @Override
202
     protected StackLayout createView() {
201
     protected StackLayout createView() {
203
-        stackLayout = new StackLayout(getActivity(), this::sendOnNavigationButtonPressed);
204
-        return stackLayout;
202
+        return new StackLayout(getActivity(), this::sendOnNavigationButtonPressed);
205
     }
203
     }
206
 
204
 
207
 	@NonNull
205
 	@NonNull
212
 
210
 
213
     @Override
211
     @Override
214
     public void setupTopTabsWithViewPager(ViewPager viewPager) {
212
     public void setupTopTabsWithViewPager(ViewPager viewPager) {
215
-        stackLayout.initTopTabs(viewPager);
213
+        getView().initTopTabs(viewPager);
216
     }
214
     }
217
 
215
 
218
     @Override
216
     @Override
219
     public void clearTopTabs() {
217
     public void clearTopTabs() {
220
-        stackLayout.clearTopTabs();
218
+        getView().clearTopTabs();
221
     }
219
     }
222
 }
220
 }

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

41
     private boolean isShown;
41
     private boolean isShown;
42
     private boolean isDestroyed;
42
     private boolean isDestroyed;
43
     private ViewVisibilityListener viewVisibilityListener = new ViewVisibilityListenerAdapter();
43
     private ViewVisibilityListener viewVisibilityListener = new ViewVisibilityListenerAdapter();
44
-    protected FabOptionsPresenter fabOptionsPresenter;
44
+    FabOptionsPresenter fabOptionsPresenter;
45
 
45
 
46
     public ViewController(Activity activity, String id, Options initialOptions) {
46
     public ViewController(Activity activity, String id, Options initialOptions) {
47
         this.activity = activity;
47
         this.activity = activity;

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

60
     @Override
60
     @Override
61
     public void onViewWillDisappear() {
61
     public void onViewWillDisappear() {
62
         super.onViewWillDisappear();
62
         super.onViewWillDisappear();
63
-        applyOnParentController(parentController -> ((ParentController) parentController).clearTopTabs());
64
     }
63
     }
65
 
64
 
66
     @Override
65
     @Override
67
     public void onViewDisappear() {
66
     public void onViewDisappear() {
68
         performOnCurrentTab(ViewController::onViewDisappear);
67
         performOnCurrentTab(ViewController::onViewDisappear);
68
+        applyOnParentController(parentController -> ((ParentController) parentController).clearTopTabs());
69
     }
69
     }
70
 
70
 
71
     @Override
71
     @Override

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

4
 import android.content.Context;
4
 import android.content.Context;
5
 import android.support.annotation.RestrictTo;
5
 import android.support.annotation.RestrictTo;
6
 import android.support.v4.view.ViewPager;
6
 import android.support.v4.view.ViewPager;
7
-import android.util.Log;
8
-import android.view.Gravity;
9
-import android.view.View;
10
 import android.widget.RelativeLayout;
7
 import android.widget.RelativeLayout;
11
 
8
 
12
-import com.github.clans.fab.FloatingActionButton;
13
 import com.reactnativenavigation.parse.Options;
9
 import com.reactnativenavigation.parse.Options;
14
-import com.reactnativenavigation.presentation.FabOptionsPresenter;
15
 import com.reactnativenavigation.presentation.OptionsPresenter;
10
 import com.reactnativenavigation.presentation.OptionsPresenter;
16
 import com.reactnativenavigation.utils.CompatUtils;
11
 import com.reactnativenavigation.utils.CompatUtils;
17
 
12
 
20
 
15
 
21
 @SuppressLint("ViewConstructor")
16
 @SuppressLint("ViewConstructor")
22
 public class StackLayout extends RelativeLayout {
17
 public class StackLayout extends RelativeLayout {
23
-
24
-    private final TopBar topBar;
18
+    private TopBar topBar;
25
 
19
 
26
     public StackLayout(Context context, TitleBarButton.OnClickListener topBarButtonClickListener) {
20
     public StackLayout(Context context, TitleBarButton.OnClickListener topBarButtonClickListener) {
27
         super(context);
21
         super(context);
39
         new OptionsPresenter(topBar, component).applyOptions(options);
33
         new OptionsPresenter(topBar, component).applyOptions(options);
40
     }
34
     }
41
 
35
 
42
-    @RestrictTo(RestrictTo.Scope.TESTS)
43
-    public TopBar getTopBar() {
44
-        return topBar;
36
+    public void onChildWillDisappear(Options disappearing, Options appearing) {
37
+        new OptionsPresenter(topBar).onChildWillDisappear(disappearing, appearing);
45
     }
38
     }
46
 
39
 
47
     public void clearOptions() {
40
     public void clearOptions() {
55
     public void clearTopTabs() {
48
     public void clearTopTabs() {
56
         topBar.clearTopTabs();
49
         topBar.clearTopTabs();
57
     }
50
     }
51
+
52
+    @RestrictTo(RestrictTo.Scope.TESTS)
53
+    public TopBar getTopBar() {
54
+        return topBar;
55
+    }
56
+
57
+    @RestrictTo(RestrictTo.Scope.TESTS)
58
+    public void setTopBar(TopBar topBar) {
59
+        this.topBar = topBar;
60
+    }
58
 }
61
 }

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

181
         }
181
         }
182
         if (animated.isTrueOrUndefined()) {
182
         if (animated.isTrueOrUndefined()) {
183
             animator.show();
183
             animator.show();
184
-        } else {
184
+        } else if (!animator.isRunning()) {
185
             setVisibility(View.VISIBLE);
185
             setVisibility(View.VISIBLE);
186
         }
186
         }
187
     }
187
     }
192
         }
192
         }
193
         if (animated.isTrueOrUndefined()) {
193
         if (animated.isTrueOrUndefined()) {
194
             animator.hide();
194
             animator.hide();
195
-        } else {
195
+        } else if (!animator.isRunning()){
196
             setVisibility(View.GONE);
196
             setVisibility(View.GONE);
197
         }
197
         }
198
     }
198
     }

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

33
     private static final Bool TOP_BAR_VISIBLE = new Bool(true);
33
     private static final Bool TOP_BAR_VISIBLE = new Bool(true);
34
     private static final Bool TOP_BAR_DRAW_BEHIND = new Bool(true);
34
     private static final Bool TOP_BAR_DRAW_BEHIND = new Bool(true);
35
     private static final Bool TOP_BAR_HIDE_ON_SCROLL = new Bool(true);
35
     private static final Bool TOP_BAR_HIDE_ON_SCROLL = new Bool(true);
36
-    private static final Bool BOTTOM_TABS_ANIMATE_HIDE = new Bool(true);
36
+    private static final Bool BOTTOM_TABS_ANIMATE = new Bool(true);
37
     private static final Bool BOTTOM_TABS_VISIBLE = new Bool(true);
37
     private static final Bool BOTTOM_TABS_VISIBLE = new Bool(true);
38
     private static final String BOTTOM_TABS_BADGE = "3";
38
     private static final String BOTTOM_TABS_BADGE = "3";
39
     private static final String BOTTOM_TABS_CURRENT_TAB_ID = "ComponentId";
39
     private static final String BOTTOM_TABS_CURRENT_TAB_ID = "ComponentId";
70
         assertThat(result.topBarOptions.visible.get()).isEqualTo(TOP_BAR_VISIBLE.get());
70
         assertThat(result.topBarOptions.visible.get()).isEqualTo(TOP_BAR_VISIBLE.get());
71
         assertThat(result.topBarOptions.drawBehind.get()).isEqualTo(TOP_BAR_DRAW_BEHIND.get());
71
         assertThat(result.topBarOptions.drawBehind.get()).isEqualTo(TOP_BAR_DRAW_BEHIND.get());
72
         assertThat(result.topBarOptions.hideOnScroll.get()).isEqualTo(TOP_BAR_HIDE_ON_SCROLL.get());
72
         assertThat(result.topBarOptions.hideOnScroll.get()).isEqualTo(TOP_BAR_HIDE_ON_SCROLL.get());
73
-        assertThat(result.bottomTabsOptions.animateHide.get()).isEqualTo(BOTTOM_TABS_ANIMATE_HIDE.get());
73
+        assertThat(result.bottomTabsOptions.animate.get()).isEqualTo(BOTTOM_TABS_ANIMATE.get());
74
         assertThat(result.bottomTabsOptions.visible.get()).isEqualTo(BOTTOM_TABS_VISIBLE.get());
74
         assertThat(result.bottomTabsOptions.visible.get()).isEqualTo(BOTTOM_TABS_VISIBLE.get());
75
         assertThat(result.bottomTabsOptions.currentTabId.get()).isEqualTo(BOTTOM_TABS_CURRENT_TAB_ID);
75
         assertThat(result.bottomTabsOptions.currentTabId.get()).isEqualTo(BOTTOM_TABS_CURRENT_TAB_ID);
76
         assertThat(result.bottomTabsOptions.currentTabIndex.get()).isEqualTo(BOTTOM_TABS_CURRENT_TAB_INDEX.get());
76
         assertThat(result.bottomTabsOptions.currentTabIndex.get()).isEqualTo(BOTTOM_TABS_CURRENT_TAB_INDEX.get());
90
                 .put("currentTabId", BOTTOM_TABS_CURRENT_TAB_ID)
90
                 .put("currentTabId", BOTTOM_TABS_CURRENT_TAB_ID)
91
                 .put("currentTabIndex", BOTTOM_TABS_CURRENT_TAB_INDEX.get())
91
                 .put("currentTabIndex", BOTTOM_TABS_CURRENT_TAB_INDEX.get())
92
                 .put("visible", BOTTOM_TABS_VISIBLE.get())
92
                 .put("visible", BOTTOM_TABS_VISIBLE.get())
93
-                .put("animateHide", BOTTOM_TABS_ANIMATE_HIDE.get());
93
+                .put("animate", BOTTOM_TABS_ANIMATE.get());
94
     }
94
     }
95
 
95
 
96
     @NonNull
96
     @NonNull
144
     }
144
     }
145
 
145
 
146
     @NonNull
146
     @NonNull
147
-    private JSONObject createOtherTabBar() throws JSONException {
147
+    private JSONObject createOtherBottomTabs() throws JSONException {
148
         return new JSONObject()
148
         return new JSONObject()
149
                 .put("currentTabId", BOTTOM_TABS_CURRENT_TAB_ID)
149
                 .put("currentTabId", BOTTOM_TABS_CURRENT_TAB_ID)
150
                 .put("currentTabIndex", BOTTOM_TABS_CURRENT_TAB_INDEX)
150
                 .put("currentTabIndex", BOTTOM_TABS_CURRENT_TAB_INDEX)
151
                 .put("visible", BOTTOM_TABS_VISIBLE)
151
                 .put("visible", BOTTOM_TABS_VISIBLE)
152
-                .put("animateHide", BOTTOM_TABS_ANIMATE_HIDE)
152
+                .put("animate", BOTTOM_TABS_ANIMATE.get())
153
                 .put("tabBadge", BOTTOM_TABS_BADGE);
153
                 .put("tabBadge", BOTTOM_TABS_BADGE);
154
     }
154
     }
155
 
155
 
188
         JSONObject defaultJson = new JSONObject()
188
         JSONObject defaultJson = new JSONObject()
189
                 .put("topBar", createOtherTopBar())
189
                 .put("topBar", createOtherTopBar())
190
                 .put("fab", createOtherFab())
190
                 .put("fab", createOtherFab())
191
-                .put("bottomTabs", createOtherTabBar());
191
+                .put("bottomTabs", createOtherBottomTabs());
192
         Options defaultOptions = Options.parse(mockLoader, defaultJson);
192
         Options defaultOptions = Options.parse(mockLoader, defaultJson);
193
 
193
 
194
         JSONObject json = new JSONObject()
194
         JSONObject json = new JSONObject()
209
     public void topBar_defaultOptions() throws Exception {
209
     public void topBar_defaultOptions() throws Exception {
210
         Options uut = new Options();
210
         Options uut = new Options();
211
         assertThat(uut.topBarOptions.visible.isFalseOrUndefined()).isTrue();
211
         assertThat(uut.topBarOptions.visible.isFalseOrUndefined()).isTrue();
212
-        assertThat(uut.topBarOptions.animateHide.isTrueOrUndefined()).isTrue();
212
+        assertThat(uut.topBarOptions.animate.isTrueOrUndefined()).isTrue();
213
     }
213
     }
214
 
214
 
215
     @Test
215
     @Test

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

147
 
147
 
148
         Options opts = new Options();
148
         Options opts = new Options();
149
         opts.topBarOptions.visible = new Bool(false);
149
         opts.topBarOptions.visible = new Bool(false);
150
-        opts.topBarOptions.animateHide = new Bool(false);
150
+        opts.topBarOptions.animate = new Bool(false);
151
         uut.mergeOptions(opts);
151
         uut.mergeOptions(opts);
152
 
152
 
153
         assertThat(stackController.getTopBar().getVisibility()).isEqualTo(View.GONE);
153
         assertThat(stackController.getTopBar().getVisibility()).isEqualTo(View.GONE);

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

8
 import com.reactnativenavigation.mocks.SimpleViewController;
8
 import com.reactnativenavigation.mocks.SimpleViewController;
9
 import com.reactnativenavigation.parse.Options;
9
 import com.reactnativenavigation.parse.Options;
10
 import com.reactnativenavigation.parse.Text;
10
 import com.reactnativenavigation.parse.Text;
11
+import com.reactnativenavigation.parse.params.Bool;
11
 import com.reactnativenavigation.utils.ViewHelper;
12
 import com.reactnativenavigation.utils.ViewHelper;
12
 import com.reactnativenavigation.views.ReactComponent;
13
 import com.reactnativenavigation.views.ReactComponent;
14
+import com.reactnativenavigation.views.StackLayout;
13
 
15
 
14
 import org.assertj.core.api.iterable.Extractor;
16
 import org.assertj.core.api.iterable.Extractor;
15
 import org.junit.Test;
17
 import org.junit.Test;
75
         });
77
         });
76
     }
78
     }
77
 
79
 
80
+    @Test
81
+    public void pop_layoutHandlesChildWillDisappear() throws Exception {
82
+        final StackLayout[] stackLayout = new StackLayout[1];
83
+        uut = new StackController(activity, "uut", new Options()) {
84
+            @Override
85
+            protected StackLayout createView() {
86
+                stackLayout[0] = spy(super.createView());
87
+                return stackLayout[0];
88
+            }
89
+        };
90
+        uut.push(child1, new MockPromise());
91
+        uut.animatePush(child2, new MockPromise() {
92
+            @Override
93
+            public void resolve(@Nullable Object value) {
94
+                uut.animatePop(new MockPromise() {
95
+                    @Override
96
+                    public void resolve(@Nullable Object value) {
97
+                        verify(stackLayout[0], times(1)).onChildWillDisappear(child2.options, child1.options);
98
+                    }
99
+                });
100
+            }
101
+        });
102
+    }
103
+
78
     @Test
104
     @Test
79
     public void stackOperations() throws Exception {
105
     public void stackOperations() throws Exception {
80
         assertThat(uut.peek()).isNull();
106
         assertThat(uut.peek()).isNull();
306
         verify(child2, times(1)).onViewWillDisappear();
332
         verify(child2, times(1)).onViewWillDisappear();
307
     }
333
     }
308
 
334
 
335
+    @Test
336
+    public void pop_animatesTopBarIfNeeded() throws Exception {
337
+        uut.ensureViewIsCreated();
338
+        uut.getView().setTopBar(spy(uut.getTopBar()));
339
+
340
+        child1.options.topBarOptions.visible = new Bool(false);
341
+        child1.options.topBarOptions.animate = new Bool(false);
342
+        child2.options.topBarOptions.visible = new Bool(true);
343
+        uut.push(child1, new MockPromise());
344
+        child1.onViewAppeared();
345
+
346
+        assertThat(uut.getTopBar().getVisibility()).isEqualTo(View.GONE);
347
+        uut.push(child2, new MockPromise());
348
+        uut.animatePop(new MockPromise() {
349
+            @Override
350
+            public void resolve(@Nullable Object value) {
351
+                verify(uut.getTopBar(), times(1)).hide(child2.options.topBarOptions.animate);
352
+            }
353
+        });
354
+    }
355
+
309
     @Test
356
     @Test
310
     public void popSpecific_CallsDestroyOnPoppedChild() throws Exception {
357
     public void popSpecific_CallsDestroyOnPoppedChild() throws Exception {
311
         child1 = spy(child1);
358
         child1 = spy(child1);

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

24
 import java.util.ArrayList;
24
 import java.util.ArrayList;
25
 import java.util.List;
25
 import java.util.List;
26
 
26
 
27
+import javax.annotation.Nullable;
28
+
27
 import static org.assertj.core.api.Assertions.assertThat;
29
 import static org.assertj.core.api.Assertions.assertThat;
28
 import static org.mockito.ArgumentMatchers.any;
30
 import static org.mockito.ArgumentMatchers.any;
29
 import static org.mockito.ArgumentMatchers.eq;
31
 import static org.mockito.ArgumentMatchers.eq;
209
     }
211
     }
210
 
212
 
211
     @Test
213
     @Test
212
-    public void applyOptions_tabsAreRemovedBeforeViewDisappears() throws Exception {
214
+    public void applyOptions_tabsAreRemovedAfterViewDisappears() throws Exception {
213
         parentController.getView().removeAllViews();
215
         parentController.getView().removeAllViews();
214
 
216
 
215
         StackController stackController = spy(new StackController(activity, "stack", new Options()));
217
         StackController stackController = spy(new StackController(activity, "stack", new Options()));
228
         uut.onViewAppeared();
230
         uut.onViewAppeared();
229
 
231
 
230
         assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isTrue();
232
         assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isTrue();
231
-        stackController.pop(new MockPromise());
232
-        assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isFalse();
233
+        stackController.animatePop(new MockPromise() {
234
+            @Override
235
+            public void resolve(@Nullable Object value) {
236
+                assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isFalse();
237
+            }
238
+        });
233
     }
239
     }
234
 
240
 
235
     @Test
241
     @Test

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

31
               name: 'navigation.playground.WelcomeScreen'
31
               name: 'navigation.playground.WelcomeScreen'
32
             }
32
             }
33
           }
33
           }
34
-        ],
35
-        options: {
36
-          topBar: {
37
-            visible: false,
38
-            animateHide: false
39
-          }
40
-        }
34
+        ]
41
       }
35
       }
42
     });
36
     });
43
   });
37
   });

+ 2
- 2
playground/src/screens/OptionsScreen.js View File

191
     Navigation.setOptions(this.props.componentId, {
191
     Navigation.setOptions(this.props.componentId, {
192
       topBar: {
192
       topBar: {
193
         visible: true,
193
         visible: true,
194
-        animateHide: true
194
+        animate: true
195
       }
195
       }
196
     });
196
     });
197
   }
197
   }
200
     Navigation.setOptions(this.props.componentId, {
200
     Navigation.setOptions(this.props.componentId, {
201
       topBar: {
201
       topBar: {
202
         visible: false,
202
         visible: false,
203
-        animateHide: true
203
+        animate: true
204
       }
204
       }
205
     });
205
     });
206
   }
206
   }

+ 1
- 1
playground/src/screens/TextScreen.js View File

70
       bottomTabs: {
70
       bottomTabs: {
71
         currentTabIndex: 1,
71
         currentTabIndex: 1,
72
         visible: false,
72
         visible: false,
73
-        animateHide: true
73
+        animate: true
74
       }
74
       }
75
     });
75
     });
76
   }
76
   }

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

10
   static get options() {
10
   static get options() {
11
     return {
11
     return {
12
       topBar: {
12
       topBar: {
13
-        largeTitle: false
13
+        largeTitle: false,
14
+        drawBehind: true,
15
+        visible: false,
16
+        animate: false
14
       }
17
       }
15
     };
18
     };
16
   }
19
   }