Browse Source

Merge branch 'snackbar'

Guy Carmeli 8 years ago
parent
commit
9b331aecb7
23 changed files with 381 additions and 19 deletions
  1. 8
    0
      android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java
  2. 5
    0
      android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java
  3. 15
    0
      android/app/src/main/java/com/reactnativenavigation/controllers/NavigationCommandsHandler.java
  4. 16
    0
      android/app/src/main/java/com/reactnativenavigation/events/LocalBroadcastEvent.java
  5. 12
    0
      android/app/src/main/java/com/reactnativenavigation/events/ScreenChangeBroadcast.java
  6. 40
    0
      android/app/src/main/java/com/reactnativenavigation/events/ScreenChangeBroadcastReceiver.java
  7. 29
    5
      android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java
  8. 3
    0
      android/app/src/main/java/com/reactnativenavigation/layouts/Layout.java
  9. 30
    2
      android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java
  10. 9
    0
      android/app/src/main/java/com/reactnativenavigation/params/SnackbarParams.java
  11. 3
    0
      android/app/src/main/java/com/reactnativenavigation/params/StyleParams.java
  12. 7
    1
      android/app/src/main/java/com/reactnativenavigation/params/parsers/Parser.java
  13. 32
    0
      android/app/src/main/java/com/reactnativenavigation/params/parsers/SnackbarParamsParser.java
  14. 0
    6
      android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarButtonParamsParser.java
  15. 8
    2
      android/app/src/main/java/com/reactnativenavigation/screens/ContentViewPagerAdapter.java
  16. 4
    0
      android/app/src/main/java/com/reactnativenavigation/screens/Screen.java
  17. 5
    0
      android/app/src/main/java/com/reactnativenavigation/screens/ViewPagerScreen.java
  18. 49
    0
      android/app/src/main/java/com/reactnativenavigation/views/SnackbarContainer.java
  19. 71
    0
      android/app/src/main/java/com/reactnativenavigation/views/Snakbar.java
  20. 19
    1
      example-redux/src/screens/FirstTabScreen.js
  21. 4
    0
      src/Screen.js
  22. 6
    1
      src/deprecated/platformSpecificDeprecated.android.js
  23. 6
    1
      src/platformSpecific.android.js

+ 8
- 0
android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java View File

@@ -6,8 +6,10 @@ import com.facebook.react.bridge.ReactMethod;
6 6
 import com.facebook.react.bridge.ReadableArray;
7 7
 import com.facebook.react.bridge.ReadableMap;
8 8
 import com.reactnativenavigation.controllers.NavigationCommandsHandler;
9
+import com.reactnativenavigation.params.SnackbarParams;
9 10
 import com.reactnativenavigation.params.TitleBarButtonParams;
10 11
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
12
+import com.reactnativenavigation.params.parsers.SnackbarParamsParser;
11 13
 import com.reactnativenavigation.params.parsers.TitleBarButtonParamsParser;
12 14
 import com.reactnativenavigation.params.parsers.TitleBarLeftButtonParamsParser;
13 15
 
@@ -153,4 +155,10 @@ public class NavigationReactModule extends ReactContextBaseJavaModule {
153 155
     public void dismissTopModal() {
154 156
         NavigationCommandsHandler.dismissTopModal();
155 157
     }
158
+
159
+    @ReactMethod
160
+    public void showSnackbar(final ReadableMap params) {
161
+        SnackbarParams snackbarParams = new SnackbarParamsParser().parse(BundleConverter.toBundle(params));
162
+        NavigationCommandsHandler.showSnackbar(snackbarParams);
163
+    }
156 164
 }

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

@@ -12,6 +12,7 @@ import com.reactnativenavigation.layouts.Layout;
12 12
 import com.reactnativenavigation.layouts.LayoutFactory;
13 13
 import com.reactnativenavigation.params.ActivityParams;
14 14
 import com.reactnativenavigation.params.ScreenParams;
15
+import com.reactnativenavigation.params.SnackbarParams;
15 16
 import com.reactnativenavigation.params.TitleBarButtonParams;
16 17
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
17 18
 import com.reactnativenavigation.react.JsDevReloadHandler;
@@ -239,4 +240,8 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard
239 240
             ((BottomTabsLayout) layout).setBottomTabBadgeByNavigatorId(navigatorId, badge);
240 241
         }
241 242
     }
243
+
244
+    public void showSnackbar(SnackbarParams params) {
245
+        layout.showSnackbar(params);
246
+    }
242 247
 }

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

@@ -6,6 +6,7 @@ import android.os.Bundle;
6 6
 import com.reactnativenavigation.NavigationApplication;
7 7
 import com.reactnativenavigation.params.ActivityParams;
8 8
 import com.reactnativenavigation.params.ScreenParams;
9
+import com.reactnativenavigation.params.SnackbarParams;
9 10
 import com.reactnativenavigation.params.TitleBarButtonParams;
10 11
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
11 12
 import com.reactnativenavigation.params.parsers.ActivityParamsParser;
@@ -294,4 +295,18 @@ public class NavigationCommandsHandler {
294 295
             }
295 296
         });
296 297
     }
298
+
299
+    public static void showSnackbar(final SnackbarParams params) {
300
+        final NavigationActivity currentActivity = NavigationActivity.currentActivity;
301
+        if (currentActivity == null) {
302
+            return;
303
+        }
304
+
305
+        NavigationApplication.instance.runOnMainThread(new Runnable() {
306
+            @Override
307
+            public void run() {
308
+                currentActivity.showSnackbar(params);
309
+            }
310
+        });
311
+    }
297 312
 }

+ 16
- 0
android/app/src/main/java/com/reactnativenavigation/events/LocalBroadcastEvent.java View File

@@ -0,0 +1,16 @@
1
+package com.reactnativenavigation.events;
2
+
3
+import android.content.Intent;
4
+import android.support.v4.content.LocalBroadcastManager;
5
+
6
+import com.reactnativenavigation.NavigationApplication;
7
+
8
+public abstract class LocalBroadcastEvent {
9
+
10
+    public abstract Intent getIntent();
11
+
12
+    public void send() {
13
+        LocalBroadcastManager.getInstance(NavigationApplication.instance).sendBroadcast(getIntent());
14
+    }
15
+
16
+}

+ 12
- 0
android/app/src/main/java/com/reactnativenavigation/events/ScreenChangeBroadcast.java View File

@@ -0,0 +1,12 @@
1
+package com.reactnativenavigation.events;
2
+
3
+import android.content.Intent;
4
+
5
+public class ScreenChangeBroadcast extends LocalBroadcastEvent {
6
+    public static final String ACTION = "screenChange";
7
+
8
+    @Override
9
+    public Intent getIntent() {
10
+        return new Intent(ACTION);
11
+    }
12
+}

+ 40
- 0
android/app/src/main/java/com/reactnativenavigation/events/ScreenChangeBroadcastReceiver.java View File

@@ -0,0 +1,40 @@
1
+package com.reactnativenavigation.events;
2
+
3
+import android.content.BroadcastReceiver;
4
+import android.content.Context;
5
+import android.content.Intent;
6
+import android.content.IntentFilter;
7
+import android.support.v4.content.LocalBroadcastManager;
8
+
9
+import com.reactnativenavigation.NavigationApplication;
10
+
11
+public class ScreenChangeBroadcastReceiver extends BroadcastReceiver {
12
+    private OnScreenChangeListener onTabSelectedListener;
13
+
14
+    public interface OnScreenChangeListener {
15
+        void onScreenChangeListener();
16
+    }
17
+
18
+    public ScreenChangeBroadcastReceiver(OnScreenChangeListener onTabSelectedListener) {
19
+        this.onTabSelectedListener = onTabSelectedListener;
20
+    }
21
+
22
+    @Override
23
+    public void onReceive(Context context, Intent intent) {
24
+        onTabSelectedListener.onScreenChangeListener();
25
+    }
26
+
27
+    public void register() {
28
+        IntentFilter intentFilter = new IntentFilter();
29
+        intentFilter.addAction(ScreenChangeBroadcast.ACTION);
30
+        getBroadcastManager().registerReceiver(this, intentFilter);
31
+    }
32
+
33
+    public void unregister() {
34
+        getBroadcastManager().unregisterReceiver(this);
35
+    }
36
+
37
+    private LocalBroadcastManager getBroadcastManager() {
38
+        return LocalBroadcastManager.getInstance(NavigationApplication.instance);
39
+    }
40
+}

+ 29
- 5
android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java View File

@@ -10,11 +10,13 @@ import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
10 10
 import com.reactnativenavigation.params.ActivityParams;
11 11
 import com.reactnativenavigation.params.ScreenParams;
12 12
 import com.reactnativenavigation.params.SideMenuParams;
13
+import com.reactnativenavigation.params.SnackbarParams;
13 14
 import com.reactnativenavigation.params.TitleBarButtonParams;
14 15
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
15 16
 import com.reactnativenavigation.screens.ScreenStack;
16 17
 import com.reactnativenavigation.views.BottomTabs;
17 18
 import com.reactnativenavigation.views.SideMenu;
19
+import com.reactnativenavigation.views.SnackbarContainer;
18 20
 
19 21
 import java.util.List;
20 22
 
@@ -25,6 +27,7 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
25 27
 
26 28
     private final AppCompatActivity activity;
27 29
     private ActivityParams params;
30
+    private SnackbarContainer snackbarContainer;
28 31
     private BottomTabs bottomTabs;
29 32
     private ScreenStack[] screenStacks;
30 33
     private final SideMenuParams sideMenuParams;
@@ -45,6 +48,7 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
45 48
         createBottomTabs();
46 49
         addBottomTabs();
47 50
         addScreenStacks();
51
+        createSnackbarContainer();
48 52
         showInitialScreenStack();
49 53
     }
50 54
 
@@ -94,6 +98,14 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
94 98
         getScreenStackParent().addView(bottomTabs, lp);
95 99
     }
96 100
 
101
+    private void createSnackbarContainer() {
102
+        snackbarContainer = new SnackbarContainer(getContext());
103
+        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
104
+        lp.addRule(ABOVE, bottomTabs.getId());
105
+        snackbarContainer.setLayoutParams(lp);
106
+        getScreenStackParent().addView(snackbarContainer);
107
+    }
108
+
97 109
     private void showInitialScreenStack() {
98 110
         showStackAndUpdateStyle(screenStacks[0]);
99 111
     }
@@ -164,6 +176,12 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
164 176
         }
165 177
     }
166 178
 
179
+    @Override
180
+    public void showSnackbar(SnackbarParams params) {
181
+        final String eventId = getCurrentScreenStack().peek().getNavigatorEventId();
182
+        snackbarContainer.showSnackbar(eventId, params);
183
+    }
184
+
167 185
     public void selectBottomTabByTabIndex(Integer index) {
168 186
         bottomTabs.setCurrentItem(index);
169 187
     }
@@ -179,6 +197,7 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
179 197
         if (isCurrentStack(screenStack)) {
180 198
             bottomTabs.setStyleFromScreen(screenParams.styleParams);
181 199
         }
200
+        snackbarContainer.onScreenChange();
182 201
     }
183 202
 
184 203
     @Override
@@ -189,12 +208,14 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
189 208
                 setBottomTabsStyleFromCurrentScreen();
190 209
             }
191 210
         });
211
+        snackbarContainer.onScreenChange();
192 212
     }
193 213
 
194 214
     @Override
195 215
     public void popToRoot(ScreenParams params) {
196 216
         getCurrentScreenStack().popToRoot(params.animateScreenTransitions);
197 217
         setBottomTabsStyleFromCurrentScreen();
218
+        snackbarContainer.onScreenChange();
198 219
     }
199 220
 
200 221
     @Override
@@ -209,14 +230,15 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
209 230
         screenStacks[currentStackIndex] = newStack;
210 231
 
211 232
         bottomTabs.setStyleFromScreen(params.styleParams);
233
+        snackbarContainer.onScreenChange();
212 234
     }
213 235
 
214 236
     @Override
215 237
     public void destroy() {
238
+        snackbarContainer.destroy();
216 239
         for (ScreenStack screenStack : screenStacks) {
217 240
             screenStack.destroy();
218 241
         }
219
-
220 242
         if (sideMenu != null) {
221 243
             sideMenu.destroy();
222 244
         }
@@ -225,12 +247,14 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
225 247
     @Override
226 248
     public boolean onTabSelected(int position, boolean wasSelected) {
227 249
         hideCurrentStack();
250
+        showNewStack(position);
251
+        snackbarContainer.onScreenChange();
252
+        return true;
253
+    }
228 254
 
229
-        ScreenStack newStack = screenStacks[position];
230
-        showStackAndUpdateStyle(newStack);
255
+    private void showNewStack(int position) {
256
+        showStackAndUpdateStyle(screenStacks[position]);
231 257
         currentStackIndex = position;
232
-
233
-        return true;
234 258
     }
235 259
 
236 260
     private void showStackAndUpdateStyle(ScreenStack newStack) {

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

@@ -2,6 +2,7 @@ package com.reactnativenavigation.layouts;
2 2
 
3 3
 import android.view.View;
4 4
 
5
+import com.reactnativenavigation.params.SnackbarParams;
5 6
 import com.reactnativenavigation.params.TitleBarButtonParams;
6 7
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
7 8
 
@@ -23,4 +24,6 @@ public interface Layout extends ScreenStackContainer {
23 24
     void toggleSideMenuVisible(boolean animated);
24 25
 
25 26
     void setSideMenuVisible(boolean animated, boolean visible);
27
+
28
+    void showSnackbar(SnackbarParams params);
26 29
 }

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

@@ -7,15 +7,18 @@ import android.widget.RelativeLayout;
7 7
 
8 8
 import com.reactnativenavigation.params.ScreenParams;
9 9
 import com.reactnativenavigation.params.SideMenuParams;
10
+import com.reactnativenavigation.params.SnackbarParams;
10 11
 import com.reactnativenavigation.params.TitleBarButtonParams;
11 12
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
12 13
 import com.reactnativenavigation.screens.ScreenStack;
13 14
 import com.reactnativenavigation.views.LeftButtonOnClickListener;
14 15
 import com.reactnativenavigation.views.SideMenu;
16
+import com.reactnativenavigation.views.SnackbarContainer;
15 17
 
16 18
 import java.util.List;
17 19
 
18 20
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
21
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
19 22
 
20 23
 public class SingleScreenLayout extends RelativeLayout implements Layout {
21 24
 
@@ -23,6 +26,7 @@ public class SingleScreenLayout extends RelativeLayout implements Layout {
23 26
     protected final ScreenParams screenParams;
24 27
     private final SideMenuParams sideMenuParams;
25 28
     protected ScreenStack stack;
29
+    private SnackbarContainer snackbarContainer;
26 30
     protected LeftButtonOnClickListener leftButtonOnClickListener;
27 31
     private @Nullable SideMenu sideMenu;
28 32
 
@@ -36,11 +40,16 @@ public class SingleScreenLayout extends RelativeLayout implements Layout {
36 40
 
37 41
     private void createLayout() {
38 42
         if (sideMenuParams == null) {
39
-            createStack(this);
43
+            createStack(getScreenStackParent());
40 44
         } else {
41 45
             sideMenu = createSideMenu();
42
-            createStack(sideMenu.getContentContainer());
46
+            createStack(getScreenStackParent());
43 47
         }
48
+        createSnackbarContainer();
49
+    }
50
+
51
+    private RelativeLayout getScreenStackParent() {
52
+        return sideMenu == null ? this : sideMenu.getContentContainer();
44 53
     }
45 54
 
46 55
     private SideMenu createSideMenu() {
@@ -64,6 +73,14 @@ public class SingleScreenLayout extends RelativeLayout implements Layout {
64 73
         stack.show();
65 74
     }
66 75
 
76
+    private void createSnackbarContainer() {
77
+        snackbarContainer = new SnackbarContainer(getContext());
78
+        RelativeLayout.LayoutParams lp = new LayoutParams(MATCH_PARENT, WRAP_CONTENT);
79
+        lp.addRule(ALIGN_PARENT_BOTTOM);
80
+        snackbarContainer.setLayoutParams(lp);
81
+        getScreenStackParent().addView(snackbarContainer);
82
+    }
83
+
67 84
     @Override
68 85
     public boolean onBackPressed() {
69 86
         if (stack.handleBackPressInJs()) {
@@ -81,6 +98,7 @@ public class SingleScreenLayout extends RelativeLayout implements Layout {
81 98
     @Override
82 99
     public void destroy() {
83 100
         stack.destroy();
101
+        snackbarContainer.destroy();
84 102
         if (sideMenu != null) {
85 103
             sideMenu.destroy();
86 104
         }
@@ -90,22 +108,26 @@ public class SingleScreenLayout extends RelativeLayout implements Layout {
90 108
     public void push(ScreenParams params) {
91 109
         LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
92 110
         stack.push(params, lp);
111
+        snackbarContainer.onScreenChange();
93 112
     }
94 113
 
95 114
     @Override
96 115
     public void pop(ScreenParams params) {
97 116
         stack.pop(params.animateScreenTransitions);
117
+        snackbarContainer.onScreenChange();
98 118
     }
99 119
 
100 120
     @Override
101 121
     public void popToRoot(ScreenParams params) {
102 122
         stack.popToRoot(params.animateScreenTransitions);
123
+        snackbarContainer.onScreenChange();
103 124
     }
104 125
 
105 126
     @Override
106 127
     public void newStack(ScreenParams params) {
107 128
         RelativeLayout parent = sideMenu == null ? this : sideMenu.getContentContainer();
108 129
         createStack(parent);
130
+        snackbarContainer.onScreenChange();
109 131
     }
110 132
 
111 133
     @Override
@@ -148,6 +170,12 @@ public class SingleScreenLayout extends RelativeLayout implements Layout {
148 170
         }
149 171
     }
150 172
 
173
+    @Override
174
+    public void showSnackbar(SnackbarParams params) {
175
+        final String navigatorEventId = stack.peek().getNavigatorEventId();
176
+        snackbarContainer.showSnackbar(navigatorEventId, params);
177
+    }
178
+
151 179
     @Override
152 180
     public boolean onTitleBarBackButtonClick() {
153 181
         if (leftButtonOnClickListener != null) {

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

@@ -0,0 +1,9 @@
1
+package com.reactnativenavigation.params;
2
+
3
+public class SnackbarParams {
4
+    public String text;
5
+    public String buttonText;
6
+    public StyleParams.Color buttonColor;
7
+    public String eventId;
8
+    public int duration;
9
+}

+ 3
- 0
android/app/src/main/java/com/reactnativenavigation/params/StyleParams.java View File

@@ -55,6 +55,9 @@ public class StyleParams {
55 55
 
56 56
     public boolean drawScreenAboveBottomTabs;
57 57
 
58
+    public Color snackbarTextColor;
59
+    public Color snackbarButtonColor;
60
+
58 61
     public boolean bottomTabsHidden;
59 62
     public boolean bottomTabsHiddenOnScroll;
60 63
     public Color bottomTabsColor;

+ 7
- 1
android/app/src/main/java/com/reactnativenavigation/params/parsers/Parser.java View File

@@ -2,6 +2,8 @@ package com.reactnativenavigation.params.parsers;
2 2
 
3 3
 import android.os.Bundle;
4 4
 
5
+import com.reactnativenavigation.params.StyleParams;
6
+
5 7
 import java.util.ArrayList;
6 8
 import java.util.Collections;
7 9
 import java.util.List;
@@ -11,7 +13,6 @@ public class Parser {
11 13
         return bundle.keySet().contains(key);
12 14
     }
13 15
 
14
-
15 16
     protected static void assertKeyExists(Bundle bundle, String key) {
16 17
         if (!hasKey(bundle, key)) {
17 18
             throw new KeyDoesNotExistsException(key);
@@ -35,4 +36,9 @@ public class Parser {
35 36
         }
36 37
         return result;
37 38
     }
39
+
40
+    protected StyleParams.Color getColor(Bundle bundle, String key, StyleParams.Color defaultColor) {
41
+        StyleParams.Color color = StyleParams.Color.parse(bundle.getString(key));
42
+        return color.hasColor() || defaultColor == null ? color : defaultColor;
43
+    }
38 44
 }

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

@@ -0,0 +1,32 @@
1
+package com.reactnativenavigation.params.parsers;
2
+
3
+import android.os.Bundle;
4
+import android.support.design.widget.Snackbar;
5
+
6
+import com.reactnativenavigation.params.AppStyle;
7
+import com.reactnativenavigation.params.SnackbarParams;
8
+
9
+public class SnackbarParamsParser extends Parser {
10
+    public SnackbarParams parse(Bundle params) {
11
+        SnackbarParams result = new SnackbarParams();
12
+        result.text = params.getString("text");
13
+        result.buttonText = params.getString("actionText");
14
+        result.buttonColor = getColor(params, "actionColor", AppStyle.appStyle.snackbarButtonColor);
15
+        result.duration = getDuration(params.getString("duration", "short"));
16
+        result.eventId = params.getString("actionId");
17
+        return result;
18
+    }
19
+
20
+    private int getDuration(String duration) {
21
+        switch (duration) {
22
+            case "short":
23
+                return Snackbar.LENGTH_SHORT;
24
+            case "long":
25
+                return Snackbar.LENGTH_LONG;
26
+            case "indefinite":
27
+                return Snackbar.LENGTH_INDEFINITE;
28
+            default:
29
+                return Snackbar.LENGTH_SHORT;
30
+        }
31
+    }
32
+}

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

@@ -3,7 +3,6 @@ package com.reactnativenavigation.params.parsers;
3 3
 import android.os.Bundle;
4 4
 
5 5
 import com.reactnativenavigation.params.AppStyle;
6
-import com.reactnativenavigation.params.StyleParams;
7 6
 import com.reactnativenavigation.params.TitleBarButtonParams;
8 7
 import com.reactnativenavigation.react.ImageLoader;
9 8
 
@@ -33,11 +32,6 @@ public class TitleBarButtonParamsParser extends Parser {
33 32
         return result;
34 33
     }
35 34
 
36
-    private StyleParams.Color getColor(Bundle bundle, String key, StyleParams.Color defaultColor) {
37
-        StyleParams.Color color = StyleParams.Color.parse(bundle.getString(key));
38
-        return color.hasColor() || defaultColor == null ? color : defaultColor;
39
-    }
40
-
41 35
     private static TitleBarButtonParams.ShowAsAction parseShowAsAction(String showAsAction) {
42 36
         if (showAsAction == null) {
43 37
             return TitleBarButtonParams.ShowAsAction.IfRoom;

+ 8
- 2
android/app/src/main/java/com/reactnativenavigation/screens/ContentViewPagerAdapter.java View File

@@ -7,6 +7,7 @@ import android.view.ViewGroup;
7 7
 import com.facebook.react.bridge.Arguments;
8 8
 import com.facebook.react.bridge.WritableMap;
9 9
 import com.reactnativenavigation.NavigationApplication;
10
+import com.reactnativenavigation.events.ScreenChangeBroadcast;
10 11
 import com.reactnativenavigation.params.TopTabParams;
11 12
 import com.reactnativenavigation.views.ContentView;
12 13
 
@@ -33,11 +34,16 @@ public class ContentViewPagerAdapter extends PagerAdapter {
33 34
         super.setPrimaryItem(container, position, object);
34 35
         if (position != currentPosition) {
35 36
             currentPosition = position;
36
-            sendPageChangeEvent();
37
+            sendScreenChangeBroadcast();
38
+            sendTabSelectedEventToJs();
37 39
         }
38 40
     }
39 41
 
40
-    private void sendPageChangeEvent() {
42
+    private void sendScreenChangeBroadcast() {
43
+        new ScreenChangeBroadcast().send();
44
+    }
45
+
46
+    private void sendTabSelectedEventToJs() {
41 47
         WritableMap data = Arguments.createMap();
42 48
         String navigatorEventId = contentViews.get(currentPosition).getNavigatorEventId();
43 49
         NavigationApplication.instance.sendNavigatorEvent("tabSelected", navigatorEventId, data);

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

@@ -132,6 +132,10 @@ public abstract class Screen extends RelativeLayout {
132 132
         return screenParams.getScreenInstanceId();
133 133
     }
134 134
 
135
+    public String getNavigatorEventId() {
136
+        return screenParams.getNavigatorEventId();
137
+    }
138
+
135 139
     public void setTopBarVisible(boolean visible, boolean animate) {
136 140
         topBarVisibilityAnimator.setVisible(visible, animate);
137 141
     }

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

@@ -92,4 +92,9 @@ public class ViewPagerScreen extends Screen {
92 92
     public String getScreenInstanceId() {
93 93
         return screenParams.topTabParams.get(viewPager.getCurrentItem()).navigationParams.screenInstanceId;
94 94
     }
95
+
96
+    @Override
97
+    public String getNavigatorEventId() {
98
+        return screenParams.topTabParams.get(viewPager.getCurrentItem()).navigationParams.navigatorEventId;
99
+    }
95 100
 }

+ 49
- 0
android/app/src/main/java/com/reactnativenavigation/views/SnackbarContainer.java View File

@@ -0,0 +1,49 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.content.Context;
4
+import android.support.design.widget.CoordinatorLayout;
5
+
6
+import com.reactnativenavigation.events.ScreenChangeBroadcastReceiver;
7
+import com.reactnativenavigation.params.SnackbarParams;
8
+
9
+public class SnackbarContainer extends CoordinatorLayout implements Snakbar.OnDismissListener, ScreenChangeBroadcastReceiver.OnScreenChangeListener {
10
+
11
+    private Snakbar snakbar;
12
+    private ScreenChangeBroadcastReceiver screenChangeBroadcastReceiver;
13
+
14
+    public SnackbarContainer(Context context) {
15
+        super(context);
16
+        registerTabSelectedReceiver();
17
+    }
18
+
19
+    private void registerTabSelectedReceiver() {
20
+        screenChangeBroadcastReceiver = new ScreenChangeBroadcastReceiver(this);
21
+        screenChangeBroadcastReceiver.register();
22
+    }
23
+
24
+    public void showSnackbar(final String navigatorEventId, final SnackbarParams params) {
25
+        snakbar = new Snakbar(this, navigatorEventId, params);
26
+        snakbar.show();
27
+    }
28
+
29
+    public void onScreenChange() {
30
+        if (snakbar != null) {
31
+            snakbar.dismiss();
32
+            snakbar = null;
33
+        }
34
+    }
35
+
36
+    @Override
37
+    public void onDismiss() {
38
+        snakbar = null;
39
+    }
40
+
41
+    public void destroy() {
42
+        screenChangeBroadcastReceiver.unregister();
43
+    }
44
+
45
+    @Override
46
+    public void onScreenChangeListener() {
47
+        onScreenChange();
48
+    }
49
+}

+ 71
- 0
android/app/src/main/java/com/reactnativenavigation/views/Snakbar.java View File

@@ -0,0 +1,71 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.support.design.widget.Snackbar;
4
+import android.view.View;
5
+
6
+import com.reactnativenavigation.NavigationApplication;
7
+import com.reactnativenavigation.params.SnackbarParams;
8
+
9
+public class Snakbar {
10
+    private final OnDismissListener parent;
11
+    private final String navigatorEventId;
12
+    private final SnackbarParams params;
13
+    private Snackbar snackbar;
14
+
15
+    public interface OnDismissListener {
16
+        void onDismiss();
17
+    }
18
+
19
+    public Snakbar(OnDismissListener parent, String navigatorEventId, SnackbarParams params) {
20
+        this.parent = parent;
21
+        this.navigatorEventId = navigatorEventId;
22
+        this.params = params;
23
+        create();
24
+    }
25
+
26
+    private void create() {
27
+        snackbar = Snackbar.make((View) parent, params.text, params.duration);
28
+        setAction(navigatorEventId, params, snackbar);
29
+        setStyle(snackbar, params);
30
+        setOnDismissListener();
31
+    }
32
+
33
+    private void setAction(final String navigatorEventId, final SnackbarParams params, Snackbar snackbar) {
34
+        if (params.eventId != null) {
35
+            snackbar.setAction(params.buttonText, new View.OnClickListener() {
36
+                @Override
37
+                public void onClick(View v) {
38
+                    NavigationApplication.instance.sendNavigatorEvent(params.eventId, navigatorEventId);
39
+                }
40
+            });
41
+        }
42
+    }
43
+
44
+    private void setStyle(Snackbar snackbar, SnackbarParams params) {
45
+        if (params.buttonColor.hasColor()) {
46
+            snackbar.setActionTextColor(params.buttonColor.getColor());
47
+        }
48
+    }
49
+
50
+    private void setOnDismissListener() {
51
+        snackbar.getView().addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
52
+            @Override
53
+            public void onViewAttachedToWindow(View v) {
54
+
55
+            }
56
+
57
+            @Override
58
+            public void onViewDetachedFromWindow(View v) {
59
+                parent.onDismiss();
60
+            }
61
+        });
62
+    }
63
+
64
+    public void show() {
65
+        snackbar.show();
66
+    }
67
+
68
+    public void dismiss() {
69
+        snackbar.dismiss();
70
+    }
71
+}

+ 19
- 1
example-redux/src/screens/FirstTabScreen.js View File

@@ -5,7 +5,8 @@ import {
5 5
   ScrollView,
6 6
   TouchableOpacity,
7 7
   StyleSheet,
8
-  Alert
8
+  Alert,
9
+  Platform
9 10
 } from 'react-native';
10 11
 import {connect} from 'react-redux';
11 12
 import * as counterActions from '../reducers/counter/actions';
@@ -131,6 +132,13 @@ class FirstTabScreen extends Component {
131 132
           <Text style={styles.button}>Toggle NavBar</Text>
132 133
         </TouchableOpacity>
133 134
 
135
+        {
136
+          Platform.OS === 'android' ?
137
+          <TouchableOpacity onPress={ this.onShowSnackbarPress.bind(this) }>
138
+            <Text style={styles.button}>Show Snackbar</Text>
139
+          </TouchableOpacity> : false
140
+        }
141
+
134 142
         <TouchableOpacity onPress={ this.onSetTitlePress.bind(this) }>
135 143
           <Text style={styles.button}>Set Title</Text>
136 144
         </TouchableOpacity>
@@ -210,6 +218,16 @@ class FirstTabScreen extends Component {
210 218
     });
211 219
   }
212 220
 
221
+  onShowSnackbarPress() {
222
+    this.props.navigator.showSnackbar({
223
+      text: 'Counter: ' + this.props.counter.count,
224
+      actionText: 'Undo',
225
+      actionColor: '#ff0000',
226
+      actionId: 'undo',
227
+      duration: 'indefinite'
228
+    });
229
+  }
230
+
213 231
   onSetTitlePress() {
214 232
     this.props.navigator.setTitle(_.random(0, 100).toString());
215 233
   }

+ 4
- 0
src/Screen.js View File

@@ -101,6 +101,10 @@ class Navigator {
101 101
     return platformSpecific.navigatorSwitchToTab(this, params);
102 102
   }
103 103
 
104
+  showSnackbar(params = {}) {
105
+    return platformSpecific.showSnackbar(this, params);
106
+  }
107
+
104 108
   setOnNavigatorEvent(callback) {
105 109
     this.navigatorEventHandler = callback;
106 110
     if (!this.navigatorEventSubscription) {

+ 6
- 1
src/deprecated/platformSpecificDeprecated.android.js View File

@@ -418,6 +418,10 @@ function addNavigationStyleParams(screen) {
418 418
   screen.navigatorStyle = Object.assign({}, screen.navigatorStyle, Screen.navigatorStyle);
419 419
 }
420 420
 
421
+function showSnackbar(navigator, params) {
422
+  return newPlatformSpecific.showSnackbar(params);
423
+}
424
+
421 425
 export default {
422 426
   startTabBasedApp,
423 427
   startSingleScreenApp,
@@ -434,5 +438,6 @@ export default {
434 438
   navigatorSwitchToTab,
435 439
   navigatorToggleDrawer,
436 440
   navigatorToggleTabs,
437
-  navigatorToggleNavBar
441
+  navigatorToggleNavBar,
442
+  showSnackbar
438 443
 };

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

@@ -108,6 +108,10 @@ function setBottomTabBadgeByNavigatorId(navigatorId, badge) {
108 108
   NativeReactModule.setBottomTabBadgeByNavigatorId(navigatorId, badge);
109 109
 }
110 110
 
111
+function showSnackbar(params) {
112
+  NativeReactModule.showSnackbar(params);
113
+}
114
+
111 115
 module.exports = {
112 116
   startApp,
113 117
   push,
@@ -126,5 +130,6 @@ module.exports = {
126 130
   selectBottomTabByNavigatorId,
127 131
   selectBottomTabByTabIndex,
128 132
   setBottomTabBadgeByNavigatorId,
129
-  setBottomTabBadgeByIndex
133
+  setBottomTabBadgeByIndex,
134
+  showSnackbar
130 135
 };