Selaa lähdekoodia

Merge branch 'v2' into typescript

Daniel Zlotin 7 vuotta sitten
vanhempi
commit
3604271f61
100 muutettua tiedostoa jossa 1560 lisäystä ja 1125 poistoa
  1. 14
    16
      AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/OverlayTest.java
  2. 9
    0
      AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/ScreenStackTest.java
  3. 17
    0
      AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/StaticLifecycleEvents.java
  4. 4
    4
      README.md
  5. 34
    0
      e2e/ScreenStack.test.js
  6. 18
    1
      lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java
  7. 3
    2
      lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarCollapseBehavior.java
  8. 0
    46
      lib/android/app/src/main/java/com/reactnativenavigation/parse/ButtonOptions.java
  9. 8
    5
      lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java
  10. 2
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/Options.java
  11. 7
    78
      lib/android/app/src/main/java/com/reactnativenavigation/parse/OverlayOptions.java
  12. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java
  13. 22
    0
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OverlayManager.java
  14. 0
    27
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OverlayPresenter.java
  15. 17
    7
      lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationEvent.java
  16. 8
    6
      lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java
  17. 6
    0
      lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationReactNativeHost.java
  18. 3
    3
      lib/android/app/src/main/java/com/reactnativenavigation/react/ReactComponentViewCreator.java
  19. 9
    3
      lib/android/app/src/main/java/com/reactnativenavigation/react/ReactGateway.java
  20. 14
    5
      lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java
  21. 13
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/DeviceScreen.java
  22. 35
    9
      lib/android/app/src/main/java/com/reactnativenavigation/utils/UiUtils.java
  23. 17
    52
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java
  24. 5
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Destroyable.java
  25. 23
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/IReactView.java
  26. 11
    14
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java
  27. 5
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java
  28. 8
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ReactViewCreator.java
  29. 22
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java
  30. 116
    87
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java
  31. 15
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewVisibilityListenerAdapter.java
  32. 0
    55
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/AlertOverlay.java
  33. 0
    27
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/DialogViewController.java
  34. 0
    35
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/OverlayFactory.java
  35. 0
    88
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/SnackbarOverlay.java
  36. 0
    80
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabController.java
  37. 23
    10
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java
  38. 0
    44
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsViewPager.java
  39. 19
    5
      lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentLayout.java
  40. 5
    4
      lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentViewCreator.java
  41. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/views/ReactComponent.java
  42. 5
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/StackLayout.java
  43. 6
    4
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java
  44. 0
    56
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopTab.java
  45. 0
    23
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabCreator.java
  46. 0
    73
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsLayout.java
  47. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsLayoutCreator.java
  48. 83
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsViewPager.java
  49. 54
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/touch/OverlayTouchDelegate.java
  50. 2
    2
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleComponentViewController.java
  51. 59
    0
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleOverlay.java
  52. 77
    6
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleViewController.java
  53. 15
    23
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestComponentLayout.java
  54. 10
    5
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestComponentViewCreator.java
  55. 57
    0
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestReactView.java
  56. 24
    2
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TopTabLayoutMock.java
  57. 0
    47
      lib/android/app/src/test/java/com/reactnativenavigation/parse/OverlayOptionsTest.java
  58. 5
    4
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ComponentViewControllerTest.java
  59. 1
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java
  60. 13
    4
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java
  61. 10
    0
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java
  62. 3
    3
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java
  63. 0
    51
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabControllerTest.java
  64. 101
    52
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java
  65. 5
    4
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ViewControllerTest.java
  66. 57
    0
      lib/android/app/src/test/java/com/reactnativenavigation/views/TouchDelegateTest.java
  67. 0
    6
      lib/ios/RNNBottomTabOptions.m
  68. 8
    0
      lib/ios/RNNBottomTabsOptions.h
  69. 51
    5
      lib/ios/RNNBottomTabsOptions.m
  70. 12
    0
      lib/ios/RNNBridgeModule.m
  71. 4
    0
      lib/ios/RNNCommandsHandler.h
  72. 49
    8
      lib/ios/RNNCommandsHandler.m
  73. 15
    0
      lib/ios/RNNComponentLifecycleEvent.h
  74. 24
    0
      lib/ios/RNNComponentLifecycleEvent.m
  75. 3
    0
      lib/ios/RNNControllerFactory.h
  76. 10
    2
      lib/ios/RNNControllerFactory.m
  77. 7
    0
      lib/ios/RNNEventEmitter.h
  78. 11
    1
      lib/ios/RNNEventEmitter.m
  79. 1
    1
      lib/ios/RNNModalManager.h
  80. 4
    4
      lib/ios/RNNModalManager.m
  81. 5
    0
      lib/ios/RNNNavigationButtons.m
  82. 9
    0
      lib/ios/RNNNavigationController.m
  83. 20
    0
      lib/ios/RNNNavigationEvent.h
  84. 26
    0
      lib/ios/RNNNavigationEvent.m
  85. 3
    0
      lib/ios/RNNNavigationOptions.h
  86. 4
    1
      lib/ios/RNNNavigationOptions.m
  87. 4
    4
      lib/ios/RNNNavigationStackManager.m
  88. 10
    0
      lib/ios/RNNOverlayManager.h
  89. 38
    0
      lib/ios/RNNOverlayManager.m
  90. 7
    0
      lib/ios/RNNOverlayOptions.h
  91. 13
    0
      lib/ios/RNNOverlayOptions.m
  92. 26
    10
      lib/ios/RNNRootViewController.m
  93. 3
    0
      lib/ios/RNNRootViewProtocol.h
  94. 10
    2
      lib/ios/RNNSideMenuChildVC.m
  95. 8
    0
      lib/ios/RNNSideMenuController.m
  96. 13
    0
      lib/ios/RNNSwizzles.h
  97. 49
    0
      lib/ios/RNNSwizzles.m
  98. 8
    0
      lib/ios/RNNTabBarController.m
  99. 1
    1
      lib/ios/RNNTopBarOptions.m
  100. 0
    0
      lib/ios/RNNTopTabOptions.m

+ 14
- 16
AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/OverlayTest.java Näytä tiedosto

@@ -1,20 +1,18 @@
1 1
 package com.reactnativenavigation.e2e.androide2e;
2 2
 
3
-public class OverlayTest {//extends BaseTest {
3
+import android.support.test.uiautomator.By;
4 4
 
5
-//	@Test
6
-//	public void testOverlayAlertAppear() throws Exception {
7
-//		elementByText("PUSH OPTIONS SCREEN").click();
8
-//		elementByText("SHOW CUSTOM ALERT").click();
9
-//		assertExists(By.text("Test view"));
10
-//		elementByText("OK").click();
11
-//		assertExists(By.text("Static Title"));
12
-//	}
13
-//
14
-//	@Test
15
-//	public void testSnackbarAppear() throws Exception {
16
-//		elementByText("PUSH OPTIONS SCREEN").click();
17
-//		elementByText("SHOW SNACKBAR").click();
18
-//		assertExists(By.text("Test!"));
19
-//	}
5
+import org.junit.Test;
6
+
7
+public class OverlayTest extends BaseTest {
8
+
9
+	@Test
10
+	public void testOverlayAlertAppear() throws Exception {
11
+		elementByText("PUSH OPTIONS SCREEN").click();
12
+        elementByText("SHOW OVERLAY").click();
13
+		assertExists(By.text("Test view"));
14
+		elementByText("OK").click();
15
+		assertExists(By.text("Overlay disappeared"));
16
+        elementByText("OK").click();
17
+	}
20 18
 }

+ 9
- 0
AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/ScreenStackTest.java Näytä tiedosto

@@ -45,4 +45,13 @@ public class ScreenStackTest extends BaseTest {
45 45
         elementByText("POP TO ROOT").click();
46 46
         assertMainShown();
47 47
     }
48
+
49
+    @Test
50
+    public void pushStackWithMultipleChildren() throws Exception {
51
+        elementByText("SHOW MODAL").click();
52
+        elementByText("SHOW MODAL WITH STACK").click();
53
+        assertExists(By.text("Screen 2"));
54
+        device().pressBack();
55
+        assertExists(By.text("Screen 1"));
56
+    }
48 57
 }

+ 17
- 0
AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/StaticLifecycleEvents.java Näytä tiedosto

@@ -0,0 +1,17 @@
1
+package com.reactnativenavigation.e2e.androide2e;
2
+
3
+import android.support.test.uiautomator.By;
4
+
5
+import org.junit.Test;
6
+
7
+public class StaticLifecycleEvents extends BaseTest {
8
+    @Test
9
+    public void didAppearDidDisappear() throws Exception {
10
+        elementByText("STATIC LIFECYCLE EVENTS").click();
11
+        assertExists(By.text("Static Lifecycle Events"));
12
+        assertExists(By.text("didAppear | navigation.playground.StaticLifecycleOverlay"));
13
+        elementByText("PUSH").click();
14
+        assertExists(By.text("didAppear | navigation.playground.PushedScreen"));
15
+        assertExists(By.text("didDisappear | navigation.playground.WelcomeScreen"));
16
+    }
17
+}

+ 4
- 4
README.md Näytä tiedosto

@@ -68,11 +68,11 @@ v2 is written in Test Driven Development. We have a test for every feature inclu
68 68
 | resetTo             |   ✅        |	✅|
69 69
 | showModal              |  ✅        |	✅|
70 70
 | dismissModal           |     ✅       |	✅|
71
-| showOverlay             |  [Contribute](/docs/docs/CONTRIBUTING.md)         |	✅ |
72
-| dismissOverlay             |  [Contribute](/docs/docs/CONTRIBUTING.md)         |	✅ |
71
+| showOverlay             |           |	✅ |
72
+| dismissOverlay             |     |	✅ |
73 73
 | customTransition            |   ✅        |	[Contribute](/docs/docs/CONTRIBUTING.md) |
74 74
 | Screen Visibility        | ✅     |✅|
75
-| async commands (await push)     |  [Contribute](/docs/docs/CONTRIBUTING.md)        |✅   |
75
+| async commands (await push)     |          |✅   |
76 76
 
77 77
 ### Navigation Options
78 78
 
@@ -129,7 +129,7 @@ v2 is written in Test Driven Development. We have a test for every feature inclu
129 129
 | disabledBackGesture        |    ✅     |    / iOS specific     |
130 130
 | screenBackgroundImageName        |   ✅      |    [Contribute](/docs/docs/CONTRIBUTING.md)        |
131 131
 | rootBackgroundImageName              |    ✅     |    [Contribute](/docs/docs/CONTRIBUTING.md)       |
132
-| sideMenuVisible          |        [Contribute](/docs/docs/CONTRIBUTING.md)   | [Contribute](/docs/docs/CONTRIBUTING.md) |
132
+| sideMenuVisible          |         | [Contribute](/docs/docs/CONTRIBUTING.md) |
133 133
 
134 134
 
135 135
 ## v1 vs v2 Feature Comparison

+ 34
- 0
e2e/ScreenStack.test.js Näytä tiedosto

@@ -59,4 +59,38 @@ describe('screen stack', () => {
59 59
     await elementById(testIDs.SWITCH_FIRST_TAB_BUTTON).tap();
60 60
     await expect(elementByLabel('This is tab 1')).toBeVisible();
61 61
   });
62
+
63
+  it('show and dismiss overlay', async () => {
64
+    await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
65
+    await elementById(testIDs.SHOW_OVERLAY_BUTTON).tap();
66
+    await expect(elementById(testIDs.DIALOG_HEADER)).toBeVisible();
67
+    await elementById(testIDs.OK_BUTTON).tap();
68
+    await expect(elementById(testIDs.DIALOG_HEADER)).toBeNotVisible();
69
+  });
70
+
71
+  it('overlay pass touches - true', async () => {
72
+    await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
73
+    await elementById(testIDs.SHOW_TOUCH_THROUGH_OVERLAY_BUTTON).tap();
74
+    await expect(elementById(testIDs.DIALOG_HEADER)).toBeVisible();
75
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeVisible();
76
+    await elementById(testIDs.HIDE_TOP_BAR_BUTTON).tap();
77
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeNotVisible();
78
+  });
79
+
80
+  it('overlay pass touches - false', async () => {
81
+    await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
82
+    await elementById(testIDs.SHOW_OVERLAY_BUTTON).tap();
83
+    await expect(elementById(testIDs.DIALOG_HEADER)).toBeVisible();
84
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeVisible();
85
+    await elementById(testIDs.HIDE_TOP_BAR_BUTTON).tap();
86
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeVisible();
87
+  });
88
+
89
+  it('push stack with multiple children', async () => {
90
+    await elementById(testIDs.SHOW_MODAL_BUTTON).tap();
91
+    await elementById(testIDs.MODAL_WITH_STACK_BUTTON).tap();
92
+    await expect(elementByLabel('Screen 2')).toBeVisible();
93
+    await Utils.tapBackIos();
94
+    await expect(elementByLabel('Screen 1')).toBeVisible();
95
+  });
62 96
 });

+ 18
- 1
lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java Näytä tiedosto

@@ -19,9 +19,22 @@ public abstract class NavigationApplication extends Application implements React
19 19
 	public void onCreate() {
20 20
 		super.onCreate();
21 21
         instance = this;
22
-        reactGateway = new ReactGateway(this, isDebug(), createAdditionalReactPackages());
22
+        reactGateway = createReactGateway();
23 23
 	}
24 24
 
25
+    /**
26
+     * Subclasses of NavigationApplication may override this method to create the singleton instance
27
+     * of {@link ReactGateway}. For example, subclasses may wish to provide a custom {@link ReactNativeHost}
28
+     * with the ReactGateway. This method will be called exactly once, in the application's {@link #onCreate()} method.
29
+     *
30
+     * Custom {@link ReactNativeHost}s must be sure to include {@link com.reactnativenavigation.react.NavigationPackage}
31
+     *
32
+     * @return a singleton {@link ReactGateway}
33
+     */
34
+	protected ReactGateway createReactGateway() {
35
+	    return new ReactGateway(this, isDebug(), createAdditionalReactPackages());
36
+    }
37
+
25 38
 	public ReactGateway getReactGateway() {
26 39
 		return reactGateway;
27 40
 	}
@@ -33,6 +46,10 @@ public abstract class NavigationApplication extends Application implements React
33 46
 
34 47
 	public abstract boolean isDebug();
35 48
 
49
+    /**
50
+     * Create a list of additional {@link ReactPackage}s to include. This method will only be called by
51
+     * the default implementation of {@link #createReactGateway()}
52
+     */
36 53
 	@Nullable
37 54
 	public abstract List<ReactPackage> createAdditionalReactPackages();
38 55
 }

+ 3
- 2
lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarCollapseBehavior.java Näytä tiedosto

@@ -16,8 +16,9 @@ public class TopBarCollapseBehavior implements ScrollEventListener.OnScrollListe
16 16
         this.animator = new TopBarAnimator(topBar);
17 17
     }
18 18
 
19
-    public void enableCollapse() {
20
-        scrollEventListener.register(topBar, this, this);
19
+    public void enableCollapse(ScrollEventListener scrollEventListener) {
20
+        this.scrollEventListener = scrollEventListener;
21
+        this.scrollEventListener.register(topBar, this, this);
21 22
     }
22 23
 
23 24
     public void disableCollapse() {

+ 0
- 46
lib/android/app/src/main/java/com/reactnativenavigation/parse/ButtonOptions.java Näytä tiedosto

@@ -1,46 +0,0 @@
1
-package com.reactnativenavigation.parse;
2
-
3
-
4
-import android.support.annotation.ColorInt;
5
-
6
-import org.json.JSONObject;
7
-
8
-import static com.reactnativenavigation.parse.OverlayOptions.NO_COLOR;
9
-
10
-public class ButtonOptions {
11
-
12
-	public static ButtonOptions parse(JSONObject json) {
13
-		ButtonOptions options = new ButtonOptions();
14
-		if (json == null) return new ButtonOptions();
15
-
16
-		//TODO: parse
17
-		options.text = json.optString("text");
18
-		options.action = json.optString("action");
19
-		options.visible = json.optBoolean("visible", true);
20
-		options.textColor = json.optInt("textColor", NO_COLOR);
21
-
22
-		return options;
23
-	}
24
-
25
-	private String text = "";
26
-	private String action;
27
-	private boolean visible = false;
28
-	@ColorInt
29
-	private int textColor;
30
-
31
-	public String getText() {
32
-		return text;
33
-	}
34
-
35
-	public String getAction() {
36
-		return action;
37
-	}
38
-
39
-	public boolean isVisible() {
40
-		return visible;
41
-	}
42
-
43
-	public int getTextColor() {
44
-		return textColor;
45
-	}
46
-}

+ 8
- 5
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java Näytä tiedosto

@@ -10,7 +10,6 @@ import com.reactnativenavigation.viewcontrollers.ComponentViewController;
10 10
 import com.reactnativenavigation.viewcontrollers.SideMenuController;
11 11
 import com.reactnativenavigation.viewcontrollers.StackController;
12 12
 import com.reactnativenavigation.viewcontrollers.ViewController;
13
-import com.reactnativenavigation.viewcontrollers.toptabs.TopTabController;
14 13
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsController;
15 14
 import com.reactnativenavigation.views.ComponentViewCreator;
16 15
 import com.reactnativenavigation.views.TopTabsLayoutCreator;
@@ -91,7 +90,7 @@ public class LayoutFactory {
91 90
 	private ViewController createComponent(LayoutNode node) {
92 91
 		String id = node.id;
93 92
 		String name = node.data.optString("name");
94
-		Options options = Options.parse(typefaceManager, node.data.optJSONObject("options"), defaultOptions);
93
+		Options options = Options.parse(typefaceManager, node.getNavigationOptions(), defaultOptions);
95 94
 		return new ComponentViewController(activity,
96 95
                 id,
97 96
                 name,
@@ -102,9 +101,13 @@ public class LayoutFactory {
102 101
 
103 102
 	private ViewController createStack(LayoutNode node) {
104 103
 		StackController stackController = new StackController(activity, node.id);
105
-		for (LayoutNode child : node.children) {
106
-			stackController.animatePush(create(child), new NoOpPromise());
107
-		}
104
+        for (int i = 0; i < node.children.size(); i++) {
105
+            if (i < node.children.size() - 1) {
106
+                stackController.push(create(node.children.get(i)), new NoOpPromise());
107
+            } else {
108
+                stackController.animatePush(create(node.children.get(i)), new NoOpPromise());
109
+            }
110
+        }
108 111
 		return stackController;
109 112
 	}
110 113
 

+ 2
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/Options.java Näytä tiedosto

@@ -36,6 +36,7 @@ public class Options implements DEFAULT_VALUES {
36 36
 		result.topTabsOptions = TopTabsOptions.parse(json.optJSONObject("topTabs"));
37 37
         result.topTabOptions = TopTabOptions.parse(typefaceManager, json.optJSONObject("topTab"));
38 38
 		result.bottomTabsOptions = BottomTabsOptions.parse(json.optJSONObject("bottomTabs"));
39
+        result.overlayOptions = OverlayOptions.parse(json.optJSONObject("overlay"));
39 40
 
40 41
 		return result.withDefaultOptions(defaultOptions);
41 42
 	}
@@ -44,6 +45,7 @@ public class Options implements DEFAULT_VALUES {
44 45
     @NonNull public TopTabsOptions topTabsOptions = new TopTabsOptions();
45 46
     @NonNull public TopTabOptions topTabOptions = new TopTabOptions();
46 47
     @NonNull public BottomTabsOptions bottomTabsOptions = new BottomTabsOptions();
48
+    @NonNull public OverlayOptions overlayOptions = new OverlayOptions();
47 49
 
48 50
     void setTopTabIndex(int i) {
49 51
         topTabOptions.tabIndex = i;

+ 7
- 78
lib/android/app/src/main/java/com/reactnativenavigation/parse/OverlayOptions.java Näytä tiedosto

@@ -1,86 +1,15 @@
1 1
 package com.reactnativenavigation.parse;
2 2
 
3
-
4
-import android.support.annotation.ColorInt;
5
-
6
-import com.reactnativenavigation.viewcontrollers.ViewController;
7
-
8 3
 import org.json.JSONObject;
9 4
 
10 5
 public class OverlayOptions {
6
+    public Options.BooleanOptions interceptTouchOutside = Options.BooleanOptions.False;
11 7
 
12
-	public static final int NO_COLOR = -1;
13
-
14
-	public static OverlayOptions parse(JSONObject json) {
15
-		OverlayOptions options = new OverlayOptions();
16
-		if (json == null) return options;
17
-
18
-		options.title = json.optString("title");
19
-		options.text = json.optString("text");
20
-		options.positiveButton = ButtonOptions.parse(json.optJSONObject("positiveButton"));
21
-		options.negativeButton = ButtonOptions.parse(json.optJSONObject("negativeButton"));
22
-		options.button = ButtonOptions.parse(json.optJSONObject("button"));
23
-		options.textColor = json.optInt("textColor", NO_COLOR);
24
-		options.duration = json.optString("duration");
25
-		options.backgroundColor = json.optInt("backgroundColor", NO_COLOR);
26
-
27
-		return options;
28
-	}
29
-
30
-	public static OverlayOptions create(ViewController componentView) {
31
-		OverlayOptions options = new OverlayOptions();
32
-		if (componentView == null) return options;
33
-
34
-		options.customView = componentView;
35
-		return options;
36
-	}
37
-
38
-	private String title = "";
39
-	private String text = "";
40
-	private ButtonOptions positiveButton;
41
-	private ButtonOptions negativeButton;
42
-	private ButtonOptions button;
43
-	@ColorInt
44
-	private int textColor;
45
-	private String duration;
46
-	@ColorInt
47
-	private int backgroundColor;
48
-
49
-	private ViewController customView;
50
-
51
-	public String getText() {
52
-		return text;
53
-	}
54
-
55
-	public String getTitle() {
56
-		return title;
57
-	}
58
-
59
-	public ButtonOptions getPositiveButton() {
60
-		return positiveButton;
61
-	}
62
-
63
-	public ButtonOptions getNegativeButton() {
64
-		return negativeButton;
65
-	}
66
-
67
-	public ViewController getCustomView() {
68
-		return customView;
69
-	}
70
-
71
-	public ButtonOptions getButton() {
72
-		return button;
73
-	}
74
-
75
-	public int getTextColor() {
76
-		return textColor;
77
-	}
78
-
79
-	public String getDuration() {
80
-		return duration;
81
-	}
8
+    public static OverlayOptions parse(JSONObject json) {
9
+        OverlayOptions options = new OverlayOptions();
10
+        if (json == null) return options;
82 11
 
83
-	public int getBackgroundColor() {
84
-		return backgroundColor;
85
-	}
12
+        options.interceptTouchOutside = Options.BooleanOptions.parse(json.optString("interceptTouchOutside", ""));
13
+        return options;
14
+    }
86 15
 }

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java Näytä tiedosto

@@ -49,7 +49,7 @@ public class OptionsPresenter {
49 49
         }
50 50
 
51 51
         if (options.hideOnScroll == True) {
52
-            topBar.enableCollapse();
52
+            topBar.enableCollapse(component.getScrollEventListener());
53 53
         } else if (options.hideOnScroll == False) {
54 54
             topBar.disableCollapse();
55 55
         }

+ 22
- 0
lib/android/app/src/main/java/com/reactnativenavigation/presentation/OverlayManager.java Näytä tiedosto

@@ -0,0 +1,22 @@
1
+package com.reactnativenavigation.presentation;
2
+
3
+import android.view.View;
4
+import android.view.ViewGroup;
5
+
6
+import com.reactnativenavigation.viewcontrollers.ViewController;
7
+
8
+import java.util.HashMap;
9
+
10
+public class OverlayManager {
11
+    private final HashMap<String, Integer> overlayRegistry = new HashMap<>();
12
+
13
+    public void show(ViewGroup root, ViewController overlay) {
14
+        View view = overlay.getView();
15
+        overlayRegistry.put(overlay.getId(), view.getId());
16
+        root.addView(view);
17
+    }
18
+
19
+    public void dismiss(ViewGroup root, String componentId) {
20
+        root.removeView(root.findViewById(overlayRegistry.get(componentId)));
21
+    }
22
+}

+ 0
- 27
lib/android/app/src/main/java/com/reactnativenavigation/presentation/OverlayPresenter.java Näytä tiedosto

@@ -1,27 +0,0 @@
1
-package com.reactnativenavigation.presentation;
2
-
3
-
4
-import android.content.Context;
5
-
6
-import com.reactnativenavigation.parse.OverlayOptions;
7
-import com.reactnativenavigation.viewcontrollers.ViewController;
8
-import com.reactnativenavigation.viewcontrollers.overlay.OverlayFactory;
9
-import com.reactnativenavigation.viewcontrollers.overlay.OverlayInterface;
10
-
11
-public class OverlayPresenter {
12
-
13
-	private OverlayInterface overlay;
14
-
15
-	public OverlayPresenter(ViewController viewController, String type, OverlayOptions options) {
16
-		this.overlay = OverlayFactory.create(type, viewController, options);
17
-	}
18
-
19
-
20
-	public void show() {
21
-		overlay.show();
22
-	}
23
-
24
-	public void dismiss() {
25
-		overlay.dismiss();
26
-	}
27
-}

+ 17
- 7
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationEvent.java Näytä tiedosto

@@ -1,14 +1,12 @@
1 1
 package com.reactnativenavigation.react;
2 2
 
3
+import android.support.annotation.NonNull;
4
+
3 5
 import com.facebook.react.bridge.Arguments;
4 6
 import com.facebook.react.bridge.ReactContext;
5 7
 import com.facebook.react.bridge.WritableMap;
6
-import com.facebook.react.bridge.WritableNativeArray;
7 8
 import com.facebook.react.modules.core.DeviceEventManagerModule;
8 9
 
9
-import org.json.JSONException;
10
-import org.json.JSONObject;
11
-
12 10
 import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
13 11
 
14 12
 public class NavigationEvent {
@@ -16,6 +14,7 @@ public class NavigationEvent {
16 14
 	private static final String componentDidAppear = "RNN.componentDidAppear";
17 15
 	private static final String componentDidDisappear = "RNN.componentDidDisappear";
18 16
 	private static final String onNavigationButtonPressed = "RNN.navigationButtonPressed";
17
+    private static final String componentLifecycle = "RNN.componentLifecycle";
19 18
 
20 19
 	private final RCTDeviceEventEmitter emitter;
21 20
 
@@ -27,15 +26,26 @@ public class NavigationEvent {
27 26
 		emit(onAppLaunched);
28 27
 	}
29 28
 
30
-	public void componentDidDisappear(String id) {
29
+	public void componentDidDisappear(String id, String componentName) {
31 30
 		emit(componentDidDisappear, id);
31
+		emit(componentLifecycle, getLifecycleEventData(id, componentName, "didDisappear"));
32 32
 	}
33 33
 
34
-	public void componentDidAppear(String id) {
34
+	public void componentDidAppear(String id, String componentName) {
35 35
 		emit(componentDidAppear, id);
36
+        emit(componentLifecycle, getLifecycleEventData(id, componentName, "didAppear"));
36 37
 	}
37 38
 
38
-	public void sendOnNavigationButtonPressed(String id, String buttonId) {
39
+    @NonNull
40
+    private WritableMap getLifecycleEventData(String id, String componentName, String didAppear) {
41
+        WritableMap map = Arguments.createMap();
42
+        map.putString("componentId", id);
43
+        map.putString("componentName", componentName);
44
+        map.putString("event", didAppear);
45
+        return map;
46
+    }
47
+
48
+    public void sendOnNavigationButtonPressed(String id, String buttonId) {
39 49
 		WritableMap map = Arguments.createMap();
40 50
 		map.putString("componentId", id);
41 51
 		map.putString("buttonId", buttonId);

+ 8
- 6
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java Näytä tiedosto

@@ -14,7 +14,6 @@ import com.reactnativenavigation.parse.LayoutFactory;
14 14
 import com.reactnativenavigation.parse.LayoutNode;
15 15
 import com.reactnativenavigation.parse.LayoutNodeParser;
16 16
 import com.reactnativenavigation.parse.Options;
17
-import com.reactnativenavigation.parse.OverlayOptions;
18 17
 import com.reactnativenavigation.utils.TypefaceLoader;
19 18
 import com.reactnativenavigation.utils.UiThread;
20 19
 import com.reactnativenavigation.viewcontrollers.Navigator;
@@ -100,14 +99,17 @@ public class NavigationModule extends ReactContextBaseJavaModule {
100 99
 	}
101 100
 
102 101
 	@ReactMethod
103
-	public void showOverlay(final String type, final ReadableMap data, final Promise promise) {
104
-        final OverlayOptions overlayOptions = OverlayOptions.parse(JSONParser.parse(data));
105
-        handle(() -> navigator().showOverlay(type, overlayOptions, promise));
102
+	public void showOverlay(final ReadableMap rawLayoutTree) {
103
+        final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(rawLayoutTree));
104
+        handle(() -> {
105
+            final ViewController viewController = newLayoutFactory().create(layoutTree);
106
+            navigator().showOverlay(viewController);
107
+        });
106 108
 	}
107 109
 
108 110
 	@ReactMethod
109
-	public void dismissOverlay() {
110
-		handle(() -> navigator().dismissOverlay());
111
+	public void dismissOverlay(final String componentId) {
112
+		handle(() -> navigator().dismissOverlay(componentId));
111 113
 	}
112 114
 
113 115
 	private NavigationActivity activity() {

+ 6
- 0
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationReactNativeHost.java Näytä tiedosto

@@ -9,6 +9,10 @@ import com.facebook.react.shell.MainReactPackage;
9 9
 import java.util.ArrayList;
10 10
 import java.util.List;
11 11
 
12
+/**
13
+ * Default implementation of {@link ReactNativeHost} that includes {@link NavigationPackage}
14
+ * and user-defined additional packages.
15
+ */
12 16
 public class NavigationReactNativeHost extends ReactNativeHost {
13 17
 
14 18
 	private final boolean isDebug;
@@ -27,6 +31,8 @@ public class NavigationReactNativeHost extends ReactNativeHost {
27 31
 
28 32
 	@Override
29 33
 	protected List<ReactPackage> getPackages() {
34
+		// Please note that users may provide their own implementations of ReactNativeHost. Any additional
35
+		// package requirements should be documented in the changelog.
30 36
 		List<ReactPackage> packages = new ArrayList<>();
31 37
 		packages.add(new MainReactPackage());
32 38
 		packages.add(new NavigationPackage(this));

+ 3
- 3
lib/android/app/src/main/java/com/reactnativenavigation/react/ReactComponentViewCreator.java Näytä tiedosto

@@ -3,8 +3,8 @@ package com.reactnativenavigation.react;
3 3
 import android.app.Activity;
4 4
 
5 5
 import com.facebook.react.ReactInstanceManager;
6
-import com.reactnativenavigation.viewcontrollers.ComponentViewController;
7
-import com.reactnativenavigation.viewcontrollers.ComponentViewController.ReactViewCreator;
6
+import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
7
+import com.reactnativenavigation.viewcontrollers.IReactView;
8 8
 
9 9
 public class ReactComponentViewCreator implements ReactViewCreator {
10 10
 	private ReactInstanceManager reactInstanceManager;
@@ -14,7 +14,7 @@ public class ReactComponentViewCreator implements ReactViewCreator {
14 14
 	}
15 15
 
16 16
 	@Override
17
-	public ComponentViewController.IReactView create(final Activity activity, final String componentId, final String componentName) {
17
+	public IReactView create(final Activity activity, final String componentId, final String componentName) {
18 18
 		return new ReactView(activity, reactInstanceManager, componentId, componentName);
19 19
 	}
20 20
 }

+ 9
- 3
lib/android/app/src/main/java/com/reactnativenavigation/react/ReactGateway.java Näytä tiedosto

@@ -1,5 +1,7 @@
1 1
 package com.reactnativenavigation.react;
2 2
 
3
+import android.app.Application;
4
+
3 5
 import com.facebook.react.ReactNativeHost;
4 6
 import com.facebook.react.ReactPackage;
5 7
 import com.facebook.soloader.SoLoader;
@@ -10,13 +12,17 @@ import java.util.List;
10 12
 
11 13
 public class ReactGateway {
12 14
 
13
-	private final NavigationReactNativeHost reactNativeHost;
15
+	private final ReactNativeHost reactNativeHost;
14 16
 	private final NavigationReactInitializer initializer;
15 17
 	private final JsDevReloadHandler jsDevReloadHandler;
16 18
 
17
-	public ReactGateway(final NavigationApplication application, final boolean isDebug, final List<ReactPackage> additionalReactPackages) {
19
+	public ReactGateway(final Application application, final boolean isDebug, final List<ReactPackage> additionalReactPackages) {
20
+		this(application, isDebug, new NavigationReactNativeHost(application, isDebug, additionalReactPackages));
21
+	}
22
+
23
+	public ReactGateway(final Application application, final boolean isDebug, final ReactNativeHost reactNativeHost) {
18 24
 		SoLoader.init(application, false);
19
-		reactNativeHost = new NavigationReactNativeHost(application, isDebug, additionalReactPackages);
25
+		this.reactNativeHost = reactNativeHost;
20 26
 		initializer = new NavigationReactInitializer(reactNativeHost.getReactInstanceManager(), isDebug);
21 27
 		jsDevReloadHandler = new JsDevReloadHandler(reactNativeHost.getReactInstanceManager());
22 28
 	}

+ 14
- 5
lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java Näytä tiedosto

@@ -3,29 +3,33 @@ package com.reactnativenavigation.react;
3 3
 import android.annotation.SuppressLint;
4 4
 import android.content.Context;
5 5
 import android.os.Bundle;
6
+import android.view.MotionEvent;
6 7
 import android.view.View;
7 8
 
8 9
 import com.facebook.react.ReactInstanceManager;
9 10
 import com.facebook.react.ReactRootView;
10 11
 import com.facebook.react.bridge.ReactContext;
12
+import com.facebook.react.uimanager.JSTouchDispatcher;
11 13
 import com.facebook.react.uimanager.UIManagerModule;
12 14
 import com.facebook.react.uimanager.events.EventDispatcher;
13 15
 import com.reactnativenavigation.interfaces.ScrollEventListener;
14
-import com.reactnativenavigation.viewcontrollers.ComponentViewController;
16
+import com.reactnativenavigation.viewcontrollers.IReactView;
15 17
 
16 18
 @SuppressLint("ViewConstructor")
17
-public class ReactView extends ReactRootView implements ComponentViewController.IReactView {
19
+public class ReactView extends ReactRootView implements IReactView {
18 20
 
19 21
 	private final ReactInstanceManager reactInstanceManager;
20 22
 	private final String componentId;
21 23
 	private final String componentName;
22 24
 	private boolean isAttachedToReactInstance = false;
25
+    private final JSTouchDispatcher jsTouchDispatcher;
23 26
 
24
-	public ReactView(final Context context, ReactInstanceManager reactInstanceManager, String componentId, String componentName) {
27
+    public ReactView(final Context context, ReactInstanceManager reactInstanceManager, String componentId, String componentName) {
25 28
 		super(context);
26 29
 		this.reactInstanceManager = reactInstanceManager;
27 30
 		this.componentId = componentId;
28 31
 		this.componentName = componentName;
32
+		jsTouchDispatcher = new JSTouchDispatcher(this);
29 33
 		start();
30 34
 	}
31 35
 
@@ -56,12 +60,12 @@ public class ReactView extends ReactRootView implements ComponentViewController.
56 60
 
57 61
 	@Override
58 62
 	public void sendComponentStart() {
59
-		new NavigationEvent(reactInstanceManager.getCurrentReactContext()).componentDidAppear(componentId);
63
+		new NavigationEvent(reactInstanceManager.getCurrentReactContext()).componentDidAppear(componentId, componentName);
60 64
 	}
61 65
 
62 66
 	@Override
63 67
 	public void sendComponentStop() {
64
-		new NavigationEvent(reactInstanceManager.getCurrentReactContext()).componentDidDisappear(componentId);
68
+		new NavigationEvent(reactInstanceManager.getCurrentReactContext()).componentDidDisappear(componentId, componentName);
65 69
 	}
66 70
 
67 71
     @Override
@@ -74,6 +78,11 @@ public class ReactView extends ReactRootView implements ComponentViewController.
74 78
         return new ScrollEventListener(getEventDispatcher());
75 79
     }
76 80
 
81
+    @Override
82
+    public void dispatchTouchEventToJs(MotionEvent event) {
83
+        jsTouchDispatcher.handleTouchEvent(event, getEventDispatcher());
84
+    }
85
+
77 86
     public EventDispatcher getEventDispatcher() {
78 87
         ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
79 88
         return reactContext == null ? null : reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();

+ 13
- 0
lib/android/app/src/main/java/com/reactnativenavigation/utils/DeviceScreen.java Näytä tiedosto

@@ -0,0 +1,13 @@
1
+package com.reactnativenavigation.utils;
2
+
3
+import android.content.res.Resources;
4
+
5
+public class DeviceScreen {
6
+    public static int width(Resources resources) {
7
+        return resources.getDisplayMetrics().widthPixels;
8
+    }
9
+
10
+    public static int height(Resources resources) {
11
+        return resources.getDisplayMetrics().heightPixels;
12
+    }
13
+}

+ 35
- 9
lib/android/app/src/main/java/com/reactnativenavigation/utils/UiUtils.java Näytä tiedosto

@@ -1,9 +1,11 @@
1 1
 package com.reactnativenavigation.utils;
2 2
 
3 3
 import android.content.Context;
4
+import android.content.res.Resources;
4 5
 import android.graphics.PorterDuff;
5 6
 import android.graphics.PorterDuffColorFilter;
6 7
 import android.graphics.drawable.Drawable;
8
+import android.os.Build;
7 9
 import android.os.Handler;
8 10
 import android.os.Looper;
9 11
 import android.util.DisplayMetrics;
@@ -11,17 +13,23 @@ import android.view.View;
11 13
 import android.view.ViewTreeObserver;
12 14
 import android.view.WindowManager;
13 15
 
16
+import com.reactnativenavigation.NavigationApplication;
17
+
14 18
 public class UiUtils {
19
+    public static final int STATUS_BAR_HEIGHT_M = 24;
20
+    public static final int STATUS_BAR_HEIGHT_L = 25;
21
+    private static int statusBarHeight = -1;
22
+
15 23
 	public static void runOnPreDrawOnce(final View view, final Runnable task) {
16
-		view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
17
-			@Override
18
-			public boolean onPreDraw() {
19
-				view.getViewTreeObserver().removeOnPreDrawListener(this);
20
-				task.run();
21
-				return true;
22
-			}
23
-		});
24
-	}
24
+        view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
25
+            @Override
26
+            public boolean onPreDraw() {
27
+                view.getViewTreeObserver().removeOnPreDrawListener(this);
28
+                task.run();
29
+                return true;
30
+            }
31
+        });
32
+    }
25 33
 
26 34
 	public static void tintDrawable(Drawable drawable, int tint) {
27 35
 		drawable.setColorFilter(new PorterDuffColorFilter(tint, PorterDuff.Mode.SRC_IN));
@@ -39,4 +47,22 @@ public class UiUtils {
39 47
 		}
40 48
 		return metrics.heightPixels;
41 49
 	}
50
+
51
+    public static int getStatusBarHeight(Context context) {
52
+        if (statusBarHeight > 0) {
53
+            return statusBarHeight;
54
+        }
55
+        final Resources resources = context.getResources();
56
+        final int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
57
+        statusBarHeight = resourceId > 0 ?
58
+                resources.getDimensionPixelSize(resourceId) :
59
+                (int) dpToPx(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? STATUS_BAR_HEIGHT_M : STATUS_BAR_HEIGHT_L);
60
+        return statusBarHeight;
61
+    }
62
+
63
+    public static float dpToPx(float dp) {
64
+        float scale = NavigationApplication.instance.getResources().getDisplayMetrics().density;
65
+        return dp * scale + 0.5f;
66
+    }
67
+
42 68
 }

+ 17
- 52
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java Näytä tiedosto

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

+ 5
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Destroyable.java Näytä tiedosto

@@ -0,0 +1,5 @@
1
+package com.reactnativenavigation.viewcontrollers;
2
+
3
+public interface Destroyable {
4
+    void destroy();
5
+}

+ 23
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/IReactView.java Näytä tiedosto

@@ -0,0 +1,23 @@
1
+package com.reactnativenavigation.viewcontrollers;
2
+
3
+import android.view.MotionEvent;
4
+import android.view.View;
5
+
6
+import com.reactnativenavigation.interfaces.ScrollEventListener;
7
+
8
+public interface IReactView extends Destroyable {
9
+
10
+    boolean isReady();
11
+
12
+    View asView();
13
+
14
+    void sendComponentStart();
15
+
16
+    void sendComponentStop();
17
+
18
+    void sendOnNavigationButtonPressed(String buttonId);
19
+
20
+    ScrollEventListener getScrollEventListener();
21
+
22
+    void dispatchTouchEventToJs(MotionEvent event);
23
+}

+ 11
- 14
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java Näytä tiedosto

@@ -8,9 +8,8 @@ import android.widget.FrameLayout;
8 8
 
9 9
 import com.facebook.react.bridge.Promise;
10 10
 import com.reactnativenavigation.parse.Options;
11
-import com.reactnativenavigation.parse.OverlayOptions;
12 11
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
13
-import com.reactnativenavigation.presentation.OverlayPresenter;
12
+import com.reactnativenavigation.presentation.OverlayManager;
14 13
 import com.reactnativenavigation.utils.CompatUtils;
15 14
 import com.reactnativenavigation.utils.NoOpPromise;
16 15
 
@@ -22,7 +21,7 @@ public class Navigator extends ParentController {
22 21
     private static final NoOpPromise NO_OP = new NoOpPromise();
23 22
     private final ModalStack modalStack = new ModalStack();
24 23
 	private ViewController root;
25
-	private OverlayPresenter overlayPresenter;
24
+    private OverlayManager overlayManager = new OverlayManager();
26 25
     private Options defaultOptions = new Options();
27 26
 
28 27
     public Navigator(final Activity activity) {
@@ -83,21 +82,21 @@ public class Navigator extends ParentController {
83 82
 	public void push(final String fromId, final ViewController viewController, Promise promise) {
84 83
 		ViewController from = findControllerById(fromId);
85 84
 		if (from != null) {
86
-		    from.performOnParentStack(stack -> stack.animatePush(viewController, promise));
85
+		    from.performOnParentStack(stack -> ((StackController) stack).animatePush(viewController, promise));
87 86
 		}
88 87
 	}
89 88
 
90 89
 	void pop(final String fromId, Promise promise) {
91 90
 		ViewController from = findControllerById(fromId);
92 91
 		if (from != null) {
93
-		    from.performOnParentStack(stack -> stack.pop(promise));
92
+		    from.performOnParentStack(stack -> ((StackController) stack).pop(promise));
94 93
 		}
95 94
 	}
96 95
 
97 96
 	public void popSpecific(final String id, Promise promise) {
98 97
 		ViewController from = findControllerById(id);
99 98
 		if (from != null) {
100
-		    from.performOnParentStack(stack -> stack.popSpecific(from, promise), () -> rejectPromise(promise));
99
+		    from.performOnParentStack(stack -> ((StackController) stack).popSpecific(from, promise), () -> rejectPromise(promise));
101 100
 		} else {
102 101
 			rejectPromise(promise);
103 102
 		}
@@ -106,14 +105,14 @@ public class Navigator extends ParentController {
106 105
 	public void popToRoot(final String id, Promise promise) {
107 106
 		ViewController from = findControllerById(id);
108 107
 		if (from != null) {
109
-		    from.performOnParentStack(stack -> stack.popToRoot(promise));
108
+		    from.performOnParentStack(stack -> ((StackController) stack).popToRoot(promise));
110 109
 		}
111 110
 	}
112 111
 
113 112
 	public void popTo(final String componentId, Promise promise) {
114 113
 		ViewController target = findControllerById(componentId);
115 114
 		if (target != null) {
116
-		    target.performOnParentStack(stack -> stack.popTo(target, promise), () -> rejectPromise(promise));
115
+		    target.performOnParentStack(stack -> ((StackController) stack).popTo(target, promise), () -> rejectPromise(promise));
117 116
 		} else {
118 117
 			rejectPromise(promise);
119 118
 		}
@@ -131,14 +130,12 @@ public class Navigator extends ParentController {
131 130
 		modalStack.dismissAll(promise);
132 131
 	}
133 132
 
134
-	public void showOverlay(String type, OverlayOptions options, Promise promise) {
135
-		overlayPresenter = new OverlayPresenter(root, type, options);
136
-		overlayPresenter.show();
137
-		promise.resolve(true);
133
+	public void showOverlay(ViewController overlay) {
134
+        overlayManager.show(getView(), overlay);
138 135
 	}
139 136
 
140
-	public void dismissOverlay() {
141
-		overlayPresenter.dismiss();
137
+	public void dismissOverlay(final String componentId) {
138
+		overlayManager.dismiss(getView(), componentId);
142 139
 	}
143 140
 
144 141
 	static void rejectPromise(Promise promise) {

+ 5
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java Näytä tiedosto

@@ -3,6 +3,7 @@ package com.reactnativenavigation.viewcontrollers;
3 3
 import android.app.Activity;
4 4
 import android.support.annotation.NonNull;
5 5
 import android.support.annotation.Nullable;
6
+import android.support.v4.view.ViewPager;
6 7
 import android.view.ViewGroup;
7 8
 
8 9
 import com.reactnativenavigation.parse.Options;
@@ -58,4 +59,8 @@ public abstract class ParentController<T extends ViewGroup> extends ViewControll
58 59
     void clearOptions() {
59 60
 
60 61
     }
62
+
63
+    public void setupTopTabsWithViewPager(ViewPager viewPager) {
64
+
65
+    }
61 66
 }

+ 8
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ReactViewCreator.java Näytä tiedosto

@@ -0,0 +1,8 @@
1
+package com.reactnativenavigation.viewcontrollers;
2
+
3
+import android.app.Activity;
4
+
5
+public interface ReactViewCreator {
6
+
7
+    IReactView create(Activity activity, String componentId, String componentName);
8
+}

+ 22
- 2
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java Näytä tiedosto

@@ -3,6 +3,7 @@ package com.reactnativenavigation.viewcontrollers;
3 3
 import android.app.Activity;
4 4
 import android.support.annotation.NonNull;
5 5
 import android.support.annotation.RestrictTo;
6
+import android.support.v4.view.ViewPager;
6 7
 import android.view.View;
7 8
 
8 9
 import com.facebook.react.bridge.Promise;
@@ -43,6 +44,20 @@ public class StackController extends ParentController <StackLayout> {
43 44
         stackLayout.clearOptions();
44 45
     }
45 46
 
47
+    public void push(ViewController child, final Promise promise) {
48
+        final ViewController toRemove = stack.peek();
49
+
50
+        child.setParentController(this);
51
+        stack.push(child.getId(), child);
52
+        View enteringView = child.getView();
53
+        getView().addView(enteringView);
54
+
55
+        if (toRemove != null) {
56
+            getView().removeView(toRemove.getView());
57
+        }
58
+        promise.resolve(child.getId());
59
+    }
60
+
46 61
     public void animatePush(final ViewController child, final Promise promise) {
47 62
 		final ViewController toRemove = stack.peek();
48 63
 
@@ -61,7 +76,7 @@ public class StackController extends ParentController <StackLayout> {
61 76
 		}
62 77
 	}
63 78
 
64
-    public void pop(final Promise promise) {
79
+    void pop(final Promise promise) {
65 80
         if (!canPop()) {
66 81
             Navigator.rejectPromise(promise);
67 82
             return;
@@ -77,7 +92,7 @@ public class StackController extends ParentController <StackLayout> {
77 92
         finishPopping(exitingView, poppedTop, promise);
78 93
     }
79 94
 
80
-	public void animatePop(final Promise promise) {
95
+	private void animatePop(final Promise promise) {
81 96
 		if (!canPop()) {
82 97
 			Navigator.rejectPromise(promise);
83 98
 			return;
@@ -177,4 +192,9 @@ public class StackController extends ParentController <StackLayout> {
177 192
 	public Collection<ViewController> getChildControllers() {
178 193
 		return stack.values();
179 194
 	}
195
+
196
+    @Override
197
+    public void setupTopTabsWithViewPager(ViewPager viewPager) {
198
+        stackLayout.setupTopTabsWithViewPager(viewPager);
199
+    }
180 200
 }

+ 116
- 87
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java Näytä tiedosto

@@ -13,135 +13,164 @@ import com.reactnativenavigation.parse.Options;
13 13
 import com.reactnativenavigation.utils.CompatUtils;
14 14
 import com.reactnativenavigation.utils.StringUtils;
15 15
 import com.reactnativenavigation.utils.Task;
16
+import com.reactnativenavigation.views.ReactComponent;
16 17
 
17
-public abstract class ViewController implements ViewTreeObserver.OnGlobalLayoutListener {
18
+public abstract class ViewController<T extends ViewGroup> implements ViewTreeObserver.OnGlobalLayoutListener {
19
+
20
+    public interface ViewVisibilityListener {
21
+        /**
22
+         * @return true if the event is consumed, false otherwise
23
+         */
24
+        boolean onViewAppeared(View view);
25
+
26
+        /**
27
+         * @return true if the event is consumed, false otherwise
28
+         */
29
+        boolean onViewDisappear(View view);
30
+    }
18 31
 
19 32
     public Options options;
20 33
 
21
-	private final Activity activity;
22
-	private final String id;
23
-	private View view;
24
-	private ParentController parentController;
25
-	private boolean isShown = false;
34
+    private final Activity activity;
35
+    private final String id;
36
+    protected T view;
37
+    @Nullable private ParentController<T> parentController;
38
+    private boolean isShown;
26 39
     private boolean isDestroyed;
40
+    private ViewVisibilityListener viewVisibilityListener = new ViewVisibilityListenerAdapter();
41
+
42
+    public ViewController(Activity activity, String id) {
43
+        this.activity = activity;
44
+        this.id = id;
45
+    }
27 46
 
28
-	public ViewController(Activity activity, String id) {
29
-		this.activity = activity;
30
-		this.id = id;
31
-	}
47
+    protected abstract T createView();
32 48
 
33
-	protected abstract View createView();
49
+    public void setViewVisibilityListener(ViewVisibilityListener viewVisibilityListener) {
50
+        this.viewVisibilityListener = viewVisibilityListener;
51
+    }
34 52
 
35
-	@SuppressWarnings("WeakerAccess")
53
+    @SuppressWarnings("WeakerAccess")
36 54
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
37
-	public void ensureViewIsCreated() {
38
-		getView();
39
-	}
55
+    public void ensureViewIsCreated() {
56
+        getView();
57
+    }
40 58
 
41
-	public boolean handleBack() {
42
-		return false;
43
-	}
59
+    public boolean handleBack() {
60
+        return false;
61
+    }
44 62
 
45 63
     public void applyOptions(Options options) {
46 64
 
47 65
     }
48 66
 
49
-	public Activity getActivity() {
50
-		return activity;
51
-	}
67
+    public Activity getActivity() {
68
+        return activity;
69
+    }
52 70
 
53
-	protected void applyOnParentStack(Task<ParentController> task) {
54
-        if (parentController != null) {
55
-            task.run(parentController);
56
-        }
71
+    protected void applyOnParentController(Task<ParentController> task) {
72
+        if (parentController != null) task.run(parentController);
57 73
     }
58 74
 
59
-	@Nullable
60
-    ParentController getParentStackController() {
61
-		return parentController;
62
-	}
75
+    @Nullable
76
+    ParentController getParentController() {
77
+        return parentController;
78
+    }
63 79
 
64
-	public void setParentController(final ParentController parentController) {
65
-		this.parentController = parentController;
66
-	}
80
+    public void setParentController(@NonNull final ParentController parentController) {
81
+        this.parentController = parentController;
82
+    }
67 83
 
68 84
     boolean performOnParentStack(Task<StackController> task) {
69
-	    if (parentController instanceof StackController) {
85
+        if (parentController instanceof StackController) {
70 86
             task.run((StackController) parentController);
71 87
             return true;
72 88
         }
73 89
         if (this instanceof StackController) {
74
-	        task.run((StackController) this);
90
+            task.run((StackController) this);
75 91
             return true;
76 92
         }
77 93
         return false;
78 94
     }
79 95
 
80
-    void performOnParentStack(Task<StackController> accept, Runnable  reject) {
96
+    void performOnParentStack(Task accept, Runnable reject) {
81 97
         if (!performOnParentStack(accept)) {
82 98
             reject.run();
83 99
         }
84 100
     }
85 101
 
86
-	@NonNull
87
-	public View getView() {
88
-		if (view == null) {
89
-		    if (isDestroyed) throw new RuntimeException("Tried to create view after it has already been destroyed");
102
+    @NonNull
103
+    public T getView() {
104
+        if (view == null) {
105
+            if (isDestroyed) {
106
+                throw new RuntimeException("Tried to create view after it has already been destroyed");
107
+            }
90 108
             view = createView();
91
-			view.setId(CompatUtils.generateViewId());
92
-			view.getViewTreeObserver().addOnGlobalLayoutListener(this);
93
-		}
94
-		return view;
95
-	}
96
-
97
-	public String getId() {
98
-		return id;
99
-	}
100
-
101
-	boolean isSameId(final String id) {
102
-		return StringUtils.isEqual(this.id, id);
103
-	}
104
-
105
-	@Nullable
106
-	public ViewController findControllerById(String id) {
107
-		return isSameId(id) ? this : null;
108
-	}
109
-
110
-	public void onViewAppeared() {
109
+            view.setId(CompatUtils.generateViewId());
110
+            view.getViewTreeObserver().addOnGlobalLayoutListener(this);
111
+        }
112
+        return view;
113
+    }
114
+
115
+    public String getId() {
116
+        return id;
117
+    }
118
+
119
+    boolean isSameId(final String id) {
120
+        return StringUtils.isEqual(this.id, id);
121
+    }
122
+
123
+    @Nullable
124
+    public ViewController findControllerById(String id) {
125
+        return isSameId(id) ? this : null;
126
+    }
127
+
128
+    public void onViewAppeared() {
111 129
         isShown = true;
130
+        applyOnParentController(parentController -> {
131
+            parentController.clearOptions();
132
+            parentController.applyOptions(options, (ReactComponent) getView());
133
+        });
112 134
     }
113 135
 
114
-	public void onViewDisappear() {
136
+    public void onViewDisappear() {
115 137
         isShown = false;
116 138
     }
117 139
 
118
-	public void destroy() {
119
-		if (isShown) {
120
-			isShown = false;
121
-			onViewDisappear();
122
-		}
123
-		if (view != null) {
124
-			view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
125
-			if (view.getParent() instanceof ViewGroup) {
126
-				((ViewManager) view.getParent()).removeView(view);
127
-			}
128
-			view = null;
140
+    public void destroy() {
141
+        if (isShown) {
142
+            isShown = false;
143
+            onViewDisappear();
144
+            if (view instanceof Destroyable) {
145
+                ((Destroyable) view).destroy();
146
+            }
147
+        }
148
+        if (view != null) {
149
+            view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
150
+            if (view.getParent() instanceof ViewGroup) {
151
+                ((ViewManager) view.getParent()).removeView(view);
152
+            }
153
+            view = null;
129 154
             isDestroyed = true;
130
-		}
131
-	}
132
-
133
-	@Override
134
-	public void onGlobalLayout() {
135
-		if (!isShown && isViewShown()) {
136
-			isShown = true;
137
-			onViewAppeared();
138
-		} else if (isShown && !isViewShown()) {
139
-			isShown = false;
140
-			onViewDisappear();
141
-		}
142
-	}
143
-
144
-	protected boolean isViewShown() {
155
+        }
156
+    }
157
+
158
+    @Override
159
+    public void onGlobalLayout() {
160
+        if (!isShown && isViewShown()) {
161
+            if (!viewVisibilityListener.onViewAppeared(view)) {
162
+                isShown = true;
163
+                onViewAppeared();
164
+            }
165
+        } else if (isShown && !isViewShown()) {
166
+            if (!viewVisibilityListener.onViewDisappear(view)) {
167
+                isShown = false;
168
+                onViewDisappear();
169
+            }
170
+        }
171
+    }
172
+
173
+    protected boolean isViewShown() {
145 174
         return !isDestroyed && getView().isShown();
146
-	}
175
+    }
147 176
 }

+ 15
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewVisibilityListenerAdapter.java Näytä tiedosto

@@ -0,0 +1,15 @@
1
+package com.reactnativenavigation.viewcontrollers;
2
+
3
+import android.view.View;
4
+
5
+public class ViewVisibilityListenerAdapter implements ViewController.ViewVisibilityListener {
6
+    @Override
7
+    public boolean onViewAppeared(View view) {
8
+        return false;
9
+    }
10
+
11
+    @Override
12
+    public boolean onViewDisappear(View view) {
13
+        return false;
14
+    }
15
+}

+ 0
- 55
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/AlertOverlay.java Näytä tiedosto

@@ -1,55 +0,0 @@
1
-package com.reactnativenavigation.viewcontrollers.overlay;
2
-
3
-
4
-import android.content.Context;
5
-import android.content.DialogInterface;
6
-import android.support.v7.app.AlertDialog;
7
-
8
-import com.reactnativenavigation.parse.OverlayOptions;
9
-import com.reactnativenavigation.viewcontrollers.ViewController;
10
-
11
-public class AlertOverlay implements OverlayInterface {
12
-
13
-	private AlertDialog dialog;
14
-
15
-	@Override
16
-	public AlertOverlay create(ViewController viewController, final OverlayOptions options) {
17
-		AlertDialog.Builder builder = new AlertDialog.Builder(viewController.getActivity());
18
-
19
-		builder.setTitle(options.getTitle());
20
-		builder.setMessage(options.getText());
21
-		if (options.getPositiveButton().isVisible()) {
22
-			builder.setPositiveButton(options.getPositiveButton().getText(), new DialogInterface.OnClickListener() {
23
-				@Override
24
-				public void onClick(DialogInterface dialog, int which) {
25
-					//TODO: perform action options.getPositiveButton().getAction();
26
-					dialog.dismiss();
27
-				}
28
-			});
29
-		}
30
-		if (options.getNegativeButton().isVisible()) {
31
-			builder.setNegativeButton(options.getNegativeButton().getText(), new DialogInterface.OnClickListener() {
32
-				@Override
33
-				public void onClick(DialogInterface dialog, int which) {
34
-					//TODO: perform action options.getNegativeButton().getAction();
35
-					dialog.dismiss();
36
-				}
37
-			});
38
-		}
39
-		dialog = builder.create();
40
-
41
-		return this;
42
-	}
43
-
44
-	@Override
45
-	public void show() {
46
-		dialog.show();
47
-	}
48
-
49
-	@Override
50
-	public void dismiss() {
51
-		if (dialog != null) {
52
-			dialog.dismiss();
53
-		}
54
-	}
55
-}

+ 0
- 27
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/DialogViewController.java Näytä tiedosto

@@ -1,27 +0,0 @@
1
-package com.reactnativenavigation.viewcontrollers.overlay;
2
-
3
-import android.app.Activity;
4
-import android.support.annotation.NonNull;
5
-import android.view.View;
6
-
7
-import com.reactnativenavigation.viewcontrollers.ComponentViewController;
8
-import com.reactnativenavigation.viewcontrollers.ViewController;
9
-
10
-
11
-public class DialogViewController extends ViewController {
12
-
13
-	private ComponentViewController.ReactViewCreator viewCreator;
14
-	private String componentName;
15
-
16
-	public DialogViewController(Activity activity, String id, String componentName, ComponentViewController.ReactViewCreator viewCreator) {
17
-		super(activity, id);
18
-		this.viewCreator = viewCreator;
19
-		this.componentName = componentName;
20
-	}
21
-
22
-	@NonNull
23
-	@Override
24
-	protected View createView() {
25
-		return viewCreator.create(getActivity(), getId(), componentName).asView();
26
-	}
27
-}

+ 0
- 35
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/OverlayFactory.java Näytä tiedosto

@@ -1,35 +0,0 @@
1
-package com.reactnativenavigation.viewcontrollers.overlay;
2
-
3
-
4
-import com.reactnativenavigation.parse.OverlayOptions;
5
-import com.reactnativenavigation.viewcontrollers.ViewController;
6
-
7
-public class OverlayFactory {
8
-
9
-	public enum Overlay {
10
-		AlertDialog("alert", new AlertOverlay()),
11
-		Snackbar("snackbar", new SnackbarOverlay());
12
-
13
-		private String name;
14
-		private OverlayInterface overlayInstance;
15
-
16
-		Overlay(String name, OverlayInterface overlayInstance) {
17
-			this.name = name;
18
-			this.overlayInstance = overlayInstance;
19
-		}
20
-
21
-		public static Overlay create(String type) {
22
-			for (Overlay overlay : values()) {
23
-				if (overlay.name.equals(type)) {
24
-					return overlay;
25
-				}
26
-			}
27
-			return AlertDialog;
28
-		}
29
-	}
30
-
31
-	public static OverlayInterface create(String type, ViewController viewController, OverlayOptions options) {
32
-		return Overlay.create(type).overlayInstance.create(viewController, options);
33
-	}
34
-
35
-}

+ 0
- 88
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/overlay/SnackbarOverlay.java Näytä tiedosto

@@ -1,88 +0,0 @@
1
-package com.reactnativenavigation.viewcontrollers.overlay;
2
-
3
-
4
-import android.app.Activity;
5
-import android.content.Context;
6
-import android.support.design.widget.Snackbar;
7
-import android.text.SpannableStringBuilder;
8
-import android.text.Spanned;
9
-import android.text.style.ForegroundColorSpan;
10
-import android.view.View;
11
-
12
-import com.reactnativenavigation.parse.OverlayOptions;
13
-import com.reactnativenavigation.viewcontrollers.ViewController;
14
-
15
-import static com.reactnativenavigation.parse.OverlayOptions.NO_COLOR;
16
-
17
-public class SnackbarOverlay implements OverlayInterface {
18
-
19
-	private Snackbar snackbar;
20
-	private OverlayOptions options;
21
-
22
-	@Override
23
-	public SnackbarOverlay create(ViewController viewController, OverlayOptions options) {
24
-		this.options = options;
25
-
26
-		init(viewController);
27
-		setAction();
28
-		setStyle();
29
-
30
-		return this;
31
-	}
32
-
33
-	private void init(ViewController viewController) {
34
-		snackbar = Snackbar.make(viewController.getView(),
35
-				options.getTextColor() == NO_COLOR ? options.getText() : getStyledText(),
36
-				getDuration(options.getDuration()));
37
-	}
38
-
39
-	private Spanned getStyledText() {
40
-		SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(options.getText());
41
-		spannableStringBuilder.setSpan(new ForegroundColorSpan(options.getTextColor()), 0,
42
-				spannableStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
43
-		return spannableStringBuilder;
44
-	}
45
-
46
-	@Override
47
-	public void show() {
48
-		snackbar.show();
49
-	}
50
-
51
-	@Override
52
-	public void dismiss() {
53
-		snackbar.dismiss();
54
-	}
55
-
56
-	private int getDuration(String duration) {
57
-		switch (duration) {
58
-			case "short":
59
-				return Snackbar.LENGTH_SHORT;
60
-			case "long":
61
-				return Snackbar.LENGTH_LONG;
62
-			case "indefinite":
63
-				return Snackbar.LENGTH_INDEFINITE;
64
-			default:
65
-				return Snackbar.LENGTH_SHORT;
66
-		}
67
-	}
68
-
69
-	private void setAction() {
70
-		if (options.getButton() != null) {
71
-			snackbar.setAction(options.getButton().getText(), new View.OnClickListener() {
72
-				@Override
73
-				public void onClick(View v) {
74
-					//TODO: perform action
75
-				}
76
-			});
77
-		}
78
-	}
79
-
80
-	private void setStyle() {
81
-		if (options.getButton() != null && options.getButton().getTextColor() != NO_COLOR) {
82
-			snackbar.setActionTextColor(options.getButton().getTextColor());
83
-		}
84
-		if (options.getBackgroundColor() != NO_COLOR) {
85
-			snackbar.getView().setBackgroundColor(options.getBackgroundColor());
86
-		}
87
-	}
88
-}

+ 0
- 80
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabController.java Näytä tiedosto

@@ -1,80 +0,0 @@
1
-package com.reactnativenavigation.viewcontrollers.toptabs;
2
-
3
-import android.app.Activity;
4
-import android.view.View;
5
-
6
-import com.reactnativenavigation.parse.Options;
7
-import com.reactnativenavigation.presentation.NavigationOptionsListener;
8
-import com.reactnativenavigation.viewcontrollers.ComponentViewController;
9
-import com.reactnativenavigation.viewcontrollers.ViewController;
10
-import com.reactnativenavigation.views.TopTab;
11
-
12
-public class TopTabController extends ViewController implements NavigationOptionsListener {
13
-
14
-    private final String componentName;
15
-    private ComponentViewController.ReactViewCreator viewCreator;
16
-    private TopTab topTab;
17
-    private boolean isSelectedTab;
18
-
19
-    public TopTabController(Activity activity, String id, String name, ComponentViewController.ReactViewCreator viewCreator, Options initialOptions) {
20
-        super(activity, id);
21
-        this.componentName = name;
22
-        this.viewCreator = viewCreator;
23
-        this.options = initialOptions;
24
-    }
25
-
26
-    @Override
27
-    public void onViewAppeared() {
28
-        super.onViewAppeared();
29
-        isSelectedTab = true;
30
-        applyOptions(options);
31
-        topTab.sendComponentStart();
32
-    }
33
-
34
-    @Override
35
-    public void applyOptions(Options options) {
36
-        applyOnParentStack(parentController -> parentController.applyOptions(options));
37
-    }
38
-
39
-    @Override
40
-    public void onViewDisappear() {
41
-        super.onViewDisappear();
42
-        isSelectedTab = false;
43
-        topTab.sendComponentStop();
44
-    }
45
-
46
-    @Override
47
-    protected boolean isViewShown() {
48
-        return super.isViewShown() && isSelectedTab;
49
-    }
50
-
51
-    @Override
52
-    public View createView() {
53
-        topTab = new TopTab(
54
-                getActivity(),
55
-                viewCreator.create(getActivity(), getId(), componentName)
56
-        );
57
-        return topTab;
58
-    }
59
-
60
-    @Override
61
-    public void destroy() {
62
-        super.destroy();
63
-        if (topTab != null) topTab.destroy();
64
-        topTab = null;
65
-    }
66
-
67
-    @Override
68
-    public void mergeOptions(Options options) {
69
-        this.options.mergeWith(options);
70
-        applyOptions(this.options);
71
-    }
72
-
73
-    String getTabTitle() {
74
-        return options.topTabOptions.title.get("");
75
-    }
76
-
77
-    public void setTabIndex(int i) {
78
-        options.topTabOptions.tabIndex = i;
79
-    }
80
-}

+ 23
- 10
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java Näytä tiedosto

@@ -2,23 +2,24 @@ package com.reactnativenavigation.viewcontrollers.toptabs;
2 2
 
3 3
 import android.app.Activity;
4 4
 import android.support.annotation.NonNull;
5
-import android.view.ViewGroup;
5
+import android.view.View;
6 6
 
7 7
 import com.reactnativenavigation.parse.Options;
8 8
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
9 9
 import com.reactnativenavigation.utils.Task;
10 10
 import com.reactnativenavigation.viewcontrollers.ParentController;
11 11
 import com.reactnativenavigation.viewcontrollers.ViewController;
12
-import com.reactnativenavigation.views.TopTabsLayout;
12
+import com.reactnativenavigation.viewcontrollers.ViewVisibilityListenerAdapter;
13
+import com.reactnativenavigation.views.ReactComponent;
13 14
 import com.reactnativenavigation.views.TopTabsLayoutCreator;
15
+import com.reactnativenavigation.views.TopTabsViewPager;
14 16
 
15 17
 import java.util.Collection;
16 18
 import java.util.List;
17 19
 
18
-public class TopTabsController extends ParentController implements NavigationOptionsListener {
20
+public class TopTabsController extends ParentController<TopTabsViewPager> implements NavigationOptionsListener {
19 21
 
20 22
     private List<ViewController> tabs;
21
-    private TopTabsLayout topTabsLayout;
22 23
     private TopTabsLayoutCreator viewCreator;
23 24
     private Options options;
24 25
 
@@ -29,14 +30,20 @@ public class TopTabsController extends ParentController implements NavigationOpt
29 30
         this.tabs = tabs;
30 31
         for (ViewController tab : tabs) {
31 32
             tab.setParentController(this);
33
+            tab.setViewVisibilityListener(new ViewVisibilityListenerAdapter() {
34
+                @Override
35
+                public boolean onViewAppeared(View view) {
36
+                    return getView().isCurrentView(view);
37
+                }
38
+            });
32 39
         }
33 40
     }
34 41
 
35 42
     @NonNull
36 43
     @Override
37
-    protected ViewGroup createView() {
38
-        topTabsLayout = viewCreator.create();
39
-        return topTabsLayout;
44
+    protected TopTabsViewPager createView() {
45
+        view = viewCreator.create();
46
+        return (TopTabsViewPager) view;
40 47
     }
41 48
 
42 49
     @NonNull
@@ -48,6 +55,7 @@ public class TopTabsController extends ParentController implements NavigationOpt
48 55
     @Override
49 56
     public void onViewAppeared() {
50 57
         applyOptions(options);
58
+        applyOnParentController(parentController -> ((ParentController) parentController).setupTopTabsWithViewPager(getView()));
51 59
         performOnCurrentTab(ViewController::onViewAppeared);
52 60
     }
53 61
 
@@ -58,7 +66,12 @@ public class TopTabsController extends ParentController implements NavigationOpt
58 66
 
59 67
     @Override
60 68
     public void applyOptions(Options options) {
61
-        topTabsLayout.applyOptions(options);
69
+        getView().applyOptions(options);
70
+    }
71
+
72
+    @Override
73
+    public void applyOptions(Options options, ReactComponent childComponent) {
74
+        applyOnParentController(parentController -> ((ParentController) parentController).applyOptions(options, childComponent));
62 75
     }
63 76
 
64 77
     @Override
@@ -67,10 +80,10 @@ public class TopTabsController extends ParentController implements NavigationOpt
67 80
     }
68 81
 
69 82
     public void switchToTab(int index) {
70
-        topTabsLayout.switchToTab(index);
83
+        getView().switchToTab(index);
71 84
     }
72 85
 
73 86
     private void performOnCurrentTab(Task<ViewController> task) {
74
-        task.run(tabs.get(topTabsLayout.getCurrentItem()));
87
+        task.run(tabs.get(getView().getCurrentItem()));
75 88
     }
76 89
 }

+ 0
- 44
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsViewPager.java Näytä tiedosto

@@ -1,44 +0,0 @@
1
-package com.reactnativenavigation.viewcontrollers.toptabs;
2
-
3
-import android.annotation.SuppressLint;
4
-import android.content.Context;
5
-import android.support.v4.view.ViewPager;
6
-import android.view.ViewGroup;
7
-
8
-import com.reactnativenavigation.viewcontrollers.ComponentViewController;
9
-import com.reactnativenavigation.viewcontrollers.ViewController;
10
-
11
-import java.util.List;
12
-
13
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
14
-
15
-@SuppressLint("ViewConstructor")
16
-public class TopTabsViewPager extends ViewPager {
17
-    private static final int OFFSCREEN_PAGE_LIMIT = 99;
18
-    private List<ViewController> tabs;
19
-
20
-    public TopTabsViewPager(Context context, List<ViewController> tabs, TopTabsAdapter adapter) {
21
-        super(context);
22
-        this.tabs = tabs;
23
-        init(adapter);
24
-    }
25
-
26
-    private void init(TopTabsAdapter adapter) {
27
-        setOffscreenPageLimit(OFFSCREEN_PAGE_LIMIT);
28
-        for (ViewController tab : tabs) {
29
-            addView(tab.getView(), new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
30
-        }
31
-        setAdapter(adapter);
32
-        addOnPageChangeListener(adapter);
33
-    }
34
-
35
-    public void destroy() {
36
-        for (ViewController tab : tabs) {
37
-            tab.destroy();
38
-        }
39
-    }
40
-
41
-    public void sendOnNavigationButtonPressed(String id) {
42
-        ((ComponentViewController.IReactView) tabs.get(getCurrentItem()).getView()).sendOnNavigationButtonPressed(id);
43
-    }
44
-}

+ 19
- 5
lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentLayout.java Näytä tiedosto

@@ -2,13 +2,15 @@ package com.reactnativenavigation.views;
2 2
 
3 3
 import android.annotation.SuppressLint;
4 4
 import android.content.Context;
5
+import android.view.MotionEvent;
5 6
 import android.view.View;
6 7
 import android.widget.FrameLayout;
7 8
 import android.widget.RelativeLayout;
8 9
 
9 10
 import com.reactnativenavigation.interfaces.ScrollEventListener;
10 11
 import com.reactnativenavigation.parse.Options;
11
-import com.reactnativenavigation.viewcontrollers.ComponentViewController.IReactView;
12
+import com.reactnativenavigation.viewcontrollers.IReactView;
13
+import com.reactnativenavigation.views.touch.OverlayTouchDelegate;
12 14
 
13 15
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
14 16
 import static android.widget.RelativeLayout.BELOW;
@@ -17,11 +19,13 @@ import static android.widget.RelativeLayout.BELOW;
17 19
 public class ComponentLayout extends FrameLayout implements ReactComponent, TitleBarButton.OnClickListener {
18 20
 
19 21
     private IReactView reactView;
22
+    private final OverlayTouchDelegate touchDelegate;
20 23
 
21
-	public ComponentLayout(Context context, IReactView reactView) {
24
+    public ComponentLayout(Context context, IReactView reactView) {
22 25
 		super(context);
23 26
 		this.reactView = reactView;
24 27
         addView(reactView.asView(), MATCH_PARENT, MATCH_PARENT);
28
+        touchDelegate = new OverlayTouchDelegate(reactView);
25 29
     }
26 30
 
27 31
     @Override
@@ -51,7 +55,7 @@ public class ComponentLayout extends FrameLayout implements ReactComponent, Titl
51 55
 
52 56
     @Override
53 57
     public void applyOptions(Options options) {
54
-
58
+        touchDelegate.setInterceptTouchOutside(options.overlayOptions.interceptTouchOutside == Options.BooleanOptions.True);
55 59
     }
56 60
 
57 61
     @Override
@@ -64,16 +68,21 @@ public class ComponentLayout extends FrameLayout implements ReactComponent, Titl
64 68
         return reactView.getScrollEventListener();
65 69
     }
66 70
 
71
+    @Override
72
+    public void dispatchTouchEventToJs(MotionEvent event) {
73
+        reactView.dispatchTouchEventToJs(event);
74
+    }
75
+
67 76
     @Override
68 77
     public void drawBehindTopBar() {
69
-        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) reactView.asView().getLayoutParams();
78
+        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
70 79
         layoutParams.removeRule(BELOW);
71 80
         reactView.asView().setLayoutParams(layoutParams);
72 81
     }
73 82
 
74 83
     @Override
75 84
     public void drawBelowTopBar(TopBar topBar) {
76
-        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) reactView.asView().getLayoutParams();
85
+        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
77 86
         layoutParams.addRule(BELOW, topBar.getId());
78 87
         reactView.asView().setLayoutParams(layoutParams);
79 88
     }
@@ -82,4 +91,9 @@ public class ComponentLayout extends FrameLayout implements ReactComponent, Titl
82 91
     public void onPress(String buttonId) {
83 92
         reactView.sendOnNavigationButtonPressed(buttonId);
84 93
     }
94
+
95
+    @Override
96
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
97
+        return touchDelegate.onInterceptTouchEvent(ev);
98
+    }
85 99
 }

+ 5
- 4
lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentViewCreator.java Näytä tiedosto

@@ -4,9 +4,10 @@ import android.app.Activity;
4 4
 
5 5
 import com.facebook.react.ReactInstanceManager;
6 6
 import com.reactnativenavigation.react.ReactComponentViewCreator;
7
-import com.reactnativenavigation.viewcontrollers.ComponentViewController;
7
+import com.reactnativenavigation.viewcontrollers.IReactView;
8
+import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
8 9
 
9
-public class ComponentViewCreator implements ComponentViewController.ReactViewCreator {
10
+public class ComponentViewCreator implements ReactViewCreator {
10 11
 
11 12
     private ReactInstanceManager instanceManager;
12 13
 
@@ -15,8 +16,8 @@ public class ComponentViewCreator implements ComponentViewController.ReactViewCr
15 16
 	}
16 17
 
17 18
 	@Override
18
-	public ComponentViewController.IReactView create(Activity activity, String componentId, String componentName) {
19
-        ComponentViewController.IReactView reactView = new ReactComponentViewCreator(instanceManager).create(activity, componentId, componentName);
19
+	public IReactView create(Activity activity, String componentId, String componentName) {
20
+        IReactView reactView = new ReactComponentViewCreator(instanceManager).create(activity, componentId, componentName);
20 21
         return new ComponentLayout(activity, reactView);
21 22
 	}
22 23
 }

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/views/ReactComponent.java Näytä tiedosto

@@ -1,6 +1,6 @@
1 1
 package com.reactnativenavigation.views;
2 2
 
3
-import com.reactnativenavigation.viewcontrollers.ComponentViewController;
3
+import com.reactnativenavigation.viewcontrollers.IReactView;
4 4
 
5
-public interface ReactComponent extends Component, ComponentViewController.IReactView {
5
+public interface ReactComponent extends Component, IReactView {
6 6
 }

+ 5
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/StackLayout.java Näytä tiedosto

@@ -2,6 +2,7 @@ package com.reactnativenavigation.views;
2 2
 
3 3
 import android.content.Context;
4 4
 import android.support.annotation.RestrictTo;
5
+import android.support.v4.view.ViewPager;
5 6
 import android.widget.RelativeLayout;
6 7
 
7 8
 import com.reactnativenavigation.parse.Options;
@@ -43,4 +44,8 @@ public class StackLayout extends RelativeLayout implements TitleBarButton.OnClic
43 44
     public void clearOptions() {
44 45
         topBar.clear();
45 46
     }
47
+
48
+    public void setupTopTabsWithViewPager(ViewPager viewPager) {
49
+        topBar.setupTopTabsWithViewPager(viewPager);
50
+    }
46 51
 }

+ 6
- 4
lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java Näytä tiedosto

@@ -5,6 +5,7 @@ import android.content.Context;
5 5
 import android.graphics.Typeface;
6 6
 import android.support.annotation.Nullable;
7 7
 import android.support.design.widget.AppBarLayout;
8
+import android.support.v4.view.ViewPager;
8 9
 import android.support.v7.widget.Toolbar;
9 10
 import android.util.Log;
10 11
 import android.view.Menu;
@@ -20,7 +21,6 @@ import com.reactnativenavigation.parse.Color;
20 21
 import com.reactnativenavigation.parse.Fraction;
21 22
 import com.reactnativenavigation.parse.Number;
22 23
 import com.reactnativenavigation.parse.Options;
23
-import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsViewPager;
24 24
 
25 25
 import java.util.ArrayList;
26 26
 
@@ -37,6 +37,7 @@ public class TopBar extends AppBarLayout implements ScrollEventListener.ScrollAw
37 37
         this.onClickListener = onClickListener;
38 38
         collapsingBehavior = new TopBarCollapseBehavior(this);
39 39
         titleBar = new Toolbar(context);
40
+        titleBar.getMenu();
40 41
         topTabs = new TopTabs(getContext());
41 42
         this.animator = new TopBarAnimator(this);
42 43
         addView(titleBar);
@@ -146,7 +147,7 @@ public class TopBar extends AppBarLayout implements ScrollEventListener.ScrollAw
146 147
         return titleBar;
147 148
     }
148 149
 
149
-    public void setupTopTabsWithViewPager(TopTabsViewPager viewPager) {
150
+    public void setupTopTabsWithViewPager(ViewPager viewPager) {
150 151
         initTopTabs();
151 152
         topTabs.setupWithViewPager(viewPager);
152 153
     }
@@ -156,8 +157,8 @@ public class TopBar extends AppBarLayout implements ScrollEventListener.ScrollAw
156 157
         addView(topTabs);
157 158
     }
158 159
 
159
-    public void enableCollapse() {
160
-        collapsingBehavior.enableCollapse();
160
+    public void enableCollapse(ScrollEventListener scrollEventListener) {
161
+        collapsingBehavior.enableCollapse(scrollEventListener);
161 162
     }
162 163
 
163 164
     public void disableCollapse() {
@@ -190,5 +191,6 @@ public class TopBar extends AppBarLayout implements ScrollEventListener.ScrollAw
190 191
         titleBar.setTitle(null);
191 192
         titleBar.setNavigationIcon(null);
192 193
         titleBar.getMenu().clear();
194
+        removeView(topTabs);
193 195
     }
194 196
 }

+ 0
- 56
lib/android/app/src/main/java/com/reactnativenavigation/views/TopTab.java Näytä tiedosto

@@ -1,56 +0,0 @@
1
-package com.reactnativenavigation.views;
2
-
3
-import android.annotation.SuppressLint;
4
-import android.content.Context;
5
-import android.view.View;
6
-import android.widget.FrameLayout;
7
-
8
-import com.reactnativenavigation.interfaces.ScrollEventListener;
9
-import com.reactnativenavigation.viewcontrollers.ComponentViewController.IReactView;
10
-
11
-@SuppressLint("ViewConstructor")
12
-public class TopTab extends FrameLayout implements IReactView {
13
-
14
-	private final IReactView reactView;
15
-
16
-	public TopTab(Context context, IReactView reactView) {
17
-		super(context);
18
-		this.reactView = reactView;
19
-        addView(reactView.asView());
20
-	}
21
-
22
-	@Override
23
-	public boolean isReady() {
24
-		return reactView.isReady();
25
-	}
26
-
27
-	@Override
28
-	public View asView() {
29
-		return this;
30
-	}
31
-
32
-	@Override
33
-	public void destroy() {
34
-		reactView.destroy();
35
-	}
36
-
37
-	@Override
38
-	public void sendComponentStart() {
39
-		reactView.sendComponentStart();
40
-	}
41
-
42
-	@Override
43
-	public void sendComponentStop() {
44
-		reactView.sendComponentStop();
45
-	}
46
-
47
-    @Override
48
-    public void sendOnNavigationButtonPressed(String buttonId) {
49
-        reactView.sendOnNavigationButtonPressed(buttonId);
50
-    }
51
-
52
-    @Override
53
-    public ScrollEventListener getScrollEventListener() {
54
-        return reactView.getScrollEventListener();
55
-    }
56
-}

+ 0
- 23
lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabCreator.java Näytä tiedosto

@@ -1,23 +0,0 @@
1
-package com.reactnativenavigation.views;
2
-
3
-import android.app.Activity;
4
-
5
-import com.facebook.react.ReactInstanceManager;
6
-import com.reactnativenavigation.react.ReactComponentViewCreator;
7
-import com.reactnativenavigation.viewcontrollers.ComponentViewController;
8
-
9
-public class TopTabCreator implements ComponentViewController.ReactViewCreator {
10
-
11
-
12
-    private ReactInstanceManager instanceManager;
13
-
14
-    public TopTabCreator(ReactInstanceManager instanceManager) {
15
-        this.instanceManager = instanceManager;
16
-    }
17
-
18
-	@Override
19
-	public ComponentViewController.IReactView create(Activity activity, String componentId, String componentName) {
20
-        ComponentViewController.IReactView reactView = new ReactComponentViewCreator(instanceManager).create(activity, componentId, componentName);
21
-        return new TopTab(activity, reactView);
22
-	}
23
-}

+ 0
- 73
lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsLayout.java Näytä tiedosto

@@ -1,73 +0,0 @@
1
-package com.reactnativenavigation.views;
2
-
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;
10
-
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;
15
-
16
-import java.util.List;
17
-
18
-@SuppressLint("ViewConstructor")
19
-public class TopTabsLayout extends RelativeLayout implements Component, TitleBarButton.OnClickListener {
20
-
21
-    private TopBar topBar;
22
-    private TopTabsViewPager viewPager;
23
-
24
-    public TopTabsLayout(Context context, List<ViewController> tabs, TopTabsAdapter adapter) {
25
-        super(context);
26
-        viewPager = new TopTabsViewPager(context, tabs, adapter);
27
-        topBar = new TopBar(context, this);
28
-        topBar.setId(View.generateViewId());
29
-
30
-        initViews();
31
-    }
32
-
33
-    private void initViews() {
34
-        LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
35
-        layoutParams.addRule(BELOW, topBar.getId());
36
-        addView(topBar, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
37
-        addView(viewPager, layoutParams);
38
-        topBar.setupTopTabsWithViewPager(viewPager);
39
-    }
40
-
41
-    @Override
42
-    public void applyOptions(Options options) {
43
-
44
-    }
45
-
46
-    @Override
47
-    public void drawBehindTopBar() {
48
-
49
-    }
50
-
51
-    @Override
52
-    public void drawBelowTopBar(TopBar topBar) {
53
-
54
-    }
55
-
56
-    @RestrictTo(RestrictTo.Scope.TESTS)
57
-    public ViewPager getViewPager() {
58
-        return viewPager;
59
-    }
60
-
61
-    public void switchToTab(int index) {
62
-        viewPager.setCurrentItem(index);
63
-    }
64
-
65
-    public int getCurrentItem() {
66
-        return viewPager.getCurrentItem();
67
-    }
68
-
69
-    @Override
70
-    public void onPress(String buttonId) {
71
-        viewPager.sendOnNavigationButtonPressed(buttonId);
72
-    }
73
-}

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsLayoutCreator.java Näytä tiedosto

@@ -16,7 +16,7 @@ public class TopTabsLayoutCreator {
16 16
         this.tabs = tabs;
17 17
     }
18 18
 
19
-    public TopTabsLayout create() {
20
-        return new TopTabsLayout(context, tabs, new TopTabsAdapter(tabs));
19
+    public TopTabsViewPager create() {
20
+        return new TopTabsViewPager(context, tabs, new TopTabsAdapter(tabs));
21 21
     }
22 22
 }

+ 83
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/TopTabsViewPager.java Näytä tiedosto

@@ -0,0 +1,83 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.annotation.SuppressLint;
4
+import android.content.Context;
5
+import android.support.v4.view.ViewPager;
6
+import android.view.View;
7
+import android.view.ViewGroup;
8
+import android.widget.RelativeLayout;
9
+
10
+import com.reactnativenavigation.parse.Options;
11
+import com.reactnativenavigation.viewcontrollers.IReactView;
12
+import com.reactnativenavigation.viewcontrollers.ViewController;
13
+import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsAdapter;
14
+
15
+import java.util.List;
16
+
17
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
18
+import static android.widget.RelativeLayout.BELOW;
19
+
20
+@SuppressLint("ViewConstructor")
21
+public class TopTabsViewPager extends ViewPager implements Component, TitleBarButton.OnClickListener {
22
+
23
+    private static final int OFFSCREEN_PAGE_LIMIT = 99;
24
+    private List<ViewController> tabs;
25
+
26
+    public TopTabsViewPager(Context context, List<ViewController> tabs, TopTabsAdapter adapter) {
27
+        super(context);
28
+        this.tabs = tabs;
29
+        initTabs(adapter);
30
+    }
31
+
32
+    private void initTabs(TopTabsAdapter adapter) {
33
+        setOffscreenPageLimit(OFFSCREEN_PAGE_LIMIT);
34
+        for (ViewController tab : tabs) {
35
+            addView(tab.getView(), new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
36
+        }
37
+        setAdapter(adapter);
38
+        addOnPageChangeListener(adapter);
39
+    }
40
+
41
+    @Override
42
+    public void applyOptions(Options options) {
43
+
44
+    }
45
+
46
+    @Override
47
+    public void drawBehindTopBar() {
48
+        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
49
+        layoutParams.removeRule(BELOW);
50
+        setLayoutParams(layoutParams);
51
+    }
52
+
53
+    @Override
54
+    public void drawBelowTopBar(TopBar topBar) {
55
+        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
56
+        layoutParams.addRule(BELOW, topBar.getId());
57
+        setLayoutParams(layoutParams);
58
+    }
59
+
60
+    public void switchToTab(int index) {
61
+        setCurrentItem(index);
62
+    }
63
+
64
+    @Override
65
+    public void onPress(String buttonId) {
66
+        ((IReactView) tabs.get(getCurrentItem()).getView()).sendOnNavigationButtonPressed(buttonId);
67
+    }
68
+
69
+    public void destroy() {
70
+        for (ViewController tab : tabs) {
71
+            tab.destroy();
72
+        }
73
+    }
74
+
75
+    public boolean isCurrentView(View view) {
76
+        for (ViewController tab : tabs) {
77
+            if (tab.getView() == view) {
78
+                return true;
79
+            }
80
+        }
81
+        return false;
82
+    }
83
+}

+ 54
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/touch/OverlayTouchDelegate.java Näytä tiedosto

@@ -0,0 +1,54 @@
1
+package com.reactnativenavigation.views.touch;
2
+
3
+import android.graphics.Rect;
4
+import android.support.annotation.VisibleForTesting;
5
+import android.view.MotionEvent;
6
+import android.view.ViewGroup;
7
+
8
+import com.reactnativenavigation.utils.UiUtils;
9
+import com.reactnativenavigation.viewcontrollers.IReactView;
10
+
11
+public class OverlayTouchDelegate {
12
+    private enum TouchLocation {Outside, Inside}
13
+    private final Rect hitRect = new Rect();
14
+    private IReactView reactView;
15
+    private boolean interceptTouchOutside;
16
+
17
+    public OverlayTouchDelegate(IReactView reactView) {
18
+        this.reactView = reactView;
19
+    }
20
+
21
+    public boolean onInterceptTouchEvent(MotionEvent event) {
22
+        switch (event.getActionMasked()) {
23
+            case MotionEvent.ACTION_DOWN:
24
+                return handleDown(event);
25
+            default:
26
+                reactView.dispatchTouchEventToJs(event);
27
+                return false;
28
+
29
+        }
30
+    }
31
+
32
+    @VisibleForTesting
33
+    public boolean handleDown(MotionEvent event) {
34
+        TouchLocation location = getTouchLocation(event);
35
+        if (location == TouchLocation.Inside) {
36
+            reactView.dispatchTouchEventToJs(event);
37
+        }
38
+        if (interceptTouchOutside) {
39
+            return location == TouchLocation.Inside;
40
+        }
41
+        return location == TouchLocation.Outside;
42
+    }
43
+
44
+    private TouchLocation getTouchLocation(MotionEvent ev) {
45
+        ((ViewGroup) reactView.asView()).getChildAt(0).getHitRect(hitRect);
46
+        return hitRect.contains((int) ev.getRawX(), (int) ev.getRawY() - UiUtils.getStatusBarHeight(reactView.asView().getContext())) ?
47
+                TouchLocation.Inside :
48
+                TouchLocation.Outside;
49
+    }
50
+
51
+    public void setInterceptTouchOutside(boolean interceptTouchOutside) {
52
+        this.interceptTouchOutside = interceptTouchOutside;
53
+    }
54
+}

+ 2
- 2
lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleComponentViewController.java Näytä tiedosto

@@ -6,7 +6,7 @@ import com.reactnativenavigation.parse.*;
6 6
 import com.reactnativenavigation.viewcontrollers.*;
7 7
 
8 8
 public class SimpleComponentViewController extends ComponentViewController {
9
-    public SimpleComponentViewController(final Activity activity, final String id) {
10
-        super(activity, id, "theComponentName", new TestComponentViewCreator(), new Options());
9
+    public SimpleComponentViewController(final Activity activity, final String id, Options initialOptions) {
10
+        super(activity, id, "theComponentName", new TestComponentViewCreator(), initialOptions);
11 11
     }
12 12
 }

+ 59
- 0
lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleOverlay.java Näytä tiedosto

@@ -0,0 +1,59 @@
1
+package com.reactnativenavigation.mocks;
2
+
3
+import android.content.Context;
4
+import android.view.MotionEvent;
5
+import android.view.View;
6
+import android.widget.FrameLayout;
7
+import android.widget.RelativeLayout;
8
+
9
+import com.reactnativenavigation.interfaces.ScrollEventListener;
10
+import com.reactnativenavigation.viewcontrollers.IReactView;
11
+
12
+public class SimpleOverlay extends RelativeLayout implements IReactView {
13
+    public SimpleOverlay(Context context) {
14
+        super(context);
15
+    }
16
+
17
+    @Override
18
+    public boolean isReady() {
19
+        return true;
20
+    }
21
+
22
+    @Override
23
+    public View asView() {
24
+        FrameLayout root = new FrameLayout(getContext());
25
+        FrameLayout overlay = new FrameLayout(getContext());
26
+        root.addView(overlay);
27
+        return root;
28
+    }
29
+
30
+    @Override
31
+    public void destroy() {
32
+
33
+    }
34
+
35
+    @Override
36
+    public void sendComponentStart() {
37
+
38
+    }
39
+
40
+    @Override
41
+    public void sendComponentStop() {
42
+
43
+    }
44
+
45
+    @Override
46
+    public void sendOnNavigationButtonPressed(String buttonId) {
47
+
48
+    }
49
+
50
+    @Override
51
+    public ScrollEventListener getScrollEventListener() {
52
+        return null;
53
+    }
54
+
55
+    @Override
56
+    public void dispatchTouchEventToJs(MotionEvent event) {
57
+
58
+    }
59
+}

+ 77
- 6
lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleViewController.java Näytä tiedosto

@@ -1,23 +1,94 @@
1 1
 package com.reactnativenavigation.mocks;
2 2
 
3
-import android.app.*;
4
-import android.view.*;
3
+import android.app.Activity;
4
+import android.content.Context;
5
+import android.support.annotation.NonNull;
6
+import android.view.MotionEvent;
7
+import android.view.View;
8
+import android.widget.FrameLayout;
5 9
 
6
-import com.reactnativenavigation.viewcontrollers.*;
10
+import com.reactnativenavigation.interfaces.ScrollEventListener;
11
+import com.reactnativenavigation.parse.Options;
12
+import com.reactnativenavigation.viewcontrollers.ViewController;
13
+import com.reactnativenavigation.views.ReactComponent;
14
+import com.reactnativenavigation.views.TopBar;
7 15
 
8
-public class SimpleViewController extends ViewController {
16
+public class SimpleViewController extends ViewController<FrameLayout> {
9 17
 
10 18
     public SimpleViewController(final Activity activity, String id) {
11 19
         super(activity, id);
20
+        options = new Options();
12 21
     }
13 22
 
14 23
     @Override
15
-    protected View createView() {
16
-        return new View(getActivity());
24
+    protected FrameLayout createView() {
25
+        return new SimpleView(getActivity());
17 26
     }
18 27
 
19 28
     @Override
20 29
     public String toString() {
21 30
         return "SimpleViewController " + getId();
22 31
     }
32
+
33
+    public class SimpleView extends FrameLayout implements ReactComponent {
34
+
35
+        public SimpleView(@NonNull Context context) {
36
+            super(context);
37
+        }
38
+
39
+        @Override
40
+        public void applyOptions(Options options) {
41
+
42
+        }
43
+
44
+        @Override
45
+        public void drawBehindTopBar() {
46
+
47
+        }
48
+
49
+        @Override
50
+        public void drawBelowTopBar(TopBar topBar) {
51
+
52
+        }
53
+
54
+        @Override
55
+        public boolean isReady() {
56
+            return false;
57
+        }
58
+
59
+        @Override
60
+        public View asView() {
61
+            return null;
62
+        }
63
+
64
+        @Override
65
+        public void destroy() {
66
+
67
+        }
68
+
69
+        @Override
70
+        public void sendComponentStart() {
71
+
72
+        }
73
+
74
+        @Override
75
+        public void sendComponentStop() {
76
+
77
+        }
78
+
79
+        @Override
80
+        public void sendOnNavigationButtonPressed(String buttonId) {
81
+
82
+        }
83
+
84
+        @Override
85
+        public ScrollEventListener getScrollEventListener() {
86
+            return null;
87
+        }
88
+
89
+        @Override
90
+        public void dispatchTouchEventToJs(MotionEvent event) {
91
+
92
+        }
93
+    }
23 94
 }

+ 15
- 23
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestComponentLayout.java Näytä tiedosto

@@ -1,39 +1,24 @@
1 1
 package com.reactnativenavigation.mocks;
2 2
 
3 3
 import android.content.Context;
4
+import android.view.MotionEvent;
4 5
 import android.view.View;
5
-import android.view.ViewGroup;
6
-import android.widget.RelativeLayout;
7 6
 
8 7
 import com.reactnativenavigation.interfaces.ScrollEventListener;
9 8
 import com.reactnativenavigation.parse.Options;
10
-import com.reactnativenavigation.views.ReactComponent;
9
+import com.reactnativenavigation.viewcontrollers.IReactView;
10
+import com.reactnativenavigation.views.ComponentLayout;
11 11
 import com.reactnativenavigation.views.TitleBarButton;
12
-import com.reactnativenavigation.views.TopBar;
13 12
 
14
-public class TestComponentLayout extends RelativeLayout implements ReactComponent, TitleBarButton.OnClickListener {
13
+public class TestComponentLayout extends ComponentLayout implements TitleBarButton.OnClickListener {
15 14
 
16
-    private final View contentView;
15
+    private IReactView reactView;
17 16
 
18
-    public TestComponentLayout(final Context context) {
19
-        super(context);
20
-        contentView = new View(context);
21
-        addView(contentView);
17
+    public TestComponentLayout(final Context context, IReactView reactView) {
18
+        super(context, reactView);
19
+        this.reactView = reactView;
22 20
     }
23 21
 
24
-    @Override
25
-    public void drawBehindTopBar() {
26
-        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
27
-        layoutParams.removeRule(BELOW);
28
-        contentView.setLayoutParams(layoutParams);
29
-    }
30
-
31
-    @Override
32
-    public void drawBelowTopBar(TopBar topBar) {
33
-        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
34
-        layoutParams.addRule(BELOW, topBar.getId());
35
-        contentView.setLayoutParams(layoutParams);
36
-    }
37 22
 
38 23
     @Override
39 24
     public boolean isReady() {
@@ -51,10 +36,12 @@ public class TestComponentLayout extends RelativeLayout implements ReactComponen
51 36
 
52 37
     @Override
53 38
     public void sendComponentStart() {
39
+        reactView.sendComponentStart();
54 40
     }
55 41
 
56 42
     @Override
57 43
     public void sendComponentStop() {
44
+        reactView.sendComponentStop();
58 45
     }
59 46
 
60 47
     @Override
@@ -72,6 +59,11 @@ public class TestComponentLayout extends RelativeLayout implements ReactComponen
72 59
         return null;
73 60
     }
74 61
 
62
+    @Override
63
+    public void dispatchTouchEventToJs(MotionEvent event) {
64
+
65
+    }
66
+
75 67
     @Override
76 68
     public void onPress(String buttonId) {
77 69
 

+ 10
- 5
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestComponentViewCreator.java Näytä tiedosto

@@ -1,13 +1,18 @@
1 1
 package com.reactnativenavigation.mocks;
2 2
 
3
-import android.app.*;
3
+import android.app.Activity;
4 4
 
5
-import com.reactnativenavigation.viewcontrollers.*;
6
-import com.reactnativenavigation.viewcontrollers.ComponentViewController.*;
5
+import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
6
+import com.reactnativenavigation.viewcontrollers.IReactView;
7
+import com.reactnativenavigation.views.ComponentLayout;
8
+import com.reactnativenavigation.views.ReactComponent;
9
+
10
+import static org.mockito.Mockito.spy;
7 11
 
8 12
 public class TestComponentViewCreator implements ReactViewCreator {
9 13
     @Override
10
-    public ComponentViewController.IReactView create(final Activity activity, final String componentId, final String componentName) {
11
-        return new TestComponentLayout(activity);
14
+    public ReactComponent create(final Activity activity, final String componentId, final String componentName) {
15
+        IReactView reactView = spy(new TestReactView(activity));
16
+        return new ComponentLayout(activity, reactView);
12 17
     }
13 18
 }

+ 57
- 0
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestReactView.java Näytä tiedosto

@@ -0,0 +1,57 @@
1
+package com.reactnativenavigation.mocks;
2
+
3
+import android.content.Context;
4
+import android.support.annotation.NonNull;
5
+import android.view.MotionEvent;
6
+import android.view.View;
7
+import android.widget.FrameLayout;
8
+
9
+import com.reactnativenavigation.interfaces.ScrollEventListener;
10
+import com.reactnativenavigation.viewcontrollers.IReactView;
11
+
12
+public class TestReactView extends FrameLayout implements IReactView {
13
+
14
+    public TestReactView(@NonNull Context context) {
15
+        super(context);
16
+    }
17
+
18
+    @Override
19
+    public boolean isReady() {
20
+        return false;
21
+    }
22
+
23
+    @Override
24
+    public View asView() {
25
+        return this;
26
+    }
27
+
28
+    @Override
29
+    public void destroy() {
30
+
31
+    }
32
+
33
+    @Override
34
+    public void sendComponentStart() {
35
+
36
+    }
37
+
38
+    @Override
39
+    public void sendComponentStop() {
40
+
41
+    }
42
+
43
+    @Override
44
+    public void sendOnNavigationButtonPressed(String buttonId) {
45
+
46
+    }
47
+
48
+    @Override
49
+    public ScrollEventListener getScrollEventListener() {
50
+        return null;
51
+    }
52
+
53
+    @Override
54
+    public void dispatchTouchEventToJs(MotionEvent event) {
55
+
56
+    }
57
+}

+ 24
- 2
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TopTabLayoutMock.java Näytä tiedosto

@@ -4,9 +4,11 @@ import android.content.*;
4 4
 import android.view.*;
5 5
 
6 6
 import com.reactnativenavigation.interfaces.ScrollEventListener;
7
-import com.reactnativenavigation.viewcontrollers.*;
7
+import com.reactnativenavigation.parse.Options;
8
+import com.reactnativenavigation.views.ReactComponent;
9
+import com.reactnativenavigation.views.TopBar;
8 10
 
9
-public class TopTabLayoutMock extends View implements ComponentViewController.IReactView {
11
+public class TopTabLayoutMock extends View implements ReactComponent {
10 12
 
11 13
     public TopTabLayoutMock(Context context) {
12 14
         super(context);
@@ -46,4 +48,24 @@ public class TopTabLayoutMock extends View implements ComponentViewController.IR
46 48
     public ScrollEventListener getScrollEventListener() {
47 49
         return null;
48 50
     }
51
+
52
+    @Override
53
+    public void dispatchTouchEventToJs(MotionEvent event) {
54
+
55
+    }
56
+
57
+    @Override
58
+    public void applyOptions(Options options) {
59
+
60
+    }
61
+
62
+    @Override
63
+    public void drawBehindTopBar() {
64
+
65
+    }
66
+
67
+    @Override
68
+    public void drawBelowTopBar(TopBar topBar) {
69
+
70
+    }
49 71
 }

+ 0
- 47
lib/android/app/src/test/java/com/reactnativenavigation/parse/OverlayOptionsTest.java Näytä tiedosto

@@ -1,47 +0,0 @@
1
-package com.reactnativenavigation.parse;
2
-
3
-import android.graphics.Color;
4
-
5
-import com.reactnativenavigation.*;
6
-
7
-import org.json.*;
8
-import org.junit.*;
9
-
10
-import static org.assertj.core.api.Java6Assertions.*;
11
-
12
-public class OverlayOptionsTest extends BaseTest {
13
-
14
-    @Test
15
-    public void parsesNullAsDefaultEmptyOptions() throws Exception {
16
-        assertThat(OverlayOptions.parse(null)).isNotNull();
17
-    }
18
-
19
-    @Test
20
-    public void parsesJson() throws Exception {
21
-        JSONObject json = new JSONObject();
22
-        json.put("title", "the title");
23
-        json.put("text", "the text");
24
-        JSONObject nestedButton = new JSONObject();
25
-        nestedButton.put("text", "OK");
26
-        nestedButton.put("action", "action");
27
-        json.put("positiveButton", nestedButton);
28
-        json.put("textColor", Color.RED);
29
-        json.put("duration", "short");
30
-        json.put("backgroundColor", Color.RED);
31
-
32
-        OverlayOptions result = OverlayOptions.parse(json);
33
-        assertThat(result.getTitle()).isEqualTo("the title");
34
-        assertThat(result.getText()).isEqualTo("the text");
35
-        assertThat(result.getPositiveButton().getText()).isEqualTo("OK");
36
-        assertThat(result.getPositiveButton().getAction()).isEqualTo("action");
37
-        assertThat(result.getTextColor()).isEqualTo(Color.RED);
38
-        assertThat(result.getDuration()).isEqualTo("short");
39
-        assertThat(result.getBackgroundColor()).isEqualTo(Color.RED);
40
-    }
41
-
42
-    @Test
43
-    public void defaultEmptyOptions() throws Exception {
44
-        OverlayOptions uut = new OverlayOptions();
45
-        assertThat(uut.getTitle()).isEmpty();
46
-    }
47
-}

+ 5
- 4
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ComponentViewControllerTest.java Näytä tiedosto

@@ -4,6 +4,7 @@ import android.app.Activity;
4 4
 
5 5
 import com.reactnativenavigation.BaseTest;
6 6
 import com.reactnativenavigation.mocks.TestComponentLayout;
7
+import com.reactnativenavigation.mocks.TestReactView;
7 8
 import com.reactnativenavigation.parse.Options;
8 9
 import com.reactnativenavigation.views.StackLayout;
9 10
 
@@ -17,15 +18,14 @@ import static org.mockito.Mockito.when;
17 18
 
18 19
 public class ComponentViewControllerTest extends BaseTest {
19 20
     private ComponentViewController uut;
20
-    private ParentController<StackLayout> parentController;
21
-    private ComponentViewController.IReactView view;
21
+    private IReactView view;
22 22
 
23 23
     @Override
24 24
     public void beforeEach() {
25 25
         super.beforeEach();
26 26
         Activity activity = newActivity();
27
-        view = spy(new TestComponentLayout(activity));
28
-        parentController = new StackController(activity, "stack");
27
+        view = spy(new TestComponentLayout(activity, new TestReactView(activity)));
28
+        ParentController<StackLayout> parentController = new StackController(activity, "stack");
29 29
         uut = new ComponentViewController(activity, "componentId1", "componentName", (activity1, componentId, componentName) -> view, new Options());
30 30
         uut.setParentController(parentController);
31 31
         parentController.ensureViewIsCreated();
@@ -40,6 +40,7 @@ public class ComponentViewControllerTest extends BaseTest {
40 40
     public void componentViewDestroyedOnDestroy() throws Exception {
41 41
         uut.ensureViewIsCreated();
42 42
         verify(view, times(0)).destroy();
43
+        uut.onViewAppeared();
43 44
         uut.destroy();
44 45
         verify(view, times(1)).destroy();
45 46
     }

+ 1
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java Näytä tiedosto

@@ -204,7 +204,7 @@ public class NavigatorTest extends BaseTest {
204 204
 
205 205
     @Test
206 206
     public void setOptions_CallsApplyNavigationOptions() {
207
-        ComponentViewController componentVc = new SimpleComponentViewController(activity, "theId");
207
+        ComponentViewController componentVc = new SimpleComponentViewController(activity, "theId", new Options());
208 208
         componentVc.setParentController(parentController);
209 209
         assertThat(componentVc.getOptions().topBarOptions.title.get("")).isEmpty();
210 210
         uut.setRoot(componentVc, new MockPromise());

+ 13
- 4
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java Näytä tiedosto

@@ -10,6 +10,7 @@ import android.widget.RelativeLayout;
10 10
 import com.reactnativenavigation.BaseTest;
11 11
 import com.reactnativenavigation.mocks.MockPromise;
12 12
 import com.reactnativenavigation.mocks.TestComponentLayout;
13
+import com.reactnativenavigation.mocks.TestReactView;
13 14
 import com.reactnativenavigation.parse.Fraction;
14 15
 import com.reactnativenavigation.parse.Options;
15 16
 import com.reactnativenavigation.parse.Text;
@@ -18,6 +19,7 @@ import org.junit.Test;
18 19
 
19 20
 import javax.annotation.Nullable;
20 21
 
22
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
21 23
 import static android.widget.RelativeLayout.BELOW;
22 24
 import static org.assertj.core.api.Java6Assertions.assertThat;
23 25
 import static org.mockito.Mockito.spy;
@@ -26,7 +28,7 @@ public class OptionsApplyingTest extends BaseTest {
26 28
     private Activity activity;
27 29
     private StackController stackController;
28 30
     private ComponentViewController uut;
29
-    private ComponentViewController.IReactView view;
31
+    private IReactView view;
30 32
     private Options initialNavigationOptions;
31 33
 
32 34
     @Override
@@ -34,7 +36,8 @@ public class OptionsApplyingTest extends BaseTest {
34 36
         super.beforeEach();
35 37
         activity = newActivity();
36 38
         initialNavigationOptions = new Options();
37
-        view = spy(new TestComponentLayout(activity));
39
+        view = spy(new TestComponentLayout(activity, new TestReactView(activity)));
40
+        view.asView().setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
38 41
         uut = new ComponentViewController(activity,
39 42
                 "componentId1",
40 43
                 "componentName",
@@ -49,9 +52,10 @@ public class OptionsApplyingTest extends BaseTest {
49 52
     @Test
50 53
     public void applyNavigationOptionsHandlesNoParentStack() throws Exception {
51 54
         uut.setParentController(null);
52
-        assertThat(uut.getParentStackController()).isNull();
55
+        assertThat(uut.getParentController()).isNull();
56
+        uut.ensureViewIsCreated();
53 57
         uut.onViewAppeared();
54
-        assertThat(uut.getParentStackController()).isNull();
58
+        assertThat(uut.getParentController()).isNull();
55 59
     }
56 60
 
57 61
     @Test
@@ -79,6 +83,7 @@ public class OptionsApplyingTest extends BaseTest {
79 83
 
80 84
     @Test
81 85
     public void reappliesOptionsOnMerge() throws Exception {
86
+        uut.ensureViewIsCreated();
82 87
         uut.onViewAppeared();
83 88
         assertThat(stackController.getTopBar().getTitle()).isEmpty();
84 89
 
@@ -91,6 +96,7 @@ public class OptionsApplyingTest extends BaseTest {
91 96
 
92 97
     @Test
93 98
     public void appliesTopBackBackgroundColor() throws Exception {
99
+        uut.ensureViewIsCreated();
94 100
         uut.onViewAppeared();
95 101
 
96 102
         Options opts = new Options();
@@ -122,6 +128,7 @@ public class OptionsApplyingTest extends BaseTest {
122 128
     public void appliesTopBarTextSize() throws Exception {
123 129
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
124 130
         initialNavigationOptions.topBarOptions.title = new Text("the title");
131
+        uut.ensureViewIsCreated();
125 132
         uut.onViewAppeared();
126 133
 
127 134
         Options opts = new Options();
@@ -137,6 +144,7 @@ public class OptionsApplyingTest extends BaseTest {
137 144
     public void appliesTopBarHidden() throws Exception {
138 145
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
139 146
         initialNavigationOptions.topBarOptions.title = new Text("the title");
147
+        uut.ensureViewIsCreated();
140 148
         uut.onViewAppeared();
141 149
         assertThat(stackController.getTopBar().getVisibility()).isNotEqualTo(View.GONE);
142 150
 
@@ -152,6 +160,7 @@ public class OptionsApplyingTest extends BaseTest {
152 160
         assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
153 161
         initialNavigationOptions.topBarOptions.title = new Text("the title");
154 162
         initialNavigationOptions.topBarOptions.drawBehind = Options.BooleanOptions.False;
163
+        uut.ensureViewIsCreated();
155 164
         uut.onViewAppeared();
156 165
         stackController.animatePush(uut, new MockPromise() {
157 166
             @Override

+ 10
- 0
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java Näytä tiedosto

@@ -84,4 +84,14 @@ public class ParentControllerTest extends BaseTest {
84 84
         uut.destroy();
85 85
         verify(child1, times(1)).destroy();
86 86
     }
87
+
88
+    @Test
89
+    public void optionsAreClearedWhenChildIsAppeared() throws Exception {
90
+        StackController stackController = spy(new StackController(activity, "stack"));
91
+        SimpleViewController child1 = new SimpleViewController(activity, "child1");
92
+        stackController.animatePush(child1, new MockPromise());
93
+
94
+        child1.onViewAppeared();
95
+        verify(stackController, times(1)).clearOptions();
96
+    }
87 97
 }

+ 3
- 3
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java Näytä tiedosto

@@ -80,13 +80,13 @@ public class StackControllerTest extends BaseTest {
80 80
 
81 81
     @Test
82 82
     public void pushAssignsRefToSelfOnPushedController() throws Exception {
83
-        assertThat(child1.getParentStackController()).isNull();
83
+        assertThat(child1.getParentController()).isNull();
84 84
         uut.animatePush(child1, new MockPromise());
85
-        assertThat(child1.getParentStackController()).isEqualTo(uut);
85
+        assertThat(child1.getParentController()).isEqualTo(uut);
86 86
 
87 87
         StackController anotherNavController = new StackController(activity, "another");
88 88
         anotherNavController.animatePush(child2, new MockPromise());
89
-        assertThat(child2.getParentStackController()).isEqualTo(anotherNavController);
89
+        assertThat(child2.getParentController()).isEqualTo(anotherNavController);
90 90
     }
91 91
 
92 92
     @Test

+ 0
- 51
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabControllerTest.java Näytä tiedosto

@@ -1,51 +0,0 @@
1
-package com.reactnativenavigation.viewcontrollers;
2
-
3
-import android.app.*;
4
-
5
-import com.reactnativenavigation.*;
6
-import com.reactnativenavigation.mocks.*;
7
-import com.reactnativenavigation.parse.*;
8
-import com.reactnativenavigation.viewcontrollers.toptabs.*;
9
-
10
-import org.junit.*;
11
-
12
-import static org.mockito.Mockito.*;
13
-
14
-public class TopTabControllerTest extends BaseTest {
15
-    private TopTabController uut;
16
-    private TopTabLayoutMock view;
17
-    private ParentController parentController;
18
-    private Options initialOptions;
19
-
20
-    @Override
21
-    public void beforeEach() {
22
-        super.beforeEach();
23
-        Activity activity = newActivity();
24
-        view = spy(new TopTabLayoutMock(activity));
25
-        initialOptions = new Options();
26
-        uut = new TopTabController(activity,
27
-                "componentId",
28
-                "componentName",
29
-                (activity1, componentId, componentName) -> view,
30
-                initialOptions
31
-        );
32
-        parentController = spy(new TopTabsControllerMock(activity, "parentComponentId"));
33
-        uut.setParentController(parentController);
34
-    }
35
-
36
-    @Test
37
-    public void styleIsAppliedOnParentControllerWhenTabIsVisible() throws Exception {
38
-        uut.ensureViewIsCreated();
39
-        uut.onViewAppeared();
40
-        verify(parentController, times(1)).applyOptions(initialOptions);
41
-    }
42
-
43
-    @Test
44
-    public void styleIsAppliedOnParentControllerWhenOptionsAreSetDynamically() throws Exception {
45
-        uut.ensureViewIsCreated();
46
-        uut.onViewAppeared();
47
-        uut.mergeOptions(new Options());
48
-        verify(parentController, times(2)).applyOptions(initialOptions);
49
-    }
50
-
51
-}

+ 101
- 52
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java Näytä tiedosto

@@ -1,67 +1,90 @@
1 1
 package com.reactnativenavigation.viewcontrollers;
2 2
 
3
-import android.app.*;
4
-import android.view.*;
5
-
6
-import com.reactnativenavigation.*;
7
-import com.reactnativenavigation.mocks.*;
8
-import com.reactnativenavigation.parse.*;
9
-import com.reactnativenavigation.viewcontrollers.ComponentViewController.*;
10
-import com.reactnativenavigation.viewcontrollers.toptabs.*;
11
-import com.reactnativenavigation.views.*;
12
-
13
-import org.junit.*;
14
-import org.mockito.*;
15
-
16
-import java.util.*;
17
-
18
-import static org.mockito.Mockito.*;
3
+import android.app.Activity;
4
+import android.support.annotation.NonNull;
5
+import android.view.ViewGroup;
6
+
7
+import com.reactnativenavigation.BaseTest;
8
+import com.reactnativenavigation.mocks.TestComponentViewCreator;
9
+import com.reactnativenavigation.mocks.TestReactView;
10
+import com.reactnativenavigation.parse.Options;
11
+import com.reactnativenavigation.parse.Text;
12
+import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsAdapter;
13
+import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsController;
14
+import com.reactnativenavigation.views.ReactComponent;
15
+import com.reactnativenavigation.views.TopTabsLayoutCreator;
16
+import com.reactnativenavigation.views.TopTabsViewPager;
17
+
18
+import org.junit.Test;
19
+import org.mockito.Mockito;
20
+
21
+import java.util.ArrayList;
22
+import java.util.List;
23
+
24
+import static org.mockito.Mockito.spy;
25
+import static org.mockito.Mockito.times;
26
+import static org.mockito.Mockito.verify;
19 27
 
20 28
 public class TopTabsViewControllerTest extends BaseTest {
21 29
 
22 30
     private static final int SIZE = 2;
23 31
 
32
+    private StackController parentController;
24 33
     private TopTabsController uut;
25
-    private List<TopTabLayoutMock> tabs = new ArrayList<>(SIZE);
26 34
     private List<ViewController> tabControllers = new ArrayList<>(SIZE);
27 35
     private List<Options> tabOptions = new ArrayList<>(SIZE);
28
-    private Options options;
29
-    private TopTabsLayout topTabsLayout;
36
+    private final Options options = new Options();
37
+    private TopTabsViewPager topTabsLayout;
30 38
 
31 39
     @Override
32 40
     public void beforeEach() {
33 41
         super.beforeEach();
34
-        tabControllers.clear();
35
-        tabs.clear();
36
-        Activity activity = newActivity();
37
-        tabControllers = createTabs(activity);
38
-        options = new Options();
39
-        topTabsLayout = spy(new TopTabsLayout(activity, tabControllers, new TopTabsAdapter(tabControllers)));
40 42
 
43
+        final Activity activity = newActivity();
44
+        tabOptions = createOptions();
45
+        tabControllers = createTabsControllers(activity);
46
+
47
+        topTabsLayout = spy(new TopTabsViewPager(activity, tabControllers, new TopTabsAdapter(tabControllers)));
41 48
         TopTabsLayoutCreator layoutCreator = Mockito.mock(TopTabsLayoutCreator.class);
42 49
         Mockito.when(layoutCreator.create()).thenReturn(topTabsLayout);
43
-        uut = new TopTabsController(activity, "componentId", tabControllers, layoutCreator, options);
50
+        uut = spy(new TopTabsController(activity, "componentId", tabControllers, layoutCreator, options));
51
+        tabControllers.forEach(viewController -> viewController.setParentController(uut));
52
+
53
+        parentController = spy(new StackController(activity, "stackId"));
54
+        uut.setParentController(parentController);
44 55
     }
45 56
 
46
-    private List<ViewController> createTabs(Activity activity) {
47
-        List<ViewController> result = new ArrayList<>(SIZE);
48
-        tabOptions = new ArrayList<>();
57
+    @NonNull
58
+    private ArrayList<Options> createOptions() {
59
+        ArrayList result = new ArrayList();
49 60
         for (int i = 0; i < SIZE; i++) {
50
-            TopTabLayoutMock reactView = spy(new TopTabLayoutMock(activity));
51
-            tabs.add(reactView);
52
-            Options options = new Options();
61
+            final Options options = new Options();
53 62
             options.topTabOptions.title = new Text("Tab " + i);
54
-            tabOptions.add(options);
55
-            result.add(spy(new TopTabController(activity,
56
-                    "idTab" + i,
57
-                    "tab" + i,
58
-                    (activity1, componentId, componentName) -> reactView,
59
-                    options)
60
-            ));
63
+            options.topBarOptions.title = new Text("Title " + i);
64
+            result.add(options);
61 65
         }
62 66
         return result;
63 67
     }
64 68
 
69
+    private List<ViewController> createTabsControllers(Activity activity) {
70
+        List<ViewController> tabControllers = new ArrayList<>(SIZE);
71
+        for (int i = 0; i < SIZE; i++) {
72
+            ComponentViewController viewController = new ComponentViewController(
73
+                    activity,
74
+                    "idTab" + i,
75
+                    "theComponentName",
76
+                    new TestComponentViewCreator(),
77
+                    tabOptions.get(i)
78
+            );
79
+            tabControllers.add(spy(viewController));
80
+        }
81
+        return tabControllers;
82
+    }
83
+
84
+    private ReactComponent tabView(int index) {
85
+        return (ReactComponent) tabControllers.get(index).getView();
86
+    }
87
+
65 88
     @Test
66 89
     public void createsViewFromComponentViewCreator() throws Exception {
67 90
         uut.ensureViewIsCreated();
@@ -73,7 +96,7 @@ public class TopTabsViewControllerTest extends BaseTest {
73 96
     @Test
74 97
     public void componentViewDestroyedOnDestroy() throws Exception {
75 98
         uut.ensureViewIsCreated();
76
-        TopTabsLayout topTabs = (TopTabsLayout) uut.getView();
99
+        TopTabsViewPager topTabs = uut.getView();
77 100
         for (int i = 0; i < SIZE; i++) {
78 101
             verify(tab(topTabs, i), times(0)).destroy();
79 102
         }
@@ -85,10 +108,18 @@ public class TopTabsViewControllerTest extends BaseTest {
85 108
 
86 109
     @Test
87 110
     public void lifecycleMethodsSentWhenSelectedTabChanges() throws Exception {
111
+        parentController.ensureViewIsCreated();
88 112
         uut.ensureViewIsCreated();
89
-        TopTabLayoutMock initialTab = tabs.get(0);
90
-        TopTabLayoutMock selectedTab = tabs.get(1);
113
+        tabControllers.get(0).ensureViewIsCreated();
114
+        tabControllers.get(1).ensureViewIsCreated();
115
+
116
+        tabControllers.get(0).onViewAppeared();
117
+
91 118
         uut.onViewAppeared();
119
+
120
+        TestReactView initialTab = getActualTabView(0);
121
+        TestReactView selectedTab = getActualTabView(1);
122
+
92 123
         uut.switchToTab(1);
93 124
         verify(initialTab, times(1)).sendComponentStop();
94 125
         verify(selectedTab, times(1)).sendComponentStart();
@@ -97,42 +128,60 @@ public class TopTabsViewControllerTest extends BaseTest {
97 128
 
98 129
     @Test
99 130
     public void lifecycleMethodsSentWhenSelectedPreviouslySelectedTab() throws Exception {
131
+        parentController.ensureViewIsCreated();
100 132
         uut.ensureViewIsCreated();
101 133
         uut.onViewAppeared();
102 134
         uut.switchToTab(1);
103 135
         uut.switchToTab(0);
104
-        verify(tabs.get(0), times(1)).sendComponentStop();
105
-        verify(tabs.get(0), times(2)).sendComponentStart();
106
-        verify(tabs.get(1), times(1)).sendComponentStart();
107
-        verify(tabs.get(1), times(1)).sendComponentStop();
136
+
137
+        verify(getActualTabView(0), times(1)).sendComponentStop();
138
+        verify(getActualTabView(0), times(2)).sendComponentStart();
139
+        verify(getActualTabView(1), times(1)).sendComponentStart();
140
+        verify(getActualTabView(1), times(1)).sendComponentStop();
108 141
     }
109 142
 
110 143
     @Test
111 144
     public void setOptionsOfInitialTab() throws Exception {
145
+        parentController.ensureViewIsCreated();
112 146
         uut.ensureViewIsCreated();
113 147
         uut.onViewAppeared();
114
-        verify(tabControllers.get(0), times(1)).applyOptions(tabOptions.get(0));
148
+        verify(tabControllers.get(0), times(1)).onViewAppeared();
149
+        verify(tabControllers.get(1), times(0)).onViewAppeared();
150
+
151
+        verify(uut, times(1)).applyOptions(tabOptions.get(0), ((ComponentViewController) tabControllers.get(0)).getComponent());
115 152
     }
116 153
 
117 154
     @Test
118 155
     public void setOptionsWhenTabChanges() throws Exception {
156
+        parentController.ensureViewIsCreated();
119 157
         uut.ensureViewIsCreated();
158
+        tabControllers.get(0).ensureViewIsCreated();
159
+        tabControllers.get(1).ensureViewIsCreated();
160
+
120 161
         uut.onViewAppeared();
121
-        verify(tabControllers.get(0), times(1)).applyOptions(tabOptions.get(0));
162
+        verify(uut, times(1)).applyOptions(tabOptions.get(0), tabView(0));
122 163
         uut.switchToTab(1);
123
-        verify(tabControllers.get(1), times(1)).applyOptions(tabOptions.get(1));
164
+        verify(uut, times(1)).applyOptions(tabOptions.get(1), tabView(1));
124 165
         uut.switchToTab(0);
125
-        verify(tabControllers.get(0), times(2)).applyOptions(tabOptions.get(0));
166
+        verify(uut, times(2)).applyOptions(tabOptions.get(0), tabView(0));
167
+    }
168
+
169
+    private TestReactView getActualTabView(int index) {
170
+        return (TestReactView) tabControllers.get(index).getView().getChildAt(0);
126 171
     }
127 172
 
128 173
     @Test
129 174
     public void appliesOptionsOnLayoutWhenVisible() throws Exception {
175
+        tabControllers.get(0).ensureViewIsCreated();
176
+        parentController.ensureViewIsCreated();
130 177
         uut.ensureViewIsCreated();
178
+
131 179
         uut.onViewAppeared();
180
+
132 181
         verify(topTabsLayout, times(1)).applyOptions(options);
133 182
     }
134 183
 
135
-    private IReactView tab(TopTabsLayout topTabs, final int index) {
136
-        return (IReactView) ((ViewGroup) topTabs.getViewPager().getChildAt(index)).getChildAt(0);
184
+    private IReactView tab(TopTabsViewPager topTabs, final int index) {
185
+        return (IReactView) ((ViewGroup) topTabs.getChildAt(index)).getChildAt(0);
137 186
     }
138 187
 }

+ 5
- 4
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ViewControllerTest.java Näytä tiedosto

@@ -3,6 +3,7 @@ package com.reactnativenavigation.viewcontrollers;
3 3
 import android.app.Activity;
4 4
 import android.view.View;
5 5
 import android.view.ViewParent;
6
+import android.widget.FrameLayout;
6 7
 import android.widget.LinearLayout;
7 8
 
8 9
 import com.reactnativenavigation.BaseTest;
@@ -45,10 +46,10 @@ public class ViewControllerTest extends BaseTest {
45 46
 
46 47
     @Test
47 48
     public void canOverrideViewCreation() throws Exception {
48
-        final View otherView = new View(activity);
49
+        final FrameLayout otherView = new FrameLayout(activity);
49 50
         ViewController myController = new ViewController(activity, "vc") {
50 51
             @Override
51
-            protected View createView() {
52
+            protected FrameLayout createView() {
52 53
                 return otherView;
53 54
             }
54 55
         };
@@ -57,10 +58,10 @@ public class ViewControllerTest extends BaseTest {
57 58
 
58 59
     @Test
59 60
     public void holdsAReferenceToStackControllerOrNull() throws Exception {
60
-        assertThat(uut.getParentStackController()).isNull();
61
+        assertThat(uut.getParentController()).isNull();
61 62
         StackController nav = new StackController(activity, "stack");
62 63
         nav.animatePush(uut, new MockPromise());
63
-        assertThat(uut.getParentStackController()).isEqualTo(nav);
64
+        assertThat(uut.getParentController()).isEqualTo(nav);
64 65
     }
65 66
 
66 67
     @Test

+ 57
- 0
lib/android/app/src/test/java/com/reactnativenavigation/views/TouchDelegateTest.java Näytä tiedosto

@@ -0,0 +1,57 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.view.MotionEvent;
4
+
5
+import com.reactnativenavigation.BaseTest;
6
+import com.reactnativenavigation.mocks.SimpleOverlay;
7
+import com.reactnativenavigation.views.touch.OverlayTouchDelegate;
8
+
9
+import org.junit.Test;
10
+
11
+import static org.assertj.core.api.Assertions.assertThat;
12
+import static org.mockito.Mockito.spy;
13
+import static org.mockito.Mockito.times;
14
+import static org.mockito.Mockito.verify;
15
+
16
+public class TouchDelegateTest extends BaseTest {
17
+    private OverlayTouchDelegate uut;
18
+    private final int x = 10;
19
+    private final int y = 10;
20
+    private final MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, x, y, 0);
21
+    private final MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, x, y, 0);
22
+    private SimpleOverlay reactView;
23
+
24
+    @Override
25
+    public void beforeEach() {
26
+        super.beforeEach();
27
+        reactView = spy(new SimpleOverlay(newActivity()));
28
+        uut = spy(new OverlayTouchDelegate(reactView));
29
+    }
30
+
31
+    @Test
32
+    public void downEventIsHandled() throws Exception {
33
+        uut.setInterceptTouchOutside(true);
34
+        uut.onInterceptTouchEvent(downEvent);
35
+        verify(uut, times(1)).handleDown(downEvent);
36
+    }
37
+
38
+    @Test
39
+    public void onlyDownEventIsHandled() throws Exception {
40
+        uut.setInterceptTouchOutside(true);
41
+        uut.onInterceptTouchEvent(upEvent);
42
+        verify(uut, times(0)).handleDown(upEvent);
43
+    }
44
+
45
+    @Test
46
+    public void nonDownEventsDontIntercept() throws Exception {
47
+        uut.setInterceptTouchOutside(true);
48
+        assertThat(uut.onInterceptTouchEvent(upEvent)).isFalse();
49
+    }
50
+
51
+    @Test
52
+    public void nonDownEventsDispatchTouchEventsToJs() throws Exception {
53
+        uut.setInterceptTouchOutside(true);
54
+        uut.onInterceptTouchEvent(upEvent);
55
+        verify(reactView, times(1)).dispatchTouchEventToJs(upEvent);
56
+    }
57
+}

+ 0
- 6
lib/ios/RNNBottomTabOptions.m Näytä tiedosto

@@ -34,12 +34,6 @@
34 34
 	[self resetOptions];
35 35
 }
36 36
 
37
--(void)mergeWith:(NSDictionary *)otherOptions {
38
-	for (id key in otherOptions) {
39
-		[self setValue:[otherOptions objectForKey:key] forKey:key];
40
-	}
41
-}
42
-
43 37
 -(void)resetOptions {
44 38
 	self.title = nil;
45 39
 	self.badge = nil;

+ 8
- 0
lib/ios/RNNBottomTabsOptions.h Näytä tiedosto

@@ -9,4 +9,12 @@
9 9
 @property (nonatomic, strong) NSNumber* drawUnder;
10 10
 @property (nonatomic, strong) NSString* currentTabId;
11 11
 
12
+@property (nonatomic, strong) NSNumber* translucent;
13
+@property (nonatomic, strong) NSNumber* hideShadow;
14
+@property (nonatomic, strong) NSNumber* backgroundColor;
15
+@property (nonatomic, strong) NSNumber* textColor;
16
+@property (nonatomic, strong) NSNumber* selectedTextColor;
17
+@property (nonatomic, strong) NSString* fontFamily;
18
+@property (nonatomic, strong) NSNumber* fontSize;
19
+
12 20
 @end

+ 51
- 5
lib/ios/RNNBottomTabsOptions.m Näytä tiedosto

@@ -29,17 +29,63 @@ extern const NSInteger BLUR_TOPBAR_TAG;
29 29
 		}
30 30
 	}
31 31
 	
32
+	if (self.backgroundColor) {
33
+		viewController.tabBarController.tabBar.barTintColor = [RCTConvert UIColor:self.backgroundColor];
34
+	}
35
+	
36
+	if (self.translucent) {
37
+		viewController.tabBarController.tabBar.translucent = [self.translucent boolValue];
38
+	}
39
+	
40
+	if (self.hideShadow) {
41
+		viewController.tabBarController.tabBar.clipsToBounds = [self.hideShadow boolValue];
42
+	}
43
+	
44
+	if (self.tabBarTextFont || self.textColor) {
45
+		NSMutableDictionary* tabBarTitleTextAttributes = [NSMutableDictionary new];
46
+		if (self.textColor) {
47
+			tabBarTitleTextAttributes[NSForegroundColorAttributeName] = [RCTConvert UIColor:self.textColor];
48
+		}
49
+		
50
+		if (self.tabBarTextFont) {
51
+			tabBarTitleTextAttributes[NSFontAttributeName] = self.tabBarTextFont;
52
+		}
53
+		
54
+		for (UITabBarItem* item in viewController.tabBarController.tabBar.items) {
55
+			[item setTitleTextAttributes:tabBarTitleTextAttributes forState:UIControlStateNormal];
56
+		}
57
+	}
58
+	
59
+	if (self.selectedTextColor){
60
+		for (UITabBarItem* item in viewController.tabBarController.tabBar.items) {
61
+			NSMutableDictionary* tabBarTitleTextAttributes = [NSMutableDictionary new];
62
+			tabBarTitleTextAttributes[NSForegroundColorAttributeName] = [RCTConvert UIColor:self.selectedTextColor];
63
+			[item setTitleTextAttributes:tabBarTitleTextAttributes forState:UIControlStateSelected];
64
+		}
65
+	}
66
+	
32 67
 	[self resetOptions];
33 68
 }
34 69
 
70
+-(UIFont *)tabBarTextFont {
71
+	if (self.fontFamily) {
72
+		return [UIFont fontWithName:self.fontFamily size:self.tabBarTextFontSizeValue];
73
+	}
74
+	else if (self.fontSize) {
75
+		return [UIFont systemFontOfSize:self.tabBarTextFontSizeValue];
76
+	}
77
+	else {
78
+		return nil;
79
+	}
80
+}
81
+
82
+-(CGFloat)tabBarTextFontSizeValue {
83
+	return self.fontSize ? [self.fontSize floatValue] : 10;
84
+}
85
+
35 86
 - (void)resetOptions {
36 87
 	self.currentTabId = nil;
37 88
 	self.currentTabIndex = nil;
38 89
 }
39 90
 
40
--(void)mergeWith:(NSDictionary *)otherOptions {
41
-	for (id key in otherOptions) {
42
-		[self setValue:[otherOptions objectForKey:key] forKey:key];
43
-	}
44
-}
45 91
 @end

+ 12
- 0
lib/ios/RNNBridgeModule.m Näytä tiedosto

@@ -78,5 +78,17 @@ RCT_EXPORT_METHOD(dismissAllModals:(RCTPromiseResolveBlock)resolve rejecter:(RCT
78 78
 	}];
79 79
 }
80 80
 
81
+RCT_EXPORT_METHOD(showOverlay:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
82
+	[_commandsHandler showOverlay:layout completion:^{
83
+		resolve(layout[@"id"]);
84
+	}];
85
+}
86
+
87
+RCT_EXPORT_METHOD(dismissOverlay:(NSString*)componentId resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
88
+	[_commandsHandler dismissOverlay:componentId completion:^{
89
+		resolve(@(1));
90
+	}];
91
+}
92
+
81 93
 @end
82 94
 

+ 4
- 0
lib/ios/RNNCommandsHandler.h Näytä tiedosto

@@ -28,4 +28,8 @@
28 28
 
29 29
 -(void) dismissAllModalsWithCompletion:(RNNTransitionCompletionBlock)completion;
30 30
 
31
+-(void)showOverlay:(NSDictionary *)layout completion:(RNNTransitionCompletionBlock)completion;
32
+
33
+-(void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion;
34
+
31 35
 @end

+ 49
- 8
lib/ios/RNNCommandsHandler.m Näytä tiedosto

@@ -1,6 +1,7 @@
1 1
 #import "RNNCommandsHandler.h"
2 2
 #import "RNNModalManager.h"
3 3
 #import "RNNNavigationStackManager.h"
4
+#import "RNNOverlayManager.h"
4 5
 #import "RNNNavigationOptions.h"
5 6
 #import "RNNRootViewController.h"
6 7
 #import "React/RCTUIManager.h"
@@ -10,6 +11,7 @@
10 11
 	RNNStore *_store;
11 12
 	RNNNavigationStackManager* _navigationStackManager;
12 13
 	RNNModalManager* _modalManager;
14
+	RNNOverlayManager* _overlayManager;
13 15
 }
14 16
 
15 17
 -(instancetype) initWithStore:(RNNStore*)store controllerFactory:(RNNControllerFactory*)controllerFactory {
@@ -18,6 +20,7 @@
18 20
 	_controllerFactory = controllerFactory;
19 21
 	_navigationStackManager = [[RNNNavigationStackManager alloc] initWithStore:_store];
20 22
 	_modalManager = [[RNNModalManager alloc] initWithStore:_store];
23
+	_overlayManager = [[RNNOverlayManager alloc] init];
21 24
 	return self;
22 25
 }
23 26
 
@@ -61,13 +64,19 @@
61 64
 	[self assertReady];
62 65
 	
63 66
 	UIViewController<RNNRootViewProtocol> *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];
64
-	[_navigationStackManager push:newVc onTop:componentId completion:completion];
67
+	[_navigationStackManager push:newVc onTop:componentId completion:^{
68
+		[_controllerFactory.eventEmitter sendNavigationEvent:[RNNNavigationEvent create:kPush fromComponent:componentId toComponent:newVc.componentId]];
69
+		completion();
70
+	}];
65 71
 }
66 72
 
67 73
 -(void)pop:(NSString*)componentId options:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion {
68 74
 	[self assertReady];
69 75
 	[CATransaction begin];
70
-	[CATransaction setCompletionBlock:completion];
76
+	[CATransaction setCompletionBlock:^{
77
+		[_controllerFactory.eventEmitter sendNavigationEvent:[RNNNavigationEvent create:kPop fromComponent:nil toComponent:componentId]];
78
+		completion();
79
+	}];
71 80
 	NSDictionary* animationData = options[@"customTransition"];
72 81
 	if (animationData){
73 82
 		if ([animationData objectForKey:@"animations"]) {
@@ -84,7 +93,10 @@
84 93
 -(void) popTo:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion {
85 94
 	[self assertReady];
86 95
 	[CATransaction begin];
87
-	[CATransaction setCompletionBlock:completion];
96
+	[CATransaction setCompletionBlock:^{
97
+		[_controllerFactory.eventEmitter sendNavigationEvent:[RNNNavigationEvent create:kPopTo fromComponent:nil toComponent:componentId]];
98
+		completion();
99
+	}];
88 100
 	
89 101
 	[_navigationStackManager popTo:componentId];
90 102
 	
@@ -94,7 +106,10 @@
94 106
 -(void) popToRoot:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion {
95 107
 	[self assertReady];
96 108
 	[CATransaction begin];
97
-	[CATransaction setCompletionBlock:completion];
109
+	[CATransaction setCompletionBlock:^{
110
+		[_controllerFactory.eventEmitter sendNavigationEvent:[RNNNavigationEvent create:kPopToRoot fromComponent:componentId toComponent:nil]];
111
+		completion();
112
+	}];
98 113
 	
99 114
 	[_navigationStackManager popToRoot:componentId];
100 115
 	
@@ -104,14 +119,20 @@
104 119
 -(void) showModal:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion {
105 120
 	[self assertReady];
106 121
 	
107
-	UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];
108
-	[_modalManager showModal:newVc completion:completion];
122
+	UIViewController<RNNRootViewProtocol> *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];
123
+	[_modalManager showModal:newVc completion:^{
124
+		[_controllerFactory.eventEmitter sendNavigationEvent:[RNNNavigationEvent create:kShowModal fromComponent:nil toComponent:newVc.componentId]];
125
+		completion();
126
+	}];
109 127
 }
110 128
 
111 129
 -(void) dismissModal:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion {
112 130
 	[self assertReady];
113 131
 	[CATransaction begin];
114
-	[CATransaction setCompletionBlock:completion];
132
+	[CATransaction setCompletionBlock:^{
133
+		[_controllerFactory.eventEmitter sendNavigationEvent:[RNNNavigationEvent create:kDismissModal fromComponent:componentId toComponent:nil]];
134
+		completion();
135
+	}];
115 136
 	
116 137
 	[_modalManager dismissModal:componentId];
117 138
 	
@@ -121,13 +142,33 @@
121 142
 -(void) dismissAllModalsWithCompletion:(RNNTransitionCompletionBlock)completion {
122 143
 	[self assertReady];
123 144
 	[CATransaction begin];
124
-	[CATransaction setCompletionBlock:completion];
145
+	[CATransaction setCompletionBlock:^{
146
+		[_controllerFactory.eventEmitter sendNavigationEvent:[RNNNavigationEvent create:kDismissAllModals fromComponent:nil toComponent:nil]];
147
+		completion();
148
+	}];
125 149
 	
126 150
 	[_modalManager dismissAllModals];
127 151
 	
128 152
 	[CATransaction commit];
129 153
 }
130 154
 
155
+-(void)showOverlay:(NSDictionary *)layout completion:(RNNTransitionCompletionBlock)completion {
156
+	[self assertReady];
157
+	UIViewController<RNNRootViewProtocol>* overlayVC = [_controllerFactory createOverlay:layout];
158
+	[_overlayManager showOverlay:overlayVC completion:^{
159
+		[_controllerFactory.eventEmitter sendNavigationEvent:[RNNNavigationEvent create:kShowOverlay fromComponent:nil toComponent:overlayVC.componentId]];
160
+		completion();
161
+	}];
162
+}
163
+
164
+- (void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion {
165
+	[self assertReady];
166
+	[_overlayManager dismissOverlay:componentId completion:^{	
167
+		[_controllerFactory.eventEmitter sendNavigationEvent:[RNNNavigationEvent create:kDismissOverlay fromComponent:componentId toComponent:nil]];
168
+		completion();
169
+	}];
170
+}
171
+
131 172
 #pragma mark - private
132 173
 
133 174
 -(void) assertReady {

+ 15
- 0
lib/ios/RNNComponentLifecycleEvent.h Näytä tiedosto

@@ -0,0 +1,15 @@
1
+#import "RNNNavigationEvent.h"
2
+
3
+#define kDidAppear         @"didAppear"
4
+#define kDidDisappear      @"didDisappear"
5
+#define kWillUnmount       @"willUnmount"
6
+#define kDidMount         @"didMount"
7
+typedef NSString*               LifecycleEvent;
8
+
9
+@interface RNNComponentLifecycleEvent : NSObject
10
+
11
++ (instancetype)create:(LifecycleEvent)event componentName:(NSString*)componentName componentId:(NSString*)componentId;
12
+
13
+- (NSDictionary*)body;
14
+
15
+@end

+ 24
- 0
lib/ios/RNNComponentLifecycleEvent.m Näytä tiedosto

@@ -0,0 +1,24 @@
1
+#import "RNNComponentLifecycleEvent.h"
2
+
3
+@interface RNNComponentLifecycleEvent()
4
+@property (nonatomic, strong) NSString* componentName;
5
+@property (nonatomic, strong) NSString* componentId;
6
+@property (nonatomic, strong) LifecycleEvent event;
7
+
8
+@end
9
+
10
+@implementation RNNComponentLifecycleEvent
11
+
12
++ (instancetype)create:(LifecycleEvent)event componentName:(NSString *)componentName componentId:(NSString *)componentId {
13
+	RNNComponentLifecycleEvent* lifecycleEvent = [[RNNComponentLifecycleEvent alloc] init];
14
+	lifecycleEvent.componentName = componentName;
15
+	lifecycleEvent.componentId = componentId;
16
+	lifecycleEvent.event = event;
17
+	return lifecycleEvent;
18
+}
19
+
20
+- (NSDictionary *)body {
21
+	return @{@"event": self.event, @"componentName": self.componentName, @"componentId": self.componentId};
22
+}
23
+
24
+@end

+ 3
- 0
lib/ios/RNNControllerFactory.h Näytä tiedosto

@@ -15,6 +15,9 @@
15 15
 
16 16
 -(UIViewController<RNNRootViewProtocol> *)createLayoutAndSaveToStore:(NSDictionary*)layout;
17 17
 
18
+- (UIViewController<RNNRootViewProtocol> *)createOverlay:(NSDictionary*)layout;
19
+
18 20
 @property (nonatomic, strong) RNNNavigationOptions* defaultOptions;
21
+@property (nonatomic, strong) RNNEventEmitter *eventEmitter;
19 22
 
20 23
 @end

+ 10
- 2
lib/ios/RNNControllerFactory.m Näytä tiedosto

@@ -12,7 +12,6 @@
12 12
 @implementation RNNControllerFactory {
13 13
 	id<RNNRootViewCreator> _creator;
14 14
 	RNNStore *_store;
15
-	RNNEventEmitter *_eventEmitter;
16 15
 	RCTBridge *_bridge;
17 16
 }
18 17
 
@@ -162,6 +161,15 @@
162 161
 	return sideMenuChild;
163 162
 }
164 163
 
165
-
164
+- (UIViewController<RNNRootViewProtocol> *)createOverlay:(NSDictionary*)layout {
165
+	UIViewController<RNNRootViewProtocol> *vc = [self fromTree:layout];
166
+	RCTRootView* rootView = (RCTRootView*)vc.view;
167
+	rootView.backgroundColor = [UIColor clearColor];
168
+	CGSize availableSize = UIApplication.sharedApplication.delegate.window.bounds.size;
169
+	rootView.frame = CGRectMake(0, 0, availableSize.width, availableSize.height);
170
+	[_bridge.uiManager setAvailableSize:availableSize forRootView:vc.view];
171
+	
172
+	return vc;
173
+}
166 174
 
167 175
 @end

+ 7
- 0
lib/ios/RNNEventEmitter.h Näytä tiedosto

@@ -4,6 +4,9 @@
4 4
 #import <React/RCTEventEmitter.h>
5 5
 #import <React/RCTBridgeModule.h>
6 6
 
7
+#import "RNNNavigationEvent.h"
8
+#import "RNNComponentLifecycleEvent.h"
9
+
7 10
 @interface RNNEventEmitter : RCTEventEmitter <RCTBridgeModule>
8 11
 
9 12
 -(void)sendOnAppLaunched;
@@ -14,4 +17,8 @@
14 17
 
15 18
 -(void)sendOnNavigationButtonPressed:(NSString*)componentId buttonId:(NSString*)buttonId;
16 19
 
20
+-(void)sendNavigationEvent:(RNNNavigationEvent*)navigationEvent;
21
+
22
+-(void)sendLifecycleEvent:(RNNComponentLifecycleEvent *)navigationEvent;
23
+
17 24
 @end

+ 11
- 1
lib/ios/RNNEventEmitter.m Näytä tiedosto

@@ -11,9 +11,11 @@ static NSString* const onAppLaunched	= @"RNN.appLaunched";
11 11
 static NSString* const componentDidAppear	= @"RNN.componentDidAppear";
12 12
 static NSString* const componentDidDisappear	= @"RNN.componentDidDisappear";
13 13
 static NSString* const onNavigationButtonPressed	= @"RNN.navigationButtonPressed";
14
+static NSString* const navigationCommands	= @"RNN.navigationCommands";
15
+static NSString* const componentLifecycle	= @"RNN.componentLifecycle";
14 16
 
15 17
 -(NSArray<NSString *> *)supportedEvents {
16
-	return @[onAppLaunched, componentDidAppear, componentDidDisappear, onNavigationButtonPressed];
18
+	return @[onAppLaunched, componentDidAppear, componentDidDisappear, onNavigationButtonPressed, navigationCommands, componentLifecycle];
17 19
 }
18 20
 
19 21
 # pragma mark public
@@ -26,6 +28,14 @@ static NSString* const onNavigationButtonPressed	= @"RNN.navigationButtonPressed
26 28
 	}
27 29
 }
28 30
 
31
+-(void)sendNavigationEvent:(RNNNavigationEvent *)navigationEvent {
32
+	[self send:navigationCommands body:navigationEvent.body];
33
+}
34
+
35
+-(void)sendLifecycleEvent:(RNNComponentLifecycleEvent *)navigationEvent {
36
+	[self send:componentLifecycle body:navigationEvent.body];
37
+}
38
+
29 39
 -(void)sendComponentDidAppear:(NSString *)componentId {
30 40
 	[self send:componentDidAppear body:componentId];
31 41
 }

+ 1
- 1
lib/ios/RNNModalManager.h Näytä tiedosto

@@ -4,7 +4,7 @@
4 4
 
5 5
 @interface RNNModalManager : NSObject
6 6
 
7
-@property (nonatomic, strong) UIViewController* toVC;
7
+@property (nonatomic, strong) UIViewController<RNNRootViewProtocol>* toVC;
8 8
 
9 9
 -(instancetype)initWithStore:(RNNStore*)store;
10 10
 -(void)showModal:(UIViewController*)viewController completion:(RNNTransitionCompletionBlock)completion;

+ 4
- 4
lib/ios/RNNModalManager.m Näytä tiedosto

@@ -22,7 +22,7 @@
22 22
 -(void)showModalAfterLoad:(NSDictionary*)notif {
23 23
 	[[NSNotificationCenter defaultCenter] removeObserver:self name:@"RCTContentDidAppearNotification" object:nil];
24 24
 	UIViewController *topVC = [self topPresentedVC];
25
-	[topVC presentViewController:self.toVC animated:YES completion:^{
25
+	[topVC presentViewController:self.toVC animated:self.toVC.isAnimated completion:^{
26 26
 		if (_completionBlock) {
27 27
 			_completionBlock();
28 28
 			_completionBlock = nil;
@@ -31,7 +31,7 @@
31 31
 }
32 32
 
33 33
 -(void)showModal:(UIViewController *)viewController completion:(RNNTransitionCompletionBlock)completion {
34
-	self.toVC = viewController;
34
+	self.toVC = (UIViewController<RNNRootViewProtocol>*)viewController;
35 35
 	_completionBlock = completion;
36 36
 	[self waitForContentToAppearAndThen:@selector(showModalAfterLoad:)];
37 37
 }
@@ -53,7 +53,7 @@
53 53
 -(void)removePendingNextModalIfOnTop {
54 54
 	NSString *componentId = [[_store pendingModalIdsToDismiss] lastObject];
55 55
 	
56
-	UIViewController *modalToDismiss = [_store findComponentForId:componentId];
56
+	UIViewController<RNNRootViewProtocol> *modalToDismiss = (UIViewController<RNNRootViewProtocol>*)[_store findComponentForId:componentId];
57 57
 	
58 58
 	if(!modalToDismiss) {
59 59
 		return;
@@ -62,7 +62,7 @@
62 62
 	UIViewController* topPresentedVC = [self topPresentedVC];
63 63
 	
64 64
 	if (modalToDismiss == topPresentedVC || [[topPresentedVC childViewControllers] containsObject:modalToDismiss]) {
65
-		[modalToDismiss dismissViewControllerAnimated:YES completion:^{
65
+		[modalToDismiss dismissViewControllerAnimated:modalToDismiss.isAnimated completion:^{
66 66
 			[[_store pendingModalIdsToDismiss] removeObject:componentId];
67 67
 			[self removePendingNextModalIfOnTop];
68 68
 		}];

+ 5
- 0
lib/ios/RNNNavigationButtons.m Näytä tiedosto

@@ -94,6 +94,11 @@
94 94
 		[barButtonItem setImage:[barButtonItem.image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
95 95
 	}
96 96
 	
97
+	id tintColor = dictionary[@"tintColor"];
98
+	if (tintColor) {
99
+		[barButtonItem setTintColor:[RCTConvert UIColor: tintColor]];
100
+	}
101
+	
97 102
 	NSString *testID = dictionary[@"testID"];
98 103
 	if (testID)
99 104
 	{

+ 9
- 0
lib/ios/RNNNavigationController.m Näytä tiedosto

@@ -11,4 +11,13 @@
11 11
 	return NO;
12 12
 }
13 13
 
14
+- (BOOL)isAnimated {
15
+	UIViewController<RNNRootViewProtocol>* rootVC = (UIViewController<RNNRootViewProtocol>*) self.topViewController;
16
+	return rootVC.isAnimated;
17
+}
18
+
19
+- (NSString *)componentId {
20
+	return ((UIViewController<RNNRootViewProtocol>*)self.topViewController).componentId;
21
+}
22
+
14 23
 @end

+ 20
- 0
lib/ios/RNNNavigationEvent.h Näytä tiedosto

@@ -0,0 +1,20 @@
1
+#import <Foundation/Foundation.h>
2
+
3
+#define kPush              @"push"
4
+#define kPop               @"pop"
5
+#define kPopTo             @"popTo"
6
+#define kPopToRoot         @"popToRoot"
7
+#define kShowModal         @"showModal"
8
+#define kDismissModal      @"dismissModal"
9
+#define kDismissAllModals  @"dismissAllModals"
10
+#define kShowOverlay       @"showOverlay"
11
+#define kDismissOverlay    @"dismissOverlay"
12
+typedef NSString*               NavigationCommand;
13
+
14
+@interface RNNNavigationEvent : NSObject
15
+
16
+@property (nonatomic, strong) NSDictionary* body;
17
+
18
++ (instancetype)create:(NavigationCommand)commandType fromComponent:(NSString *)fromComponentId toComponent:(NSString *)toComponentId;
19
+
20
+@end

+ 26
- 0
lib/ios/RNNNavigationEvent.m Näytä tiedosto

@@ -0,0 +1,26 @@
1
+#import "RNNNavigationEvent.h"
2
+
3
+@interface RNNNavigationEvent ()
4
+	@property (nonatomic, strong) NavigationCommand command;
5
+	@property (nonatomic, strong) NSString* toComponentId;
6
+	@property (nonatomic, strong) NSString* fromComponentId;
7
+@end
8
+
9
+@implementation RNNNavigationEvent
10
+
11
++ (instancetype)create:(NavigationCommand)commandType fromComponent:(NSString *)fromComponentId toComponent:(NSString *)toComponentId {
12
+	RNNNavigationEvent* navigationCommand = [[RNNNavigationEvent alloc] init];
13
+	navigationCommand.command = commandType;
14
+	navigationCommand.fromComponentId = fromComponentId;
15
+	navigationCommand.toComponentId = toComponentId;
16
+	return navigationCommand;
17
+}
18
+
19
+- (NSDictionary *)body {
20
+	NSMutableDictionary* mutableParams = [NSMutableDictionary new];
21
+	self.fromComponentId ? [mutableParams setObject:self.fromComponentId forKey:@"fromComponentId"] : nil;
22
+	self.toComponentId ? [mutableParams setObject:self.toComponentId forKey:@"toComponentId"] : nil;
23
+	return @{@"commandName": self.command, @"params": mutableParams};
24
+}
25
+
26
+@end

+ 3
- 0
lib/ios/RNNNavigationOptions.h Näytä tiedosto

@@ -5,6 +5,7 @@
5 5
 #import "RNNSideMenuOptions.h"
6 6
 #import "RNNTopTabOptions.h"
7 7
 #import "RNNTopTabsOptions.h"
8
+#import "RNNOverlayOptions.h"
8 9
 
9 10
 extern const NSInteger BLUR_STATUS_TAG;
10 11
 extern const NSInteger BLUR_TOPBAR_TAG;
@@ -18,9 +19,11 @@ extern const NSInteger TOP_BAR_TRANSPARENT_TAG;
18 19
 @property (nonatomic, strong) RNNTopTabsOptions* topTabs;
19 20
 @property (nonatomic, strong) RNNTopTabOptions* topTab;
20 21
 @property (nonatomic, strong) RNNSideMenuOptions* sideMenu;
22
+@property (nonatomic, strong) RNNOverlayOptions* overlay;
21 23
 
22 24
 @property (nonatomic, strong) RNNNavigationOptions* defaultOptions;
23 25
 
26
+@property (nonatomic, strong) NSNumber* animated;
24 27
 @property (nonatomic, strong) NSNumber* statusBarHidden;
25 28
 @property (nonatomic, strong) NSNumber* screenBackgroundColor;
26 29
 @property (nonatomic, strong) NSMutableDictionary* originalTopBarImages;

+ 4
- 1
lib/ios/RNNNavigationOptions.m Näytä tiedosto

@@ -30,7 +30,9 @@ const NSInteger TOP_BAR_TRANSPARENT_TAG = 78264803;
30 30
 	self.backgroundImage = [RCTConvert UIImage:[options objectForKey:@"backgroundImage"]];
31 31
 	self.rootBackgroundImage = [RCTConvert UIImage:[options objectForKey:@"rootBackgroundImage"]];
32 32
 	self.bottomTab = [[RNNBottomTabOptions alloc] initWithDict:[options objectForKey:@"bottomTab"]];
33
-    
33
+	self.overlay = [[RNNOverlayOptions alloc] initWithDict:[options objectForKey:@"overlay"]];
34
+	self.animated = [options objectForKey:@"animated"];
35
+	
34 36
 	return self;
35 37
 }
36 38
 
@@ -53,6 +55,7 @@ const NSInteger TOP_BAR_TRANSPARENT_TAG = 78264803;
53 55
 	[self.topTab applyOn:viewController];
54 56
 	[self.bottomTab applyOn:viewController];
55 57
 	[self.sideMenu applyOn:viewController];
58
+	[self.overlay applyOn:viewController];
56 59
 	[self applyOtherOptionsOn:viewController];
57 60
 }
58 61
 

+ 4
- 4
lib/ios/RNNNavigationStackManager.m Näytä tiedosto

@@ -52,7 +52,7 @@ dispatch_queue_t RCTGetUIManagerQueue(void);
52 52
 		}
53 53
 	}];
54 54
 	
55
-	[[self.fromVC navigationController] pushViewController:self.toVC animated:YES];
55
+	[[self.fromVC navigationController] pushViewController:self.toVC animated:self.toVC.isAnimated];
56 56
 	[CATransaction commit];
57 57
 	
58 58
 	self.toVC = nil;
@@ -61,17 +61,17 @@ dispatch_queue_t RCTGetUIManagerQueue(void);
61 61
 }
62 62
 
63 63
 -(void)pop:(NSString *)componentId withAnimationData:(NSDictionary *)animationData {
64
-	UIViewController* vc = [_store findComponentForId:componentId];
64
+	UIViewController<RNNRootViewProtocol>* vc = (UIViewController<RNNRootViewProtocol>*)[_store findComponentForId:componentId];
65 65
 	UINavigationController* nvc = [vc navigationController];
66 66
 	if ([nvc topViewController] == vc) {
67 67
 		if (animationData) {
68 68
 			RNNRootViewController* RNNVC = (RNNRootViewController*)vc;
69 69
 			nvc.delegate = RNNVC;
70 70
 			[RNNVC.animator setupTransition:animationData];
71
-			[nvc popViewControllerAnimated:YES];
71
+			[nvc popViewControllerAnimated:vc.isAnimated];
72 72
 		} else {
73 73
 			nvc.delegate = nil;
74
-			[nvc popViewControllerAnimated:YES];
74
+			[nvc popViewControllerAnimated:vc.isAnimated];
75 75
 		}
76 76
 	} else {
77 77
 		NSMutableArray * vcs = nvc.viewControllers.mutableCopy;

+ 10
- 0
lib/ios/RNNOverlayManager.h Näytä tiedosto

@@ -0,0 +1,10 @@
1
+#import <Foundation/Foundation.h>
2
+#import <UIKit/UIKit.h>
3
+#import "RNNStore.h"
4
+
5
+@interface RNNOverlayManager : NSObject
6
+
7
+- (void)showOverlay:(UIViewController*)viewController completion:(RNNTransitionCompletionBlock)completion;
8
+- (void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion;
9
+
10
+@end

+ 38
- 0
lib/ios/RNNOverlayManager.m Näytä tiedosto

@@ -0,0 +1,38 @@
1
+#import "RNNOverlayManager.h"
2
+
3
+@implementation RNNOverlayManager {
4
+	NSMutableDictionary* _overlayDict;
5
+}
6
+
7
+- (instancetype)init {
8
+	self = [super init];
9
+	_overlayDict = [[NSMutableDictionary alloc] init];
10
+	return self;
11
+}
12
+
13
+#pragma mark - public
14
+
15
+- (void)showOverlay:(RNNRootViewController *)viewController completion:(RNNTransitionCompletionBlock)completion {
16
+	[self cacheOverlay:viewController];
17
+	[[[UIApplication sharedApplication] keyWindow] addSubview:viewController.view];
18
+	completion();
19
+}
20
+
21
+- (void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion {
22
+	RNNRootViewController* viewController = [_overlayDict objectForKey:componentId];
23
+	[self removeCachedOverlay:viewController];
24
+	completion();
25
+}
26
+
27
+#pragma mark - private
28
+
29
+- (void)cacheOverlay:(RNNRootViewController*)viewController {
30
+	[_overlayDict setObject:viewController forKey:viewController.componentId];
31
+}
32
+
33
+- (void)removeCachedOverlay:(RNNRootViewController*)viewController {
34
+	[viewController.view removeFromSuperview];
35
+	[_overlayDict removeObjectForKey:viewController.componentId];
36
+}
37
+
38
+@end

+ 7
- 0
lib/ios/RNNOverlayOptions.h Näytä tiedosto

@@ -0,0 +1,7 @@
1
+#import "RNNOptions.h"
2
+
3
+@interface RNNOverlayOptions : RNNOptions
4
+
5
+@property (nonatomic, strong) NSNumber* interceptTouchOutside;
6
+
7
+@end

+ 13
- 0
lib/ios/RNNOverlayOptions.m Näytä tiedosto

@@ -0,0 +1,13 @@
1
+#import "RNNOverlayOptions.h"
2
+#import <React/RCTRootView.h>
3
+
4
+@implementation RNNOverlayOptions
5
+
6
+- (void)applyOn:(UIViewController *)viewController {
7
+	if (self.interceptTouchOutside) {
8
+		RCTRootView* rootView = (RCTRootView*)viewController.view;
9
+		rootView.passThroughTouches = ![self.interceptTouchOutside boolValue];
10
+	}
11
+}
12
+
13
+@end

+ 26
- 10
lib/ios/RNNRootViewController.m Näytä tiedosto

@@ -38,16 +38,42 @@
38 38
 -(void)viewWillAppear:(BOOL)animated{
39 39
 	[super viewWillAppear:animated];
40 40
 	[self.options applyOn:self];
41
+	[self sendLifecycleEvent:kDidMount];
42
+}
43
+
44
+-(void)viewDidAppear:(BOOL)animated {
45
+	[super viewDidAppear:animated];
46
+	[self.eventEmitter sendComponentDidAppear:self.componentId];
47
+	[self sendLifecycleEvent:kDidAppear];
48
+}
49
+
50
+- (void)viewWillDisappear:(BOOL)animated {
51
+	[super viewWillDisappear:animated];
52
+	[self sendLifecycleEvent:kWillUnmount];
53
+}
54
+
55
+-(void)viewDidDisappear:(BOOL)animated {
56
+	[super viewDidDisappear:animated];
57
+	[self.eventEmitter sendComponentDidDisappear:self.componentId];
58
+	[self sendLifecycleEvent:kDidDisappear];
41 59
 }
42 60
 
43 61
 - (void)viewDidLoad {
44 62
 	[super viewDidLoad];
45 63
 }
46 64
 
65
+- (void)sendLifecycleEvent:(LifecycleEvent)event {
66
+	[self.eventEmitter sendLifecycleEvent:[RNNComponentLifecycleEvent create:event componentName:self.componentName componentId:self.componentId]];
67
+}
68
+
47 69
 -(BOOL)isCustomTransitioned {
48 70
 	return self.animator != nil;
49 71
 }
50 72
 
73
+- (BOOL)isAnimated {
74
+	return self.options.animated ? [self.options.animated boolValue] : YES;
75
+}
76
+
51 77
 - (BOOL)prefersStatusBarHidden {
52 78
 	if ([self.options.statusBarHidden boolValue]) {
53 79
 		return YES;
@@ -69,16 +95,6 @@
69 95
 	return NO;
70 96
 }
71 97
 
72
--(void)viewDidAppear:(BOOL)animated {
73
-	[super viewDidAppear:animated];
74
-	[self.eventEmitter sendComponentDidAppear:self.componentId];
75
-}
76
-
77
--(void)viewDidDisappear:(BOOL)animated {
78
-	[super viewDidDisappear:animated];
79
-	[self.eventEmitter sendComponentDidDisappear:self.componentId];
80
-}
81
-
82 98
 - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
83 99
 	RNNRootViewController* vc =  (RNNRootViewController*)viewController;
84 100
 	if (![vc.options.backButtonTransition isEqualToString:@"custom"]){

+ 3
- 0
lib/ios/RNNRootViewProtocol.h Näytä tiedosto

@@ -5,6 +5,9 @@
5 5
 @required
6 6
 
7 7
 - (BOOL)isCustomTransitioned;
8
+- (BOOL)isAnimated;
9
+
10
+- (NSString *)componentId;
8 11
 
9 12
 @end
10 13
 

+ 10
- 2
lib/ios/RNNSideMenuChildVC.m Näytä tiedosto

@@ -11,13 +11,13 @@
11 11
 @interface RNNSideMenuChildVC ()
12 12
 
13 13
 @property (readwrite) RNNSideMenuChildType type;
14
-@property (readwrite) UIViewController *child;
14
+@property (readwrite) UIViewController<RNNRootViewProtocol> *child;
15 15
 
16 16
 @end
17 17
 
18 18
 @implementation RNNSideMenuChildVC
19 19
 
20
--(instancetype) initWithChild:(UIViewController*)child type:(RNNSideMenuChildType)type {
20
+-(instancetype) initWithChild:(UIViewController<RNNRootViewProtocol>*)child type:(RNNSideMenuChildType)type {
21 21
 	self = [super init];
22 22
 	
23 23
 	self.child = child;
@@ -37,4 +37,12 @@
37 37
 	return NO;
38 38
 }
39 39
 
40
+- (BOOL)isAnimated {
41
+	return YES;
42
+}
43
+
44
+- (NSString *)componentId {
45
+	return _child.componentId;
46
+}
47
+
40 48
 @end

+ 8
- 0
lib/ios/RNNSideMenuController.m Näytä tiedosto

@@ -76,4 +76,12 @@
76 76
 	return NO;
77 77
 }
78 78
 
79
+- (BOOL)isAnimated {
80
+	return YES;
81
+}
82
+
83
+- (NSString *)componentId {
84
+	return _center.componentId;
85
+}
86
+
79 87
 @end

+ 13
- 0
lib/ios/RNNSwizzles.h Näytä tiedosto

@@ -0,0 +1,13 @@
1
+//
2
+//  RNNSwizzles.h
3
+//  ReactNativeNavigation
4
+//
5
+//  Created by Leo Natan (Wix) on 1/17/18.
6
+//  Copyright © 2018 Wix. All rights reserved.
7
+//
8
+
9
+#import <Foundation/Foundation.h>
10
+
11
+@interface RNNSwizzles : NSObject
12
+
13
+@end

+ 49
- 0
lib/ios/RNNSwizzles.m Näytä tiedosto

@@ -0,0 +1,49 @@
1
+//
2
+//  RNNSwizzles.m
3
+//  ReactNativeNavigation
4
+//
5
+//  Created by Leo Natan (Wix) on 1/17/18.
6
+//  Copyright © 2018 Wix. All rights reserved.
7
+//
8
+
9
+#import "RNNSwizzles.h"
10
+@import ObjectiveC;
11
+@import UIKit;
12
+
13
+static id (*__SWZ_initWithEventDispatcher_orig)(id self, SEL _cmd, id eventDispatcher);
14
+
15
+@implementation RNNSwizzles
16
+
17
+#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3
18
+- (id)__swz_initWithEventDispatcher:(id)eventDispatcher
19
+{
20
+	id returnValue = __SWZ_initWithEventDispatcher_orig(self, _cmd, eventDispatcher);
21
+	
22
+	if (@available(iOS 11.0, *)) {
23
+		[(UIScrollView*)[returnValue valueForKey:@"scrollView"] setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentAutomatic];
24
+	}
25
+	
26
+	return returnValue;
27
+}
28
+
29
++ (void)load
30
+{
31
+	Class cls = NSClassFromString(@"RCTScrollView");
32
+	if(cls == NULL)
33
+	{
34
+		return;
35
+	}
36
+	Method m1 = class_getInstanceMethod(cls, NSSelectorFromString(@"initWithEventDispatcher:"));
37
+	
38
+	if(m1 == NULL)
39
+	{
40
+		return;
41
+	}
42
+	
43
+	__SWZ_initWithEventDispatcher_orig = (void*)method_getImplementation(m1);
44
+	Method m2 = class_getInstanceMethod([RNNSwizzles class], NSSelectorFromString(@"__swz_initWithEventDispatcher:"));
45
+	method_exchangeImplementations(m1, m2);
46
+}
47
+#endif
48
+
49
+@end

+ 8
- 0
lib/ios/RNNTabBarController.m Näytä tiedosto

@@ -37,4 +37,12 @@
37 37
 	return NO;
38 38
 }
39 39
 
40
+- (BOOL)isAnimated {
41
+	return YES;
42
+}
43
+
44
+- (NSString *)componentId {
45
+	return ((UIViewController<RNNRootViewProtocol>*)self.selectedViewController).componentId;
46
+}
47
+
40 48
 @end

+ 1
- 1
lib/ios/RNNTopBarOptions.m Näytä tiedosto

@@ -98,7 +98,7 @@ extern const NSInteger BLUR_TOPBAR_TAG;
98 98
 		}
99 99
 	}
100 100
 	
101
-	void (^disableTopBarTransparent)() = ^void(){
101
+	void (^disableTopBarTransparent)(void) = ^ {
102 102
 		UIView *transparentView = [viewController.navigationController.navigationBar viewWithTag:TOP_BAR_TRANSPARENT_TAG];
103 103
 		if (transparentView){
104 104
 			[transparentView removeFromSuperview];

+ 0
- 0
lib/ios/RNNTopTabOptions.m Näytä tiedosto


Some files were not shown because too many files changed in this diff