Browse Source

Initial commit for Toolbar items

Guy Carmeli 8 years ago
parent
commit
532f008f44

+ 12
- 0
android/app/src/main/java/com/reactnativenavigation/activities/BaseReactActivity.java View File

@@ -9,6 +9,7 @@ import android.provider.Settings;
9 9
 import android.support.v7.app.AppCompatActivity;
10 10
 import android.util.Log;
11 11
 import android.view.KeyEvent;
12
+import android.view.Menu;
12 13
 import android.widget.EditText;
13 14
 import android.widget.Toast;
14 15
 
@@ -42,6 +43,7 @@ public class BaseReactActivity extends AppCompatActivity implements DefaultHardw
42 43
     protected  @Nullable ReactInstanceManager mReactInstanceManager;
43 44
     private LifecycleState mLifecycleState = LifecycleState.BEFORE_RESUME;
44 45
     private boolean mDoRefresh = false;
46
+    private Menu mMenu;
45 47
 
46 48
     /**
47 49
      * Returns the name of the bundle in assets. If this is null, and no file path is specified for
@@ -197,6 +199,16 @@ public class BaseReactActivity extends AppCompatActivity implements DefaultHardw
197 199
         }
198 200
     }
199 201
 
202
+    @Override
203
+    public boolean onCreateOptionsMenu(Menu menu) {
204
+        mMenu = menu;
205
+        return super.onCreateOptionsMenu(menu);
206
+    }
207
+
208
+    public Menu getMenu() {
209
+        return mMenu;
210
+    }
211
+
200 212
     @Override
201 213
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
202 214
         if (mReactInstanceManager != null) {

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

@@ -6,7 +6,7 @@ import android.widget.FrameLayout;
6 6
 
7 7
 import com.reactnativenavigation.R;
8 8
 import com.reactnativenavigation.core.RctManager;
9
-import com.reactnativenavigation.core.Screen;
9
+import com.reactnativenavigation.core.objects.Screen;
10 10
 import com.reactnativenavigation.views.RctView;
11 11
 
12 12
 /**

+ 19
- 7
android/app/src/main/java/com/reactnativenavigation/activities/TabActivity.java View File

@@ -2,12 +2,13 @@ package com.reactnativenavigation.activities;
2 2
 
3 3
 import android.support.design.widget.TabLayout;
4 4
 import android.support.v4.view.ViewPager;
5
-import android.support.v7.widget.Toolbar;
5
+import android.view.Menu;
6 6
 
7 7
 import com.reactnativenavigation.R;
8 8
 import com.reactnativenavigation.adapters.ViewPagerAdapter;
9 9
 import com.reactnativenavigation.core.RctManager;
10
-import com.reactnativenavigation.core.Screen;
10
+import com.reactnativenavigation.core.objects.Screen;
11
+import com.reactnativenavigation.views.RnnToolBar;
11 12
 
12 13
 import java.util.ArrayList;
13 14
 
@@ -15,35 +16,46 @@ import java.util.ArrayList;
15 16
  * Created by guyc on 02/04/16.
16 17
  */
17 18
 public class TabActivity extends BaseReactActivity {
18
-    public static final String EXTRA_SCREENS = "extraTabs";
19
+    public static final String EXTRA_SCREENS = "extraScreens";
19 20
 
20
-    private Toolbar mToolbar;
21
+    private RnnToolBar mToolbar;
21 22
     private TabLayout mTabLayout;
22 23
     private ViewPager mViewPager;
23 24
 
25
+    private ArrayList<Screen> mScreens;
26
+
24 27
     @Override
25 28
     protected void handleOnCreate() {
26 29
         mReactInstanceManager = RctManager.getInstance().getReactInstanceManager();
27 30
 
28 31
         setContentView(R.layout.tab_activity);
29
-        mToolbar = (Toolbar) findViewById(R.id.toolbar);
32
+        mToolbar = (RnnToolBar) findViewById(R.id.toolbar);
30 33
         mTabLayout = (TabLayout) findViewById(R.id.tabLayout);
31 34
         mViewPager = (ViewPager) findViewById(R.id.viewPager);
32 35
 
36
+        mScreens = (ArrayList<Screen>) getIntent().getSerializableExtra(EXTRA_SCREENS);
37
+
33 38
         setupToolbar();
34 39
         setupViewPager();
35 40
     }
36 41
 
37 42
     private void setupToolbar() {
38 43
         setSupportActionBar(mToolbar);
44
+        mToolbar.setScreens(mScreens);
39 45
     }
40 46
 
41 47
     private void setupViewPager() {
42
-        ArrayList<Screen> screens = (ArrayList<Screen>) getIntent().getSerializableExtra(EXTRA_SCREENS);
43
-        ViewPagerAdapter adapter = new ViewPagerAdapter(this, mViewPager, screens);
48
+        ViewPagerAdapter adapter = new ViewPagerAdapter(this, mViewPager, mToolbar, mScreens);
44 49
         mViewPager.setAdapter(adapter);
45 50
         mTabLayout.setupWithViewPager(mViewPager);
46 51
         mTabLayout.setOnTabSelectedListener(adapter);
47 52
         adapter.notifyDataSetChanged();
48 53
     }
54
+
55
+    @Override
56
+    public boolean onCreateOptionsMenu(Menu menu) {
57
+        boolean ret = super.onCreateOptionsMenu(menu);
58
+        mToolbar.handleOnCreateOptionsMenuAsync();
59
+        return ret;
60
+    }
49 61
 }

+ 7
- 2
android/app/src/main/java/com/reactnativenavigation/adapters/ViewPagerAdapter.java View File

@@ -3,6 +3,7 @@ package com.reactnativenavigation.adapters;
3 3
 import android.support.design.widget.TabLayout;
4 4
 import android.support.v4.view.PagerAdapter;
5 5
 import android.support.v4.view.ViewPager;
6
+import android.support.v7.widget.Toolbar;
6 7
 import android.view.View;
7 8
 import android.view.ViewGroup;
8 9
 
@@ -11,7 +12,7 @@ import com.facebook.react.bridge.Arguments;
11 12
 import com.facebook.react.bridge.WritableMap;
12 13
 import com.reactnativenavigation.activities.BaseReactActivity;
13 14
 import com.reactnativenavigation.core.RctManager;
14
-import com.reactnativenavigation.core.Screen;
15
+import com.reactnativenavigation.core.objects.Screen;
15 16
 import com.reactnativenavigation.views.RctView;
16 17
 
17 18
 import java.util.ArrayList;
@@ -25,12 +26,14 @@ public class ViewPagerAdapter extends PagerAdapter implements TabLayout.OnTabSel
25 26
 
26 27
     private BaseReactActivity mContext;
27 28
     private ViewPager mViewPager;
29
+    private Toolbar mToolbar;
28 30
     private final ArrayList<Screen> mScreens;
29 31
     private final ReactInstanceManager mReactInstanceManager;
30 32
 
31
-    public ViewPagerAdapter(BaseReactActivity context, ViewPager viewPager, ArrayList<Screen> screens) {
33
+    public ViewPagerAdapter(BaseReactActivity context, ViewPager viewPager, Toolbar toolbar, ArrayList<Screen> screens) {
32 34
         mContext = context;
33 35
         mViewPager = viewPager;
36
+        mToolbar = toolbar;
34 37
         mScreens = screens;
35 38
         mReactInstanceManager = RctManager.getInstance().getReactInstanceManager();
36 39
     }
@@ -65,9 +68,11 @@ public class ViewPagerAdapter extends PagerAdapter implements TabLayout.OnTabSel
65 68
 
66 69
     @Override
67 70
     public void onTabSelected(TabLayout.Tab tab) {
71
+        // Set the viewPager's current item
68 72
         int position = tab.getPosition();
69 73
         mViewPager.setCurrentItem(position);
70 74
 
75
+        // Send tab selected event
71 76
         WritableMap params = Arguments.createMap();
72 77
         Screen screen = mScreens.get(position);
73 78
         params.putString(Screen.KEY_NAVIGATOR_EVENT_ID, screen.navigatorEventId);

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

@@ -0,0 +1,95 @@
1
+package com.reactnativenavigation.core.objects;
2
+
3
+import android.content.Context;
4
+import android.graphics.Bitmap;
5
+import android.graphics.BitmapFactory;
6
+import android.graphics.drawable.BitmapDrawable;
7
+import android.graphics.drawable.Drawable;
8
+import android.net.Uri;
9
+
10
+import com.facebook.react.bridge.ReadableMap;
11
+import com.reactnativenavigation.BuildConfig;
12
+import com.reactnativenavigation.utils.ResourceDrawableIdHelper;
13
+
14
+import java.io.Serializable;
15
+import java.net.URL;
16
+import java.util.HashMap;
17
+import java.util.Map;
18
+import java.util.concurrent.atomic.AtomicInteger;
19
+
20
+/**
21
+ * Created by guyc on 08/04/16.
22
+ */
23
+public class Button extends JsonObject implements Serializable {
24
+    private static final long serialVersionUID = -570145217281069067L;
25
+
26
+    private static ResourceDrawableIdHelper sResDrawableIdHelper = new ResourceDrawableIdHelper();
27
+
28
+    private static final String KEY_ID = "id";
29
+    private static final String KEY_TITLE = "title";
30
+    private static final String KEY_ICON = "icon";
31
+
32
+    public String id;
33
+    public String title;
34
+    private String mIconSource;
35
+
36
+    private static AtomicInteger sAtomicIdGenerator = new AtomicInteger();
37
+    private static Map<String, Integer> sStringToNumericId = new HashMap<>();
38
+
39
+    public Button(ReadableMap button) {
40
+        id = getString(button, KEY_ID);
41
+        title = getString(button, KEY_TITLE, "");
42
+        mIconSource = getString(button, KEY_ICON);
43
+    }
44
+
45
+    public boolean hasIcon() {
46
+        return mIconSource != null;
47
+    }
48
+
49
+    public Drawable getIcon(Context ctx) {
50
+        if (mIconSource == null) {
51
+            return null;
52
+        }
53
+
54
+        try {
55
+            Uri icon = getIconUri(ctx);
56
+            URL url = new URL(icon.toString());
57
+            Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());
58
+            return new BitmapDrawable(bitmap);
59
+        } catch (Exception e) {
60
+            if (BuildConfig.DEBUG) {
61
+                e.printStackTrace();
62
+            }
63
+        }
64
+        return null;
65
+    }
66
+
67
+    private Uri getIconUri(Context context) {
68
+        Uri ret = null;
69
+        if (mIconSource != null) {
70
+            try {
71
+                ret = Uri.parse(mIconSource);
72
+                // Verify scheme is set, so that relative uri (used by static resources) are not handled.
73
+                if (ret.getScheme() == null) {
74
+                    ret = null;
75
+                }
76
+            } catch (Exception e) {
77
+                // ignore malformed uri, then attempt to extract resource ID.
78
+            }
79
+            if (ret == null) {
80
+                ret = sResDrawableIdHelper.getResourceDrawableUri(context, mIconSource);
81
+            }
82
+        }
83
+        return ret;
84
+    }
85
+
86
+    public int getItemId() {
87
+        if (sStringToNumericId.containsKey(id)) {
88
+            return sStringToNumericId.get(id);
89
+        }
90
+
91
+        int itemId = sAtomicIdGenerator.addAndGet(1);
92
+        sStringToNumericId.put(id, itemId);
93
+        return itemId;
94
+    }
95
+}

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

@@ -0,0 +1,21 @@
1
+package com.reactnativenavigation.core.objects;
2
+
3
+import com.facebook.react.bridge.ReadableMap;
4
+
5
+/**
6
+ * Created by guyc on 08/04/16.
7
+ */
8
+public class JsonObject {
9
+
10
+    protected String getString(ReadableMap map, String key) {
11
+        return getString(map, key, null);
12
+    }
13
+
14
+    protected String getString(ReadableMap map, String key, String defaultValue) {
15
+        return map.hasKey(key) ? map.getString(key) : defaultValue;
16
+    }
17
+
18
+    protected int getInt(ReadableMap map, String key) {
19
+        return map.hasKey(key) ? map.getInt(key) : -1;
20
+    }
21
+}

android/app/src/main/java/com/reactnativenavigation/core/Screen.java → android/app/src/main/java/com/reactnativenavigation/core/objects/Screen.java View File

@@ -1,20 +1,26 @@
1
-package com.reactnativenavigation.core;
1
+package com.reactnativenavigation.core.objects;
2 2
 
3
+import com.facebook.react.bridge.ReadableArray;
3 4
 import com.facebook.react.bridge.ReadableMap;
4 5
 
5 6
 import java.io.Serializable;
7
+import java.util.ArrayList;
8
+import java.util.List;
6 9
 
7 10
 /**
8 11
  * Created by guyc on 02/04/16.
9 12
  */
10
-public class Screen implements Serializable {
13
+public class Screen extends JsonObject implements Serializable {
11 14
     private static final long serialVersionUID = -1033475305421107791L;
15
+
12 16
     private static final String KEY_TITLE = "title";
13 17
     private static final String KEY_SCREEN = "screen";
14 18
     public static final String KEY_SCREEN_INSTANCE_ID = "screenInstanceID";
15 19
     public static final String KEY_STACK_ID = "stackID";
16 20
     public static final String KEY_NAVIGATOR_ID = "navigatorID";
17 21
     public static final String KEY_NAVIGATOR_EVENT_ID = "navigatorEventID";
22
+    private static final String KEY_ICON = "icon";
23
+    private static final String KEY_RIGHT_BUTTONS = "rightButtons";
18 24
 
19 25
     public String title;
20 26
     public String screenId;
@@ -22,6 +28,8 @@ public class Screen implements Serializable {
22 28
     public String stackId;
23 29
     public String navigatorId;
24 30
     public String navigatorEventId;
31
+    public int icon;
32
+    public List<Button> buttons;
25 33
 
26 34
     public Screen(ReadableMap screen) {
27 35
         title = getString(screen, KEY_TITLE);
@@ -30,9 +38,14 @@ public class Screen implements Serializable {
30 38
         stackId = getString(screen, KEY_STACK_ID);
31 39
         navigatorId = getString(screen, KEY_NAVIGATOR_ID);
32 40
         navigatorEventId = getString(screen, KEY_NAVIGATOR_EVENT_ID);
33
-    }
41
+        icon = getInt(screen, KEY_ICON);
34 42
 
35
-    private String getString(ReadableMap map, String key) {
36
-        return map.hasKey(key) ? map.getString(key) : null;
43
+        if (screen.hasKey(KEY_RIGHT_BUTTONS)) {
44
+            buttons = new ArrayList<>();
45
+            ReadableArray rightButtons = screen.getArray(KEY_RIGHT_BUTTONS);
46
+            for (int i = 0; i < rightButtons.size(); i++) {
47
+                buttons.add(new Button(rightButtons.getMap(i)));
48
+            }
49
+        }
37 50
     }
38 51
 }

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

@@ -12,7 +12,7 @@ import com.facebook.react.bridge.ReadableMap;
12 12
 import com.reactnativenavigation.activities.RctActivity;
13 13
 import com.reactnativenavigation.activities.SingleScreenActivity;
14 14
 import com.reactnativenavigation.activities.TabActivity;
15
-import com.reactnativenavigation.core.Screen;
15
+import com.reactnativenavigation.core.objects.Screen;
16 16
 import com.reactnativenavigation.utils.ContextProvider;
17 17
 
18 18
 import java.util.ArrayList;

+ 2
- 1
android/app/src/main/java/com/reactnativenavigation/utils/ContextProvider.java View File

@@ -1,6 +1,7 @@
1 1
 package com.reactnativenavigation.utils;
2 2
 
3 3
 import android.app.Activity;
4
+import android.support.annotation.Nullable;
4 5
 
5 6
 import java.lang.ref.WeakReference;
6 7
 
@@ -17,7 +18,7 @@ public class ContextProvider {
17 18
         }
18 19
     }
19 20
 
20
-    public static Activity getActivityContext() {
21
+    public static @Nullable Activity getActivityContext() {
21 22
         return sActivityWR != null ? sActivityWR.get() : null;
22 23
     }
23 24
 

+ 1
- 1
android/app/src/main/java/com/reactnativenavigation/views/RctView.java View File

@@ -6,7 +6,7 @@ import android.widget.FrameLayout;
6 6
 import com.facebook.react.ReactInstanceManager;
7 7
 import com.facebook.react.ReactRootView;
8 8
 import com.reactnativenavigation.activities.BaseReactActivity;
9
-import com.reactnativenavigation.core.Screen;
9
+import com.reactnativenavigation.core.objects.Screen;
10 10
 
11 11
 /**
12 12
  * Created by guyc on 10/03/16.

+ 95
- 0
android/app/src/main/java/com/reactnativenavigation/views/RnnToolBar.java View File

@@ -0,0 +1,95 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.content.Context;
4
+import android.graphics.drawable.Drawable;
5
+import android.os.AsyncTask;
6
+import android.support.v7.widget.Toolbar;
7
+import android.util.AttributeSet;
8
+import android.view.Menu;
9
+import android.view.MenuItem;
10
+
11
+import com.reactnativenavigation.activities.BaseReactActivity;
12
+import com.reactnativenavigation.core.objects.Button;
13
+import com.reactnativenavigation.core.objects.Screen;
14
+import com.reactnativenavigation.utils.ContextProvider;
15
+
16
+import java.util.HashMap;
17
+import java.util.List;
18
+import java.util.Map;
19
+
20
+/**
21
+ * Created by guyc on 09/04/16.
22
+ */
23
+public class RnnToolBar extends Toolbar {
24
+
25
+    private List<Screen> mScreens;
26
+    private static boolean sIsSettingUpToolbar = false;
27
+
28
+    public RnnToolBar(Context context) {
29
+        super(context);
30
+    }
31
+
32
+    public RnnToolBar(Context context, AttributeSet attrs) {
33
+        super(context, attrs);
34
+    }
35
+
36
+    public RnnToolBar(Context context, AttributeSet attrs, int defStyleAttr) {
37
+        super(context, attrs, defStyleAttr);
38
+    }
39
+
40
+    public void setScreens(List<Screen> screens) {
41
+        mScreens = screens;
42
+    }
43
+
44
+    public void handleOnCreateOptionsMenuAsync() {
45
+        if (!sIsSettingUpToolbar) {
46
+            new SetupToolbarButtons().execute(mScreens.get(0));
47
+        }
48
+    }
49
+
50
+    private static class SetupToolbarButtons extends AsyncTask<Screen, Void, Map<String, Drawable>> {
51
+        private List<Button> mButtons;
52
+
53
+        public SetupToolbarButtons() {
54
+            sIsSettingUpToolbar = true;
55
+        }
56
+
57
+        @Override
58
+        protected Map<String, Drawable> doInBackground(Screen... screen) {
59
+            mButtons = screen[0].buttons;
60
+            Context context = ContextProvider.getActivityContext();
61
+            if (context == null) {
62
+                return null;
63
+            }
64
+
65
+            Map<String, Drawable> icons = new HashMap<>();
66
+            for (Button button : mButtons) {
67
+                if (button.hasIcon()) {
68
+                    icons.put(button.id, button.getIcon(context));
69
+                }
70
+            }
71
+            return icons;
72
+        }
73
+
74
+        @Override
75
+        protected void onPostExecute(Map<String, Drawable> icons) {
76
+            Context context = ContextProvider.getActivityContext();
77
+            if (context == null) {
78
+                return;
79
+            }
80
+
81
+            Menu menu = ((BaseReactActivity) context).getMenu();
82
+
83
+            for (Button button : mButtons) {
84
+                MenuItem item = menu.add(Menu.NONE, button.getItemId(), Menu.NONE, button.title);
85
+                if (icons.containsKey(button.id)) {
86
+                    Drawable icon = icons.get(button.id);
87
+
88
+                    item.setIcon(icon).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
89
+                }
90
+            }
91
+
92
+            sIsSettingUpToolbar = false;
93
+        }
94
+    }
95
+}

+ 1
- 1
android/app/src/main/res/layout/tab_activity.xml View File

@@ -12,7 +12,7 @@
12 12
         android:layout_width="match_parent"
13 13
         android:layout_height="wrap_content"
14 14
         android:fitsSystemWindows="true">
15
-        <android.support.v7.widget.Toolbar
15
+        <com.reactnativenavigation.views.RnnToolBar
16 16
             android:id="@+id/toolbar"
17 17
             android:layout_width="match_parent"
18 18
             android:layout_height="?attr/actionBarSize"

+ 28
- 4
src/platformSpecific.android.js View File

@@ -5,6 +5,8 @@ import {
5 5
   RctActivity
6 6
 } from 'react-native-navigation';
7 7
 
8
+var resolveAssetSource = require('resolveAssetSource');
9
+
8 10
 function startSingleScreenApp(params) {
9 11
   let screen = params.screen;
10 12
   if (!screen.screen) {
@@ -13,7 +15,8 @@ function startSingleScreenApp(params) {
13 15
   }
14 16
 
15 17
   console.log(RctActivity);
16
-  addNavigationParams(screen);
18
+  addNavigatorParams(screen);
19
+  addNavigatorButtons(screen);
17 20
   RctActivity.startSingleScreenApp(screen);
18 21
 }
19 22
 
@@ -24,24 +27,45 @@ function startTabBasedApp(params) {
24 27
   }
25 28
 
26 29
   params.tabs.forEach(function (tab, idx) {
27
-    addNavigationParams(tab, idx)
30
+    addNavigatorParams(tab, idx)
31
+    addNavigatorButtons(tab);
28 32
   });
29 33
 
30 34
   RctActivity.startTabBasedApp(params.tabs);
31 35
 }
32 36
 
33 37
 function navigatorPush(navigator, params) {
34
-  addNavigationParams(params)
38
+  addNavigatorParams(params)
39
+  addNavigatorButtons(params);
35 40
   RctActivity.navigatorPush(params);
36 41
 }
37 42
 
38
-function addNavigationParams(screen, idx = '') {
43
+function addNavigatorParams(screen, idx = '') {
39 44
   screen.stackID = utils.getRandomId();
40 45
   screen.navigatorID = utils.getRandomId() + '_nav' + idx;
41 46
   screen.screenInstanceID = utils.getRandomId();
42 47
   screen.navigatorEventID = screen.screenInstanceID + '_events';
43 48
 }
44 49
 
50
+function addNavigatorButtons(screen) {
51
+  const Screen = Navigation.getRegisteredScreen(screen.screen);
52
+  Object.assign(screen, Screen.navigatorButtons);
53
+
54
+  // Get image uri from image id
55
+  if (screen.rightButtons) {
56
+    screen.rightButtons.forEach(function(button) {
57
+      if (button.icon) {
58
+        const icon = resolveAssetSource(button.icon);
59
+        console.log('This is an icon:\n' + JSON.stringify(icon));
60
+        if (icon) {
61
+          button.icon = icon.uri;
62
+        }
63
+        console.log('final icon: ' + button.icon);
64
+      }
65
+    });
66
+  }
67
+}
68
+
45 69
 export default {
46 70
   startSingleScreenApp,
47 71
   startTabBasedApp,

+ 3
- 5
src/platformSpecific.ios.js View File

@@ -37,9 +37,8 @@ function startTabBasedApp(params) {
37 37
       return (
38 38
         <TabBarControllerIOS
39 39
           id={controllerID + '_tabs'}
40
-          style={params.tabsStyle}
41
-        >
42
-        {
40
+          style={params.tabsStyle}>
41
+          {
43 42
           params.tabs.map(function(tab, index) {
44 43
             const navigatorID = controllerID + '_nav' + index;
45 44
             const screenInstanceID = utils.getRandomId();
@@ -96,8 +95,7 @@ function startSingleScreenApp(params) {
96 95
             componentLeft={params.drawer.left ? params.drawer.left.screen : undefined}
97 96
             passPropsLeft={{navigatorID: navigatorID}}
98 97
             componentRight={params.drawer.right ? params.drawer.right.screen : undefined}
99
-            passPropsRight={{navigatorID: navigatorID}}
100
-          >
98
+            passPropsRight={{navigatorID: navigatorID}}>
101 99
             {this.renderBody()}
102 100
           </DrawerControllerIOS>
103 101
         );