Browse Source

Merge branch 'sideMenu' into v2.0

Guy Carmeli 8 years ago
parent
commit
616a04bc62
39 changed files with 858 additions and 216 deletions
  1. 7
    1
      android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java
  2. 4
    1
      android/app/src/main/java/com/reactnativenavigation/controllers/Modal.java
  3. 7
    2
      android/app/src/main/java/com/reactnativenavigation/controllers/ModalController.java
  4. 8
    0
      android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java
  5. 28
    0
      android/app/src/main/java/com/reactnativenavigation/controllers/NavigationCommandsHandler.java
  6. 77
    11
      android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java
  7. 4
    0
      android/app/src/main/java/com/reactnativenavigation/layouts/Layout.java
  8. 3
    2
      android/app/src/main/java/com/reactnativenavigation/layouts/LayoutFactory.java
  9. 2
    2
      android/app/src/main/java/com/reactnativenavigation/layouts/ScreenStackContainer.java
  10. 66
    18
      android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java
  11. 1
    0
      android/app/src/main/java/com/reactnativenavigation/params/ActivityParams.java
  12. 1
    0
      android/app/src/main/java/com/reactnativenavigation/params/ScreenParams.java
  13. 9
    0
      android/app/src/main/java/com/reactnativenavigation/params/SideMenuParams.java
  14. 4
    0
      android/app/src/main/java/com/reactnativenavigation/params/parsers/ActivityParamsParser.java
  15. 2
    0
      android/app/src/main/java/com/reactnativenavigation/params/parsers/ScreenParamsParser.java
  16. 16
    0
      android/app/src/main/java/com/reactnativenavigation/params/parsers/SideMenuParamsParser.java
  17. 3
    3
      android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarLeftButtonParamsParser.java
  18. 3
    4
      android/app/src/main/java/com/reactnativenavigation/screens/FragmentScreen.java
  19. 6
    6
      android/app/src/main/java/com/reactnativenavigation/screens/Screen.java
  20. 5
    5
      android/app/src/main/java/com/reactnativenavigation/screens/ScreenFactory.java
  21. 36
    9
      android/app/src/main/java/com/reactnativenavigation/screens/ScreenStack.java
  22. 3
    3
      android/app/src/main/java/com/reactnativenavigation/screens/SingleScreen.java
  23. 3
    3
      android/app/src/main/java/com/reactnativenavigation/screens/ViewPagerScreen.java
  24. 6
    2
      android/app/src/main/java/com/reactnativenavigation/views/ContentView.java
  25. 10
    4
      android/app/src/main/java/com/reactnativenavigation/views/LeftButton.java
  26. 7
    0
      android/app/src/main/java/com/reactnativenavigation/views/LeftButtonOnClickListener.java
  27. 74
    0
      android/app/src/main/java/com/reactnativenavigation/views/SideMenu.java
  28. 4
    4
      android/app/src/main/java/com/reactnativenavigation/views/TitleBar.java
  29. 0
    5
      android/app/src/main/java/com/reactnativenavigation/views/TitleBarBackButtonListener.java
  30. 4
    4
      android/app/src/main/java/com/reactnativenavigation/views/TopBar.java
  31. 86
    71
      example-redux/src/app.js
  32. 101
    0
      example-redux/src/screens/BottomTabsSideMenu.js
  33. 48
    15
      example-redux/src/screens/FirstTabScreen.js
  34. 31
    3
      example-redux/src/screens/ListScreen.js
  35. 44
    7
      example-redux/src/screens/SecondTabScreen.js
  36. 89
    0
      example-redux/src/screens/SideMenu.js
  37. 4
    0
      example-redux/src/screens/index.js
  38. 37
    30
      src/deprecated/platformSpecificDeprecated.android.js
  39. 15
    1
      src/platformSpecific.android.js

+ 7
- 1
android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java View File

@@ -80,7 +80,13 @@ public class NavigationReactModule extends ReactContextBaseJavaModule {
80 80
     }
81 81
 
82 82
     @ReactMethod
83
-    public void toggleSideMenuVisible(final ReadableMap params) {
83
+    public void toggleSideMenuVisible(boolean animated) {
84
+        NavigationCommandsHandler.toggleSideMenuVisible(animated);
85
+    }
86
+
87
+    @ReactMethod
88
+    public void setSideMenuVisible(boolean animated, boolean visible) {
89
+        NavigationCommandsHandler.setSideMenuVisible(animated, visible);
84 90
     }
85 91
 
86 92
     @ReactMethod

+ 4
- 1
android/app/src/main/java/com/reactnativenavigation/controllers/Modal.java View File

@@ -39,13 +39,16 @@ public class Modal extends Dialog implements DialogInterface.OnDismissListener,
39 39
     }
40 40
 
41 41
     @Override
42
-    public boolean onTitleBarBackPress() {
42
+    public boolean onTitleBarBackButtonClick() {
43 43
         if (!layout.onBackPressed()) {
44 44
             onBackPressed();
45 45
         }
46 46
         return true;
47 47
     }
48 48
 
49
+    public void onSideMenuButtonClick() {
50
+    }
51
+
49 52
     public interface OnModalDismissedListener {
50 53
         void onModalDismissed(Modal modal);
51 54
     }

+ 7
- 2
android/app/src/main/java/com/reactnativenavigation/controllers/ModalController.java View File

@@ -98,8 +98,13 @@ public class ModalController implements ScreenStackContainer, Modal.OnModalDismi
98 98
     }
99 99
 
100 100
     @Override
101
-    public boolean onTitleBarBackPress() {
102
-        // Do nothing and let the layout handle the back press
101
+    public boolean onTitleBarBackButtonClick() {
102
+        // Do nothing and let the layout handle the back button click
103 103
         return false;
104 104
     }
105
+
106
+    @Override
107
+    public void onSideMenuButtonClick() {
108
+        // Do nothing and let the layout handle the click
109
+    }
105 110
 }

+ 8
- 0
android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java View File

@@ -195,4 +195,12 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard
195 195
         layout.setTitleBarLeftButton(screenInstanceId, navigatorEventId, titleBarLeftButton);
196 196
         modalController.setTitleBarLeftButton(screenInstanceId, navigatorEventId, titleBarLeftButton);
197 197
     }
198
+
199
+    public void toggleSideMenuVisible(boolean animated) {
200
+        layout.toggleSideMenuVisible(animated);
201
+    }
202
+
203
+    public void setSideMenuVisible(boolean animated, boolean visible) {
204
+        layout.setSideMenuVisible(animated, visible);
205
+    }
198 206
 }

+ 28
- 0
android/app/src/main/java/com/reactnativenavigation/controllers/NavigationCommandsHandler.java View File

@@ -210,4 +210,32 @@ public class NavigationCommandsHandler {
210 210
             }
211 211
         });
212 212
     }
213
+
214
+    public static void toggleSideMenuVisible(final boolean animated) {
215
+        final NavigationActivity currentActivity = NavigationActivity.currentActivity;
216
+        if (currentActivity == null) {
217
+            return;
218
+        }
219
+
220
+        NavigationApplication.instance.runOnMainThread(new Runnable() {
221
+            @Override
222
+            public void run() {
223
+                currentActivity.toggleSideMenuVisible(animated);
224
+            }
225
+        });
226
+    }
227
+
228
+    public static void setSideMenuVisible(final boolean animated, final boolean visible) {
229
+        final NavigationActivity currentActivity = NavigationActivity.currentActivity;
230
+        if (currentActivity == null) {
231
+            return;
232
+        }
233
+
234
+        NavigationApplication.instance.runOnMainThread(new Runnable() {
235
+            @Override
236
+            public void run() {
237
+                currentActivity.setSideMenuVisible(animated, visible);
238
+            }
239
+        });
240
+    }
213 241
 }

+ 77
- 11
android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java View File

@@ -1,6 +1,7 @@
1 1
 package com.reactnativenavigation.layouts;
2 2
 
3 3
 import android.support.annotation.NonNull;
4
+import android.support.annotation.Nullable;
4 5
 import android.support.v7.app.AppCompatActivity;
5 6
 import android.view.View;
6 7
 import android.widget.RelativeLayout;
@@ -8,10 +9,12 @@ import android.widget.RelativeLayout;
8 9
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
9 10
 import com.reactnativenavigation.params.ActivityParams;
10 11
 import com.reactnativenavigation.params.ScreenParams;
12
+import com.reactnativenavigation.params.SideMenuParams;
11 13
 import com.reactnativenavigation.params.TitleBarButtonParams;
12 14
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
13 15
 import com.reactnativenavigation.screens.ScreenStack;
14 16
 import com.reactnativenavigation.views.BottomTabs;
17
+import com.reactnativenavigation.views.SideMenu;
15 18
 
16 19
 import java.util.List;
17 20
 
@@ -24,23 +27,36 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
24 27
     private ActivityParams params;
25 28
     private BottomTabs bottomTabs;
26 29
     private ScreenStack[] screenStacks;
30
+    private final SideMenuParams sideMenuParams;
31
+    private @Nullable SideMenu sideMenu;
27 32
     private int currentStackIndex = 0;
28 33
 
29 34
     public BottomTabsLayout(AppCompatActivity activity, ActivityParams params) {
30 35
         super(activity);
31 36
         this.activity = activity;
32 37
         this.params = params;
38
+        this.sideMenuParams = params.sideMenuParams;
33 39
         screenStacks = new ScreenStack[params.tabParams.size()];
34 40
         createLayout();
35 41
     }
36 42
 
37 43
     private void createLayout() {
44
+        createSideMenu();
38 45
         createBottomTabs();
39
-        addBottomTabsToScreen();
46
+        addBottomTabs();
40 47
         addScreenStacks();
41 48
         showInitialScreenStack();
42 49
     }
43 50
 
51
+    private void createSideMenu() {
52
+        if (sideMenuParams == null) {
53
+            return;
54
+        }
55
+        sideMenu = new SideMenu(getContext(), sideMenuParams);
56
+        RelativeLayout.LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
57
+        addView(sideMenu, lp);
58
+    }
59
+
44 60
     private void addScreenStacks() {
45 61
         for (int i = 0; i < screenStacks.length; i++) {
46 62
             createAndAddScreens(i);
@@ -48,12 +64,16 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
48 64
     }
49 65
 
50 66
     private void createAndAddScreens(int position) {
51
-        ScreenStack newStack = new ScreenStack(activity, this, this);
52 67
         ScreenParams screenParams = params.tabParams.get(position);
68
+        ScreenStack newStack = new ScreenStack(activity, getScreenStackParent(), screenParams.navigatorId, this);
53 69
         newStack.pushInitialScreen(screenParams, createScreenLayoutParams(screenParams));
54 70
         screenStacks[position] = newStack;
55 71
     }
56 72
 
73
+    private RelativeLayout getScreenStackParent() {
74
+        return sideMenu == null ? this : sideMenu.getContentContainer();
75
+    }
76
+
57 77
     @NonNull
58 78
     private LayoutParams createScreenLayoutParams(ScreenParams params) {
59 79
         LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
@@ -68,10 +88,10 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
68 88
         bottomTabs.addTabs(params.tabParams, this);
69 89
     }
70 90
 
71
-    private void addBottomTabsToScreen() {
91
+    private void addBottomTabs() {
72 92
         LayoutParams lp = new LayoutParams(MATCH_PARENT, WRAP_CONTENT);
73 93
         lp.addRule(ALIGN_PARENT_BOTTOM);
74
-        addView(bottomTabs, lp);
94
+        getScreenStackParent().addView(bottomTabs, lp);
75 95
     }
76 96
 
77 97
     private void showInitialScreenStack() {
@@ -126,10 +146,33 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
126 146
         }
127 147
     }
128 148
 
149
+    @Override
150
+    public void toggleSideMenuVisible(boolean animated) {
151
+        if (sideMenu != null) {
152
+            sideMenu.toggleVisible(animated);
153
+        }
154
+    }
155
+
156
+    @Override
157
+    public void setSideMenuVisible(boolean animated, boolean visible) {
158
+        if (sideMenu != null) {
159
+            sideMenu.setVisible(visible, animated);
160
+        }
161
+    }
162
+
129 163
     @Override
130 164
     public void push(ScreenParams screenParams) {
131
-        getCurrentScreenStack().push(screenParams, createScreenLayoutParams(screenParams));
132
-        bottomTabs.setStyleFromScreen(screenParams.styleParams);
165
+        ScreenStack screenStack = getScreenStack(screenParams.navigatorId);
166
+        if (screenStack == null) {
167
+            return;
168
+        }
169
+
170
+        if (isCurrentStack(screenStack)) {
171
+            screenStack.push(screenParams, createScreenLayoutParams(screenParams));
172
+            bottomTabs.setStyleFromScreen(screenParams.styleParams);
173
+        } else {
174
+            screenStack.push(screenParams, createScreenLayoutParams(screenParams));
175
+        }
133 176
     }
134 177
 
135 178
     @Override
@@ -154,7 +197,7 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
154 197
         currentScreenStack.destroy();
155 198
         removeView(currentScreenStack.peek());
156 199
 
157
-        ScreenStack newStack = new ScreenStack(activity, this, this);
200
+        ScreenStack newStack = new ScreenStack(activity, getScreenStackParent(), params.navigatorId, this);
158 201
         LayoutParams lp = createScreenLayoutParams(params);
159 202
         newStack.pushInitialScreen(params, lp);
160 203
         screenStacks[currentStackIndex] = newStack;
@@ -167,6 +210,10 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
167 210
         for (ScreenStack screenStack : screenStacks) {
168 211
             screenStack.destroy();
169 212
         }
213
+
214
+        if (sideMenu != null) {
215
+            sideMenu.destroy();
216
+        }
170 217
     }
171 218
 
172 219
     @Override
@@ -181,25 +228,38 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
181 228
     }
182 229
 
183 230
     private void showStackAndUpdateStyle(ScreenStack newStack) {
184
-        newStack.showFirstScreen();
231
+        newStack.show();
185 232
         bottomTabs.setStyleFromScreen(newStack.getCurrentScreenStyleParams());
186 233
     }
187 234
 
188 235
     private void hideCurrentStack() {
189 236
         ScreenStack currentScreenStack = getCurrentScreenStack();
190
-        currentScreenStack.hideScreen();
237
+        currentScreenStack.hide();
191 238
     }
192 239
 
193 240
     private ScreenStack getCurrentScreenStack() {
194 241
         return screenStacks[currentStackIndex];
195 242
     }
196 243
 
244
+    private @Nullable ScreenStack getScreenStack(String navigatorId) {
245
+        for (ScreenStack screenStack : screenStacks) {
246
+            if (screenStack.getNavigatorId().equals(navigatorId)) {
247
+                return screenStack;
248
+            }
249
+        }
250
+        return null;
251
+    }
252
+
253
+    private boolean isCurrentStack(ScreenStack screenStack) {
254
+        return getCurrentScreenStack() == screenStack;
255
+    }
256
+
197 257
     private void setBottomTabsStyleFromCurrentScreen() {
198 258
         bottomTabs.setStyleFromScreen(getCurrentScreenStack().getCurrentScreenStyleParams());
199 259
     }
200 260
 
201 261
     @Override
202
-    public boolean onTitleBarBackPress() {
262
+    public boolean onTitleBarBackButtonClick() {
203 263
         if (getCurrentScreenStack().canPop()) {
204 264
             getCurrentScreenStack().pop(true, new ScreenStack.OnScreenPop() {
205 265
                 @Override
@@ -209,7 +269,13 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
209 269
             });
210 270
             return true;
211 271
         }
212
-
213 272
         return false;
214 273
     }
274
+
275
+    @Override
276
+    public void onSideMenuButtonClick() {
277
+        if (sideMenu != null) {
278
+            sideMenu.openDrawer();
279
+        }
280
+    }
215 281
 }

+ 4
- 0
android/app/src/main/java/com/reactnativenavigation/layouts/Layout.java View File

@@ -19,4 +19,8 @@ public interface Layout extends ScreenStackContainer {
19 19
     void setTitleBarRightButtons(String screenInstanceId, String navigatorEventId, List<TitleBarButtonParams> titleBarButtons);
20 20
 
21 21
     void setTitleBarLeftButton(String screenInstanceId, String navigatorEventId, TitleBarLeftButtonParams titleBarLeftButtonParams);
22
+
23
+    void toggleSideMenuVisible(boolean animated);
24
+
25
+    void setSideMenuVisible(boolean animated, boolean visible);
22 26
 }

+ 3
- 2
android/app/src/main/java/com/reactnativenavigation/layouts/LayoutFactory.java View File

@@ -1,6 +1,7 @@
1 1
 package com.reactnativenavigation.layouts;
2 2
 
3 3
 import android.support.v7.app.AppCompatActivity;
4
+import android.util.Log;
4 5
 
5 6
 import com.reactnativenavigation.params.ActivityParams;
6 7
 
@@ -16,7 +17,7 @@ public class LayoutFactory {
16 17
     }
17 18
 
18 19
     private static Layout createSingleScreenLayout(AppCompatActivity activity, ActivityParams params) {
19
-        return new SingleScreenLayout(activity, params.screenParams);
20
+        return new SingleScreenLayout(activity, params.sideMenuParams, params.screenParams);
20 21
     }
21 22
 
22 23
     private static Layout createBottomTabsScreenLayout(AppCompatActivity activity, ActivityParams params) {
@@ -27,7 +28,7 @@ public class LayoutFactory {
27 28
     }
28 29
 
29 30
     private static void removeAllButTheFirst5Tabs(ActivityParams params) {
30
-        android.util.Log.e("LOG", "LayoutFactory:createBottomTabsScreenLayout() does not support more than 5 tabs, currently");
31
+        Log.e("Navigation", "LayoutFactory:createBottomTabsScreenLayout() does not support more than 5 tabs, currently");
31 32
         while (params.tabParams.size() > 5) {
32 33
             params.tabParams.remove(params.tabParams.size() - 1);
33 34
         }

+ 2
- 2
android/app/src/main/java/com/reactnativenavigation/layouts/ScreenStackContainer.java View File

@@ -1,9 +1,9 @@
1 1
 package com.reactnativenavigation.layouts;
2 2
 
3 3
 import com.reactnativenavigation.params.ScreenParams;
4
-import com.reactnativenavigation.views.TitleBarBackButtonListener;
4
+import com.reactnativenavigation.views.LeftButtonOnClickListener;
5 5
 
6
-public interface ScreenStackContainer extends TitleBarBackButtonListener {
6
+public interface ScreenStackContainer extends LeftButtonOnClickListener {
7 7
     void push(ScreenParams screenParams);
8 8
 
9 9
     void pop(ScreenParams screenParams);

+ 66
- 18
android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java View File

@@ -1,46 +1,69 @@
1 1
 package com.reactnativenavigation.layouts;
2 2
 
3
+import android.support.annotation.Nullable;
3 4
 import android.support.v7.app.AppCompatActivity;
4 5
 import android.view.View;
5 6
 import android.widget.RelativeLayout;
6 7
 
7 8
 import com.reactnativenavigation.params.ScreenParams;
9
+import com.reactnativenavigation.params.SideMenuParams;
8 10
 import com.reactnativenavigation.params.TitleBarButtonParams;
9 11
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
10
-import com.reactnativenavigation.screens.ScreenAnimator;
11 12
 import com.reactnativenavigation.screens.ScreenStack;
12
-import com.reactnativenavigation.views.TitleBarBackButtonListener;
13
+import com.reactnativenavigation.views.LeftButtonOnClickListener;
14
+import com.reactnativenavigation.views.SideMenu;
13 15
 
14 16
 import java.util.List;
15 17
 
18
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
19
+
16 20
 public class SingleScreenLayout extends RelativeLayout implements Layout {
17 21
 
18 22
     private final AppCompatActivity activity;
19 23
     private final ScreenParams screenParams;
24
+    private final SideMenuParams sideMenuParams;
20 25
     private ScreenStack stack;
21
-    private ScreenAnimator screenAnimator;
22
-    private TitleBarBackButtonListener titleBarBackButtonListener;
26
+    private LeftButtonOnClickListener leftButtonOnClickListener;
27
+    private @Nullable SideMenu sideMenu;
23 28
 
24
-    public SingleScreenLayout(AppCompatActivity activity, ScreenParams screenParams, TitleBarBackButtonListener titleBarBackButtonListener) {
25
-        this(activity, screenParams);
26
-        this.titleBarBackButtonListener = titleBarBackButtonListener;
29
+    public SingleScreenLayout(AppCompatActivity activity, ScreenParams screenParams,
30
+                              LeftButtonOnClickListener leftButtonOnClickListener) {
31
+        this(activity, null, screenParams);
32
+        this.leftButtonOnClickListener = leftButtonOnClickListener;
27 33
     }
28 34
 
29
-    public SingleScreenLayout(AppCompatActivity activity, ScreenParams screenParams) {
35
+    public SingleScreenLayout(AppCompatActivity activity, @Nullable SideMenuParams sideMenuParams, ScreenParams screenParams) {
30 36
         super(activity);
31 37
         this.activity = activity;
32 38
         this.screenParams = screenParams;
33
-        createStack();
39
+        this.sideMenuParams = sideMenuParams;
40
+        createLayout();
41
+    }
42
+
43
+    private void createLayout() {
44
+        if (sideMenuParams == null) {
45
+            createStack(this);
46
+        } else {
47
+            sideMenu = createSideMenu();
48
+            createStack(sideMenu.getContentContainer());
49
+        }
34 50
     }
35 51
 
36
-    private void createStack() {
52
+    private SideMenu createSideMenu() {
53
+        SideMenu sideMenu = new SideMenu(getContext(), sideMenuParams);
54
+        RelativeLayout.LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
55
+        addView(sideMenu, lp);
56
+        return sideMenu;
57
+    }
58
+
59
+    private void createStack(RelativeLayout parent) {
37 60
         if (stack != null) {
38 61
             stack.destroy();
39 62
         }
40
-        stack = new ScreenStack(activity, this, this);
41
-        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
63
+        stack = new ScreenStack(activity, parent, screenParams.navigatorId, this);
64
+        LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
42 65
         stack.pushInitialScreen(screenParams, lp);
43
-        stack.showFirstScreen();
66
+        stack.show();
44 67
     }
45 68
 
46 69
     @Override
@@ -56,11 +79,14 @@ public class SingleScreenLayout extends RelativeLayout implements Layout {
56 79
     @Override
57 80
     public void destroy() {
58 81
         stack.destroy();
82
+        if (sideMenu != null) {
83
+            sideMenu.destroy();
84
+        }
59 85
     }
60 86
 
61 87
     @Override
62 88
     public void push(ScreenParams params) {
63
-        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
89
+        LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
64 90
         stack.push(params, lp);
65 91
     }
66 92
 
@@ -76,7 +102,8 @@ public class SingleScreenLayout extends RelativeLayout implements Layout {
76 102
 
77 103
     @Override
78 104
     public void newStack(ScreenParams params) {
79
-        createStack();
105
+        RelativeLayout parent = sideMenu == null ? this : sideMenu.getContentContainer();
106
+        createStack(parent);
80 107
     }
81 108
 
82 109
     @Override
@@ -106,11 +133,32 @@ public class SingleScreenLayout extends RelativeLayout implements Layout {
106 133
     }
107 134
 
108 135
     @Override
109
-    public boolean onTitleBarBackPress() {
110
-        if (titleBarBackButtonListener != null) {
111
-            return titleBarBackButtonListener.onTitleBarBackPress();
136
+    public void toggleSideMenuVisible(boolean animated) {
137
+        if (sideMenu != null) {
138
+            sideMenu.toggleVisible(animated);
139
+        }
140
+    }
141
+
142
+    @Override
143
+    public void setSideMenuVisible(boolean animated, boolean visible) {
144
+        if (sideMenu != null) {
145
+            sideMenu.setVisible(visible, animated);
146
+        }
147
+    }
148
+
149
+    @Override
150
+    public boolean onTitleBarBackButtonClick() {
151
+        if (leftButtonOnClickListener != null) {
152
+            return leftButtonOnClickListener.onTitleBarBackButtonClick();
112 153
         }
113 154
 
114 155
         return onBackPressed();
115 156
     }
157
+
158
+    @Override
159
+    public void onSideMenuButtonClick() {
160
+        if (sideMenu != null) {
161
+            sideMenu.openDrawer();
162
+        }
163
+    }
116 164
 }

+ 1
- 0
android/app/src/main/java/com/reactnativenavigation/params/ActivityParams.java View File

@@ -10,4 +10,5 @@ public class ActivityParams {
10 10
     public Type type;
11 11
     public ScreenParams screenParams;
12 12
     public List<ScreenParams> tabParams;
13
+    public SideMenuParams sideMenuParams;
13 14
 }

+ 1
- 0
android/app/src/main/java/com/reactnativenavigation/params/ScreenParams.java View File

@@ -21,6 +21,7 @@ public class ScreenParams {
21 21
 
22 22
     public String screenInstanceId;
23 23
     public String navigatorEventId;
24
+    public String navigatorId;
24 25
     public Bundle navigationParams;
25 26
 
26 27
     public boolean hasTopTabs() {

+ 9
- 0
android/app/src/main/java/com/reactnativenavigation/params/SideMenuParams.java View File

@@ -0,0 +1,9 @@
1
+package com.reactnativenavigation.params;
2
+
3
+import android.os.Bundle;
4
+
5
+public class SideMenuParams {
6
+    public String screenId;
7
+    public Bundle navigationParams;
8
+    public boolean disableOpenGesture;
9
+}

+ 4
- 0
android/app/src/main/java/com/reactnativenavigation/params/parsers/ActivityParamsParser.java View File

@@ -21,6 +21,10 @@ public class ActivityParamsParser extends Parser {
21 21
             result.tabParams = ScreenParamsParser.parseTabs(params.getBundle("tabs"));
22 22
         }
23 23
 
24
+        if (hasKey(params, "sideMenu")) {
25
+            result.sideMenuParams = SideMenuParamsParser.parse(params.getBundle("sideMenu"));
26
+        }
27
+
24 28
         return result;
25 29
     }
26 30
 }

+ 2
- 0
android/app/src/main/java/com/reactnativenavigation/params/parsers/ScreenParamsParser.java View File

@@ -17,6 +17,7 @@ public class ScreenParamsParser extends Parser {
17 17
     private static final String KEY_SCREEN_ID = "screenId";
18 18
     private static final String KEY_SCREEN_INSTANCE_ID = "screenInstanceID";
19 19
     private static final String KEY_NAVIGATOR_EVENT_ID = "navigatorEventID";
20
+    private static final String KEY_NAVIGATOR_ID = "navigatorID";
20 21
     private static final String KEY_NAVIGATION_PARAMS = "navigationParams";
21 22
     private static final String KEY_RIGHT_BUTTONS = "rightButtons";
22 23
     private static final String KEY_LEFT_BUTTON = "leftButton";
@@ -34,6 +35,7 @@ public class ScreenParamsParser extends Parser {
34 35
         assertKeyExists(params, KEY_NAVIGATION_PARAMS);
35 36
         result.navigationParams = params.getBundle(KEY_NAVIGATION_PARAMS);
36 37
         result.navigatorEventId = result.navigationParams.getString(KEY_NAVIGATOR_EVENT_ID);
38
+        result.navigatorId = result.navigationParams.getString(KEY_NAVIGATOR_ID);
37 39
         result.screenInstanceId = result.navigationParams.getString(KEY_SCREEN_INSTANCE_ID);
38 40
 
39 41
         result.styleParams = new StyleParamsParser(params.getBundle(STYLE_PARAMS)).parse();

+ 16
- 0
android/app/src/main/java/com/reactnativenavigation/params/parsers/SideMenuParamsParser.java View File

@@ -0,0 +1,16 @@
1
+package com.reactnativenavigation.params.parsers;
2
+
3
+import android.os.Bundle;
4
+
5
+import com.reactnativenavigation.params.SideMenuParams;
6
+
7
+public class SideMenuParamsParser extends Parser {
8
+
9
+    public static SideMenuParams parse(Bundle sideMenu) {
10
+        SideMenuParams result = new SideMenuParams();
11
+        result.screenId = sideMenu.getString("screenId");
12
+        result.navigationParams = sideMenu.getBundle("navigationParams");
13
+        result.disableOpenGesture = sideMenu.getBoolean("disableOpenGesture", false);
14
+        return result;
15
+    }
16
+}

+ 3
- 3
android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarLeftButtonParamsParser.java View File

@@ -8,9 +8,9 @@ import com.reactnativenavigation.params.TitleBarLeftButtonParams;
8 8
 public class TitleBarLeftButtonParamsParser extends TitleBarButtonParamsParser {
9 9
 
10 10
     public TitleBarLeftButtonParams parseSingleButton(Bundle params) {
11
-        TitleBarLeftButtonParams backButtonParams = new TitleBarLeftButtonParams(super.parseSingleButton(params));
12
-        backButtonParams.iconState = getIconStateFromId(backButtonParams.eventId);
13
-        return backButtonParams;
11
+        TitleBarLeftButtonParams leftButtonParams = new TitleBarLeftButtonParams(super.parseSingleButton(params));
12
+        leftButtonParams.iconState = getIconStateFromId(leftButtonParams.eventId);
13
+        return leftButtonParams;
14 14
     }
15 15
 
16 16
     private MaterialMenuDrawable.IconState getIconStateFromId(String id) {

+ 3
- 4
android/app/src/main/java/com/reactnativenavigation/screens/FragmentScreen.java View File

@@ -11,7 +11,7 @@ import android.widget.FrameLayout;
11 11
 import com.reactnativenavigation.R;
12 12
 import com.reactnativenavigation.params.ScreenParams;
13 13
 import com.reactnativenavigation.views.ContentView;
14
-import com.reactnativenavigation.views.TitleBarBackButtonListener;
14
+import com.reactnativenavigation.views.LeftButtonOnClickListener;
15 15
 
16 16
 import java.lang.reflect.InvocationTargetException;
17 17
 import java.lang.reflect.Method;
@@ -25,8 +25,8 @@ public class FragmentScreen extends Screen {
25 25
     private static final String CONTRACT_GET_SUPPORT_FRAGMENT = "getSupportFragment";
26 26
     private FrameLayout content;
27 27
 
28
-    public FragmentScreen(AppCompatActivity activity, ScreenParams screenParams, TitleBarBackButtonListener titleBarBackButtonListener) {
29
-        super(activity, screenParams, titleBarBackButtonListener);
28
+    public FragmentScreen(AppCompatActivity activity, ScreenParams screenParams, LeftButtonOnClickListener leftButtonOnClickListener) {
29
+        super(activity, screenParams, leftButtonOnClickListener);
30 30
     }
31 31
 
32 32
     @Override
@@ -40,7 +40,6 @@ public class FragmentScreen extends Screen {
40 40
     private void addContent() {
41 41
         ContentView contentView = new ContentView(getContext(),
42 42
                 screenParams.screenId,
43
-                screenParams.navigatorEventId,
44 43
                 screenParams.navigationParams);
45 44
         addView(contentView, 0, 0);
46 45
         LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT);

+ 6
- 6
android/app/src/main/java/com/reactnativenavigation/screens/Screen.java View File

@@ -14,7 +14,7 @@ import com.reactnativenavigation.params.StyleParams;
14 14
 import com.reactnativenavigation.params.TitleBarButtonParams;
15 15
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
16 16
 import com.reactnativenavigation.utils.ViewUtils;
17
-import com.reactnativenavigation.views.TitleBarBackButtonListener;
17
+import com.reactnativenavigation.views.LeftButtonOnClickListener;
18 18
 import com.reactnativenavigation.views.TopBar;
19 19
 
20 20
 import java.util.List;
@@ -27,15 +27,15 @@ public abstract class Screen extends RelativeLayout {
27 27
     protected final AppCompatActivity activity;
28 28
     protected final ScreenParams screenParams;
29 29
     protected TopBar topBar;
30
-    private final TitleBarBackButtonListener titleBarBackButtonListener;
30
+    private final LeftButtonOnClickListener leftButtonOnClickListener;
31 31
     private VisibilityAnimator topBarVisibilityAnimator;
32 32
     private ScreenAnimator screenAnimator;
33 33
 
34
-    public Screen(AppCompatActivity activity, ScreenParams screenParams, TitleBarBackButtonListener titleBarBackButtonListener) {
34
+    public Screen(AppCompatActivity activity, ScreenParams screenParams, LeftButtonOnClickListener leftButtonOnClickListener) {
35 35
         super(activity);
36 36
         this.activity = activity;
37 37
         this.screenParams = screenParams;
38
-        this.titleBarBackButtonListener = titleBarBackButtonListener;
38
+        this.leftButtonOnClickListener = leftButtonOnClickListener;
39 39
 
40 40
         screenAnimator = new ScreenAnimator(this);
41 41
         createViews();
@@ -61,7 +61,7 @@ public abstract class Screen extends RelativeLayout {
61 61
             screenParams.leftButton.setColorFromScreenStyle(screenParams.styleParams.titleBarButtonColor);
62 62
         }
63 63
         topBar.addTitleBarAndSetButtons(screenParams.rightButtons, screenParams.leftButton,
64
-                titleBarBackButtonListener, screenParams.navigatorEventId);
64
+                leftButtonOnClickListener, screenParams.navigatorEventId);
65 65
     }
66 66
 
67 67
     private void createTopBar() {
@@ -138,7 +138,7 @@ public abstract class Screen extends RelativeLayout {
138 138
         topBar.setTitleBarRightButtons(navigatorEventId, titleBarButtons);
139 139
     }
140 140
 
141
-    public void setTitleBarLeftButton(String navigatorEventId, TitleBarBackButtonListener backButtonListener,
141
+    public void setTitleBarLeftButton(String navigatorEventId, LeftButtonOnClickListener backButtonListener,
142 142
                                       TitleBarLeftButtonParams titleBarLeftButtonParams) {
143 143
         topBar.setTitleBarRightButton(navigatorEventId, backButtonListener, titleBarLeftButtonParams);
144 144
     }

+ 5
- 5
android/app/src/main/java/com/reactnativenavigation/screens/ScreenFactory.java View File

@@ -3,18 +3,18 @@ package com.reactnativenavigation.screens;
3 3
 import android.support.v7.app.AppCompatActivity;
4 4
 
5 5
 import com.reactnativenavigation.params.ScreenParams;
6
-import com.reactnativenavigation.views.TitleBarBackButtonListener;
6
+import com.reactnativenavigation.views.LeftButtonOnClickListener;
7 7
 
8 8
 public class ScreenFactory {
9 9
     public static Screen create(AppCompatActivity activity,
10 10
                                 ScreenParams screenParams,
11
-                                TitleBarBackButtonListener titleBarBackButtonListener) {
11
+                                LeftButtonOnClickListener leftButtonOnClickListener) {
12 12
         if (screenParams.isFragmentScreen()) {
13
-            return new FragmentScreen(activity, screenParams, titleBarBackButtonListener);
13
+            return new FragmentScreen(activity, screenParams, leftButtonOnClickListener);
14 14
         } else if (screenParams.hasTopTabs()) {
15
-            return new ViewPagerScreen(activity, screenParams, titleBarBackButtonListener);
15
+            return new ViewPagerScreen(activity, screenParams, leftButtonOnClickListener);
16 16
         } else {
17
-            return new SingleScreen(activity, screenParams, titleBarBackButtonListener);
17
+            return new SingleScreen(activity, screenParams, leftButtonOnClickListener);
18 18
         }
19 19
     }
20 20
 }

+ 36
- 9
android/app/src/main/java/com/reactnativenavigation/screens/ScreenStack.java View File

@@ -11,7 +11,7 @@ import com.reactnativenavigation.params.TitleBarButtonParams;
11 11
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
12 12
 import com.reactnativenavigation.utils.KeyboardVisibilityDetector;
13 13
 import com.reactnativenavigation.utils.Task;
14
-import com.reactnativenavigation.views.TitleBarBackButtonListener;
14
+import com.reactnativenavigation.views.LeftButtonOnClickListener;
15 15
 
16 16
 import java.util.List;
17 17
 import java.util.Stack;
@@ -24,28 +24,45 @@ public class ScreenStack {
24 24
 
25 25
     private final AppCompatActivity activity;
26 26
     private RelativeLayout parent;
27
-    private TitleBarBackButtonListener titleBarBackButtonListener;
27
+    private LeftButtonOnClickListener leftButtonOnClickListener;
28 28
     private Stack<Screen> stack = new Stack<>();
29 29
     private final KeyboardVisibilityDetector keyboardVisibilityDetector;
30
+    private boolean isStackVisible = false;
31
+    private final String navigatorId;
32
+
33
+    public String getNavigatorId() {
34
+        return navigatorId;
35
+    }
30 36
 
31 37
     public ScreenStack(AppCompatActivity activity,
32 38
                        RelativeLayout parent,
33
-                       TitleBarBackButtonListener titleBarBackButtonListener) {
39
+                       String navigatorId,
40
+                       LeftButtonOnClickListener leftButtonOnClickListener) {
34 41
         this.activity = activity;
35 42
         this.parent = parent;
36
-        this.titleBarBackButtonListener = titleBarBackButtonListener;
43
+        this.navigatorId = navigatorId;
44
+        this.leftButtonOnClickListener = leftButtonOnClickListener;
37 45
         keyboardVisibilityDetector = new KeyboardVisibilityDetector(parent);
38 46
     }
39 47
 
40 48
     public void pushInitialScreen(ScreenParams initialScreenParams, RelativeLayout.LayoutParams params) {
41
-        Screen initialScreen = ScreenFactory.create(activity, initialScreenParams, titleBarBackButtonListener);
49
+        Screen initialScreen = ScreenFactory.create(activity, initialScreenParams, leftButtonOnClickListener);
42 50
         initialScreen.setVisibility(View.INVISIBLE);
43 51
         addScreen(initialScreen, params);
44 52
     }
45 53
 
46 54
     public void push(final ScreenParams params, RelativeLayout.LayoutParams layoutParams) {
47
-        Screen nextScreen = ScreenFactory.create(activity, params, titleBarBackButtonListener);
55
+        Screen nextScreen = ScreenFactory.create(activity, params, leftButtonOnClickListener);
48 56
         final Screen previousScreen = stack.peek();
57
+        if (isStackVisible) {
58
+            pushScreenToVisibleStack(params, layoutParams, nextScreen, previousScreen);
59
+        } else {
60
+            pushScreenToInvisibleStack(layoutParams, nextScreen, previousScreen);
61
+        }
62
+    }
63
+
64
+    private void pushScreenToVisibleStack(ScreenParams params, RelativeLayout.LayoutParams layoutParams,
65
+                                          Screen nextScreen, final Screen previousScreen) {
49 66
         addScreen(nextScreen, layoutParams);
50 67
         nextScreen.show(params.animateScreenTransitions, new Runnable() {
51 68
             @Override
@@ -55,6 +72,13 @@ public class ScreenStack {
55 72
         });
56 73
     }
57 74
 
75
+    private void pushScreenToInvisibleStack(RelativeLayout.LayoutParams layoutParams, Screen nextScreen,
76
+                                            Screen previousScreen) {
77
+        nextScreen.setVisibility(View.INVISIBLE);
78
+        addScreen(nextScreen, layoutParams);
79
+        removePreviousWithoutUnmount(previousScreen);
80
+    }
81
+
58 82
     private void addScreen(Screen screen, RelativeLayout.LayoutParams layoutParams) {
59 83
         parent.addView(screen, layoutParams);
60 84
         stack.push(screen);
@@ -109,6 +133,7 @@ public class ScreenStack {
109 133
     }
110 134
 
111 135
     private void readdPrevious(Screen previous) {
136
+        previous.setVisibility(View.VISIBLE);
112 137
         parent.addView(previous, 0);
113 138
         previous.preventMountAfterReattachedToWindow();
114 139
     }
@@ -166,7 +191,7 @@ public class ScreenStack {
166 191
         performOnScreen(screenInstanceId, new Task<Screen>() {
167 192
             @Override
168 193
             public void run(Screen param) {
169
-                param.setTitleBarLeftButton(navigatorEventId, titleBarBackButtonListener, titleBarLeftButtonParams);
194
+                param.setTitleBarLeftButton(navigatorEventId, leftButtonOnClickListener, titleBarLeftButtonParams);
170 195
             }
171 196
         });
172 197
     }
@@ -188,11 +213,13 @@ public class ScreenStack {
188 213
         }
189 214
     }
190 215
 
191
-    public void showFirstScreen() {
216
+    public void show() {
217
+        isStackVisible = true;
192 218
         stack.peek().setVisibility(View.VISIBLE);
193 219
     }
194 220
 
195
-    public void hideScreen() {
221
+    public void hide() {
222
+        isStackVisible = false;
196 223
         stack.peek().setVisibility(View.INVISIBLE);
197 224
     }
198 225
 }

+ 3
- 3
android/app/src/main/java/com/reactnativenavigation/screens/SingleScreen.java View File

@@ -4,7 +4,7 @@ import android.support.v7.app.AppCompatActivity;
4 4
 
5 5
 import com.reactnativenavigation.params.ScreenParams;
6 6
 import com.reactnativenavigation.views.ContentView;
7
-import com.reactnativenavigation.views.TitleBarBackButtonListener;
7
+import com.reactnativenavigation.views.LeftButtonOnClickListener;
8 8
 
9 9
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
10 10
 
@@ -13,13 +13,13 @@ public class SingleScreen extends Screen {
13 13
     private ContentView contentView;
14 14
 
15 15
     public SingleScreen(AppCompatActivity activity, ScreenParams screenParams,
16
-                        TitleBarBackButtonListener titleBarBarBackButtonListener) {
16
+                        LeftButtonOnClickListener titleBarBarBackButtonListener) {
17 17
         super(activity, screenParams, titleBarBarBackButtonListener);
18 18
     }
19 19
 
20 20
     @Override
21 21
     protected void createContent() {
22
-        contentView = new ContentView(getContext(), screenParams.screenId, screenParams.navigatorEventId, screenParams.navigationParams);
22
+        contentView = new ContentView(getContext(), screenParams.screenId, screenParams.navigationParams);
23 23
         LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
24 24
         if (screenParams.styleParams.drawScreenBelowTopBar) {
25 25
             params.addRule(BELOW, topBar.getId());

+ 3
- 3
android/app/src/main/java/com/reactnativenavigation/screens/ViewPagerScreen.java View File

@@ -7,7 +7,7 @@ import android.support.v7.app.AppCompatActivity;
7 7
 import com.reactnativenavigation.params.ScreenParams;
8 8
 import com.reactnativenavigation.params.TopTabParams;
9 9
 import com.reactnativenavigation.views.ContentView;
10
-import com.reactnativenavigation.views.TitleBarBackButtonListener;
10
+import com.reactnativenavigation.views.LeftButtonOnClickListener;
11 11
 
12 12
 import java.util.ArrayList;
13 13
 import java.util.List;
@@ -20,7 +20,7 @@ public class ViewPagerScreen extends Screen {
20 20
     private List<ContentView> contentViews;
21 21
     private ViewPager viewPager;
22 22
 
23
-    public ViewPagerScreen(AppCompatActivity activity, ScreenParams screenParams, TitleBarBackButtonListener backButtonListener) {
23
+    public ViewPagerScreen(AppCompatActivity activity, ScreenParams screenParams, LeftButtonOnClickListener backButtonListener) {
24 24
         super(activity, screenParams, backButtonListener);
25 25
     }
26 26
 
@@ -45,7 +45,7 @@ public class ViewPagerScreen extends Screen {
45 45
     private void addPages() {
46 46
         contentViews = new ArrayList<>();
47 47
         for (TopTabParams tab : screenParams.topTabParams) {
48
-            ContentView contentView = new ContentView(getContext(), tab.screenId, screenParams.navigatorEventId, tab.navigationParams);
48
+            ContentView contentView = new ContentView(getContext(), tab.screenId, tab.navigationParams, screenParams.navigatorEventId);
49 49
             addContent(contentView);
50 50
             contentViews.add(contentView);
51 51
         }

+ 6
- 2
android/app/src/main/java/com/reactnativenavigation/views/ContentView.java View File

@@ -10,10 +10,14 @@ import com.reactnativenavigation.react.ReactViewHacks;
10 10
 public class ContentView extends ReactRootView {
11 11
 
12 12
     private final String screenId;
13
-    private final String navigatorEventId;
13
+    private String navigatorEventId;
14 14
     private final Bundle navigationParams;
15 15
 
16
-    public ContentView(Context context, String screenId, String navigatorEventId, Bundle navigationParams) {
16
+    public ContentView(Context context, String screenId, Bundle navigationParams) {
17
+        this(context, screenId, navigationParams, null);
18
+    }
19
+
20
+    public ContentView(Context context, String screenId, Bundle navigationParams, String navigatorEventId) {
17 21
         super(context);
18 22
         this.screenId = screenId;
19 23
         this.navigatorEventId = navigatorEventId;

+ 10
- 4
android/app/src/main/java/com/reactnativenavigation/views/LeftButton.java View File

@@ -19,16 +19,16 @@ public class LeftButton extends MaterialMenuDrawable implements View.OnClickList
19 19
     }
20 20
 
21 21
     private TitleBarLeftButtonParams params;
22
-    private final TitleBarBackButtonListener titleBarBackButtonListener;
22
+    private final LeftButtonOnClickListener onClickListener;
23 23
     private final String navigatorEventId;
24 24
 
25 25
     public LeftButton(Context context,
26 26
                       TitleBarLeftButtonParams params,
27
-                      TitleBarBackButtonListener titleBarBackButtonListener,
27
+                      LeftButtonOnClickListener onClickListener,
28 28
                       String navigatorEventId) {
29 29
         super(context, getColor(params), Stroke.THIN);
30 30
         this.params = params;
31
-        this.titleBarBackButtonListener = titleBarBackButtonListener;
31
+        this.onClickListener = onClickListener;
32 32
         this.navigatorEventId = navigatorEventId;
33 33
         setInitialState();
34 34
     }
@@ -44,7 +44,9 @@ public class LeftButton extends MaterialMenuDrawable implements View.OnClickList
44 44
     @Override
45 45
     public void onClick(View v) {
46 46
         if (isBackButton()) {
47
-            titleBarBackButtonListener.onTitleBarBackPress();
47
+            onClickListener.onTitleBarBackButtonClick();
48
+        } else if (isSideMenuButton()) {
49
+            onClickListener.onSideMenuButtonClick();
48 50
         } else {
49 51
             sendClickEvent();
50 52
         }
@@ -62,6 +64,10 @@ public class LeftButton extends MaterialMenuDrawable implements View.OnClickList
62 64
         return getIconState() == IconState.ARROW;
63 65
     }
64 66
 
67
+    private boolean isSideMenuButton() {
68
+        return getIconState() == IconState.BURGER;
69
+    }
70
+
65 71
     private void sendClickEvent() {
66 72
         NavigationApplication.instance.sendNavigatorEvent(params.eventId, navigatorEventId);
67 73
     }

+ 7
- 0
android/app/src/main/java/com/reactnativenavigation/views/LeftButtonOnClickListener.java View File

@@ -0,0 +1,7 @@
1
+package com.reactnativenavigation.views;
2
+
3
+public interface LeftButtonOnClickListener {
4
+    boolean onTitleBarBackButtonClick();
5
+
6
+    void onSideMenuButtonClick();
7
+}

+ 74
- 0
android/app/src/main/java/com/reactnativenavigation/views/SideMenu.java View File

@@ -0,0 +1,74 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.content.Context;
4
+import android.support.v4.widget.DrawerLayout;
5
+import android.view.Gravity;
6
+import android.widget.RelativeLayout;
7
+
8
+import com.reactnativenavigation.params.SideMenuParams;
9
+import com.reactnativenavigation.utils.ViewUtils;
10
+
11
+public class SideMenu extends DrawerLayout {
12
+
13
+    private ContentView sideMenuView;
14
+    private RelativeLayout contentContainer;
15
+
16
+    public RelativeLayout getContentContainer() {
17
+        return contentContainer;
18
+    }
19
+
20
+    public void destroy() {
21
+        sideMenuView.ensureUnmountOnDetachedFromWindow();
22
+        removeView(sideMenuView);
23
+    }
24
+
25
+    public void setVisible(boolean visible, boolean animated) {
26
+        if (!isShown() && visible) {
27
+            openDrawer(animated);
28
+        }
29
+
30
+        if (isShown() && !visible) {
31
+            closeDrawer(animated);
32
+        }
33
+    }
34
+
35
+    public void openDrawer() {
36
+        openDrawer(Gravity.LEFT);
37
+    }
38
+
39
+    public void openDrawer(boolean animated) {
40
+        openDrawer(Gravity.LEFT, animated);
41
+    }
42
+
43
+    public void closeDrawer(boolean animated) {
44
+        closeDrawer(Gravity.LEFT, animated);
45
+    }
46
+
47
+    public void toggleVisible(boolean animated) {
48
+        if (isShown()) {
49
+            closeDrawer(animated);
50
+        } else {
51
+            openDrawer(animated);
52
+        }
53
+    }
54
+
55
+    public SideMenu(Context context, SideMenuParams sideMenuParams) {
56
+        super(context);
57
+        createContentContainer();
58
+        createSideMenu(sideMenuParams);
59
+    }
60
+
61
+    private void createContentContainer() {
62
+        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
63
+        contentContainer = new RelativeLayout(getContext());
64
+        contentContainer.setId(ViewUtils.generateViewId());
65
+        addView(contentContainer, lp);
66
+    }
67
+
68
+    private void createSideMenu(SideMenuParams sideMenuParams) {
69
+        sideMenuView = new ContentView(getContext(), sideMenuParams.screenId, sideMenuParams.navigationParams);
70
+        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
71
+        lp.gravity = Gravity.START;
72
+        addView(sideMenuView, lp);
73
+    }
74
+}

+ 4
- 4
android/app/src/main/java/com/reactnativenavigation/views/TitleBar.java View File

@@ -46,9 +46,9 @@ public class TitleBar extends Toolbar {
46 46
     }
47 47
 
48 48
     public void setLeftButton(TitleBarLeftButtonParams leftButtonParams,
49
-                               TitleBarBackButtonListener titleBarBackButtonListener, String navigatorEventId) {
49
+                              LeftButtonOnClickListener leftButtonOnClickListener, String navigatorEventId) {
50 50
         if (shouldSetLeftButton(leftButtonParams)) {
51
-            createAndSetLeftButton(leftButtonParams, titleBarBackButtonListener, navigatorEventId);
51
+            createAndSetLeftButton(leftButtonParams, leftButtonOnClickListener, navigatorEventId);
52 52
         } else if (hasLeftButton()) {
53 53
             updateLeftButton(leftButtonParams);
54 54
         }
@@ -101,8 +101,8 @@ public class TitleBar extends Toolbar {
101 101
         return leftButton == null && leftButtonParams != null;
102 102
     }
103 103
 
104
-    private void createAndSetLeftButton(TitleBarLeftButtonParams leftButtonParams, TitleBarBackButtonListener titleBarBackButtonListener, String navigatorEventId) {
105
-        leftButton = new LeftButton(getContext(), leftButtonParams, titleBarBackButtonListener, navigatorEventId);
104
+    private void createAndSetLeftButton(TitleBarLeftButtonParams leftButtonParams, LeftButtonOnClickListener leftButtonOnClickListener, String navigatorEventId) {
105
+        leftButton = new LeftButton(getContext(), leftButtonParams, leftButtonOnClickListener, navigatorEventId);
106 106
         setNavigationOnClickListener(leftButton);
107 107
         setNavigationIcon(leftButton);
108 108
     }

+ 0
- 5
android/app/src/main/java/com/reactnativenavigation/views/TitleBarBackButtonListener.java View File

@@ -1,5 +0,0 @@
1
-package com.reactnativenavigation.views;
2
-
3
-public interface TitleBarBackButtonListener {
4
-    boolean onTitleBarBackPress();
5
-}

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

@@ -24,12 +24,12 @@ public class TopBar extends AppBarLayout {
24 24
 
25 25
     public void addTitleBarAndSetButtons(List<TitleBarButtonParams> rightButtons,
26 26
                                          TitleBarLeftButtonParams leftButton,
27
-                                         TitleBarBackButtonListener titleBarBackButtonListener,
27
+                                         LeftButtonOnClickListener leftButtonOnClickListener,
28 28
                                          String navigatorEventId) {
29 29
         titleBar = new TitleBar(getContext());
30 30
         addView(titleBar);
31 31
         titleBar.setRightButtons(rightButtons, navigatorEventId);
32
-        titleBar.setLeftButton(leftButton, titleBarBackButtonListener, navigatorEventId);
32
+        titleBar.setLeftButton(leftButton, leftButtonOnClickListener, navigatorEventId);
33 33
     }
34 34
 
35 35
     public void setTitle(String title) {
@@ -56,9 +56,9 @@ public class TopBar extends AppBarLayout {
56 56
     }
57 57
 
58 58
     public void setTitleBarRightButton(String navigatorEventId,
59
-                                       TitleBarBackButtonListener titleBarBackButtonListener,
59
+                                       LeftButtonOnClickListener leftButtonOnClickListener,
60 60
                                        TitleBarLeftButtonParams titleBarLeftButtonParams) {
61
-        titleBar.setLeftButton(titleBarLeftButtonParams, titleBarBackButtonListener, navigatorEventId);
61
+        titleBar.setLeftButton(titleBarLeftButtonParams, leftButtonOnClickListener, navigatorEventId);
62 62
     }
63 63
 
64 64
     private void setTopTabsStyle(StyleParams style) {

+ 86
- 71
example-redux/src/app.js View File

@@ -35,76 +35,82 @@ export default class App {
35 35
   startApp(root) {
36 36
     switch (root) {
37 37
       case 'login':
38
-        //Navigation.startSingleScreenApp({
39
-        //  screen: {
40
-        //    screen: 'example.LoginScreen',
41
-        //    title: 'Login',
42
-        //    navigatorStyle: {}
43
-        //  },
44
-        //  passProps: {
45
-        //    str: 'This is a prop passed in \'startSingleScreenApp()\'!',
46
-        //    obj: {
47
-        //      str: 'This is a prop passed in an object!',
48
-        //      arr: [
49
-        //        {
50
-        //          str: 'This is a prop in an object in an array in an object!'
51
-        //        }
52
-        //      ],
53
-        //      arr2: [
54
-        //        [
55
-        //          'array of strings',
56
-        //          'with two strings'
57
-        //        ],
58
-        //        [
59
-        //          1, 2, 3
60
-        //        ]
61
-        //      ]
62
-        //    },
63
-        //    num: 1234,
64
-        //    fn: function() {
65
-        //      return 'Hello from a function!';
66
-        //    }
67
-        //  }
68
-        //});
69 38
         Navigation.startSingleScreenApp({
70
-          screen: {
71
-            screen: 'example.FirstTabScreen',
72
-            title: 'Login',
73
-            topTabs: [
74
-              {
75
-                screenId: 'example.ListScreen',
76
-                title: 'Tab1',
77
-                passProps: {
78
-                  str: 'This is a prop passed to Tab1'
79
-                }
80
-              },
81
-              {
82
-                screenId: 'example.PushedScreen',
83
-                title: 'Tab2',
84
-                passProps: {
85
-                  str: 'This is a prop passed to Tab2'
86
-                }
87
-
88
-              },
89
-              {
90
-                screenId: 'example.PushedScreen',
91
-                title: 'Tab3',
92
-                passProps: {
93
-                  str: 'This is a prop passed to Tab3'
94
-                }
95
-              },
96
-              {
97
-                screenId: 'example.FirstTabScreen',
98
-                title: 'Tab4',
99
-                passProps: {
100
-                  str: 'This is a prop passed to Tab4',
101
-                  fn: () => 'Hello from a function passed as passProps!'
102
-                }
103
-              }
104
-            ],
105
-            navigatorStyle: {}
106
-          }
39
+         screen: {
40
+           screen: 'example.LoginScreen',
41
+           title: 'Login',
42
+           navigatorStyle: {}
43
+         },
44
+         passProps: {
45
+           str: 'This is a prop passed in \'startSingleScreenApp()\'!',
46
+           obj: {
47
+             str: 'This is a prop passed in an object!',
48
+             arr: [
49
+               {
50
+                 str: 'This is a prop in an object in an array in an object!'
51
+               }
52
+             ],
53
+             arr2: [
54
+               [
55
+                 'array of strings',
56
+                 'with two strings'
57
+               ],
58
+               [
59
+                 1, 2, 3
60
+               ]
61
+             ]
62
+           },
63
+           num: 1234,
64
+           fn: function() {
65
+             return 'Hello from a function!';
66
+           }
67
+         }
107 68
         });
69
+        // Navigation.startSingleScreenApp({
70
+        //   screen: {
71
+        //     screen: 'example.FirstTabScreen',
72
+        //     title: 'Login',
73
+        //     topTabs: [
74
+        //       {
75
+        //         screenId: 'example.ListScreen',
76
+        //         title: 'Tab1',
77
+        //         passProps: {
78
+        //           str: 'This is a prop passed to Tab1'
79
+        //         }
80
+        //       },
81
+        //       {
82
+        //         screenId: 'example.PushedScreen',
83
+        //         title: 'Tab2',
84
+        //         passProps: {
85
+        //           str: 'This is a prop passed to Tab2'
86
+        //         }
87
+        //
88
+        //       },
89
+        //       {
90
+        //         screenId: 'example.PushedScreen',
91
+        //         title: 'Tab3',
92
+        //         passProps: {
93
+        //           str: 'This is a prop passed to Tab3'
94
+        //         }
95
+        //       },
96
+        //       {
97
+        //         screenId: 'example.FirstTabScreen',
98
+        //         title: 'Tab4',
99
+        //         passProps: {
100
+        //           str: 'This is a prop passed to Tab4',
101
+        //           fn: () => 'Hello from a function passed as passProps!'
102
+        //         }
103
+        //       }
104
+        //     ],
105
+        //     navigatorStyle: {}
106
+        //   },
107
+        //   drawer: { // optional, add this if you want a side menu drawer in your app
108
+        //     left: { // optional, define if you want a drawer from the left
109
+        //       screen: 'example.SideMenu' // unique ID registered with Navigation.registerScreen
110
+        //     },
111
+        //     disableOpenGesture: false // optional, can the drawer be opened with a swipe instead of button
112
+        //   }
113
+        // });
108 114
         return;
109 115
       case 'after-login':
110 116
         Navigation.startTabBasedApp({
@@ -115,7 +121,7 @@ export default class App {
115 121
               icon: require('../img/one.png'),
116 122
               selectedIcon: require('../img/one_selected.png'),
117 123
               title: 'Screen One',
118
-              navigatorStyle: {},
124
+              navigatorStyle: {}
119 125
             },
120 126
             {
121 127
               label: 'Two',
@@ -123,7 +129,7 @@ export default class App {
123 129
               icon: require('../img/two.png'),
124 130
               selectedIcon: require('../img/two_selected.png'),
125 131
               title: 'Screen Two',
126
-              navigatorStyle: {},
132
+              navigatorStyle: {}
127 133
             }
128 134
           ],
129 135
           passProps: {
@@ -139,7 +145,16 @@ export default class App {
139 145
             num: 1234
140 146
           },
141 147
           animationType: 'slide-down',
142
-          title: 'Redux Example'
148
+          title: 'Redux Example',
149
+          drawer: { // optional, add this if you want a side menu drawer in your app
150
+            left: { // optional, define if you want a drawer from the left
151
+              screen: 'example.BottomTabsSideMenu' // unique ID registered with Navigation.registerScreen
152
+            },
153
+            disableOpenGesture: false, // optional, can the drawer be opened with a swipe instead of button
154
+            passProps: {
155
+              title: 'Hello from SideMenu'
156
+            }
157
+          }
143 158
         });
144 159
         return;
145 160
       default:

+ 101
- 0
example-redux/src/screens/BottomTabsSideMenu.js View File

@@ -0,0 +1,101 @@
1
+import React, {Component, PropTypes} from 'react';
2
+import {
3
+  Text,
4
+  View,
5
+  ScrollView,
6
+  TouchableOpacity,
7
+  StyleSheet,
8
+  Alert
9
+} from 'react-native';
10
+import {connect} from 'react-redux';
11
+import * as counterActions from '../reducers/counter/actions';
12
+import _ from 'lodash';
13
+
14
+class SideMenu extends Component {
15
+
16
+  constructor(props) {
17
+    super(props);
18
+    // if you want to listen on navigator events, set this up
19
+    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
20
+  }
21
+
22
+  onNavigatorEvent(event) {
23
+      console.log('SideMenu', 'Unhandled event ' + event.id);
24
+  }
25
+
26
+  render() {
27
+    return (
28
+      <View style={styles.sideMenu}>
29
+        <Text style={styles.title}>{this.props.title}</Text>
30
+
31
+        <TouchableOpacity onPress={ this.onShowModalPress.bind(this) }>
32
+          <Text style={styles.button}>Show modal</Text>
33
+        </TouchableOpacity>
34
+
35
+        <TouchableOpacity onPress={ this.onPushScreenToFirstTab.bind(this) }>
36
+          <Text style={styles.button}>Push screen to first tab</Text>
37
+        </TouchableOpacity>
38
+
39
+        <TouchableOpacity onPress={ this.onPushScreenToSecondTab.bind(this) }>
40
+          <Text style={styles.button}>Push screen to second tab</Text>
41
+        </TouchableOpacity>
42
+      </View>
43
+    );
44
+  }
45
+
46
+  onShowModalPress() {
47
+    this.props.navigator.showModal({
48
+      title: "Modal Screen from SideMenu",
49
+      screen: "example.PushedScreen",
50
+      passProps: {
51
+        str: 'This is a prop passed in \'navigator.showModal()\'!',
52
+        obj: {
53
+          str: 'This is a prop passed in an object!',
54
+          arr: [
55
+            {
56
+              str: 'This is a prop in an object in an array in an object!'
57
+            }
58
+          ]
59
+        },
60
+        num: 1234
61
+      }
62
+    });
63
+  }
64
+
65
+  onPushScreenToFirstTab() {
66
+    this.props.navigator.handleDeepLink({
67
+      link: 'tab1/pushScreen/example.PushedScreen'
68
+    });
69
+  }
70
+
71
+  onPushScreenToSecondTab() {
72
+    console.log('SideMenu', 'onPushScreenToSecondTab ' + 'tab2/pushScreen/example.PushedScreen');
73
+    this.props.navigator.handleDeepLink({
74
+      link: 'tab2/pushScreen/example.PushedScreen'
75
+    });
76
+  }
77
+}
78
+
79
+const styles = StyleSheet.create({
80
+  sideMenu: {
81
+    flex: 1,
82
+    width: 260,
83
+    backgroundColor: '#efefef',
84
+    padding: 20
85
+  },
86
+  title: {
87
+    textAlign: 'center',
88
+    marginBottom: 15
89
+  },
90
+  button: {
91
+    textAlign: 'center',
92
+    fontSize: 18,
93
+    borderBottomWidth: 1,
94
+    borderColor: 'grey',
95
+    marginBottom: 10,
96
+    marginTop:10,
97
+    color: 'black'
98
+  }
99
+});
100
+
101
+export default connect()(SideMenu);

+ 48
- 15
example-redux/src/screens/FirstTabScreen.js View File

@@ -46,23 +46,56 @@ class FirstTabScreen extends Component {
46 46
   }
47 47
 
48 48
   onNavigatorEvent(event) {
49
-    switch (event.id) {
50
-      case 'edit':
51
-        Alert.alert('NavBar', 'Edit button pressed');
52
-        break;
53
-
54
-      case 'add':
55
-        Alert.alert('NavBar', 'Add button pressed');
56
-        break;
57
-
58
-      case 'selectedTabChanged':
59
-        this.onTabSelected(event.position);
60
-        break;
49
+    if (event.type == 'DeepLink') {
50
+      this.handleDeepLink(event);
51
+    } else {
52
+      switch (event.id) {
53
+        case 'edit':
54
+          Alert.alert('NavBar', 'Edit button pressed');
55
+          break;
56
+
57
+        case 'add':
58
+          Alert.alert('NavBar', 'Add button pressed');
59
+          break;
60
+
61
+        case 'selectedTabChanged':
62
+          this.onTabSelected(event.position);
63
+          break;
64
+
65
+        default:
66
+          console.log('Unhandled event ' + event.id);
67
+          break;
68
+      }
69
+    }
70
+  }
61 71
 
62
-      default:
63
-        console.log('Unhandled event ' + event.id);
64
-        break;
72
+  handleDeepLink(event) {
73
+    const parts = event.link.split('/');
74
+    if (parts[0] == 'tab1' && parts[1] == 'pushScreen') {
75
+      this.props.navigator.toggleDrawer({
76
+        side: 'left',
77
+        animated: true,
78
+        to: 'closed'
79
+      });
80
+
81
+      this.props.navigator.push({
82
+        title: "Pushed from SideMenu",
83
+        screen: parts[2],
84
+        passProps: {
85
+          str: 'This is a prop passed in \'navigator.push()\'!',
86
+          obj: {
87
+            str: 'This is a prop passed in an object!',
88
+            arr: [
89
+              {
90
+                str: 'This is a prop in an object in an array in an object!'
91
+              }
92
+            ]
93
+          },
94
+          num: 1234
95
+        }
96
+      });
65 97
     }
98
+    return;
66 99
   }
67 100
 
68 101
   onTabSelected(position) {

+ 31
- 3
example-redux/src/screens/ListScreen.js View File

@@ -30,15 +30,43 @@ class ListScreen extends Component {
30 30
 
31 31
   constructor(props) {
32 32
     super(props);
33
-
33
+    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
34
+    
34 35
     var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
35 36
     this.state = {
36 37
       dataSource: ds.cloneWithRows(this._genRows({}))
37 38
     }
38 39
   }
39 40
 
40
-  componentWillMount() {
41
-    this._pressData = {};
41
+  onNavigatorEvent(event) {
42
+    if (event.type == 'DeepLink') {
43
+      const parts = event.link.split('/');
44
+      if (parts[0] == 'tab1' && parts[1] == 'pushScreen') {
45
+        this.props.navigator.toggleDrawer({
46
+          side: 'left',
47
+          animated: true,
48
+          to: 'closed'
49
+        });
50
+
51
+        this.props.navigator.push({
52
+          title: "Pushed from SideMenu",
53
+          screen: parts[2],
54
+          passProps: {
55
+            str: 'This is a prop passed in \'navigator.push()\'!',
56
+            obj: {
57
+              str: 'This is a prop passed in an object!',
58
+              arr: [
59
+                {
60
+                  str: 'This is a prop in an object in an array in an object!'
61
+                }
62
+              ]
63
+            },
64
+            num: 1234
65
+          }
66
+        });
67
+      }
68
+    }
69
+      console.log('ListScreen', 'Unhandled event ' + event.id);
42 70
   }
43 71
 
44 72
   render() {

+ 44
- 7
example-redux/src/screens/SecondTabScreen.js View File

@@ -22,6 +22,7 @@ class SecondTabScreen extends Component {
22 22
   constructor(props) {
23 23
     super(props);
24 24
     this.buttonsCounter = 0;
25
+    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
25 26
   }
26 27
 
27 28
   render() {
@@ -80,15 +81,51 @@ class SecondTabScreen extends Component {
80 81
   }
81 82
 
82 83
   onNavigatorEvent(event) {
83
-    switch (event.id) {
84
-      case 'left':
85
-        Alert.alert('NavBar', 'Left button pressed');
86
-        break;
87
-      case 'right':
88
-        Alert.alert('NavBar', 'Right button pressed');
89
-        break;
84
+    if (event.type == 'DeepLink') {
85
+      this.handleDeepLink(event);
86
+    } else {
87
+      switch (event.id) {
88
+        case 'left':
89
+          Alert.alert('NavBar', 'Left button pressed');
90
+          break;
91
+        case 'right':
92
+          Alert.alert('NavBar', 'Right button pressed');
93
+          break;
94
+      }
90 95
     }
96
+    console.log('ListScreen', 'Unhandled event ' + event.id);
91 97
   }
98
+
99
+  handleDeepLink(event) {
100
+    const parts = event.link.split('/');
101
+    if (parts[0] == 'tab2' && parts[1] == 'pushScreen') {
102
+      this.props.navigator.toggleDrawer({
103
+        side: 'left',
104
+        animated: true,
105
+        to: 'closed'
106
+      });
107
+
108
+      this.props.navigator.push({
109
+        title: "Pushed from SideMenu",
110
+        screen: parts[2],
111
+        passProps: {
112
+          str: 'This is a prop passed in \'navigator.push()\'!',
113
+          obj: {
114
+            str: 'This is a prop passed in an object!',
115
+            arr: [
116
+              {
117
+                str: 'This is a prop in an object in an array in an object!'
118
+              }
119
+            ]
120
+          },
121
+          num: 1234
122
+        }
123
+      });
124
+    }
125
+    return;
126
+
127
+  }
128
+
92 129
 }
93 130
 
94 131
 const styles = StyleSheet.create({

+ 89
- 0
example-redux/src/screens/SideMenu.js View File

@@ -0,0 +1,89 @@
1
+import React, {Component, PropTypes} from 'react';
2
+import {
3
+  Text,
4
+  View,
5
+  ScrollView,
6
+  TouchableOpacity,
7
+  StyleSheet,
8
+  Alert
9
+} from 'react-native';
10
+import {connect} from 'react-redux';
11
+import * as counterActions from '../reducers/counter/actions';
12
+import _ from 'lodash';
13
+
14
+class SideMenu extends Component {
15
+
16
+  constructor(props) {
17
+    super(props);
18
+    // if you want to listen on navigator events, set this up
19
+    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
20
+  }
21
+
22
+  onNavigatorEvent(event) {
23
+      console.log('SideMenu', 'Unhandled event ' + event.id);
24
+  }
25
+
26
+  render() {
27
+    return (
28
+      <View style={styles.sideMenu}>
29
+        <Text style={styles.title}>Hello from SideMenu</Text>
30
+
31
+        <TouchableOpacity onPress={ this.onShowModalPress.bind(this) }>
32
+          <Text style={styles.button}>Show modal</Text>
33
+        </TouchableOpacity>
34
+
35
+        <TouchableOpacity onPress={ this.onPushScreen.bind(this) }>
36
+          <Text style={styles.button}>Push screen</Text>
37
+        </TouchableOpacity>
38
+      </View>
39
+    );
40
+  }
41
+
42
+  onShowModalPress() {
43
+    this.props.navigator.showModal({
44
+      title: "Modal Screen from SideMenu",
45
+      screen: "example.PushedScreen",
46
+      passProps: {
47
+        str: 'This is a prop passed in \'navigator.showModal()\'!',
48
+        obj: {
49
+          str: 'This is a prop passed in an object!',
50
+          arr: [
51
+            {
52
+              str: 'This is a prop in an object in an array in an object!'
53
+            }
54
+          ]
55
+        },
56
+        num: 1234
57
+      }
58
+    });
59
+  }
60
+
61
+  onPushScreen() {
62
+    this.props.navigator.handleDeepLink({
63
+      link: 'tab1/pushScreen/example.PushedScreen'
64
+    });
65
+  }
66
+}
67
+
68
+const styles = StyleSheet.create({
69
+  sideMenu: {
70
+    flex: 1,
71
+    backgroundColor: '#efefef',
72
+    padding: 20
73
+  },
74
+  title: {
75
+    textAlign: 'center',
76
+    marginBottom: 15
77
+  },
78
+  button: {
79
+    textAlign: 'center',
80
+    fontSize: 18,
81
+    borderBottomWidth: 1,
82
+    borderColor: 'grey',
83
+    marginBottom: 10,
84
+    marginTop:10,
85
+    color: 'black'
86
+  }
87
+});
88
+
89
+export default connect()(SideMenu);

+ 4
- 0
example-redux/src/screens/index.js View File

@@ -5,6 +5,8 @@ import FirstTabScreen from './FirstTabScreen';
5 5
 import SecondTabScreen from './SecondTabScreen';
6 6
 import PushedScreen from './PushedScreen';
7 7
 import ListScreen from './ListScreen';
8
+import SideMenu from './SideMenu';
9
+import BottomTabsSideMenu from './BottomTabsSideMenu';
8 10
 
9 11
 // register all screens of the app (including internal ones)
10 12
 export function registerScreens(store, Provider) {
@@ -13,4 +15,6 @@ export function registerScreens(store, Provider) {
13 15
   Navigation.registerComponent('example.SecondTabScreen', () => SecondTabScreen, store, Provider);
14 16
   Navigation.registerComponent('example.PushedScreen', () => PushedScreen, store, Provider);
15 17
   Navigation.registerComponent('example.ListScreen', () => ListScreen, store, Provider);
18
+  Navigation.registerComponent('example.SideMenu', () => SideMenu, store, Provider);
19
+  Navigation.registerComponent('example.BottomTabsSideMenu', () => BottomTabsSideMenu, store, Provider);
16 20
 }

+ 37
- 30
src/deprecated/platformSpecificDeprecated.android.js View File

@@ -15,12 +15,10 @@ function startSingleScreenApp(params) {
15 15
     return;
16 16
   }
17 17
   addNavigatorParams(screen);
18
-  addNavigatorButtons(screen);
18
+  addNavigatorButtons(screen, params.drawer);
19 19
   addNavigationStyleParams(screen);
20 20
   screen.passProps = params.passProps;
21 21
 
22
-  //const drawer = setupDrawer(params.drawer);
23
-
24 22
   /*
25 23
    * adapt to new API
26 24
    */
@@ -29,6 +27,7 @@ function startSingleScreenApp(params) {
29 27
   params.screen = adaptNavigationStyleToScreenStyle(screen);
30 28
   params.screen = adaptNavigationParams(screen);
31 29
   params.appStyle = convertStyleParams(params.appStyle);
30
+  params.sideMenu = convertDrawerParamsToSideMenuParams(params.drawer);
32 31
 
33 32
   newPlatformSpecific.startApp(params);
34 33
 }
@@ -134,6 +133,21 @@ function convertStyleParams(originalStyleObject) {
134 133
   }
135 134
 }
136 135
 
136
+function convertDrawerParamsToSideMenuParams(drawerParams) {
137
+  const drawer = Object.assign({}, drawerParams);
138
+  if (!drawer.left || !drawer.left.screen) {
139
+    return null;
140
+  }
141
+
142
+  let result = {};
143
+  result.disableOpenGesture = drawer.disableOpenGesture !== undefined;
144
+  result.screenId = drawer.left.screen;
145
+  addNavigatorParams(result);
146
+  result = adaptNavigationParams(result);
147
+  result.passProps = drawer.passProps;
148
+  return result;
149
+}
150
+
137 151
 function adaptNavigationParams(screen) {
138 152
   screen.navigationParams = {
139 153
     screenInstanceID: screen.screenInstanceID,
@@ -153,7 +167,7 @@ function startTabBasedApp(params) {
153 167
 
154 168
   params.tabs.forEach(function(tab, idx) {
155 169
     addNavigatorParams(tab, null, idx);
156
-    addNavigatorButtons(tab);
170
+    addNavigatorButtons(tab, params.drawer);
157 171
     addNavigationStyleParams(tab);
158 172
     addTabIcon(tab);
159 173
     tab.passProps = params.passProps;
@@ -169,7 +183,7 @@ function startTabBasedApp(params) {
169 183
   params.tabs = newTabs;
170 184
 
171 185
   params.appStyle = convertStyleParams(params.appStyle);
172
-  // TODO: add drawer params
186
+  params.sideMenu = convertDrawerParamsToSideMenuParams(params.drawer);
173 187
 
174 188
   newPlatformSpecific.startApp(params);
175 189
 }
@@ -229,11 +243,13 @@ function navigatorSwitchToTab(navigator, params) {
229 243
 }
230 244
 
231 245
 function navigatorToggleDrawer(navigator, params) {
232
-  //RctActivity.toggleDrawer({
233
-  //  side: params.side,
234
-  //  animated: !(params.animated === false),
235
-  //  to: params.to || ''
236
-  //});
246
+  const animated = !(params.animated === false);
247
+  if (params.to) {
248
+    const visible = params.to === 'open';
249
+    newPlatformSpecific.setSideMenuVisible(animated, visible);
250
+  } else {
251
+    newPlatformSpecific.toggleSideMenuVisible(animated);
252
+  }
237 253
 }
238 254
 
239 255
 function navigatorToggleNavBar(navigator, params) {
@@ -284,7 +300,7 @@ function addNavigatorParams(screen, navigator = null, idx = '') {
284 300
   screen.navigatorEventID = screen.screenInstanceID + '_events';
285 301
 }
286 302
 
287
-function addNavigatorButtons(screen) {
303
+function addNavigatorButtons(screen, sideMenuParams) {
288 304
   const Screen = Navigation.getRegisteredScreen(screen.screen);
289 305
   Object.assign(screen, Screen.navigatorButtons);
290 306
 
@@ -302,7 +318,10 @@ function addNavigatorButtons(screen) {
302 318
     });
303 319
   }
304 320
 
305
-  const leftButton = getLeftButton(screen);
321
+  let leftButton = getLeftButton(screen);
322
+  if (sideMenuParams && !leftButton) {
323
+    leftButton = createSideMenuButton();
324
+  }
306 325
   if (leftButton) {
307 326
     if (leftButton.icon) {
308 327
       const icon = resolveAssetSource(leftButton.icon);
@@ -320,6 +339,12 @@ function addNavigatorButtons(screen) {
320 339
   }
321 340
 }
322 341
 
342
+function createSideMenuButton() {
343
+  return {
344
+    id: "sideMenu"
345
+  };
346
+}
347
+
323 348
 function addTitleBarBackButtonIfNeeded(screen) {
324 349
   const leftButton = getLeftButton(screen);
325 350
   if (!leftButton) {
@@ -350,24 +375,6 @@ function addNavigationStyleParams(screen) {
350 375
   screen.navigatorStyle = Object.assign({}, screen.navigatorStyle, Screen.navigatorStyle);
351 376
 }
352 377
 
353
-function setupDrawer(drawerParams) {
354
-  const drawer = Object.assign({}, drawerParams);
355
-  [drawer.left, drawer.right].forEach(side => {
356
-    if (!side) {
357
-      return;
358
-    }
359
-    const icon = resolveAssetSource(side.icon);
360
-    if (icon) {
361
-      side.icon = icon.uri;
362
-    }
363
-  });
364
-  if (drawer.disableOpenGesture === undefined) {
365
-    drawer.disableOpenGesture = false;
366
-  }
367
-
368
-  return drawer;
369
-}
370
-
371 378
 export default {
372 379
   startTabBasedApp,
373 380
   startSingleScreenApp,

+ 15
- 1
src/platformSpecific.android.js View File

@@ -78,6 +78,18 @@ function savePassProps(params) {
78 78
       savePassProps(tab);
79 79
     });
80 80
   }
81
+
82
+  if (params.sideMenu) {
83
+    PropRegistry.save(params.sideMenu.navigationParams.screenInstanceID, params.sideMenu.passProps);
84
+  }
85
+}
86
+
87
+function toggleSideMenuVisible(animated) {
88
+  NativeReactModule.toggleSideMenuVisible(animated);
89
+}
90
+
91
+function setSideMenuVisible(animated, visible) {
92
+  NativeReactModule.setSideMenuVisible(animated, visible);
81 93
 }
82 94
 
83 95
 module.exports = {
@@ -92,5 +104,7 @@ module.exports = {
92 104
   setScreenTitleBarButtons,
93 105
   showModal,
94 106
   dismissTopModal,
95
-  dismissAllModals
107
+  dismissAllModals,
108
+  toggleSideMenuVisible,
109
+  setSideMenuVisible
96 110
 };