浏览代码

Merge branch 'v2' into typescript

Daniel Zlotin 7 年前
父节点
当前提交
dc2d741146
共有 75 个文件被更改,包括 1162 次插入1120 次删除
  1. 16
    0
      e2e/ScreenStyle.test.js
  2. 3
    1
      lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java
  3. 0
    5
      lib/android/app/src/main/java/com/reactnativenavigation/anim/NavigationAnimator.java
  4. 12
    10
      lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarAnimator.java
  5. 21
    54
      lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarCollapseBehavior.java
  6. 72
    9
      lib/android/app/src/main/java/com/reactnativenavigation/interfaces/ScrollEventListener.java
  7. 7
    7
      lib/android/app/src/main/java/com/reactnativenavigation/parse/BottomTabsOptions.java
  8. 15
    16
      lib/android/app/src/main/java/com/reactnativenavigation/parse/Button.java
  9. 0
    5
      lib/android/app/src/main/java/com/reactnativenavigation/parse/DEFAULT_VALUES.java
  10. 7
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/Fraction.java
  11. 9
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/FractionParser.java
  12. 6
    29
      lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java
  13. 12
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/NullFraction.java
  14. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/NullNumber.java
  15. 12
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/NullText.java
  16. 6
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/Options.java
  17. 4
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/Param.java
  18. 7
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/Text.java
  19. 9
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TextParser.java
  20. 17
    18
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarOptions.java
  21. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopTabOptions.java
  22. 11
    12
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java
  23. 2
    13
      lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java
  24. 14
    0
      lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java
  25. 42
    39
      lib/android/app/src/main/java/com/reactnativenavigation/utils/ImageUtils.java
  26. 37
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/NoOpPromise.java
  27. 20
    22
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/BottomTabsController.java
  28. 9
    8
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java
  29. 0
    104
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ContainerViewController.java
  30. 8
    38
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java
  31. 16
    5
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java
  32. 78
    80
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java
  33. 12
    9
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java
  34. 0
    36
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/CustomOverlay.java
  35. 1
    4
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/OverlayFactory.java
  36. 2
    3
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabController.java
  37. 8
    5
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsAdapter.java
  38. 5
    5
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java
  39. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsViewPager.java
  40. 1
    9
      lib/android/app/src/main/java/com/reactnativenavigation/views/Component.java
  41. 22
    32
      lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentLayout.java
  42. 5
    6
      lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentViewCreator.java
  43. 0
    29
      lib/android/app/src/main/java/com/reactnativenavigation/views/CustomDialog.java
  44. 46
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/StackLayout.java
  45. 20
    22
      lib/android/app/src/main/java/com/reactnativenavigation/views/TitleBarButton.java
  46. 44
    34
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java
  47. 6
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopTab.java
  48. 23
    40
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsLayout.java
  49. 3
    3
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsLayoutCreator.java
  50. 22
    23
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestComponentLayout.java
  51. 0
    70
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestComponentView.java
  52. 6
    0
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TopTabLayoutMock.java
  53. 8
    8
      lib/android/app/src/test/java/com/reactnativenavigation/parse/NavigationOptionsTest.java
  54. 4
    14
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/BottomTabsControllerTest.java
  55. 16
    13
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ComponentViewControllerTest.java
  56. 83
    67
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java
  57. 71
    56
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java
  58. 3
    3
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java
  59. 142
    99
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java
  60. 11
    6
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java
  61. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ViewControllerTest.java
  62. 1
    1
      lib/android/app/src/test/java/com/reactnativenavigation/views/TopBarTest.java
  63. 6
    0
      lib/ios/RNNBridgeModule.m
  64. 2
    0
      lib/ios/RNNCommandsHandler.h
  65. 6
    0
      lib/ios/RNNCommandsHandler.m
  66. 2
    0
      lib/ios/RNNControllerFactory.h
  67. 1
    0
      lib/ios/RNNControllerFactory.m
  68. 2
    0
      lib/ios/RNNNavigationOptions.h
  69. 6
    1
      lib/ios/RNNNavigationOptions.m
  70. 8
    4
      lib/ios/RNNOptions.h
  71. 5
    0
      lib/ios/RNNOptions.m
  72. 19
    2
      playground/src/screens/OptionsScreen.js
  73. 13
    0
      playground/src/screens/PushedScreen.js
  74. 47
    34
      playground/src/screens/WelcomeScreen.js
  75. 1
    0
      playground/src/testIDs.js

+ 16
- 0
e2e/ScreenStyle.test.js 查看文件

110
     await expect(elementById(testIDs.FIRST_TAB_BAR_BUTTON)).toBeVisible();
110
     await expect(elementById(testIDs.FIRST_TAB_BAR_BUTTON)).toBeVisible();
111
     await expect(elementById(testIDs.SECOND_TAB_BAR_BUTTON)).toBeVisible();
111
     await expect(elementById(testIDs.SECOND_TAB_BAR_BUTTON)).toBeVisible();
112
   });
112
   });
113
+
114
+  it('default options should apply to all screens in stack', async () => {
115
+    await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
116
+    await elementById(testIDs.PUSH_DEFAULT_OPTIONS_BUTTON).tap();
117
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeNotVisible();
118
+    await elementById(testIDs.PUSH_BUTTON).tap();
119
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeNotVisible();
120
+  });
121
+
122
+  it('default options should not override static options', async () => {
123
+    await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
124
+    await elementById(testIDs.PUSH_DEFAULT_OPTIONS_BUTTON).tap();
125
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeNotVisible();
126
+    await elementById(testIDs.POP_BUTTON).tap();
127
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeVisible();
128
+  });
113
 });
129
 });

+ 3
- 1
lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java 查看文件

13
 public abstract class NavigationApplication extends Application implements ReactApplication {
13
 public abstract class NavigationApplication extends Application implements ReactApplication {
14
 
14
 
15
 	private ReactGateway reactGateway;
15
 	private ReactGateway reactGateway;
16
+	public static NavigationApplication instance;
16
 
17
 
17
 	@Override
18
 	@Override
18
 	public void onCreate() {
19
 	public void onCreate() {
19
 		super.onCreate();
20
 		super.onCreate();
20
-		reactGateway = new ReactGateway(this, isDebug(), createAdditionalReactPackages());
21
+        instance = this;
22
+        reactGateway = new ReactGateway(this, isDebug(), createAdditionalReactPackages());
21
 	}
23
 	}
22
 
24
 
23
 	public ReactGateway getReactGateway() {
25
 	public ReactGateway getReactGateway() {

+ 0
- 5
lib/android/app/src/main/java/com/reactnativenavigation/anim/NavigationAnimator.java 查看文件

4
 import android.animation.AnimatorListenerAdapter;
4
 import android.animation.AnimatorListenerAdapter;
5
 import android.animation.AnimatorSet;
5
 import android.animation.AnimatorSet;
6
 import android.animation.ObjectAnimator;
6
 import android.animation.ObjectAnimator;
7
-import android.animation.TimeInterpolator;
8
 import android.content.Context;
7
 import android.content.Context;
9
 import android.support.annotation.Nullable;
8
 import android.support.annotation.Nullable;
10
-import android.util.DisplayMetrics;
11
 import android.view.View;
9
 import android.view.View;
12
-import android.view.ViewGroup;
13
-import android.view.WindowManager;
14
 import android.view.animation.AccelerateInterpolator;
10
 import android.view.animation.AccelerateInterpolator;
15
 import android.view.animation.DecelerateInterpolator;
11
 import android.view.animation.DecelerateInterpolator;
16
 
12
 
17
 import com.reactnativenavigation.utils.UiUtils;
13
 import com.reactnativenavigation.utils.UiUtils;
18
-import com.reactnativenavigation.views.TopBar;
19
 
14
 
20
 @SuppressWarnings("ResourceType")
15
 @SuppressWarnings("ResourceType")
21
 public class NavigationAnimator {
16
 public class NavigationAnimator {

+ 12
- 10
lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarAnimator.java 查看文件

15
 public class TopBarAnimator {
15
 public class TopBarAnimator {
16
 
16
 
17
     private static final int DURATION_TOPBAR = 300;
17
     private static final int DURATION_TOPBAR = 300;
18
-    private DecelerateInterpolator decelerateInterpolator;
19
-    private AccelerateInterpolator accelerateInterpolator;
18
+    private final DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator();
19
+    private final AccelerateInterpolator accelerateInterpolator = new AccelerateInterpolator();
20
 
20
 
21
     private TopBar topBar;
21
     private TopBar topBar;
22
     private View contentView;
22
     private View contentView;
23
 
23
 
24
+    public TopBarAnimator(TopBar topBar) {
25
+        this.topBar = topBar;
26
+    }
27
+
24
     public TopBarAnimator(TopBar topBar, View contentView) {
28
     public TopBarAnimator(TopBar topBar, View contentView) {
25
-        decelerateInterpolator = new DecelerateInterpolator();
26
-        accelerateInterpolator = new AccelerateInterpolator();
27
         this.topBar = topBar;
29
         this.topBar = topBar;
28
         this.contentView = contentView;
30
         this.contentView = contentView;
29
     }
31
     }
60
         hide(0, accelerateInterpolator, DURATION_TOPBAR);
62
         hide(0, accelerateInterpolator, DURATION_TOPBAR);
61
     }
63
     }
62
 
64
 
63
-    public void hide(float startTranslation, TimeInterpolator interpolator, int duration) {
64
-        ObjectAnimator topbarAnim = ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Y, startTranslation, -1 * topBar.getMeasuredHeight());
65
-        topbarAnim.setInterpolator(interpolator);
66
-        topbarAnim.setDuration(duration);
65
+    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);
67
 
69
 
68
-        topbarAnim.addListener(new AnimatorListenerAdapter() {
70
+        animator.addListener(new AnimatorListenerAdapter() {
69
             @Override
71
             @Override
70
             public void onAnimationEnd(Animator animation) {
72
             public void onAnimationEnd(Animator animation) {
71
                 if (contentView != null) {
73
                 if (contentView != null) {
77
                 topBar.setVisibility(View.GONE);
79
                 topBar.setVisibility(View.GONE);
78
             }
80
             }
79
         });
81
         });
80
-        topbarAnim.start();
82
+        animator.start();
81
     }
83
     }
82
 }
84
 }

+ 21
- 54
lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarCollapseBehavior.java 查看文件

3
 
3
 
4
 import android.view.View;
4
 import android.view.View;
5
 
5
 
6
-import com.facebook.react.uimanager.events.EventDispatcher;
7
 import com.reactnativenavigation.interfaces.ScrollEventListener;
6
 import com.reactnativenavigation.interfaces.ScrollEventListener;
8
-import com.reactnativenavigation.utils.UiThread;
9
 import com.reactnativenavigation.views.TopBar;
7
 import com.reactnativenavigation.views.TopBar;
10
 
8
 
11
-public class TopBarCollapseBehavior {
9
+public class TopBarCollapseBehavior implements ScrollEventListener.OnScrollListener, ScrollEventListener.OnDragListener {
12
     private TopBar topBar;
10
     private TopBar topBar;
13
-
14
-    private EventDispatcher eventDispatcher;
15
     private ScrollEventListener scrollEventListener;
11
     private ScrollEventListener scrollEventListener;
16
-    private boolean dragStarted;
17
     private TopBarAnimator animator;
12
     private TopBarAnimator animator;
18
 
13
 
19
-    public TopBarCollapseBehavior(EventDispatcher eventDispatcher, TopBar topBar) {
20
-        this.eventDispatcher = eventDispatcher;
14
+    public TopBarCollapseBehavior(TopBar topBar) {
21
         this.topBar = topBar;
15
         this.topBar = topBar;
22
-        this.animator = new TopBarAnimator(topBar, null);
16
+        this.animator = new TopBarAnimator(topBar);
23
     }
17
     }
24
 
18
 
25
     public void enableCollapse() {
19
     public void enableCollapse() {
26
-        scrollEventListener = (new ScrollEventListener(new ScrollEventListener.OnVerticalScrollListener() {
27
-            @Override
28
-            public void onVerticalScroll(int scrollY, int oldScrollY) {
29
-                if (scrollY < 0) return;
30
-                if (!dragStarted) return;
31
-
32
-                final int scrollDiff = calcScrollDiff(scrollY, oldScrollY, topBar.getMeasuredHeight());
33
-                final float nextTranslation = topBar.getTranslationY() - scrollDiff;
34
-                if (scrollDiff < 0) {
35
-                    down(topBar.getMeasuredHeight(), nextTranslation);
36
-                } else {
37
-                    up(topBar.getMeasuredHeight(), nextTranslation);
38
-                }
39
-            }
20
+        scrollEventListener.register(topBar, this, this);
21
+    }
40
 
22
 
41
-            @Override
42
-            public void onDrag(boolean started, double velocity) {
43
-                dragStarted = started;
44
-                UiThread.post(() -> {
45
-                    if (!dragStarted) {
46
-                        if (velocity > 0) {
47
-                            animator.show(topBar.getTranslationY(), null, 100);
48
-                        } else {
49
-                            animator.hide(topBar.getTranslationY(), null, 100);
50
-                        }
51
-                    }
52
-                });
53
-            }
54
-        }));
55
-        if (eventDispatcher != null) {
56
-            eventDispatcher.addListener(scrollEventListener);
57
-        }
23
+    public void disableCollapse() {
24
+        scrollEventListener.unregister();
25
+        topBar.setVisibility(View.VISIBLE);
26
+        topBar.setTranslationY(0);
58
     }
27
     }
59
 
28
 
60
-    private void up(int measuredHeight, float nextTranslation) {
29
+    @Override
30
+    public void onScrollUp(float nextTranslation) {
31
+        final int measuredHeight = topBar.getMeasuredHeight();
61
         if (nextTranslation < -measuredHeight && topBar.getVisibility() == View.VISIBLE) {
32
         if (nextTranslation < -measuredHeight && topBar.getVisibility() == View.VISIBLE) {
62
             topBar.setVisibility(View.GONE);
33
             topBar.setVisibility(View.GONE);
63
             topBar.setTranslationY(-measuredHeight);
34
             topBar.setTranslationY(-measuredHeight);
66
         }
37
         }
67
     }
38
     }
68
 
39
 
69
-    private void down(int measuredHeight, float nextTranslation) {
40
+    @Override
41
+    public void onScrollDown(float nextTranslation) {
42
+        final int measuredHeight = topBar.getMeasuredHeight();
70
         if (topBar.getVisibility() == View.GONE && nextTranslation > -measuredHeight) {
43
         if (topBar.getVisibility() == View.GONE && nextTranslation > -measuredHeight) {
71
             topBar.setVisibility(View.VISIBLE);
44
             topBar.setVisibility(View.VISIBLE);
72
             topBar.setTranslationY(nextTranslation);
45
             topBar.setTranslationY(nextTranslation);
75
         }
48
         }
76
     }
49
     }
77
 
50
 
78
-    private int calcScrollDiff(int scrollY, int oldScrollY, int measuredHeight) {
79
-        int diff = scrollY - oldScrollY;
80
-        if (Math.abs(diff) > measuredHeight) {
81
-            diff = (Math.abs(diff) / diff) * measuredHeight;
82
-        }
83
-        return diff;
51
+    @Override
52
+    public void onShow() {
53
+        animator.show(topBar.getTranslationY(), null, 100);
84
     }
54
     }
85
 
55
 
86
-    public void disableCollapse() {
87
-        if (eventDispatcher != null) {
88
-            eventDispatcher.removeListener(scrollEventListener);
89
-        }
90
-        topBar.setVisibility(View.VISIBLE);
91
-        topBar.setTranslationY(0);
56
+    @Override
57
+    public void onHide() {
58
+        animator.hide(topBar.getTranslationY(), null, 100);
92
     }
59
     }
93
 }
60
 }

+ 72
- 9
lib/android/app/src/main/java/com/reactnativenavigation/interfaces/ScrollEventListener.java 查看文件

1
 package com.reactnativenavigation.interfaces;
1
 package com.reactnativenavigation.interfaces;
2
 
2
 
3
 import com.facebook.react.uimanager.events.Event;
3
 import com.facebook.react.uimanager.events.Event;
4
+import com.facebook.react.uimanager.events.EventDispatcher;
4
 import com.facebook.react.uimanager.events.EventDispatcherListener;
5
 import com.facebook.react.uimanager.events.EventDispatcherListener;
5
 import com.facebook.react.views.scroll.ScrollEvent;
6
 import com.facebook.react.views.scroll.ScrollEvent;
6
 import com.reactnativenavigation.utils.ReflectionUtils;
7
 import com.reactnativenavigation.utils.ReflectionUtils;
8
+import com.reactnativenavigation.utils.UiThread;
7
 
9
 
8
 public class ScrollEventListener implements EventDispatcherListener {
10
 public class ScrollEventListener implements EventDispatcherListener {
9
 
11
 
10
-    private OnVerticalScrollListener verticalScrollListener;
12
+    public interface OnScrollListener {
13
+        void onScrollUp(float nextTranslation);
14
+
15
+        void onScrollDown(float nextTranslation);
16
+    }
17
+
18
+    public interface OnDragListener {
19
+        void onShow();
20
+
21
+        void onHide();
22
+    }
23
+
24
+    public interface ScrollAwareView {
25
+        int getMeasuredHeight();
26
+
27
+        float getTranslationY();
28
+    }
29
+
30
+    private ScrollAwareView view;
31
+    private OnScrollListener onScrollListener;
32
+    private OnDragListener dragListener;
33
+    private EventDispatcher eventDispatcher;
11
     private int prevScrollY = -1;
34
     private int prevScrollY = -1;
35
+    private boolean dragStarted;
12
 
36
 
13
-    public interface OnVerticalScrollListener {
14
-        void onVerticalScroll(int scrollY, int oldScrollY);
37
+    public ScrollEventListener(EventDispatcher eventDispatcher) {
38
+        this.eventDispatcher = eventDispatcher;
39
+    }
15
 
40
 
16
-        void onDrag(boolean started, double velocity);
41
+    public void register(ScrollAwareView scrollAwareView, OnScrollListener scrollListener, OnDragListener dragListener) {
42
+        this.view = scrollAwareView;
43
+        this.onScrollListener = scrollListener;
44
+        this.dragListener = dragListener;
45
+        eventDispatcher.addListener(this);
17
     }
46
     }
18
 
47
 
19
-    public ScrollEventListener(OnVerticalScrollListener verticalScrollListener) {
20
-        this.verticalScrollListener = verticalScrollListener;
48
+    public void unregister() {
49
+        eventDispatcher.removeListener(this);
21
     }
50
     }
22
 
51
 
23
     @Override
52
     @Override
31
         try {
60
         try {
32
             if ("topScroll".equals(event.getEventName())) {
61
             if ("topScroll".equals(event.getEventName())) {
33
                 int scrollY = (int) ReflectionUtils.getDeclaredField(event, "mScrollY");
62
                 int scrollY = (int) ReflectionUtils.getDeclaredField(event, "mScrollY");
34
-                verticalScrollListener.onVerticalScroll(scrollY, prevScrollY);
63
+                onVerticalScroll(scrollY, prevScrollY);
35
                 if (scrollY != prevScrollY) {
64
                 if (scrollY != prevScrollY) {
36
                     prevScrollY = scrollY;
65
                     prevScrollY = scrollY;
37
                 }
66
                 }
38
             } else if ("topScrollBeginDrag".equals(event.getEventName())) {
67
             } else if ("topScrollBeginDrag".equals(event.getEventName())) {
39
                 double velocity = (double) ReflectionUtils.getDeclaredField(event, "mYVelocity");
68
                 double velocity = (double) ReflectionUtils.getDeclaredField(event, "mYVelocity");
40
-                verticalScrollListener.onDrag(true, velocity);
69
+                onDrag(true, velocity);
41
             } else if ("topScrollEndDrag".equals(event.getEventName())) {
70
             } else if ("topScrollEndDrag".equals(event.getEventName())) {
42
                 double velocity = (double) ReflectionUtils.getDeclaredField(event, "mYVelocity");
71
                 double velocity = (double) ReflectionUtils.getDeclaredField(event, "mYVelocity");
43
-                verticalScrollListener.onDrag(false, velocity);
72
+                onDrag(false, velocity);
44
             }
73
             }
45
         } catch (Exception e) {
74
         } catch (Exception e) {
46
             e.printStackTrace();
75
             e.printStackTrace();
47
         }
76
         }
48
     }
77
     }
78
+
79
+    private void onVerticalScroll(int scrollY, int oldScrollY) {
80
+        if (scrollY < 0) return;
81
+        if (!dragStarted) return;
82
+
83
+        final int scrollDiff = calcScrollDiff(scrollY, oldScrollY, view.getMeasuredHeight());
84
+        final float translationY = view.getTranslationY() - scrollDiff;
85
+        if (scrollDiff < 0) {
86
+            onScrollListener.onScrollDown(translationY);
87
+        } else {
88
+            onScrollListener.onScrollUp(translationY);
89
+        }
90
+    }
91
+
92
+    private int calcScrollDiff(int scrollY, int oldScrollY, int measuredHeight) {
93
+        int diff = scrollY - oldScrollY;
94
+        if (Math.abs(diff) > measuredHeight) {
95
+            diff = (Math.abs(diff) / diff) * measuredHeight;
96
+        }
97
+        return diff;
98
+    }
99
+
100
+    private void onDrag(boolean started, double velocity) {
101
+        dragStarted = started;
102
+        UiThread.post(() -> {
103
+            if (!dragStarted) {
104
+                if (velocity > 0) {
105
+                    dragListener.onShow();
106
+                } else {
107
+                    dragListener.onHide();
108
+                }
109
+            }
110
+        });
111
+    }
49
 }
112
 }

+ 7
- 7
lib/android/app/src/main/java/com/reactnativenavigation/parse/BottomTabsOptions.java 查看文件

11
 		BottomTabsOptions options = new BottomTabsOptions();
11
 		BottomTabsOptions options = new BottomTabsOptions();
12
 		if (json == null) return options;
12
 		if (json == null) return options;
13
 
13
 
14
-		options.currentTabId = json.optString("currentTabId", NO_VALUE);
14
+		options.currentTabId = TextParser.parse(json, "currentTabId");
15
 		options.currentTabIndex = json.optInt("currentTabIndex", NO_INT_VALUE);
15
 		options.currentTabIndex = json.optInt("currentTabIndex", NO_INT_VALUE);
16
 		options.tabBadge = json.optInt("tabBadge", NO_INT_VALUE);
16
 		options.tabBadge = json.optInt("tabBadge", NO_INT_VALUE);
17
 		options.hidden = BooleanOptions.parse(json.optString("hidden"));
17
 		options.hidden = BooleanOptions.parse(json.optString("hidden"));
20
 		return options;
20
 		return options;
21
 	}
21
 	}
22
 
22
 
23
-	public int tabBadge = NO_INT_VALUE;
24
-	public BooleanOptions hidden = BooleanOptions.False;
25
-	public BooleanOptions animateHide = BooleanOptions.False;
23
+	int tabBadge = NO_INT_VALUE;
24
+	BooleanOptions hidden = BooleanOptions.False;
25
+	BooleanOptions animateHide = BooleanOptions.False;
26
 	public int currentTabIndex = NO_INT_VALUE;
26
 	public int currentTabIndex = NO_INT_VALUE;
27
-	public String currentTabId = NO_VALUE;
27
+	public Text currentTabId = new NullText();
28
 
28
 
29
 	void mergeWith(final BottomTabsOptions other) {
29
 	void mergeWith(final BottomTabsOptions other) {
30
-		if (!NO_VALUE.equals(other.currentTabId)) {
30
+		if (other.currentTabId.hasValue()) {
31
 			currentTabId = other.currentTabId;
31
 			currentTabId = other.currentTabId;
32
 		}
32
 		}
33
 		if (NO_INT_VALUE != other.currentTabIndex) {
33
 		if (NO_INT_VALUE != other.currentTabIndex) {
45
 	}
45
 	}
46
 
46
 
47
     void mergeWithDefault(final BottomTabsOptions defaultOptions) {
47
     void mergeWithDefault(final BottomTabsOptions defaultOptions) {
48
-        if (NO_VALUE.equals(currentTabId)) {
48
+        if (!currentTabId.hasValue()) {
49
             currentTabId = defaultOptions.currentTabId;
49
             currentTabId = defaultOptions.currentTabId;
50
         }
50
         }
51
         if (NO_INT_VALUE == currentTabIndex) {
51
         if (NO_INT_VALUE == currentTabIndex) {

+ 15
- 16
lib/android/app/src/main/java/com/reactnativenavigation/parse/Button.java 查看文件

8
 
8
 
9
 import java.util.ArrayList;
9
 import java.util.ArrayList;
10
 
10
 
11
-import static com.reactnativenavigation.parse.DEFAULT_VALUES.NO_VALUE;
12
 import static com.reactnativenavigation.parse.Options.NO_INT_VALUE;
11
 import static com.reactnativenavigation.parse.Options.NO_INT_VALUE;
13
 
12
 
14
 public class Button {
13
 public class Button {
15
 	public String id;
14
 	public String id;
16
-	public String title;
15
+	public Text title;
17
 	public Options.BooleanOptions disabled;
16
 	public Options.BooleanOptions disabled;
18
 	public Options.BooleanOptions disableIconTint;
17
 	public Options.BooleanOptions disableIconTint;
19
 	public int showAsAction;
18
 	public int showAsAction;
20
 	@ColorInt public int buttonColor;
19
 	@ColorInt public int buttonColor;
21
 	public int buttonFontSize;
20
 	public int buttonFontSize;
22
-	public String buttonFontWeight;
23
-	public String icon;
21
+	public Text buttonFontWeight;
22
+	public Text icon;
24
 
23
 
25
 	private static Button parseJson(JSONObject json)  {
24
 	private static Button parseJson(JSONObject json)  {
26
 		Button button = new Button();
25
 		Button button = new Button();
27
 		button.id = json.optString("id");
26
 		button.id = json.optString("id");
28
-		button.title = json.optString("title", NO_VALUE);
29
-		button.disabled = Options.BooleanOptions.parse(json.optString("disabled", NO_VALUE));
30
-		button.disableIconTint = Options.BooleanOptions.parse(json.optString("disableIconTint", NO_VALUE));
31
-		button.showAsAction = parseShowAsAction(json.optString("showAsAction", NO_VALUE));
27
+		button.title = TextParser.parse(json, "title");
28
+		button.disabled = Options.BooleanOptions.parse(json.optString("disabled", ""));
29
+		button.disableIconTint = Options.BooleanOptions.parse(json.optString("disableIconTint", ""));
30
+		button.showAsAction = parseShowAsAction(json);
32
 		button.buttonColor = json.optInt("buttonColor", NO_INT_VALUE);
31
 		button.buttonColor = json.optInt("buttonColor", NO_INT_VALUE);
33
 		button.buttonFontSize = json.optInt("buttonFontSize", NO_INT_VALUE);
32
 		button.buttonFontSize = json.optInt("buttonFontSize", NO_INT_VALUE);
34
-		button.buttonFontWeight = json.optString("buttonFontWeight", NO_VALUE);
33
+		button.buttonFontWeight = TextParser.parse(json, "buttonFontWeight");
35
 
34
 
36
-		JSONObject iconObject = json.optJSONObject("icon");
37
-		if (iconObject != null) {
38
-			button.icon = iconObject.optString("uri", NO_VALUE);
35
+		if (json.has("icon")) {
36
+			button.icon = TextParser.parse(json.optJSONObject("icon"), "uri");
39
 		}
37
 		}
40
 
38
 
41
 		return button;
39
 		return button;
42
 	}
40
 	}
43
 
41
 
44
-	public static ArrayList<Button> parseJsonArray(JSONArray jsonArray) {
42
+	static ArrayList<Button> parseJsonArray(JSONArray jsonArray) {
45
 		ArrayList<Button> buttons = new ArrayList<>();
43
 		ArrayList<Button> buttons = new ArrayList<>();
46
 
44
 
47
 		if (jsonArray == null) {
45
 		if (jsonArray == null) {
57
 		return buttons;
55
 		return buttons;
58
 	}
56
 	}
59
 
57
 
60
-	private static int parseShowAsAction(String showAsAction) {
61
-		if (NO_VALUE.equals(showAsAction)) {
58
+	private static int parseShowAsAction(JSONObject json) {
59
+	    final Text showAsAction = TextParser.parse(json, "showAsAction");
60
+		if (!showAsAction.hasValue()) {
62
 			return MenuItem.SHOW_AS_ACTION_IF_ROOM;
61
 			return MenuItem.SHOW_AS_ACTION_IF_ROOM;
63
 		}
62
 		}
64
 
63
 
65
-		switch (showAsAction) {
64
+		switch (showAsAction.get()) {
66
 			case "always":
65
 			case "always":
67
 				return MenuItem.SHOW_AS_ACTION_ALWAYS;
66
 				return MenuItem.SHOW_AS_ACTION_ALWAYS;
68
 			case "never":
67
 			case "never":

+ 0
- 5
lib/android/app/src/main/java/com/reactnativenavigation/parse/DEFAULT_VALUES.java 查看文件

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
 
3
 
4
-import android.graphics.Color;
5
-
6
 public interface DEFAULT_VALUES {
4
 public interface DEFAULT_VALUES {
7
-	String NO_VALUE = "";
8
 	int NO_INT_VALUE = Integer.MIN_VALUE;
5
 	int NO_INT_VALUE = Integer.MIN_VALUE;
9
-	float NO_FLOAT_VALUE = Float.MIN_VALUE;
10
-	int NO_COLOR_VALUE = Color.TRANSPARENT;
11
 }
6
 }

+ 7
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/Fraction.java 查看文件

1
+package com.reactnativenavigation.parse;
2
+
3
+public class Fraction extends Param<Float> {
4
+    public Fraction(float value) {
5
+        super(value);
6
+    }
7
+}

+ 9
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/FractionParser.java 查看文件

1
+package com.reactnativenavigation.parse;
2
+
3
+import org.json.JSONObject;
4
+
5
+public class FractionParser {
6
+    public static Fraction parse(JSONObject json, String fraction) {
7
+        return json.has(fraction) ? new Fraction(json.optInt(fraction)) : new NullFraction();
8
+    }
9
+}

+ 6
- 29
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java 查看文件

3
 import android.app.Activity;
3
 import android.app.Activity;
4
 
4
 
5
 import com.facebook.react.ReactInstanceManager;
5
 import com.facebook.react.ReactInstanceManager;
6
-import com.reactnativenavigation.react.ReactComponentViewCreator;
6
+import com.reactnativenavigation.utils.NoOpPromise;
7
 import com.reactnativenavigation.utils.TypefaceLoader;
7
 import com.reactnativenavigation.utils.TypefaceLoader;
8
 import com.reactnativenavigation.viewcontrollers.BottomTabsController;
8
 import com.reactnativenavigation.viewcontrollers.BottomTabsController;
9
 import com.reactnativenavigation.viewcontrollers.ComponentViewController;
9
 import com.reactnativenavigation.viewcontrollers.ComponentViewController;
10
 import com.reactnativenavigation.viewcontrollers.SideMenuController;
10
 import com.reactnativenavigation.viewcontrollers.SideMenuController;
11
 import com.reactnativenavigation.viewcontrollers.StackController;
11
 import com.reactnativenavigation.viewcontrollers.StackController;
12
 import com.reactnativenavigation.viewcontrollers.ViewController;
12
 import com.reactnativenavigation.viewcontrollers.ViewController;
13
-import com.reactnativenavigation.viewcontrollers.overlay.DialogViewController;
14
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabController;
13
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabController;
15
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsController;
14
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsController;
16
 import com.reactnativenavigation.views.ComponentViewCreator;
15
 import com.reactnativenavigation.views.ComponentViewCreator;
49
 				return createSideMenuLeft(node);
48
 				return createSideMenuLeft(node);
50
 			case SideMenuRight:
49
 			case SideMenuRight:
51
 				return createSideMenuRight(node);
50
 				return createSideMenuRight(node);
52
-//			case CustomDialog:
53
-//				return createDialogComponent(node);
54
             case TopTabs:
51
             case TopTabs:
55
                 return createTopTabs(node);
52
                 return createTopTabs(node);
56
-//            case TopTab:
57
-//                return createTopTab(node);
58
 			default:
53
 			default:
59
 				throw new IllegalArgumentException("Invalid node type: " + node.type);
54
 				throw new IllegalArgumentException("Invalid node type: " + node.type);
60
 		}
55
 		}
108
 	private ViewController createStack(LayoutNode node) {
103
 	private ViewController createStack(LayoutNode node) {
109
 		StackController stackController = new StackController(activity, node.id);
104
 		StackController stackController = new StackController(activity, node.id);
110
 		for (LayoutNode child : node.children) {
105
 		for (LayoutNode child : node.children) {
111
-			stackController.push(create(child), null);
106
+			stackController.animatePush(create(child), new NoOpPromise());
112
 		}
107
 		}
113
 		return stackController;
108
 		return stackController;
114
 	}
109
 	}
123
 		return tabsComponent;
118
 		return tabsComponent;
124
 	}
119
 	}
125
 
120
 
126
-	private ViewController createDialogComponent(LayoutNode node) {
127
-		String id = node.id;
128
-		String name = node.data.optString("name");
129
-		ReactComponentViewCreator creator = new ReactComponentViewCreator(reactInstanceManager);
130
-		return new DialogViewController(activity, id, name, creator);
131
-	}
132
-
133
     private ViewController createTopTabs(LayoutNode node) {
121
     private ViewController createTopTabs(LayoutNode node) {
134
-        final List<TopTabController> tabs = new ArrayList<>();
122
+        final List<ViewController> tabs = new ArrayList<>();
135
         for (int i = 0; i < node.children.size(); i++) {
123
         for (int i = 0; i < node.children.size(); i++) {
136
-            TopTabController tabController = (TopTabController) create(node.children.get(i));
137
-            tabController.setTabIndex(i);
124
+            ViewController tabController = create(node.children.get(i));
125
+            Options options = Options.parse(typefaceManager, node.children.get(i).getNavigationOptions(), defaultOptions);
126
+            options.setTopTabIndex(i);
138
             tabs.add(tabController);
127
             tabs.add(tabController);
139
         }
128
         }
140
         Options options = Options.parse(typefaceManager, node.getNavigationOptions(), defaultOptions);
129
         Options options = Options.parse(typefaceManager, node.getNavigationOptions(), defaultOptions);
141
         return new TopTabsController(activity, node.id, tabs, new TopTabsLayoutCreator(activity, tabs), options);
130
         return new TopTabsController(activity, node.id, tabs, new TopTabsLayoutCreator(activity, tabs), options);
142
     }
131
     }
143
-
144
-    private ViewController createTopTab(LayoutNode node) {
145
-        String id = node.id;
146
-        String name = node.data.optString("name");
147
-        Options options = Options.parse(typefaceManager, node.getNavigationOptions(), defaultOptions);
148
-        return new TopTabController(activity,
149
-                id,
150
-                name,
151
-                new ReactComponentViewCreator(reactInstanceManager),
152
-                options
153
-        );
154
-    }
155
 }
132
 }

+ 12
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/NullFraction.java 查看文件

1
+package com.reactnativenavigation.parse;
2
+
3
+public class NullFraction extends Fraction {
4
+    NullFraction() {
5
+        super(0);
6
+    }
7
+
8
+    @Override
9
+    public boolean hasValue() {
10
+        return false;
11
+    }
12
+}

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/NullNumber.java 查看文件

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
 public class NullNumber extends Number {
3
 public class NullNumber extends Number {
4
-    public NullNumber() {
4
+    NullNumber() {
5
         super(0);
5
         super(0);
6
     }
6
     }
7
 
7
 

+ 12
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/NullText.java 查看文件

1
+package com.reactnativenavigation.parse;
2
+
3
+public class NullText extends Text {
4
+    public NullText() {
5
+        super("");
6
+    }
7
+
8
+    @Override
9
+    public boolean hasValue() {
10
+        return false;
11
+    }
12
+}

+ 6
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/Options.java 查看文件

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
 import android.support.annotation.NonNull;
3
 import android.support.annotation.NonNull;
4
+import android.text.TextUtils;
4
 
5
 
5
 import com.reactnativenavigation.utils.TypefaceLoader;
6
 import com.reactnativenavigation.utils.TypefaceLoader;
6
 
7
 
14
 		NoValue;
15
 		NoValue;
15
 
16
 
16
 		static BooleanOptions parse(String value) {
17
 		static BooleanOptions parse(String value) {
17
-			if (value != null && !value.equals("")) {
18
+			if (!TextUtils.isEmpty(value)) {
18
 				return Boolean.valueOf(value) ? True : False;
19
 				return Boolean.valueOf(value) ? True : False;
19
 			}
20
 			}
20
 			return NoValue;
21
 			return NoValue;
44
     @NonNull public TopTabOptions topTabOptions = new TopTabOptions();
45
     @NonNull public TopTabOptions topTabOptions = new TopTabOptions();
45
     @NonNull public BottomTabsOptions bottomTabsOptions = new BottomTabsOptions();
46
     @NonNull public BottomTabsOptions bottomTabsOptions = new BottomTabsOptions();
46
 
47
 
48
+    void setTopTabIndex(int i) {
49
+        topTabOptions.tabIndex = i;
50
+    }
51
+
47
 	public void mergeWith(final Options other) {
52
 	public void mergeWith(final Options other) {
48
         topBarOptions.mergeWith(other.topBarOptions);
53
         topBarOptions.mergeWith(other.topBarOptions);
49
         topTabsOptions.mergeWith(other.topTabsOptions);
54
         topTabsOptions.mergeWith(other.topTabsOptions);

+ 4
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/Param.java 查看文件

14
         throw new RuntimeException("Tried to get null value!");
14
         throw new RuntimeException("Tried to get null value!");
15
     }
15
     }
16
 
16
 
17
+    public T get(T defaultValue) {
18
+        return hasValue() ? value : defaultValue;
19
+    }
20
+
17
     public boolean hasValue() {
21
     public boolean hasValue() {
18
         return value != null;
22
         return value != null;
19
     }
23
     }

+ 7
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/Text.java 查看文件

1
+package com.reactnativenavigation.parse;
2
+
3
+public class Text extends Param<String> {
4
+    public Text(String value) {
5
+        super(value);
6
+    }
7
+}

+ 9
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/TextParser.java 查看文件

1
+package com.reactnativenavigation.parse;
2
+
3
+import org.json.JSONObject;
4
+
5
+public class TextParser {
6
+    public static Text parse(JSONObject json, String text) {
7
+        return json.has(text) ? new Text(json.optString(text)) : new NullText();
8
+    }
9
+}

+ 17
- 18
lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarOptions.java 查看文件

2
 
2
 
3
 
3
 
4
 import android.graphics.Typeface;
4
 import android.graphics.Typeface;
5
-import android.support.annotation.ColorInt;
6
 import android.support.annotation.Nullable;
5
 import android.support.annotation.Nullable;
7
 
6
 
8
 import com.reactnativenavigation.utils.TypefaceLoader;
7
 import com.reactnativenavigation.utils.TypefaceLoader;
17
         TopBarOptions options = new TopBarOptions();
16
         TopBarOptions options = new TopBarOptions();
18
         if (json == null) return options;
17
         if (json == null) return options;
19
 
18
 
20
-        options.title = json.optString("title", NO_VALUE);
21
-        options.backgroundColor = json.optInt("backgroundColor", NO_COLOR_VALUE);
22
-        options.textColor = json.optInt("textColor", NO_COLOR_VALUE);
23
-        options.textFontSize = (float) json.optDouble("textFontSize", NO_FLOAT_VALUE);
24
-        options.textFontFamily = typefaceManager.getTypeFace(json.optString("textFontFamily", NO_VALUE));
19
+        options.title = TextParser.parse(json, "title");
20
+        options.backgroundColor = ColorParser.parse(json, "backgroundColor");
21
+        options.textColor = ColorParser.parse(json, "textColor");
22
+        options.textFontSize = FractionParser.parse(json, "textFontSize");
23
+        options.textFontFamily = typefaceManager.getTypeFace(json.optString("textFontFamily", ""));
25
         options.hidden = Options.BooleanOptions.parse(json.optString("hidden"));
24
         options.hidden = Options.BooleanOptions.parse(json.optString("hidden"));
26
         options.animateHide = Options.BooleanOptions.parse(json.optString("animateHide"));
25
         options.animateHide = Options.BooleanOptions.parse(json.optString("animateHide"));
27
         options.hideOnScroll = Options.BooleanOptions.parse(json.optString("hideOnScroll"));
26
         options.hideOnScroll = Options.BooleanOptions.parse(json.optString("hideOnScroll"));
32
         return options;
31
         return options;
33
     }
32
     }
34
 
33
 
35
-    public String title = NO_VALUE;
36
-    @ColorInt public int backgroundColor = NO_COLOR_VALUE;
37
-    @ColorInt public int textColor = NO_COLOR_VALUE;
38
-    public float textFontSize = NO_FLOAT_VALUE;
34
+    public Text title = new NullText();
35
+    public Color backgroundColor = new NullColor();
36
+    public Color textColor = new NullColor();
37
+    public Fraction textFontSize = new NullFraction();
39
     @Nullable public Typeface textFontFamily;
38
     @Nullable public Typeface textFontFamily;
40
     public Options.BooleanOptions hidden = Options.BooleanOptions.NoValue;
39
     public Options.BooleanOptions hidden = Options.BooleanOptions.NoValue;
41
     public Options.BooleanOptions animateHide = Options.BooleanOptions.NoValue;
40
     public Options.BooleanOptions animateHide = Options.BooleanOptions.NoValue;
45
     public ArrayList<Button> rightButtons;
44
     public ArrayList<Button> rightButtons;
46
 
45
 
47
     void mergeWith(final TopBarOptions other) {
46
     void mergeWith(final TopBarOptions other) {
48
-        if (!NO_VALUE.equals(other.title)) title = other.title;
49
-        if (other.backgroundColor != NO_COLOR_VALUE)
47
+        if (other.title != null) title = other.title;
48
+        if (other.backgroundColor.hasValue())
50
             backgroundColor = other.backgroundColor;
49
             backgroundColor = other.backgroundColor;
51
-        if (other.textColor != NO_COLOR_VALUE)
50
+        if (other.textColor.hasValue())
52
             textColor = other.textColor;
51
             textColor = other.textColor;
53
-        if (other.textFontSize != NO_FLOAT_VALUE)
52
+        if (other.textFontSize.hasValue())
54
             textFontSize = other.textFontSize;
53
             textFontSize = other.textFontSize;
55
         if (other.textFontFamily != null)
54
         if (other.textFontFamily != null)
56
             textFontFamily = other.textFontFamily;
55
             textFontFamily = other.textFontFamily;
73
     }
72
     }
74
 
73
 
75
     void mergeWithDefault(TopBarOptions defaultOptions) {
74
     void mergeWithDefault(TopBarOptions defaultOptions) {
76
-        if (NO_VALUE.equals(title))
75
+        if (title == null)
77
             title = defaultOptions.title;
76
             title = defaultOptions.title;
78
-        if (backgroundColor == NO_COLOR_VALUE)
77
+        if (!backgroundColor.hasValue())
79
             backgroundColor = defaultOptions.backgroundColor;
78
             backgroundColor = defaultOptions.backgroundColor;
80
-        if (textColor == NO_COLOR_VALUE)
79
+        if (!textColor.hasValue())
81
             textColor = defaultOptions.textColor;
80
             textColor = defaultOptions.textColor;
82
-        if (textFontSize == NO_FLOAT_VALUE)
81
+        if (!textFontSize.hasValue())
83
             textFontSize = defaultOptions.textFontSize;
82
             textFontSize = defaultOptions.textFontSize;
84
         if (textFontFamily == null)
83
         if (textFontFamily == null)
85
             textFontFamily = defaultOptions.textFontFamily;
84
             textFontFamily = defaultOptions.textFontFamily;

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/parse/TopTabOptions.java 查看文件

8
 import org.json.JSONObject;
8
 import org.json.JSONObject;
9
 
9
 
10
 public class TopTabOptions implements DEFAULT_VALUES {
10
 public class TopTabOptions implements DEFAULT_VALUES {
11
-    public String title = NO_VALUE;
11
+    public Text title = new NullText();
12
     @Nullable public Typeface fontFamily;
12
     @Nullable public Typeface fontFamily;
13
     public int tabIndex;
13
     public int tabIndex;
14
 
14
 
16
         TopTabOptions result = new TopTabOptions();
16
         TopTabOptions result = new TopTabOptions();
17
         if (json == null) return result;
17
         if (json == null) return result;
18
 
18
 
19
-        result.title = json.optString("title", NO_VALUE);
19
+        result.title = TextParser.parse(json, "title");
20
         result.fontFamily = typefaceManager.getTypeFace(json.optString("titleFontFamily"));
20
         result.fontFamily = typefaceManager.getTypeFace(json.optString("titleFontFamily"));
21
         return result;
21
         return result;
22
     }
22
     }

+ 11
- 12
lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java 查看文件

5
 import com.reactnativenavigation.parse.TopBarOptions;
5
 import com.reactnativenavigation.parse.TopBarOptions;
6
 import com.reactnativenavigation.parse.TopTabOptions;
6
 import com.reactnativenavigation.parse.TopTabOptions;
7
 import com.reactnativenavigation.parse.TopTabsOptions;
7
 import com.reactnativenavigation.parse.TopTabsOptions;
8
-import com.reactnativenavigation.views.Component;
8
+import com.reactnativenavigation.views.ReactComponent;
9
 import com.reactnativenavigation.views.TopBar;
9
 import com.reactnativenavigation.views.TopBar;
10
 
10
 
11
 import java.util.ArrayList;
11
 import java.util.ArrayList;
14
 import static com.reactnativenavigation.parse.Options.BooleanOptions.True;
14
 import static com.reactnativenavigation.parse.Options.BooleanOptions.True;
15
 
15
 
16
 public class OptionsPresenter {
16
 public class OptionsPresenter {
17
-
18
-    private Component reactComponent;
19
     private TopBar topBar;
17
     private TopBar topBar;
18
+    private ReactComponent component;
20
 
19
 
21
-    public OptionsPresenter(Component reactComponent) {
22
-        this.reactComponent = reactComponent;
23
-        this.topBar = reactComponent.getTopBar();
20
+    public OptionsPresenter(TopBar topBar, ReactComponent component) {
21
+        this.topBar = topBar;
22
+        this.component = component;
24
     }
23
     }
25
 
24
 
26
     public void applyOptions(Options options) {
25
     public void applyOptions(Options options) {
27
-        applyTopBarOptions(options.topBarOptions);
28
         applyButtons(options.topBarOptions.leftButtons, options.topBarOptions.rightButtons);
26
         applyButtons(options.topBarOptions.leftButtons, options.topBarOptions.rightButtons);
27
+        applyTopBarOptions(options.topBarOptions);
29
         applyTopTabsOptions(options.topTabsOptions);
28
         applyTopTabsOptions(options.topTabsOptions);
30
         applyTopTabOptions(options.topTabOptions);
29
         applyTopTabOptions(options.topTabOptions);
31
     }
30
     }
32
 
31
 
33
     private void applyTopBarOptions(TopBarOptions options) {
32
     private void applyTopBarOptions(TopBarOptions options) {
34
-        topBar.setTitle(options.title);
33
+        if (options.title.hasValue()) topBar.setTitle(options.title.get());
35
         topBar.setBackgroundColor(options.backgroundColor);
34
         topBar.setBackgroundColor(options.backgroundColor);
36
         topBar.setTitleTextColor(options.textColor);
35
         topBar.setTitleTextColor(options.textColor);
37
         topBar.setTitleFontSize(options.textFontSize);
36
         topBar.setTitleFontSize(options.textFontSize);
38
 
37
 
39
         topBar.setTitleTypeface(options.textFontFamily);
38
         topBar.setTitleTypeface(options.textFontFamily);
40
-        if (options.hidden == Options.BooleanOptions.True) {
39
+        if (options.hidden == True) {
41
             topBar.hide(options.animateHide);
40
             topBar.hide(options.animateHide);
42
         }
41
         }
43
-        if (options.hidden == Options.BooleanOptions.False) {
42
+        if (options.hidden == False) {
44
             topBar.show(options.animateHide);
43
             topBar.show(options.animateHide);
45
         }
44
         }
46
         if (options.drawBehind == True) {
45
         if (options.drawBehind == True) {
47
-            reactComponent.drawBehindTopBar();
46
+            component.drawBehindTopBar();
48
         } else if (options.drawBehind == False) {
47
         } else if (options.drawBehind == False) {
49
-            reactComponent.drawBelowTopBar();
48
+            component.drawBelowTopBar(topBar);
50
         }
49
         }
51
 
50
 
52
         if (options.hideOnScroll == True) {
51
         if (options.hideOnScroll == True) {

+ 2
- 13
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java 查看文件

19
 import com.reactnativenavigation.utils.UiThread;
19
 import com.reactnativenavigation.utils.UiThread;
20
 import com.reactnativenavigation.viewcontrollers.Navigator;
20
 import com.reactnativenavigation.viewcontrollers.Navigator;
21
 import com.reactnativenavigation.viewcontrollers.ViewController;
21
 import com.reactnativenavigation.viewcontrollers.ViewController;
22
-import com.reactnativenavigation.viewcontrollers.overlay.OverlayFactory;
23
 
22
 
24
 public class NavigationModule extends ReactContextBaseJavaModule {
23
 public class NavigationModule extends ReactContextBaseJavaModule {
25
 	private static final String NAME = "RNNBridgeModule";
24
 	private static final String NAME = "RNNBridgeModule";
102
 
101
 
103
 	@ReactMethod
102
 	@ReactMethod
104
 	public void showOverlay(final String type, final ReadableMap data, final Promise promise) {
103
 	public void showOverlay(final String type, final ReadableMap data, final Promise promise) {
105
-		if (OverlayFactory.Overlay.create(type) == OverlayFactory.Overlay.CustomDialog) {
106
-			final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(data));
107
-			handle(() -> {
108
-                ViewController viewController = newLayoutFactory().create(layoutTree);
109
-                navigator().showOverlay(type, OverlayOptions.create(viewController), promise);
110
-            });
111
-		} else {
112
-			final OverlayOptions overlayOptions = OverlayOptions.parse(JSONParser.parse(data));
113
-			handle(() -> navigator().showOverlay(type, overlayOptions, promise));
114
-		}
115
-
116
-
104
+        final OverlayOptions overlayOptions = OverlayOptions.parse(JSONParser.parse(data));
105
+        handle(() -> navigator().showOverlay(type, overlayOptions, promise));
117
 	}
106
 	}
118
 
107
 
119
 	@ReactMethod
108
 	@ReactMethod

+ 14
- 0
lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java 查看文件

7
 
7
 
8
 import com.facebook.react.ReactInstanceManager;
8
 import com.facebook.react.ReactInstanceManager;
9
 import com.facebook.react.ReactRootView;
9
 import com.facebook.react.ReactRootView;
10
+import com.facebook.react.bridge.ReactContext;
11
+import com.facebook.react.uimanager.UIManagerModule;
12
+import com.facebook.react.uimanager.events.EventDispatcher;
13
+import com.reactnativenavigation.interfaces.ScrollEventListener;
10
 import com.reactnativenavigation.viewcontrollers.ComponentViewController;
14
 import com.reactnativenavigation.viewcontrollers.ComponentViewController;
11
 
15
 
12
 @SuppressLint("ViewConstructor")
16
 @SuppressLint("ViewConstructor")
64
 	public void sendOnNavigationButtonPressed(String buttonId) {
68
 	public void sendOnNavigationButtonPressed(String buttonId) {
65
 		new NavigationEvent(reactInstanceManager.getCurrentReactContext()).sendOnNavigationButtonPressed(componentId, buttonId);
69
 		new NavigationEvent(reactInstanceManager.getCurrentReactContext()).sendOnNavigationButtonPressed(componentId, buttonId);
66
 	}
70
 	}
71
+
72
+    @Override
73
+    public ScrollEventListener getScrollEventListener() {
74
+        return new ScrollEventListener(getEventDispatcher());
75
+    }
76
+
77
+    public EventDispatcher getEventDispatcher() {
78
+        ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
79
+        return reactContext == null ? null : reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
80
+    }
67
 }
81
 }

+ 42
- 39
lib/android/app/src/main/java/com/reactnativenavigation/utils/ImageUtils.java 查看文件

8
 import android.net.Uri;
8
 import android.net.Uri;
9
 import android.os.StrictMode;
9
 import android.os.StrictMode;
10
 import android.support.annotation.NonNull;
10
 import android.support.annotation.NonNull;
11
+import android.support.annotation.Nullable;
11
 
12
 
13
+import com.reactnativenavigation.NavigationApplication;
14
+
15
+import java.io.FileNotFoundException;
12
 import java.io.IOException;
16
 import java.io.IOException;
13
 import java.io.InputStream;
17
 import java.io.InputStream;
14
 import java.net.URL;
18
 import java.net.URL;
21
 		void onError(Throwable error);
25
 		void onError(Throwable error);
22
 	}
26
 	}
23
 
27
 
24
-	public static void tryLoadIcon(final Context context, final String uri, final ImageLoadingListener listener) {
25
-		if (uri == null) {
26
-			if (listener != null) {
27
-				listener.onError(new IllegalArgumentException("Uri is null"));
28
-			}
29
-			return;
30
-		}
31
-		runWorkerThread(new Runnable() {
32
-			@Override
33
-			public void run() {
34
-				loadIcon(context, uri, listener);
35
-			}
36
-		});
37
-	}
28
+	public static void loadIcon(final Context context, final String uri, final ImageLoadingListener listener) {
29
+        try {
30
+            StrictMode.ThreadPolicy threadPolicy = adjustThreadPolicyDebug();
31
+            
32
+            InputStream is = openStream(context, uri);
33
+            Bitmap bitmap = BitmapFactory.decodeStream(is);
34
+            Drawable drawable = new BitmapDrawable(context.getResources(), bitmap);
35
+            listener.onComplete(drawable);
38
 
36
 
39
-	private static void loadIcon(Context context, String uri, final ImageLoadingListener listener) {
40
-		try {
41
-			InputStream is = null;
42
-			if (uri.contains("http")) {
43
-				URL url = new URL(uri);
44
-				is = url.openStream();
45
-			} else {
46
-				is = context.getContentResolver().openInputStream(Uri.parse(uri));
47
-			}
37
+            restoreThreadPolicyDebug(threadPolicy);
38
+        } catch (IOException e) {
39
+            listener.onError(e);
40
+        }
41
+    }
48
 
42
 
49
-			Bitmap bitmap = BitmapFactory.decodeStream(is);
50
-			Drawable drawable = new BitmapDrawable(context.getResources(), bitmap);
51
-			if (listener != null) {
52
-				listener.onComplete(drawable);
53
-			}
54
-		} catch (IOException e) {
55
-			if (listener != null) {
56
-				listener.onError(e);
57
-			} else {
58
-				e.printStackTrace();
59
-			}
60
-		}
61
-	}
43
+    private static StrictMode.ThreadPolicy adjustThreadPolicyDebug() {
44
+        StrictMode.ThreadPolicy threadPolicy = null;
45
+        if (NavigationApplication.instance.isDebug()) {
46
+            threadPolicy = StrictMode.getThreadPolicy();
47
+            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitNetwork().build());
48
+        }
49
+        return threadPolicy;
50
+    }
62
 
51
 
63
-	private static void runWorkerThread(Runnable runnable) {
64
-		new Thread(runnable).start();
65
-	}
52
+    private static void restoreThreadPolicyDebug(@Nullable StrictMode.ThreadPolicy threadPolicy) {
53
+        if (NavigationApplication.instance.isDebug() && threadPolicy != null) {
54
+            StrictMode.setThreadPolicy(threadPolicy);
55
+        }
56
+    }
57
+
58
+    private static InputStream openStream(Context context, String uri) throws IOException {
59
+        return uri.contains("http") ? remoteUrl(uri) : localFile(context, uri);
60
+    }
61
+
62
+    private static InputStream remoteUrl(String uri) throws IOException {
63
+        return new URL(uri).openStream();
64
+    }
65
+
66
+    private static InputStream localFile(Context context, String uri) throws FileNotFoundException {
67
+        return context.getContentResolver().openInputStream(Uri.parse(uri));
68
+    }
66
 }
69
 }

+ 37
- 0
lib/android/app/src/main/java/com/reactnativenavigation/utils/NoOpPromise.java 查看文件

1
+package com.reactnativenavigation.utils;
2
+
3
+import com.facebook.react.bridge.Promise;
4
+
5
+import javax.annotation.Nullable;
6
+
7
+public class NoOpPromise implements Promise {
8
+    @Override
9
+    public void resolve(@Nullable Object value) {
10
+
11
+    }
12
+
13
+    @Override
14
+    public void reject(String code, String message) {
15
+
16
+    }
17
+
18
+    @Override
19
+    public void reject(String code, Throwable e) {
20
+
21
+    }
22
+
23
+    @Override
24
+    public void reject(String code, String message, Throwable e) {
25
+
26
+    }
27
+
28
+    @Override
29
+    public void reject(String message) {
30
+
31
+    }
32
+
33
+    @Override
34
+    public void reject(Throwable reason) {
35
+
36
+    }
37
+}

+ 20
- 22
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/BottomTabsController.java 查看文件

11
 import android.widget.RelativeLayout;
11
 import android.widget.RelativeLayout;
12
 
12
 
13
 import com.reactnativenavigation.parse.Options;
13
 import com.reactnativenavigation.parse.Options;
14
+import com.reactnativenavigation.parse.Text;
14
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
15
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
15
 import com.reactnativenavigation.utils.CompatUtils;
16
 import com.reactnativenavigation.utils.CompatUtils;
16
 
17
 
23
 import static android.widget.RelativeLayout.ABOVE;
24
 import static android.widget.RelativeLayout.ABOVE;
24
 import static android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM;
25
 import static android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM;
25
 import static com.reactnativenavigation.parse.DEFAULT_VALUES.NO_INT_VALUE;
26
 import static com.reactnativenavigation.parse.DEFAULT_VALUES.NO_INT_VALUE;
26
-import static com.reactnativenavigation.parse.DEFAULT_VALUES.NO_VALUE;
27
 
27
 
28
 public class BottomTabsController extends ParentController
28
 public class BottomTabsController extends ParentController
29
 		implements BottomNavigationView.OnNavigationItemSelectedListener, NavigationOptionsListener {
29
 		implements BottomNavigationView.OnNavigationItemSelectedListener, NavigationOptionsListener {
60
 		return true;
60
 		return true;
61
 	}
61
 	}
62
 
62
 
63
-	public void selectTabAtIndex(final int newIndex) {
63
+	void selectTabAtIndex(final int newIndex) {
64
 		tabs.get(selectedIndex).getView().setVisibility(View.GONE);
64
 		tabs.get(selectedIndex).getView().setVisibility(View.GONE);
65
 		selectedIndex = newIndex;
65
 		selectedIndex = newIndex;
66
 		tabs.get(selectedIndex).getView().setVisibility(View.VISIBLE);
66
 		tabs.get(selectedIndex).getView().setVisibility(View.VISIBLE);
87
 		getView().addView(tab.getView(), params);
87
 		getView().addView(tab.getView(), params);
88
 	}
88
 	}
89
 
89
 
90
-	public int getSelectedIndex() {
90
+	int getSelectedIndex() {
91
 		return selectedIndex;
91
 		return selectedIndex;
92
 	}
92
 	}
93
 
93
 
99
 
99
 
100
 	@Override
100
 	@Override
101
 	public void mergeOptions(Options options) {
101
 	public void mergeOptions(Options options) {
102
-		if (options.bottomTabsOptions != null) {
103
-			if (options.bottomTabsOptions.currentTabIndex != NO_INT_VALUE) {
104
-				selectTabAtIndex(options.bottomTabsOptions.currentTabIndex);
105
-			}
106
-			if (!NO_VALUE.equals(options.bottomTabsOptions.currentTabId)) {
107
-				String id = options.bottomTabsOptions.currentTabId;
108
-				for (ViewController controller : tabs) {
109
-					if (controller.getId().equals(id)) {
110
-						selectTabAtIndex(tabs.indexOf(controller));
111
-					}
112
-					if (controller instanceof StackController) {
113
-						if (hasControlWithId((StackController) controller, id)) {
114
-							selectTabAtIndex(tabs.indexOf(controller));
115
-						}
116
-					}
117
-				}
118
-			}
119
-		}
120
-	}
102
+        if (options.bottomTabsOptions.currentTabIndex != NO_INT_VALUE) {
103
+            selectTabAtIndex(options.bottomTabsOptions.currentTabIndex);
104
+        }
105
+        if (options.bottomTabsOptions.currentTabId.hasValue()) {
106
+            Text id = options.bottomTabsOptions.currentTabId;
107
+            for (ViewController controller : tabs) {
108
+                if (controller.getId().equals(id.get())) {
109
+                    selectTabAtIndex(tabs.indexOf(controller));
110
+                }
111
+                if (controller instanceof StackController) {
112
+                    if (hasControlWithId((StackController) controller, id.get())) {
113
+                        selectTabAtIndex(tabs.indexOf(controller));
114
+                    }
115
+                }
116
+            }
117
+        }
118
+    }
121
 
119
 
122
 	private boolean hasControlWithId(StackController controller, String id) {
120
 	private boolean hasControlWithId(StackController controller, String id) {
123
 		for (ViewController child : controller.getChildControllers()) {
121
 		for (ViewController child : controller.getChildControllers()) {

+ 9
- 8
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java 查看文件

4
 import android.support.annotation.*;
4
 import android.support.annotation.*;
5
 import android.view.*;
5
 import android.view.*;
6
 
6
 
7
+import com.reactnativenavigation.interfaces.ScrollEventListener;
7
 import com.reactnativenavigation.parse.*;
8
 import com.reactnativenavigation.parse.*;
8
 import com.reactnativenavigation.presentation.*;
9
 import com.reactnativenavigation.presentation.*;
9
 import com.reactnativenavigation.views.*;
10
 import com.reactnativenavigation.views.*;
28
         void sendComponentStop();
29
         void sendComponentStop();
29
 
30
 
30
         void sendOnNavigationButtonPressed(String buttonId);
31
         void sendOnNavigationButtonPressed(String buttonId);
32
+
33
+        ScrollEventListener getScrollEventListener();
31
     }
34
     }
32
 
35
 
33
     private final String componentName;
36
     private final String componentName;
34
 
37
 
35
     private final ReactViewCreator viewCreator;
38
     private final ReactViewCreator viewCreator;
36
-    private Options options;
37
     private ReactComponent component;
39
     private ReactComponent component;
38
 
40
 
39
     public ComponentViewController(final Activity activity,
41
     public ComponentViewController(final Activity activity,
44
         super(activity, id);
46
         super(activity, id);
45
         this.componentName = componentName;
47
         this.componentName = componentName;
46
         this.viewCreator = viewCreator;
48
         this.viewCreator = viewCreator;
47
-        this.options = initialNavigationOptions;
48
-    }
49
-
50
-    @RestrictTo(RestrictTo.Scope.TESTS)
51
-    TopBar getTopBar() {
52
-        return component.getTopBar();
49
+        options = initialNavigationOptions;
53
     }
50
     }
54
 
51
 
55
     @Override
52
     @Override
63
     public void onViewAppeared() {
60
     public void onViewAppeared() {
64
         super.onViewAppeared();
61
         super.onViewAppeared();
65
         ensureViewIsCreated();
62
         ensureViewIsCreated();
66
-        component.applyOptions(options);
63
+        applyOnParentStack(parentController -> {
64
+            parentController.clearOptions();
65
+            parentController.applyOptions(options, component);
66
+        });
67
         component.sendComponentStart();
67
         component.sendComponentStart();
68
     }
68
     }
69
 
69
 
89
     public void mergeOptions(Options options) {
89
     public void mergeOptions(Options options) {
90
         this.options.mergeWith(options);
90
         this.options.mergeWith(options);
91
         component.applyOptions(this.options);
91
         component.applyOptions(this.options);
92
+        applyOnParentStack(parentController -> parentController.applyOptions(this.options, component));
92
     }
93
     }
93
 
94
 
94
     Options getOptions() {
95
     Options getOptions() {

+ 0
- 104
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ContainerViewController.java 查看文件

1
-package com.reactnativenavigation.viewcontrollers;
2
-
3
-import android.app.Activity;
4
-import android.support.annotation.NonNull;
5
-import android.support.annotation.RestrictTo;
6
-import android.view.View;
7
-
8
-import com.reactnativenavigation.parse.Options;
9
-import com.reactnativenavigation.presentation.NavigationOptionsListener;
10
-import com.reactnativenavigation.views.ReactComponent;
11
-import com.reactnativenavigation.views.TopBar;
12
-
13
-public class ContainerViewController extends ViewController implements NavigationOptionsListener {
14
-
15
-    public interface ReactViewCreator {
16
-
17
-        IReactView create(Activity activity, String containerId, String containerName);
18
-    }
19
-
20
-    public interface IReactView {
21
-
22
-        boolean isReady();
23
-
24
-        View asView();
25
-
26
-        void destroy();
27
-
28
-        void sendComponentStart();
29
-
30
-        void sendComponentStop();
31
-
32
-        void sendOnNavigationButtonPressed(String buttonId);
33
-    }
34
-
35
-    private final String componentName;
36
-
37
-    private final ReactViewCreator viewCreator;
38
-    private Options options;
39
-    private ReactComponent component;
40
-
41
-    public ContainerViewController(final Activity activity,
42
-                                   final String id,
43
-                                   final String componentName,
44
-                                   final ReactViewCreator viewCreator,
45
-                                   final Options initialOptions) {
46
-        super(activity, id);
47
-        this.componentName = componentName;
48
-        this.viewCreator = viewCreator;
49
-        this.options = initialOptions;
50
-    }
51
-
52
-    @RestrictTo(RestrictTo.Scope.TESTS)
53
-    TopBar getTopBar() {
54
-        return component.getTopBar();
55
-    }
56
-
57
-    @RestrictTo(RestrictTo.Scope.TESTS)
58
-    ReactComponent getComponent() {
59
-        return component;
60
-    }
61
-
62
-    @Override
63
-    public void destroy() {
64
-        super.destroy();
65
-        if (component != null) component.destroy();
66
-        component = null;
67
-    }
68
-
69
-    @Override
70
-    public void onViewAppeared() {
71
-        super.onViewAppeared();
72
-        ensureViewIsCreated();
73
-        component.applyOptions(options);
74
-        component.sendComponentStart();
75
-    }
76
-
77
-    @Override
78
-    public void onViewDisappear() {
79
-        super.onViewDisappear();
80
-        component.sendComponentStop();
81
-    }
82
-
83
-    @Override
84
-    protected boolean isViewShown() {
85
-        return super.isViewShown() && component.isReady();
86
-    }
87
-
88
-    @NonNull
89
-    @Override
90
-    protected View createView() {
91
-        component = (ReactComponent) viewCreator.create(getActivity(), getId(), componentName);
92
-        return component.asView();
93
-    }
94
-
95
-    @Override
96
-    public void mergeOptions(Options options) {
97
-        this.options.mergeWith(options);
98
-        component.applyOptions(this.options);
99
-    }
100
-
101
-    Options getOptions() {
102
-        return options;
103
-    }
104
-}

+ 8
- 38
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java 查看文件

12
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
12
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
13
 import com.reactnativenavigation.presentation.OverlayPresenter;
13
 import com.reactnativenavigation.presentation.OverlayPresenter;
14
 import com.reactnativenavigation.utils.CompatUtils;
14
 import com.reactnativenavigation.utils.CompatUtils;
15
+import com.reactnativenavigation.utils.NoOpPromise;
15
 
16
 
16
 import java.util.Collection;
17
 import java.util.Collection;
17
 import java.util.Collections;
18
 import java.util.Collections;
18
 
19
 
19
 public class Navigator extends ParentController {
20
 public class Navigator extends ParentController {
20
 
21
 
21
-	private final ModalStack modalStack = new ModalStack();
22
+    private static final NoOpPromise NO_OP = new NoOpPromise();
23
+    private final ModalStack modalStack = new ModalStack();
22
 	private ViewController root;
24
 	private ViewController root;
23
 	private OverlayPresenter overlayPresenter;
25
 	private OverlayPresenter overlayPresenter;
24
     private Options defaultOptions = new Options();
26
     private Options defaultOptions = new Options();
27
 		super(activity, "navigator" + CompatUtils.generateViewId());
29
 		super(activity, "navigator" + CompatUtils.generateViewId());
28
 	}
30
 	}
29
 
31
 
30
-	@NonNull
32
+    @NonNull
31
 	@Override
33
 	@Override
32
 	protected ViewGroup createView() {
34
 	protected ViewGroup createView() {
33
 		return new FrameLayout(getActivity());
35
 		return new FrameLayout(getActivity());
46
 
48
 
47
 	@Override
49
 	@Override
48
 	public void destroy() {
50
 	public void destroy() {
49
-		modalStack.dismissAll(null);
51
+		modalStack.dismissAll(NO_OP);
50
 		super.destroy();
52
 		super.destroy();
51
 	}
53
 	}
52
 
54
 
53
-	/*
54
-	 * Navigation methods
55
-	 */
56
-
57
-	void setRoot(final ViewController viewController) {
58
-		setRoot(viewController, null);
59
-	}
60
-
61
 	public void setRoot(final ViewController viewController, Promise promise) {
55
 	public void setRoot(final ViewController viewController, Promise promise) {
62
 		if (root != null) {
56
 		if (root != null) {
63
 			root.destroy();
57
 			root.destroy();
65
 
59
 
66
 		root = viewController;
60
 		root = viewController;
67
 		getView().addView(viewController.getView());
61
 		getView().addView(viewController.getView());
68
-		if (promise != null) {
69
-			promise.resolve(viewController.getId());
70
-		}
62
+        promise.resolve(viewController.getId());
71
 	}
63
 	}
72
 
64
 
73
     public void setDefaultOptions(Options defaultOptions) {
65
     public void setDefaultOptions(Options defaultOptions) {
88
 		}
80
 		}
89
 	}
81
 	}
90
 
82
 
91
-	public void push(final String fromId, final ViewController viewController) {
92
-		push(fromId, viewController, null);
93
-	}
94
-
95
 	public void push(final String fromId, final ViewController viewController, Promise promise) {
83
 	public void push(final String fromId, final ViewController viewController, Promise promise) {
96
 		ViewController from = findControllerById(fromId);
84
 		ViewController from = findControllerById(fromId);
97
 		if (from != null) {
85
 		if (from != null) {
98
-		    from.performOnParentStack(stack -> stack.push(viewController, promise));
86
+		    from.performOnParentStack(stack -> stack.animatePush(viewController, promise));
99
 		}
87
 		}
100
 	}
88
 	}
101
 
89
 
102
-	void pop(final String fromId) {
103
-		pop(fromId, null);
104
-	}
105
-
106
 	void pop(final String fromId, Promise promise) {
90
 	void pop(final String fromId, Promise promise) {
107
 		ViewController from = findControllerById(fromId);
91
 		ViewController from = findControllerById(fromId);
108
 		if (from != null) {
92
 		if (from != null) {
110
 		}
94
 		}
111
 	}
95
 	}
112
 
96
 
113
-	void popSpecific(final String id) {
114
-		popSpecific(id, null);
115
-	}
116
-
117
 	public void popSpecific(final String id, Promise promise) {
97
 	public void popSpecific(final String id, Promise promise) {
118
 		ViewController from = findControllerById(id);
98
 		ViewController from = findControllerById(id);
119
 		if (from != null) {
99
 		if (from != null) {
123
 		}
103
 		}
124
 	}
104
 	}
125
 
105
 
126
-	void popToRoot(final String id) {
127
-		popToRoot(id, null);
128
-	}
129
-
130
 	public void popToRoot(final String id, Promise promise) {
106
 	public void popToRoot(final String id, Promise promise) {
131
 		ViewController from = findControllerById(id);
107
 		ViewController from = findControllerById(id);
132
 		if (from != null) {
108
 		if (from != null) {
134
 		}
110
 		}
135
 	}
111
 	}
136
 
112
 
137
-	void popTo(final String componentId) {
138
-		popTo(componentId, null);
139
-	}
140
-
141
 	public void popTo(final String componentId, Promise promise) {
113
 	public void popTo(final String componentId, Promise promise) {
142
 		ViewController target = findControllerById(componentId);
114
 		ViewController target = findControllerById(componentId);
143
 		if (target != null) {
115
 		if (target != null) {
170
 	}
142
 	}
171
 
143
 
172
 	static void rejectPromise(Promise promise) {
144
 	static void rejectPromise(Promise promise) {
173
-		if (promise != null) {
174
-			promise.reject(new Throwable("Nothing to pop"));
175
-		}
145
+        promise.reject(new Throwable("Nothing to pop"));
176
 	}
146
 	}
177
 
147
 
178
     @Nullable
148
     @Nullable

+ 16
- 5
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java 查看文件

5
 import android.support.annotation.Nullable;
5
 import android.support.annotation.Nullable;
6
 import android.view.ViewGroup;
6
 import android.view.ViewGroup;
7
 
7
 
8
+import com.reactnativenavigation.parse.Options;
9
+import com.reactnativenavigation.views.ReactComponent;
10
+
8
 import java.util.Collection;
11
 import java.util.Collection;
9
 
12
 
10
-public abstract class ParentController extends ViewController {
13
+public abstract class ParentController<T extends ViewGroup> extends ViewController {
11
 
14
 
12
 	public ParentController(final Activity activity, final String id) {
15
 	public ParentController(final Activity activity, final String id) {
13
 		super(activity, id);
16
 		super(activity, id);
15
 
18
 
16
 	@NonNull
19
 	@NonNull
17
 	@Override
20
 	@Override
18
-	public ViewGroup getView() {
19
-		return (ViewGroup) super.getView();
21
+	public T getView() {
22
+		return (T) super.getView();
20
 	}
23
 	}
21
 
24
 
22
 	@NonNull
25
 	@NonNull
23
 	@Override
26
 	@Override
24
-	protected abstract ViewGroup createView();
27
+	protected abstract T createView();
25
 
28
 
26
-	@NonNull
29
+    @NonNull
27
 	public abstract Collection<? extends ViewController> getChildControllers();
30
 	public abstract Collection<? extends ViewController> getChildControllers();
28
 
31
 
29
 	@Nullable
32
 	@Nullable
40
 		return null;
43
 		return null;
41
 	}
44
 	}
42
 
45
 
46
+    public void applyOptions(Options options, ReactComponent childComponent) {
47
+
48
+    }
49
+
43
 	@Override
50
 	@Override
44
 	public void destroy() {
51
 	public void destroy() {
45
 		super.destroy();
52
 		super.destroy();
47
 			child.destroy();
54
 			child.destroy();
48
 		}
55
 		}
49
 	}
56
 	}
57
+
58
+    void clearOptions() {
59
+
60
+    }
50
 }
61
 }

+ 78
- 80
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java 查看文件

2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.support.annotation.NonNull;
4
 import android.support.annotation.NonNull;
5
+import android.support.annotation.RestrictTo;
5
 import android.view.View;
6
 import android.view.View;
6
-import android.view.ViewGroup;
7
-import android.widget.FrameLayout;
8
 
7
 
9
 import com.facebook.react.bridge.Promise;
8
 import com.facebook.react.bridge.Promise;
10
 import com.reactnativenavigation.anim.NavigationAnimator;
9
 import com.reactnativenavigation.anim.NavigationAnimator;
10
+import com.reactnativenavigation.parse.Options;
11
+import com.reactnativenavigation.utils.NoOpPromise;
12
+import com.reactnativenavigation.views.ReactComponent;
13
+import com.reactnativenavigation.views.StackLayout;
14
+import com.reactnativenavigation.views.TopBar;
11
 
15
 
12
 import java.util.Collection;
16
 import java.util.Collection;
13
 import java.util.Iterator;
17
 import java.util.Iterator;
14
 
18
 
15
-public class StackController extends ParentController {
19
+public class StackController extends ParentController <StackLayout> {
16
 
20
 
17
-	private final IdStack<ViewController> stack = new IdStack<>();
18
-	private final NavigationAnimator animator;
21
+    private static final NoOpPromise NO_OP = new NoOpPromise();
22
+    private final IdStack<ViewController> stack = new IdStack<>();
23
+    private final NavigationAnimator animator;
24
+    private StackLayout stackLayout;
19
 
25
 
20
-	public StackController(final Activity activity, String id) {
21
-		this(activity, id, new NavigationAnimator(activity));
22
-	}
23
-
24
-	public StackController(final Activity activity, String id, NavigationAnimator animator) {
26
+    public StackController(final Activity activity, String id) {
25
 		super(activity, id);
27
 		super(activity, id);
26
-		this.animator = animator;
27
-	}
28
+        animator = new NavigationAnimator(activity);
29
+    }
28
 
30
 
29
-	public void push(final ViewController child) {
30
-		push(child, null);
31
-	}
31
+    @RestrictTo(RestrictTo.Scope.TESTS)
32
+    TopBar getTopBar() {
33
+        return stackLayout.getTopBar();
34
+    }
32
 
35
 
33
-	public void push(final ViewController child, final Promise promise) {
34
-		final ViewController previousTop = peek();
36
+    @Override
37
+    public void applyOptions(Options options, ReactComponent component) {
38
+        stackLayout.applyOptions(options, component);
39
+    }
40
+
41
+    @Override
42
+    void clearOptions() {
43
+        stackLayout.clearOptions();
44
+    }
45
+
46
+    public void animatePush(final ViewController child, final Promise promise) {
47
+		final ViewController toRemove = stack.peek();
35
 
48
 
36
 		child.setParentController(this);
49
 		child.setParentController(this);
37
 		stack.push(child.getId(), child);
50
 		stack.push(child.getId(), child);
38
 		View enteringView = child.getView();
51
 		View enteringView = child.getView();
39
 		getView().addView(enteringView);
52
 		getView().addView(enteringView);
40
 
53
 
41
-		//TODO animatePush only when needed
42
-		if (previousTop != null) {
43
-			animator.animatePush(enteringView, new NavigationAnimator.NavigationAnimationListener() {
44
-				@Override
45
-				public void onAnimationEnd() {
46
-					getView().removeView(previousTop.getView());
47
-					if (promise != null) {
48
-						promise.resolve(child.getId());
49
-					}
50
-				}
51
-			});
52
-		} else if (promise != null) {
54
+		if (toRemove != null) {
55
+            animator.animatePush(enteringView, () -> {
56
+                getView().removeView(toRemove.getView());
57
+                promise.resolve(child.getId());
58
+            });
59
+		} else {
53
 			promise.resolve(child.getId());
60
 			promise.resolve(child.getId());
54
 		}
61
 		}
55
 	}
62
 	}
56
 
63
 
57
-	boolean canPop() {
58
-		return stack.size() > 1;
59
-	}
64
+    public void pop(final Promise promise) {
65
+        if (!canPop()) {
66
+            Navigator.rejectPromise(promise);
67
+            return;
68
+        }
60
 
69
 
61
-	void pop(Promise promise) {
62
-		pop(true, promise);
63
-	}
70
+        final ViewController poppedTop = stack.pop();
71
+        ViewController newTop = stack.peek();
64
 
72
 
65
-	void pop() {
66
-		pop(true, null);
67
-	}
73
+        View enteringView = newTop.getView();
74
+        final View exitingView = poppedTop.getView();
75
+        getView().addView(enteringView, getView().getChildCount() - 1);
68
 
76
 
69
-	private void pop(boolean animate, final Promise promise) {
77
+        finishPopping(exitingView, poppedTop, promise);
78
+    }
79
+
80
+	public void animatePop(final Promise promise) {
70
 		if (!canPop()) {
81
 		if (!canPop()) {
71
 			Navigator.rejectPromise(promise);
82
 			Navigator.rejectPromise(promise);
72
 			return;
83
 			return;
73
 		}
84
 		}
74
 
85
 
75
 		final ViewController poppedTop = stack.pop();
86
 		final ViewController poppedTop = stack.pop();
76
-		ViewController newTop = peek();
87
+		ViewController newTop = stack.peek();
77
 
88
 
78
 		View enteringView = newTop.getView();
89
 		View enteringView = newTop.getView();
79
 		final View exitingView = poppedTop.getView();
90
 		final View exitingView = poppedTop.getView();
80
 		getView().addView(enteringView, getView().getChildCount() - 1);
91
 		getView().addView(enteringView, getView().getChildCount() - 1);
81
 
92
 
82
-		if (animate) {
83
-			animator.animatePop(exitingView, new NavigationAnimator.NavigationAnimationListener() {
84
-				@Override
85
-				public void onAnimationEnd() {
86
-					finishPopping(exitingView, poppedTop, promise);
87
-				}
88
-			});
89
-		} else {
90
-			finishPopping(exitingView, poppedTop, promise);
91
-		}
93
+        animator.animatePop(exitingView, () -> finishPopping(exitingView, poppedTop, promise));
92
 	}
94
 	}
93
 
95
 
96
+    boolean canPop() {
97
+        return stack.size() > 1;
98
+    }
99
+
94
 	private void finishPopping(View exitingView, ViewController poppedTop, Promise promise) {
100
 	private void finishPopping(View exitingView, ViewController poppedTop, Promise promise) {
95
 		getView().removeView(exitingView);
101
 		getView().removeView(exitingView);
96
 		poppedTop.destroy();
102
 		poppedTop.destroy();
97
-		if (promise != null) {
98
-			promise.resolve(poppedTop.getId());
99
-		}
100
-	}
101
-
102
-	void popSpecific(final ViewController childController) {
103
-		popSpecific(childController, null);
103
+        promise.resolve(poppedTop.getId());
104
 	}
104
 	}
105
 
105
 
106
 	void popSpecific(final ViewController childController, Promise promise) {
106
 	void popSpecific(final ViewController childController, Promise promise) {
107
 		if (stack.isTop(childController.getId())) {
107
 		if (stack.isTop(childController.getId())) {
108
-			pop(promise);
108
+			animatePop(promise);
109
 		} else {
109
 		} else {
110
 			stack.remove(childController.getId());
110
 			stack.remove(childController.getId());
111
 			childController.destroy();
111
 			childController.destroy();
112
-			if (promise != null) {
113
-				promise.resolve(childController.getId());
114
-			}
112
+            promise.resolve(childController.getId());
115
 		}
113
 		}
116
 	}
114
 	}
117
 
115
 
118
-	void popTo(ViewController viewController) {
119
-		popTo(viewController, null);
120
-	}
121
-
122
 	void popTo(final ViewController viewController, Promise promise) {
116
 	void popTo(final ViewController viewController, Promise promise) {
123
 		if (!stack.containsId(viewController.getId())) {
117
 		if (!stack.containsId(viewController.getId())) {
124
 			Navigator.rejectPromise(promise);
118
 			Navigator.rejectPromise(promise);
130
 		while (!viewController.getId().equals(currentControlId)) {
124
 		while (!viewController.getId().equals(currentControlId)) {
131
 			String nextControlId = iterator.next();
125
 			String nextControlId = iterator.next();
132
 			boolean animate = nextControlId.equals(viewController.getId());
126
 			boolean animate = nextControlId.equals(viewController.getId());
133
-			pop(animate, animate ? promise : null);
127
+			if (animate) {
128
+			    animatePop(promise);
129
+            } else {
130
+			    pop(NO_OP);
131
+            }
134
 			currentControlId = nextControlId;
132
 			currentControlId = nextControlId;
135
 		}
133
 		}
136
 	}
134
 	}
137
 
135
 
138
-	void popToRoot() {
139
-		popToRoot(null);
140
-	}
141
-
142
 	void popToRoot(Promise promise) {
136
 	void popToRoot(Promise promise) {
143
 		while (canPop()) {
137
 		while (canPop()) {
144
-			boolean animate = stack.size() == 2; //first element is root
145
-			pop(animate, animate ? promise : null);
138
+			boolean animate = stack.size() == 2; // First element is root
139
+            if (animate) {
140
+                animatePop(promise);
141
+            } else {
142
+                pop(NO_OP);
143
+            }
146
 		}
144
 		}
147
 	}
145
 	}
148
 
146
 
161
 	@Override
159
 	@Override
162
 	public boolean handleBack() {
160
 	public boolean handleBack() {
163
 		if (canPop()) {
161
 		if (canPop()) {
164
-			pop(null);
162
+			animatePop(NO_OP);
165
 			return true;
163
 			return true;
166
-		} else {
167
-			return false;
168
 		}
164
 		}
165
+        return false;
169
 	}
166
 	}
170
 
167
 
171
-	@NonNull
172
-	@Override
173
-	protected ViewGroup createView() {
174
-		return new FrameLayout(getActivity());
175
-	}
168
+    @NonNull
169
+    @Override
170
+    protected StackLayout createView() {
171
+        stackLayout = new StackLayout(getActivity());
172
+        return stackLayout;
173
+    }
176
 
174
 
177
 	@NonNull
175
 	@NonNull
178
 	@Override
176
 	@Override

+ 12
- 9
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java 查看文件

16
 
16
 
17
 public abstract class ViewController implements ViewTreeObserver.OnGlobalLayoutListener {
17
 public abstract class ViewController implements ViewTreeObserver.OnGlobalLayoutListener {
18
 
18
 
19
+    public Options options;
20
+
19
 	private final Activity activity;
21
 	private final Activity activity;
20
 	private final String id;
22
 	private final String id;
21
-
22
 	private View view;
23
 	private View view;
23
 	private ParentController parentController;
24
 	private ParentController parentController;
24
 	private boolean isShown = false;
25
 	private boolean isShown = false;
25
-
26
     private boolean isDestroyed;
26
     private boolean isDestroyed;
27
 
27
 
28
 	public ViewController(Activity activity, String id) {
28
 	public ViewController(Activity activity, String id) {
32
 
32
 
33
 	protected abstract View createView();
33
 	protected abstract View createView();
34
 
34
 
35
-	@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
35
+	@SuppressWarnings("WeakerAccess")
36
+    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
36
 	public void ensureViewIsCreated() {
37
 	public void ensureViewIsCreated() {
37
 		getView();
38
 		getView();
38
 	}
39
 	}
41
 		return false;
42
 		return false;
42
 	}
43
 	}
43
 
44
 
45
+    public void applyOptions(Options options) {
46
+
47
+    }
48
+
44
 	public Activity getActivity() {
49
 	public Activity getActivity() {
45
 		return activity;
50
 		return activity;
46
 	}
51
 	}
47
 
52
 
48
-    protected ViewController getParentController() {
49
-	    return parentController;
53
+	protected void applyOnParentStack(Task<ParentController> task) {
54
+        if (parentController != null) {
55
+            task.run(parentController);
56
+        }
50
     }
57
     }
51
 
58
 
52
 	@Nullable
59
 	@Nullable
106
 
113
 
107
 	public void onViewDisappear() {
114
 	public void onViewDisappear() {
108
         isShown = false;
115
         isShown = false;
109
-    }
110
-
111
-    public void applyOptions(Options options) {
112
-
113
     }
116
     }
114
 
117
 
115
 	public void destroy() {
118
 	public void destroy() {

+ 0
- 36
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/CustomOverlay.java 查看文件

1
-package com.reactnativenavigation.viewcontrollers.overlay;
2
-
3
-
4
-import android.content.Context;
5
-
6
-import com.reactnativenavigation.parse.OverlayOptions;
7
-import com.reactnativenavigation.viewcontrollers.ComponentViewController;
8
-import com.reactnativenavigation.viewcontrollers.ViewController;
9
-import com.reactnativenavigation.views.CustomDialog;
10
-
11
-public class CustomOverlay implements OverlayInterface {
12
-
13
-	private CustomDialog dialog;
14
-
15
-	@Override
16
-	public CustomOverlay create(ViewController root, OverlayOptions options) {
17
-		//TODO; implement
18
-
19
-		ViewController viewController = options.getCustomView();
20
-		dialog = new CustomDialog(root.getActivity(), viewController.getView());
21
-
22
-		return this;
23
-	}
24
-
25
-	@Override
26
-	public void show() {
27
-		dialog.show();
28
-	}
29
-
30
-	@Override
31
-	public void dismiss() {
32
-		if (dialog != null) {
33
-			dialog.dismiss();
34
-		}
35
-	}
36
-}

+ 1
- 4
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/OverlayFactory.java 查看文件

1
 package com.reactnativenavigation.viewcontrollers.overlay;
1
 package com.reactnativenavigation.viewcontrollers.overlay;
2
 
2
 
3
 
3
 
4
-import android.content.Context;
5
-
6
 import com.reactnativenavigation.parse.OverlayOptions;
4
 import com.reactnativenavigation.parse.OverlayOptions;
7
 import com.reactnativenavigation.viewcontrollers.ViewController;
5
 import com.reactnativenavigation.viewcontrollers.ViewController;
8
 
6
 
10
 
8
 
11
 	public enum Overlay {
9
 	public enum Overlay {
12
 		AlertDialog("alert", new AlertOverlay()),
10
 		AlertDialog("alert", new AlertOverlay()),
13
-		Snackbar("snackbar", new SnackbarOverlay()),
14
-		CustomDialog("custom", new CustomOverlay());
11
+		Snackbar("snackbar", new SnackbarOverlay());
15
 
12
 
16
 		private String name;
13
 		private String name;
17
 		private OverlayInterface overlayInstance;
14
 		private OverlayInterface overlayInstance;

+ 2
- 3
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabController.java 查看文件

13
 
13
 
14
     private final String componentName;
14
     private final String componentName;
15
     private ComponentViewController.ReactViewCreator viewCreator;
15
     private ComponentViewController.ReactViewCreator viewCreator;
16
-    private final Options options;
17
     private TopTab topTab;
16
     private TopTab topTab;
18
     private boolean isSelectedTab;
17
     private boolean isSelectedTab;
19
 
18
 
34
 
33
 
35
     @Override
34
     @Override
36
     public void applyOptions(Options options) {
35
     public void applyOptions(Options options) {
37
-        getParentController().applyOptions(options);
36
+        applyOnParentStack(parentController -> parentController.applyOptions(options));
38
     }
37
     }
39
 
38
 
40
     @Override
39
     @Override
72
     }
71
     }
73
 
72
 
74
     String getTabTitle() {
73
     String getTabTitle() {
75
-        return options.topTabOptions.title;
74
+        return options.topTabOptions.title.get("");
76
     }
75
     }
77
 
76
 
78
     public void setTabIndex(int i) {
77
     public void setTabIndex(int i) {

+ 8
- 5
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsAdapter.java 查看文件

5
 import android.view.View;
5
 import android.view.View;
6
 import android.view.ViewGroup;
6
 import android.view.ViewGroup;
7
 
7
 
8
+import com.reactnativenavigation.parse.Options;
9
+import com.reactnativenavigation.viewcontrollers.ViewController;
10
+
8
 import java.util.List;
11
 import java.util.List;
9
 
12
 
10
 public class TopTabsAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener {
13
 public class TopTabsAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener {
11
-    private List<TopTabController> tabs;
14
+    private List<ViewController> tabs;
12
     private int currentPage = 0;
15
     private int currentPage = 0;
13
 
16
 
14
-    public TopTabsAdapter(List<TopTabController> tabs) {
17
+    public TopTabsAdapter(List<ViewController> tabs) {
15
         this.tabs = tabs;
18
         this.tabs = tabs;
16
     }
19
     }
17
 
20
 
18
     @Override
21
     @Override
19
     public CharSequence getPageTitle(int position) {
22
     public CharSequence getPageTitle(int position) {
20
-        return tabs.get(position).getTabTitle();
23
+        return getTabOptions(position).topTabOptions.title.get("");
21
     }
24
     }
22
 
25
 
23
     @Override
26
     @Override
52
 
55
 
53
     }
56
     }
54
 
57
 
55
-    int getCurrentItem() {
56
-        return currentPage;
58
+    private Options getTabOptions(int position) {
59
+        return tabs.get(position).options;
57
     }
60
     }
58
 }
61
 }

+ 5
- 5
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java 查看文件

17
 
17
 
18
 public class TopTabsController extends ParentController implements NavigationOptionsListener {
18
 public class TopTabsController extends ParentController implements NavigationOptionsListener {
19
 
19
 
20
-    private List<TopTabController> tabs;
20
+    private List<ViewController> tabs;
21
     private TopTabsLayout topTabsLayout;
21
     private TopTabsLayout topTabsLayout;
22
     private TopTabsLayoutCreator viewCreator;
22
     private TopTabsLayoutCreator viewCreator;
23
     private Options options;
23
     private Options options;
24
 
24
 
25
-    public TopTabsController(Activity activity, String id, List<TopTabController> tabs, TopTabsLayoutCreator viewCreator, Options options) {
25
+    public TopTabsController(Activity activity, String id, List<ViewController> tabs, TopTabsLayoutCreator viewCreator, Options options) {
26
         super(activity, id);
26
         super(activity, id);
27
         this.viewCreator = viewCreator;
27
         this.viewCreator = viewCreator;
28
         this.options = options;
28
         this.options = options;
48
     @Override
48
     @Override
49
     public void onViewAppeared() {
49
     public void onViewAppeared() {
50
         applyOptions(options);
50
         applyOptions(options);
51
-        performOnCurrentTab(TopTabController::onViewAppeared);
51
+        performOnCurrentTab(ViewController::onViewAppeared);
52
     }
52
     }
53
 
53
 
54
     @Override
54
     @Override
55
     public void onViewDisappear() {
55
     public void onViewDisappear() {
56
-        performOnCurrentTab(TopTabController::onViewDisappear);
56
+        performOnCurrentTab(ViewController::onViewDisappear);
57
     }
57
     }
58
 
58
 
59
     @Override
59
     @Override
70
         topTabsLayout.switchToTab(index);
70
         topTabsLayout.switchToTab(index);
71
     }
71
     }
72
 
72
 
73
-    private void performOnCurrentTab(Task<TopTabController> task) {
73
+    private void performOnCurrentTab(Task<ViewController> task) {
74
         task.run(tabs.get(topTabsLayout.getCurrentItem()));
74
         task.run(tabs.get(topTabsLayout.getCurrentItem()));
75
     }
75
     }
76
 }
76
 }

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsViewPager.java 查看文件

15
 @SuppressLint("ViewConstructor")
15
 @SuppressLint("ViewConstructor")
16
 public class TopTabsViewPager extends ViewPager {
16
 public class TopTabsViewPager extends ViewPager {
17
     private static final int OFFSCREEN_PAGE_LIMIT = 99;
17
     private static final int OFFSCREEN_PAGE_LIMIT = 99;
18
-    private List<TopTabController> tabs;
18
+    private List<ViewController> tabs;
19
 
19
 
20
-    public TopTabsViewPager(Context context, List<TopTabController> tabs, TopTabsAdapter adapter) {
20
+    public TopTabsViewPager(Context context, List<ViewController> tabs, TopTabsAdapter adapter) {
21
         super(context);
21
         super(context);
22
         this.tabs = tabs;
22
         this.tabs = tabs;
23
         init(adapter);
23
         init(adapter);

+ 1
- 9
lib/android/app/src/main/java/com/reactnativenavigation/views/Component.java 查看文件

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
-import android.view.View;
4
-
5
 import com.reactnativenavigation.parse.Options;
3
 import com.reactnativenavigation.parse.Options;
6
 
4
 
7
 public interface Component {
5
 public interface Component {
8
     void applyOptions(Options options);
6
     void applyOptions(Options options);
9
 
7
 
10
-    void sendOnNavigationButtonPressed(String id);
11
-
12
-    TopBar getTopBar();
13
-
14
-    View getContentView();
15
-
16
     void drawBehindTopBar();
8
     void drawBehindTopBar();
17
 
9
 
18
-    void drawBelowTopBar();
10
+    void drawBelowTopBar(TopBar topBar);
19
 }
11
 }

+ 22
- 32
lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentLayout.java 查看文件

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
-import android.annotation.*;
4
-import android.content.*;
5
-import android.view.*;
6
-import android.widget.*;
3
+import android.annotation.SuppressLint;
4
+import android.content.Context;
5
+import android.view.View;
6
+import android.widget.FrameLayout;
7
+import android.widget.RelativeLayout;
7
 
8
 
8
-import com.facebook.react.uimanager.events.*;
9
-import com.reactnativenavigation.parse.*;
10
-import com.reactnativenavigation.presentation.*;
11
-import com.reactnativenavigation.viewcontrollers.ComponentViewController.*;
9
+import com.reactnativenavigation.interfaces.ScrollEventListener;
10
+import com.reactnativenavigation.parse.Options;
11
+import com.reactnativenavigation.viewcontrollers.ComponentViewController.IReactView;
12
 
12
 
13
-import static android.view.ViewGroup.LayoutParams.*;
13
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
14
+import static android.widget.RelativeLayout.BELOW;
14
 
15
 
15
 @SuppressLint("ViewConstructor")
16
 @SuppressLint("ViewConstructor")
16
-public class ComponentLayout extends RelativeLayout implements ReactComponent {
17
+public class ComponentLayout extends FrameLayout implements ReactComponent, TitleBarButton.OnClickListener {
17
 
18
 
18
-    private TopBar topBar;
19
     private IReactView reactView;
19
     private IReactView reactView;
20
-    private final OptionsPresenter optionsPresenter;
21
 
20
 
22
-	public ComponentLayout(Context context, IReactView reactView, EventDispatcher eventDispatcher) {
21
+	public ComponentLayout(Context context, IReactView reactView) {
23
 		super(context);
22
 		super(context);
24
 		this.reactView = reactView;
23
 		this.reactView = reactView;
25
-		this.topBar = new TopBar(context, this, eventDispatcher);
26
-        optionsPresenter = new OptionsPresenter(this);
27
-        initViews();
28
-    }
29
-
30
-    private void initViews() {
31
-        LayoutParams layoutParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
32
-        layoutParams.addRule(BELOW, topBar.getId());
33
-        addView(reactView.asView(), layoutParams);
34
-        addView(topBar, new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
24
+        addView(reactView.asView(), MATCH_PARENT, MATCH_PARENT);
35
     }
25
     }
36
 
26
 
37
     @Override
27
     @Override
61
 
51
 
62
     @Override
52
     @Override
63
     public void applyOptions(Options options) {
53
     public void applyOptions(Options options) {
64
-        optionsPresenter.applyOptions(options);
54
+
65
     }
55
     }
66
 
56
 
67
     @Override
57
     @Override
70
     }
60
     }
71
 
61
 
72
     @Override
62
     @Override
73
-    public TopBar getTopBar() {
74
-        return topBar;
75
-    }
76
-
77
-    @Override
78
-    public View getContentView() {
79
-        return reactView.asView();
63
+    public ScrollEventListener getScrollEventListener() {
64
+        return reactView.getScrollEventListener();
80
     }
65
     }
81
 
66
 
82
     @Override
67
     @Override
87
     }
72
     }
88
 
73
 
89
     @Override
74
     @Override
90
-    public void drawBelowTopBar() {
75
+    public void drawBelowTopBar(TopBar topBar) {
91
         RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) reactView.asView().getLayoutParams();
76
         RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) reactView.asView().getLayoutParams();
92
         layoutParams.addRule(BELOW, topBar.getId());
77
         layoutParams.addRule(BELOW, topBar.getId());
93
         reactView.asView().setLayoutParams(layoutParams);
78
         reactView.asView().setLayoutParams(layoutParams);
94
     }
79
     }
80
+
81
+    @Override
82
+    public void onPress(String buttonId) {
83
+        reactView.sendOnNavigationButtonPressed(buttonId);
84
+    }
95
 }
85
 }

+ 5
- 6
lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentViewCreator.java 查看文件

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
-import android.app.*;
3
+import android.app.Activity;
4
 
4
 
5
-import com.facebook.react.*;
6
-import com.facebook.react.uimanager.*;
7
-import com.reactnativenavigation.react.*;
8
-import com.reactnativenavigation.viewcontrollers.*;
5
+import com.facebook.react.ReactInstanceManager;
6
+import com.reactnativenavigation.react.ReactComponentViewCreator;
7
+import com.reactnativenavigation.viewcontrollers.ComponentViewController;
9
 
8
 
10
 public class ComponentViewCreator implements ComponentViewController.ReactViewCreator {
9
 public class ComponentViewCreator implements ComponentViewController.ReactViewCreator {
11
 
10
 
18
 	@Override
17
 	@Override
19
 	public ComponentViewController.IReactView create(Activity activity, String componentId, String componentName) {
18
 	public ComponentViewController.IReactView create(Activity activity, String componentId, String componentName) {
20
         ComponentViewController.IReactView reactView = new ReactComponentViewCreator(instanceManager).create(activity, componentId, componentName);
19
         ComponentViewController.IReactView reactView = new ReactComponentViewCreator(instanceManager).create(activity, componentId, componentName);
21
-        return new ComponentLayout(activity, reactView, instanceManager.getCurrentReactContext().getNativeModule(UIManagerModule.class).getEventDispatcher());
20
+        return new ComponentLayout(activity, reactView);
22
 	}
21
 	}
23
 }
22
 }

+ 0
- 29
lib/android/app/src/main/java/com/reactnativenavigation/views/CustomDialog.java 查看文件

1
-package com.reactnativenavigation.views;
2
-
3
-import android.app.Dialog;
4
-import android.content.Context;
5
-import android.support.annotation.NonNull;
6
-import android.util.Log;
7
-import android.view.View;
8
-import android.view.ViewGroup;
9
-import android.view.ViewTreeObserver;
10
-import android.view.WindowManager;
11
-
12
-import com.facebook.react.ReactRootView;
13
-
14
-
15
-public class CustomDialog extends Dialog {
16
-
17
-	private View component;
18
-
19
-	public CustomDialog(@NonNull Context context, @NonNull View component) {
20
-		super(context);
21
-
22
-		this.component = component;
23
-		init();
24
-	}
25
-
26
-	private void init() {
27
-		addContentView(component, new WindowManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
28
-	}
29
-}

+ 46
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/StackLayout.java 查看文件

1
+package com.reactnativenavigation.views;
2
+
3
+import android.content.Context;
4
+import android.support.annotation.RestrictTo;
5
+import android.widget.RelativeLayout;
6
+
7
+import com.reactnativenavigation.parse.Options;
8
+import com.reactnativenavigation.presentation.OptionsPresenter;
9
+import com.reactnativenavigation.utils.CompatUtils;
10
+
11
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
12
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
13
+
14
+public class StackLayout extends RelativeLayout implements TitleBarButton.OnClickListener {
15
+
16
+    private final TopBar topBar;
17
+
18
+    public StackLayout(Context context) {
19
+        super(context);
20
+        topBar = new TopBar(context, this);
21
+        topBar.setId(CompatUtils.generateViewId());
22
+        createLayout();
23
+    }
24
+
25
+    void createLayout() {
26
+        addView(topBar, MATCH_PARENT, WRAP_CONTENT);
27
+    }
28
+
29
+    @Override
30
+    public void onPress(String buttonId) {
31
+
32
+    }
33
+
34
+    public void applyOptions(Options options, ReactComponent component) {
35
+        new OptionsPresenter(topBar, component).applyOptions(options);
36
+    }
37
+
38
+    @RestrictTo(RestrictTo.Scope.TESTS)
39
+    public TopBar getTopBar() {
40
+        return topBar;
41
+    }
42
+
43
+    public void clearOptions() {
44
+        topBar.clear();
45
+    }
46
+}

+ 20
- 22
lib/android/app/src/main/java/com/reactnativenavigation/views/TitleBarButton.java 查看文件

22
 import java.util.ArrayList;
22
 import java.util.ArrayList;
23
 
23
 
24
 public class TitleBarButton implements MenuItem.OnMenuItemClickListener {
24
 public class TitleBarButton implements MenuItem.OnMenuItemClickListener {
25
+    public interface OnClickListener {
26
+        void onPress(String buttonId);
27
+    }
28
+
25
 	private Toolbar toolbar;
29
 	private Toolbar toolbar;
26
 	private final Button button;
30
 	private final Button button;
27
-	private Component component;
28
 	private Drawable icon;
31
 	private Drawable icon;
32
+    private OnClickListener onPressListener;
29
 
33
 
30
-	TitleBarButton(Component component, Toolbar toolbar, Button button) {
31
-		this.component = component;
34
+    TitleBarButton(Toolbar toolbar, Button button, OnClickListener onPressListener) {
35
+        this.onPressListener = onPressListener;
32
 		this.toolbar = toolbar;
36
 		this.toolbar = toolbar;
33
 		this.button = button;
37
 		this.button = button;
34
 	}
38
 	}
35
 
39
 
36
 	void addToMenu(Context context, final Menu menu) {
40
 	void addToMenu(Context context, final Menu menu) {
37
-		MenuItem menuItem = menu.add(button.title);
41
+		MenuItem menuItem = menu.add(button.title.get(""));
38
 		menuItem.setShowAsAction(button.showAsAction);
42
 		menuItem.setShowAsAction(button.showAsAction);
39
 		menuItem.setEnabled(button.disabled != Options.BooleanOptions.True);
43
 		menuItem.setEnabled(button.disabled != Options.BooleanOptions.True);
40
 		menuItem.setOnMenuItemClickListener(this);
44
 		menuItem.setOnMenuItemClickListener(this);
53
 			return;
57
 			return;
54
 		}
58
 		}
55
 
59
 
56
-		ImageUtils.tryLoadIcon(context, button.icon, new ImageUtils.ImageLoadingListener() {
60
+		ImageUtils.loadIcon(context, button.icon.get(), new ImageUtils.ImageLoadingListener() {
57
 			@Override
61
 			@Override
58
 			public void onComplete(@NonNull Drawable drawable) {
62
 			public void onComplete(@NonNull Drawable drawable) {
59
 				icon = drawable;
63
 				icon = drawable;
60
-				UiUtils.runOnMainThread(() -> {
61
-                    setIconColor();
62
-                    setNavigationClickListener();
63
-                    toolbar.setNavigationIcon(icon);
64
-                });
64
+                setIconColor();
65
+                setNavigationClickListener();
66
+                toolbar.setNavigationIcon(icon);
65
 			}
67
 			}
66
 
68
 
67
 			@Override
69
 			@Override
68
 			public void onError(Throwable error) {
70
 			public void onError(Throwable error) {
69
-				//TODO: handle
70
 				error.printStackTrace();
71
 				error.printStackTrace();
71
 			}
72
 			}
72
 		});
73
 		});
73
 	}
74
 	}
74
 
75
 
75
 	private void applyIcon(Context context, final MenuItem menuItem) {
76
 	private void applyIcon(Context context, final MenuItem menuItem) {
76
-		ImageUtils.tryLoadIcon(context, button.icon, new ImageUtils.ImageLoadingListener() {
77
+		ImageUtils.loadIcon(context, button.icon.get(), new ImageUtils.ImageLoadingListener() {
77
 			@Override
78
 			@Override
78
 			public void onComplete(@NonNull Drawable drawable) {
79
 			public void onComplete(@NonNull Drawable drawable) {
79
 				icon = drawable;
80
 				icon = drawable;
80
-				UiUtils.runOnMainThread(() -> {
81
-                    menuItem.setIcon(icon);
82
-                    setIconColor();
83
-                });
81
+                menuItem.setIcon(icon);
82
+                setIconColor();
84
 			}
83
 			}
85
 
84
 
86
 			@Override
85
 			@Override
87
 			public void onError(Throwable error) {
86
 			public void onError(Throwable error) {
88
-				//TODO: handle
89
 				error.printStackTrace();
87
 				error.printStackTrace();
90
 			}
88
 			}
91
 		});
89
 		});
112
 	}
110
 	}
113
 
111
 
114
 	private void setFontSize(MenuItem menuItem) {
112
 	private void setFontSize(MenuItem menuItem) {
115
-		SpannableString spanString = new SpannableString(button.title);
116
-		spanString.setSpan(new AbsoluteSizeSpan(button.buttonFontSize, true), 0, button.title.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
113
+		SpannableString spanString = new SpannableString(button.title.get());
114
+		spanString.setSpan(new AbsoluteSizeSpan(button.buttonFontSize, true), 0, button.title.get().length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
117
 		menuItem.setTitleCondensed(spanString);
115
 		menuItem.setTitleCondensed(spanString);
118
 	}
116
 	}
119
 
117
 
120
 	private void setNavigationClickListener() {
118
 	private void setNavigationClickListener() {
121
-		toolbar.setNavigationOnClickListener(view -> component.sendOnNavigationButtonPressed(button.id));
119
+		toolbar.setNavigationOnClickListener(view -> onPressListener.onPress(button.id));
122
 	}
120
 	}
123
 
121
 
124
 	@Override
122
 	@Override
125
 	public boolean onMenuItemClick(MenuItem menuItem) {
123
 	public boolean onMenuItemClick(MenuItem menuItem) {
126
-		this.component.sendOnNavigationButtonPressed(button.id);
124
+		onPressListener.onPress(button.id);
127
 		return true;
125
 		return true;
128
 	}
126
 	}
129
 
127
 
130
 	@NonNull
128
 	@NonNull
131
 	private ArrayList<View> findActualTextViewInMenuByLabel() {
129
 	private ArrayList<View> findActualTextViewInMenuByLabel() {
132
 		ArrayList<View> outViews = new ArrayList<>();
130
 		ArrayList<View> outViews = new ArrayList<>();
133
-		this.toolbar.findViewsWithText(outViews, button.title, View.FIND_VIEWS_WITH_TEXT);
131
+		this.toolbar.findViewsWithText(outViews, button.title.get(), View.FIND_VIEWS_WITH_TEXT);
134
 		return outViews;
132
 		return outViews;
135
 	}
133
 	}
136
 
134
 

+ 44
- 34
lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java 查看文件

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
-import android.annotation.*;
4
-import android.content.*;
5
-import android.graphics.*;
6
-import android.support.annotation.*;
7
-import android.support.design.widget.*;
3
+import android.annotation.SuppressLint;
4
+import android.content.Context;
5
+import android.graphics.Typeface;
6
+import android.support.annotation.Nullable;
7
+import android.support.design.widget.AppBarLayout;
8
 import android.support.v7.widget.Toolbar;
8
 import android.support.v7.widget.Toolbar;
9
-import android.util.*;
10
-import android.view.*;
11
-import android.widget.*;
12
-
13
-import com.facebook.react.uimanager.events.*;
14
-import com.reactnativenavigation.anim.*;
9
+import android.util.Log;
10
+import android.view.Menu;
11
+import android.view.View;
12
+import android.view.ViewGroup;
13
+import android.widget.TextView;
14
+
15
+import com.reactnativenavigation.anim.TopBarAnimator;
16
+import com.reactnativenavigation.anim.TopBarCollapseBehavior;
17
+import com.reactnativenavigation.interfaces.ScrollEventListener;
15
 import com.reactnativenavigation.parse.Button;
18
 import com.reactnativenavigation.parse.Button;
16
 import com.reactnativenavigation.parse.Color;
19
 import com.reactnativenavigation.parse.Color;
17
-import com.reactnativenavigation.parse.*;
20
+import com.reactnativenavigation.parse.Fraction;
18
 import com.reactnativenavigation.parse.Number;
21
 import com.reactnativenavigation.parse.Number;
19
-import com.reactnativenavigation.viewcontrollers.toptabs.*;
22
+import com.reactnativenavigation.parse.Options;
23
+import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsViewPager;
20
 
24
 
21
-import java.util.*;
25
+import java.util.ArrayList;
22
 
26
 
23
 @SuppressLint("ViewConstructor")
27
 @SuppressLint("ViewConstructor")
24
-public class TopBar extends AppBarLayout {
28
+public class TopBar extends AppBarLayout implements ScrollEventListener.ScrollAwareView {
25
     private final Toolbar titleBar;
29
     private final Toolbar titleBar;
30
+    private TitleBarButton.OnClickListener onClickListener;
26
     private final TopBarCollapseBehavior collapsingBehavior;
31
     private final TopBarCollapseBehavior collapsingBehavior;
27
     private final TopBarAnimator animator;
32
     private final TopBarAnimator animator;
28
-    private Component component;
29
     private TopTabs topTabs;
33
     private TopTabs topTabs;
30
 
34
 
31
-    public TopBar(final Context context, Component component, EventDispatcher eventDispatcher) {
35
+    public TopBar(final Context context, TitleBarButton.OnClickListener onClickListener) {
32
         super(context);
36
         super(context);
33
-        collapsingBehavior = new TopBarCollapseBehavior(eventDispatcher, this);
34
-        this.component = component;
37
+        this.onClickListener = onClickListener;
38
+        collapsingBehavior = new TopBarCollapseBehavior(this);
35
         titleBar = new Toolbar(context);
39
         titleBar = new Toolbar(context);
36
         topTabs = new TopTabs(getContext());
40
         topTabs = new TopTabs(getContext());
37
-        this.animator = new TopBarAnimator(this, component != null ? component.getContentView() : null);
41
+        this.animator = new TopBarAnimator(this);
38
         addView(titleBar);
42
         addView(titleBar);
39
     }
43
     }
40
 
44
 
46
         return titleBar.getTitle() != null ? titleBar.getTitle().toString() : "";
50
         return titleBar.getTitle() != null ? titleBar.getTitle().toString() : "";
47
     }
51
     }
48
 
52
 
49
-    public void setTitleTextColor(@ColorInt int color) {
50
-        titleBar.setTitleTextColor(color);
53
+    public void setTitleTextColor(Color color) {
54
+        if (color.hasValue()) titleBar.setTitleTextColor(color.get());
51
     }
55
     }
52
 
56
 
53
-    public void setTitleFontSize(float size) {
57
+    public void setTitleFontSize(Fraction size) {
54
         TextView titleTextView = getTitleTextView();
58
         TextView titleTextView = getTitleTextView();
55
-        if (titleTextView != null) {
56
-            titleTextView.setTextSize(size);
59
+        if (titleTextView != null && size.hasValue()) {
60
+            titleTextView.setTextSize(size.get());
57
         }
61
         }
58
     }
62
     }
59
 
63
 
85
         return findTextView(titleBar);
89
         return findTextView(titleBar);
86
     }
90
     }
87
 
91
 
88
-    @Override
89
-    public void setBackgroundColor(@ColorInt int color) {
90
-        titleBar.setBackgroundColor(color);
92
+    public void setBackgroundColor(Color color) {
93
+        if (color.hasValue()) titleBar.setBackgroundColor(color.get());
91
     }
94
     }
92
 
95
 
93
     @Nullable
96
     @Nullable
94
     private TextView findTextView(ViewGroup root) {
97
     private TextView findTextView(ViewGroup root) {
95
         for (int i = 0; i < root.getChildCount(); i++) {
98
         for (int i = 0; i < root.getChildCount(); i++) {
96
             View view = root.getChildAt(i);
99
             View view = root.getChildAt(i);
100
+            if (view instanceof ViewGroup) {
101
+                view = findTextView((ViewGroup) view);
102
+            }
97
             if (view instanceof TextView) {
103
             if (view instanceof TextView) {
98
                 return (TextView) view;
104
                 return (TextView) view;
99
             }
105
             }
100
-            if (view instanceof ViewGroup) {
101
-                return findTextView((ViewGroup) view);
102
-            }
103
         }
106
         }
104
         return null;
107
         return null;
105
     }
108
     }
106
 
109
 
107
     private void setLeftButtons(ArrayList<Button> leftButtons) {
110
     private void setLeftButtons(ArrayList<Button> leftButtons) {
108
-        if (leftButtons == null || leftButtons.isEmpty()) {
111
+        if (leftButtons == null) return;
112
+        if (leftButtons.isEmpty()) {
109
             titleBar.setNavigationIcon(null);
113
             titleBar.setNavigationIcon(null);
110
             return;
114
             return;
111
         }
115
         }
119
     }
123
     }
120
 
124
 
121
     private void setLeftButton(final Button button) {
125
     private void setLeftButton(final Button button) {
122
-        TitleBarButton leftBarButton = new TitleBarButton(component, this.titleBar, button);
126
+        TitleBarButton leftBarButton = new TitleBarButton(this.titleBar, button, onClickListener);
123
         leftBarButton.applyNavigationIcon(getContext());
127
         leftBarButton.applyNavigationIcon(getContext());
124
     }
128
     }
125
 
129
 
133
 
137
 
134
         for (int i = 0; i < rightButtons.size(); i++) {
138
         for (int i = 0; i < rightButtons.size(); i++) {
135
             Button button = rightButtons.get(i);
139
             Button button = rightButtons.get(i);
136
-            TitleBarButton titleBarButton = new TitleBarButton(component, this.titleBar, button);
140
+            TitleBarButton titleBarButton = new TitleBarButton(this.titleBar, button, onClickListener);
137
             titleBarButton.addToMenu(getContext(), menu);
141
             titleBarButton.addToMenu(getContext(), menu);
138
         }
142
         }
139
     }
143
     }
181
             setVisibility(View.GONE);
185
             setVisibility(View.GONE);
182
         }
186
         }
183
     }
187
     }
188
+
189
+    public void clear() {
190
+        titleBar.setTitle(null);
191
+        titleBar.setNavigationIcon(null);
192
+        titleBar.getMenu().clear();
193
+    }
184
 }
194
 }

+ 6
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/TopTab.java 查看文件

5
 import android.view.View;
5
 import android.view.View;
6
 import android.widget.FrameLayout;
6
 import android.widget.FrameLayout;
7
 
7
 
8
+import com.reactnativenavigation.interfaces.ScrollEventListener;
8
 import com.reactnativenavigation.viewcontrollers.ComponentViewController.IReactView;
9
 import com.reactnativenavigation.viewcontrollers.ComponentViewController.IReactView;
9
 
10
 
10
 @SuppressLint("ViewConstructor")
11
 @SuppressLint("ViewConstructor")
47
     public void sendOnNavigationButtonPressed(String buttonId) {
48
     public void sendOnNavigationButtonPressed(String buttonId) {
48
         reactView.sendOnNavigationButtonPressed(buttonId);
49
         reactView.sendOnNavigationButtonPressed(buttonId);
49
     }
50
     }
51
+
52
+    @Override
53
+    public ScrollEventListener getScrollEventListener() {
54
+        return reactView.getScrollEventListener();
55
+    }
50
 }
56
 }

+ 23
- 40
lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsLayout.java 查看文件

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
-import android.annotation.*;
4
-import android.content.*;
5
-import android.support.annotation.*;
6
-import android.support.v4.view.*;
7
-import android.view.*;
8
-import android.widget.*;
3
+import android.annotation.SuppressLint;
4
+import android.content.Context;
5
+import android.support.annotation.RestrictTo;
6
+import android.support.v4.view.ViewPager;
7
+import android.view.View;
8
+import android.view.ViewGroup;
9
+import android.widget.RelativeLayout;
9
 
10
 
10
-import com.reactnativenavigation.parse.*;
11
-import com.reactnativenavigation.presentation.*;
12
-import com.reactnativenavigation.utils.*;
13
-import com.reactnativenavigation.viewcontrollers.toptabs.*;
11
+import com.reactnativenavigation.parse.Options;
12
+import com.reactnativenavigation.viewcontrollers.ViewController;
13
+import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsAdapter;
14
+import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsViewPager;
14
 
15
 
15
-import java.util.*;
16
+import java.util.List;
16
 
17
 
17
 @SuppressLint("ViewConstructor")
18
 @SuppressLint("ViewConstructor")
18
-public class TopTabsLayout extends RelativeLayout implements Component {
19
+public class TopTabsLayout extends RelativeLayout implements Component, TitleBarButton.OnClickListener {
19
 
20
 
20
     private TopBar topBar;
21
     private TopBar topBar;
21
-    private List<TopTabController> tabs;
22
     private TopTabsViewPager viewPager;
22
     private TopTabsViewPager viewPager;
23
-    private final OptionsPresenter optionsPresenter;
24
 
23
 
25
-    public TopTabsLayout(Context context, List<TopTabController> tabs, TopTabsAdapter adapter) {
24
+    public TopTabsLayout(Context context, List<ViewController> tabs, TopTabsAdapter adapter) {
26
         super(context);
25
         super(context);
27
-        this.tabs = tabs;
28
-        topBar = new TopBar(context, this, null);
29
-        topBar.setId(View.generateViewId());
30
         viewPager = new TopTabsViewPager(context, tabs, adapter);
26
         viewPager = new TopTabsViewPager(context, tabs, adapter);
31
-        optionsPresenter = new OptionsPresenter(this);
27
+        topBar = new TopBar(context, this);
28
+        topBar.setId(View.generateViewId());
29
+
32
         initViews();
30
         initViews();
33
     }
31
     }
34
 
32
 
42
 
40
 
43
     @Override
41
     @Override
44
     public void applyOptions(Options options) {
42
     public void applyOptions(Options options) {
45
-        optionsPresenter.applyOptions(options);
46
-    }
47
-
48
-    @Override
49
-    public void sendOnNavigationButtonPressed(String id) {
50
-        viewPager.sendOnNavigationButtonPressed(id);
51
-    }
52
-
53
-    @Override
54
-    public TopBar getTopBar() {
55
-        return topBar;
56
-    }
57
 
43
 
58
-    @Override
59
-    public View getContentView() {
60
-        return viewPager;
61
     }
44
     }
62
 
45
 
63
     @Override
46
     @Override
66
     }
49
     }
67
 
50
 
68
     @Override
51
     @Override
69
-    public void drawBelowTopBar() {
52
+    public void drawBelowTopBar(TopBar topBar) {
70
 
53
 
71
     }
54
     }
72
 
55
 
75
         return viewPager;
58
         return viewPager;
76
     }
59
     }
77
 
60
 
78
-
79
-    public void performOnCurrentTab(Task<TopTabController> task) {
80
-        task.run(tabs.get(viewPager.getCurrentItem()));
81
-    }
82
-
83
     public void switchToTab(int index) {
61
     public void switchToTab(int index) {
84
         viewPager.setCurrentItem(index);
62
         viewPager.setCurrentItem(index);
85
     }
63
     }
87
     public int getCurrentItem() {
65
     public int getCurrentItem() {
88
         return viewPager.getCurrentItem();
66
         return viewPager.getCurrentItem();
89
     }
67
     }
68
+
69
+    @Override
70
+    public void onPress(String buttonId) {
71
+        viewPager.sendOnNavigationButtonPressed(buttonId);
72
+    }
90
 }
73
 }

+ 3
- 3
lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsLayoutCreator.java 查看文件

2
 
2
 
3
 import android.content.Context;
3
 import android.content.Context;
4
 
4
 
5
-import com.reactnativenavigation.viewcontrollers.toptabs.TopTabController;
5
+import com.reactnativenavigation.viewcontrollers.ViewController;
6
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsAdapter;
6
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsAdapter;
7
 
7
 
8
 import java.util.List;
8
 import java.util.List;
9
 
9
 
10
 public class TopTabsLayoutCreator {
10
 public class TopTabsLayoutCreator {
11
     private Context context;
11
     private Context context;
12
-    private List<TopTabController> tabs;
12
+    private List<ViewController> tabs;
13
 
13
 
14
-    public TopTabsLayoutCreator(Context context, List<TopTabController> tabs) {
14
+    public TopTabsLayoutCreator(Context context, List<ViewController> tabs) {
15
         this.context = context;
15
         this.context = context;
16
         this.tabs = tabs;
16
         this.tabs = tabs;
17
     }
17
     }

+ 22
- 23
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestComponentLayout.java 查看文件

1
 package com.reactnativenavigation.mocks;
1
 package com.reactnativenavigation.mocks;
2
 
2
 
3
-import android.content.*;
4
-import android.view.*;
5
-import android.widget.*;
3
+import android.content.Context;
4
+import android.view.View;
5
+import android.view.ViewGroup;
6
+import android.widget.RelativeLayout;
6
 
7
 
7
-import com.reactnativenavigation.parse.*;
8
-import com.reactnativenavigation.presentation.*;
9
-import com.reactnativenavigation.views.*;
8
+import com.reactnativenavigation.interfaces.ScrollEventListener;
9
+import com.reactnativenavigation.parse.Options;
10
+import com.reactnativenavigation.views.ReactComponent;
11
+import com.reactnativenavigation.views.TitleBarButton;
12
+import com.reactnativenavigation.views.TopBar;
10
 
13
 
11
-public class TestComponentLayout extends RelativeLayout implements ReactComponent {
14
+public class TestComponentLayout extends RelativeLayout implements ReactComponent, TitleBarButton.OnClickListener {
12
 
15
 
13
-    private final TopBar topBar;
14
     private final View contentView;
16
     private final View contentView;
15
-    private final OptionsPresenter optionsPresenter;
16
 
17
 
17
     public TestComponentLayout(final Context context) {
18
     public TestComponentLayout(final Context context) {
18
         super(context);
19
         super(context);
19
-        topBar = new TopBar(context, this, null);
20
         contentView = new View(context);
20
         contentView = new View(context);
21
-        addView(topBar);
22
         addView(contentView);
21
         addView(contentView);
23
-        optionsPresenter = new OptionsPresenter(this);
24
-    }
25
-
26
-    public TopBar getTopBar() {
27
-        return topBar;
28
-    }
29
-
30
-    @Override
31
-    public View getContentView() {
32
-        return contentView;
33
     }
22
     }
34
 
23
 
35
     @Override
24
     @Override
40
     }
29
     }
41
 
30
 
42
     @Override
31
     @Override
43
-    public void drawBelowTopBar() {
32
+    public void drawBelowTopBar(TopBar topBar) {
44
         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
33
         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
45
         layoutParams.addRule(BELOW, topBar.getId());
34
         layoutParams.addRule(BELOW, topBar.getId());
46
         contentView.setLayoutParams(layoutParams);
35
         contentView.setLayoutParams(layoutParams);
70
 
59
 
71
     @Override
60
     @Override
72
     public void applyOptions(Options options) {
61
     public void applyOptions(Options options) {
73
-        optionsPresenter.applyOptions(options);
62
+
74
     }
63
     }
75
 
64
 
76
     @Override
65
     @Override
77
     public void sendOnNavigationButtonPressed(String id) {
66
     public void sendOnNavigationButtonPressed(String id) {
78
 
67
 
79
     }
68
     }
69
+
70
+    @Override
71
+    public ScrollEventListener getScrollEventListener() {
72
+        return null;
73
+    }
74
+
75
+    @Override
76
+    public void onPress(String buttonId) {
77
+
78
+    }
80
 }
79
 }

+ 0
- 70
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestComponentView.java 查看文件

1
-package com.reactnativenavigation.mocks;
2
-
3
-import android.content.*;
4
-import android.view.*;
5
-
6
-import com.reactnativenavigation.parse.*;
7
-import com.reactnativenavigation.views.*;
8
-
9
-public class TestComponentView extends View implements ReactComponent {
10
-
11
-    private TopBar topBar;
12
-
13
-    public TestComponentView(final Context context) {
14
-        super(context);
15
-        topBar = new TopBar(context, this, null);
16
-
17
-    }
18
-
19
-    @Override
20
-    public boolean isReady() {
21
-        return false;
22
-    }
23
-
24
-    @Override
25
-    public View asView() {
26
-        return this;
27
-    }
28
-
29
-    @Override
30
-    public void destroy() {
31
-    }
32
-
33
-    @Override
34
-    public void sendComponentStart() {
35
-    }
36
-
37
-    @Override
38
-    public void sendComponentStop() {
39
-    }
40
-
41
-    @Override
42
-    public void applyOptions(Options options) {
43
-
44
-    }
45
-
46
-    @Override
47
-    public void sendOnNavigationButtonPressed(String id) {
48
-
49
-    }
50
-
51
-    @Override
52
-    public TopBar getTopBar() {
53
-        return topBar;
54
-    }
55
-
56
-    @Override
57
-    public View getContentView() {
58
-        return null;
59
-    }
60
-
61
-    @Override
62
-    public void drawBehindTopBar() {
63
-
64
-    }
65
-
66
-    @Override
67
-    public void drawBelowTopBar() {
68
-
69
-    }
70
-}

+ 6
- 0
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TopTabLayoutMock.java 查看文件

3
 import android.content.*;
3
 import android.content.*;
4
 import android.view.*;
4
 import android.view.*;
5
 
5
 
6
+import com.reactnativenavigation.interfaces.ScrollEventListener;
6
 import com.reactnativenavigation.viewcontrollers.*;
7
 import com.reactnativenavigation.viewcontrollers.*;
7
 
8
 
8
 public class TopTabLayoutMock extends View implements ComponentViewController.IReactView {
9
 public class TopTabLayoutMock extends View implements ComponentViewController.IReactView {
40
     public void sendOnNavigationButtonPressed(String buttonId) {
41
     public void sendOnNavigationButtonPressed(String buttonId) {
41
 
42
 
42
     }
43
     }
44
+
45
+    @Override
46
+    public ScrollEventListener getScrollEventListener() {
47
+        return null;
48
+    }
43
 }
49
 }

+ 8
- 8
lib/android/app/src/test/java/com/reactnativenavigation/parse/NavigationOptionsTest.java 查看文件

53
     }
53
     }
54
 
54
 
55
     private void assertResult(Options result) {
55
     private void assertResult(Options result) {
56
-        assertThat(result.topBarOptions.title).isEqualTo(TITLE);
57
-        assertThat(result.topBarOptions.backgroundColor).isEqualTo(TOP_BAR_BACKGROUND_COLOR);
58
-        assertThat(result.topBarOptions.textColor).isEqualTo(TOP_BAR_TEXT_COLOR);
59
-        assertThat(result.topBarOptions.textFontSize).isEqualTo(TOP_BAR_FONT_SIZE);
56
+        assertThat(result.topBarOptions.title.get()).isEqualTo(TITLE);
57
+        assertThat(result.topBarOptions.backgroundColor.get()).isEqualTo(TOP_BAR_BACKGROUND_COLOR);
58
+        assertThat(result.topBarOptions.textColor.get()).isEqualTo(TOP_BAR_TEXT_COLOR);
59
+        assertThat(result.topBarOptions.textFontSize.get()).isEqualTo(TOP_BAR_FONT_SIZE);
60
         assertThat(result.topBarOptions.textFontFamily).isEqualTo(TOP_BAR_TYPEFACE);
60
         assertThat(result.topBarOptions.textFontFamily).isEqualTo(TOP_BAR_TYPEFACE);
61
         assertThat(result.topBarOptions.hidden).isEqualTo(TOP_BAR_HIDDEN);
61
         assertThat(result.topBarOptions.hidden).isEqualTo(TOP_BAR_HIDDEN);
62
         assertThat(result.topBarOptions.drawBehind).isEqualTo(TOP_BAR_DRAW_BEHIND);
62
         assertThat(result.topBarOptions.drawBehind).isEqualTo(TOP_BAR_DRAW_BEHIND);
64
         assertThat(result.bottomTabsOptions.animateHide).isEqualTo(BOTTOM_TABS_ANIMATE_HIDE);
64
         assertThat(result.bottomTabsOptions.animateHide).isEqualTo(BOTTOM_TABS_ANIMATE_HIDE);
65
         assertThat(result.bottomTabsOptions.hidden).isEqualTo(BOTTOM_TABS_HIDDEN);
65
         assertThat(result.bottomTabsOptions.hidden).isEqualTo(BOTTOM_TABS_HIDDEN);
66
         assertThat(result.bottomTabsOptions.tabBadge).isEqualTo(BOTTOM_TABS_BADGE);
66
         assertThat(result.bottomTabsOptions.tabBadge).isEqualTo(BOTTOM_TABS_BADGE);
67
-        assertThat(result.bottomTabsOptions.currentTabId).isEqualTo(BOTTOM_TABS_CURRENT_TAB_ID);
67
+        assertThat(result.bottomTabsOptions.currentTabId.get()).isEqualTo(BOTTOM_TABS_CURRENT_TAB_ID);
68
         assertThat(result.bottomTabsOptions.currentTabIndex).isEqualTo(BOTTOM_TABS_CURRENT_TAB_INDEX);
68
         assertThat(result.bottomTabsOptions.currentTabIndex).isEqualTo(BOTTOM_TABS_CURRENT_TAB_INDEX);
69
     }
69
     }
70
 
70
 
81
     @NonNull
81
     @NonNull
82
     private JSONObject createTopBar() throws JSONException {
82
     private JSONObject createTopBar() throws JSONException {
83
         return new JSONObject()
83
         return new JSONObject()
84
-                .put("title", TITLE)
84
+                .put("title", "the title")
85
                 .put("backgroundColor", TOP_BAR_BACKGROUND_COLOR)
85
                 .put("backgroundColor", TOP_BAR_BACKGROUND_COLOR)
86
                 .put("textColor", TOP_BAR_TEXT_COLOR)
86
                 .put("textColor", TOP_BAR_TEXT_COLOR)
87
                 .put("textFontSize", TOP_BAR_FONT_SIZE)
87
                 .put("textFontSize", TOP_BAR_FONT_SIZE)
94
     @NonNull
94
     @NonNull
95
     private JSONObject createOtherTopBar() throws JSONException {
95
     private JSONObject createOtherTopBar() throws JSONException {
96
         return new JSONObject()
96
         return new JSONObject()
97
-                .put("title", TITLE)
97
+                .put("title", "the title")
98
                 .put("backgroundColor", TOP_BAR_BACKGROUND_COLOR)
98
                 .put("backgroundColor", TOP_BAR_BACKGROUND_COLOR)
99
                 .put("textColor", TOP_BAR_TEXT_COLOR)
99
                 .put("textColor", TOP_BAR_TEXT_COLOR)
100
                 .put("textFontSize", TOP_BAR_FONT_SIZE)
100
                 .put("textFontSize", TOP_BAR_FONT_SIZE)
142
     @Test
142
     @Test
143
     public void defaultEmptyOptions() throws Exception {
143
     public void defaultEmptyOptions() throws Exception {
144
         Options uut = new Options();
144
         Options uut = new Options();
145
-        assertThat(uut.topBarOptions.title).isEmpty();
145
+        assertThat(uut.topBarOptions.title.get("")).isEmpty();
146
     }
146
     }
147
 }
147
 }

+ 4
- 14
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/BottomTabsControllerTest.java 查看文件

57
         List<ViewController> tabs = createTabs();
57
         List<ViewController> tabs = createTabs();
58
         uut.setTabs(tabs);
58
         uut.setTabs(tabs);
59
         assertThat(uut.getView().getChildCount()).isEqualTo(6);
59
         assertThat(uut.getView().getChildCount()).isEqualTo(6);
60
-        assertThat(uut.getChildControllers()).extracting(new Extractor<ViewController, Integer>() {
61
-            @Override
62
-            public Integer extract(final ViewController input) {
63
-                return input.getView().getVisibility();
64
-            }
65
-        }).containsExactly(View.VISIBLE, View.GONE, View.GONE, View.GONE, View.GONE);
60
+        assertThat(uut.getChildControllers()).extracting((Extractor<ViewController, Integer>) input -> input.getView().getVisibility()).containsExactly(View.VISIBLE, View.GONE, View.GONE, View.GONE, View.GONE);
66
     }
61
     }
67
 
62
 
68
     @Test
63
     @Test
73
         uut.selectTabAtIndex(3);
68
         uut.selectTabAtIndex(3);
74
 
69
 
75
         assertThat(uut.getSelectedIndex()).isEqualTo(3);
70
         assertThat(uut.getSelectedIndex()).isEqualTo(3);
76
-        assertThat(uut.getChildControllers()).extracting(new Extractor<ViewController, Integer>() {
77
-            @Override
78
-            public Integer extract(final ViewController input) {
79
-                return input.getView().getVisibility();
80
-            }
81
-        }).containsExactly(View.GONE, View.GONE, View.GONE, View.VISIBLE, View.GONE);
71
+        assertThat(uut.getChildControllers()).extracting((Extractor<ViewController, Integer>) input -> input.getView().getVisibility()).containsExactly(View.GONE, View.GONE, View.GONE, View.VISIBLE, View.GONE);
82
     }
72
     }
83
 
73
 
84
     @Test
74
     @Test
86
         assertThat(uut.findControllerById("123")).isNull();
76
         assertThat(uut.findControllerById("123")).isNull();
87
         assertThat(uut.findControllerById(uut.getId())).isEqualTo(uut);
77
         assertThat(uut.findControllerById(uut.getId())).isEqualTo(uut);
88
         StackController inner = new StackController(activity, "inner");
78
         StackController inner = new StackController(activity, "inner");
89
-        inner.push(child1);
79
+        inner.animatePush(child1, new MockPromise());
90
         assertThat(uut.findControllerById(child1.getId())).isNull();
80
         assertThat(uut.findControllerById(child1.getId())).isNull();
91
-        uut.setTabs(Arrays.<ViewController>asList(inner));
81
+        uut.setTabs(Collections.singletonList(inner));
92
         assertThat(uut.findControllerById(child1.getId())).isEqualTo(child1);
82
         assertThat(uut.findControllerById(child1.getId())).isEqualTo(child1);
93
     }
83
     }
94
 
84
 

+ 16
- 13
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ComponentViewControllerTest.java 查看文件

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
-import android.app.*;
3
+import android.app.Activity;
4
 
4
 
5
-import com.reactnativenavigation.*;
6
-import com.reactnativenavigation.mocks.*;
7
-import com.reactnativenavigation.parse.*;
5
+import com.reactnativenavigation.BaseTest;
6
+import com.reactnativenavigation.mocks.TestComponentLayout;
7
+import com.reactnativenavigation.parse.Options;
8
+import com.reactnativenavigation.views.StackLayout;
8
 
9
 
9
-import org.junit.*;
10
+import org.junit.Test;
10
 
11
 
11
-import static org.assertj.core.api.Java6Assertions.*;
12
-import static org.mockito.Mockito.*;
12
+import static org.assertj.core.api.Java6Assertions.assertThat;
13
+import static org.mockito.Mockito.spy;
14
+import static org.mockito.Mockito.times;
15
+import static org.mockito.Mockito.verify;
16
+import static org.mockito.Mockito.when;
13
 
17
 
14
 public class ComponentViewControllerTest extends BaseTest {
18
 public class ComponentViewControllerTest extends BaseTest {
15
     private ComponentViewController uut;
19
     private ComponentViewController uut;
20
+    private ParentController<StackLayout> parentController;
16
     private ComponentViewController.IReactView view;
21
     private ComponentViewController.IReactView view;
17
 
22
 
18
     @Override
23
     @Override
20
         super.beforeEach();
25
         super.beforeEach();
21
         Activity activity = newActivity();
26
         Activity activity = newActivity();
22
         view = spy(new TestComponentLayout(activity));
27
         view = spy(new TestComponentLayout(activity));
23
-        uut = new ComponentViewController(activity, "componentId1", "componentName", new ComponentViewController.ReactViewCreator() {
24
-            @Override
25
-            public ComponentViewController.IReactView create(final Activity activity1, final String componentId, final String componentName) {
26
-                return view;
27
-            }
28
-        }, new Options());
28
+        parentController = new StackController(activity, "stack");
29
+        uut = new ComponentViewController(activity, "componentId1", "componentName", (activity1, componentId, componentName) -> view, new Options());
30
+        uut.setParentController(parentController);
31
+        parentController.ensureViewIsCreated();
29
     }
32
     }
30
 
33
 
31
     @Test
34
     @Test

+ 83
- 67
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java 查看文件

20
 public class NavigatorTest extends BaseTest {
20
 public class NavigatorTest extends BaseTest {
21
     private Activity activity;
21
     private Activity activity;
22
     private Navigator uut;
22
     private Navigator uut;
23
+    private ParentController parentController;
23
     private SimpleViewController child1;
24
     private SimpleViewController child1;
24
     private ViewController child2;
25
     private ViewController child2;
25
     private ViewController child3;
26
     private ViewController child3;
32
         super.beforeEach();
33
         super.beforeEach();
33
         activity = newActivity();
34
         activity = newActivity();
34
         uut = new Navigator(activity);
35
         uut = new Navigator(activity);
36
+        parentController = new StackController(activity, "stack");
37
+        parentController.ensureViewIsCreated();
35
         child1 = new SimpleViewController(activity, "child1");
38
         child1 = new SimpleViewController(activity, "child1");
36
         child2 = new SimpleViewController(activity, "child2");
39
         child2 = new SimpleViewController(activity, "child2");
37
         child3 = new SimpleViewController(activity, "child3");
40
         child3 = new SimpleViewController(activity, "child3");
42
     @Test
45
     @Test
43
     public void setRoot_AddsChildControllerView() throws Exception {
46
     public void setRoot_AddsChildControllerView() throws Exception {
44
         assertThat(uut.getView().getChildCount()).isZero();
47
         assertThat(uut.getView().getChildCount()).isZero();
45
-        uut.setRoot(child1);
48
+        uut.setRoot(child1, new MockPromise());
46
         assertIsChildById(uut.getView(), child1.getView());
49
         assertIsChildById(uut.getView(), child1.getView());
47
     }
50
     }
48
 
51
 
49
     @Test
52
     @Test
50
     public void setRoot_ReplacesExistingChildControllerViews() throws Exception {
53
     public void setRoot_ReplacesExistingChildControllerViews() throws Exception {
51
-        uut.setRoot(child1);
52
-        uut.setRoot(child2);
54
+        uut.setRoot(child1, new MockPromise());
55
+        uut.setRoot(child2, new MockPromise());
53
         assertIsChildById(uut.getView(), child2.getView());
56
         assertIsChildById(uut.getView(), child2.getView());
54
     }
57
     }
55
 
58
 
62
     @Test
65
     @Test
63
     public void push() throws Exception {
66
     public void push() throws Exception {
64
         StackController stackController = newStack();
67
         StackController stackController = newStack();
65
-        stackController.push(child1);
66
-        uut.setRoot(stackController);
68
+        stackController.animatePush(child1, new MockPromise());
69
+        uut.setRoot(stackController, new MockPromise());
67
 
70
 
68
         assertIsChildById(uut.getView(), stackController.getView());
71
         assertIsChildById(uut.getView(), stackController.getView());
69
         assertIsChildById(stackController.getView(), child1.getView());
72
         assertIsChildById(stackController.getView(), child1.getView());
70
 
73
 
71
-        uut.push(child1.getId(), child2);
74
+        uut.push(child1.getId(), child2, new MockPromise());
72
 
75
 
73
         assertIsChildById(uut.getView(), stackController.getView());
76
         assertIsChildById(uut.getView(), stackController.getView());
74
         assertIsChildById(stackController.getView(), child2.getView());
77
         assertIsChildById(stackController.getView(), child2.getView());
76
 
79
 
77
     @Test
80
     @Test
78
     public void push_InvalidPushWithoutAStack_DoesNothing() throws Exception {
81
     public void push_InvalidPushWithoutAStack_DoesNothing() throws Exception {
79
-        uut.setRoot(child1);
80
-        uut.push(child1.getId(), child2);
82
+        uut.setRoot(child1, new MockPromise());
83
+        uut.push(child1.getId(), child2, new MockPromise());
81
         assertIsChildById(uut.getView(), child1.getView());
84
         assertIsChildById(uut.getView(), child1.getView());
82
     }
85
     }
83
 
86
 
86
         BottomTabsController bottomTabsController = newTabs();
89
         BottomTabsController bottomTabsController = newTabs();
87
         StackController stack1 = newStack();
90
         StackController stack1 = newStack();
88
         StackController stack2 = newStack();
91
         StackController stack2 = newStack();
89
-        stack1.push(child1);
90
-        stack2.push(child2);
92
+        stack1.animatePush(child1, new MockPromise());
93
+        stack2.animatePush(child2, new MockPromise());
91
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
94
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
92
-        uut.setRoot(bottomTabsController);
95
+        uut.setRoot(bottomTabsController, new MockPromise());
93
 
96
 
94
         SimpleViewController newChild = new SimpleViewController(activity, "new child");
97
         SimpleViewController newChild = new SimpleViewController(activity, "new child");
95
-        uut.push(child2.getId(), newChild);
98
+        uut.push(child2.getId(), newChild, new MockPromise());
96
 
99
 
97
         assertThat(stack1.getChildControllers()).doesNotContain(newChild);
100
         assertThat(stack1.getChildControllers()).doesNotContain(newChild);
98
         assertThat(stack2.getChildControllers()).contains(newChild);
101
         assertThat(stack2.getChildControllers()).contains(newChild);
100
 
103
 
101
     @Test
104
     @Test
102
     public void pop_InvalidDoesNothing() throws Exception {
105
     public void pop_InvalidDoesNothing() throws Exception {
103
-        uut.pop("123");
104
-        uut.setRoot(child1);
105
-        uut.pop(child1.getId());
106
+        uut.pop("123", new MockPromise());
107
+        uut.setRoot(child1, new MockPromise());
108
+        uut.pop(child1.getId(), new MockPromise());
106
         assertThat(uut.getChildControllers()).hasSize(1);
109
         assertThat(uut.getChildControllers()).hasSize(1);
107
     }
110
     }
108
 
111
 
111
         BottomTabsController bottomTabsController = newTabs();
114
         BottomTabsController bottomTabsController = newTabs();
112
         StackController stack1 = newStack();
115
         StackController stack1 = newStack();
113
         StackController stack2 = newStack();
116
         StackController stack2 = newStack();
114
-        stack1.push(child1);
115
-        stack2.push(child2);
116
-        stack2.push(child3);
117
-        stack2.push(child4);
118
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
117
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
119
-        uut.setRoot(bottomTabsController);
120
-
121
-        uut.pop("child4");
122
-
123
-        assertThat(stack2.getChildControllers()).containsOnly(child2, child3);
118
+        uut.setRoot(bottomTabsController, new MockPromise());
119
+        stack1.animatePush(child1, new MockPromise());
120
+        stack2.animatePush(child2, new MockPromise());
121
+        stack2.animatePush(child3, new MockPromise() {
122
+            @Override
123
+            public void resolve(@Nullable Object value) {
124
+                stack2.animatePush(child4, new MockPromise() {
125
+                    @Override
126
+                    public void resolve(@Nullable Object value) {
127
+                        uut.pop("child4", new MockPromise());
128
+                        assertThat(stack2.getChildControllers()).containsOnly(child2, child3);
129
+                    }
130
+                });
131
+            }
132
+        });
124
     }
133
     }
125
 
134
 
126
     @Test
135
     @Test
128
         BottomTabsController bottomTabsController = newTabs();
137
         BottomTabsController bottomTabsController = newTabs();
129
         StackController stack1 = newStack();
138
         StackController stack1 = newStack();
130
         StackController stack2 = newStack();
139
         StackController stack2 = newStack();
131
-        stack1.push(child1);
132
-        stack2.push(child2);
133
-        stack2.push(child3);
134
-        stack2.push(child4);
140
+        stack1.animatePush(child1, new MockPromise());
141
+        stack2.animatePush(child2, new MockPromise());
142
+        stack2.animatePush(child3, new MockPromise());
143
+        stack2.animatePush(child4, new MockPromise());
135
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
144
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
136
-        uut.setRoot(bottomTabsController);
145
+        uut.setRoot(bottomTabsController, new MockPromise());
137
 
146
 
138
-        uut.popSpecific(child2.getId());
147
+        uut.popSpecific(child2.getId(), new MockPromise());
139
 
148
 
140
         assertThat(stack2.getChildControllers()).containsOnly(child4, child3);
149
         assertThat(stack2.getChildControllers()).containsOnly(child4, child3);
141
     }
150
     }
145
         BottomTabsController bottomTabsController = newTabs();
154
         BottomTabsController bottomTabsController = newTabs();
146
         StackController stack1 = newStack();
155
         StackController stack1 = newStack();
147
         StackController stack2 = newStack();
156
         StackController stack2 = newStack();
148
-        stack1.push(child1);
149
-        stack2.push(child2);
150
-        stack2.push(child3);
151
-        stack2.push(child4);
152
-        stack2.push(child5);
153
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
157
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
154
-        uut.setRoot(bottomTabsController);
158
+        uut.setRoot(bottomTabsController, new MockPromise());
155
 
159
 
156
-        uut.popTo(child2.getId());
157
-
158
-        assertThat(stack2.getChildControllers()).containsOnly(child2);
160
+        stack1.animatePush(child1, new MockPromise());
161
+        stack2.animatePush(child2, new MockPromise());
162
+        stack2.animatePush(child3, new MockPromise());
163
+        stack2.animatePush(child4, new MockPromise());
164
+        stack2.animatePush(child5, new MockPromise() {
165
+            @Override
166
+            public void resolve(@Nullable Object value) {
167
+                uut.popTo(child2.getId(), new MockPromise());
168
+                assertThat(stack2.getChildControllers()).containsOnly(child2);
169
+            }
170
+        });
159
     }
171
     }
160
 
172
 
161
     @Test
173
     @Test
163
         BottomTabsController bottomTabsController = newTabs();
175
         BottomTabsController bottomTabsController = newTabs();
164
         StackController stack1 = newStack();
176
         StackController stack1 = newStack();
165
         StackController stack2 = newStack();
177
         StackController stack2 = newStack();
166
-        stack1.push(child1);
167
-        stack2.push(child2);
168
-        stack2.push(child3);
169
-        stack2.push(child4);
170
-        stack2.push(child5);
171
-
172
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
178
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
173
-        uut.setRoot(bottomTabsController);
179
+        uut.setRoot(bottomTabsController, new MockPromise());
174
 
180
 
175
-        uut.popToRoot(child3.getId());
181
+        stack1.animatePush(child1, new MockPromise());
182
+        stack2.animatePush(child2, new MockPromise());
183
+        stack2.animatePush(child3, new MockPromise());
184
+        stack2.animatePush(child4, new MockPromise());
185
+        stack2.animatePush(child5, new MockPromise() {
186
+            @Override
187
+            public void resolve(@Nullable Object value) {
188
+                uut.popToRoot(child3.getId(), new MockPromise());
176
 
189
 
177
-        assertThat(stack2.getChildControllers()).containsOnly(child2);
190
+                assertThat(stack2.getChildControllers()).containsOnly(child2);
191
+            }
192
+        });
178
     }
193
     }
179
 
194
 
180
     @Test
195
     @Test
181
     public void handleBack_DelegatesToRoot() throws Exception {
196
     public void handleBack_DelegatesToRoot() throws Exception {
182
         assertThat(uut.handleBack()).isFalse();
197
         assertThat(uut.handleBack()).isFalse();
183
         ViewController spy = spy(child1);
198
         ViewController spy = spy(child1);
184
-        uut.setRoot(spy);
199
+        uut.setRoot(spy, new MockPromise());
185
         when(spy.handleBack()).thenReturn(true);
200
         when(spy.handleBack()).thenReturn(true);
186
         assertThat(uut.handleBack()).isTrue();
201
         assertThat(uut.handleBack()).isTrue();
187
         verify(spy, times(1)).handleBack();
202
         verify(spy, times(1)).handleBack();
190
     @Test
205
     @Test
191
     public void setOptions_CallsApplyNavigationOptions() {
206
     public void setOptions_CallsApplyNavigationOptions() {
192
         ComponentViewController componentVc = new SimpleComponentViewController(activity, "theId");
207
         ComponentViewController componentVc = new SimpleComponentViewController(activity, "theId");
193
-        uut.setRoot(componentVc);
194
-        assertThat(componentVc.getOptions().topBarOptions.title).isEmpty();
208
+        componentVc.setParentController(parentController);
209
+        assertThat(componentVc.getOptions().topBarOptions.title.get("")).isEmpty();
210
+        uut.setRoot(componentVc, new MockPromise());
195
 
211
 
196
         Options options = new Options();
212
         Options options = new Options();
197
-        options.topBarOptions.title = "new title";
213
+        options.topBarOptions.title = new Text("new title");
198
 
214
 
199
         uut.setOptions("theId", options);
215
         uut.setOptions("theId", options);
200
-        assertThat(componentVc.getOptions().topBarOptions.title).isEqualTo("new title");
216
+        assertThat(componentVc.getOptions().topBarOptions.title.get()).isEqualTo("new title");
201
     }
217
     }
202
 
218
 
203
     @Test
219
     @Test
212
 
228
 
213
     @NonNull
229
     @NonNull
214
     private StackController newStack() {
230
     private StackController newStack() {
215
-        return new StackController(activity, "stack" + CompatUtils.generateViewId(), new TestNavigationAnimator());
231
+        return new StackController(activity, "stack" + CompatUtils.generateViewId());
216
     }
232
     }
217
 
233
 
218
     @Test
234
     @Test
219
     public void push_Promise() throws Exception {
235
     public void push_Promise() throws Exception {
220
         final StackController stackController = newStack();
236
         final StackController stackController = newStack();
221
-        stackController.push(child1);
222
-        uut.setRoot(stackController);
237
+        stackController.animatePush(child1, new MockPromise());
238
+        uut.setRoot(stackController, new MockPromise());
223
 
239
 
224
         assertIsChildById(uut.getView(), stackController.getView());
240
         assertIsChildById(uut.getView(), stackController.getView());
225
         assertIsChildById(stackController.getView(), child1.getView());
241
         assertIsChildById(stackController.getView(), child1.getView());
235
 
251
 
236
     @Test
252
     @Test
237
     public void push_InvalidPushWithoutAStack_DoesNothing_Promise() throws Exception {
253
     public void push_InvalidPushWithoutAStack_DoesNothing_Promise() throws Exception {
238
-        uut.setRoot(child1);
254
+        uut.setRoot(child1, new MockPromise());
239
         uut.push(child1.getId(), child2, new MockPromise() {
255
         uut.push(child1.getId(), child2, new MockPromise() {
240
             @Override
256
             @Override
241
             public void reject(String code, Throwable e) {
257
             public void reject(String code, Throwable e) {
247
 
263
 
248
     @Test
264
     @Test
249
     public void pop_InvalidDoesNothing_Promise() throws Exception {
265
     public void pop_InvalidDoesNothing_Promise() throws Exception {
250
-        uut.pop("123");
251
-        uut.setRoot(child1);
266
+        uut.pop("123", new MockPromise());
267
+        uut.setRoot(child1, new MockPromise());
252
         uut.pop(child1.getId(), new MockPromise() {
268
         uut.pop(child1.getId(), new MockPromise() {
253
             @Override
269
             @Override
254
             public void reject(Throwable reason) {
270
             public void reject(Throwable reason) {
262
         BottomTabsController bottomTabsController = newTabs();
278
         BottomTabsController bottomTabsController = newTabs();
263
         StackController stack1 = newStack();
279
         StackController stack1 = newStack();
264
         final StackController stack2 = newStack();
280
         final StackController stack2 = newStack();
265
-        stack1.push(child1);
266
-        stack2.push(child2);
267
-        stack2.push(child3);
268
-        stack2.push(child4);
269
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
281
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
270
-        uut.setRoot(bottomTabsController);
282
+        uut.setRoot(bottomTabsController, new MockPromise());
271
 
283
 
272
-        uut.pop("child4", new MockPromise() {
284
+        stack1.animatePush(child1, new MockPromise());
285
+        stack2.animatePush(child2, new MockPromise());
286
+        stack2.animatePush(child3, new MockPromise());
287
+        stack2.animatePush(child4, new MockPromise() {
273
             @Override
288
             @Override
274
             public void resolve(@Nullable Object value) {
289
             public void resolve(@Nullable Object value) {
290
+                uut.pop("child4", new MockPromise());
275
                 assertThat(stack2.getChildControllers()).containsOnly(child2, child3);
291
                 assertThat(stack2.getChildControllers()).containsOnly(child2, child3);
276
             }
292
             }
277
         });
293
         });
280
     @Test
296
     @Test
281
     public void pushIntoModal() throws Exception {
297
     public void pushIntoModal() throws Exception {
282
         StackController stackController = newStack();
298
         StackController stackController = newStack();
283
-        stackController.push(child1);
299
+        stackController.animatePush(child1, new MockPromise());
284
         uut.showModal(stackController, new MockPromise());
300
         uut.showModal(stackController, new MockPromise());
285
-        uut.push(stackController.getId(), child2);
301
+        uut.push(stackController.getId(), child2, new MockPromise());
286
         assertIsChildById(stackController.getView(), child2.getView());
302
         assertIsChildById(stackController.getView(), child2.getView());
287
     }
303
     }
288
 }
304
 }

+ 71
- 56
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java 查看文件

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
-import android.app.*;
3
+import android.app.Activity;
4
 import android.graphics.Color;
4
 import android.graphics.Color;
5
-import android.graphics.drawable.*;
6
-import android.view.*;
7
-import android.widget.*;
5
+import android.graphics.drawable.ColorDrawable;
6
+import android.view.View;
7
+import android.view.ViewGroup;
8
+import android.widget.RelativeLayout;
8
 
9
 
9
-import com.reactnativenavigation.*;
10
-import com.reactnativenavigation.mocks.*;
11
-import com.reactnativenavigation.parse.*;
10
+import com.reactnativenavigation.BaseTest;
11
+import com.reactnativenavigation.mocks.MockPromise;
12
+import com.reactnativenavigation.mocks.TestComponentLayout;
13
+import com.reactnativenavigation.parse.Fraction;
14
+import com.reactnativenavigation.parse.Options;
15
+import com.reactnativenavigation.parse.Text;
12
 
16
 
13
-import org.junit.*;
17
+import org.junit.Test;
14
 
18
 
15
-import static android.widget.RelativeLayout.*;
16
-import static org.assertj.core.api.Java6Assertions.*;
17
-import static org.mockito.Mockito.*;
19
+import javax.annotation.Nullable;
20
+
21
+import static android.widget.RelativeLayout.BELOW;
22
+import static org.assertj.core.api.Java6Assertions.assertThat;
23
+import static org.mockito.Mockito.spy;
18
 
24
 
19
 public class OptionsApplyingTest extends BaseTest {
25
 public class OptionsApplyingTest extends BaseTest {
20
     private Activity activity;
26
     private Activity activity;
27
+    private StackController stackController;
21
     private ComponentViewController uut;
28
     private ComponentViewController uut;
22
     private ComponentViewController.IReactView view;
29
     private ComponentViewController.IReactView view;
23
     private Options initialNavigationOptions;
30
     private Options initialNavigationOptions;
34
                 (activity1, componentId, componentName) -> view,
41
                 (activity1, componentId, componentName) -> view,
35
                 initialNavigationOptions
42
                 initialNavigationOptions
36
         );
43
         );
37
-        uut.ensureViewIsCreated();
44
+        stackController = new StackController(activity, "stack");
45
+        stackController.ensureViewIsCreated();
46
+        uut.setParentController(stackController);
38
     }
47
     }
39
 
48
 
40
     @Test
49
     @Test
41
     public void applyNavigationOptionsHandlesNoParentStack() throws Exception {
50
     public void applyNavigationOptionsHandlesNoParentStack() throws Exception {
51
+        uut.setParentController(null);
42
         assertThat(uut.getParentStackController()).isNull();
52
         assertThat(uut.getParentStackController()).isNull();
43
         uut.onViewAppeared();
53
         uut.onViewAppeared();
44
         assertThat(uut.getParentStackController()).isNull();
54
         assertThat(uut.getParentStackController()).isNull();
47
     @Test
57
     @Test
48
     public void initialOptionsAppliedOnAppear() throws Exception {
58
     public void initialOptionsAppliedOnAppear() throws Exception {
49
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
59
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
50
-        initialNavigationOptions.topBarOptions.title = "the title";
60
+        initialNavigationOptions.topBarOptions.title = new Text("the title");
51
         StackController stackController = new StackController(activity, "stackId");
61
         StackController stackController = new StackController(activity, "stackId");
52
-        stackController.push(uut);
53
-        assertThat(uut.getTopBar().getTitle()).isEmpty();
62
+        stackController.animatePush(uut, new MockPromise() {});
63
+        assertThat(stackController.getTopBar().getTitle()).isEmpty();
54
 
64
 
55
         uut.onViewAppeared();
65
         uut.onViewAppeared();
56
-        assertThat(uut.getTopBar().getTitle()).isEqualTo("the title");
66
+        assertThat(stackController.getTopBar().getTitle()).isEqualTo("the title");
57
     }
67
     }
58
 
68
 
59
     @Test
69
     @Test
60
     public void mergeNavigationOptionsUpdatesCurrentOptions() throws Exception {
70
     public void mergeNavigationOptionsUpdatesCurrentOptions() throws Exception {
61
-        assertThat(uut.getOptions().topBarOptions.title).isEmpty();
71
+        uut.ensureViewIsCreated();
72
+        assertThat(uut.getOptions().topBarOptions.title.get("")).isEmpty();
62
         Options options = new Options();
73
         Options options = new Options();
63
-        options.topBarOptions.title = "new title";
74
+        options.topBarOptions.title = new Text("new title");
64
         uut.mergeOptions(options);
75
         uut.mergeOptions(options);
65
-        assertThat(uut.getOptions().topBarOptions.title).isEqualTo("new title");
76
+        assertThat(uut.getOptions().topBarOptions.title.get()).isEqualTo("new title");
66
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
77
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
67
     }
78
     }
68
 
79
 
69
     @Test
80
     @Test
70
     public void reappliesOptionsOnMerge() throws Exception {
81
     public void reappliesOptionsOnMerge() throws Exception {
71
         uut.onViewAppeared();
82
         uut.onViewAppeared();
72
-        assertThat(uut.getTopBar().getTitle()).isEmpty();
83
+        assertThat(stackController.getTopBar().getTitle()).isEmpty();
73
 
84
 
74
         Options opts = new Options();
85
         Options opts = new Options();
75
-        opts.topBarOptions.title = "the new title";
86
+        opts.topBarOptions.title = new Text("the new title");
76
         uut.mergeOptions(opts);
87
         uut.mergeOptions(opts);
77
 
88
 
78
-        assertThat(uut.getTopBar().getTitle()).isEqualTo("the new title");
89
+        assertThat(stackController.getTopBar().getTitle()).isEqualTo("the new title");
79
     }
90
     }
80
 
91
 
81
     @Test
92
     @Test
82
     public void appliesTopBackBackgroundColor() throws Exception {
93
     public void appliesTopBackBackgroundColor() throws Exception {
83
         uut.onViewAppeared();
94
         uut.onViewAppeared();
84
-        //TODO: FIX TEST
85
-        assertThat(((ColorDrawable) uut.getTopBar().getTitleBar().getBackground()).getColor()).isNotEqualTo(Color.RED);
86
 
95
 
87
         Options opts = new Options();
96
         Options opts = new Options();
88
-        opts.topBarOptions.backgroundColor = Color.RED;
97
+        opts.topBarOptions.backgroundColor = new com.reactnativenavigation.parse.Color(Color.RED);
89
         uut.mergeOptions(opts);
98
         uut.mergeOptions(opts);
90
 
99
 
91
-        assertThat(((ColorDrawable) uut.getTopBar().getTitleBar().getBackground()).getColor()).isEqualTo(Color.RED);
100
+        assertThat(((ColorDrawable) stackController.getTopBar().getTitleBar().getBackground()).getColor()).isEqualTo(Color.RED);
92
     }
101
     }
93
 
102
 
94
     @Test
103
     @Test
95
     public void appliesTopBarTextColor() throws Exception {
104
     public void appliesTopBarTextColor() throws Exception {
96
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
105
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
97
-        initialNavigationOptions.topBarOptions.title = "the title";
98
-        uut.onViewAppeared();
99
-        assertThat(uut.getTopBar().getTitleTextView().getCurrentTextColor()).isNotEqualTo(Color.RED);
100
-
101
-        Options opts = new Options();
102
-        opts.topBarOptions.title = "the title";
103
-        opts.topBarOptions.textColor = Color.RED;
104
-        uut.mergeOptions(opts);
105
-
106
-        assertThat(uut.getTopBar().getTitleTextView()).isNotEqualTo(null);
107
-        assertThat(uut.getTopBar().getTitleTextView().getCurrentTextColor()).isEqualTo(Color.RED);
106
+        initialNavigationOptions.topBarOptions.title = new Text("the title");
107
+        stackController.animatePush(uut, new MockPromise() {
108
+            @Override
109
+            public void resolve(@Nullable Object value) {
110
+                Options opts = new Options();
111
+                opts.topBarOptions.title = new Text("the title");
112
+                opts.topBarOptions.textColor = new com.reactnativenavigation.parse.Color(Color.RED);
113
+                uut.mergeOptions(opts);
114
+
115
+                assertThat(stackController.getTopBar().getTitleTextView()).isNotEqualTo(null);
116
+                assertThat(stackController.getTopBar().getTitleTextView().getCurrentTextColor()).isEqualTo(Color.RED);
117
+            }
118
+        });
108
     }
119
     }
109
 
120
 
110
     @Test
121
     @Test
111
     public void appliesTopBarTextSize() throws Exception {
122
     public void appliesTopBarTextSize() throws Exception {
112
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
123
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
113
-        initialNavigationOptions.topBarOptions.title = "the title";
124
+        initialNavigationOptions.topBarOptions.title = new Text("the title");
114
         uut.onViewAppeared();
125
         uut.onViewAppeared();
115
-        assertThat(uut.getTopBar().getTitleTextView().getTextSize()).isNotEqualTo(18);
116
 
126
 
117
         Options opts = new Options();
127
         Options opts = new Options();
118
-        opts.topBarOptions.title = "the title";
119
-        opts.topBarOptions.textFontSize = 18;
128
+        opts.topBarOptions.title = new Text("the title");
129
+        opts.topBarOptions.textFontSize = new Fraction(18);
120
         uut.mergeOptions(opts);
130
         uut.mergeOptions(opts);
121
 
131
 
122
-        assertThat(uut.getTopBar().getTitleTextView()).isNotEqualTo(null);
123
-        assertThat(uut.getTopBar().getTitleTextView().getTextSize()).isEqualTo(18);
132
+        assertThat(stackController.getTopBar().getTitleTextView()).isNotEqualTo(null);
133
+        assertThat(stackController.getTopBar().getTitleTextView().getTextSize()).isEqualTo(18);
124
     }
134
     }
125
 
135
 
126
     @Test
136
     @Test
127
     public void appliesTopBarHidden() throws Exception {
137
     public void appliesTopBarHidden() throws Exception {
128
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
138
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
129
-        initialNavigationOptions.topBarOptions.title = "the title";
139
+        initialNavigationOptions.topBarOptions.title = new Text("the title");
130
         uut.onViewAppeared();
140
         uut.onViewAppeared();
131
-        assertThat(uut.getTopBar().getVisibility()).isNotEqualTo(View.GONE);
141
+        assertThat(stackController.getTopBar().getVisibility()).isNotEqualTo(View.GONE);
132
 
142
 
133
         Options opts = new Options();
143
         Options opts = new Options();
134
         opts.topBarOptions.hidden = Options.BooleanOptions.True;
144
         opts.topBarOptions.hidden = Options.BooleanOptions.True;
135
         uut.mergeOptions(opts);
145
         uut.mergeOptions(opts);
136
 
146
 
137
-        assertThat(uut.getTopBar().getVisibility()).isEqualTo(View.GONE);
147
+        assertThat(stackController.getTopBar().getVisibility()).isEqualTo(View.GONE);
138
     }
148
     }
139
 
149
 
140
     @Test
150
     @Test
141
     public void appliesDrawUnder() throws Exception {
151
     public void appliesDrawUnder() throws Exception {
142
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
152
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
143
-        initialNavigationOptions.topBarOptions.title = "the title";
153
+        initialNavigationOptions.topBarOptions.title = new Text("the title");
144
         initialNavigationOptions.topBarOptions.drawBehind = Options.BooleanOptions.False;
154
         initialNavigationOptions.topBarOptions.drawBehind = Options.BooleanOptions.False;
145
         uut.onViewAppeared();
155
         uut.onViewAppeared();
146
-        RelativeLayout.LayoutParams uutLayoutParams = (RelativeLayout.LayoutParams) ((ViewGroup) uut.getComponent().asView()).getChildAt(1).getLayoutParams();
147
-        assertThat(uutLayoutParams.getRule(BELOW)).isNotEqualTo(0);
148
-
149
-        Options opts = new Options();
150
-        opts.topBarOptions.drawBehind = Options.BooleanOptions.True;
151
-        uut.mergeOptions(opts);
152
-
153
-        uutLayoutParams = (RelativeLayout.LayoutParams) ((ViewGroup) uut.getComponent().asView()).getChildAt(1).getLayoutParams();
154
-        assertThat(uutLayoutParams.getRule(BELOW)).isEqualTo(0);
156
+        stackController.animatePush(uut, new MockPromise() {
157
+            @Override
158
+            public void resolve(@Nullable Object value) {
159
+                RelativeLayout.LayoutParams uutLayoutParams = (RelativeLayout.LayoutParams) ((ViewGroup) uut.getComponent().asView()).getChildAt(0).getLayoutParams();
160
+                assertThat(uutLayoutParams.getRule(BELOW)).isNotEqualTo(0);
161
+
162
+                Options opts = new Options();
163
+                opts.topBarOptions.drawBehind = Options.BooleanOptions.True;
164
+                uut.mergeOptions(opts);
165
+
166
+                uutLayoutParams = (RelativeLayout.LayoutParams) (uut.getComponent().asView()).getLayoutParams();
167
+                assertThat(uutLayoutParams.getRule(BELOW)).isNotEqualTo(stackController.getTopBar().getId());
168
+            }
169
+        });
155
     }
170
     }
156
 }
171
 }

+ 3
- 3
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java 查看文件

65
 
65
 
66
     @Test
66
     @Test
67
     public void findControllerById_Recursive() throws Exception {
67
     public void findControllerById_Recursive() throws Exception {
68
-        StackController stackController = new StackController(activity, "stack", new TestNavigationAnimator());
68
+        StackController stackController = new StackController(activity, "stack");
69
         SimpleViewController child1 = new SimpleViewController(activity, "child1");
69
         SimpleViewController child1 = new SimpleViewController(activity, "child1");
70
         SimpleViewController child2 = new SimpleViewController(activity, "child2");
70
         SimpleViewController child2 = new SimpleViewController(activity, "child2");
71
-        stackController.push(child1);
72
-        stackController.push(child2);
71
+        stackController.animatePush(child1, new MockPromise());
72
+        stackController.animatePush(child2, new MockPromise());
73
         children.add(stackController);
73
         children.add(stackController);
74
 
74
 
75
         assertThat(uut.findControllerById("child2")).isEqualTo(child2);
75
         assertThat(uut.findControllerById("child2")).isEqualTo(child2);

+ 142
- 99
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java 查看文件

9
 import org.assertj.core.api.iterable.*;
9
 import org.assertj.core.api.iterable.*;
10
 import org.junit.*;
10
 import org.junit.*;
11
 
11
 
12
+import javax.annotation.Nullable;
13
+
12
 import static org.assertj.core.api.Java6Assertions.*;
14
 import static org.assertj.core.api.Java6Assertions.*;
13
 import static org.mockito.Mockito.*;
15
 import static org.mockito.Mockito.*;
14
 
16
 
24
     public void beforeEach() {
26
     public void beforeEach() {
25
         super.beforeEach();
27
         super.beforeEach();
26
         activity = newActivity();
28
         activity = newActivity();
27
-        uut = new StackController(activity, "uut", new TestNavigationAnimator());
29
+        uut = new StackController(activity, "uut");
28
         child1 = new SimpleViewController(activity, "child1");
30
         child1 = new SimpleViewController(activity, "child1");
29
         child2 = new SimpleViewController(activity, "child2");
31
         child2 = new SimpleViewController(activity, "child2");
30
         child3 = new SimpleViewController(activity, "child3");
32
         child3 = new SimpleViewController(activity, "child3");
38
     @Test
40
     @Test
39
     public void holdsAStackOfViewControllers() throws Exception {
41
     public void holdsAStackOfViewControllers() throws Exception {
40
         assertThat(uut.isEmpty()).isTrue();
42
         assertThat(uut.isEmpty()).isTrue();
41
-        uut.push(child1);
42
-        uut.push(child2);
43
-        uut.push(child3);
43
+        uut.animatePush(child1, new MockPromise());
44
+        uut.animatePush(child2, new MockPromise());
45
+        uut.animatePush(child3, new MockPromise());
44
         assertThat(uut.peek()).isEqualTo(child3);
46
         assertThat(uut.peek()).isEqualTo(child3);
45
         assertContainsOnlyId(child1.getId(), child2.getId(), child3.getId());
47
         assertContainsOnlyId(child1.getId(), child2.getId(), child3.getId());
46
     }
48
     }
48
     @Test
50
     @Test
49
     public void push() throws Exception {
51
     public void push() throws Exception {
50
         assertThat(uut.isEmpty()).isTrue();
52
         assertThat(uut.isEmpty()).isTrue();
51
-        uut.push(child1);
53
+        uut.animatePush(child1, new MockPromise());
52
         assertContainsOnlyId(child1.getId());
54
         assertContainsOnlyId(child1.getId());
53
     }
55
     }
54
 
56
 
55
     @Test
57
     @Test
56
     public void pop() throws Exception {
58
     public void pop() throws Exception {
57
-        uut.push(child1);
58
-        uut.push(child2);
59
-        assertContainsOnlyId(child2.getId(), child1.getId());
60
-        uut.pop();
61
-        assertContainsOnlyId(child1.getId());
59
+        uut.animatePush(child1, new MockPromise());
60
+        uut.animatePush(child2, new MockPromise() {
61
+            @Override
62
+            public void resolve(@Nullable Object value) {
63
+                assertContainsOnlyId(child2.getId(), child1.getId());
64
+                uut.pop(new MockPromise());
65
+                assertContainsOnlyId(child1.getId());
66
+            }
67
+        });
62
     }
68
     }
63
 
69
 
64
     @Test
70
     @Test
66
         assertThat(uut.peek()).isNull();
72
         assertThat(uut.peek()).isNull();
67
         assertThat(uut.size()).isZero();
73
         assertThat(uut.size()).isZero();
68
         assertThat(uut.isEmpty()).isTrue();
74
         assertThat(uut.isEmpty()).isTrue();
69
-        uut.push(child1);
75
+        uut.animatePush(child1, new MockPromise());
70
         assertThat(uut.peek()).isEqualTo(child1);
76
         assertThat(uut.peek()).isEqualTo(child1);
71
         assertThat(uut.size()).isEqualTo(1);
77
         assertThat(uut.size()).isEqualTo(1);
72
         assertThat(uut.isEmpty()).isFalse();
78
         assertThat(uut.isEmpty()).isFalse();
75
     @Test
81
     @Test
76
     public void pushAssignsRefToSelfOnPushedController() throws Exception {
82
     public void pushAssignsRefToSelfOnPushedController() throws Exception {
77
         assertThat(child1.getParentStackController()).isNull();
83
         assertThat(child1.getParentStackController()).isNull();
78
-        uut.push(child1);
84
+        uut.animatePush(child1, new MockPromise());
79
         assertThat(child1.getParentStackController()).isEqualTo(uut);
85
         assertThat(child1.getParentStackController()).isEqualTo(uut);
80
 
86
 
81
-        StackController anotherNavController = new StackController(activity, "another", new TestNavigationAnimator());
82
-        anotherNavController.push(child2);
87
+        StackController anotherNavController = new StackController(activity, "another");
88
+        anotherNavController.animatePush(child2, new MockPromise());
83
         assertThat(child2.getParentStackController()).isEqualTo(anotherNavController);
89
         assertThat(child2.getParentStackController()).isEqualTo(anotherNavController);
84
     }
90
     }
85
 
91
 
88
         assertThat(uut.isEmpty()).isTrue();
94
         assertThat(uut.isEmpty()).isTrue();
89
         assertThat(uut.handleBack()).isFalse();
95
         assertThat(uut.handleBack()).isFalse();
90
 
96
 
91
-        uut.push(child1);
97
+        uut.animatePush(child1, new MockPromise());
92
         assertThat(uut.size()).isEqualTo(1);
98
         assertThat(uut.size()).isEqualTo(1);
93
         assertThat(uut.handleBack()).isFalse();
99
         assertThat(uut.handleBack()).isFalse();
94
 
100
 
95
-        uut.push(child2);
96
-        assertThat(uut.size()).isEqualTo(2);
97
-        assertThat(uut.handleBack()).isTrue();
98
-        assertThat(uut.size()).isEqualTo(1);
99
-        assertThat(uut.handleBack()).isFalse();
101
+        uut.animatePush(child2, new MockPromise() {
102
+            @Override
103
+            public void resolve(@Nullable Object value) {
104
+                assertThat(uut.size()).isEqualTo(2);
105
+                assertThat(uut.handleBack()).isTrue();
106
+
107
+                assertThat(uut.size()).isEqualTo(1);
108
+                assertThat(uut.handleBack()).isFalse();
109
+            }
110
+        });
100
     }
111
     }
101
 
112
 
102
     @Test
113
     @Test
103
     public void popDoesNothingWhenZeroOrOneChild() throws Exception {
114
     public void popDoesNothingWhenZeroOrOneChild() throws Exception {
104
         assertThat(uut.isEmpty()).isTrue();
115
         assertThat(uut.isEmpty()).isTrue();
105
-        uut.pop();
116
+        uut.pop(new MockPromise());
106
         assertThat(uut.isEmpty()).isTrue();
117
         assertThat(uut.isEmpty()).isTrue();
107
 
118
 
108
-        uut.push(child1);
109
-        uut.pop();
119
+        uut.animatePush(child1, new MockPromise());
120
+        uut.pop(new MockPromise());
110
         assertContainsOnlyId(child1.getId());
121
         assertContainsOnlyId(child1.getId());
111
     }
122
     }
112
 
123
 
114
     public void canPopWhenSizeIsMoreThanOne() throws Exception {
125
     public void canPopWhenSizeIsMoreThanOne() throws Exception {
115
         assertThat(uut.isEmpty()).isTrue();
126
         assertThat(uut.isEmpty()).isTrue();
116
         assertThat(uut.canPop()).isFalse();
127
         assertThat(uut.canPop()).isFalse();
117
-        uut.push(child1);
128
+        uut.animatePush(child1, new MockPromise());
118
         assertContainsOnlyId(child1.getId());
129
         assertContainsOnlyId(child1.getId());
119
         assertThat(uut.canPop()).isFalse();
130
         assertThat(uut.canPop()).isFalse();
120
-        uut.push(child2);
131
+        uut.animatePush(child2, new MockPromise());
121
         assertContainsOnlyId(child1.getId(), child2.getId());
132
         assertContainsOnlyId(child1.getId(), child2.getId());
122
         assertThat(uut.canPop()).isTrue();
133
         assertThat(uut.canPop()).isTrue();
123
     }
134
     }
125
     @Test
136
     @Test
126
     public void pushAddsToViewTree() throws Exception {
137
     public void pushAddsToViewTree() throws Exception {
127
         assertThat(uut.getView().findViewById(child1.getView().getId())).isNull();
138
         assertThat(uut.getView().findViewById(child1.getView().getId())).isNull();
128
-        uut.push(child1);
139
+        uut.animatePush(child1, new MockPromise());
129
         assertThat(uut.getView().findViewById(child1.getView().getId())).isNotNull();
140
         assertThat(uut.getView().findViewById(child1.getView().getId())).isNotNull();
130
     }
141
     }
131
 
142
 
132
     @Test
143
     @Test
133
     public void pushRemovesPreviousFromTree() throws Exception {
144
     public void pushRemovesPreviousFromTree() throws Exception {
134
         assertThat(uut.getView().findViewById(child1.getView().getId())).isNull();
145
         assertThat(uut.getView().findViewById(child1.getView().getId())).isNull();
135
-        uut.push(child1);
146
+        uut.animatePush(child1, new MockPromise());
136
         assertThat(uut.getView().findViewById(child1.getView().getId())).isNotNull();
147
         assertThat(uut.getView().findViewById(child1.getView().getId())).isNotNull();
137
-        uut.push(child2);
138
-        assertThat(uut.getView().findViewById(child1.getView().getId())).isNull();
139
-        assertThat(uut.getView().findViewById(child2.getView().getId())).isNotNull();
148
+        uut.animatePush(child2, new MockPromise() {
149
+            @Override
150
+            public void resolve(@Nullable Object value) {
151
+                assertThat(uut.getView().findViewById(child1.getView().getId())).isNull();
152
+                assertThat(uut.getView().findViewById(child2.getView().getId())).isNotNull();
153
+            }
154
+        });
140
     }
155
     }
141
 
156
 
142
     @Test
157
     @Test
143
     public void popReplacesViewWithPrevious() throws Exception {
158
     public void popReplacesViewWithPrevious() throws Exception {
144
-        uut.push(child1);
145
-        uut.push(child2);
146
         final View child2View = child2.getView();
159
         final View child2View = child2.getView();
147
         final View child1View = child1.getView();
160
         final View child1View = child1.getView();
148
-        assertIsChildById(uut.getView(), child2View);
149
-        assertNotChildOf(uut.getView(), child1View);
150
-        uut.pop();
151
-        assertNotChildOf(uut.getView(), child2View);
152
-        assertIsChildById(uut.getView(), child1View);
161
+
162
+        uut.animatePush(child1, new MockPromise());
163
+        uut.animatePush(child2, new MockPromise() {
164
+            @Override
165
+            public void resolve(@Nullable Object value) {
166
+                assertIsChildById(uut.getView(), child2View);
167
+                assertNotChildOf(uut.getView(), child1View);
168
+                uut.pop(new MockPromise());
169
+                assertNotChildOf(uut.getView(), child2View);
170
+                assertIsChildById(uut.getView(), child1View);
171
+            }
172
+        });
153
     }
173
     }
154
 
174
 
155
     @Test
175
     @Test
156
     public void popSpecificWhenTopIsRegularPop() throws Exception {
176
     public void popSpecificWhenTopIsRegularPop() throws Exception {
157
-        uut.push(child1);
158
-        uut.push(child2);
159
-        uut.popSpecific(child2);
160
-        assertContainsOnlyId(child1.getId());
161
-        assertIsChildById(uut.getView(), child1.getView());
177
+        uut.animatePush(child1, new MockPromise());
178
+        uut.animatePush(child2, new MockPromise() {
179
+            @Override
180
+            public void resolve(@Nullable Object value) {
181
+                uut.popSpecific(child2, new MockPromise() {
182
+                    @Override
183
+                    public void resolve(@Nullable Object value) {
184
+                        assertContainsOnlyId(child1.getId());
185
+                        assertIsChildById(uut.getView(), child1.getView());
186
+                    }
187
+                });
188
+            }
189
+        });
162
     }
190
     }
163
 
191
 
164
     @Test
192
     @Test
165
     public void popSpecificDeepInStack() throws Exception {
193
     public void popSpecificDeepInStack() throws Exception {
166
-        uut.push(child1);
167
-        uut.push(child2);
194
+        uut.animatePush(child1, new MockPromise());
195
+        uut.animatePush(child2, new MockPromise());
168
         assertIsChildById(uut.getView(), child2.getView());
196
         assertIsChildById(uut.getView(), child2.getView());
169
-        uut.popSpecific(child1);
197
+        uut.popSpecific(child1, new MockPromise());
170
         assertContainsOnlyId(child2.getId());
198
         assertContainsOnlyId(child2.getId());
171
         assertIsChildById(uut.getView(), child2.getView());
199
         assertIsChildById(uut.getView(), child2.getView());
172
     }
200
     }
173
 
201
 
174
     @Test
202
     @Test
175
     public void popTo_PopsTopUntilControllerIsNewTop() throws Exception {
203
     public void popTo_PopsTopUntilControllerIsNewTop() throws Exception {
176
-        uut.push(child1);
177
-        uut.push(child2);
178
-        uut.push(child3);
179
-
180
-        assertThat(uut.size()).isEqualTo(3);
181
-        assertThat(uut.peek()).isEqualTo(child3);
204
+        uut.animatePush(child1, new MockPromise());
205
+        uut.animatePush(child2, new MockPromise());
206
+        uut.animatePush(child3, new MockPromise() {
207
+            @Override
208
+            public void resolve(@Nullable Object value) {
209
+                assertThat(uut.size()).isEqualTo(3);
210
+                assertThat(uut.peek()).isEqualTo(child3);
182
 
211
 
183
-        uut.popTo(child1);
212
+                uut.popTo(child1, new MockPromise());
184
 
213
 
185
-        assertThat(uut.size()).isEqualTo(1);
186
-        assertThat(uut.peek()).isEqualTo(child1);
214
+                assertThat(uut.size()).isEqualTo(1);
215
+                assertThat(uut.peek()).isEqualTo(child1);
216
+            }
217
+        });
187
     }
218
     }
188
 
219
 
189
     @Test
220
     @Test
190
     public void popTo_NotAChildOfThisStack_DoesNothing() throws Exception {
221
     public void popTo_NotAChildOfThisStack_DoesNothing() throws Exception {
191
-        uut.push(child1);
192
-        uut.push(child3);
222
+        uut.animatePush(child1, new MockPromise());
223
+        uut.animatePush(child3, new MockPromise());
193
         assertThat(uut.size()).isEqualTo(2);
224
         assertThat(uut.size()).isEqualTo(2);
194
-        uut.popTo(child2);
225
+        uut.popTo(child2, new MockPromise());
195
         assertThat(uut.size()).isEqualTo(2);
226
         assertThat(uut.size()).isEqualTo(2);
196
     }
227
     }
197
 
228
 
198
     @Test
229
     @Test
199
     public void popToRoot_PopsEverythingAboveFirstController() throws Exception {
230
     public void popToRoot_PopsEverythingAboveFirstController() throws Exception {
200
-        uut.push(child1);
201
-        uut.push(child2);
202
-        uut.push(child3);
203
-
204
-        assertThat(uut.size()).isEqualTo(3);
205
-        assertThat(uut.peek()).isEqualTo(child3);
206
-
207
-        uut.popToRoot();
208
-
209
-        assertThat(uut.size()).isEqualTo(1);
210
-        assertThat(uut.peek()).isEqualTo(child1);
231
+        uut.animatePush(child1, new MockPromise());
232
+        uut.animatePush(child2, new MockPromise());
233
+        uut.animatePush(child3, new MockPromise() {
234
+            @Override
235
+            public void resolve(@Nullable Object value) {
236
+                assertThat(uut.size()).isEqualTo(3);
237
+                assertThat(uut.peek()).isEqualTo(child3);
238
+
239
+                uut.popToRoot(new MockPromise() {
240
+                    @Override
241
+                    public void resolve(@Nullable Object value) {
242
+                        assertThat(uut.size()).isEqualTo(1);
243
+                        assertThat(uut.peek()).isEqualTo(child1);
244
+                    }
245
+                });
246
+            }
247
+        });
211
     }
248
     }
212
 
249
 
213
     @Test
250
     @Test
214
     public void popToRoot_EmptyStackDoesNothing() throws Exception {
251
     public void popToRoot_EmptyStackDoesNothing() throws Exception {
215
         assertThat(uut.isEmpty()).isTrue();
252
         assertThat(uut.isEmpty()).isTrue();
216
-        uut.popToRoot();
253
+        uut.popToRoot(new MockPromise());
217
         assertThat(uut.isEmpty()).isTrue();
254
         assertThat(uut.isEmpty()).isTrue();
218
     }
255
     }
219
 
256
 
221
     public void findControllerById_ReturnsSelfOrChildrenById() throws Exception {
258
     public void findControllerById_ReturnsSelfOrChildrenById() throws Exception {
222
         assertThat(uut.findControllerById("123")).isNull();
259
         assertThat(uut.findControllerById("123")).isNull();
223
         assertThat(uut.findControllerById(uut.getId())).isEqualTo(uut);
260
         assertThat(uut.findControllerById(uut.getId())).isEqualTo(uut);
224
-        uut.push(child1);
261
+        uut.animatePush(child1, new MockPromise());
225
         assertThat(uut.findControllerById(child1.getId())).isEqualTo(child1);
262
         assertThat(uut.findControllerById(child1.getId())).isEqualTo(child1);
226
     }
263
     }
227
 
264
 
228
     @Test
265
     @Test
229
     public void findControllerById_Deeply() throws Exception {
266
     public void findControllerById_Deeply() throws Exception {
230
-        StackController stack = new StackController(activity, "stack2", new TestNavigationAnimator());
231
-        stack.push(child2);
232
-        uut.push(stack);
267
+        StackController stack = new StackController(activity, "stack2");
268
+        stack.animatePush(child2, new MockPromise());
269
+        uut.animatePush(stack, new MockPromise());
233
         assertThat(uut.findControllerById(child2.getId())).isEqualTo(child2);
270
         assertThat(uut.findControllerById(child2.getId())).isEqualTo(child2);
234
     }
271
     }
235
 
272
 
238
         child1 = spy(child1);
275
         child1 = spy(child1);
239
         child2 = spy(child2);
276
         child2 = spy(child2);
240
         child3 = spy(child3);
277
         child3 = spy(child3);
241
-        uut.push(child1);
242
-        uut.push(child2);
243
-        uut.push(child3);
244
-
245
-        verify(child3, times(0)).destroy();
246
-        uut.pop();
247
-        verify(child3, times(1)).destroy();
278
+        uut.animatePush(child1, new MockPromise());
279
+        uut.animatePush(child2, new MockPromise());
280
+        uut.animatePush(child3, new MockPromise() {
281
+            @Override
282
+            public void resolve(@Nullable Object value) {
283
+                verify(child3, times(0)).destroy();
284
+                uut.pop(new MockPromise());
285
+                verify(child3, times(1)).destroy();
286
+            }
287
+        });
248
     }
288
     }
249
 
289
 
250
     @Test
290
     @Test
252
         child1 = spy(child1);
292
         child1 = spy(child1);
253
         child2 = spy(child2);
293
         child2 = spy(child2);
254
         child3 = spy(child3);
294
         child3 = spy(child3);
255
-        uut.push(child1);
256
-        uut.push(child2);
257
-        uut.push(child3);
295
+        uut.animatePush(child1, new MockPromise());
296
+        uut.animatePush(child2, new MockPromise());
297
+        uut.animatePush(child3, new MockPromise());
258
 
298
 
259
         verify(child2, times(0)).destroy();
299
         verify(child2, times(0)).destroy();
260
-        uut.popSpecific(child2);
300
+        uut.popSpecific(child2, new MockPromise());
261
         verify(child2, times(1)).destroy();
301
         verify(child2, times(1)).destroy();
262
     }
302
     }
263
 
303
 
266
         child1 = spy(child1);
306
         child1 = spy(child1);
267
         child2 = spy(child2);
307
         child2 = spy(child2);
268
         child3 = spy(child3);
308
         child3 = spy(child3);
269
-        uut.push(child1);
270
-        uut.push(child2);
271
-        uut.push(child3);
272
-
273
-        verify(child2, times(0)).destroy();
274
-        verify(child3, times(0)).destroy();
275
-        uut.popTo(child1);
276
-        verify(child2, times(1)).destroy();
277
-        verify(child3, times(1)).destroy();
309
+        uut.animatePush(child1, new MockPromise());
310
+        uut.animatePush(child2, new MockPromise());
311
+        uut.animatePush(child3, new MockPromise() {
312
+            @Override
313
+            public void resolve(@Nullable Object value) {
314
+                verify(child2, times(0)).destroy();
315
+                verify(child3, times(0)).destroy();
316
+
317
+                uut.popTo(child1, new MockPromise() {
318
+                    @Override
319
+                    public void resolve(@Nullable Object value) {
320
+                        verify(child2, times(1)).destroy();
321
+                        verify(child3, times(1)).destroy();
322
+                    }
323
+                });
324
+            }
325
+        });
278
     }
326
     }
279
 
327
 
280
     private void assertContainsOnlyId(String... ids) {
328
     private void assertContainsOnlyId(String... ids) {
281
         assertThat(uut.size()).isEqualTo(ids.length);
329
         assertThat(uut.size()).isEqualTo(ids.length);
282
-        assertThat(uut.getChildControllers()).extracting(new Extractor<ViewController, String>() {
283
-            @Override
284
-            public String extract(final ViewController input) {
285
-                return input.getId();
286
-            }
287
-        }).containsOnly(ids);
330
+        assertThat(uut.getChildControllers()).extracting((Extractor<ViewController, String>) ViewController::getId).containsOnly(ids);
288
     }
331
     }
289
 }
332
 }

+ 11
- 6
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java 查看文件

23
 
23
 
24
     private TopTabsController uut;
24
     private TopTabsController uut;
25
     private List<TopTabLayoutMock> tabs = new ArrayList<>(SIZE);
25
     private List<TopTabLayoutMock> tabs = new ArrayList<>(SIZE);
26
-    private List<TopTabController> tabControllers = new ArrayList<>(SIZE);
26
+    private List<ViewController> tabControllers = new ArrayList<>(SIZE);
27
     private List<Options> tabOptions = new ArrayList<>(SIZE);
27
     private List<Options> tabOptions = new ArrayList<>(SIZE);
28
     private Options options;
28
     private Options options;
29
     private TopTabsLayout topTabsLayout;
29
     private TopTabsLayout topTabsLayout;
34
         tabControllers.clear();
34
         tabControllers.clear();
35
         tabs.clear();
35
         tabs.clear();
36
         Activity activity = newActivity();
36
         Activity activity = newActivity();
37
-        createTabs(activity);
37
+        tabControllers = createTabs(activity);
38
         options = new Options();
38
         options = new Options();
39
         topTabsLayout = spy(new TopTabsLayout(activity, tabControllers, new TopTabsAdapter(tabControllers)));
39
         topTabsLayout = spy(new TopTabsLayout(activity, tabControllers, new TopTabsAdapter(tabControllers)));
40
 
40
 
43
         uut = new TopTabsController(activity, "componentId", tabControllers, layoutCreator, options);
43
         uut = new TopTabsController(activity, "componentId", tabControllers, layoutCreator, options);
44
     }
44
     }
45
 
45
 
46
-    private void createTabs(Activity activity) {
46
+    private List<ViewController> createTabs(Activity activity) {
47
+        List<ViewController> result = new ArrayList<>(SIZE);
48
+        tabOptions = new ArrayList<>();
47
         for (int i = 0; i < SIZE; i++) {
49
         for (int i = 0; i < SIZE; i++) {
48
             TopTabLayoutMock reactView = spy(new TopTabLayoutMock(activity));
50
             TopTabLayoutMock reactView = spy(new TopTabLayoutMock(activity));
49
             tabs.add(reactView);
51
             tabs.add(reactView);
50
-            tabOptions.add(new Options());
51
-            tabControllers.add(spy(new TopTabController(activity,
52
+            Options options = new Options();
53
+            options.topTabOptions.title = new Text("Tab " + i);
54
+            tabOptions.add(options);
55
+            result.add(spy(new TopTabController(activity,
52
                     "idTab" + i,
56
                     "idTab" + i,
53
                     "tab" + i,
57
                     "tab" + i,
54
                     (activity1, componentId, componentName) -> reactView,
58
                     (activity1, componentId, componentName) -> reactView,
55
-                    tabOptions.get(i))
59
+                    options)
56
             ));
60
             ));
57
         }
61
         }
62
+        return result;
58
     }
63
     }
59
 
64
 
60
     @Test
65
     @Test

+ 2
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ViewControllerTest.java 查看文件

6
 import android.widget.LinearLayout;
6
 import android.widget.LinearLayout;
7
 
7
 
8
 import com.reactnativenavigation.BaseTest;
8
 import com.reactnativenavigation.BaseTest;
9
+import com.reactnativenavigation.mocks.MockPromise;
9
 import com.reactnativenavigation.mocks.SimpleViewController;
10
 import com.reactnativenavigation.mocks.SimpleViewController;
10
 
11
 
11
 import org.assertj.android.api.Assertions;
12
 import org.assertj.android.api.Assertions;
58
     public void holdsAReferenceToStackControllerOrNull() throws Exception {
59
     public void holdsAReferenceToStackControllerOrNull() throws Exception {
59
         assertThat(uut.getParentStackController()).isNull();
60
         assertThat(uut.getParentStackController()).isNull();
60
         StackController nav = new StackController(activity, "stack");
61
         StackController nav = new StackController(activity, "stack");
61
-        nav.push(uut);
62
+        nav.animatePush(uut, new MockPromise());
62
         assertThat(uut.getParentStackController()).isEqualTo(nav);
63
         assertThat(uut.getParentStackController()).isEqualTo(nav);
63
     }
64
     }
64
 
65
 

+ 1
- 1
lib/android/app/src/test/java/com/reactnativenavigation/views/TopBarTest.java 查看文件

9
 public class TopBarTest extends BaseTest {
9
 public class TopBarTest extends BaseTest {
10
     @Test
10
     @Test
11
     public void title() throws Exception {
11
     public void title() throws Exception {
12
-        TopBar topBar = new TopBar(newActivity(), null, null);
12
+        TopBar topBar = new TopBar(newActivity(), buttonId -> {});
13
         assertThat(topBar.getTitle()).isEmpty();
13
         assertThat(topBar.getTitle()).isEmpty();
14
 
14
 
15
         topBar.setTitle("new title");
15
         topBar.setTitle("new title");

+ 6
- 0
lib/ios/RNNBridgeModule.m 查看文件

30
 	}];
30
 	}];
31
 }
31
 }
32
 
32
 
33
+RCT_EXPORT_METHOD(setDefaultOptions:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
34
+	[_commandsHandler setDefaultOptions:options completion:^{
35
+		resolve(nil);
36
+	}];
37
+}
38
+
33
 RCT_EXPORT_METHOD(push:(NSString*)componentId layout:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
39
 RCT_EXPORT_METHOD(push:(NSString*)componentId layout:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
34
 	[_commandsHandler push:componentId layout:layout completion:^{
40
 	[_commandsHandler push:componentId layout:layout completion:^{
35
 		resolve(componentId);
41
 		resolve(componentId);

+ 2
- 0
lib/ios/RNNCommandsHandler.h 查看文件

12
 
12
 
13
 -(void) setOptions:(NSString*)componentId options:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion;
13
 -(void) setOptions:(NSString*)componentId options:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion;
14
 
14
 
15
+-(void) setDefaultOptions:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion;
16
+
15
 -(void) push:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion;
17
 -(void) push:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion;
16
 
18
 
17
 -(void) pop:(NSString*)componentId options:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion;
19
 -(void) pop:(NSString*)componentId options:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion;

+ 6
- 0
lib/ios/RNNCommandsHandler.m 查看文件

51
 	}
51
 	}
52
 }
52
 }
53
 
53
 
54
+-(void) setDefaultOptions:(NSDictionary*)optionsDict completion:(RNNTransitionCompletionBlock)completion {
55
+	[self assertReady];
56
+	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:optionsDict];
57
+	[_controllerFactory setDefaultOptions:options];
58
+}
59
+
54
 -(void) push:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion {
60
 -(void) push:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion {
55
 	[self assertReady];
61
 	[self assertReady];
56
 	
62
 	

+ 2
- 0
lib/ios/RNNControllerFactory.h 查看文件

15
 
15
 
16
 -(UIViewController<RNNRootViewProtocol> *)createLayoutAndSaveToStore:(NSDictionary*)layout;
16
 -(UIViewController<RNNRootViewProtocol> *)createLayoutAndSaveToStore:(NSDictionary*)layout;
17
 
17
 
18
+@property (nonatomic, strong) RNNNavigationOptions* defaultOptions;
19
+
18
 @end
20
 @end

+ 1
- 0
lib/ios/RNNControllerFactory.m 查看文件

89
 	NSDictionary* customTransition = node.data[@"customTransition"];
89
 	NSDictionary* customTransition = node.data[@"customTransition"];
90
 	RNNAnimator* animator = [[RNNAnimator alloc] initWithAnimationsDictionary:customTransition];
90
 	RNNAnimator* animator = [[RNNAnimator alloc] initWithAnimationsDictionary:customTransition];
91
 	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"options"]];
91
 	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"options"]];
92
+	options.defaultOptions = _defaultOptions;
92
 	NSString* componentId = node.nodeId;
93
 	NSString* componentId = node.nodeId;
93
 	RNNRootViewController* component = [[RNNRootViewController alloc] initWithName:name withOptions:options withComponentId:componentId rootViewCreator:_creator eventEmitter:_eventEmitter animator:animator];
94
 	RNNRootViewController* component = [[RNNRootViewController alloc] initWithName:name withOptions:options withComponentId:componentId rootViewCreator:_creator eventEmitter:_eventEmitter animator:animator];
94
 	CGSize availableSize = UIApplication.sharedApplication.delegate.window.bounds.size;
95
 	CGSize availableSize = UIApplication.sharedApplication.delegate.window.bounds.size;

+ 2
- 0
lib/ios/RNNNavigationOptions.h 查看文件

19
 @property (nonatomic, strong) RNNTopTabOptions* topTab;
19
 @property (nonatomic, strong) RNNTopTabOptions* topTab;
20
 @property (nonatomic, strong) RNNSideMenuOptions* sideMenu;
20
 @property (nonatomic, strong) RNNSideMenuOptions* sideMenu;
21
 
21
 
22
+@property (nonatomic, strong) RNNNavigationOptions* defaultOptions;
23
+
22
 @property (nonatomic, strong) NSNumber* statusBarHidden;
24
 @property (nonatomic, strong) NSNumber* statusBarHidden;
23
 @property (nonatomic, strong) NSNumber* screenBackgroundColor;
25
 @property (nonatomic, strong) NSNumber* screenBackgroundColor;
24
 @property (nonatomic, strong) NSMutableDictionary* originalTopBarImages;
26
 @property (nonatomic, strong) NSMutableDictionary* originalTopBarImages;

+ 6
- 1
lib/ios/RNNNavigationOptions.m 查看文件

46
 }
46
 }
47
 
47
 
48
 -(void)applyOn:(UIViewController*)viewController {
48
 -(void)applyOn:(UIViewController*)viewController {
49
+	[_defaultOptions applyOn:viewController];
50
+	
49
 	[self.topBar applyOn:viewController];
51
 	[self.topBar applyOn:viewController];
50
 	[self.bottomTabs applyOn:viewController];
52
 	[self.bottomTabs applyOn:viewController];
51
 	[self.topTab applyOn:viewController];
53
 	[self.topTab applyOn:viewController];
52
 	[self.bottomTab applyOn:viewController];
54
 	[self.bottomTab applyOn:viewController];
53
 	[self.sideMenu applyOn:viewController];
55
 	[self.sideMenu applyOn:viewController];
54
-	
56
+	[self applyOtherOptionsOn:viewController];
57
+}
58
+
59
+- (void)applyOtherOptionsOn:(UIViewController*)viewController {
55
 	if (self.popGesture) {
60
 	if (self.popGesture) {
56
 		viewController.navigationController.interactivePopGestureRecognizer.enabled = [self.popGesture boolValue];
61
 		viewController.navigationController.interactivePopGestureRecognizer.enabled = [self.popGesture boolValue];
57
 	}
62
 	}

+ 8
- 4
lib/ios/RNNOptions.h 查看文件

1
 #import <Foundation/Foundation.h>
1
 #import <Foundation/Foundation.h>
2
 #import <UIKit/UIKit.h>
2
 #import <UIKit/UIKit.h>
3
 #import <React/RCTConvert.h>
3
 #import <React/RCTConvert.h>
4
+
5
+@class RNNOptions;
6
+
4
 @protocol RNNOptionsProtocol <NSObject>
7
 @protocol RNNOptionsProtocol <NSObject>
5
 
8
 
6
 @optional
9
 @optional
7
--(void)resetOptions;
8
--(void)applyOn:(UIViewController*)viewController;
10
+- (void)resetOptions;
11
+- (void)applyOn:(UIViewController *)viewController;
9
 
12
 
10
 @end
13
 @end
11
 
14
 
12
 @interface RNNOptions : NSObject <RNNOptionsProtocol>
15
 @interface RNNOptions : NSObject <RNNOptionsProtocol>
13
 
16
 
14
--(instancetype)initWithDict:(NSDictionary*)dict;
15
--(void)mergeWith:(NSDictionary*)otherOptions;
17
+- (instancetype)initWithDict:(NSDictionary*)dict;
18
+- (void)mergeWith:(NSDictionary*)otherOptions;
19
+- (void)applyOn:(UIViewController *)viewController defaultOptions:(RNNOptions*)defaultOptions;
16
 
20
 
17
 @end
21
 @end

+ 5
- 0
lib/ios/RNNOptions.m 查看文件

9
 	return self;
9
 	return self;
10
 }
10
 }
11
 
11
 
12
+- (void)applyOn:(UIViewController *)viewController defaultOptions:(RNNOptions *)defaultOptions {
13
+	[defaultOptions applyOn:viewController];
14
+	[self applyOn:viewController];
15
+}
16
+
12
 -(void)mergeWith:(NSDictionary *)otherOptions {
17
 -(void)mergeWith:(NSDictionary *)otherOptions {
13
 	for (id key in otherOptions) {
18
 	for (id key in otherOptions) {
14
 		[self setValue:[otherOptions objectForKey:key] forKey:key];
19
 		[self setValue:[otherOptions objectForKey:key] forKey:key];

+ 19
- 2
playground/src/screens/OptionsScreen.js 查看文件

48
     this.onClickTopBarTransparent = this.onClickTopBarTransparent.bind(this);
48
     this.onClickTopBarTransparent = this.onClickTopBarTransparent.bind(this);
49
     this.onClickTopBarOpaque = this.onClickTopBarOpaque.bind(this);
49
     this.onClickTopBarOpaque = this.onClickTopBarOpaque.bind(this);
50
     this.onClickCustomTranstition = this.onClickCustomTranstition.bind(this);
50
     this.onClickCustomTranstition = this.onClickCustomTranstition.bind(this);
51
+    this.onClickPushDefaultOptionsScreen = this.onClickPushDefaultOptionsScreen.bind(this);
51
   }
52
   }
52
 
53
 
53
   render() {
54
   render() {
63
         <Button title="Custom Transition" onPress={this.onClickCustomTranstition} />
64
         <Button title="Custom Transition" onPress={this.onClickCustomTranstition} />
64
         <Button title="Show custom alert" testID={testIDs.SHOW_CUSTOM_ALERT_BUTTON} onPress={this.onClickAlert} />
65
         <Button title="Show custom alert" testID={testIDs.SHOW_CUSTOM_ALERT_BUTTON} onPress={this.onClickAlert} />
65
         <Button title="Show snackbar" testID={testIDs.SHOW_SNACKBAR_BUTTON} onPress={this.onClickSnackbar} />
66
         <Button title="Show snackbar" testID={testIDs.SHOW_SNACKBAR_BUTTON} onPress={this.onClickSnackbar} />
66
-        <Text style={styles.footer}>{`this.props.componentId = ${this.props.componentId}`}</Text>
67
+        <Button title="Push Default Options Screen" testID={testIDs.PUSH_DEFAULT_OPTIONS_BUTTON} onPress={this.onClickPushDefaultOptionsScreen} />
68
+        <Text style={styles.footer}>{`this.props.containerId = ${this.props.containerId}`}</Text>
67
       </View>
69
       </View>
68
     );
70
     );
69
   }
71
   }
187
       }
189
       }
188
     });
190
     });
189
   }
191
   }
192
+
193
+  onClickPushDefaultOptionsScreen() {
194
+    Navigation.setDefaultOptions({
195
+      topBar: {
196
+        hidden: true
197
+      }
198
+    });
199
+
200
+    Navigation.push(this.props.componentId, {
201
+      component: {
202
+        name: 'navigation.playground.PushedScreen'
203
+      }
204
+    });
205
+  }
190
 }
206
 }
191
 
207
 
192
 const styles = {
208
 const styles = {
193
   root: {
209
   root: {
194
     flexGrow: 1,
210
     flexGrow: 1,
195
     justifyContent: 'center',
211
     justifyContent: 'center',
196
-    alignItems: 'center'
212
+    alignItems: 'center',
213
+    backgroundColor: 'white'
197
   },
214
   },
198
   h1: {
215
   h1: {
199
     fontSize: 24,
216
     fontSize: 24,

+ 13
- 0
playground/src/screens/PushedScreen.js 查看文件

9
 const testIDs = require('../testIDs');
9
 const testIDs = require('../testIDs');
10
 
10
 
11
 class PushedScreen extends Component {
11
 class PushedScreen extends Component {
12
+  static get options() {
13
+    return {
14
+      topBar: {
15
+        testID: testIDs.TOP_BAR_ELEMENT
16
+      }
17
+    };
18
+  }
19
+
12
   constructor(props) {
20
   constructor(props) {
13
     super(props);
21
     super(props);
14
     this.onClickPush = this.onClickPush.bind(this);
22
     this.onClickPush = this.onClickPush.bind(this);
41
         passProps: {
49
         passProps: {
42
           stackPosition: this.getStackPosition() + 1,
50
           stackPosition: this.getStackPosition() + 1,
43
           previousScreenIds: _.concat([], this.props.previousScreenIds || [], this.props.componentId)
51
           previousScreenIds: _.concat([], this.props.previousScreenIds || [], this.props.componentId)
52
+        },
53
+        options: {
54
+          topBar: {
55
+            title: `Pushed ${this.getStackPosition() + 1}`
56
+          }
44
         }
57
         }
45
       }
58
       }
46
     });
59
     });

+ 47
- 34
playground/src/screens/WelcomeScreen.js 查看文件

168
   async onClickPush() {
168
   async onClickPush() {
169
     await Navigation.push(this.props.componentId, {
169
     await Navigation.push(this.props.componentId, {
170
       component: {
170
       component: {
171
-        name: 'navigation.playground.PushedScreen'
171
+        name: 'navigation.playground.PushedScreen',
172
+        options: {
173
+          topBar: {
174
+            title: 'pushed'
175
+          }
176
+        }
172
       }
177
       }
173
     });
178
     });
174
   }
179
   }
209
 
214
 
210
   onClickPushTopTabsScreen() {
215
   onClickPushTopTabsScreen() {
211
     Navigation.push(this.props.componentId, {
216
     Navigation.push(this.props.componentId, {
212
-      topTabs: [
213
-        {
214
-          name: 'navigation.playground.TopTabOptionsScreen',
215
-          passProps: {
216
-            title: 'Tab 1',
217
-            text: 'This is top tab 1'
218
-          },
219
-          options: {
220
-            topTab: {
221
-              title: 'Tab 1'
217
+      topTabs: {
218
+        children: [
219
+          {
220
+            component: {
221
+              name: 'navigation.playground.TopTabOptionsScreen',
222
+              passProps: {
223
+                title: 'Tab 1',
224
+                text: 'This is top tab 1'
225
+              },
226
+              options: {
227
+                topTab: {
228
+                  title: 'Tab 1'
229
+                }
230
+              }
222
             }
231
             }
223
-          }
224
-        },
225
-        {
226
-          name: 'navigation.playground.TopTabScreen',
227
-          passProps: {
228
-            title: 'Tab 2',
229
-            text: 'This is top tab 2'
230
           },
232
           },
231
-          options: {
232
-            topTab: {
233
-              title: 'Tab 2',
234
-              titleFontFamily: 'HelveticaNeue-Italic'
233
+          {
234
+            component: {
235
+              name: 'navigation.playground.TopTabScreen',
236
+              passProps: {
237
+                title: 'Tab 2',
238
+                text: 'This is top tab 2'
239
+              },
240
+              options: {
241
+                topTab: {
242
+                  title: 'Tab 2',
243
+                  titleFontFamily: 'HelveticaNeue-Italic'
244
+                }
245
+              }
235
             }
246
             }
236
-          }
237
-        },
238
-        {
239
-          name: 'navigation.playground.TopTabScreen',
240
-          passProps: {
241
-            title: 'Tab 3',
242
-            text: 'This is top tab 3'
243
           },
247
           },
244
-          options: {
245
-            topTab: {
246
-              title: 'Tab 3'
248
+          {
249
+            component: {
250
+              name: 'navigation.playground.TopTabScreen',
251
+              passProps: {
252
+                title: 'Tab 3',
253
+                text: 'This is top tab 3'
254
+              },
255
+              options: {
256
+                topTab: {
257
+                  title: 'Tab 3'
258
+                }
259
+              }
247
             }
260
             }
248
           }
261
           }
249
-        }
250
-      ],
262
+        ]
263
+      },
251
       options: {
264
       options: {
252
         topTabs: {
265
         topTabs: {
253
           selectedTabColor: '#12766b',
266
           selectedTabColor: '#12766b',

+ 1
- 0
playground/src/testIDs.js 查看文件

7
   PUSH_LIFECYCLE_BUTTON: `PUSH_LIFECYCLE_BUTTON`,
7
   PUSH_LIFECYCLE_BUTTON: `PUSH_LIFECYCLE_BUTTON`,
8
   PUSH_BUTTON: `PUSH_BUTTON`,
8
   PUSH_BUTTON: `PUSH_BUTTON`,
9
   PUSH_OPTIONS_BUTTON: `PUSH_OPTIONS_BUTTON`,
9
   PUSH_OPTIONS_BUTTON: `PUSH_OPTIONS_BUTTON`,
10
+  PUSH_DEFAULT_OPTIONS_BUTTON: `PUSH_DEFAULT_OPTIONS_BUTTON`,
10
   BACK_HANDLER_BUTTON: `BACK_HANDLER_BUTTON`,
11
   BACK_HANDLER_BUTTON: `BACK_HANDLER_BUTTON`,
11
   SHOW_MODAL_BUTTON: `SHOW_MODAL_BUTTON`,
12
   SHOW_MODAL_BUTTON: `SHOW_MODAL_BUTTON`,
12
   SHOW_REDBOX_BUTTON: `SHOW_REDBOX_BUTTON`,
13
   SHOW_REDBOX_BUTTON: `SHOW_REDBOX_BUTTON`,