Browse Source

V2 overlays (#2510)

* overlay support
yogevbd 6 years ago
parent
commit
1446cd2fe9
No account linked to committer's email address

+ 26
- 0
e2e/ScreenStack.test.js View File

@@ -59,4 +59,30 @@ describe('screen stack', () => {
59 59
     await elementById(testIDs.SWITCH_FIRST_TAB_BUTTON).tap();
60 60
     await expect(elementByLabel('This is tab 1')).toBeVisible();
61 61
   });
62
+
63
+  it('show and dismiss overlay', async () => {
64
+    await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
65
+    await elementById(testIDs.SHOW_OVERLAY_BUTTON).tap();
66
+    await expect(elementById(testIDs.DIALOG_HEADER)).toBeVisible();
67
+    await elementById(testIDs.OK_BUTTON).tap();
68
+    await expect(elementById(testIDs.DIALOG_HEADER)).toBeNotVisible();
69
+  });
70
+
71
+  it('overlay pass touches - true', async () => {
72
+    await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
73
+    await elementById(testIDs.SHOW_TOUCH_THROUGH_OVERLAY_BUTTON).tap();
74
+    await expect(elementById(testIDs.DIALOG_HEADER)).toBeVisible();
75
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeVisible();
76
+    await elementById(testIDs.HIDE_TOP_BAR_BUTTON).tap();
77
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeNotVisible();
78
+  });
79
+
80
+  it('overlay pass touches - false', async () => {
81
+    await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
82
+    await elementById(testIDs.SHOW_OVERLAY_BUTTON).tap();
83
+    await expect(elementById(testIDs.DIALOG_HEADER)).toBeVisible();
84
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeVisible();
85
+    await elementById(testIDs.HIDE_TOP_BAR_BUTTON).tap();
86
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeVisible();
87
+  });
62 88
 });

+ 12
- 0
lib/ios/RNNBridgeModule.m View File

@@ -78,5 +78,17 @@ RCT_EXPORT_METHOD(dismissAllModals:(RCTPromiseResolveBlock)resolve rejecter:(RCT
78 78
 	}];
79 79
 }
80 80
 
81
+RCT_EXPORT_METHOD(showOverlay:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
82
+	[_commandsHandler showOverlay:layout completion:^{
83
+		resolve(layout[@"id"]);
84
+	}];
85
+}
86
+
87
+RCT_EXPORT_METHOD(dismissOverlay:(NSString*)componentId resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
88
+	[_commandsHandler dismissOverlay:componentId completion:^{
89
+		resolve(@(1));
90
+	}];
91
+}
92
+
81 93
 @end
82 94
 

+ 4
- 0
lib/ios/RNNCommandsHandler.h View File

@@ -28,4 +28,8 @@
28 28
 
29 29
 -(void) dismissAllModalsWithCompletion:(RNNTransitionCompletionBlock)completion;
30 30
 
31
+-(void)showOverlay:(NSDictionary *)layout completion:(RNNTransitionCompletionBlock)completion;
32
+
33
+-(void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion;
34
+
31 35
 @end

+ 14
- 0
lib/ios/RNNCommandsHandler.m View File

@@ -1,6 +1,7 @@
1 1
 #import "RNNCommandsHandler.h"
2 2
 #import "RNNModalManager.h"
3 3
 #import "RNNNavigationStackManager.h"
4
+#import "RNNOverlayManager.h"
4 5
 #import "RNNNavigationOptions.h"
5 6
 #import "RNNRootViewController.h"
6 7
 #import "React/RCTUIManager.h"
@@ -10,6 +11,7 @@
10 11
 	RNNStore *_store;
11 12
 	RNNNavigationStackManager* _navigationStackManager;
12 13
 	RNNModalManager* _modalManager;
14
+	RNNOverlayManager* _overlayManager;
13 15
 }
14 16
 
15 17
 -(instancetype) initWithStore:(RNNStore*)store controllerFactory:(RNNControllerFactory*)controllerFactory {
@@ -18,6 +20,7 @@
18 20
 	_controllerFactory = controllerFactory;
19 21
 	_navigationStackManager = [[RNNNavigationStackManager alloc] initWithStore:_store];
20 22
 	_modalManager = [[RNNModalManager alloc] initWithStore:_store];
23
+	_overlayManager = [[RNNOverlayManager alloc] init];
21 24
 	return self;
22 25
 }
23 26
 
@@ -128,6 +131,17 @@
128 131
 	[CATransaction commit];
129 132
 }
130 133
 
134
+-(void)showOverlay:(NSDictionary *)layout completion:(RNNTransitionCompletionBlock)completion {
135
+	[self assertReady];
136
+	UIViewController* overlayVC = [_controllerFactory createOverlay:layout];
137
+	[_overlayManager showOverlay:overlayVC completion:completion];
138
+}
139
+
140
+- (void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion {
141
+	[self assertReady];
142
+	[_overlayManager dismissOverlay:componentId completion:completion];
143
+}
144
+
131 145
 #pragma mark - private
132 146
 
133 147
 -(void) assertReady {

+ 3
- 0
lib/ios/RNNControllerFactory.h View File

@@ -15,6 +15,9 @@
15 15
 
16 16
 -(UIViewController<RNNRootViewProtocol> *)createLayoutAndSaveToStore:(NSDictionary*)layout;
17 17
 
18
+-(UIViewController *)createOverlay:(NSDictionary*)layout;
19
+
18 20
 @property (nonatomic, strong) RNNNavigationOptions* defaultOptions;
19 21
 
22
+
20 23
 @end

+ 12
- 1
lib/ios/RNNControllerFactory.m View File

@@ -162,6 +162,17 @@
162 162
 	return sideMenuChild;
163 163
 }
164 164
 
165
-
165
+- (UIViewController *)createOverlay:(NSDictionary*)layout {
166
+	UIViewController *vc = [self fromTree:layout];
167
+	NSDictionary* options = layout[@"data"][@"options"];
168
+	RCTRootView* rootView = (RCTRootView*)vc.view;
169
+	rootView.passThroughTouches = ![options[@"interceptTouches"] boolValue];
170
+	rootView.backgroundColor = [UIColor clearColor];
171
+	CGSize availableSize = UIApplication.sharedApplication.delegate.window.bounds.size;
172
+	rootView.frame = CGRectMake(0, 0, availableSize.width, availableSize.height);
173
+	[_bridge.uiManager setAvailableSize:availableSize forRootView:vc.view];
174
+	
175
+	return vc;
176
+}
166 177
 
167 178
 @end

+ 10
- 0
lib/ios/RNNOverlayManager.h View File

@@ -0,0 +1,10 @@
1
+#import <Foundation/Foundation.h>
2
+#import <UIKit/UIKit.h>
3
+#import "RNNStore.h"
4
+
5
+@interface RNNOverlayManager : NSObject
6
+
7
+- (void)showOverlay:(UIViewController*)viewController completion:(RNNTransitionCompletionBlock)completion;
8
+- (void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion;
9
+
10
+@end

+ 38
- 0
lib/ios/RNNOverlayManager.m View File

@@ -0,0 +1,38 @@
1
+#import "RNNOverlayManager.h"
2
+
3
+@implementation RNNOverlayManager {
4
+	NSMutableDictionary* _overlayDict;
5
+}
6
+
7
+- (instancetype)init {
8
+	self = [super init];
9
+	_overlayDict = [[NSMutableDictionary alloc] init];
10
+	return self;
11
+}
12
+
13
+#pragma mark - public
14
+
15
+- (void)showOverlay:(RNNRootViewController *)viewController completion:(RNNTransitionCompletionBlock)completion {
16
+	[self cacheOverlay:viewController];
17
+	[[[UIApplication sharedApplication] keyWindow] addSubview:viewController.view];
18
+	completion();
19
+}
20
+
21
+- (void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion {
22
+	RNNRootViewController* viewController = [_overlayDict objectForKey:componentId];
23
+	[self removeCachedOverlay:viewController];
24
+	completion();
25
+}
26
+
27
+#pragma mark - private
28
+
29
+- (void)cacheOverlay:(RNNRootViewController*)viewController {
30
+	[_overlayDict setObject:viewController forKey:viewController.componentId];
31
+}
32
+
33
+- (void)removeCachedOverlay:(RNNRootViewController*)viewController {
34
+	[viewController.view removeFromSuperview];
35
+	[_overlayDict removeObjectForKey:viewController.componentId];
36
+}
37
+
38
+@end

+ 20
- 4
lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj View File

@@ -76,6 +76,8 @@
76 76
 		507F44201FFA8A8800D9425B /* RNNRootViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 507F441F1FFA8A8800D9425B /* RNNRootViewProtocol.h */; };
77 77
 		50CB3B691FDE911400AA153B /* RNNSideMenuOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */; };
78 78
 		50CB3B6A1FDE911400AA153B /* RNNSideMenuOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50CB3B681FDE911400AA153B /* RNNSideMenuOptions.m */; };
79
+		50D031342005149000386B3D /* RNNOverlayManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 50D031322005149000386B3D /* RNNOverlayManager.h */; };
80
+		50D031352005149000386B3D /* RNNOverlayManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 50D031332005149000386B3D /* RNNOverlayManager.m */; };
79 81
 		50EB93421FE14A3E00BD8EEE /* RNNBottomTabOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50EB93401FE14A3E00BD8EEE /* RNNBottomTabOptions.m */; };
80 82
 		50F5DFC11F407A8C001A00BC /* RNNTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 50F5DFBF1F407A8C001A00BC /* RNNTabBarController.h */; };
81 83
 		50F5DFC21F407A8C001A00BC /* RNNTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F5DFC01F407A8C001A00BC /* RNNTabBarController.m */; };
@@ -240,6 +242,8 @@
240 242
 		507F441F1FFA8A8800D9425B /* RNNRootViewProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNRootViewProtocol.h; sourceTree = "<group>"; };
241 243
 		50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSideMenuOptions.h; sourceTree = "<group>"; };
242 244
 		50CB3B681FDE911400AA153B /* RNNSideMenuOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNSideMenuOptions.m; sourceTree = "<group>"; };
245
+		50D031322005149000386B3D /* RNNOverlayManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNOverlayManager.h; sourceTree = "<group>"; };
246
+		50D031332005149000386B3D /* RNNOverlayManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNOverlayManager.m; sourceTree = "<group>"; };
243 247
 		50EB933F1FE14A3E00BD8EEE /* RNNBottomTabOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNBottomTabOptions.h; sourceTree = "<group>"; };
244 248
 		50EB93401FE14A3E00BD8EEE /* RNNBottomTabOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNBottomTabOptions.m; sourceTree = "<group>"; };
245 249
 		50F5DFBF1F407A8C001A00BC /* RNNTabBarController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTabBarController.h; sourceTree = "<group>"; };
@@ -459,16 +463,26 @@
459 463
 			name = HMSegmentControl;
460 464
 			sourceTree = "<group>";
461 465
 		};
462
-		7B1E4C4B1E2D173700C3A525 /* Controllers */ = {
466
+		50D031312005146C00386B3D /* Managers */ = {
463 467
 			isa = PBXGroup;
464 468
 			children = (
465
-				E8AEDB471F584175000F5A6A /* Components */,
466
-				E8AEDB461F58414D000F5A6A /* Animations */,
467
-				504AFE611FFE52EF0076E904 /* Options */,
468 469
 				261F0E621E6EC94900989DE2 /* RNNModalManager.h */,
469 470
 				261F0E631E6EC94900989DE2 /* RNNModalManager.m */,
470 471
 				261F0E681E6F028A00989DE2 /* RNNNavigationStackManager.h */,
471 472
 				261F0E691E6F028A00989DE2 /* RNNNavigationStackManager.m */,
473
+				50D031322005149000386B3D /* RNNOverlayManager.h */,
474
+				50D031332005149000386B3D /* RNNOverlayManager.m */,
475
+			);
476
+			name = Managers;
477
+			sourceTree = "<group>";
478
+		};
479
+		7B1E4C4B1E2D173700C3A525 /* Controllers */ = {
480
+			isa = PBXGroup;
481
+			children = (
482
+				E8AEDB471F584175000F5A6A /* Components */,
483
+				E8AEDB461F58414D000F5A6A /* Animations */,
484
+				504AFE611FFE52EF0076E904 /* Options */,
485
+				50D031312005146C00386B3D /* Managers */,
472 486
 				26916C941E4B9CCC00D13680 /* RNNRootViewCreator.h */,
473 487
 				26916C961E4B9E7700D13680 /* RNNReactRootViewCreator.h */,
474 488
 				26916C971E4B9E7700D13680 /* RNNReactRootViewCreator.m */,
@@ -668,6 +682,7 @@
668 682
 				E8DA24401F97459B00CD552B /* RNNElementFinder.h in Headers */,
669 683
 				263905BE1E4C6F440023D7D3 /* RCCTheSideBarManagerViewController.h in Headers */,
670 684
 				263905CE1E4C6F440023D7D3 /* TheSidebarController.h in Headers */,
685
+				50D031342005149000386B3D /* RNNOverlayManager.h in Headers */,
671 686
 				7B1126A71E2D2B6C00F9B03B /* RNNEventEmitter.h in Headers */,
672 687
 				E8A430111F9CB87B00B61A20 /* RNNAnimatedView.h in Headers */,
673 688
 				268692821E5054F800E2C612 /* RNNStore.h in Headers */,
@@ -850,6 +865,7 @@
850 865
 				268692831E5054F800E2C612 /* RNNStore.m in Sources */,
851 866
 				7BC9346E1E26886E00EFA125 /* RNNControllerFactory.m in Sources */,
852 867
 				507F43F91FF525B500D9425B /* RNNSegmentedControl.m in Sources */,
868
+				50D031352005149000386B3D /* RNNOverlayManager.m in Sources */,
853 869
 				E8E5182F1F83A48B000467AC /* RNNTransitionStateHolder.m in Sources */,
854 870
 				263905B61E4C6F440023D7D3 /* MMExampleDrawerVisualStateManager.m in Sources */,
855 871
 				E8E518331F83B3E0000467AC /* RNNUtils.m in Sources */,

+ 15
- 7
lib/src/Navigation.js View File

@@ -119,18 +119,26 @@ class Navigation {
119 119
   }
120 120
 
121 121
   /**
122
-   * Obtain the events registery instance
122
+   * Show overlay on top of the window
123
+   * @param {*} params
123 124
    */
124
-  events() {
125
-    return this.publicEventsRegistry;
125
+  showOverlay(params) {
126
+    return this.commands.showOverlay(params);
126 127
   }
127 128
 
128
-  showOverlay(type, options) {
129
-    return this.commands.showOverlay(type, options);
129
+  /**
130
+   * dismiss overlay by componentId
131
+   * @param {string} componentId
132
+   */
133
+  dismissOverlay(componentId) {
134
+    return this.commands.dismissOverlay(componentId);
130 135
   }
131 136
 
132
-  dismissOverlay() {
133
-    return this.commands.dismissOverlay();
137
+  /**
138
+   * Obtain the events registery instance
139
+   */
140
+  events() {
141
+    return this.publicEventsRegistry;
134 142
   }
135 143
 }
136 144
 

+ 4
- 5
lib/src/adapters/NativeCommandsSender.js View File

@@ -47,13 +47,12 @@ class NativeCommandsSender {
47 47
     return this.nativeCommandsModule.dismissAllModals();
48 48
   }
49 49
 
50
-  showOverlay(type, options) {
51
-    return this.nativeCommandsModule.showOverlay(type, options);
50
+  showOverlay(layout) {
51
+    return this.nativeCommandsModule.showOverlay(layout);
52 52
   }
53 53
 
54
-  dismissOverlay() {
55
-    this.nativeCommandsModule.dismissOverlay();
56
-    return Promise.resolve(true);
54
+  dismissOverlay(componentId) {
55
+    return this.nativeCommandsModule.dismissOverlay(componentId);
57 56
   }
58 57
 }
59 58
 

+ 12
- 16
lib/src/commands/Commands.js View File

@@ -62,22 +62,18 @@ class Commands {
62 62
     return this.nativeCommandsSender.popToRoot(componentId);
63 63
   }
64 64
 
65
-  // showOverlay(type, options) {
66
-    // let promise;
67
-    // if (type === 'custom') {
68
-    //   const layout = this.layoutTreeParser.createDialogComponent({ name: options });
69
-    //   this.layoutTreeCrawler.crawl(layout);
70
-    //   promise = this.nativeCommandsSender.showOverlay(type, layout);
71
-    // } else {
72
-    //   const input = _.cloneDeep(options);
73
-    //   OptionsProcessor.processOptions(input);
74
-    //   promise = this.nativeCommandsSender.showOverlay(type, input);
75
-    // }
76
-    // return promise;
77
-  // }
78
-
79
-  dismissOverlay() {
80
-    return this.nativeCommandsSender.dismissOverlay();
65
+  showOverlay(componentData) {
66
+    const input = _.cloneDeep(componentData);
67
+    OptionsProcessor.processOptions(input);
68
+
69
+    const layout = this.layoutTreeParser.parse(input);
70
+    this.layoutTreeCrawler.crawl(layout);
71
+
72
+    return this.nativeCommandsSender.showOverlay(layout);
73
+  }
74
+
75
+  dismissOverlay(componentId) {
76
+    return this.nativeCommandsSender.dismissOverlay(componentId);
81 77
   }
82 78
 }
83 79
 

+ 36
- 10
lib/src/commands/Commands.test.js View File

@@ -238,24 +238,50 @@ describe('Commands', () => {
238 238
     });
239 239
   });
240 240
 
241
-  xdescribe('showOverlay', () => {
241
+  describe('showOverlay', () => {
242
+    it('sends command to native after parsing into a correct layout tree', () => {
243
+      uut.showOverlay({
244
+        component: {
245
+          name: 'com.example.MyScreen'
246
+        }
247
+      });
248
+      expect(mockCommandsSender.showOverlay).toHaveBeenCalledTimes(1);
249
+      expect(mockCommandsSender.showOverlay).toHaveBeenCalledWith({
250
+        type: 'Component',
251
+        id: 'Component+UNIQUE_ID',
252
+        data: {
253
+          name: 'com.example.MyScreen',
254
+          options: {}
255
+        },
256
+        children: []
257
+      });
258
+    });
259
+
242 260
     it('deep clones input to avoid mutation errors', () => {
243
-      const obj = { title: 'test' };
244
-      uut.showOverlay('alert', obj);
245
-      expect(mockCommandsSender.showOverlay.mock.calls[0][1]).not.toBe(obj);
261
+      const obj = {};
262
+      uut.showOverlay({ component: { name: 'name', inner: obj } });
263
+      expect(mockCommandsSender.showOverlay.mock.calls[0][0].data.inner).not.toBe(obj);
246 264
     });
247 265
 
248
-    it('resolves with the parsed layout', async () => {
249
-      mockCommandsSender.showOverlay.mockReturnValue(Promise.resolve('result'));
250
-      const result = await uut.showOverlay('custom', 'com.example.MyScreen');
251
-      expect(result).toEqual('result');
266
+    it('resolves with the component id', async () => {
267
+      mockCommandsSender.showOverlay.mockReturnValue(Promise.resolve('Component1'));
268
+      const result = await uut.showOverlay({ component: { name: 'com.example.MyScreen' } });
269
+      expect(result).toEqual('Component1');
252 270
     });
253 271
   });
254 272
 
255 273
   describe('dismissOverlay', () => {
256
-    it('check promis returns true', () => {
257
-      uut.dismissOverlay();
274
+    it('check promise returns true', async () => {
275
+      mockCommandsSender.dismissOverlay.mockReturnValue(Promise.resolve(true));
276
+      const result = await uut.dismissOverlay('Component1');
277
+      expect(mockCommandsSender.dismissOverlay).toHaveBeenCalledTimes(1);
278
+      expect(result).toEqual(true);
279
+    });
280
+
281
+    it('send command to native with componentId', () => {
282
+      uut.dismissOverlay('Component1');
258 283
       expect(mockCommandsSender.dismissOverlay).toHaveBeenCalledTimes(1);
284
+      expect(mockCommandsSender.dismissOverlay).toHaveBeenCalledWith('Component1');
259 285
     });
260 286
   });
261 287
 });

+ 11
- 5
playground/src/screens/CustomDialog.js View File

@@ -4,28 +4,34 @@ const { PureComponent } = require('react');
4 4
 const { View, Text, Button } = require('react-native');
5 5
 const Navigation = require('react-native-navigation');
6 6
 
7
+const testIDs = require('../testIDs');
8
+
7 9
 class CustomDialog extends PureComponent {
8 10
 
9 11
   render() {
10 12
     return (
11 13
       <View style={styles.root}>
12
-        <Text style={styles.h1}>Test view</Text>
13
-        <Button title="OK" onPress={this.onCLickOk} />
14
+        <Text style={styles.h1} testID={testIDs.DIALOG_HEADER}>Test view</Text>
15
+        <Button title="OK" testID={testIDs.OK_BUTTON} onPress={() => this.onCLickOk()} />
14 16
       </View>
15 17
     );
16 18
   }
17 19
 
18 20
   onCLickOk() {
19
-    Navigation.dismissOverlay();
21
+    Navigation.dismissOverlay(this.props.componentId);
20 22
   }
21 23
 }
22 24
 
23 25
 const styles = {
24 26
   root: {
25
-    flex: 1,
26 27
     backgroundColor: 'green',
27 28
     justifyContent: 'center',
28
-    alignItems: 'center'
29
+    alignItems: 'center',
30
+    height: 100,
31
+    bottom: 0,
32
+    position: 'absolute',
33
+    left: 0,
34
+    right: 0
29 35
   },
30 36
   h1: {
31 37
     fontSize: 24,

+ 13
- 0
playground/src/screens/OptionsScreen.js View File

@@ -16,6 +16,7 @@ class OptionsScreen extends Component {
16 16
       topBar: {
17 17
         title: 'Static Title',
18 18
         textColor: 'black',
19
+        drawUnder: false,
19 20
         largeTitle: false,
20 21
         hidden: false,
21 22
         textFontSize: 16,
@@ -48,6 +49,7 @@ class OptionsScreen extends Component {
48 49
     this.onClickTopBarTransparent = this.onClickTopBarTransparent.bind(this);
49 50
     this.onClickTopBarOpaque = this.onClickTopBarOpaque.bind(this);
50 51
     this.onClickCustomTranstition = this.onClickCustomTranstition.bind(this);
52
+    this.onClickShowOverlay = this.onClickShowOverlay.bind(this);
51 53
     this.onClickPushDefaultOptionsScreen = this.onClickPushDefaultOptionsScreen.bind(this);
52 54
   }
53 55
 
@@ -64,6 +66,8 @@ class OptionsScreen extends Component {
64 66
         <Button title="Custom Transition" onPress={this.onClickCustomTranstition} />
65 67
         <Button title="Show custom alert" testID={testIDs.SHOW_CUSTOM_ALERT_BUTTON} onPress={this.onClickAlert} />
66 68
         <Button title="Show snackbar" testID={testIDs.SHOW_SNACKBAR_BUTTON} onPress={this.onClickSnackbar} />
69
+        <Button title="Show overlay" testID={testIDs.SHOW_OVERLAY_BUTTON} onPress={() => this.onClickShowOverlay(true)} />
70
+        <Button title="Show touch through overlay" testID={testIDs.SHOW_TOUCH_THROUGH_OVERLAY_BUTTON} onPress={() => this.onClickShowOverlay(false)} />
67 71
         <Button title="Push Default Options Screen" testID={testIDs.PUSH_DEFAULT_OPTIONS_BUTTON} onPress={this.onClickPushDefaultOptionsScreen} />
68 72
         <Text style={styles.footer}>{`this.props.containerId = ${this.props.containerId}`}</Text>
69 73
       </View>
@@ -190,6 +194,15 @@ class OptionsScreen extends Component {
190 194
     });
191 195
   }
192 196
 
197
+  onClickShowOverlay(interceptTouches) {
198
+    Navigation.showOverlay({
199
+      component: {
200
+        name: 'navigation.playground.CustomDialog',
201
+        options: { interceptTouches }
202
+      }
203
+    });
204
+  }
205
+
193 206
   onClickPushDefaultOptionsScreen() {
194 207
     Navigation.setDefaultOptions({
195 208
       topBar: {

+ 5
- 1
playground/src/testIDs.js View File

@@ -46,6 +46,9 @@ module.exports = {
46 46
   SHOW_BOTTOM_TABS_BUTTON: `SHOW_BOTTOM_TABS_BUTTON`,
47 47
   FIRST_TAB_BAR_BUTTON: `FIRST_TAB_BAR_BUTTON`,
48 48
   SECOND_TAB_BAR_BUTTON: `SECOND_TAB_BAR_BUTTON`,
49
+  SHOW_OVERLAY_BUTTON: `SHOW_OVERLAY_BUTTON`,
50
+  SHOW_TOUCH_THROUGH_OVERLAY_BUTTON: `SHOW_TOUCH_THROUGH_OVERLAY_BUTTON`,
51
+  OK_BUTTON: `OK_BUTTON`,
49 52
 
50 53
   // Elements
51 54
   SCROLLVIEW_ELEMENT: `SCROLLVIEW_ELEMENT`,
@@ -57,5 +60,6 @@ module.exports = {
57 60
   PUSHED_SCREEN_HEADER: `PUSHED_SCREEN_HEADER`,
58 61
   OPTIONS_SCREEN_HEADER: `OPTIONS_SCREEN_HEADER`,
59 62
   MODAL_SCREEN: `MODAL_SCREEN`,
60
-  CENTERED_TEXT_HEADER: `CENTERED_TEXT_HEADER`
63
+  CENTERED_TEXT_HEADER: `CENTERED_TEXT_HEADER`,
64
+  DIALOG_HEADER: `DIALOG_HEADER`
61 65
 };