Browse Source

Drawer implementation

Jason Skuby 8 years ago
parent
commit
b96c05fd8d

+ 53
- 4
android/app/src/main/java/com/reactnativenavigation/activities/BaseReactActivity.java View File

@@ -1,11 +1,13 @@
1 1
 package com.reactnativenavigation.activities;
2 2
 
3 3
 import android.content.Intent;
4
+import android.content.res.Configuration;
4 5
 import android.os.Build;
5 6
 import android.os.Bundle;
6 7
 import android.os.Handler;
7 8
 import android.provider.Settings;
8 9
 import android.support.annotation.CallSuper;
10
+import android.support.v7.app.ActionBarDrawerToggle;
9 11
 import android.support.v7.app.AppCompatActivity;
10 12
 import android.util.Log;
11 13
 import android.view.KeyEvent;
@@ -48,8 +50,10 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
48 50
     protected static final String KEY_ANIMATED = "animated";
49 51
     protected static final String KEY_BADGE = "badge";
50 52
     protected static final String KEY_HIDDEN = "hidden";
53
+    protected static final String KEY_SIDE = "side";
51 54
     protected static final String KEY_TAB_INDEX = "tabIndex";
52 55
     protected static final String KEY_TITLE = "title";
56
+    protected static final String KEY_TO = "to";
53 57
     private static final String TAG = "BaseReactActivity";
54 58
     private static final String REDBOX_PERMISSION_MESSAGE =
55 59
             "Overlay permissions needs to be granted in order for react native apps to run in dev mode";
@@ -59,6 +63,7 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
59 63
     private boolean mDoRefresh = false;
60 64
     private Menu mMenu;
61 65
     protected RnnToolBar mToolbar;
66
+    protected ActionBarDrawerToggle mDrawerToggle;
62 67
 
63 68
     /**
64 69
      * Returns the name of the bundle in assets. If this is null, and no file path is specified for
@@ -223,7 +228,7 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
223 228
 
224 229
             if (getCurrentNavigatorId().equals(screen.navigatorId) &&
225 230
                 getScreenStackSize() >= 1) {
226
-                mToolbar.showBackButton(screen);
231
+                mToolbar.setNavUpButton(screen);
227 232
             }
228 233
         }
229 234
     }
@@ -233,15 +238,16 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
233 238
         if (mToolbar != null &&
234 239
             getCurrentNavigatorId().equals(navigatorId) &&
235 240
             getScreenStackSize() <= 2) {
236
-            mToolbar.hideBackButton();
241
+            mToolbar.setNavUpButton();
237 242
         }
243
+
238 244
         return null;
239 245
     }
240 246
 
241 247
     @CallSuper
242 248
     public Screen popToRoot(String navigatorId) {
243 249
         if (mToolbar != null) {
244
-            mToolbar.hideBackButton();
250
+            mToolbar.setNavUpButton();
245 251
         }
246 252
 
247 253
         return null;
@@ -251,7 +257,7 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
251 257
     public Screen resetTo(Screen screen) {
252 258
         StyleHelper.updateStyles(mToolbar, screen);
253 259
         if (mToolbar != null) {
254
-            mToolbar.hideBackButton();
260
+            mToolbar.setNavUpButton();
255 261
         }
256 262
 
257 263
         return null;
@@ -273,6 +279,14 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
273 279
 
274 280
     public abstract int getScreenStackSize();
275 281
 
282
+    @Override
283
+    public void onConfigurationChanged(Configuration newConfig) {
284
+        super.onConfigurationChanged(newConfig);
285
+        if (mDrawerToggle != null) {
286
+            mDrawerToggle.onConfigurationChanged(newConfig);
287
+        }
288
+    }
289
+
276 290
     @Override
277 291
     public boolean onCreateOptionsMenu(Menu menu) {
278 292
         mMenu = menu;
@@ -285,6 +299,12 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
285 299
 
286 300
     @Override
287 301
     public boolean onOptionsItemSelected(MenuItem item) {
302
+        if (mDrawerToggle != null &&
303
+            getScreenStackSize() == 1 &&
304
+            mDrawerToggle.onOptionsItemSelected(item)) {
305
+            return true;
306
+        }
307
+
288 308
         if (item.getItemId() == android.R.id.home) {
289 309
             onBackPressed();
290 310
         } else {
@@ -297,6 +317,14 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
297 317
         return super.onOptionsItemSelected(item);
298 318
     }
299 319
 
320
+    @Override
321
+    public void onPostCreate(Bundle savedInstanceState) {
322
+        super.onPostCreate(savedInstanceState);
323
+        if (mDrawerToggle != null) {
324
+            mDrawerToggle.syncState();
325
+        }
326
+    }
327
+
300 328
     public Menu getMenu() {
301 329
         return mMenu;
302 330
     }
@@ -384,4 +412,25 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
384 412
             mToolbar.showToolbar(animated);
385 413
         }
386 414
     }
415
+
416
+    public void toggleDrawer(ReadableMap params) {
417
+        if (mToolbar == null || mDrawerToggle == null) {
418
+            return;
419
+        }
420
+
421
+        boolean animated = params.getBoolean(KEY_ANIMATED);
422
+        String side = params.getString(KEY_SIDE);
423
+        String to = params.getString(KEY_TO);
424
+        switch (to) {
425
+            case "open":
426
+                mToolbar.showDrawer(animated);
427
+                break;
428
+            case "closed":
429
+                mToolbar.hideDrawer(animated);
430
+                break;
431
+            default:
432
+                mToolbar.toggleDrawer(animated);
433
+                break;
434
+        }
435
+    }
387 436
 }

+ 23
- 2
android/app/src/main/java/com/reactnativenavigation/activities/BottomTabActivity.java View File

@@ -4,6 +4,7 @@ import android.graphics.Color;
4 4
 import android.graphics.drawable.Drawable;
5 5
 import android.os.AsyncTask;
6 6
 import android.os.Bundle;
7
+import android.support.v4.widget.DrawerLayout;
7 8
 import android.view.Menu;
8 9
 import android.widget.FrameLayout;
9 10
 
@@ -12,6 +13,7 @@ import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
12 13
 import com.facebook.react.bridge.ReadableMap;
13 14
 import com.reactnativenavigation.R;
14 15
 import com.reactnativenavigation.core.RctManager;
16
+import com.reactnativenavigation.core.objects.Drawer;
15 17
 import com.reactnativenavigation.core.objects.Screen;
16 18
 import com.reactnativenavigation.utils.StyleHelper;
17 19
 import com.reactnativenavigation.views.RnnToolBar;
@@ -25,6 +27,7 @@ import java.util.Map;
25 27
  * Created by guyc on 02/04/16.
26 28
  */
27 29
 public class BottomTabActivity extends BaseReactActivity implements AHBottomNavigation.OnTabSelectedListener {
30
+    public static final String DRAWER_PARAMS = "drawerParams";
28 31
     public static final String EXTRA_SCREENS = "extraScreens";
29 32
 
30 33
     private static final String TAB_STYLE_BUTTON_COLOR = "tabBarButtonColor";
@@ -40,6 +43,8 @@ public class BottomTabActivity extends BaseReactActivity implements AHBottomNavi
40 43
     private AHBottomNavigation mBottomNavigation;
41 44
     private FrameLayout mContentFrame;
42 45
     private ArrayList<ScreenStack> mScreenStacks;
46
+    private ScreenStack mDrawerStack;
47
+    private DrawerLayout mDrawerLayout;
43 48
     private int mCurrentStackPosition = -1;
44 49
 
45 50
     @Override
@@ -52,7 +57,9 @@ public class BottomTabActivity extends BaseReactActivity implements AHBottomNavi
52 57
         mContentFrame = (FrameLayout) findViewById(R.id.contentFrame);
53 58
 
54 59
         final ArrayList<Screen> screens = (ArrayList<Screen>) getIntent().getSerializableExtra(EXTRA_SCREENS);
60
+        final Drawer drawer = (Drawer) getIntent().getSerializableExtra(DRAWER_PARAMS);
55 61
         mBottomNavigation.setForceTint(true);
62
+        setupDrawer(drawer, screens.get(0));
56 63
         setupTabs(getIntent().getExtras());
57 64
         setupPages(screens);
58 65
 
@@ -65,6 +72,20 @@ public class BottomTabActivity extends BaseReactActivity implements AHBottomNavi
65 72
         });
66 73
     }
67 74
 
75
+    protected void setupDrawer(Drawer drawer, Screen screen) {
76
+        if (drawer == null || drawer.left == null) {
77
+            return;
78
+        }
79
+
80
+        mDrawerStack = new ScreenStack(this);
81
+        FrameLayout drawerFrame = (FrameLayout) findViewById(R.id.drawerFrame);
82
+        drawerFrame.addView(mDrawerStack);
83
+        mDrawerStack.push(drawer.left);
84
+
85
+        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
86
+        mDrawerToggle = mToolbar.setupDrawer(mDrawerLayout, drawer.left, screen);
87
+    }
88
+
68 89
     private void setupPages(ArrayList<Screen> screens) {
69 90
         new SetupTabsTask(this, mToolbar, screens).execute();
70 91
     }
@@ -189,9 +210,9 @@ public class BottomTabActivity extends BaseReactActivity implements AHBottomNavi
189 210
 
190 211
         // Hide or show back button if needed
191 212
         if (getScreenStackSize() > 1) {
192
-            mToolbar.showBackButton(getCurrentScreen());
213
+            mToolbar.setNavUpButton(getCurrentScreen());
193 214
         } else {
194
-            mToolbar.hideBackButton();
215
+            mToolbar.setNavUpButton();
195 216
         }
196 217
     }
197 218
 

+ 23
- 0
android/app/src/main/java/com/reactnativenavigation/activities/SingleScreenActivity.java View File

@@ -1,9 +1,11 @@
1 1
 package com.reactnativenavigation.activities;
2 2
 
3
+import android.support.v4.widget.DrawerLayout;
3 4
 import android.widget.FrameLayout;
4 5
 
5 6
 import com.reactnativenavigation.R;
6 7
 import com.reactnativenavigation.core.RctManager;
8
+import com.reactnativenavigation.core.objects.Drawer;
7 9
 import com.reactnativenavigation.core.objects.Screen;
8 10
 import com.reactnativenavigation.utils.StyleHelper;
9 11
 import com.reactnativenavigation.views.RnnToolBar;
@@ -14,10 +16,13 @@ import com.reactnativenavigation.views.ScreenStack;
14 16
  */
15 17
 public class SingleScreenActivity extends BaseReactActivity {
16 18
 
19
+    public static final String DRAWER_PARAMS = "drawerParams";
17 20
     public static final String EXTRA_SCREEN = "extraScreen";
18 21
 
19 22
     private ScreenStack mScreenStack;
20 23
     private String mNavigatorId;
24
+    private ScreenStack mDrawerStack;
25
+    private DrawerLayout mDrawerLayout;
21 26
 
22 27
     @Override
23 28
     protected void handleOnCreate() {
@@ -27,7 +32,11 @@ public class SingleScreenActivity extends BaseReactActivity {
27 32
         mToolbar = (RnnToolBar) findViewById(R.id.toolbar);
28 33
 
29 34
         final Screen screen = (Screen) getIntent().getSerializableExtra(EXTRA_SCREEN);
35
+        final Drawer drawer = (Drawer) getIntent().getSerializableExtra(DRAWER_PARAMS);
36
+
30 37
         mNavigatorId = screen.navigatorId;
38
+        setupToolbar(screen);
39
+        setupDrawer(drawer, screen);
31 40
 
32 41
         mScreenStack = new ScreenStack(this);
33 42
         FrameLayout contentFrame = (FrameLayout) findViewById(R.id.contentFrame);
@@ -44,6 +53,20 @@ public class SingleScreenActivity extends BaseReactActivity {
44 53
         });
45 54
     }
46 55
 
56
+    protected void setupDrawer(Drawer drawer, Screen screen) {
57
+        if (drawer == null || drawer.left == null) {
58
+            return;
59
+        }
60
+
61
+        mDrawerStack = new ScreenStack(this);
62
+        FrameLayout drawerFrame = (FrameLayout) findViewById(R.id.drawerFrame);
63
+        drawerFrame.addView(mDrawerStack);
64
+        mDrawerStack.push(drawer.left);
65
+
66
+        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
67
+        mDrawerToggle = mToolbar.setupDrawer(mDrawerLayout, drawer.left, screen);
68
+    }
69
+
47 70
     protected void setupToolbar(Screen screen) {
48 71
         mToolbar.update(screen);
49 72
         StyleHelper.updateStyles(mToolbar, screen);

+ 23
- 0
android/app/src/main/java/com/reactnativenavigation/core/objects/Drawer.java View File

@@ -0,0 +1,23 @@
1
+package com.reactnativenavigation.core.objects;
2
+
3
+import com.facebook.react.bridge.ReadableMap;
4
+
5
+import java.io.Serializable;
6
+
7
+public class Drawer extends JsonObject implements Serializable {
8
+    private static final long serialVersionUID = 982836768712398756L;
9
+
10
+    private static final String KEY_LEFT = "left";
11
+    private static final String KEY_RIGHT = "right";
12
+    private static final String KEY_DISABLE_OPEN_GESTURE = "disableOpenGesture";
13
+
14
+    public final Screen left;
15
+    public final Screen right;
16
+    public final boolean disableOpenGesture;
17
+
18
+    public Drawer(ReadableMap params) {
19
+        left = params.hasKey(KEY_LEFT) ? new Screen(params.getMap(KEY_LEFT)) : null;
20
+        right = params.hasKey(KEY_RIGHT) ? new Screen(params.getMap(KEY_RIGHT)) : null;
21
+        disableOpenGesture = getBoolean(params, KEY_DISABLE_OPEN_GESTURE);
22
+    }
23
+}

+ 6
- 2
android/app/src/main/java/com/reactnativenavigation/core/objects/Screen.java View File

@@ -34,7 +34,7 @@ public class Screen extends JsonObject implements Serializable {
34 34
     private static final String KEY_RIGHT_BUTTONS = "rightButtons";
35 35
     private static final String KEY_TOOL_BAR_STYLE = "navigatorStyle";
36 36
     private static final String KEY_STATUS_BAR_COLOR = "statusBarColor";
37
-    private static final String KEY_TOOL_BAR_COLOR = "toolBarColor";
37
+    private static final String KEY_TOOL_BAR_COLOR = "navBarBackgroundColor";
38 38
     private static final String KEY_TOOL_BAR_HIDDEN = "navBarHidden";
39 39
     private static final String KEY_NAVIGATION_BAR_COLOR = "navigationBarColor";
40 40
     private static final String KEY_NAV_BAR_BUTTON_COLOR = "navBarButtonColor";
@@ -44,7 +44,7 @@ public class Screen extends JsonObject implements Serializable {
44 44
     private static final String KEY_TAB_INDICATOR_COLOR = "tabIndicatorColor";
45 45
     private static final String KEY_PROPS = "passProps";
46 46
 
47
-    public final String title;
47
+    public String title;
48 48
     public final String label;
49 49
     public final String screenId;
50 50
     public final String screenInstanceId;
@@ -85,6 +85,10 @@ public class Screen extends JsonObject implements Serializable {
85 85
         setToolbarStyle(screen);
86 86
     }
87 87
 
88
+    public void setTitle(ReadableMap params) {
89
+        this.title = getString(params, KEY_TITLE);
90
+    }
91
+
88 92
     public void setButtons(ReadableMap params) {
89 93
         this.buttons = getButtons(params);
90 94
     }

+ 23
- 2
android/app/src/main/java/com/reactnativenavigation/modules/RctActivityModule.java View File

@@ -15,6 +15,7 @@ import com.reactnativenavigation.activities.BottomTabActivity;
15 15
 import com.reactnativenavigation.activities.RootActivity;
16 16
 import com.reactnativenavigation.activities.SingleScreenActivity;
17 17
 import com.reactnativenavigation.controllers.ModalController;
18
+import com.reactnativenavigation.core.objects.Drawer;
18 19
 import com.reactnativenavigation.core.objects.Screen;
19 20
 import com.reactnativenavigation.modal.RnnModal;
20 21
 import com.reactnativenavigation.utils.BridgeUtils;
@@ -39,7 +40,7 @@ public class RctActivityModule extends ReactContextBaseJavaModule {
39 40
     }
40 41
 
41 42
     @ReactMethod
42
-    public void startTabBasedApp(ReadableArray screens, ReadableMap style) {
43
+    public void startTabBasedApp(ReadableArray screens, ReadableMap style, ReadableMap drawerParams) {
43 44
         Activity context = ContextProvider.getActivityContext();
44 45
         if (context != null && !context.isFinishing()) {
45 46
             Intent intent = new Intent(context, BottomTabActivity.class);
@@ -47,6 +48,9 @@ public class RctActivityModule extends ReactContextBaseJavaModule {
47 48
 
48 49
             Bundle extras = new Bundle();
49 50
             extras.putSerializable(BottomTabActivity.EXTRA_SCREENS, createScreens(screens));
51
+            if (drawerParams != null) {
52
+                extras.putSerializable(BottomTabActivity.DRAWER_PARAMS, new Drawer(drawerParams));
53
+            }
50 54
             if (style != null) {
51 55
                 BridgeUtils.addMapToBundle(((ReadableNativeMap) style).toHashMap(), extras);
52 56
             }
@@ -72,7 +76,7 @@ public class RctActivityModule extends ReactContextBaseJavaModule {
72 76
     }
73 77
 
74 78
     @ReactMethod
75
-    public void startSingleScreenApp(ReadableMap screen) {
79
+    public void startSingleScreenApp(ReadableMap screen, ReadableMap drawerParams) {
76 80
         BaseReactActivity context = ContextProvider.getActivityContext();
77 81
         if (context != null && !context.isFinishing()) {
78 82
             Intent intent = new Intent(context, SingleScreenActivity.class);
@@ -80,6 +84,9 @@ public class RctActivityModule extends ReactContextBaseJavaModule {
80 84
 
81 85
             Bundle extras = new Bundle();
82 86
             extras.putSerializable(SingleScreenActivity.EXTRA_SCREEN, new Screen(screen));
87
+            if (drawerParams != null) {
88
+                extras.putSerializable(SingleScreenActivity.DRAWER_PARAMS, new Drawer(drawerParams));
89
+            }
83 90
             intent.putExtras(extras);
84 91
 
85 92
             context.startActivity(intent);
@@ -148,6 +155,20 @@ public class RctActivityModule extends ReactContextBaseJavaModule {
148 155
         });
149 156
     }
150 157
 
158
+    @ReactMethod
159
+    public void toggleDrawer(final ReadableMap params) {
160
+        final BaseReactActivity context = ContextProvider.getActivityContext();
161
+        if (context == null || context.isFinishing()) {
162
+            return;
163
+        }
164
+        context.runOnUiThread(new Runnable() {
165
+            @Override
166
+            public void run() {
167
+                context.toggleDrawer(params);
168
+            }
169
+        });
170
+    }
171
+
151 172
     @ReactMethod
152 173
     public void toggleNavigationBar(final ReadableMap params) {
153 174
         final BaseReactActivity context = ContextProvider.getActivityContext();

+ 139
- 19
android/app/src/main/java/com/reactnativenavigation/views/RnnToolBar.java View File

@@ -12,10 +12,14 @@ import android.support.annotation.NonNull;
12 12
 import android.support.annotation.UiThread;
13 13
 import android.support.v4.content.ContextCompat;
14 14
 import android.support.v4.content.res.ResourcesCompat;
15
+import android.support.v4.widget.DrawerLayout;
15 16
 import android.support.v7.app.ActionBar;
17
+import android.support.v7.app.ActionBarDrawerToggle;
16 18
 import android.support.v7.app.AppCompatActivity;
19
+import android.support.v7.graphics.drawable.DrawerArrowDrawable;
17 20
 import android.support.v7.widget.Toolbar;
18 21
 import android.util.AttributeSet;
22
+import android.view.Gravity;
19 23
 import android.view.Menu;
20 24
 import android.view.MenuItem;
21 25
 import android.view.View;
@@ -27,6 +31,7 @@ import com.reactnativenavigation.activities.BaseReactActivity;
27 31
 import com.reactnativenavigation.core.objects.Button;
28 32
 import com.reactnativenavigation.core.objects.Screen;
29 33
 import com.reactnativenavigation.utils.ContextProvider;
34
+import com.reactnativenavigation.utils.IconUtils;
30 35
 import com.reactnativenavigation.utils.ImageUtils;
31 36
 
32 37
 import java.lang.ref.WeakReference;
@@ -43,8 +48,13 @@ public class RnnToolBar extends Toolbar {
43 48
     private static final int ANIMATE_DURATION = 180;
44 49
 
45 50
     private List<Screen> mScreens;
51
+    private AsyncTask mDrawerIconTask;
46 52
     private AsyncTask mSetupToolbarTask;
47 53
     private Drawable mBackground;
54
+    private Drawable mDrawerIcon;
55
+    private Screen mDrawerScreen;
56
+    private DrawerLayout mDrawerLayout;
57
+    private ActionBarDrawerToggle mDrawerToggle;
48 58
     private ArrayList<View> mMenuItems;
49 59
 
50 60
     public RnnToolBar(Context context) {
@@ -105,6 +115,65 @@ public class RnnToolBar extends Toolbar {
105 115
         }
106 116
     }
107 117
 
118
+    public ActionBarDrawerToggle setupDrawer(DrawerLayout drawerLayout, Screen drawerScreen, Screen screen) {
119
+        if (drawerLayout == null || drawerScreen == null) {
120
+            return null;
121
+        }
122
+
123
+        mDrawerLayout = drawerLayout;
124
+        mDrawerScreen = drawerScreen;
125
+        mDrawerToggle = new ActionBarDrawerToggle(
126
+            ContextProvider.getActivityContext(),
127
+            mDrawerLayout,
128
+            this,
129
+            R.string.drawer_open,
130
+            R.string.drawer_close
131
+        );
132
+        mDrawerLayout.setDrawerListener(mDrawerToggle);
133
+        setupDrawerIconAsync(drawerScreen.icon, screen);
134
+
135
+        return mDrawerToggle;
136
+    }
137
+
138
+    public void setDrawerIcon(Drawable icon) {
139
+        mDrawerIcon = icon;
140
+    }
141
+
142
+    public void showDrawer(boolean animated) {
143
+        if (mDrawerLayout == null) {
144
+            return;
145
+        }
146
+
147
+        mDrawerLayout.openDrawer(Gravity.LEFT);
148
+    }
149
+
150
+    public void hideDrawer(boolean animated) {
151
+        if (mDrawerLayout == null) {
152
+            return;
153
+        }
154
+
155
+        mDrawerLayout.closeDrawer(Gravity.LEFT);
156
+    }
157
+
158
+    public void toggleDrawer(boolean animated) {
159
+        if (mDrawerLayout == null) {
160
+            return;
161
+        }
162
+
163
+        boolean visible = mDrawerLayout.isDrawerOpen(Gravity.LEFT);
164
+        if (visible) {
165
+            hideDrawer(animated);
166
+        } else {
167
+            showDrawer(animated);
168
+        }
169
+    }
170
+
171
+    public void setupDrawerIconAsync(String drawerIconSource, Screen screen) {
172
+        if (mDrawerIconTask == null) {
173
+            mDrawerIconTask = new SetupDrawerIconTask(this, drawerIconSource, screen).execute();
174
+        }
175
+    }
176
+
108 177
     public void setupToolbarButtonsAsync(Screen newScreen) {
109 178
         if (newScreen != null) {
110 179
             this.setupToolbarButtonsAsync(null, newScreen);
@@ -144,29 +213,44 @@ public class RnnToolBar extends Toolbar {
144 213
         hideToolbar(false);
145 214
     }
146 215
 
147
-    @SuppressWarnings({"ConstantConditions"})
148
-    public void showBackButton(Screen screen) {
149
-        ActionBar actionBar = ContextProvider.getActivityContext().getSupportActionBar();
150
-        Drawable backButton = setupBackButton(screen);
151
-        actionBar.setHomeAsUpIndicator(backButton);
152
-        actionBar.setDisplayHomeAsUpEnabled(true);
216
+    public void setNavUpButton() {
217
+        setNavUpButton(null);
153 218
     }
154 219
 
155
-    @SuppressLint("PrivateResource")
156 220
     @SuppressWarnings({"ConstantConditions"})
157
-    private Drawable setupBackButton(Screen screen) {
158
-        Resources resources = getResources();
159
-        final Drawable backButton = ResourcesCompat.getDrawable(resources,
160
-                R.drawable.abc_ic_ab_back_mtrl_am_alpha,
161
-                ContextProvider.getActivityContext().getTheme());
162
-        int tintColor = screen.navBarButtonColor != null ? screen.navBarButtonColor : Color.BLACK;
163
-        ImageUtils.tint(backButton, tintColor);
164
-        return backButton;
165
-    }
221
+    public void setNavUpButton(Screen screen) {
222
+        ActionBar actionBar = ContextProvider.getActivityContext().getSupportActionBar();
223
+        if (actionBar == null) {
224
+            return;
225
+        }
166 226
 
167
-    @SuppressWarnings({"ConstantConditions"})
168
-    public void hideBackButton() {
169
-        ContextProvider.getActivityContext().getSupportActionBar().setDisplayHomeAsUpEnabled(false);
227
+        boolean isBack = screen != null;
228
+        boolean hasDrawer = mDrawerToggle != null;
229
+
230
+        Drawable navIcon = null;
231
+        DrawerArrowDrawable navArrow = null;
232
+        if (hasDrawer && mDrawerIcon == null) {
233
+            navArrow = (DrawerArrowDrawable) this.getNavigationIcon();
234
+        } else {
235
+            if (isBack) {
236
+                navArrow = new DrawerArrowDrawable(ContextProvider.getActivityContext());
237
+            } else if (hasDrawer) {
238
+                navIcon = mDrawerIcon;
239
+            }
240
+        }
241
+
242
+        if (navArrow != null) {
243
+            navArrow.setProgress(isBack ? 1.0f : 0.0f);
244
+            if (screen.navBarButtonColor != null) {
245
+                navArrow.setColor(screen.navBarButtonColor);
246
+            } else {
247
+                navArrow.setColor(Color.BLACK);
248
+            }
249
+            navIcon = navArrow;
250
+        }
251
+
252
+        actionBar.setHomeAsUpIndicator(navIcon);
253
+        actionBar.setDisplayHomeAsUpEnabled(navIcon != null);
170 254
     }
171 255
 
172 256
     /**
@@ -186,6 +270,42 @@ public class RnnToolBar extends Toolbar {
186 270
         setupToolbarButtonsAsync(screen);
187 271
     }
188 272
 
273
+    private static class SetupDrawerIconTask extends AsyncTask<Void, Void, Drawable> {
274
+        private final WeakReference<RnnToolBar> mToolbarWR;
275
+        private final String mDrawerIconSource;
276
+        private final Integer mTintColor;
277
+
278
+        public SetupDrawerIconTask(RnnToolBar toolBar, String drawerIconSource, Screen screen) {
279
+            mToolbarWR = new WeakReference<>(toolBar);
280
+            mDrawerIconSource = drawerIconSource;
281
+            mTintColor = screen.navBarButtonColor;
282
+        }
283
+
284
+        @Override
285
+        protected Drawable doInBackground(Void... params) {
286
+            Context context = ContextProvider.getActivityContext();
287
+            if (context == null || mDrawerIconSource == null) {
288
+                return null;
289
+            }
290
+
291
+            return IconUtils.getIcon(context, mDrawerIconSource);
292
+        }
293
+
294
+        @Override
295
+        protected void onPostExecute(Drawable drawerIcon) {
296
+            RnnToolBar toolBar = mToolbarWR.get();
297
+            if (drawerIcon != null) {
298
+                if (mTintColor != null) {
299
+                    ImageUtils.tint(drawerIcon, mTintColor);
300
+                }
301
+                toolBar.setDrawerIcon(drawerIcon);
302
+            }
303
+
304
+            toolBar.setNavUpButton();
305
+            mToolbarWR.clear();
306
+        }
307
+    }
308
+
189 309
     private static class SetupToolbarButtonsTask extends AsyncTask<Void, Void, Map<String, Drawable>> {
190 310
         private final List<Button> mOldButtons;
191 311
         private final List<Button> mNewButtons;

+ 14
- 3
android/app/src/main/res/layout/bottom_tab_activity.xml View File

@@ -20,11 +20,22 @@
20 20
             app:layout_scrollFlags="scroll|enterAlways"/>
21 21
     </android.support.design.widget.AppBarLayout>
22 22
 
23
-    <FrameLayout
24
-        android:id="@+id/contentFrame"
23
+    <android.support.v4.widget.DrawerLayout
24
+        xmlns:android="http://schemas.android.com/apk/res/android"
25
+        android:id="@+id/drawerLayout"
25 26
         android:layout_width="match_parent"
26 27
         android:layout_height="0dp"
27
-        android:layout_weight="1"/>
28
+        android:layout_weight="1">
29
+        <FrameLayout
30
+            android:id="@+id/contentFrame"
31
+            android:layout_width="match_parent"
32
+            android:layout_height="0dp"
33
+            android:layout_weight="1"/>
34
+        <FrameLayout android:id="@+id/drawerFrame"
35
+            android:layout_width="240dp"
36
+            android:layout_height="match_parent"
37
+            android:layout_gravity="start"/>
38
+    </android.support.v4.widget.DrawerLayout>
28 39
 
29 40
     <com.aurelhubert.ahbottomnavigation.AHBottomNavigation
30 41
         android:id="@+id/bottom_tab_bar"

+ 13
- 3
android/app/src/main/res/layout/single_screen_activity.xml View File

@@ -17,8 +17,18 @@
17 17
             app:layout_scrollFlags="scroll|enterAlways"/>
18 18
     </android.support.design.widget.AppBarLayout>
19 19
 
20
-    <FrameLayout
21
-        android:id="@+id/contentFrame"
20
+    <android.support.v4.widget.DrawerLayout
21
+        xmlns:android="http://schemas.android.com/apk/res/android"
22
+        android:id="@+id/drawerLayout"
22 23
         android:layout_width="match_parent"
23
-        android:layout_height="match_parent"/>
24
+        android:layout_height="match_parent">
25
+        <FrameLayout
26
+            android:id="@+id/contentFrame"
27
+            android:layout_width="match_parent"
28
+            android:layout_height="match_parent"/>
29
+        <FrameLayout android:id="@+id/drawerFrame"
30
+            android:layout_width="240dp"
31
+            android:layout_height="match_parent"
32
+            android:layout_gravity="start"/>
33
+    </android.support.v4.widget.DrawerLayout>
24 34
 </LinearLayout>

+ 5
- 0
android/app/src/main/res/values/strings.xml View File

@@ -0,0 +1,5 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<resources>
3
+    <string name="drawer_close">Drawer Close</string>
4
+    <string name="drawer_open">Drawer Open</string>
5
+</resources>

+ 31
- 2
src/platformSpecific.android.js View File

@@ -19,7 +19,8 @@ function startSingleScreenApp(params) {
19 19
   addNavigatorButtons(screen);
20 20
   addNavigationStyleParams(screen);
21 21
   screen.passProps = params.passProps;
22
-  RctActivity.startSingleScreenApp(screen);
22
+  const drawer = setupDrawer(params.drawer);
23
+  RctActivity.startSingleScreenApp(screen, drawer);
23 24
 }
24 25
 
25 26
 function startTabBasedApp(params) {
@@ -41,7 +42,8 @@ function startTabBasedApp(params) {
41 42
     tab.passProps = params.passProps;
42 43
   });
43 44
 
44
-  RctActivity.startTabBasedApp(params.tabs, params.tabsStyle);
45
+  const drawer = setupDrawer(params.drawer);
46
+  RctActivity.startTabBasedApp(params.tabs, params.tabsStyle, drawer);
45 47
 }
46 48
 
47 49
 function navigatorPush(navigator, params) {
@@ -101,6 +103,14 @@ function navigatorSwitchToTab(navigator, params) {
101 103
   });
102 104
 }
103 105
 
106
+function navigatorToggleDrawer(navigator, params) {
107
+  RctActivity.toggleDrawer({
108
+    side: params.side,
109
+    animated: !(params.animated === false),
110
+    to: params.to || ''
111
+  });
112
+}
113
+
104 114
 function navigatorToggleNavBar(navigator, params) {
105 115
   RctActivity.toggleNavigationBar({
106 116
     hidden: params.to === 'hidden',
@@ -160,6 +170,24 @@ function addNavigationStyleParams(screen) {
160 170
   screen.navigatorStyle = Screen.navigatorStyle;
161 171
 }
162 172
 
173
+function setupDrawer(drawerParams) {
174
+  const drawer = Object.assign({}, drawerParams);
175
+  [drawer.left, drawer.right].forEach(side => {
176
+    if (!side) {
177
+      return;
178
+    }
179
+    const icon = resolveAssetSource(side.icon);
180
+    if (icon) {
181
+      side.icon = icon.uri;
182
+    }
183
+  });
184
+  if (drawer.disableOpenGesture === undefined) {
185
+    drawer.disableOpenGesture = false;
186
+  };
187
+
188
+  return drawer;
189
+}
190
+
163 191
 export default {
164 192
   startTabBasedApp,
165 193
   startSingleScreenApp,
@@ -174,6 +202,7 @@ export default {
174 202
   navigatorSetTabBadge,
175 203
   navigatorSetTitle,
176 204
   navigatorSwitchToTab,
205
+  navigatorToggleDrawer,
177 206
   navigatorToggleTabs,
178 207
   navigatorToggleNavBar
179 208
 }