Browse Source

release 0.1.0, redux support, explicit setOnNavigatorEvent, simplified API - no more direct work with Screen

talkol 8 years ago
parent
commit
a2d94dde9a
48 changed files with 750 additions and 262 deletions
  1. 3
    0
      RELEASES.md
  2. 17
    0
      example-redux/README.md
  3. BIN
      example-redux/img/colors.png
  4. BIN
      example-redux/img/navicon_add@2x.png
  5. BIN
      example-redux/img/navicon_edit@2x.png
  6. BIN
      example-redux/img/navicon_menu@2x.png
  7. BIN
      example-redux/img/one@2x.png
  8. BIN
      example-redux/img/one_selected@2x.png
  9. BIN
      example-redux/img/three@2x.png
  10. BIN
      example-redux/img/three_selected@2x.png
  11. BIN
      example-redux/img/two@2x.png
  12. BIN
      example-redux/img/two_selected@2x.png
  13. 1
    7
      example-redux/index.android.js
  14. 2
    51
      example-redux/index.ios.js
  15. 45
    14
      example-redux/ios/exampleRedux.xcodeproj/project.pbxproj
  16. 31
    42
      example-redux/ios/exampleRedux/AppDelegate.m
  17. 7
    8
      example-redux/ios/exampleRedux/Info.plist
  18. 9
    1
      example-redux/package.json
  19. 70
    0
      example-redux/src/app.js
  20. 15
    0
      example-redux/src/components/ExampleComponent.js
  21. 2
    0
      example-redux/src/reducers/app/actionTypes.js
  22. 20
    0
      example-redux/src/reducers/app/actions.js
  23. 17
    0
      example-redux/src/reducers/app/reducer.js
  24. 2
    0
      example-redux/src/reducers/counter/actionTypes.js
  25. 9
    0
      example-redux/src/reducers/counter/actions.js
  26. 21
    0
      example-redux/src/reducers/counter/reducer.js
  27. 7
    0
      example-redux/src/reducers/index.js
  28. 93
    0
      example-redux/src/screens/FirstTabScreen.js
  29. 69
    0
      example-redux/src/screens/LoginScreen.js
  30. 77
    0
      example-redux/src/screens/PushedScreen.js
  31. 74
    0
      example-redux/src/screens/SecondTabScreen.js
  32. 14
    0
      example-redux/src/screens/index.js
  33. 3
    1
      example/README.md
  34. 1
    7
      example/index.android.js
  35. 1
    1
      example/ios/example/Info.plist
  36. 4
    4
      example/src/app.js
  37. 8
    17
      example/src/screens/FirstTabScreen.js
  38. 8
    16
      example/src/screens/ModalScreen.js
  39. 7
    17
      example/src/screens/PushedScreen.js
  40. 6
    10
      example/src/screens/SecondTabScreen.js
  41. 2
    8
      example/src/screens/SideMenu.js
  42. 7
    15
      example/src/screens/StyledScreen.js
  43. 5
    16
      example/src/screens/ThirdTabScreen.js
  44. 20
    0
      example/src/screens/index.js
  45. 4
    1
      package.json
  46. 42
    1
      src/Navigation.js
  47. 25
    18
      src/Screen.js
  48. 2
    7
      src/platformSpecific.ios.js

+ 3
- 0
RELEASES.md View File

1
+# Release Notes
2
+
3
+### 0.1.0

+ 17
- 0
example-redux/README.md View File

1
+# example-redux
2
+
3
+A simple usage example for an app based on redux. If you're not using redux, take a look at [example](../example) (without redux). The non-redux example will also include more examples of pure navigation features since we don't want to maintain two full examples. Make sure to look at it as well.
4
+
5
+## Installation - iOS
6
+
7
+* In the `example/` folder, run `npm install`
8
+
9
+> Make sure you're using npm ver 3. If you normally use npm ver 2 on your system and reluctant to upgrade, you can install [npm 3 alongside 2](https://www.npmjs.com/package/npm3). For more details see https://github.com/wix/react-native-navigation/issues/1. In addition, redux also causes some issues with npm 2. If you have to use npm 2 on this project, fix those by running `npm run fix_npm2` in your project directory after running `npm install`.
10
+
11
+* Open `example/ios/example.xcodeproj` in Xcode and press the play button
12
+
13
+## Folder Structure
14
+
15
+* `screens/` - all your app screens, every screen is a redux connected ("smart") component
16
+* `components/` - all react sub-components, they are not aware of redux ("dumb") and get everything by props
17
+* `reducers/` - all of your redux goodness (reducts and their actions) goes here, all business logic should be here

BIN
example-redux/img/colors.png View File


BIN
example-redux/img/navicon_add@2x.png View File


BIN
example-redux/img/navicon_edit@2x.png View File


BIN
example-redux/img/navicon_menu@2x.png View File


BIN
example-redux/img/one@2x.png View File


BIN
example-redux/img/one_selected@2x.png View File


BIN
example-redux/img/three@2x.png View File


BIN
example-redux/img/three_selected@2x.png View File


BIN
example-redux/img/two@2x.png View File


BIN
example-redux/img/two_selected@2x.png View File


+ 1
- 7
example-redux/index.android.js View File

16
     return (
16
     return (
17
       <View style={styles.container}>
17
       <View style={styles.container}>
18
         <Text style={styles.welcome}>
18
         <Text style={styles.welcome}>
19
-          Welcome to React Native!
20
-        </Text>
21
-        <Text style={styles.instructions}>
22
-          To get started, edit index.android.js
23
-        </Text>
24
-        <Text style={styles.instructions}>
25
-          Shake or press menu button for dev menu
19
+          Coming Soon
26
         </Text>
20
         </Text>
27
       </View>
21
       </View>
28
     );
22
     );

+ 2
- 51
example-redux/index.ios.js View File

1
-/**
2
- * Sample React Native App
3
- * https://github.com/facebook/react-native
4
- */
5
-'use strict';
6
-import React, {
7
-  AppRegistry,
8
-  Component,
9
-  StyleSheet,
10
-  Text,
11
-  View
12
-} from 'react-native';
1
+import App from './src/app';
13
 
2
 
14
-class exampleRedux extends Component {
15
-  render() {
16
-    return (
17
-      <View style={styles.container}>
18
-        <Text style={styles.welcome}>
19
-          Welcome to React Native!
20
-        </Text>
21
-        <Text style={styles.instructions}>
22
-          To get started, edit index.ios.js
23
-        </Text>
24
-        <Text style={styles.instructions}>
25
-          Press Cmd+R to reload,{'\n'}
26
-          Cmd+D or shake for dev menu
27
-        </Text>
28
-      </View>
29
-    );
30
-  }
31
-}
32
-
33
-const styles = StyleSheet.create({
34
-  container: {
35
-    flex: 1,
36
-    justifyContent: 'center',
37
-    alignItems: 'center',
38
-    backgroundColor: '#F5FCFF',
39
-  },
40
-  welcome: {
41
-    fontSize: 20,
42
-    textAlign: 'center',
43
-    margin: 10,
44
-  },
45
-  instructions: {
46
-    textAlign: 'center',
47
-    color: '#333333',
48
-    marginBottom: 5,
49
-  },
50
-});
51
-
52
-AppRegistry.registerComponent('exampleRedux', () => exampleRedux);
3
+const app = new App();

+ 45
- 14
example-redux/ios/exampleRedux.xcodeproj/project.pbxproj View File

22
 		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
22
 		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
23
 		146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
23
 		146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
24
 		832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
24
 		832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
25
+		CCCF23211C9C238500455574 /* libReactNativeControllers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CCCF23201C9C236100455574 /* libReactNativeControllers.a */; };
25
 /* End PBXBuildFile section */
26
 /* End PBXBuildFile section */
26
 
27
 
27
 /* Begin PBXContainerItemProxy section */
28
 /* Begin PBXContainerItemProxy section */
102
 			remoteGlobalIDString = 58B5119B1A9E6C1200147676;
103
 			remoteGlobalIDString = 58B5119B1A9E6C1200147676;
103
 			remoteInfo = RCTText;
104
 			remoteInfo = RCTText;
104
 		};
105
 		};
106
+		CCCF231F1C9C236100455574 /* PBXContainerItemProxy */ = {
107
+			isa = PBXContainerItemProxy;
108
+			containerPortal = CCCF23111C9C236100455574 /* ReactNativeControllers.xcodeproj */;
109
+			proxyType = 2;
110
+			remoteGlobalIDString = D8AFADBD1BEE6F3F00A4592D;
111
+			remoteInfo = ReactNativeControllers;
112
+		};
105
 /* End PBXContainerItemProxy section */
113
 /* End PBXContainerItemProxy section */
106
 
114
 
107
 /* Begin PBXFileReference section */
115
 /* Begin PBXFileReference section */
108
-		008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = main.jsbundle; path = main.jsbundle; sourceTree = "<group>"; };
109
-		00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = "<group>"; };
110
-		00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
111
-		00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj; sourceTree = "<group>"; };
112
-		00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
113
-		00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = "<group>"; };
116
+		008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
117
+		00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = "<group>"; };
118
+		00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = "<group>"; };
119
+		00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = "<group>"; };
120
+		00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = "<group>"; };
121
+		00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = "<group>"; };
114
 		00E356EE1AD99517003FC87E /* exampleReduxTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = exampleReduxTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
122
 		00E356EE1AD99517003FC87E /* exampleReduxTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = exampleReduxTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
115
 		00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
123
 		00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
116
 		00E356F21AD99517003FC87E /* exampleReduxTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = exampleReduxTests.m; sourceTree = "<group>"; };
124
 		00E356F21AD99517003FC87E /* exampleReduxTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = exampleReduxTests.m; sourceTree = "<group>"; };
117
-		139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj; sourceTree = "<group>"; };
118
-		139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = "<group>"; };
125
+		139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = "<group>"; };
126
+		139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = "<group>"; };
119
 		13B07F961A680F5B00A75B9A /* exampleRedux.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = exampleRedux.app; sourceTree = BUILT_PRODUCTS_DIR; };
127
 		13B07F961A680F5B00A75B9A /* exampleRedux.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = exampleRedux.app; sourceTree = BUILT_PRODUCTS_DIR; };
120
 		13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = exampleRedux/AppDelegate.h; sourceTree = "<group>"; };
128
 		13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = exampleRedux/AppDelegate.h; sourceTree = "<group>"; };
121
 		13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = exampleRedux/AppDelegate.m; sourceTree = "<group>"; };
129
 		13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = exampleRedux/AppDelegate.m; sourceTree = "<group>"; };
123
 		13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = exampleRedux/Images.xcassets; sourceTree = "<group>"; };
131
 		13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = exampleRedux/Images.xcassets; sourceTree = "<group>"; };
124
 		13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = exampleRedux/Info.plist; sourceTree = "<group>"; };
132
 		13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = exampleRedux/Info.plist; sourceTree = "<group>"; };
125
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = exampleRedux/main.m; sourceTree = "<group>"; };
133
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = exampleRedux/main.m; sourceTree = "<group>"; };
126
-		146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../node_modules/react-native/React/React.xcodeproj; sourceTree = "<group>"; };
127
-		78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = "<group>"; };
128
-		832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../node_modules/react-native/Libraries/Text/RCTText.xcodeproj; sourceTree = "<group>"; };
134
+		146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
135
+		78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
136
+		832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
137
+		CCCF23111C9C236100455574 /* ReactNativeControllers.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeControllers.xcodeproj; path = "../node_modules/react-native-controllers/ios/ReactNativeControllers.xcodeproj"; sourceTree = "<group>"; };
129
 /* End PBXFileReference section */
138
 /* End PBXFileReference section */
130
 
139
 
131
 /* Begin PBXFrameworksBuildPhase section */
140
 /* Begin PBXFrameworksBuildPhase section */
140
 			isa = PBXFrameworksBuildPhase;
149
 			isa = PBXFrameworksBuildPhase;
141
 			buildActionMask = 2147483647;
150
 			buildActionMask = 2147483647;
142
 			files = (
151
 			files = (
152
+				CCCF23211C9C238500455574 /* libReactNativeControllers.a in Frameworks */,
143
 				146834051AC3E58100842450 /* libReact.a in Frameworks */,
153
 				146834051AC3E58100842450 /* libReact.a in Frameworks */,
144
 				00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
154
 				00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
145
 				00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
155
 				00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
272
 				832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
282
 				832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
273
 				00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
283
 				00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
274
 				139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
284
 				139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
285
+				CCCF23111C9C236100455574 /* ReactNativeControllers.xcodeproj */,
275
 			);
286
 			);
276
 			name = Libraries;
287
 			name = Libraries;
277
 			sourceTree = "<group>";
288
 			sourceTree = "<group>";
305
 			name = Products;
316
 			name = Products;
306
 			sourceTree = "<group>";
317
 			sourceTree = "<group>";
307
 		};
318
 		};
319
+		CCCF23121C9C236100455574 /* Products */ = {
320
+			isa = PBXGroup;
321
+			children = (
322
+				CCCF23201C9C236100455574 /* libReactNativeControllers.a */,
323
+			);
324
+			name = Products;
325
+			sourceTree = "<group>";
326
+		};
308
 /* End PBXGroup section */
327
 /* End PBXGroup section */
309
 
328
 
310
 /* Begin PBXNativeTarget section */
329
 /* Begin PBXNativeTarget section */
411
 					ProductGroup = 146834001AC3E56700842450 /* Products */;
430
 					ProductGroup = 146834001AC3E56700842450 /* Products */;
412
 					ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
431
 					ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
413
 				},
432
 				},
433
+				{
434
+					ProductGroup = CCCF23121C9C236100455574 /* Products */;
435
+					ProjectRef = CCCF23111C9C236100455574 /* ReactNativeControllers.xcodeproj */;
436
+				},
414
 			);
437
 			);
415
 			projectRoot = "";
438
 			projectRoot = "";
416
 			targets = (
439
 			targets = (
491
 			remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
514
 			remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
492
 			sourceTree = BUILT_PRODUCTS_DIR;
515
 			sourceTree = BUILT_PRODUCTS_DIR;
493
 		};
516
 		};
517
+		CCCF23201C9C236100455574 /* libReactNativeControllers.a */ = {
518
+			isa = PBXReferenceProxy;
519
+			fileType = archive.ar;
520
+			path = libReactNativeControllers.a;
521
+			remoteRef = CCCF231F1C9C236100455574 /* PBXContainerItemProxy */;
522
+			sourceTree = BUILT_PRODUCTS_DIR;
523
+		};
494
 /* End PBXReferenceProxy section */
524
 /* End PBXReferenceProxy section */
495
 
525
 
496
 /* Begin PBXResourcesBuildPhase section */
526
 /* Begin PBXResourcesBuildPhase section */
526
 			runOnlyForDeploymentPostprocessing = 0;
556
 			runOnlyForDeploymentPostprocessing = 0;
527
 			shellPath = /bin/sh;
557
 			shellPath = /bin/sh;
528
 			shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
558
 			shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
529
-			showEnvVarsInLog = 1;
530
 		};
559
 		};
531
 /* End PBXShellScriptBuildPhase section */
560
 /* End PBXShellScriptBuildPhase section */
532
 
561
 
617
 					"$(inherited)",
646
 					"$(inherited)",
618
 					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
647
 					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
619
 					"$(SRCROOT)/../node_modules/react-native/React/**",
648
 					"$(SRCROOT)/../node_modules/react-native/React/**",
649
+					"$(SRCROOT)/../node_modules/react-native-controllers/ios/**",
620
 				);
650
 				);
621
-				INFOPLIST_FILE = "exampleRedux/Info.plist";
651
+				INFOPLIST_FILE = exampleRedux/Info.plist;
622
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
652
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
623
 				OTHER_LDFLAGS = "-ObjC";
653
 				OTHER_LDFLAGS = "-ObjC";
624
 				PRODUCT_NAME = exampleRedux;
654
 				PRODUCT_NAME = exampleRedux;
633
 					"$(inherited)",
663
 					"$(inherited)",
634
 					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
664
 					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
635
 					"$(SRCROOT)/../node_modules/react-native/React/**",
665
 					"$(SRCROOT)/../node_modules/react-native/React/**",
666
+					"$(SRCROOT)/../node_modules/react-native-controllers/ios/**",
636
 				);
667
 				);
637
-				INFOPLIST_FILE = "exampleRedux/Info.plist";
668
+				INFOPLIST_FILE = exampleRedux/Info.plist;
638
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
669
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
639
 				OTHER_LDFLAGS = "-ObjC";
670
 				OTHER_LDFLAGS = "-ObjC";
640
 				PRODUCT_NAME = exampleRedux;
671
 				PRODUCT_NAME = exampleRedux;

+ 31
- 42
example-redux/ios/exampleRedux/AppDelegate.m View File

1
-/**
2
- * Copyright (c) 2015-present, Facebook, Inc.
3
- * All rights reserved.
4
- *
5
- * This source code is licensed under the BSD-style license found in the
6
- * LICENSE file in the root directory of this source tree. An additional grant
7
- * of patent rights can be found in the PATENTS file in the same directory.
8
- */
9
-
10
 #import "AppDelegate.h"
1
 #import "AppDelegate.h"
11
 
2
 
3
+// **********************************************
4
+// *** DON'T MISS: THE NEXT LINE IS IMPORTANT ***
5
+// **********************************************
6
+#import "RCCManager.h"
7
+
8
+// IMPORTANT: if you're getting an Xcode error that RCCManager.h isn't found, you've probably ran "npm install"
9
+// with npm ver 2. You'll need to "npm install" with npm 3 (see https://github.com/wix/react-native-navigation/issues/1)
10
+
12
 #import "RCTRootView.h"
11
 #import "RCTRootView.h"
13
 
12
 
14
 @implementation AppDelegate
13
 @implementation AppDelegate
16
 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
15
 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
17
 {
16
 {
18
   NSURL *jsCodeLocation;
17
   NSURL *jsCodeLocation;
19
-
20
-  /**
21
-   * Loading JavaScript code - uncomment the one you want.
22
-   *
23
-   * OPTION 1
24
-   * Load from development server. Start the server from the repository root:
25
-   *
26
-   * $ npm start
27
-   *
28
-   * To run on device, change `localhost` to the IP address of your computer
29
-   * (you can get this by typing `ifconfig` into the terminal and selecting the
30
-   * `inet` value under `en0:`) and make sure your computer and iOS device are
31
-   * on the same Wi-Fi network.
32
-   */
33
-
34
   jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
18
   jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
35
-
36
-  /**
37
-   * OPTION 2
38
-   * Load from pre-bundled file on disk. The static bundle is automatically
39
-   * generated by "Bundle React Native code and images" build step.
40
-   */
41
-
42
-//   jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
43
-
44
-  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
45
-                                                      moduleName:@"exampleRedux"
46
-                                               initialProperties:nil
47
-                                                   launchOptions:launchOptions];
48
-
19
+  // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
20
+  
21
+  
22
+  // **********************************************
23
+  // *** DON'T MISS: THIS IS HOW WE BOOTSTRAP *****
24
+  // **********************************************
49
   self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
25
   self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
50
-  UIViewController *rootViewController = [UIViewController new];
51
-  rootViewController.view = rootView;
52
-  self.window.rootViewController = rootViewController;
53
-  [self.window makeKeyAndVisible];
26
+  self.window.backgroundColor = [UIColor whiteColor];
27
+  [[RCCManager sharedIntance] initBridgeWithBundleURL:jsCodeLocation];
28
+  
29
+  /*
30
+   // original RN bootstrap - remove this part
31
+   RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
32
+   moduleName:@"example"
33
+   initialProperties:nil
34
+   launchOptions:launchOptions];
35
+   self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
36
+   UIViewController *rootViewController = [UIViewController new];
37
+   rootViewController.view = rootView;
38
+   self.window.rootViewController = rootViewController;
39
+   [self.window makeKeyAndVisible];
40
+   */
41
+  
42
+  
54
   return YES;
43
   return YES;
55
 }
44
 }
56
 
45
 

+ 7
- 8
example-redux/ios/exampleRedux/Info.plist View File

15
 	<key>CFBundlePackageType</key>
15
 	<key>CFBundlePackageType</key>
16
 	<string>APPL</string>
16
 	<string>APPL</string>
17
 	<key>CFBundleShortVersionString</key>
17
 	<key>CFBundleShortVersionString</key>
18
-	<string>1.0</string>
18
+	<string>1.0.0</string>
19
 	<key>CFBundleSignature</key>
19
 	<key>CFBundleSignature</key>
20
 	<string>????</string>
20
 	<string>????</string>
21
 	<key>CFBundleVersion</key>
21
 	<key>CFBundleVersion</key>
35
 		<string>UIInterfaceOrientationLandscapeRight</string>
35
 		<string>UIInterfaceOrientationLandscapeRight</string>
36
 	</array>
36
 	</array>
37
 	<key>UIViewControllerBasedStatusBarAppearance</key>
37
 	<key>UIViewControllerBasedStatusBarAppearance</key>
38
-	<false/>
38
+	<true/>
39
 	<key>NSLocationWhenInUseUsageDescription</key>
39
 	<key>NSLocationWhenInUseUsageDescription</key>
40
 	<string></string>
40
 	<string></string>
41
-  <key>NSAppTransportSecurity</key>
42
-  <dict>
43
-    <!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
44
-    <key>NSAllowsArbitraryLoads</key>
45
-    <true/>
46
-  </dict>
41
+	<key>NSAppTransportSecurity</key>
42
+	<dict>
43
+		<key>NSAllowsArbitraryLoads</key>
44
+		<true/>
45
+	</dict>
47
 </dict>
46
 </dict>
48
 </plist>
47
 </plist>

+ 9
- 1
example-redux/package.json View File

3
   "version": "0.0.1",
3
   "version": "0.0.1",
4
   "private": true,
4
   "private": true,
5
   "scripts": {
5
   "scripts": {
6
-    "start": "node node_modules/react-native/local-cli/cli.js start"
6
+    "start": "node node_modules/react-native/local-cli/cli.js start",
7
+    "fix_npm2": "npm run _fix_npm2_step1; npm run _fix_npm2_step2",
8
+    "_fix_npm2_step1": "rm -rf node_modules/react-native/node_modules/react; rm -rf node_modules/react-native/node_modules/fbjs; rm -rf node_modules/react/node_modules/fbjs",
9
+    "_fix_npm2_step2": "cd node_modules; find . -name .babelrc | grep -v packager | xargs rm"
7
   },
10
   },
8
   "dependencies": {
11
   "dependencies": {
9
     "react-native": "^0.21.0",
12
     "react-native": "^0.21.0",
13
+    "fbjs": "^0.6.1",
14
+    "react-redux": "^4.0.6",
15
+    "redux": "^3.0.5",
16
+    "redux-thunk": "^1.0.3",
17
+    "seamless-immutable": "^5.0.1",
10
     "react-native-navigation": "latest"
18
     "react-native-navigation": "latest"
11
   }
19
   }
12
 }
20
 }

+ 70
- 0
example-redux/src/app.js View File

1
+import { createStore, applyMiddleware, combineReducers } from 'redux';
2
+import { Provider } from 'react-redux';
3
+import { Navigation } from 'react-native-navigation';
4
+import thunk from 'redux-thunk';
5
+import * as reducers from './reducers';
6
+import * as appActions from './reducers/app/actions';
7
+
8
+// redux related book keeping
9
+const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
10
+const reducer = combineReducers(reducers);
11
+const store = createStoreWithMiddleware(reducer);
12
+
13
+// screen related book keeping
14
+import { registerScreens } from './screens';
15
+registerScreens(store, Provider);
16
+
17
+// notice that this is just a simple class, it's not a React component
18
+export default class App {
19
+  constructor() {
20
+    // since react-redux only works on components, we need to subscribe this class manually
21
+    store.subscribe(this.onStoreUpdate.bind(this));
22
+    store.dispatch(appActions.appInitialized());
23
+  }
24
+  onStoreUpdate() {
25
+    const { root } = store.getState().app;
26
+    // handle a root change
27
+    // if your app doesn't change roots in runtime, you can remove onStoreUpdate() altogether
28
+    if (this.currentRoot !== root) {
29
+      this.currentRoot = root;
30
+      this.startApp(root);
31
+    }
32
+  }
33
+  startApp(root) {
34
+    switch (root) {
35
+      case 'login':
36
+        Navigation.startSingleScreenApp({
37
+          screen: {
38
+            screen: 'example.LoginScreen',
39
+            title: 'Login',
40
+            navigatorStyle: {}
41
+          }
42
+        });
43
+        return;
44
+      case 'after-login':
45
+        Navigation.startTabBasedApp({
46
+          tabs: [
47
+            {
48
+              label: 'One',
49
+              screen: 'example.FirstTabScreen',
50
+              icon: require('../img/one.png'),
51
+              selectedIcon: require('../img/one_selected.png'),
52
+              title: 'Screen One',
53
+              navigatorStyle: {}
54
+            },
55
+            {
56
+              label: 'Two',
57
+              screen: 'example.SecondTabScreen',
58
+              icon: require('../img/two.png'),
59
+              selectedIcon: require('../img/two_selected.png'),
60
+              title: 'Screen Two',
61
+              navigatorStyle: {}
62
+            }
63
+          ]
64
+        });
65
+        return;
66
+      default:
67
+        console.error('Unknown app root');
68
+    }
69
+  }
70
+}

+ 15
- 0
example-redux/src/components/ExampleComponent.js View File

1
+import React, {
2
+  Component,
3
+  Text
4
+} from 'react-native';
5
+
6
+export default class ExampleComponent extends Component {
7
+  constructor(props) {
8
+    super(props);
9
+  }
10
+  render() {
11
+    return (
12
+      <Text>I am a regular non-redux aware component</Text>
13
+    );
14
+  }
15
+}

+ 2
- 0
example-redux/src/reducers/app/actionTypes.js View File

1
+export const INITIALIZED = 'example.app.INITIALIZED';
2
+export const ROOT_CHANGED = 'example.app.ROOT_CHANGED';

+ 20
- 0
example-redux/src/reducers/app/actions.js View File

1
+import * as types from './actionTypes';
2
+
3
+export function appInitialized() {
4
+  return async function(dispatch, getState) {
5
+    // since all business logic should be inside redux actions
6
+    // this is a good place to put your app initialization code
7
+    dispatch(changeAppRoot('login'));
8
+  };
9
+}
10
+
11
+export function changeAppRoot(root) {
12
+  return {type: types.ROOT_CHANGED, root: root};
13
+}
14
+
15
+export function login() {
16
+  return async function(dispatch, getState) {
17
+    // login logic would go here, and when it's done, we switch app roots
18
+    dispatch(changeAppRoot('after-login'));
19
+  };
20
+}

+ 17
- 0
example-redux/src/reducers/app/reducer.js View File

1
+import * as types from './actionTypes';
2
+import Immutable from 'seamless-immutable';
3
+
4
+const initialState = Immutable({
5
+  root: undefined // 'login' / 'after-login'
6
+});
7
+
8
+export default function app(state = initialState, action = {}) {
9
+  switch (action.type) {
10
+    case types.ROOT_CHANGED:
11
+      return state.merge({
12
+        root: action.root
13
+      });
14
+    default:
15
+      return state;
16
+  }
17
+}

+ 2
- 0
example-redux/src/reducers/counter/actionTypes.js View File

1
+export const INCREMENT = 'example.counter.INCREMENT';
2
+export const DECREMENT = 'example.counter.DECREMENT';

+ 9
- 0
example-redux/src/reducers/counter/actions.js View File

1
+import * as types from './actionTypes';
2
+
3
+export function increment() {
4
+  return {type: types.INCREMENT};
5
+}
6
+
7
+export function decrement() {
8
+  return {type: types.DECREMENT};
9
+}

+ 21
- 0
example-redux/src/reducers/counter/reducer.js View File

1
+import * as types from './actionTypes';
2
+import Immutable from 'seamless-immutable';
3
+
4
+const initialState = Immutable({
5
+  count: 0
6
+});
7
+
8
+export default function counter(state = initialState, action = {}) {
9
+  switch (action.type) {
10
+    case types.INCREMENT:
11
+      return state.merge({
12
+        count: state.count + 1
13
+      });
14
+    case types.DECREMENT:
15
+      return state.merge({
16
+        count: state.count - 1
17
+      });
18
+    default:
19
+      return state;
20
+  }
21
+}

+ 7
- 0
example-redux/src/reducers/index.js View File

1
+import app from './app/reducer';
2
+import counter from './counter/reducer';
3
+
4
+export {
5
+  app,
6
+  counter
7
+};

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

1
+import React, {
2
+  Component,
3
+  Text,
4
+  View,
5
+  ScrollView,
6
+  TouchableOpacity,
7
+  StyleSheet,
8
+  AlertIOS
9
+} from 'react-native';
10
+import { connect } from 'react-redux';
11
+import * as counterActions from '../reducers/counter/actions';
12
+
13
+// this is a traditional React component connected to the redux store
14
+class FirstTabScreen extends Component {
15
+  static navigatorButtons = {
16
+    rightButtons: [
17
+      {
18
+        title: 'Edit',
19
+        id: 'edit'
20
+      },
21
+      {
22
+        icon: require('../../img/navicon_add.png'),
23
+        id: 'add'
24
+      }
25
+    ]
26
+  };
27
+  constructor(props) {
28
+    super(props);
29
+    // if you want to listen on navigator events, set this up
30
+    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
31
+  }
32
+  onNavigatorEvent(event) {
33
+    if (event.id == 'edit') {
34
+      AlertIOS.alert('NavBar', 'Edit button pressed');
35
+    }
36
+    if (event.id == 'add') {
37
+      AlertIOS.alert('NavBar', 'Add button pressed');
38
+    }
39
+  }
40
+  render() {
41
+    return (
42
+      <View style={{flex: 1, padding: 20}}>
43
+
44
+        <Text style={styles.text}>
45
+          <Text style={{fontWeight: '500'}}>Same Counter: </Text> {this.props.counter.count}
46
+        </Text>
47
+
48
+        <TouchableOpacity onPress={ this.onIncrementPress.bind(this) }>
49
+          <Text style={styles.button}>Increment Counter</Text>
50
+        </TouchableOpacity>
51
+
52
+        <TouchableOpacity onPress={ this.onPushPress.bind(this) }>
53
+          <Text style={styles.button}>Push Screen</Text>
54
+        </TouchableOpacity>
55
+
56
+      </View>
57
+    );
58
+  }
59
+  onIncrementPress() {
60
+    this.props.dispatch(counterActions.increment());
61
+  }
62
+  onPushPress() {
63
+    this.props.navigator.push({
64
+      title: "More",
65
+      screen: "example.PushedScreen"
66
+    });
67
+  }
68
+}
69
+
70
+const styles = StyleSheet.create({
71
+  text: {
72
+    textAlign: 'center',
73
+    fontSize: 18,
74
+    marginBottom: 10,
75
+    marginTop:10,
76
+  },
77
+  button: {
78
+    textAlign: 'center',
79
+    fontSize: 18,
80
+    marginBottom: 10,
81
+    marginTop:10,
82
+    color: 'blue'
83
+  }
84
+});
85
+
86
+// which props do we want to inject, given the global state?
87
+function mapStateToProps(state) {
88
+  return {
89
+    counter: state.counter
90
+  };
91
+}
92
+
93
+export default connect(mapStateToProps)(FirstTabScreen);

+ 69
- 0
example-redux/src/screens/LoginScreen.js View File

1
+import React, {
2
+  Component,
3
+  Text,
4
+  View,
5
+  ScrollView,
6
+  TouchableOpacity,
7
+  StyleSheet,
8
+  AlertIOS
9
+} from 'react-native';
10
+import { connect } from 'react-redux';
11
+import * as counterActions from '../reducers/counter/actions';
12
+import * as appActions from '../reducers/app/actions';
13
+
14
+// this is a traditional React component connected to the redux store
15
+class LoginScreen extends Component {
16
+  constructor(props) {
17
+    super(props);
18
+  }
19
+  render() {
20
+    return (
21
+      <View style={{flex: 1, padding: 20}}>
22
+
23
+        <Text style={styles.text}>
24
+          <Text style={{fontWeight: '500'}}>Counter: </Text> {this.props.counter.count}
25
+        </Text>
26
+
27
+        <TouchableOpacity onPress={ this.onIncrementPress.bind(this) }>
28
+          <Text style={styles.button}>Increment Counter</Text>
29
+        </TouchableOpacity>
30
+
31
+        <TouchableOpacity onPress={ this.onLoginPress.bind(this) }>
32
+          <Text style={styles.button}>Login</Text>
33
+        </TouchableOpacity>
34
+
35
+      </View>
36
+    );
37
+  }
38
+  onIncrementPress() {
39
+    this.props.dispatch(counterActions.increment());
40
+  }
41
+  onLoginPress() {
42
+    this.props.dispatch(appActions.login());
43
+  }
44
+}
45
+
46
+const styles = StyleSheet.create({
47
+  text: {
48
+    textAlign: 'center',
49
+    fontSize: 18,
50
+    marginBottom: 10,
51
+    marginTop:10,
52
+  },
53
+  button: {
54
+    textAlign: 'center',
55
+    fontSize: 18,
56
+    marginBottom: 10,
57
+    marginTop:10,
58
+    color: 'blue'
59
+  }
60
+});
61
+
62
+// which props do we want to inject, given the global state?
63
+function mapStateToProps(state) {
64
+  return {
65
+    counter: state.counter
66
+  };
67
+}
68
+
69
+export default connect(mapStateToProps)(LoginScreen);

+ 77
- 0
example-redux/src/screens/PushedScreen.js View File

1
+import React, {
2
+  Component,
3
+  Text,
4
+  View,
5
+  ScrollView,
6
+  TouchableOpacity,
7
+  StyleSheet
8
+} from 'react-native';
9
+import { connect } from 'react-redux';
10
+import * as counterActions from '../reducers/counter/actions';
11
+
12
+// this is a traditional React component connected to the redux store
13
+class PushedScreen extends Component {
14
+  constructor(props) {
15
+    super(props);
16
+  }
17
+  render() {
18
+    return (
19
+      <View style={{flex: 1, padding: 20}}>
20
+
21
+        <Text style={styles.text}>
22
+          <Text style={{fontWeight: '500'}}>Counter: </Text> {this.props.counter.count}
23
+        </Text>
24
+
25
+        <TouchableOpacity onPress={ this.onIncrementPress.bind(this) }>
26
+          <Text style={styles.button}>Increment Counter</Text>
27
+        </TouchableOpacity>
28
+
29
+        <TouchableOpacity onPress={ this.onPushPress.bind(this) }>
30
+          <Text style={styles.button}>Push Another</Text>
31
+        </TouchableOpacity>
32
+
33
+        <TouchableOpacity onPress={ this.onPopPress.bind(this) }>
34
+          <Text style={styles.button}>Pop Screen</Text>
35
+        </TouchableOpacity>
36
+
37
+      </View>
38
+    );
39
+  }
40
+  onIncrementPress() {
41
+    this.props.dispatch(counterActions.increment());
42
+  }
43
+  onPushPress() {
44
+    this.props.navigator.push({
45
+      title: "More",
46
+      screen: "example.PushedScreen"
47
+    });
48
+  }
49
+  onPopPress() {
50
+    this.props.navigator.pop();
51
+  }
52
+}
53
+
54
+const styles = StyleSheet.create({
55
+  text: {
56
+    textAlign: 'center',
57
+    fontSize: 18,
58
+    marginBottom: 10,
59
+    marginTop:10,
60
+  },
61
+  button: {
62
+    textAlign: 'center',
63
+    fontSize: 18,
64
+    marginBottom: 10,
65
+    marginTop:10,
66
+    color: 'blue'
67
+  }
68
+});
69
+
70
+// which props do we want to inject, given the global state?
71
+function mapStateToProps(state) {
72
+  return {
73
+    counter: state.counter
74
+  };
75
+}
76
+
77
+export default connect(mapStateToProps)(PushedScreen);

+ 74
- 0
example-redux/src/screens/SecondTabScreen.js View File

1
+import React, {
2
+  Component,
3
+  Text,
4
+  Image,
5
+  View,
6
+  ScrollView,
7
+  TouchableOpacity,
8
+  StyleSheet,
9
+  AlertIOS
10
+} from 'react-native';
11
+import { connect } from 'react-redux';
12
+import * as counterActions from '../reducers/counter/actions';
13
+
14
+// this is a traditional React component connected to the redux store
15
+class SecondTabScreen extends Component {
16
+  static navigatorStyle = {
17
+    drawUnderNavBar: true,
18
+    drawUnderTabBar: true,
19
+    navBarTranslucent: true
20
+  };
21
+  constructor(props) {
22
+    super(props);
23
+    this.buttonsCounter = 0;
24
+  }
25
+  render() {
26
+    return (
27
+      <ScrollView style={{flex: 1}}>
28
+
29
+        <Image style={{width: undefined, height: 100}} source={require('../../img/colors.png')} />
30
+
31
+        <View style={{padding: 20}}>
32
+
33
+          <Text style={styles.text}>
34
+            <Text style={{fontWeight: '500'}}>Here Too: </Text> {this.props.counter.count}
35
+          </Text>
36
+
37
+          <TouchableOpacity onPress={ this.onIncrementPress.bind(this) }>
38
+            <Text style={styles.button}>Increment Counter</Text>
39
+          </TouchableOpacity>
40
+
41
+        </View>
42
+
43
+      </ScrollView>
44
+    );
45
+  }
46
+  onIncrementPress() {
47
+    this.props.dispatch(counterActions.increment());
48
+  }
49
+}
50
+
51
+const styles = StyleSheet.create({
52
+  text: {
53
+    textAlign: 'center',
54
+    fontSize: 18,
55
+    marginBottom: 10,
56
+    marginTop:10,
57
+  },
58
+  button: {
59
+    textAlign: 'center',
60
+    fontSize: 18,
61
+    marginBottom: 10,
62
+    marginTop:10,
63
+    color: 'blue'
64
+  }
65
+});
66
+
67
+// which props do we want to inject, given the global state?
68
+function mapStateToProps(state) {
69
+  return {
70
+    counter: state.counter
71
+  };
72
+}
73
+
74
+export default connect(mapStateToProps)(SecondTabScreen);

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

1
+import { Navigation } from 'react-native-navigation';
2
+
3
+import LoginScreen from './LoginScreen';
4
+import FirstTabScreen from './FirstTabScreen';
5
+import SecondTabScreen from './SecondTabScreen';
6
+import PushedScreen from './PushedScreen';
7
+
8
+// register all screens of the app (including internal ones)
9
+export function registerScreens(store, Provider) {
10
+  Navigation.registerComponent('example.LoginScreen', () => LoginScreen, store, Provider);
11
+  Navigation.registerComponent('example.FirstTabScreen', () => FirstTabScreen, store, Provider);
12
+  Navigation.registerComponent('example.SecondTabScreen', () => SecondTabScreen, store, Provider);
13
+  Navigation.registerComponent('example.PushedScreen', () => PushedScreen, store, Provider);
14
+}

+ 3
- 1
example/README.md View File

1
 # example
1
 # example
2
 
2
 
3
+A simple usage example. If you're using redux, take a look at [example-redux](../example-redux).
4
+
3
 ## Installation - iOS
5
 ## Installation - iOS
4
 
6
 
5
 * In the `example/` folder, run `npm install`
7
 * In the `example/` folder, run `npm install`
6
 
8
 
7
-> Make sure you're using npm ver 3. If you normally use npm ver 2 on your system and reluctant to upgrade, you can install [npm 3 alongside 2](https://www.npmjs.com/package/npm3).
9
+> Make sure you're using npm ver 3. If you normally use npm ver 2 on your system and reluctant to upgrade, you can install [npm 3 alongside 2](https://www.npmjs.com/package/npm3). For more details see https://github.com/wix/react-native-navigation/issues/1
8
 
10
 
9
 * Open `example/ios/example.xcodeproj` in Xcode and press the play button
11
 * Open `example/ios/example.xcodeproj` in Xcode and press the play button

+ 1
- 7
example/index.android.js View File

16
     return (
16
     return (
17
       <View style={styles.container}>
17
       <View style={styles.container}>
18
         <Text style={styles.welcome}>
18
         <Text style={styles.welcome}>
19
-          Welcome to React Native!
20
-        </Text>
21
-        <Text style={styles.instructions}>
22
-          To get started, edit index.android.js
23
-        </Text>
24
-        <Text style={styles.instructions}>
25
-          Shake or press menu button for dev menu
19
+          Coming Soon
26
         </Text>
20
         </Text>
27
       </View>
21
       </View>
28
     );
22
     );

+ 1
- 1
example/ios/example/Info.plist View File

15
 	<key>CFBundlePackageType</key>
15
 	<key>CFBundlePackageType</key>
16
 	<string>APPL</string>
16
 	<string>APPL</string>
17
 	<key>CFBundleShortVersionString</key>
17
 	<key>CFBundleShortVersionString</key>
18
-	<string>1.0</string>
18
+	<string>1.0.0</string>
19
 	<key>CFBundleSignature</key>
19
 	<key>CFBundleSignature</key>
20
 	<string>????</string>
20
 	<string>????</string>
21
 	<key>CFBundleVersion</key>
21
 	<key>CFBundleVersion</key>

+ 4
- 4
example/src/app.js View File

1
 import { Navigation } from 'react-native-navigation';
1
 import { Navigation } from 'react-native-navigation';
2
 
2
 
3
-import './screens/FirstTabScreen';
4
-import './screens/SecondTabScreen';
5
-import './screens/ThirdTabScreen';
6
-import './screens/SideMenu';
3
+// screen related book keeping
4
+import { registerScreens } from './screens';
5
+registerScreens();
7
 
6
 
7
+// this will start our app
8
 Navigation.startTabBasedApp({
8
 Navigation.startTabBasedApp({
9
   tabs: [
9
   tabs: [
10
     {
10
     {

+ 8
- 17
example/src/screens/FirstTabScreen.js View File

1
 import React, {
1
 import React, {
2
+  Component,
2
   Text,
3
   Text,
3
   View,
4
   View,
4
   ScrollView,
5
   ScrollView,
7
   AlertIOS
8
   AlertIOS
8
 } from 'react-native';
9
 } from 'react-native';
9
 
10
 
10
-// important imports, the magic is here
11
-import { Navigation, Screen } from 'react-native-navigation';
12
-
13
-// need to import every screen we push
14
-import './PushedScreen';
15
-import './StyledScreen';
16
-import './ModalScreen';
17
-
18
-// instead of React.Component, we extend Screen (imported above)
19
-class FirstTabScreen extends Screen {
11
+export default class FirstTabScreen extends Component {
20
   static navigatorButtons = {
12
   static navigatorButtons = {
21
     leftButtons: [{
13
     leftButtons: [{
22
       icon: require('../../img/navicon_menu.png'),
14
       icon: require('../../img/navicon_menu.png'),
35
   };
27
   };
36
   constructor(props) {
28
   constructor(props) {
37
     super(props);
29
     super(props);
30
+    // if you want to listen on navigator events, set this up
31
+    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
38
   }
32
   }
39
   onNavigatorEvent(event) {
33
   onNavigatorEvent(event) {
40
     if (event.id == 'menu') {
34
     if (event.id == 'menu') {
41
-      this.navigator.toggleDrawer({
35
+      this.props.navigator.toggleDrawer({
42
         side: 'left',
36
         side: 'left',
43
         animated: true
37
         animated: true
44
       });
38
       });
70
     );
64
     );
71
   }
65
   }
72
   onPushPress() {
66
   onPushPress() {
73
-    this.navigator.push({
67
+    this.props.navigator.push({
74
       title: "More",
68
       title: "More",
75
       screen: "example.PushedScreen"
69
       screen: "example.PushedScreen"
76
     });
70
     });
77
   }
71
   }
78
   onPushStyledPress() {
72
   onPushStyledPress() {
79
-    this.navigator.push({
73
+    this.props.navigator.push({
80
       title: "Styled",
74
       title: "Styled",
81
       screen: "example.StyledScreen"
75
       screen: "example.StyledScreen"
82
     });
76
     });
83
   }
77
   }
84
   onModalPress() {
78
   onModalPress() {
85
-    this.navigator.showModal({
79
+    this.props.navigator.showModal({
86
       title: "Modal",
80
       title: "Modal",
87
       screen: "example.ModalScreen"
81
       screen: "example.ModalScreen"
88
     });
82
     });
98
     color: 'blue'
92
     color: 'blue'
99
   }
93
   }
100
 });
94
 });
101
-
102
-// every screen must be registered with a unique name
103
-Navigation.registerScreen('example.FirstTabScreen', () => FirstTabScreen);

+ 8
- 16
example/src/screens/ModalScreen.js View File

1
 import React, {
1
 import React, {
2
+  Component,
2
   Text,
3
   Text,
3
   View,
4
   View,
4
   ScrollView,
5
   ScrollView,
6
   StyleSheet
7
   StyleSheet
7
 } from 'react-native';
8
 } from 'react-native';
8
 
9
 
9
-// important imports, the magic is here
10
-import { Navigation, Screen } from 'react-native-navigation';
11
-
12
-// need to import every screen we push
13
-import './PushedScreen';
14
-import './StyledScreen';
15
-
16
-// instead of React.Component, we extend Screen (imported above)
17
-class ModalScreen extends Screen {
10
+export default class ModalScreen extends Component {
18
   static navigatorButtons = {
11
   static navigatorButtons = {
19
     leftButtons: [{
12
     leftButtons: [{
20
       title: 'Close',
13
       title: 'Close',
23
   };
16
   };
24
   constructor(props) {
17
   constructor(props) {
25
     super(props);
18
     super(props);
19
+    // if you want to listen on navigator events, set this up
20
+    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
26
   }
21
   }
27
   render() {
22
   render() {
28
     return (
23
     return (
45
   }
40
   }
46
   onNavigatorEvent(event) {
41
   onNavigatorEvent(event) {
47
     if (event.id == 'close') {
42
     if (event.id == 'close') {
48
-      this.navigator.dismissModal();
43
+      this.props.navigator.dismissModal();
49
     }
44
     }
50
   }
45
   }
51
   onPushPress() {
46
   onPushPress() {
52
-    this.navigator.push({
47
+    this.props.navigator.push({
53
       title: "More",
48
       title: "More",
54
       screen: "example.PushedScreen"
49
       screen: "example.PushedScreen"
55
     });
50
     });
56
   }
51
   }
57
   onPushStyledPress() {
52
   onPushStyledPress() {
58
-    this.navigator.push({
53
+    this.props.navigator.push({
59
       title: "More",
54
       title: "More",
60
       screen: "example.StyledScreen"
55
       screen: "example.StyledScreen"
61
     });
56
     });
62
   }
57
   }
63
   onClosePress() {
58
   onClosePress() {
64
-    this.navigator.dismissModal();
59
+    this.props.navigator.dismissModal();
65
   }
60
   }
66
 }
61
 }
67
 
62
 
74
     color: 'blue'
69
     color: 'blue'
75
   }
70
   }
76
 });
71
 });
77
-
78
-// every screen must be registered with a unique name
79
-Navigation.registerScreen('example.ModalScreen', () => ModalScreen);

+ 7
- 17
example/src/screens/PushedScreen.js View File

1
 import React, {
1
 import React, {
2
+  Component,
2
   Text,
3
   Text,
3
   View,
4
   View,
4
   ScrollView,
5
   ScrollView,
6
   StyleSheet
7
   StyleSheet
7
 } from 'react-native';
8
 } from 'react-native';
8
 
9
 
9
-// important imports, the magic is here
10
-import { Navigation, Screen } from 'react-native-navigation';
11
-
12
-// need to import every screen we push
13
-import './PushedScreen';
14
-import './StyledScreen';
15
-
16
-// instead of React.Component, we extend Screen (imported above)
17
-class PushedScreen extends Screen {
10
+export default class PushedScreen extends Component {
18
   constructor(props) {
11
   constructor(props) {
19
     super(props);
12
     super(props);
20
   }
13
   }
46
     );
39
     );
47
   }
40
   }
48
   onPushPress() {
41
   onPushPress() {
49
-    this.navigator.push({
42
+    this.props.navigator.push({
50
       title: "More",
43
       title: "More",
51
       screen: "example.PushedScreen"
44
       screen: "example.PushedScreen"
52
     });
45
     });
53
   }
46
   }
54
   onPushStyledPress() {
47
   onPushStyledPress() {
55
-    this.navigator.push({
48
+    this.props.navigator.push({
56
       title: "More",
49
       title: "More",
57
       screen: "example.StyledScreen"
50
       screen: "example.StyledScreen"
58
     });
51
     });
59
   }
52
   }
60
   onPopPress() {
53
   onPopPress() {
61
-    this.navigator.pop();
54
+    this.props.navigator.pop();
62
   }
55
   }
63
   onPopToRootPress() {
56
   onPopToRootPress() {
64
-    this.navigator.popToRoot();
57
+    this.props.navigator.popToRoot();
65
   }
58
   }
66
   onResetToPress() {
59
   onResetToPress() {
67
-    this.navigator.resetTo({
60
+    this.props.navigator.resetTo({
68
       title: "New Root",
61
       title: "New Root",
69
       screen: "example.PushedScreen"
62
       screen: "example.PushedScreen"
70
     });
63
     });
80
     color: 'blue'
73
     color: 'blue'
81
   }
74
   }
82
 });
75
 });
83
-
84
-// every screen must be registered with a unique name
85
-Navigation.registerScreen('example.PushedScreen', () => PushedScreen);

+ 6
- 10
example/src/screens/SecondTabScreen.js View File

1
 import React, {
1
 import React, {
2
+  Component,
2
   Text,
3
   Text,
3
   View,
4
   View,
4
   ScrollView,
5
   ScrollView,
7
   AlertIOS
8
   AlertIOS
8
 } from 'react-native';
9
 } from 'react-native';
9
 
10
 
10
-// important imports, the magic is here
11
-import { Navigation, Screen } from 'react-native-navigation';
12
-
13
-// instead of React.Component, we extend Screen (imported above)
14
-class SecondTabScreen extends Screen {
11
+export default class SecondTabScreen extends Component {
15
   constructor(props) {
12
   constructor(props) {
16
     super(props);
13
     super(props);
17
     this.buttonsCounter = 0;
14
     this.buttonsCounter = 0;
15
+    // if you want to listen on navigator events, set this up
16
+    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
18
   }
17
   }
19
   render() {
18
   render() {
20
     return (
19
     return (
32
     );
31
     );
33
   }
32
   }
34
   onChangeTitlePress() {
33
   onChangeTitlePress() {
35
-    this.navigator.setTitle({
34
+    this.props.navigator.setTitle({
36
       title: Math.round(Math.random() * 100000).toString()
35
       title: Math.round(Math.random() * 100000).toString()
37
     });
36
     });
38
   }
37
   }
59
     }
58
     }
60
     this.buttonsCounter++;
59
     this.buttonsCounter++;
61
 
60
 
62
-    this.navigator.setButtons({
61
+    this.props.navigator.setButtons({
63
       rightButtons: buttons,
62
       rightButtons: buttons,
64
       animated: true
63
       animated: true
65
     });
64
     });
86
     color: 'blue'
85
     color: 'blue'
87
   }
86
   }
88
 });
87
 });
89
-
90
-// every screen must be registered with a unique name
91
-Navigation.registerScreen('example.SecondTabScreen', () => SecondTabScreen);

+ 2
- 8
example/src/screens/SideMenu.js View File

1
 import React, {
1
 import React, {
2
+  Component,
2
   Text,
3
   Text,
3
   View,
4
   View,
4
   ScrollView,
5
   ScrollView,
7
   AlertIOS
8
   AlertIOS
8
 } from 'react-native';
9
 } from 'react-native';
9
 
10
 
10
-// important imports, the magic is here
11
-import { Navigation, Screen } from 'react-native-navigation';
12
-
13
-// instead of React.Component, we extend Screen (imported above)
14
-class SideMenu extends Screen {
11
+export default class SideMenu extends Component {
15
   constructor(props) {
12
   constructor(props) {
16
     super(props);
13
     super(props);
17
   }
14
   }
35
     color: 'blue'
32
     color: 'blue'
36
   }
33
   }
37
 });
34
 });
38
-
39
-// every screen must be registered with a unique name
40
-Navigation.registerScreen('example.SideMenu', () => SideMenu);

+ 7
- 15
example/src/screens/StyledScreen.js View File

1
 import React, {
1
 import React, {
2
+  Component,
2
   Text,
3
   Text,
3
   View,
4
   View,
4
   ScrollView,
5
   ScrollView,
8
   AlertIOS
9
   AlertIOS
9
 } from 'react-native';
10
 } from 'react-native';
10
 
11
 
11
-// important imports, the magic is here
12
-import { Navigation, Screen } from 'react-native-navigation';
13
-
14
-// need to import every screen we push
15
-import './PushedScreen';
16
-import './StyledScreen';
17
-
18
-// instead of React.Component, we extend Screen (imported above)
19
-class StyledScreen extends Screen {
12
+export default class StyledScreen extends Component {
20
   static navigatorStyle = {
13
   static navigatorStyle = {
21
     drawUnderNavBar: true,
14
     drawUnderNavBar: true,
22
     drawUnderTabBar: true,
15
     drawUnderTabBar: true,
31
   };
24
   };
32
   constructor(props) {
25
   constructor(props) {
33
     super(props);
26
     super(props);
27
+    // if you want to listen on navigator events, set this up
28
+    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
34
   }
29
   }
35
   render() {
30
   render() {
36
     return (
31
     return (
63
     }
58
     }
64
   }
59
   }
65
   onPushPress() {
60
   onPushPress() {
66
-    this.navigator.push({
61
+    this.props.navigator.push({
67
       title: "More",
62
       title: "More",
68
       screen: "example.PushedScreen"
63
       screen: "example.PushedScreen"
69
     });
64
     });
70
   }
65
   }
71
   onPushStyledPress() {
66
   onPushStyledPress() {
72
-    this.navigator.push({
67
+    this.props.navigator.push({
73
       title: "More",
68
       title: "More",
74
       screen: "example.StyledScreen"
69
       screen: "example.StyledScreen"
75
     });
70
     });
76
   }
71
   }
77
   onPopPress() {
72
   onPopPress() {
78
-    this.navigator.pop();
73
+    this.props.navigator.pop();
79
   }
74
   }
80
 }
75
 }
81
 
76
 
88
     color: 'blue'
83
     color: 'blue'
89
   }
84
   }
90
 });
85
 });
91
-
92
-// every screen must be registered with a unique name
93
-Navigation.registerScreen('example.StyledScreen', () => StyledScreen);

+ 5
- 16
example/src/screens/ThirdTabScreen.js View File

1
 import React, {
1
 import React, {
2
+  Component,
2
   Text,
3
   Text,
3
   View,
4
   View,
4
   ScrollView,
5
   ScrollView,
6
   StyleSheet
7
   StyleSheet
7
 } from 'react-native';
8
 } from 'react-native';
8
 
9
 
9
-// important imports, the magic is here
10
-import { Navigation, Screen } from 'react-native-navigation';
11
-
12
-// need to import every screen we push
13
-import './PushedScreen';
14
-import './StyledScreen';
15
-import './ModalScreen';
16
-
17
-// instead of React.Component, we extend Screen (imported above)
18
-class ThirdTabScreen extends Screen {
10
+export default class ThirdTabScreen extends Component {
19
   constructor(props) {
11
   constructor(props) {
20
     super(props);
12
     super(props);
21
   }
13
   }
39
     );
31
     );
40
   }
32
   }
41
   onPushPress() {
33
   onPushPress() {
42
-    this.navigator.push({
34
+    this.props.navigator.push({
43
       title: "More",
35
       title: "More",
44
       screen: "example.PushedScreen"
36
       screen: "example.PushedScreen"
45
     });
37
     });
46
   }
38
   }
47
   onPushStyledPress() {
39
   onPushStyledPress() {
48
-    this.navigator.push({
40
+    this.props.navigator.push({
49
       title: "Styled",
41
       title: "Styled",
50
       screen: "example.StyledScreen"
42
       screen: "example.StyledScreen"
51
     });
43
     });
52
   }
44
   }
53
   onModalPress() {
45
   onModalPress() {
54
-    this.navigator.showModal({
46
+    this.props.navigator.showModal({
55
       title: "Modal",
47
       title: "Modal",
56
       screen: "example.ModalScreen"
48
       screen: "example.ModalScreen"
57
     });
49
     });
67
     color: 'blue'
59
     color: 'blue'
68
   }
60
   }
69
 });
61
 });
70
-
71
-// every screen must be registered with a unique name
72
-Navigation.registerScreen('example.ThirdTabScreen', () => ThirdTabScreen);

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

1
+import { Navigation } from 'react-native-navigation';
2
+
3
+import FirstTabScreen from './FirstTabScreen';
4
+import SecondTabScreen from './SecondTabScreen';
5
+import ThirdTabScreen from './ThirdTabScreen';
6
+import PushedScreen from './PushedScreen';
7
+import StyledScreen from './StyledScreen';
8
+import ModalScreen from './ModalScreen';
9
+import SideMenu from './SideMenu';
10
+
11
+// register all screens of the app (including internal ones)
12
+export function registerScreens() {
13
+  Navigation.registerComponent('example.FirstTabScreen', () => FirstTabScreen);
14
+  Navigation.registerComponent('example.SecondTabScreen', () => SecondTabScreen);
15
+  Navigation.registerComponent('example.ThirdTabScreen', () => ThirdTabScreen);
16
+  Navigation.registerComponent('example.PushedScreen', () => PushedScreen);
17
+  Navigation.registerComponent('example.StyledScreen', () => StyledScreen);
18
+  Navigation.registerComponent('example.ModalScreen', () => ModalScreen);
19
+  Navigation.registerComponent('example.SideMenu', () => SideMenu);
20
+}

+ 4
- 1
package.json View File

7
     "type": "git",
7
     "type": "git",
8
     "url": "https://github.com/wix/react-native-navigation.git"
8
     "url": "https://github.com/wix/react-native-navigation.git"
9
   },
9
   },
10
-  "version": "0.0.5",
10
+  "version": "0.1.0",
11
   "description": "React Native Navigation - truly native navigation for iOS and Android",
11
   "description": "React Native Navigation - truly native navigation for iOS and Android",
12
   "nativePackage": true,
12
   "nativePackage": true,
13
   "bugs": {
13
   "bugs": {
22
   },
22
   },
23
   "dependencies": {
23
   "dependencies": {
24
     "react-native-controllers": "^1.2.3"
24
     "react-native-controllers": "^1.2.3"
25
+  },
26
+  "optionalDependencies": {
27
+    "react-redux": "*"
25
   }
28
   }
26
 }
29
 }

+ 42
- 1
src/Navigation.js View File

1
-import { AppRegistry } from 'react-native';
1
+import React, { AppRegistry } from 'react-native';
2
 import platformSpecific from './platformSpecific';
2
 import platformSpecific from './platformSpecific';
3
+import Screen from './Screen';
3
 
4
 
4
 const registeredScreens = {};
5
 const registeredScreens = {};
5
 
6
 
8
   AppRegistry.registerComponent(screenID, generator);
9
   AppRegistry.registerComponent(screenID, generator);
9
 }
10
 }
10
 
11
 
12
+function registerComponent(screenID, generator, store = undefined, Provider = undefined) {
13
+  if (store && Provider) return _registerComponentRedux(screenID, generator, store, Provider);
14
+  else return _registerComponentNoRedux(screenID, generator);
15
+}
16
+
17
+function _registerComponentNoRedux(screenID, generator) {
18
+  const generatorWrapper = function() {
19
+    const InternalComponent = generator();
20
+    return class extends Screen {
21
+      static navigatorStyle = InternalComponent.navigatorStyle || {};
22
+      static navigatorButtons = InternalComponent.navigatorButtons || {};
23
+      render() {
24
+        return (
25
+          <InternalComponent navigator={this.navigator} {...this.props} />
26
+        );
27
+      }
28
+    };
29
+  }
30
+  registerScreen(screenID, generatorWrapper);
31
+}
32
+
33
+function _registerComponentRedux(screenID, generator, store, Provider) {
34
+  const generatorWrapper = function() {
35
+    const InternalComponent = generator();
36
+    return class extends Screen {
37
+      static navigatorStyle = InternalComponent.navigatorStyle || {};
38
+      static navigatorButtons = InternalComponent.navigatorButtons || {};
39
+      render() {
40
+        return (
41
+          <Provider store={store}>
42
+            <InternalComponent navigator={this.navigator} {...this.props} />
43
+          </Provider>
44
+        );
45
+      }
46
+    };
47
+  }
48
+  registerScreen(screenID, generatorWrapper);
49
+}
50
+
11
 function getRegisteredScreen(screenID) {
51
 function getRegisteredScreen(screenID) {
12
   const generator = registeredScreens[screenID];
52
   const generator = registeredScreens[screenID];
13
   if (!generator) {
53
   if (!generator) {
28
 export default Navigation = {
68
 export default Navigation = {
29
   registerScreen,
69
   registerScreen,
30
   getRegisteredScreen,
70
   getRegisteredScreen,
71
+  registerComponent,
31
   showModal,
72
   showModal,
32
   dismissModal,
73
   dismissModal,
33
   startTabBasedApp: platformSpecific.startTabBasedApp,
74
   startTabBasedApp: platformSpecific.startTabBasedApp,

+ 25
- 18
src/Screen.js View File

3
 import Navigation from './Navigation';
3
 import Navigation from './Navigation';
4
 
4
 
5
 class Navigator {
5
 class Navigator {
6
-  constructor(navigatorID, screenInstance) {
6
+  constructor(navigatorID, navigatorEventID) {
7
     this.navigatorID = navigatorID;
7
     this.navigatorID = navigatorID;
8
-    this.screenInstance = screenInstance;
8
+    this.navigatorEventID = navigatorEventID;
9
+    this.navigatorEventHandler = null;
10
+    this.navigatorEventSubscription = null;
9
   }
11
   }
10
   push(params = {}) {
12
   push(params = {}) {
11
     return platformSpecific.navigatorPush(this, params);
13
     return platformSpecific.navigatorPush(this, params);
26
     return Navigation.dismissModal(params);
28
     return Navigation.dismissModal(params);
27
   }
29
   }
28
   setButtons(params = {}) {
30
   setButtons(params = {}) {
29
-    const navigatorEventID = this.screenInstance.listenOnNavigatorEvents();
30
-    return platformSpecific.navigatorSetButtons(this, navigatorEventID, params);
31
+    return platformSpecific.navigatorSetButtons(this, this.navigatorEventID, params);
31
   }
32
   }
32
   setTitle(params = {}) {
33
   setTitle(params = {}) {
33
     return platformSpecific.navigatorSetTitle(this, params);
34
     return platformSpecific.navigatorSetTitle(this, params);
35
   toggleDrawer(params = {}) {
36
   toggleDrawer(params = {}) {
36
     return platformSpecific.navigatorToggleDrawer(this, params);
37
     return platformSpecific.navigatorToggleDrawer(this, params);
37
   }
38
   }
39
+  setOnNavigatorEvent(callback) {
40
+    this.navigatorEventHandler = callback;
41
+    if (!this.navigatorEventSubscription) {
42
+      this.navigatorEventSubscription = NativeAppEventEmitter.addListener(this.navigatorEventID, (event) => this.onNavigatorEvent(event));
43
+    }
44
+  }
45
+  onNavigatorEvent(event) {
46
+    if (this.navigatorEventHandler) {
47
+      this.navigatorEventHandler(event);
48
+    }
49
+  }
50
+  cleanup() {
51
+    if (this.navigatorEventSubscription) {
52
+      this.navigatorEventSubscription.remove();
53
+    }
54
+  }
38
 }
55
 }
39
 
56
 
40
 export default class Screen extends Component {
57
 export default class Screen extends Component {
43
   constructor(props) {
60
   constructor(props) {
44
     super(props);
61
     super(props);
45
     if (props.navigatorID) {
62
     if (props.navigatorID) {
46
-      this.navigator = new Navigator(props.navigatorID, this);
47
-    }
48
-    if (props.listenForEvents) {
49
-      this.listenOnNavigatorEvents();
63
+      this.navigator = new Navigator(props.navigatorID, props.navigatorEventID);
50
     }
64
     }
51
   }
65
   }
52
-  listenOnNavigatorEvents() {
53
-    if (!this.navigatorEventSubscription) {
54
-      this.navigatorEventSubscription = NativeAppEventEmitter.addListener(this.props.navigatorEventID, (event) => this.onNavigatorEvent(event));
55
-    }
56
-    return this.props.navigatorEventID;
57
-  }
58
-  onNavigatorEvent(event) {}
59
   componentWillUnmount() {
66
   componentWillUnmount() {
60
-    this.navigator = undefined;
61
-    if (this.navigatorEventSubscription) {
62
-      this.navigatorEventSubscription.remove();
67
+    if (this.navigator) {
68
+      this.navigator.cleanup();
69
+      this.navigator = undefined;
63
     }
70
     }
64
   }
71
   }
65
 }
72
 }

+ 2
- 7
src/platformSpecific.ios.js View File

58
                   passProps={{
58
                   passProps={{
59
                     navigatorID: navigatorID,
59
                     navigatorID: navigatorID,
60
                     screenInstanceID: screenInstanceID,
60
                     screenInstanceID: screenInstanceID,
61
-                    navigatorEventID: navigatorEventID,
62
-                    listenForEvents: !!(navigatorButtons.leftButtons || navigatorButtons.rightButtons)
61
+                    navigatorEventID: navigatorEventID
63
                   }}
62
                   }}
64
                   style={navigatorStyle}
63
                   style={navigatorStyle}
65
                   leftButtons={navigatorButtons.leftButtons}
64
                   leftButtons={navigatorButtons.leftButtons}
122
           passProps={{
121
           passProps={{
123
             navigatorID: navigatorID,
122
             navigatorID: navigatorID,
124
             screenInstanceID: screenInstanceID,
123
             screenInstanceID: screenInstanceID,
125
-            navigatorEventID: navigatorEventID,
126
-            listenForEvents: !!(navigatorButtons.leftButtons || navigatorButtons.rightButtons)
124
+            navigatorEventID: navigatorEventID
127
           }}
125
           }}
128
           style={navigatorStyle}
126
           style={navigatorStyle}
129
           leftButtons={navigatorButtons.leftButtons}
127
           leftButtons={navigatorButtons.leftButtons}
177
   passProps.navigatorID = navigator.navigatorID;
175
   passProps.navigatorID = navigator.navigatorID;
178
   passProps.screenInstanceID = screenInstanceID;
176
   passProps.screenInstanceID = screenInstanceID;
179
   passProps.navigatorEventID = navigatorEventID;
177
   passProps.navigatorEventID = navigatorEventID;
180
-  passProps.listenForEvents = !!(navigatorButtons.leftButtons || navigatorButtons.rightButtons);
181
   Controllers.NavigationControllerIOS(navigator.navigatorID).push({
178
   Controllers.NavigationControllerIOS(navigator.navigatorID).push({
182
     title: params.title,
179
     title: params.title,
183
     component: params.screen,
180
     component: params.screen,
217
   passProps.navigatorID = navigator.navigatorID;
214
   passProps.navigatorID = navigator.navigatorID;
218
   passProps.screenInstanceID = screenInstanceID;
215
   passProps.screenInstanceID = screenInstanceID;
219
   passProps.navigatorEventID = navigatorEventID;
216
   passProps.navigatorEventID = navigatorEventID;
220
-  passProps.listenForEvents = !!(navigatorButtons.leftButtons || navigatorButtons.rightButtons);
221
   Controllers.NavigationControllerIOS(navigator.navigatorID).resetTo({
217
   Controllers.NavigationControllerIOS(navigator.navigatorID).resetTo({
222
     title: params.title,
218
     title: params.title,
223
     component: params.screen,
219
     component: params.screen,
279
       passProps.navigatorID = navigatorID;
275
       passProps.navigatorID = navigatorID;
280
       passProps.screenInstanceID = screenInstanceID;
276
       passProps.screenInstanceID = screenInstanceID;
281
       passProps.navigatorEventID = navigatorEventID;
277
       passProps.navigatorEventID = navigatorEventID;
282
-      passProps.listenForEvents = !!(navigatorButtons.leftButtons || navigatorButtons.rightButtons);
283
       return (
278
       return (
284
         <NavigationControllerIOS
279
         <NavigationControllerIOS
285
           id={navigatorID}
280
           id={navigatorID}