Browse Source

Merge branch 'modal'

Guy Carmeli 8 years ago
parent
commit
53017b78c6
22 changed files with 578 additions and 71 deletions
  1. 6
    17
      android/app/src/main/java/com/reactnativenavigation/activities/BaseReactActivity.java
  2. 5
    2
      android/app/src/main/java/com/reactnativenavigation/activities/SingleScreenActivity.java
  3. 11
    19
      android/app/src/main/java/com/reactnativenavigation/activities/TabActivity.java
  4. 4
    0
      android/app/src/main/java/com/reactnativenavigation/adapters/ViewPagerAdapter.java
  5. 70
    0
      android/app/src/main/java/com/reactnativenavigation/controllers/ModalController.java
  6. 14
    12
      android/app/src/main/java/com/reactnativenavigation/core/objects/Screen.java
  7. 90
    0
      android/app/src/main/java/com/reactnativenavigation/modal/RnnModal.java
  8. 74
    7
      android/app/src/main/java/com/reactnativenavigation/modules/RctActivityModule.java
  9. 20
    0
      android/app/src/main/java/com/reactnativenavigation/utils/RefUtils.java
  10. 30
    0
      android/app/src/main/java/com/reactnativenavigation/utils/StyleHelper.java
  11. 26
    0
      android/app/src/main/java/com/reactnativenavigation/views/RctView.java
  12. 77
    0
      android/app/src/main/java/com/reactnativenavigation/views/RnnTabLayout.java
  13. 44
    3
      android/app/src/main/java/com/reactnativenavigation/views/RnnToolBar.java
  14. 18
    3
      android/app/src/main/java/com/reactnativenavigation/views/ScreenStack.java
  15. 12
    0
      android/app/src/main/res/anim/slide_down.xml
  16. 9
    0
      android/app/src/main/res/anim/slide_up.xml
  17. 25
    0
      android/app/src/main/res/layout/modal_layout.xml
  18. 1
    1
      android/app/src/main/res/layout/tab_activity.xml
  19. 10
    0
      android/app/src/main/res/values/styles.xml
  20. 12
    0
      example-redux/src/screens/FirstTabScreen.js
  21. 1
    1
      example-redux/src/screens/index.js
  22. 19
    6
      src/platformSpecific.android.js

+ 6
- 17
android/app/src/main/java/com/reactnativenavigation/activities/BaseReactActivity.java View File

@@ -29,7 +29,7 @@ import com.reactnativenavigation.core.objects.Button;
29 29
 import com.reactnativenavigation.core.objects.Screen;
30 30
 import com.reactnativenavigation.packages.RnnPackage;
31 31
 import com.reactnativenavigation.utils.ContextProvider;
32
-import com.reactnativenavigation.utils.SdkSupports;
32
+import com.reactnativenavigation.utils.StyleHelper;
33 33
 import com.reactnativenavigation.views.RnnToolBar;
34 34
 
35 35
 import java.util.Arrays;
@@ -170,24 +170,12 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
170 170
         setContentView(mReactRootView);
171 171
     }
172 172
 
173
-    public void setNavigationColors(Screen screen) {
174
-        if (screen.toolBarColor != null) {
175
-            mToolbar.setBackgroundColor(screen.toolBarColor);
173
+    public void setNavigationStyle(Screen screen) {
174
+        if (mToolbar != null) {
175
+            mToolbar.setStyle(screen);
176 176
         }
177 177
 
178
-        if (screen.titleColor != null) {
179
-            mToolbar.setTitleTextColor(screen.titleColor);
180
-        }
181
-
182
-        if (SdkSupports.lollipop()) {
183
-            if (screen.statusBarColor != null) {
184
-                getWindow().setStatusBarColor(screen.statusBarColor);
185
-            }
186
-
187
-            if (screen.navigationBarColor != null) {
188
-                getWindow().setNavigationBarColor(screen.navigationBarColor);
189
-            }
190
-        }
178
+        StyleHelper.setWindowStyle(getWindow(), this, screen);
191 179
     }
192 180
 
193 181
     @Override
@@ -227,6 +215,7 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
227 215
 
228 216
     @CallSuper
229 217
     public void push(Screen screen) {
218
+        setNavigationStyle(screen);
230 219
         if (mToolbar != null &&
231 220
             getCurrentNavigatorId().equals(screen.navigatorId) &&
232 221
             getScreenStackSize() >= 1) {

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

@@ -36,7 +36,7 @@ public class SingleScreenActivity extends BaseReactActivity {
36 36
     }
37 37
 
38 38
     protected void setupToolbar(Screen screen) {
39
-        setNavigationColors(screen);
39
+        setNavigationStyle(screen);
40 40
         mToolbar.setTitle(screen.title);
41 41
         setSupportActionBar(mToolbar);
42 42
     }
@@ -44,13 +44,16 @@ public class SingleScreenActivity extends BaseReactActivity {
44 44
     @Override
45 45
     public void push(Screen screen) {
46 46
         super.push(screen);
47
+        setNavigationStyle(screen);
47 48
         mScreenStack.push(screen);
48 49
     }
49 50
 
50 51
     @Override
51 52
     public Screen pop(String navigatorId) {
52 53
         super.pop(navigatorId);
53
-        return mScreenStack.pop();
54
+        Screen screen = mScreenStack.pop();
55
+        setNavigationStyle(screen);
56
+        return screen;
54 57
     }
55 58
 
56 59
     @Override

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

@@ -1,6 +1,5 @@
1 1
 package com.reactnativenavigation.activities;
2 2
 
3
-import android.support.design.widget.TabLayout;
4 3
 import android.support.v4.view.ViewPager;
5 4
 import android.view.Menu;
6 5
 
@@ -8,6 +7,7 @@ import com.reactnativenavigation.R;
8 7
 import com.reactnativenavigation.adapters.ViewPagerAdapter;
9 8
 import com.reactnativenavigation.core.RctManager;
10 9
 import com.reactnativenavigation.core.objects.Screen;
10
+import com.reactnativenavigation.views.RnnTabLayout;
11 11
 import com.reactnativenavigation.views.RnnToolBar;
12 12
 
13 13
 import java.util.ArrayList;
@@ -18,7 +18,7 @@ import java.util.ArrayList;
18 18
 public class TabActivity extends BaseReactActivity {
19 19
     public static final String EXTRA_SCREENS = "extraScreens";
20 20
 
21
-    private TabLayout mTabLayout;
21
+    private RnnTabLayout mTabLayout;
22 22
     private ViewPager mViewPager;
23 23
     private ViewPagerAdapter mAdapter;
24 24
 
@@ -28,7 +28,7 @@ public class TabActivity extends BaseReactActivity {
28 28
 
29 29
         setContentView(R.layout.tab_activity);
30 30
         mToolbar = (RnnToolBar) findViewById(R.id.toolbar);
31
-        mTabLayout = (TabLayout) findViewById(R.id.tabLayout);
31
+        mTabLayout = (RnnTabLayout) findViewById(R.id.tabLayout);
32 32
         mViewPager = (ViewPager) findViewById(R.id.viewPager);
33 33
 
34 34
         ArrayList<Screen> screens = (ArrayList<Screen>) getIntent().getSerializableExtra(EXTRA_SCREENS);
@@ -39,26 +39,16 @@ public class TabActivity extends BaseReactActivity {
39 39
 
40 40
     private void setupToolbar(ArrayList<Screen> screens) {
41 41
         Screen initialScreen = screens.get(0);
42
-        setNavigationColors(initialScreen);
42
+        setNavigationStyle(initialScreen);
43 43
         mToolbar.setScreens(screens);
44
-        mToolbar.setTitle(initialScreen.title == null ? "" : initialScreen.title);
44
+        mToolbar.setTitle(initialScreen.title);
45 45
         setSupportActionBar(mToolbar);
46 46
     }
47 47
 
48 48
     @Override
49
-    public void setNavigationColors(Screen screen) {
50
-        super.setNavigationColors(screen);
51
-        if (screen.toolBarColor != null) {
52
-            mTabLayout.setBackgroundColor(screen.toolBarColor);
53
-        }
54
-
55
-        if (screen.tabNormalTextColor != null && screen.tabSelectedTextColor != null) {
56
-            mTabLayout.setTabTextColors(screen.tabNormalTextColor, screen.tabSelectedTextColor);
57
-        }
58
-
59
-        if (screen.tabIndicatorColor != null) {
60
-            mTabLayout.setSelectedTabIndicatorColor(screen.tabIndicatorColor);
61
-        }
49
+    public void setNavigationStyle(Screen screen) {
50
+        super.setNavigationStyle(screen);
51
+        mTabLayout.setStyle(screen);
62 52
     }
63 53
 
64 54
     private void setupViewPager(ArrayList<Screen> screens) {
@@ -85,7 +75,9 @@ public class TabActivity extends BaseReactActivity {
85 75
     @Override
86 76
     public Screen pop(String navigatorId) {
87 77
         super.pop(navigatorId);
88
-        return mAdapter.pop(navigatorId);
78
+        Screen screen = mAdapter.pop(navigatorId);
79
+        setNavigationStyle(screen);
80
+        return screen;
89 81
     }
90 82
 
91 83
     @Override

+ 4
- 0
android/app/src/main/java/com/reactnativenavigation/adapters/ViewPagerAdapter.java View File

@@ -11,6 +11,7 @@ import com.facebook.react.bridge.WritableMap;
11 11
 import com.reactnativenavigation.activities.BaseReactActivity;
12 12
 import com.reactnativenavigation.core.RctManager;
13 13
 import com.reactnativenavigation.core.objects.Screen;
14
+import com.reactnativenavigation.utils.ContextProvider;
14 15
 import com.reactnativenavigation.views.RnnToolBar;
15 16
 import com.reactnativenavigation.views.ScreenStack;
16 17
 
@@ -109,6 +110,9 @@ public class ViewPagerAdapter extends PagerAdapter implements TabLayout.OnTabSel
109 110
         // Set title
110 111
         mToolbar.setTitle(newScreen.title == null ? "" : newScreen.title);
111 112
 
113
+        // Set navigation color
114
+        ContextProvider.getActivityContext().setNavigationStyle(newScreen);
115
+
112 116
         // Send tab selected event
113 117
         WritableMap params = Arguments.createMap();
114 118
         Screen screen = mScreenStacks.get(position).peek();

+ 70
- 0
android/app/src/main/java/com/reactnativenavigation/controllers/ModalController.java View File

@@ -0,0 +1,70 @@
1
+package com.reactnativenavigation.controllers;
2
+
3
+import android.support.annotation.Nullable;
4
+
5
+import com.reactnativenavigation.modal.RnnModal;
6
+import com.reactnativenavigation.utils.RefUtils;
7
+
8
+import java.lang.ref.WeakReference;
9
+import java.util.HashMap;
10
+import java.util.Iterator;
11
+import java.util.Map;
12
+
13
+/**
14
+ * Created by guyc on 06/05/16.
15
+ */
16
+public class ModalController {
17
+    private static ModalController sInstance;
18
+
19
+    private final Map<String, WeakReference<RnnModal>> mModals;
20
+
21
+    private ModalController() {
22
+        mModals = new HashMap<>();
23
+    }
24
+
25
+    public static synchronized ModalController getInstance() {
26
+        if (sInstance == null) {
27
+            sInstance = new ModalController();
28
+        }
29
+
30
+        return sInstance;
31
+    }
32
+
33
+    public void add(RnnModal modal, String navigatorId) {
34
+        mModals.put(navigatorId, new WeakReference<>(modal));
35
+    }
36
+
37
+    public boolean isModalDisplayed() {
38
+        return mModals.size() != 0;
39
+    }
40
+
41
+    public boolean isModalDisplayed(String navigatorId) {
42
+        return mModals.size() != 0 && mModals.containsKey(navigatorId);
43
+    }
44
+
45
+    @Nullable
46
+    public RnnModal get(String navigatorId) {
47
+        if (mModals.containsKey(navigatorId)) {
48
+            return RefUtils.get(mModals.get(navigatorId));
49
+        }
50
+
51
+        return null;
52
+    }
53
+
54
+    public void remove(String navigatorId) {
55
+        if (mModals.containsKey(navigatorId)) {
56
+            mModals.remove(navigatorId);
57
+        }
58
+    }
59
+
60
+    public void dismissAllModals() {
61
+        Iterator<String> iterator = mModals.keySet().iterator();
62
+        while (iterator.hasNext()) {
63
+            WeakReference<RnnModal> ref = mModals.get(iterator.next());
64
+            RnnModal modal = RefUtils.get(ref);
65
+            if (modal != null) {
66
+                modal.dismiss();
67
+            }
68
+        }
69
+    }
70
+}

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

@@ -36,14 +36,14 @@ public class Screen extends JsonObject implements Serializable {
36 36
     private static final String KEY_TAB_SELECTED_TEXT_COLOR = "tabSelectedTextColor";
37 37
     private static final String KEY_TAB_INDICATOR_COLOR = "tabIndicatorColor";
38 38
 
39
-    public String title;
40
-    public String label;
41
-    public String screenId;
42
-    public String screenInstanceId;
43
-    public String navigatorId;
44
-    public String navigatorEventId;
45
-    public int icon;
46
-    public ArrayList<Button> buttons;
39
+    public final String title;
40
+    public final String label;
41
+    public final String screenId;
42
+    public final String screenInstanceId;
43
+    public final String navigatorId;
44
+    public final String navigatorEventId;
45
+    public final int icon;
46
+    public final ArrayList<Button> buttons;
47 47
 
48 48
     // Navigation styling
49 49
     @Nullable @ColorInt public Integer toolBarColor;
@@ -69,18 +69,20 @@ public class Screen extends JsonObject implements Serializable {
69 69
         navigatorEventId = getString(screen, KEY_NAVIGATOR_EVENT_ID);
70 70
         icon = getInt(screen, KEY_ICON);
71 71
 
72
-        setButtons(screen);
72
+        buttons = getButtons(screen);
73 73
         setToolbarStyle(screen);
74 74
     }
75 75
 
76
-    private void setButtons(ReadableMap screen) {
76
+    private ArrayList<Button> getButtons(ReadableMap screen) {
77
+        ArrayList<Button> ret = null;
77 78
         if (screen.hasKey(KEY_RIGHT_BUTTONS)) {
78
-            buttons = new ArrayList<>();
79
+            ret = new ArrayList<>();
79 80
             ReadableArray rightButtons = screen.getArray(KEY_RIGHT_BUTTONS);
80 81
             for (int i = 0; i < rightButtons.size(); i++) {
81
-                buttons.add(new Button(rightButtons.getMap(i)));
82
+                ret.add(new Button(rightButtons.getMap(i)));
82 83
             }
83 84
         }
85
+        return ret;
84 86
     }
85 87
 
86 88
     public void setToolbarStyle(ReadableMap screen) {

+ 90
- 0
android/app/src/main/java/com/reactnativenavigation/modal/RnnModal.java View File

@@ -0,0 +1,90 @@
1
+package com.reactnativenavigation.modal;
2
+
3
+import android.annotation.SuppressLint;
4
+import android.app.Dialog;
5
+import android.content.Context;
6
+import android.content.DialogInterface;
7
+import android.view.LayoutInflater;
8
+import android.view.View;
9
+import android.view.Window;
10
+import android.view.WindowManager;
11
+import android.view.animation.Animation;
12
+import android.view.animation.AnimationUtils;
13
+
14
+import com.reactnativenavigation.R;
15
+import com.reactnativenavigation.activities.BaseReactActivity;
16
+import com.reactnativenavigation.controllers.ModalController;
17
+import com.reactnativenavigation.core.objects.Screen;
18
+import com.reactnativenavigation.utils.SdkSupports;
19
+import com.reactnativenavigation.utils.StyleHelper;
20
+import com.reactnativenavigation.views.RctView;
21
+import com.reactnativenavigation.views.RnnToolBar;
22
+import com.reactnativenavigation.views.ScreenStack;
23
+
24
+/**
25
+ * Created by guyc on 02/05/16.
26
+ */
27
+public class RnnModal extends Dialog implements DialogInterface.OnDismissListener {
28
+
29
+    private ScreenStack mScreenStack;
30
+    private View mContentView;
31
+    private Screen mScreen;
32
+
33
+    public RnnModal(BaseReactActivity context, Screen screen) {
34
+        super(context, R.style.Modal);
35
+        mScreen = screen;
36
+        ModalController.getInstance().add(this, screen.navigatorId);
37
+        init(context);
38
+    }
39
+
40
+    @SuppressLint("InflateParams")
41
+    private void init(final Context context) {
42
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
43
+        mContentView = LayoutInflater.from(context).inflate(R.layout.modal_layout, null, false);
44
+        RnnToolBar toolBar = (RnnToolBar) mContentView.findViewById(R.id.toolbar);
45
+        mScreenStack = (ScreenStack) mContentView.findViewById(R.id.screenStack);
46
+
47
+        setContentView(mContentView);
48
+        toolBar.setStyle(mScreen);
49
+        toolBar.setTitle(mScreen.title);
50
+        toolBar.setupToolbarButtonsAsync(mScreen);
51
+        mScreenStack.push(mScreen, new RctView.OnDisplayedListener() {
52
+            @Override
53
+            public void onDisplayed() {
54
+                Animation animation = AnimationUtils.loadAnimation(context, R.anim.slide_up);
55
+                mContentView.setAnimation(animation);
56
+                mContentView.animate();
57
+            }
58
+        });
59
+
60
+        // Set navigation colors
61
+        if (SdkSupports.lollipop()) {
62
+            Window window = getWindow();
63
+            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
64
+            StyleHelper.setWindowStyle(window, context.getApplicationContext(), mScreen);
65
+        }
66
+    }
67
+
68
+    public void push(Screen screen) {
69
+        mScreenStack.push(screen);
70
+    }
71
+
72
+    public Screen pop() {
73
+        return mScreenStack.pop();
74
+    }
75
+
76
+    @Override
77
+    public void onBackPressed() {
78
+        if (mScreenStack.getStackSize() > 1) {
79
+            mScreenStack.pop();
80
+        } else {
81
+            ModalController.getInstance().remove(mScreen.navigatorId);
82
+            super.onBackPressed();
83
+        }
84
+    }
85
+
86
+    @Override
87
+    public void onDismiss(DialogInterface dialog) {
88
+        ModalController.getInstance().remove(mScreen.navigatorId);
89
+    }
90
+}

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

@@ -12,7 +12,9 @@ import com.facebook.react.bridge.ReadableMap;
12 12
 import com.reactnativenavigation.activities.BaseReactActivity;
13 13
 import com.reactnativenavigation.activities.SingleScreenActivity;
14 14
 import com.reactnativenavigation.activities.TabActivity;
15
+import com.reactnativenavigation.controllers.ModalController;
15 16
 import com.reactnativenavigation.core.objects.Screen;
17
+import com.reactnativenavigation.modal.RnnModal;
16 18
 import com.reactnativenavigation.utils.ContextProvider;
17 19
 
18 20
 import java.util.ArrayList;
@@ -71,29 +73,94 @@ public class RctActivityModule extends ReactContextBaseJavaModule {
71 73
     }
72 74
 
73 75
     @ReactMethod
74
-    public void navigatorPush(final ReadableMap screen) {
76
+    public void navigatorPush(final ReadableMap skreen) {
77
+        final Screen screen = new Screen(skreen);
75 78
         final BaseReactActivity context = ContextProvider.getActivityContext();
76
-         if (context != null && !context.isFinishing()) {
77
-             context.runOnUiThread(new Runnable() {
79
+        if (context == null || context.isFinishing()) {
80
+            return;
81
+        }
82
+
83
+        // First, check is the screen should be displayed in a Modal
84
+        ModalController modalController = ModalController.getInstance();
85
+        if (modalController.isModalDisplayed(screen.navigatorId)) {
86
+            final RnnModal modal = modalController.get(screen.navigatorId);
87
+            if (modal != null) {
88
+                context.runOnUiThread(new Runnable() {
89
+                    @Override
90
+                    public void run() {
91
+                        modal.push(screen);
92
+                    }
93
+                });
94
+            }
95
+            return;
96
+        }
97
+
98
+        // No Modal is displayed, Push to activity
99
+         context.runOnUiThread(new Runnable() {
78 100
                  @Override
79 101
                  public void run() {
80
-                     context.push(new Screen(screen));
102
+                     context.push(screen);
81 103
                  }
82 104
              });
83
-        }
84 105
     }
85 106
 
86 107
     @ReactMethod
87 108
     public void navigatorPop(final ReadableMap navigator) {
88
-        final String navID = navigator.getString("navigatorID");
109
+        final String navigatorId = navigator.getString("navigatorID");
110
+        final BaseReactActivity context = ContextProvider.getActivityContext();
111
+        if (context == null || context.isFinishing()) {
112
+            return;
113
+        }
114
+
115
+        // First, check if the screen should be popped from a Modal
116
+        ModalController modalController = ModalController.getInstance();
117
+        if (modalController.isModalDisplayed(navigatorId)) {
118
+            final RnnModal modal = modalController.get(navigatorId);
119
+            if (modal != null) {
120
+                context.runOnUiThread(new Runnable() {
121
+                    @Override
122
+                    public void run() {
123
+                        modal.pop();
124
+                    }
125
+                });
126
+            }
127
+            return;
128
+        }
129
+
130
+        context.runOnUiThread(new Runnable() {
131
+            @Override
132
+            public void run() {
133
+                context.pop(navigatorId);
134
+            }
135
+        });
136
+    }
137
+
138
+    @ReactMethod
139
+    public void showModal(final ReadableMap screen) {
89 140
         final BaseReactActivity context = ContextProvider.getActivityContext();
90 141
         if (context != null && !context.isFinishing()) {
91 142
             context.runOnUiThread(new Runnable() {
92 143
                 @Override
93 144
                 public void run() {
94
-                    context.pop(navID);
145
+                    new RnnModal(context, new Screen(screen)).show();
95 146
                 }
96 147
             });
97 148
         }
98 149
     }
150
+
151
+    @ReactMethod
152
+    public void dismissAllModals(final ReadableMap params) {
153
+        final BaseReactActivity context = ContextProvider.getActivityContext();
154
+        if (context != null && !context.isFinishing()) {
155
+        context.runOnUiThread(new Runnable() {
156
+            @Override
157
+            public void run() {
158
+                ModalController modalController = ModalController.getInstance();
159
+                if (modalController.isModalDisplayed()) {
160
+                    modalController.dismissAllModals();
161
+                }
162
+            }
163
+        });
164
+        }
165
+    }
99 166
 }

+ 20
- 0
android/app/src/main/java/com/reactnativenavigation/utils/RefUtils.java View File

@@ -0,0 +1,20 @@
1
+package com.reactnativenavigation.utils;
2
+
3
+import java.lang.ref.WeakReference;
4
+
5
+/**
6
+ * Created by guyc on 06/05/16.
7
+ */
8
+public class RefUtils {
9
+    /**
10
+     * Extract the object within a WeakReference object
11
+     * @param wr the WeakReference to extract
12
+     * @return the object within the WR or null when object not available.
13
+     */
14
+    public static <T> T get(WeakReference<T> wr) {
15
+        if (wr != null) {
16
+            return wr.get();
17
+        }
18
+        return null;
19
+    }
20
+}

+ 30
- 0
android/app/src/main/java/com/reactnativenavigation/utils/StyleHelper.java View File

@@ -0,0 +1,30 @@
1
+package com.reactnativenavigation.utils;
2
+
3
+import android.content.Context;
4
+import android.support.v4.content.ContextCompat;
5
+import android.view.Window;
6
+
7
+import com.reactnativenavigation.core.objects.Screen;
8
+
9
+/**
10
+ * Created by guyc on 07/05/16.
11
+ */
12
+public class StyleHelper {
13
+    public static void setWindowStyle(Window window, Context context, Screen screen) {
14
+        if (SdkSupports.lollipop()) {
15
+            final int black = ContextCompat.getColor(context, android.R.color.black);
16
+            if (screen.statusBarColor != null) {
17
+                window.setStatusBarColor(screen.statusBarColor);
18
+            } else {
19
+                window.setStatusBarColor(black);
20
+            }
21
+
22
+            if (screen.navigationBarColor != null) {
23
+                window.setNavigationBarColor(screen.navigationBarColor);
24
+            } else {
25
+                window.setNavigationBarColor(black);
26
+            }
27
+        }
28
+
29
+    }
30
+}

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

@@ -1,6 +1,7 @@
1 1
 package com.reactnativenavigation.views;
2 2
 
3 3
 import android.os.Bundle;
4
+import android.view.ViewTreeObserver;
4 5
 import android.widget.FrameLayout;
5 6
 
6 7
 import com.facebook.react.ReactInstanceManager;
@@ -15,11 +16,26 @@ public class RctView extends FrameLayout {
15 16
 
16 17
     private ReactRootView mReactRootView;
17 18
 
19
+    /**
20
+     * Interface used to run some code when the {@link ReactRootView} is visible.
21
+     */
22
+    public interface OnDisplayedListener {
23
+        /**
24
+         * This method will be invoked when the {@link ReactRootView} is visible.
25
+         */
26
+        public void onDisplayed();
27
+    }
28
+
18 29
     public ReactRootView getReactRootView() {
19 30
         return mReactRootView;
20 31
     }
21 32
 
22 33
     public RctView(BaseReactActivity ctx, ReactInstanceManager rctInstanceManager, Screen screen) {
34
+        this(ctx, rctInstanceManager, screen, null);
35
+    }
36
+
37
+    public RctView(BaseReactActivity ctx, ReactInstanceManager rctInstanceManager, Screen screen,
38
+                   final OnDisplayedListener onDisplayedListener) {
23 39
         super(ctx);
24 40
         setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
25 41
 
@@ -34,6 +50,16 @@ public class RctView extends FrameLayout {
34 50
 
35 51
         mReactRootView.startReactApplication(rctInstanceManager, componentName, passProps);
36 52
 
53
+        if (onDisplayedListener != null) {
54
+            mReactRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
55
+                @Override
56
+                public void onGlobalLayout() {
57
+                    onDisplayedListener.onDisplayed();
58
+                    mReactRootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
59
+                }
60
+            });
61
+        }
62
+
37 63
         addView(mReactRootView);
38 64
     }
39 65
 }

+ 77
- 0
android/app/src/main/java/com/reactnativenavigation/views/RnnTabLayout.java View File

@@ -0,0 +1,77 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.content.Context;
4
+import android.content.res.ColorStateList;
5
+import android.content.res.TypedArray;
6
+import android.graphics.drawable.Drawable;
7
+import android.support.design.widget.TabLayout;
8
+import android.util.AttributeSet;
9
+import android.util.TypedValue;
10
+
11
+import com.reactnativenavigation.R;
12
+import com.reactnativenavigation.core.objects.Screen;
13
+
14
+/**
15
+ * Created by guyc on 07/05/16.
16
+ */
17
+public class RnnTabLayout extends TabLayout {
18
+    private Drawable mBackground;
19
+    private ColorStateList mTabTextColors;
20
+    private int mSelectedTabIndicatorColor;
21
+
22
+    public RnnTabLayout(Context context) {
23
+        this(context, null);
24
+    }
25
+
26
+    public RnnTabLayout(Context context, AttributeSet attrs) {
27
+        this(context, attrs, 0);
28
+    }
29
+
30
+    public RnnTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
31
+        super(context, attrs, defStyleAttr);
32
+        init(context);
33
+    }
34
+
35
+    private void init(Context ctx) {
36
+        mBackground = getBackground();
37
+        mTabTextColors = getTabTextColors();
38
+
39
+        // Get default accent color which is used as the selected tab indicator color
40
+        TypedValue typedValue = new TypedValue();
41
+        TypedArray a = ctx.obtainStyledAttributes(typedValue.data, new int[]{R.attr.colorAccent});
42
+        mSelectedTabIndicatorColor = a.getColor(0, 0);
43
+        a.recycle();
44
+    }
45
+
46
+    public void setStyle(Screen screen) {
47
+        if (screen.toolBarColor != null) {
48
+            setBackgroundColor(screen.toolBarColor);
49
+        } else {
50
+            resetBackground();
51
+        }
52
+
53
+        if (screen.tabNormalTextColor != null && screen.tabSelectedTextColor != null) {
54
+            setTabTextColors(screen.tabNormalTextColor, screen.tabSelectedTextColor);
55
+        } else {
56
+            resetTextColors();
57
+        }
58
+
59
+        if (screen.tabIndicatorColor != null) {
60
+            setSelectedTabIndicatorColor(screen.tabIndicatorColor);
61
+        } else {
62
+            resetSelectedTabIndicatorColor();
63
+        }
64
+    }
65
+
66
+    public void resetBackground() {
67
+        setBackground(mBackground);
68
+    }
69
+
70
+    public void resetTextColors() {
71
+        setTabTextColors(mTabTextColors);
72
+    }
73
+
74
+    public void resetSelectedTabIndicatorColor() {
75
+        setSelectedTabIndicatorColor(mSelectedTabIndicatorColor);
76
+    }
77
+}

+ 44
- 3
android/app/src/main/java/com/reactnativenavigation/views/RnnToolBar.java View File

@@ -5,6 +5,7 @@ import android.content.Context;
5 5
 import android.content.res.Resources;
6 6
 import android.graphics.drawable.Drawable;
7 7
 import android.os.AsyncTask;
8
+import android.support.v4.content.ContextCompat;
8 9
 import android.support.v4.content.res.ResourcesCompat;
9 10
 import android.support.v7.app.ActionBar;
10 11
 import android.support.v7.widget.Toolbar;
@@ -32,27 +33,62 @@ public class RnnToolBar extends Toolbar {
32 33
 
33 34
     private List<Screen> mScreens;
34 35
     private AsyncTask mSetupToolbarTask;
36
+    private Drawable mBackground;
35 37
 
36 38
     public RnnToolBar(Context context) {
37 39
         super(context);
40
+        init();
38 41
     }
39 42
 
40 43
     public RnnToolBar(Context context, AttributeSet attrs) {
41 44
         super(context, attrs);
45
+        init();
42 46
     }
43 47
 
44 48
     public RnnToolBar(Context context, AttributeSet attrs, int defStyleAttr) {
45 49
         super(context, attrs, defStyleAttr);
50
+        init();
51
+    }
52
+
53
+    private void init() {
54
+        mBackground = getBackground();
46 55
     }
47 56
 
48 57
     public void setScreens(List<Screen> screens) {
49 58
         mScreens = screens;
50 59
     }
51 60
 
61
+    public void setStyle(Screen screen) {
62
+        if (screen.toolBarColor != null) {
63
+            setBackgroundColor(screen.toolBarColor);
64
+        } else {
65
+            resetBackground();
66
+        }
67
+
68
+        if (screen.titleColor != null) {
69
+            setTitleTextColor(screen.titleColor);
70
+        } else {
71
+            resetTitleTextColor();
72
+        }
73
+    }
74
+
75
+    private void resetBackground() {
76
+        setBackground(mBackground);
77
+    }
78
+
79
+    private void resetTitleTextColor() {
80
+        setTitleTextColor(ContextCompat.getColor(getContext(), android.R.color.primary_text_light));
81
+    }
82
+
52 83
     public void handleOnCreateOptionsMenuAsync() {
53 84
         setupToolbarButtonsAsync(null, mScreens.get(0));
54 85
     }
55 86
 
87
+    public void setupToolbarButtonsAsync(Screen newScreen) {
88
+        this.setupToolbarButtonsAsync(null, newScreen);
89
+    }
90
+
91
+
56 92
     public void setupToolbarButtonsAsync(Screen oldScreen, Screen newScreen) {
57 93
         if (mSetupToolbarTask == null) {
58 94
             mSetupToolbarTask = new SetupToolbarButtonsTask(this, oldScreen, newScreen).execute();
@@ -60,10 +96,16 @@ public class RnnToolBar extends Toolbar {
60 96
     }
61 97
 
62 98
     @SuppressWarnings({"ConstantConditions"})
63
-    @SuppressLint("PrivateResource")
64 99
     public void showBackButton(Screen screen) {
65 100
         ActionBar actionBar = ContextProvider.getActivityContext().getSupportActionBar();
101
+        Drawable backButton = setupBackButton(screen);
102
+        actionBar.setHomeAsUpIndicator(backButton);
103
+        actionBar.setDisplayHomeAsUpEnabled(true);
104
+    }
66 105
 
106
+    @SuppressLint("PrivateResource")
107
+    @SuppressWarnings({"ConstantConditions"})
108
+    private Drawable setupBackButton(Screen screen) {
67 109
         Resources resources = getResources();
68 110
         final Drawable backButton;
69 111
         if (screen.buttonsTintColor != null) {
@@ -76,8 +118,7 @@ public class RnnToolBar extends Toolbar {
76 118
                     R.drawable.abc_ic_ab_back_mtrl_am_alpha,
77 119
                     ContextProvider.getActivityContext().getTheme());
78 120
         }
79
-        actionBar.setHomeAsUpIndicator(backButton);
80
-        actionBar.setDisplayHomeAsUpEnabled(true);
121
+        return backButton;
81 122
     }
82 123
 
83 124
     @SuppressWarnings({"ConstantConditions"})

+ 18
- 3
android/app/src/main/java/com/reactnativenavigation/views/ScreenStack.java View File

@@ -1,6 +1,8 @@
1 1
 package com.reactnativenavigation.views;
2 2
 
3 3
 import android.animation.LayoutTransition;
4
+import android.content.Context;
5
+import android.util.AttributeSet;
4 6
 import android.widget.FrameLayout;
5 7
 
6 8
 import com.facebook.react.ReactInstanceManager;
@@ -29,20 +31,33 @@ public class ScreenStack extends FrameLayout {
29 31
     private final Stack<ScreenView> mStack = new Stack<>();
30 32
     private final ReactInstanceManager mReactInstanceManager =
31 33
             RctManager.getInstance().getReactInstanceManager();
32
-    private final BaseReactActivity mReactActivity;
34
+    private BaseReactActivity mReactActivity;
33 35
 
34 36
     public ScreenStack(BaseReactActivity context) {
35 37
         super(context);
36
-        mReactActivity = context;
38
+        init(context);
39
+    }
40
+
41
+    public ScreenStack(Context context, AttributeSet attrs) {
42
+        super(context, attrs);
43
+        init(context);
44
+    }
45
+
46
+    private void init(Context context) {
47
+        mReactActivity = (BaseReactActivity) context;
37 48
         setLayoutTransition(new LayoutTransition());
38 49
     }
39 50
 
40 51
     public void push(Screen screen) {
52
+        push(screen, null);
53
+    }
54
+
55
+    public void push(Screen screen, RctView.OnDisplayedListener onDisplayed) {
41 56
         RctView oldView = null;
42 57
         if (!mStack.isEmpty()) {
43 58
             oldView = mStack.peek().view;
44 59
         }
45
-        RctView view = new RctView(mReactActivity, mReactInstanceManager, screen);
60
+        RctView view = new RctView(mReactActivity, mReactInstanceManager, screen, onDisplayed);
46 61
         addView(view, MATCH_PARENT, MATCH_PARENT);
47 62
         if (oldView != null) {
48 63
             ReactRootView reactRootView = oldView.getReactRootView();

+ 12
- 0
android/app/src/main/res/anim/slide_down.xml View File

@@ -0,0 +1,12 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<set xmlns:android="http://schemas.android.com/apk/res/android"
3
+    android:interpolator="@android:anim/accelerate_interpolator"
4
+    android:shareInterpolator="true"
5
+    android:duration="190">
6
+    <translate
7
+        android:fromYDelta="0"
8
+        android:toYDelta="100%"/>
9
+    <alpha
10
+        android:fromAlpha="1"
11
+        android:toAlpha="0"/>
12
+</set>

+ 9
- 0
android/app/src/main/res/anim/slide_up.xml View File

@@ -0,0 +1,9 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<set xmlns:android="http://schemas.android.com/apk/res/android"
3
+    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
4
+    android:shareInterpolator="true">
5
+    <translate
6
+        android:fromYDelta="100%"
7
+        android:toYDelta="0"
8
+        android:duration="250"/>
9
+</set>

+ 25
- 0
android/app/src/main/res/layout/modal_layout.xml View File

@@ -0,0 +1,25 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+    xmlns:app="http://schemas.android.com/apk/res-auto"
4
+    android:background="@android:color/transparent"
5
+    android:orientation="vertical"
6
+    android:layout_width="match_parent"
7
+    android:layout_height="match_parent">
8
+
9
+    <android.support.design.widget.AppBarLayout
10
+        android:id="@+id/appbar"
11
+        android:layout_width="match_parent"
12
+        android:layout_height="wrap_content"
13
+        android:fitsSystemWindows="true">
14
+        <com.reactnativenavigation.views.RnnToolBar
15
+            android:id="@+id/toolbar"
16
+            android:layout_width="match_parent"
17
+            android:layout_height="?attr/actionBarSize"
18
+            app:layout_scrollFlags="scroll|enterAlways"/>
19
+    </android.support.design.widget.AppBarLayout>
20
+
21
+    <com.reactnativenavigation.views.ScreenStack
22
+        android:id="@+id/screenStack"
23
+        android:layout_width="match_parent"
24
+        android:layout_height="match_parent"/>
25
+</LinearLayout>

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

@@ -17,7 +17,7 @@
17 17
             android:layout_width="match_parent"
18 18
             android:layout_height="?attr/actionBarSize"
19 19
             app:layout_scrollFlags="scroll|enterAlways"/>
20
-        <android.support.design.widget.TabLayout
20
+        <com.reactnativenavigation.views.RnnTabLayout
21 21
             android:id="@+id/tabLayout"
22 22
             android:layout_width="match_parent"
23 23
             android:layout_height="?attr/actionBarSize"

+ 10
- 0
android/app/src/main/res/values/styles.xml View File

@@ -0,0 +1,10 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<resources>
3
+    <style name="Modal" parent="@android:style/Theme.Translucent.NoTitleBar">
4
+        <item name="android:windowAnimationStyle">@style/modalAnimations</item>
5
+    </style>
6
+
7
+    <style name="modalAnimations">
8
+        <item name="android:windowExitAnimation">@anim/slide_down</item>
9
+    </style>
10
+</resources>

+ 12
- 0
example-redux/src/screens/FirstTabScreen.js View File

@@ -72,18 +72,30 @@ class FirstTabScreen extends Component {
72 72
           <Text style={styles.button}>Push Screen</Text>
73 73
         </TouchableOpacity>
74 74
 
75
+        <TouchableOpacity onPress={ this.onShowModalPress.bind(this) }>
76
+          <Text style={styles.button}>Modal Screen</Text>
77
+        </TouchableOpacity>
75 78
       </View>
76 79
     );
77 80
   }
81
+
78 82
   onIncrementPress() {
79 83
     this.props.dispatch(counterActions.increment());
80 84
   }
85
+
81 86
   onPushPress() {
82 87
     this.props.navigator.push({
83 88
       title: "More",
84 89
       screen: "example.PushedScreen"
85 90
     });
86 91
   }
92
+
93
+  onShowModalPress() {
94
+    this.props.navigator.showModal({
95
+      title: "Modal Screen",
96
+      screen: "example.PushedScreen"
97
+    });
98
+  }
87 99
 }
88 100
 
89 101
 const styles = StyleSheet.create({

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

@@ -1,4 +1,4 @@
1
-import { Navigation } from 'react-native-navigation';
1
+import {Navigation} from 'react-native-navigation';
2 2
 
3 3
 import LoginScreen from './LoginScreen';
4 4
 import FirstTabScreen from './FirstTabScreen';

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

@@ -21,7 +21,7 @@ function startSingleScreenApp(params) {
21 21
 
22 22
   addNavigatorParams(screen);
23 23
   addNavigatorButtons(screen);
24
-  addToolbarStyleParams(screen);
24
+  addNavigationStyleParams(screen);
25 25
   RctActivity.startSingleScreenApp(screen);
26 26
 }
27 27
 
@@ -34,7 +34,7 @@ function startTabBasedApp(params) {
34 34
   params.tabs.forEach(function (tab, idx) {
35 35
     addNavigatorParams(tab, null, idx)
36 36
     addNavigatorButtons(tab);
37
-    addToolbarStyleParams(tab);
37
+    addNavigationStyleParams(tab);
38 38
   });
39 39
 
40 40
   RctActivity.startTabBasedApp(params.tabs);
@@ -43,7 +43,7 @@ function startTabBasedApp(params) {
43 43
 function navigatorPush(navigator, params) {
44 44
   addNavigatorParams(params, navigator)
45 45
   addNavigatorButtons(params);
46
-  addToolbarStyleParams(params);
46
+  addNavigationStyleParams(params);
47 47
   RctActivity.navigatorPush(params);
48 48
 }
49 49
 
@@ -51,6 +51,17 @@ function navigatorPop(navigator, params) {
51 51
   RctActivity.navigatorPop(navigator);
52 52
 }
53 53
 
54
+function showModal(params) {
55
+  addNavigatorParams(params);
56
+  addNavigatorButtons(params);
57
+  addNavigationStyleParams(params);
58
+  RctActivity.showModal(params);
59
+}
60
+
61
+function dismissAllModals(params) {
62
+  RctActivity.dismissAllModals(params.animationType);
63
+}
64
+
54 65
 function addNavigatorParams(screen, navigator = null, idx = '') {
55 66
   screen.navigatorID = navigator ? navigator.navigatorID : utils.getRandomId() + '_nav' + idx;
56 67
   screen.screenInstanceID = utils.getRandomId();
@@ -74,14 +85,16 @@ function addNavigatorButtons(screen) {
74 85
   }
75 86
 }
76 87
 
77
-function addToolbarStyleParams(screen) {
88
+function addNavigationStyleParams(screen) {
78 89
   const Screen = Navigation.getRegisteredScreen(screen.screen);
79 90
   screen.navigatorStyle = Screen.navigatorStyle;
80 91
 }
81 92
 
82 93
 export default {
83
-  startSingleScreenApp,
84 94
   startTabBasedApp,
95
+  startSingleScreenApp,
85 96
   navigatorPush,
86
-  navigatorPop
97
+  navigatorPop,
98
+  showModal,
99
+  dismissAllModals
87 100
 }