@sdcx/overlay 0.5.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +10 -1
- package/RNOverlay.podspec +4 -4
- package/android/build.gradle +47 -26
- package/android/src/main/java/com/reactnative/overlay/Overlay.java +66 -80
- package/android/src/main/java/com/reactnative/overlay/OverlayModule.java +111 -108
- package/android/src/main/java/com/reactnative/overlay/OverlayPackage.java +14 -15
- package/android/src/main/java/com/reactnative/overlay/OverlayRootView.java +95 -113
- package/dist/NativeOverlay.d.ts +11 -0
- package/dist/NativeOverlay.js +2 -0
- package/{lib → dist}/index.d.ts +2 -5
- package/dist/index.js +9 -0
- package/ios/Overlay/RNOverlay.h +3 -2
- package/ios/Overlay/RNOverlay.mm +58 -0
- package/ios/Overlay/RNOverlayHostingView.h +24 -0
- package/ios/Overlay/RNOverlayHostingView.mm +194 -0
- package/ios/Overlay/RNOverlayModule.h +8 -3
- package/ios/Overlay/RNOverlayModule.mm +101 -0
- package/package.json +50 -64
- package/src/NativeOverlay.ts +14 -0
- package/src/index.ts +7 -18
- package/ios/Overlay/RNOverlay.m +0 -60
- package/ios/Overlay/RNOverlayModule.m +0 -89
- package/lib/index.js +0 -10
|
@@ -1,119 +1,101 @@
|
|
|
1
1
|
package com.reactnative.overlay;
|
|
2
2
|
|
|
3
3
|
import android.content.Context;
|
|
4
|
-
import android.os.Bundle;
|
|
5
4
|
import android.util.AttributeSet;
|
|
6
5
|
import android.view.MotionEvent;
|
|
7
|
-
import android.view.
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
import com.facebook.react.
|
|
12
|
-
import com.facebook.react.
|
|
13
|
-
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
method.setAccessible(true);
|
|
103
|
-
mGlobalLayoutListener = (ViewTreeObserver.OnGlobalLayoutListener) method.invoke(this);
|
|
104
|
-
} catch (Exception e) {
|
|
105
|
-
e.printStackTrace();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return mGlobalLayoutListener;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
void addOnGlobalLayoutListener() {
|
|
112
|
-
removeOnGlobalLayoutListener();
|
|
113
|
-
getViewTreeObserver().addOnGlobalLayoutListener(getGlobalLayoutListener());
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
void removeOnGlobalLayoutListener() {
|
|
117
|
-
getViewTreeObserver().removeOnGlobalLayoutListener(getGlobalLayoutListener());
|
|
118
|
-
}
|
|
6
|
+
import android.view.View;
|
|
7
|
+
import android.view.ViewGroup;
|
|
8
|
+
import android.widget.FrameLayout;
|
|
9
|
+
|
|
10
|
+
import com.facebook.react.bridge.UIManager;
|
|
11
|
+
import com.facebook.react.runtime.ReactSurfaceView;
|
|
12
|
+
import com.facebook.react.uimanager.TouchTargetHelper;
|
|
13
|
+
import com.facebook.react.uimanager.UIManagerHelper;
|
|
14
|
+
import com.facebook.react.uimanager.common.UIManagerType;
|
|
15
|
+
|
|
16
|
+
public class OverlayRootView extends FrameLayout {
|
|
17
|
+
private static final String TAG = "Overlay";
|
|
18
|
+
|
|
19
|
+
public OverlayRootView(Context context) {
|
|
20
|
+
super(context);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public OverlayRootView(Context context, AttributeSet attrs) {
|
|
24
|
+
super(context, attrs);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public OverlayRootView(Context context, AttributeSet attrs, int defStyle) {
|
|
28
|
+
super(context, attrs, defStyle);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private boolean passThroughTouches = false;
|
|
32
|
+
|
|
33
|
+
public void setPassThroughTouches(boolean passThroughTouches) {
|
|
34
|
+
this.passThroughTouches = passThroughTouches;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
ReactSurfaceView reactSurfaceView;
|
|
38
|
+
|
|
39
|
+
@Override
|
|
40
|
+
public boolean dispatchTouchEvent(MotionEvent ev) {
|
|
41
|
+
// FLog.i(TAG, "dispatchTouchEvent");
|
|
42
|
+
if (reactSurfaceView == null) {
|
|
43
|
+
reactSurfaceView = findReactSurfaceView(this);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (reactSurfaceView != null) {
|
|
47
|
+
if (shouldPassTouches(ev)) return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return super.dispatchTouchEvent(ev);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private boolean shouldPassTouches(MotionEvent ev) {
|
|
54
|
+
if (!passThroughTouches) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
int action = ev.getAction() & MotionEvent.ACTION_MASK;
|
|
59
|
+
if (action != MotionEvent.ACTION_DOWN) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
int tag = TouchTargetHelper.findTargetTagForTouch(ev.getX(), ev.getY(), reactSurfaceView.getRootViewGroup());
|
|
64
|
+
// FLog.i(TAG, "findTargetTagForTouch:" + tag);
|
|
65
|
+
UIManager uiManager = UIManagerHelper.getUIManager(reactSurfaceView.getCurrentReactContext(), UIManagerType.FABRIC);
|
|
66
|
+
if (uiManager == null) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
View view = uiManager.resolveView(tag);
|
|
71
|
+
if (view == null) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// FLog.i(TAG, "child name:%s", view.getClass().getSimpleName());
|
|
76
|
+
// FLog.i(TAG, "target, width:%d, height:%d", view.getWidth(), view.getHeight());
|
|
77
|
+
|
|
78
|
+
if (view == reactSurfaceView || view == reactSurfaceView.getChildAt(0)) {
|
|
79
|
+
if (view.getWidth() == reactSurfaceView.getWidth() && view.getHeight() == reactSurfaceView.getHeight()) {
|
|
80
|
+
reactSurfaceView.onChildStartedNativeGesture(reactSurfaceView, ev);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private ReactSurfaceView findReactSurfaceView(ViewGroup parent) {
|
|
88
|
+
for (int i = 0; i < parent.getChildCount(); i++) {
|
|
89
|
+
View child = parent.getChildAt(i);
|
|
90
|
+
if (child instanceof ReactSurfaceView) {
|
|
91
|
+
return (ReactSurfaceView) child;
|
|
92
|
+
}
|
|
93
|
+
if (child instanceof ViewGroup) {
|
|
94
|
+
ReactSurfaceView result = findReactSurfaceView((ViewGroup) child);
|
|
95
|
+
if (result != null) return result;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
119
101
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TurboModule, CodegenTypes } from 'react-native';
|
|
2
|
+
export interface OverlayOptions {
|
|
3
|
+
overlayId: CodegenTypes.Int32;
|
|
4
|
+
passThroughTouches?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface Spec extends TurboModule {
|
|
7
|
+
show(moduleName: string, options: OverlayOptions): void;
|
|
8
|
+
hide(moduleName: string, overlayId: CodegenTypes.Int32): void;
|
|
9
|
+
}
|
|
10
|
+
declare const _default: Spec;
|
|
11
|
+
export default _default;
|
package/{lib → dist}/index.d.ts
RENAMED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { Insets } from 'react-native';
|
|
2
|
-
|
|
3
|
-
id: number;
|
|
4
|
-
passThroughTouches?: boolean;
|
|
5
|
-
}
|
|
1
|
+
import { type Insets } from 'react-native';
|
|
2
|
+
import { type OverlayOptions } from './NativeOverlay';
|
|
6
3
|
export interface OverlayProps extends OverlayOptions {
|
|
7
4
|
insets: Insets;
|
|
8
5
|
}
|
package/dist/index.js
ADDED
package/ios/Overlay/RNOverlay.h
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#import <UIKit/UIKit.h>
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
@class RCTHost;
|
|
3
4
|
|
|
4
5
|
@interface RNOverlay : NSObject
|
|
5
6
|
|
|
6
|
-
- (instancetype)initWithModuleName:(NSString *)moduleName
|
|
7
|
+
- (instancetype)initWithModuleName:(NSString *)moduleName host:(RCTHost *)rctHost;
|
|
7
8
|
|
|
8
9
|
- (void)show:(NSDictionary *)props options:(NSDictionary *)options;
|
|
9
10
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#import "RNOverlay.h"
|
|
2
|
+
#import "RNOverlayHostingView.h"
|
|
3
|
+
|
|
4
|
+
#import <React-RuntimeApple/ReactCommon/RCTHost.h>
|
|
5
|
+
#import <React/RCTUtils.h>
|
|
6
|
+
|
|
7
|
+
@interface RNOverlay ()
|
|
8
|
+
|
|
9
|
+
@property(nonatomic, weak) UIWindow *keyWindow;
|
|
10
|
+
@property(nonatomic, strong) RNOverlayHostingView *rootView;
|
|
11
|
+
@property(nonatomic, copy) NSString *moduleName;
|
|
12
|
+
@property(nonatomic, weak) RCTHost *rctHost;
|
|
13
|
+
|
|
14
|
+
@end
|
|
15
|
+
|
|
16
|
+
@implementation RNOverlay
|
|
17
|
+
|
|
18
|
+
- (instancetype)initWithModuleName:(NSString *)moduleName host:(RCTHost *)rctHost {
|
|
19
|
+
if (self = [super init]) {
|
|
20
|
+
_moduleName = moduleName;
|
|
21
|
+
_rctHost = rctHost;
|
|
22
|
+
}
|
|
23
|
+
return self;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
- (void)show:(NSDictionary *)props options:(NSDictionary *)options {
|
|
27
|
+
RNOverlayHostingView *rctView = [self createReactRootView:props];
|
|
28
|
+
rctView.passThroughTouches = [options[@"passThroughTouches"] boolValue];
|
|
29
|
+
rctView.frame = [UIScreen mainScreen].bounds;
|
|
30
|
+
self.rootView = rctView;
|
|
31
|
+
|
|
32
|
+
UIWindow *keyWindow = RCTKeyWindow();
|
|
33
|
+
[keyWindow addSubview:rctView];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
- (void)hide {
|
|
37
|
+
if (self.rootView) {
|
|
38
|
+
[self.rootView removeFromSuperview];
|
|
39
|
+
self.rootView = nil;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
- (void)update {
|
|
44
|
+
UIWindow *keyWindow = RCTKeyWindow();
|
|
45
|
+
if (keyWindow != self.keyWindow) {
|
|
46
|
+
[self.rootView removeFromSuperview];
|
|
47
|
+
[keyWindow addSubview:self.rootView];
|
|
48
|
+
self.keyWindow = keyWindow;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
- (RNOverlayHostingView *)createReactRootView:(NSDictionary *)props {
|
|
53
|
+
RCTFabricSurface *surface = [self.rctHost createSurfaceWithModuleName:self.moduleName initialProperties:props];
|
|
54
|
+
RNOverlayHostingView *rootView = [[RNOverlayHostingView alloc] initWithSurface:(id)surface];
|
|
55
|
+
return rootView;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#import <UIKit/UIKit.h>
|
|
2
|
+
|
|
3
|
+
#import <React/RCTSurfaceDelegate.h>
|
|
4
|
+
#import <React/RCTSurfaceProtocol.h>
|
|
5
|
+
#import <React/RCTSurfaceSizeMeasureMode.h>
|
|
6
|
+
#import <React/RCTSurfaceStage.h>
|
|
7
|
+
|
|
8
|
+
@class RCTSurface;
|
|
9
|
+
|
|
10
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
11
|
+
|
|
12
|
+
@interface RNOverlayHostingView : UIView <RCTSurfaceDelegate>
|
|
13
|
+
|
|
14
|
+
- (instancetype)initWithSurface:(id<RCTSurfaceProtocol>)surface;
|
|
15
|
+
|
|
16
|
+
@property (nonatomic, strong, readonly) id<RCTSurfaceProtocol> surface;
|
|
17
|
+
|
|
18
|
+
@property (nonatomic, assign) BOOL passThroughTouches;
|
|
19
|
+
|
|
20
|
+
@property (nonatomic, assign) RCTSurfaceSizeMeasureMode sizeMeasureMode;
|
|
21
|
+
|
|
22
|
+
@end
|
|
23
|
+
|
|
24
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#import "RNOverlayHostingView.h"
|
|
2
|
+
|
|
3
|
+
#import "RCTConstants.h"
|
|
4
|
+
#import "RCTDefines.h"
|
|
5
|
+
#import "RCTSurface.h"
|
|
6
|
+
#import "RCTSurfaceDelegate.h"
|
|
7
|
+
#import "RCTSurfaceView.h"
|
|
8
|
+
#import "RCTUtils.h"
|
|
9
|
+
|
|
10
|
+
@interface RNOverlayHostingView ()
|
|
11
|
+
|
|
12
|
+
@property (nonatomic, assign) BOOL isSurfaceViewVisible;
|
|
13
|
+
|
|
14
|
+
@end
|
|
15
|
+
|
|
16
|
+
@implementation RNOverlayHostingView {
|
|
17
|
+
UIView *_Nullable _surfaceView;
|
|
18
|
+
RCTSurfaceStage _stage;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
RCT_NOT_IMPLEMENTED(-(instancetype)init)
|
|
22
|
+
RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
|
|
23
|
+
RCT_NOT_IMPLEMENTED(-(nullable instancetype)initWithCoder : (NSCoder *)coder)
|
|
24
|
+
|
|
25
|
+
- (instancetype)initWithSurface:(id<RCTSurfaceProtocol>)surface {
|
|
26
|
+
return [self initWithSurface:surface sizeMeasureMode:RCTSurfaceSizeMeasureModeWidthExact | RCTSurfaceSizeMeasureModeHeightExact];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
- (instancetype)initWithSurface:(id<RCTSurfaceProtocol>)surface
|
|
30
|
+
sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode {
|
|
31
|
+
if (self = [super initWithFrame:CGRectZero]) {
|
|
32
|
+
_surface = surface;
|
|
33
|
+
_sizeMeasureMode = sizeMeasureMode;
|
|
34
|
+
_surface.delegate = self;
|
|
35
|
+
_stage = surface.stage;
|
|
36
|
+
[self _updateViews];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return self;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
- (void)dealloc {
|
|
43
|
+
[_surface stop];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
|
47
|
+
UIView *hitView = [super hitTest:point withEvent:event];
|
|
48
|
+
if (self.passThroughTouches && [self shouldPassTouches:hitView]) {
|
|
49
|
+
return nil;
|
|
50
|
+
}
|
|
51
|
+
return hitView;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
- (BOOL)shouldPassTouches:(UIView *)hitView {
|
|
55
|
+
if (!hitView) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// RCTRootComponentView
|
|
60
|
+
if (hitView == _surfaceView || hitView == [_surfaceView.subviews firstObject]) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
- (void)layoutSubviews {
|
|
68
|
+
[super layoutSubviews];
|
|
69
|
+
|
|
70
|
+
CGSize minimumSize;
|
|
71
|
+
CGSize maximumSize;
|
|
72
|
+
|
|
73
|
+
RCTSurfaceMinimumSizeAndMaximumSizeFromSizeAndSizeMeasureMode(
|
|
74
|
+
self.bounds.size, _sizeMeasureMode, &minimumSize, &maximumSize);
|
|
75
|
+
CGRect windowFrame = [self.window convertRect:self.frame fromView:self.superview];
|
|
76
|
+
|
|
77
|
+
[_surface setMinimumSize:minimumSize maximumSize:maximumSize viewportOffset:windowFrame.origin];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
- (CGSize)intrinsicContentSize {
|
|
81
|
+
if (RCTSurfaceStageIsPreparing(_stage)) {
|
|
82
|
+
return CGSizeZero;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return _surface.intrinsicSize;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
- (CGSize)sizeThatFits:(CGSize)size {
|
|
89
|
+
if (RCTSurfaceStageIsPreparing(_stage)) {
|
|
90
|
+
return CGSizeZero;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
CGSize minimumSize;
|
|
94
|
+
CGSize maximumSize;
|
|
95
|
+
|
|
96
|
+
RCTSurfaceMinimumSizeAndMaximumSizeFromSizeAndSizeMeasureMode(size, _sizeMeasureMode, &minimumSize, &maximumSize);
|
|
97
|
+
|
|
98
|
+
return [_surface sizeThatFitsMinimumSize:minimumSize maximumSize:maximumSize];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
- (void)setStage:(RCTSurfaceStage)stage {
|
|
102
|
+
if (stage == _stage) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
BOOL shouldInvalidateLayout = RCTSurfaceStageIsRunning(stage) != RCTSurfaceStageIsRunning(_stage) ||
|
|
107
|
+
RCTSurfaceStageIsPreparing(stage) != RCTSurfaceStageIsPreparing(_stage);
|
|
108
|
+
|
|
109
|
+
_stage = stage;
|
|
110
|
+
|
|
111
|
+
if (shouldInvalidateLayout) {
|
|
112
|
+
[self _invalidateLayout];
|
|
113
|
+
[self _updateViews];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
- (void)setSizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode {
|
|
118
|
+
if (sizeMeasureMode == _sizeMeasureMode) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
_sizeMeasureMode = sizeMeasureMode;
|
|
123
|
+
[self _invalidateLayout];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
#pragma mark - isSurfaceViewVisible
|
|
128
|
+
|
|
129
|
+
- (void)setIsSurfaceViewVisible:(BOOL)visible {
|
|
130
|
+
if (_isSurfaceViewVisible == visible) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
_isSurfaceViewVisible = visible;
|
|
135
|
+
|
|
136
|
+
if (visible) {
|
|
137
|
+
_surfaceView = _surface.view;
|
|
138
|
+
_surfaceView.frame = self.bounds;
|
|
139
|
+
_surfaceView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
140
|
+
[self addSubview:_surfaceView];
|
|
141
|
+
} else {
|
|
142
|
+
[_surfaceView removeFromSuperview];
|
|
143
|
+
_surfaceView = nil;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#pragma mark - UITraitCollection updates
|
|
148
|
+
|
|
149
|
+
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
|
|
150
|
+
[super traitCollectionDidChange:previousTraitCollection];
|
|
151
|
+
|
|
152
|
+
if (RCTSharedApplication().applicationState == UIApplicationStateBackground) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
[[NSNotificationCenter defaultCenter]
|
|
157
|
+
postNotificationName:RCTUserInterfaceStyleDidChangeNotification
|
|
158
|
+
object:self
|
|
159
|
+
userInfo:@{
|
|
160
|
+
RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey : self.traitCollection,
|
|
161
|
+
}];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
#pragma mark - Private stuff
|
|
165
|
+
|
|
166
|
+
- (void)_invalidateLayout {
|
|
167
|
+
[self invalidateIntrinsicContentSize];
|
|
168
|
+
[self.superview setNeedsLayout];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
- (void)_updateViews {
|
|
172
|
+
self.isSurfaceViewVisible = RCTSurfaceStageIsRunning(_stage);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
- (void)didMoveToWindow {
|
|
176
|
+
[super didMoveToWindow];
|
|
177
|
+
[self _updateViews];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
#pragma mark - RCTSurfaceDelegate
|
|
181
|
+
|
|
182
|
+
- (void)surface:(__unused RCTSurface *)surface didChangeStage:(RCTSurfaceStage)stage {
|
|
183
|
+
RCTExecuteOnMainQueue(^{
|
|
184
|
+
[self setStage:stage];
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
- (void)surface:(__unused RCTSurface *)surface didChangeIntrinsicSize:(__unused CGSize)intrinsicSize {
|
|
189
|
+
RCTExecuteOnMainQueue(^{
|
|
190
|
+
[self _invalidateLayout];
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@end
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
#import <
|
|
2
|
-
#import <
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
#import <overlay/overlay.h>
|
|
3
|
+
#import <React/RCTInitializing.h>
|
|
3
4
|
|
|
4
5
|
NS_ASSUME_NONNULL_BEGIN
|
|
5
6
|
|
|
6
|
-
@
|
|
7
|
+
@class RCTHost;
|
|
8
|
+
|
|
9
|
+
@interface RNOverlayModule : NSObject <NativeOverlaySpec, RCTInvalidating>
|
|
10
|
+
|
|
11
|
+
- (instancetype)initWithHost:(RCTHost *)host;
|
|
7
12
|
|
|
8
13
|
@end
|
|
9
14
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#import "RNOverlayModule.h"
|
|
2
|
+
#import "RNOverlay.h"
|
|
3
|
+
|
|
4
|
+
#import <React/RCTLog.h>
|
|
5
|
+
#import <React-RuntimeApple/ReactCommon/RCTHost.h>
|
|
6
|
+
#import <React/RCTConversions.h>
|
|
7
|
+
|
|
8
|
+
NSString* genKey(NSString* moduleName, NSNumber* id) {
|
|
9
|
+
return [NSString stringWithFormat:@"%@-%@", moduleName, id];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@interface RNOverlayModule ()
|
|
13
|
+
|
|
14
|
+
@property(nonatomic, strong) NSMutableDictionary *overlays;
|
|
15
|
+
@property(nonatomic, strong) RCTHost *host;
|
|
16
|
+
|
|
17
|
+
@end
|
|
18
|
+
|
|
19
|
+
@implementation RNOverlayModule
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
23
|
+
return YES;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
- (dispatch_queue_t)methodQueue {
|
|
27
|
+
return dispatch_get_main_queue();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
RCT_EXPORT_MODULE(OverlayHost)
|
|
31
|
+
|
|
32
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
|
|
33
|
+
return std::make_shared<facebook::react::NativeOverlaySpecJSI>(params);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
- (instancetype)init {
|
|
37
|
+
if (self = [super init]) {
|
|
38
|
+
_overlays = [[NSMutableDictionary alloc] init];
|
|
39
|
+
}
|
|
40
|
+
return self;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
- (instancetype)initWithHost:(RCTHost *)host {
|
|
44
|
+
if (self = [super init]) {
|
|
45
|
+
_overlays = [[NSMutableDictionary alloc] init];
|
|
46
|
+
_host = host;
|
|
47
|
+
}
|
|
48
|
+
return self;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
- (void)handleReload {
|
|
52
|
+
for (NSString *key in self.overlays) {
|
|
53
|
+
RNOverlay *overlay = self.overlays[key];
|
|
54
|
+
[overlay hide];
|
|
55
|
+
}
|
|
56
|
+
[self.overlays removeAllObjects];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (void)invalidate {
|
|
60
|
+
[self handleReload];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
- (void)show:(NSString *)moduleName options:(JS::NativeOverlay::OverlayOptions &)options {
|
|
64
|
+
NSString* key = genKey(moduleName, @(options.overlayId()));
|
|
65
|
+
RNOverlay *overlay = self.overlays[key];
|
|
66
|
+
if (overlay != nil) {
|
|
67
|
+
[overlay update];
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
overlay = [[RNOverlay alloc] initWithModuleName:moduleName host:self.host];
|
|
72
|
+
self.overlays[key] = overlay;
|
|
73
|
+
|
|
74
|
+
UIWindow *window = RCTKeyWindow();
|
|
75
|
+
UIEdgeInsets safeAreaInsets = window.safeAreaInsets;
|
|
76
|
+
NSDictionary* insets = @{
|
|
77
|
+
@"top" : @(safeAreaInsets.top),
|
|
78
|
+
@"right" : @(safeAreaInsets.right),
|
|
79
|
+
@"bottom" : @(safeAreaInsets.bottom),
|
|
80
|
+
@"left" : @(safeAreaInsets.left),
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
NSDictionary *props = @{
|
|
84
|
+
@"insets": insets,
|
|
85
|
+
@"overlayId": @(options.overlayId()),
|
|
86
|
+
@"passThroughTouches": @((BOOL)options.passThroughTouches())
|
|
87
|
+
};
|
|
88
|
+
[overlay show:props options:props];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
- (void)hide:(NSString *)moduleName overlayId:(NSInteger)overlayId {
|
|
92
|
+
NSString* key = genKey(moduleName, @(overlayId));
|
|
93
|
+
RNOverlay *overlay = self.overlays[key];
|
|
94
|
+
if (!overlay) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
[self.overlays removeObjectForKey:key];
|
|
98
|
+
[overlay hide];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@end
|