Browse Source

pushes, start of lifecycle

Daniel Zlotin 7 years ago
parent
commit
7f7a586a08

+ 2
- 2
ios/RNN.m View File

@@ -43,11 +43,11 @@
43 43
 
44 44
 -(void)registerForJsEvents
45 45
 {
46
-	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onJavaScriptLoaded) name:RCTJavaScriptDidLoadNotification object:nil];
46
+	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onJavaScriptLoaded) name:RCTJavaScriptDidLoadNotification object:self.bridge];
47 47
 	
48 48
 #pragma GCC diagnostic push
49 49
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
50
-	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onJavaScriptDevReload) name:RCTReloadNotification object:nil];
50
+	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onJavaScriptDevReload) name:RCTReloadNotification object:self.bridge];
51 51
 #pragma GCC diagnostic pop
52 52
 }
53 53
 

+ 3
- 67
ios/RNNControllerFactory.m View File

@@ -1,63 +1,7 @@
1 1
 
2 2
 #import "RNNControllerFactory.h"
3
-
4
-#import "RNN.h"
5
-#import "RCTRootView.h"
6
-
7
-@interface RNNLayoutNode : NSObject
8
-@property NSString* type;
9
-@property NSString* nodeId;
10
-@property NSDictionary* data;
11
-@property NSArray* children;
12
-@end
13
-
14
-@implementation RNNLayoutNode
15
-
16
-+(instancetype)create:(NSDictionary *)json
17
-{
18
-	RNNLayoutNode* node = [RNNLayoutNode new];
19
-	node.type = json[@"type"];
20
-	node.nodeId = json[@"id"];
21
-	node.data = json[@"data"];
22
-	node.children = json[@"children"];
23
-	return node;
24
-}
25
-
26
--(BOOL)isContainer
27
-{
28
-	return [self.type isEqualToString:@"Container"];
29
-}
30
-
31
--(BOOL)isContainerStack
32
-{
33
-	return [self.type isEqualToString:@"ContainerStack"];
34
-}
35
-
36
--(BOOL)isTabs
37
-{
38
-	return [self.type isEqualToString:@"Tabs"];
39
-}
40
-
41
--(BOOL)isSideMenuRoot
42
-{
43
-	return [self.type isEqualToString:@"SideMenuRoot"];
44
-}
45
-
46
--(BOOL)isSideMenuLeft
47
-{
48
-	return [self.type isEqualToString:@"SideMenuLeft"];
49
-}
50
-
51
--(BOOL)isSideMenuRight
52
-{
53
-	return [self.type isEqualToString:@"SideMenuRight"];
54
-}
55
-
56
--(BOOL)isSideMenuCenter
57
-{
58
-	return [self.type isEqualToString:@"SideMenuCenter"];
59
-}
60
-@end
3
+#import "RNNLayoutNode.h"
4
+#import "RNNRootViewController.h"
61 5
 
62 6
 @implementation RNNControllerFactory
63 7
 
@@ -86,15 +30,7 @@
86 30
 
87 31
 -(UIViewController*)createContainer:(RNNLayoutNode*)node
88 32
 {
89
-	NSString* containerName = node.data[@"name"];
90
-	
91
-	RCTRootView *reactView = [[RCTRootView alloc] initWithBridge:RNN.instance.bridge
92
-													  moduleName:containerName
93
-											   initialProperties:@{@"id": node.nodeId}];
94
-	
95
-	UIViewController* controller = [UIViewController new];
96
-	controller.view = reactView;
97
-	return controller;
33
+	return [[RNNRootViewController alloc]initWithNode:node];
98 34
 }
99 35
 
100 36
 -(UINavigationController*)createContainerStack:(RNNLayoutNode*)node

+ 22
- 0
ios/RNNLayoutNode.h View File

@@ -0,0 +1,22 @@
1
+
2
+#import <Foundation/Foundation.h>
3
+#import <UIKit/UIKit.h>
4
+
5
+@interface RNNLayoutNode : NSObject
6
+
7
+@property NSString* type;
8
+@property NSString* nodeId;
9
+@property NSDictionary* data;
10
+@property NSArray* children;
11
+
12
++(instancetype)create:(NSDictionary *)json;
13
+
14
+-(BOOL)isContainer;
15
+-(BOOL)isContainerStack;
16
+-(BOOL)isTabs;
17
+-(BOOL)isSideMenuRoot;
18
+-(BOOL)isSideMenuLeft;
19
+-(BOOL)isSideMenuRight;
20
+-(BOOL)isSideMenuCenter;
21
+
22
+@end

+ 45
- 0
ios/RNNLayoutNode.m View File

@@ -0,0 +1,45 @@
1
+
2
+#import "RNNLayoutNode.h"
3
+
4
+@implementation RNNLayoutNode
5
+
6
++(instancetype)create:(NSDictionary *)json
7
+{
8
+	RNNLayoutNode* node = [RNNLayoutNode new];
9
+	node.type = json[@"type"];
10
+	node.nodeId = json[@"id"];
11
+	node.data = json[@"data"];
12
+	node.children = json[@"children"];
13
+	return node;
14
+}
15
+
16
+-(BOOL)isContainer
17
+{
18
+	return [self.type isEqualToString:@"Container"];
19
+}
20
+-(BOOL)isContainerStack
21
+{
22
+	return [self.type isEqualToString:@"ContainerStack"];
23
+}
24
+-(BOOL)isTabs
25
+{
26
+	return [self.type isEqualToString:@"Tabs"];
27
+}
28
+-(BOOL)isSideMenuRoot
29
+{
30
+	return [self.type isEqualToString:@"SideMenuRoot"];
31
+}
32
+-(BOOL)isSideMenuLeft
33
+{
34
+	return [self.type isEqualToString:@"SideMenuLeft"];
35
+}
36
+-(BOOL)isSideMenuRight
37
+{
38
+	return [self.type isEqualToString:@"SideMenuRight"];
39
+}
40
+-(BOOL)isSideMenuCenter
41
+{
42
+	return [self.type isEqualToString:@"SideMenuCenter"];
43
+}
44
+
45
+@end

+ 10
- 0
ios/RNNRootViewController.h View File

@@ -0,0 +1,10 @@
1
+
2
+#import <Foundation/Foundation.h>
3
+#import <UIKit/UIKit.h>
4
+#import "RNNLayoutNode.h"
5
+
6
+@interface RNNRootViewController : UIViewController
7
+
8
+-(instancetype)initWithNode:(RNNLayoutNode*)node;
9
+
10
+@end

+ 34
- 0
ios/RNNRootViewController.m View File

@@ -0,0 +1,34 @@
1
+
2
+#import "RNNRootViewController.h"
3
+#import "RCTRootView.h"
4
+#import "RNN.h"
5
+
6
+@interface RNNRootViewController()
7
+@end
8
+
9
+@implementation RNNRootViewController
10
+
11
+-(instancetype)initWithNode:(RNNLayoutNode*)node
12
+{
13
+	self = [super init];
14
+	NSString* containerName = node.data[@"name"];
15
+	
16
+	self.view = [[RCTRootView alloc] initWithBridge:RNN.instance.bridge
17
+													  moduleName:containerName
18
+											   initialProperties:@{@"id": node.nodeId}];
19
+	return self;
20
+}
21
+
22
+-(void)viewDidAppear:(BOOL)animated
23
+{
24
+	[super viewDidAppear:animated];
25
+	//send the event onAppear
26
+}
27
+
28
+-(void)viewDidDisappear:(BOOL)animated
29
+{
30
+	[super viewDidDisappear:animated];
31
+	//send the event onDisappear
32
+}
33
+
34
+@end

+ 16
- 0
ios/ReactNativeNavigation.xcodeproj/project.pbxproj View File

@@ -19,6 +19,10 @@
19 19
 		7BBFE5441E25330E002A6182 /* RNNBridgeModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BBFE5431E25330E002A6182 /* RNNBridgeModule.m */; };
20 20
 		7BBFE5611E253F97002A6182 /* RNN.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BBFE5601E253F97002A6182 /* RNN.m */; };
21 21
 		7BC9346E1E26886E00EFA125 /* RNNControllerFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BC9346D1E26886E00EFA125 /* RNNControllerFactory.m */; };
22
+		7BEF0D181E437684003E96B0 /* RNNRootViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BEF0D161E437684003E96B0 /* RNNRootViewController.h */; };
23
+		7BEF0D191E437684003E96B0 /* RNNRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BEF0D171E437684003E96B0 /* RNNRootViewController.m */; };
24
+		7BEF0D1C1E43771B003E96B0 /* RNNLayoutNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BEF0D1A1E43771B003E96B0 /* RNNLayoutNode.h */; };
25
+		7BEF0D1D1E43771B003E96B0 /* RNNLayoutNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */; };
22 26
 /* End PBXBuildFile section */
23 27
 
24 28
 /* Begin PBXCopyFilesBuildPhase section */
@@ -46,6 +50,10 @@
46 50
 		7BBFE5601E253F97002A6182 /* RNN.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNN.m; sourceTree = "<group>"; };
47 51
 		7BC9346C1E26886E00EFA125 /* RNNControllerFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNControllerFactory.h; sourceTree = "<group>"; };
48 52
 		7BC9346D1E26886E00EFA125 /* RNNControllerFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNControllerFactory.m; sourceTree = "<group>"; };
53
+		7BEF0D161E437684003E96B0 /* RNNRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNRootViewController.h; sourceTree = "<group>"; };
54
+		7BEF0D171E437684003E96B0 /* RNNRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNRootViewController.m; sourceTree = "<group>"; };
55
+		7BEF0D1A1E43771B003E96B0 /* RNNLayoutNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNLayoutNode.h; sourceTree = "<group>"; };
56
+		7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNLayoutNode.m; sourceTree = "<group>"; };
49 57
 		D8AFADBD1BEE6F3F00A4592D /* libReactNativeNavigation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativeNavigation.a; sourceTree = BUILT_PRODUCTS_DIR; };
50 58
 /* End PBXFileReference section */
51 59
 
@@ -65,8 +73,12 @@
65 73
 			children = (
66 74
 				7BA500761E254908001B9E1B /* RNNSplashScreen.h */,
67 75
 				7BA500771E254908001B9E1B /* RNNSplashScreen.m */,
76
+				7BEF0D1A1E43771B003E96B0 /* RNNLayoutNode.h */,
77
+				7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */,
68 78
 				7BC9346C1E26886E00EFA125 /* RNNControllerFactory.h */,
69 79
 				7BC9346D1E26886E00EFA125 /* RNNControllerFactory.m */,
80
+				7BEF0D161E437684003E96B0 /* RNNRootViewController.h */,
81
+				7BEF0D171E437684003E96B0 /* RNNRootViewController.m */,
70 82
 			);
71 83
 			name = Controllers;
72 84
 			sourceTree = "<group>";
@@ -116,9 +128,11 @@
116 128
 				7B1126A41E2D2B6C00F9B03B /* ReactNativeNavigation.h in Headers */,
117 129
 				7B1126A31E2D2B6C00F9B03B /* RNNSplashScreen.h in Headers */,
118 130
 				7B1126A51E2D2B6C00F9B03B /* RNN.h in Headers */,
131
+				7BEF0D181E437684003E96B0 /* RNNRootViewController.h in Headers */,
119 132
 				7B1126A61E2D2B6C00F9B03B /* RNNBridgeModule.h in Headers */,
120 133
 				7B1126A71E2D2B6C00F9B03B /* RNNEventEmitter.h in Headers */,
121 134
 				7B1126A91E2D2B6C00F9B03B /* RNNControllerFactory.h in Headers */,
135
+				7BEF0D1C1E43771B003E96B0 /* RNNLayoutNode.h in Headers */,
122 136
 			);
123 137
 			runOnlyForDeploymentPostprocessing = 0;
124 138
 		};
@@ -179,9 +193,11 @@
179 193
 			isa = PBXSourcesBuildPhase;
180 194
 			buildActionMask = 2147483647;
181 195
 			files = (
196
+				7BEF0D191E437684003E96B0 /* RNNRootViewController.m in Sources */,
182 197
 				7B1126A01E2D263F00F9B03B /* RNNEventEmitter.m in Sources */,
183 198
 				7BA500751E2544B9001B9E1B /* ReactNativeNavigation.m in Sources */,
184 199
 				7BBFE5441E25330E002A6182 /* RNNBridgeModule.m in Sources */,
200
+				7BEF0D1D1E43771B003E96B0 /* RNNLayoutNode.m in Sources */,
185 201
 				7BA500781E254908001B9E1B /* RNNSplashScreen.m in Sources */,
186 202
 				7BBFE5611E253F97002A6182 /* RNN.m in Sources */,
187 203
 				7BC9346E1E26886E00EFA125 /* RNNControllerFactory.m in Sources */,

+ 5
- 0
playground/e2e/app.test.js View File

@@ -23,6 +23,11 @@ describe('app', () => {
23 23
     elementByLabel('Switch to tab based app with side menus').swipeRight();
24 24
     expect(elementByLabel('This is a side menu screen')).toBeVisible();
25 25
   });
26
+
27
+  xit('screen lifecycle', () => {
28
+    elementByLabel('Switch to lifecycle screen').tap();
29
+    expect(elementByLabel('Appeared!')).toBeVisible();
30
+  });
26 31
 });
27 32
 
28 33
 function elementByLabel(label) {

+ 42
- 0
playground/src/containers/LifecycleScreen.js View File

@@ -0,0 +1,42 @@
1
+import React, { Component } from 'react';
2
+import { View, Text } from 'react-native';
3
+
4
+class LifecycleScreen extends Component {
5
+  constructor(props) {
6
+    super(props);
7
+    this.state = {
8
+      text: 'nothing yet'
9
+    };
10
+  }
11
+
12
+  onAppear() {
13
+    this.setState({ text: 'Appeared!' });
14
+  }
15
+
16
+  onDisappear() {
17
+    this.setState({ text: 'Disappeared!' });
18
+  }
19
+
20
+  render() {
21
+    return (
22
+      <View style={styles.root}>
23
+        <Text style={styles.h1}>{this.state.text}</Text>
24
+      </View>
25
+    );
26
+  }
27
+}
28
+export default LifecycleScreen;
29
+
30
+const styles = {
31
+  root: {
32
+    flexGrow: 1,
33
+    justifyContent: 'center',
34
+    alignItems: 'center',
35
+    backgroundColor: '#f5fcff'
36
+  },
37
+  h1: {
38
+    fontSize: 24,
39
+    textAlign: 'center',
40
+    margin: 10
41
+  }
42
+};

+ 7
- 0
playground/src/containers/WelcomeScreen.js View File

@@ -15,6 +15,7 @@ class WelcomeScreen extends Component {
15 15
         <Text style={styles.h1}>{`React Native Navigation!`}</Text>
16 16
         <Button title="Switch to tab based app" onPress={this.onClickSwitchToTabs} />
17 17
         <Button title="Switch to app with side menus" onPress={this.onClickSwitchToSideMenus} />
18
+        <Button title="Switch to lifecycle screen" onPress={this.onClickLifecycleScreen} />
18 19
         <Button title="Push" onPress={this.onClickPush} />
19 20
         <Text style={styles.footer}>{`this.props.id = ${this.props.id}`}</Text>
20 21
       </View>
@@ -87,6 +88,12 @@ class WelcomeScreen extends Component {
87 88
       }
88 89
     });
89 90
   }
91
+
92
+  onClickLifecycleScreen() {
93
+    Navigation.on(this.props.id).push({
94
+      name: 'com.example.LifecycleScreen'
95
+    });
96
+  }
90 97
 }
91 98
 
92 99
 export default WelcomeScreen;

+ 2
- 0
playground/src/containers/index.js View File

@@ -2,8 +2,10 @@ import Navigation from 'react-native-navigation';
2 2
 
3 3
 import WelcomeScreen from './WelcomeScreen';
4 4
 import SimpleScreen from './SimpleScreen';
5
+import LifecycleScreen from './LifecycleScreen';
5 6
 
6 7
 export function registerContainers() {
7 8
   Navigation.registerContainer(`com.example.WelcomeScreen`, () => WelcomeScreen);
8 9
   Navigation.registerContainer(`com.example.SimpleScreen`, () => SimpleScreen);
10
+  Navigation.registerContainer(`com.example.LifecycleScreen`, () => LifecycleScreen);
9 11
 }

+ 1
- 0
src/containers/ContainerWrapper.js View File

@@ -25,6 +25,7 @@ export default class ContainerWrapper {
25 25
           <OriginalContainer
26 26
             {...this.state.allProps}
27 27
             id={this.state.id}
28
+            key={this.state.id}
28 29
           />
29 30
         );
30 31
       }

+ 30
- 3
src/containers/ContainerWrapper.test.js View File

@@ -1,3 +1,4 @@
1
+/* eslint-disable consistent-this, react/no-multi-comp */
1 2
 import React, { Component } from 'react';
2 3
 import { AppRegistry, Text } from 'react-native';
3 4
 import renderer from 'react-test-renderer';
@@ -14,7 +15,7 @@ describe('ContainerWrapper', () => {
14 15
   class MyContainer extends Component {
15 16
     constructor(props) {
16 17
       super(props);
17
-      myContainerRef = this; //eslint-disable-line
18
+      myContainerRef = this;
18 19
     }
19 20
 
20 21
     render() {
@@ -22,10 +23,10 @@ describe('ContainerWrapper', () => {
22 23
     }
23 24
   }
24 25
 
25
-  class TestParent extends Component { //eslint-disable-line
26
+  class TestParent extends Component {
26 27
     constructor(props) {
27 28
       super(props);
28
-      testParentRef = this; //eslint-disable-line
29
+      testParentRef = this;
29 30
       this.ChildClass = props.ChildClass;
30 31
       this.state = { propsFromState: {} };
31 32
     }
@@ -96,4 +97,30 @@ describe('ContainerWrapper', () => {
96 97
     testParentRef.setState({ propsFromState: { id: 'ERROR' } });
97 98
     expect(myContainerRef.props.id).toEqual('container1');
98 99
   });
100
+
101
+  it('assignes key by id', () => {
102
+    const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store);
103
+    renderer.create(<NavigationContainer id={'container123'} />);
104
+    expect(myContainerRef.props.id).toEqual('container123');
105
+    expect(myContainerRef._reactInternalInstance._currentElement.key).toEqual('container123');
106
+  });
107
+
108
+  xdescribe('container lifecycle', () => {
109
+    const onStartCallback = jest.fn();
110
+    const onStopCallback = jest.fn();
111
+
112
+    class MyLifecycleContainer extends MyContainer {
113
+      onStart() {
114
+        onStartCallback();
115
+      }
116
+
117
+      onStop() {
118
+        onStopCallback();
119
+      }
120
+    }
121
+
122
+    it('', () => {
123
+      //
124
+    });
125
+  });
99 126
 });