react-native-screens 3.13.1 → 3.15.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/README.md +2 -2
- package/RNScreens.podspec +5 -4
- package/android/build.gradle +18 -1
- package/android/src/main/java/com/swmansion/rnscreens/Screen.kt +0 -5
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt +8 -4
- package/android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt +24 -6
- package/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt +17 -21
- package/android/src/main/jni/Android.mk +1 -2
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerDelegate.java +39 -14
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerInterface.java +15 -6
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerDelegate.java +3 -3
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerInterface.java +1 -1
- package/android/src/paper/java/com/swmansion/rnscreens/FabricEnabledViewGroup.kt +4 -10
- package/common/cpp/Android.mk +1 -2
- package/createNativeStackNavigator/README.md +4 -0
- package/ios/RNSConvert.h +30 -0
- package/ios/RNSConvert.mm +120 -0
- package/ios/RNSEnums.h +59 -0
- package/ios/RNSFullWindowOverlay.h +17 -2
- package/ios/RNSFullWindowOverlay.mm +199 -0
- package/ios/RNSScreen.h +70 -79
- package/ios/{RNSScreen.m → RNSScreen.mm} +678 -302
- package/ios/RNSScreenContainer.h +15 -1
- package/ios/{RNSScreenContainer.m → RNSScreenContainer.mm} +99 -8
- package/ios/{RNSScreenNavigationContainer.m → RNSScreenNavigationContainer.mm} +22 -0
- package/ios/RNSScreenStack.h +19 -3
- package/ios/{RNSScreenStack.m → RNSScreenStack.mm} +431 -137
- package/ios/{RNSScreenStackAnimator.m → RNSScreenStackAnimator.mm} +19 -14
- package/ios/RNSScreenStackHeaderConfig.h +20 -21
- package/ios/{RNSScreenStackHeaderConfig.m → RNSScreenStackHeaderConfig.mm} +232 -117
- package/ios/RNSScreenStackHeaderSubview.h +45 -0
- package/ios/RNSScreenStackHeaderSubview.mm +137 -0
- package/ios/RNSScreenViewEvent.h +12 -0
- package/ios/RNSScreenViewEvent.mm +59 -0
- package/ios/{RNSScreenWindowTraits.m → RNSScreenWindowTraits.mm} +3 -2
- package/ios/RNSSearchBar.h +14 -1
- package/ios/RNSSearchBar.mm +351 -0
- package/ios/{UIViewController+RNScreens.m → UIViewController+RNScreens.mm} +0 -0
- package/ios/{UIWindow+RNScreens.m → UIWindow+RNScreens.mm} +0 -0
- package/lib/commonjs/fabric/FullWindowOverlayNativeComponent.js +21 -0
- package/lib/commonjs/fabric/FullWindowOverlayNativeComponent.js.map +1 -0
- package/lib/commonjs/fabric/ScreenContainerNativeComponent.js +21 -0
- package/lib/commonjs/fabric/ScreenContainerNativeComponent.js.map +1 -0
- package/lib/commonjs/fabric/ScreenNativeComponent.js.map +1 -1
- package/lib/commonjs/fabric/ScreenNavigationContainerNativeComponent.js +21 -0
- package/lib/commonjs/fabric/ScreenNavigationContainerNativeComponent.js.map +1 -0
- package/lib/commonjs/fabric/ScreenStackHeaderConfigNativeComponent.js.map +1 -1
- package/lib/commonjs/fabric/ScreenStackNativeComponent.js.map +1 -1
- package/lib/commonjs/fabric/SearchBarNativeComponent.js +25 -0
- package/lib/commonjs/fabric/SearchBarNativeComponent.js.map +1 -0
- package/lib/commonjs/index.native.js +20 -32
- package/lib/commonjs/index.native.js.map +1 -1
- package/lib/commonjs/native-stack/views/NativeStackView.js +4 -0
- package/lib/commonjs/native-stack/views/NativeStackView.js.map +1 -1
- package/lib/commonjs/reanimated/ReanimatedNativeStackScreen.js +10 -2
- package/lib/commonjs/reanimated/ReanimatedNativeStackScreen.js.map +1 -1
- package/lib/module/fabric/FullWindowOverlayNativeComponent.js +9 -0
- package/lib/module/fabric/FullWindowOverlayNativeComponent.js.map +1 -0
- package/lib/module/fabric/ScreenContainerNativeComponent.js +9 -0
- package/lib/module/fabric/ScreenContainerNativeComponent.js.map +1 -0
- package/lib/module/fabric/ScreenNativeComponent.js.map +1 -1
- package/lib/module/fabric/ScreenNavigationContainerNativeComponent.js +9 -0
- package/lib/module/fabric/ScreenNavigationContainerNativeComponent.js.map +1 -0
- package/lib/module/fabric/ScreenStackHeaderConfigNativeComponent.js.map +1 -1
- package/lib/module/fabric/ScreenStackNativeComponent.js.map +1 -1
- package/lib/module/fabric/SearchBarNativeComponent.js +11 -0
- package/lib/module/fabric/SearchBarNativeComponent.js.map +1 -0
- package/lib/module/index.native.js +21 -34
- package/lib/module/index.native.js.map +1 -1
- package/lib/module/native-stack/views/NativeStackView.js +4 -0
- package/lib/module/native-stack/views/NativeStackView.js.map +1 -1
- package/lib/module/reanimated/ReanimatedNativeStackScreen.js +9 -2
- package/lib/module/reanimated/ReanimatedNativeStackScreen.js.map +1 -1
- package/lib/typescript/native-stack/types.d.ts +12 -0
- package/lib/typescript/reanimated/ReanimatedNativeStackScreen.d.ts +1 -1
- package/lib/typescript/reanimated/ReanimatedScreen.d.ts +1 -1
- package/lib/typescript/types.d.ts +24 -0
- package/native-stack/README.md +21 -0
- package/package.json +2 -2
- package/src/fabric/FullWindowOverlayNativeComponent.js +19 -0
- package/src/fabric/ScreenContainerNativeComponent.js +19 -0
- package/src/fabric/ScreenNativeComponent.js +41 -8
- package/src/fabric/ScreenNavigationContainerNativeComponent.js +19 -0
- package/src/fabric/ScreenStackHeaderConfigNativeComponent.js +1 -1
- package/src/fabric/ScreenStackNativeComponent.js +4 -0
- package/src/fabric/SearchBarNativeComponent.js +62 -0
- package/src/index.native.tsx +17 -36
- package/src/native-stack/types.tsx +12 -0
- package/src/native-stack/views/NativeStackView.tsx +4 -0
- package/src/reanimated/ReanimatedNativeStackScreen.tsx +8 -0
- package/src/types.tsx +25 -0
- package/ios/RNSFullWindowOverlay.m +0 -105
- package/ios/RNSScreenComponentView.h +0 -23
- package/ios/RNSScreenComponentView.mm +0 -159
- package/ios/RNSScreenController.h +0 -10
- package/ios/RNSScreenController.mm +0 -79
- package/ios/RNSScreenStackComponentView.h +0 -15
- package/ios/RNSScreenStackComponentView.mm +0 -295
- package/ios/RNSScreenStackHeaderConfigComponentView.h +0 -42
- package/ios/RNSScreenStackHeaderConfigComponentView.mm +0 -662
- package/ios/RNSScreenStackHeaderSubviewComponentView.h +0 -14
- package/ios/RNSScreenStackHeaderSubviewComponentView.mm +0 -77
- package/ios/RNSSearchBar.m +0 -198
- package/lib/commonjs/fabric/Screen.js +0 -29
- package/lib/commonjs/fabric/Screen.js.map +0 -1
- package/lib/commonjs/fabric/ScreenStack.js +0 -26
- package/lib/commonjs/fabric/ScreenStack.js.map +0 -1
- package/lib/commonjs/fabric/ScreenStackHeaderSubview.js +0 -37
- package/lib/commonjs/fabric/ScreenStackHeaderSubview.js.map +0 -1
- package/lib/commonjs/fabric/index.js +0 -40
- package/lib/commonjs/fabric/index.js.map +0 -1
- package/lib/module/fabric/Screen.js +0 -16
- package/lib/module/fabric/Screen.js.map +0 -1
- package/lib/module/fabric/ScreenStack.js +0 -15
- package/lib/module/fabric/ScreenStack.js.map +0 -1
- package/lib/module/fabric/ScreenStackHeaderSubview.js +0 -24
- package/lib/module/fabric/ScreenStackHeaderSubview.js.map +0 -1
- package/lib/module/fabric/index.js +0 -6
- package/lib/module/fabric/index.js.map +0 -1
- package/src/fabric/Screen.js +0 -15
- package/src/fabric/ScreenStack.js +0 -10
- package/src/fabric/ScreenStackHeaderSubview.js +0 -22
- package/src/fabric/index.js +0 -11
|
@@ -1,21 +1,39 @@
|
|
|
1
|
-
#
|
|
2
|
-
#import
|
|
3
|
-
#import
|
|
4
|
-
#import
|
|
5
|
-
#import
|
|
1
|
+
#ifdef RN_FABRIC_ENABLED
|
|
2
|
+
#import <React/RCTMountingTransactionObserving.h>
|
|
3
|
+
#import <React/RCTSurfaceTouchHandler.h>
|
|
4
|
+
#import <React/UIView+React.h>
|
|
5
|
+
#import <react/renderer/components/rnscreens/ComponentDescriptors.h>
|
|
6
|
+
#import <react/renderer/components/rnscreens/EventEmitters.h>
|
|
7
|
+
#import <react/renderer/components/rnscreens/Props.h>
|
|
8
|
+
#import <react/renderer/components/rnscreens/RCTComponentViewHelpers.h>
|
|
6
9
|
|
|
10
|
+
#import "RCTFabricComponentsPlugins.h"
|
|
11
|
+
|
|
12
|
+
#else
|
|
7
13
|
#import <React/RCTBridge.h>
|
|
8
14
|
#import <React/RCTRootContentView.h>
|
|
9
15
|
#import <React/RCTShadowView.h>
|
|
10
16
|
#import <React/RCTTouchHandler.h>
|
|
11
17
|
#import <React/RCTUIManager.h>
|
|
12
18
|
#import <React/RCTUIManagerUtils.h>
|
|
19
|
+
#endif // RN_FABRIC_ENABLED
|
|
20
|
+
|
|
21
|
+
#import "RNSScreen.h"
|
|
22
|
+
#import "RNSScreenStack.h"
|
|
23
|
+
#import "RNSScreenStackAnimator.h"
|
|
24
|
+
#import "RNSScreenStackHeaderConfig.h"
|
|
25
|
+
#import "RNSScreenWindowTraits.h"
|
|
13
26
|
|
|
14
27
|
@interface RNSScreenStackView () <
|
|
15
28
|
UINavigationControllerDelegate,
|
|
16
29
|
UIAdaptivePresentationControllerDelegate,
|
|
17
30
|
UIGestureRecognizerDelegate,
|
|
18
|
-
UIViewControllerTransitioningDelegate
|
|
31
|
+
UIViewControllerTransitioningDelegate
|
|
32
|
+
#ifdef RN_FABRIC_ENABLED
|
|
33
|
+
,
|
|
34
|
+
RCTMountingTransactionObserving
|
|
35
|
+
#endif
|
|
36
|
+
>
|
|
19
37
|
|
|
20
38
|
@property (nonatomic) NSMutableArray<UIViewController *> *presentedModals;
|
|
21
39
|
@property (nonatomic) BOOL updatingModals;
|
|
@@ -71,13 +89,29 @@
|
|
|
71
89
|
@implementation RNSScreenStackView {
|
|
72
90
|
UINavigationController *_controller;
|
|
73
91
|
NSMutableArray<RNSScreenView *> *_reactSubviews;
|
|
74
|
-
__weak RNSScreenStackManager *_manager;
|
|
75
|
-
BOOL _hasLayout;
|
|
76
92
|
BOOL _invalidated;
|
|
93
|
+
BOOL _isFullWidthSwiping;
|
|
77
94
|
UIPercentDrivenInteractiveTransition *_interactionController;
|
|
95
|
+
BOOL _hasLayout;
|
|
96
|
+
__weak RNSScreenStackManager *_manager;
|
|
78
97
|
BOOL _updateScheduled;
|
|
79
|
-
|
|
98
|
+
#ifdef RN_FABRIC_ENABLED
|
|
99
|
+
UIView *_snapshot;
|
|
100
|
+
#endif
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
#ifdef RN_FABRIC_ENABLED
|
|
104
|
+
- (instancetype)initWithFrame:(CGRect)frame
|
|
105
|
+
{
|
|
106
|
+
if (self = [super initWithFrame:frame]) {
|
|
107
|
+
static const auto defaultProps = std::make_shared<const facebook::react::RNSScreenStackProps>();
|
|
108
|
+
_props = defaultProps;
|
|
109
|
+
[self initCommonProps];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return self;
|
|
80
113
|
}
|
|
114
|
+
#endif // RN_FABRIC_ENABLED
|
|
81
115
|
|
|
82
116
|
- (instancetype)initWithManager:(RNSScreenStackManager *)manager
|
|
83
117
|
{
|
|
@@ -85,26 +119,41 @@
|
|
|
85
119
|
_hasLayout = NO;
|
|
86
120
|
_invalidated = NO;
|
|
87
121
|
_manager = manager;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
122
|
+
[self initCommonProps];
|
|
123
|
+
}
|
|
124
|
+
return self;
|
|
125
|
+
}
|
|
92
126
|
|
|
127
|
+
- (void)initCommonProps
|
|
128
|
+
{
|
|
129
|
+
_reactSubviews = [NSMutableArray new];
|
|
130
|
+
_presentedModals = [NSMutableArray new];
|
|
131
|
+
_controller = [RNScreensNavigationController new];
|
|
132
|
+
_controller.delegate = self;
|
|
93
133
|
#if !TARGET_OS_TV
|
|
94
|
-
|
|
134
|
+
[self setupGestureHandlers];
|
|
95
135
|
#endif
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
return self;
|
|
136
|
+
// we have to initialize viewControllers with a non empty array for
|
|
137
|
+
// largeTitle header to render in the opened state. If it is empty
|
|
138
|
+
// the header will render in collapsed state which is perhaps a bug
|
|
139
|
+
// in UIKit but ¯\_(ツ)_/¯
|
|
140
|
+
[_controller setViewControllers:@[ [UIViewController new] ]];
|
|
103
141
|
}
|
|
104
142
|
|
|
105
|
-
-
|
|
143
|
+
#pragma mark - Common
|
|
144
|
+
|
|
145
|
+
- (void)emitOnFinishTransitioningEvent
|
|
106
146
|
{
|
|
107
|
-
|
|
147
|
+
#ifdef RN_FABRIC_ENABLED
|
|
148
|
+
if (_eventEmitter != nullptr) {
|
|
149
|
+
std::dynamic_pointer_cast<const facebook::react::RNSScreenStackEventEmitter>(_eventEmitter)
|
|
150
|
+
->onFinishTransitioning(facebook::react::RNSScreenStackEventEmitter::OnFinishTransitioning{});
|
|
151
|
+
}
|
|
152
|
+
#else
|
|
153
|
+
if (self.onFinishTransitioning) {
|
|
154
|
+
self.onFinishTransitioning(nil);
|
|
155
|
+
}
|
|
156
|
+
#endif
|
|
108
157
|
}
|
|
109
158
|
|
|
110
159
|
- (void)navigationController:(UINavigationController *)navigationController
|
|
@@ -112,6 +161,12 @@
|
|
|
112
161
|
animated:(BOOL)animated
|
|
113
162
|
{
|
|
114
163
|
UIView *view = viewController.view;
|
|
164
|
+
#ifdef RN_FABRIC_ENABLED
|
|
165
|
+
if (![view isKindOfClass:[RNSScreenView class]]) {
|
|
166
|
+
// if the current view is a snapshot, config was already removed so we don't trigger the method
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
#endif
|
|
115
170
|
RNSScreenStackHeaderConfig *config = nil;
|
|
116
171
|
for (UIView *subview in view.reactSubviews) {
|
|
117
172
|
if ([subview isKindOfClass:[RNSScreenStackHeaderConfig class]]) {
|
|
@@ -122,100 +177,65 @@
|
|
|
122
177
|
[RNSScreenStackHeaderConfig willShowViewController:viewController animated:animated withConfig:config];
|
|
123
178
|
}
|
|
124
179
|
|
|
125
|
-
- (void)navigationController:(UINavigationController *)navigationController
|
|
126
|
-
didShowViewController:(UIViewController *)viewController
|
|
127
|
-
animated:(BOOL)animated
|
|
128
|
-
{
|
|
129
|
-
if (self.onFinishTransitioning) {
|
|
130
|
-
self.onFinishTransitioning(nil);
|
|
131
|
-
}
|
|
132
|
-
[RNSScreenWindowTraits updateWindowTraits];
|
|
133
|
-
}
|
|
134
|
-
|
|
135
180
|
- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
|
|
136
181
|
{
|
|
137
182
|
// We don't directly set presentation delegate but instead rely on the ScreenView's delegate to
|
|
138
183
|
// forward certain calls to the container (Stack).
|
|
139
|
-
|
|
140
|
-
if ([screenView isKindOfClass:[RNSScreenView class]]) {
|
|
184
|
+
if ([presentationController.presentedViewController isKindOfClass:[RNSScreen class]]) {
|
|
141
185
|
// we trigger the update of status bar's appearance here because there is no other lifecycle method
|
|
142
186
|
// that can handle it when dismissing a modal, the same for orientation
|
|
143
187
|
[RNSScreenWindowTraits updateWindowTraits];
|
|
144
188
|
[_presentedModals removeObject:presentationController.presentedViewController];
|
|
145
|
-
|
|
146
|
-
// have tried to push another one during the transition
|
|
189
|
+
|
|
147
190
|
_updatingModals = NO;
|
|
191
|
+
#ifdef RN_FABRIC_ENABLED
|
|
192
|
+
[self emitOnFinishTransitioningEvent];
|
|
193
|
+
#else
|
|
194
|
+
// we double check if there are no new controllers pending to be presented since someone could
|
|
195
|
+
// have tried to push another one during the transition.
|
|
196
|
+
// We don't do it on Fabric since update of container will be triggered from "unmount" method afterwards
|
|
148
197
|
[self updateContainer];
|
|
149
198
|
if (self.onFinishTransitioning) {
|
|
150
199
|
// instead of directly triggering onFinishTransitioning this time we enqueue the event on the
|
|
151
200
|
// main queue. We do that because onDismiss event is also enqueued and we want for the transition
|
|
152
201
|
// finish event to arrive later than onDismiss (see RNSScreen#notifyDismiss)
|
|
153
202
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
154
|
-
|
|
155
|
-
self.onFinishTransitioning(nil);
|
|
156
|
-
}
|
|
203
|
+
[self emitOnFinishTransitioningEvent];
|
|
157
204
|
});
|
|
158
205
|
}
|
|
206
|
+
#endif
|
|
159
207
|
}
|
|
160
208
|
}
|
|
161
209
|
|
|
162
|
-
- (void)markChildUpdated
|
|
163
|
-
{
|
|
164
|
-
// do nothing
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
- (void)didUpdateChildren
|
|
168
|
-
{
|
|
169
|
-
// do nothing
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
- (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex
|
|
173
|
-
{
|
|
174
|
-
if (![subview isKindOfClass:[RNSScreenView class]]) {
|
|
175
|
-
RCTLogError(@"ScreenStack only accepts children of type Screen");
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
subview.reactSuperview = self;
|
|
179
|
-
[_reactSubviews insertObject:subview atIndex:atIndex];
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
- (void)removeReactSubview:(RNSScreenView *)subview
|
|
183
|
-
{
|
|
184
|
-
subview.reactSuperview = nil;
|
|
185
|
-
[_reactSubviews removeObject:subview];
|
|
186
|
-
}
|
|
187
|
-
|
|
188
210
|
- (NSArray<UIView *> *)reactSubviews
|
|
189
211
|
{
|
|
190
212
|
return _reactSubviews;
|
|
191
213
|
}
|
|
192
214
|
|
|
193
|
-
- (void)didUpdateReactSubviews
|
|
194
|
-
{
|
|
195
|
-
// we need to wait until children have their layout set. At this point they don't have the layout
|
|
196
|
-
// set yet, however the layout call is already enqueued on ui thread. Enqueuing update call on the
|
|
197
|
-
// ui queue will guarantee that the update will run after layout.
|
|
198
|
-
dispatch_async(dispatch_get_main_queue(), ^{
|
|
199
|
-
self->_hasLayout = YES;
|
|
200
|
-
[self maybeAddToParentAndUpdateContainer];
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
215
|
- (void)didMoveToWindow
|
|
205
216
|
{
|
|
206
217
|
[super didMoveToWindow];
|
|
218
|
+
#ifdef RN_FABRIC_ENABLED
|
|
219
|
+
// for handling nested stacks
|
|
220
|
+
[self maybeAddToParentAndUpdateContainer];
|
|
221
|
+
#else
|
|
207
222
|
if (!_invalidated) {
|
|
208
223
|
// We check whether the view has been invalidated before running side-effects in didMoveToWindow
|
|
209
224
|
// This is needed because when LayoutAnimations are used it is possible for view to be re-attached
|
|
210
225
|
// to a window despite the fact it has been removed from the React Native view hierarchy.
|
|
211
226
|
[self maybeAddToParentAndUpdateContainer];
|
|
212
227
|
}
|
|
228
|
+
#endif
|
|
213
229
|
}
|
|
214
230
|
|
|
215
231
|
- (void)maybeAddToParentAndUpdateContainer
|
|
216
232
|
{
|
|
217
233
|
BOOL wasScreenMounted = _controller.parentViewController != nil;
|
|
234
|
+
#ifdef RN_FABRIC_ENABLED
|
|
235
|
+
BOOL isScreenReadyForShowing = self.window;
|
|
236
|
+
#else
|
|
218
237
|
BOOL isScreenReadyForShowing = self.window && _hasLayout;
|
|
238
|
+
#endif
|
|
219
239
|
if (!isScreenReadyForShowing && !wasScreenMounted) {
|
|
220
240
|
// We wait with adding to parent controller until the stack is mounted and has its initial
|
|
221
241
|
// layout done.
|
|
@@ -318,9 +338,7 @@
|
|
|
318
338
|
__weak RNSScreenStackView *weakSelf = self;
|
|
319
339
|
|
|
320
340
|
void (^afterTransitions)(void) = ^{
|
|
321
|
-
|
|
322
|
-
weakSelf.onFinishTransitioning(nil);
|
|
323
|
-
}
|
|
341
|
+
[weakSelf emitOnFinishTransitioningEvent];
|
|
324
342
|
weakSelf.updatingModals = NO;
|
|
325
343
|
if (weakSelf.scheduleModalsUpdate) {
|
|
326
344
|
// if modals update was requested during setModalViewControllers we set scheduleModalsUpdate
|
|
@@ -364,7 +382,7 @@
|
|
|
364
382
|
#endif
|
|
365
383
|
|
|
366
384
|
BOOL shouldAnimate = lastModal && [next isKindOfClass:[RNSScreen class]] &&
|
|
367
|
-
((
|
|
385
|
+
((RNSScreen *)next).screenView.stackAnimation != RNSScreenStackAnimationNone;
|
|
368
386
|
|
|
369
387
|
// if you want to present another modal quick enough after dismissing the previous one,
|
|
370
388
|
// it will result in wrong changeRootController, see repro in
|
|
@@ -391,7 +409,7 @@
|
|
|
391
409
|
[_presentedModals containsObject:changeRootController.presentedViewController]) {
|
|
392
410
|
BOOL shouldAnimate = changeRootIndex == controllers.count &&
|
|
393
411
|
[changeRootController.presentedViewController isKindOfClass:[RNSScreen class]] &&
|
|
394
|
-
((
|
|
412
|
+
((RNSScreen *)changeRootController.presentedViewController).screenView.stackAnimation !=
|
|
395
413
|
RNSScreenStackAnimationNone;
|
|
396
414
|
[changeRootController dismissViewControllerAnimated:shouldAnimate completion:finish];
|
|
397
415
|
} else {
|
|
@@ -434,33 +452,39 @@
|
|
|
434
452
|
}
|
|
435
453
|
|
|
436
454
|
UIViewController *top = controllers.lastObject;
|
|
437
|
-
|
|
455
|
+
#ifdef RN_FABRIC_ENABLED
|
|
456
|
+
UIViewController *previousTop = _controller.topViewController;
|
|
457
|
+
#else
|
|
458
|
+
UIViewController *previousTop = _controller.viewControllers.lastObject;
|
|
459
|
+
#endif
|
|
438
460
|
|
|
439
|
-
//
|
|
461
|
+
// At the start we set viewControllers to contain a single UIViewController
|
|
440
462
|
// instance. This is a workaround for header height adjustment bug (see comment
|
|
441
463
|
// in the init function). Here, we need to detect if the initial empty
|
|
442
464
|
// controller is still there
|
|
443
|
-
BOOL firstTimePush = ![
|
|
465
|
+
BOOL firstTimePush = ![previousTop isKindOfClass:[RNSScreen class]];
|
|
444
466
|
|
|
445
467
|
if (firstTimePush) {
|
|
446
468
|
// nothing pushed yet
|
|
447
469
|
[_controller setViewControllers:controllers animated:NO];
|
|
448
|
-
} else if (top !=
|
|
449
|
-
|
|
450
|
-
// `stackAnimation: 'none'`, which will resolve in no animation anyways.
|
|
451
|
-
if (![controllers containsObject:lastTop]) {
|
|
470
|
+
} else if (top != previousTop) {
|
|
471
|
+
if (![controllers containsObject:previousTop]) {
|
|
452
472
|
// if the previous top screen does not exist anymore and the new top was not on the stack before, probably replace
|
|
453
473
|
// was called, so we check the animation
|
|
454
474
|
if (![_controller.viewControllers containsObject:top] &&
|
|
455
475
|
((RNSScreenView *)top.view).replaceAnimation == RNSScreenReplaceAnimationPush) {
|
|
456
476
|
// setting new controllers with animation does `push` animation by default
|
|
477
|
+
#ifdef RN_FABRIC_ENABLED
|
|
478
|
+
auto screenController = (RNSScreen *)top;
|
|
479
|
+
[screenController resetViewToScreen];
|
|
480
|
+
#endif
|
|
457
481
|
[_controller setViewControllers:controllers animated:YES];
|
|
458
482
|
} else {
|
|
459
483
|
// last top controller is no longer on stack
|
|
460
484
|
// in this case we set the controllers stack to the new list with
|
|
461
485
|
// added the last top element to it and perform (animated) pop
|
|
462
486
|
NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers];
|
|
463
|
-
[newControllers addObject:
|
|
487
|
+
[newControllers addObject:previousTop];
|
|
464
488
|
[_controller setViewControllers:newControllers animated:NO];
|
|
465
489
|
[_controller popViewControllerAnimated:YES];
|
|
466
490
|
}
|
|
@@ -471,6 +495,10 @@
|
|
|
471
495
|
NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers];
|
|
472
496
|
[newControllers removeLastObject];
|
|
473
497
|
[_controller setViewControllers:newControllers animated:NO];
|
|
498
|
+
#ifdef RN_FABRIC_ENABLED
|
|
499
|
+
auto screenController = (RNSScreen *)top;
|
|
500
|
+
[screenController resetViewToScreen];
|
|
501
|
+
#endif
|
|
474
502
|
[_controller pushViewController:top animated:YES];
|
|
475
503
|
} else {
|
|
476
504
|
// don't really know what this case could be, but may need to handle it
|
|
@@ -506,45 +534,23 @@
|
|
|
506
534
|
[self setModalViewControllers:modalControllers];
|
|
507
535
|
}
|
|
508
536
|
|
|
509
|
-
// By default, the header buttons that are not inside the native hit area
|
|
510
|
-
// cannot be clicked, so we check it by ourselves
|
|
511
|
-
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
|
512
|
-
{
|
|
513
|
-
if (CGRectContainsPoint(_controller.navigationBar.frame, point)) {
|
|
514
|
-
// headerConfig should be the first subview of the topmost screen
|
|
515
|
-
UIView *headerConfig = [[_reactSubviews.lastObject reactSubviews] firstObject];
|
|
516
|
-
if ([headerConfig isKindOfClass:[RNSScreenStackHeaderConfig class]]) {
|
|
517
|
-
UIView *headerHitTestResult = [headerConfig hitTest:point withEvent:event];
|
|
518
|
-
if (headerHitTestResult != nil) {
|
|
519
|
-
return headerHitTestResult;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
return [super hitTest:point withEvent:event];
|
|
524
|
-
}
|
|
525
|
-
|
|
526
537
|
- (void)layoutSubviews
|
|
527
538
|
{
|
|
528
539
|
[super layoutSubviews];
|
|
529
540
|
_controller.view.frame = self.bounds;
|
|
530
541
|
}
|
|
531
542
|
|
|
532
|
-
- (void)invalidate
|
|
533
|
-
{
|
|
534
|
-
_invalidated = YES;
|
|
535
|
-
for (UIViewController *controller in _presentedModals) {
|
|
536
|
-
[controller dismissViewControllerAnimated:NO completion:nil];
|
|
537
|
-
}
|
|
538
|
-
[_presentedModals removeAllObjects];
|
|
539
|
-
[_controller willMoveToParentViewController:nil];
|
|
540
|
-
[_controller removeFromParentViewController];
|
|
541
|
-
}
|
|
542
|
-
|
|
543
543
|
- (void)dismissOnReload
|
|
544
544
|
{
|
|
545
|
+
#ifdef RN_FABRIC_ENABLED
|
|
546
|
+
if ([_controller.visibleViewController isKindOfClass:[RNSScreen class]]) {
|
|
547
|
+
[(RNSScreen *)_controller.visibleViewController resetViewToScreen];
|
|
548
|
+
}
|
|
549
|
+
#else
|
|
545
550
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
546
551
|
[self invalidate];
|
|
547
552
|
});
|
|
553
|
+
#endif
|
|
548
554
|
}
|
|
549
555
|
|
|
550
556
|
#pragma mark methods connected to transitioning
|
|
@@ -556,9 +562,9 @@
|
|
|
556
562
|
{
|
|
557
563
|
RNSScreenView *screen;
|
|
558
564
|
if (operation == UINavigationControllerOperationPush) {
|
|
559
|
-
screen = (
|
|
565
|
+
screen = ((RNSScreen *)toVC).screenView;
|
|
560
566
|
} else if (operation == UINavigationControllerOperationPop) {
|
|
561
|
-
screen = (
|
|
567
|
+
screen = ((RNSScreen *)fromVC).screenView;
|
|
562
568
|
}
|
|
563
569
|
if (screen != nil &&
|
|
564
570
|
// we need to return the animator when full width swiping even if the animation is not custom,
|
|
@@ -579,29 +585,29 @@
|
|
|
579
585
|
while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)])
|
|
580
586
|
parent = parent.superview;
|
|
581
587
|
if (parent != nil) {
|
|
588
|
+
#ifdef RN_FABRIC_ENABLED
|
|
589
|
+
RCTSurfaceTouchHandler *touchHandler = [parent performSelector:@selector(touchHandler)];
|
|
590
|
+
#else
|
|
582
591
|
RCTTouchHandler *touchHandler = [parent performSelector:@selector(touchHandler)];
|
|
583
|
-
|
|
592
|
+
#endif
|
|
593
|
+
[touchHandler setEnabled:NO];
|
|
594
|
+
[touchHandler setEnabled:YES];
|
|
584
595
|
[touchHandler reset];
|
|
585
596
|
}
|
|
586
597
|
}
|
|
587
598
|
|
|
588
599
|
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
|
|
589
600
|
{
|
|
590
|
-
RNSScreenView *topScreen =
|
|
591
|
-
|
|
592
|
-
if (![topScreen isKindOfClass:[RNSScreenView class]] || !topScreen.gestureEnabled ||
|
|
593
|
-
_controller.viewControllers.count < 2) {
|
|
594
|
-
return NO;
|
|
595
|
-
}
|
|
601
|
+
RNSScreenView *topScreen = _reactSubviews.lastObject;
|
|
596
602
|
|
|
597
603
|
#if TARGET_OS_TV
|
|
598
604
|
[self cancelTouchesInParent];
|
|
599
605
|
return YES;
|
|
600
606
|
#else
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
if ([gestureRecognizer
|
|
607
|
+
// RNSPanGestureRecognizer will receive events iff topScreen.fullScreenSwipeEnabled == YES;
|
|
608
|
+
// Events are filtered in gestureRecognizer:shouldReceivePressOrTouchEvent: method
|
|
609
|
+
if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) {
|
|
610
|
+
if ([self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) {
|
|
605
611
|
_isFullWidthSwiping = YES;
|
|
606
612
|
[self cancelTouchesInParent];
|
|
607
613
|
return YES;
|
|
@@ -609,6 +615,7 @@
|
|
|
609
615
|
return NO;
|
|
610
616
|
}
|
|
611
617
|
|
|
618
|
+
// Now we're dealing with RNSScreenEdgeGestureRecognizer (or _UIParallaxTransitionPanGestureRecognizer)
|
|
612
619
|
if (topScreen.customAnimationOnSwipe && [RNSScreenStackAnimator isCustomAnimation:topScreen.stackAnimation]) {
|
|
613
620
|
if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) {
|
|
614
621
|
// if we do not set any explicit `semanticContentAttribute`, it is `UISemanticContentAttributeUnspecified` instead
|
|
@@ -627,14 +634,13 @@
|
|
|
627
634
|
if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) {
|
|
628
635
|
// it should only recognize with `customAnimationOnSwipe` set
|
|
629
636
|
return NO;
|
|
630
|
-
} else if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) {
|
|
631
|
-
// it should only recognize with `fullScreenSwipeEnabled` set
|
|
632
|
-
return NO;
|
|
633
637
|
}
|
|
638
|
+
// _UIParallaxTransitionPanGestureRecognizer (other...)
|
|
634
639
|
[self cancelTouchesInParent];
|
|
635
640
|
return YES;
|
|
636
641
|
}
|
|
637
|
-
|
|
642
|
+
|
|
643
|
+
#endif // TARGET_OS_TV
|
|
638
644
|
}
|
|
639
645
|
|
|
640
646
|
#if !TARGET_OS_TV
|
|
@@ -662,7 +668,7 @@
|
|
|
662
668
|
|
|
663
669
|
- (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer
|
|
664
670
|
{
|
|
665
|
-
RNSScreenView *topScreen =
|
|
671
|
+
RNSScreenView *topScreen = _reactSubviews.lastObject;
|
|
666
672
|
float translation;
|
|
667
673
|
float velocity;
|
|
668
674
|
float distance;
|
|
@@ -716,7 +722,6 @@
|
|
|
716
722
|
}
|
|
717
723
|
}
|
|
718
724
|
}
|
|
719
|
-
#endif
|
|
720
725
|
|
|
721
726
|
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
|
|
722
727
|
interactionControllerForAnimationController:
|
|
@@ -731,8 +736,294 @@
|
|
|
731
736
|
return _interactionController;
|
|
732
737
|
}
|
|
733
738
|
|
|
739
|
+
- (void)navigationController:(UINavigationController *)navigationController
|
|
740
|
+
didShowViewController:(UIViewController *)viewController
|
|
741
|
+
animated:(BOOL)animated
|
|
742
|
+
{
|
|
743
|
+
[self emitOnFinishTransitioningEvent];
|
|
744
|
+
[RNSScreenWindowTraits updateWindowTraits];
|
|
745
|
+
}
|
|
746
|
+
#endif
|
|
747
|
+
|
|
748
|
+
- (void)markChildUpdated
|
|
749
|
+
{
|
|
750
|
+
// do nothing
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
- (void)didUpdateChildren
|
|
754
|
+
{
|
|
755
|
+
// do nothing
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
- (UIViewController *)reactViewController
|
|
759
|
+
{
|
|
760
|
+
return _controller;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
- (BOOL)isInGestureResponseDistance:(UIGestureRecognizer *)gestureRecognizer topScreen:(RNSScreenView *)topScreen
|
|
764
|
+
{
|
|
765
|
+
NSDictionary *gestureResponseDistanceValues = topScreen.gestureResponseDistance;
|
|
766
|
+
float x = [gestureRecognizer locationInView:gestureRecognizer.view].x;
|
|
767
|
+
float y = [gestureRecognizer locationInView:gestureRecognizer.view].y;
|
|
768
|
+
BOOL isRTL = _controller.view.semanticContentAttribute == UISemanticContentAttributeForceRightToLeft;
|
|
769
|
+
if (isRTL) {
|
|
770
|
+
x = _controller.view.frame.size.width - x;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// see:
|
|
774
|
+
// https://github.com/software-mansion/react-native-screens/pull/1442/commits/74d4bae321875d8305ad021b3d448ebf713e7d56
|
|
775
|
+
// this prop is always default initialized so we do not expect any nils
|
|
776
|
+
float start = [gestureResponseDistanceValues[@"start"] floatValue];
|
|
777
|
+
float end = [gestureResponseDistanceValues[@"end"] floatValue];
|
|
778
|
+
float top = [gestureResponseDistanceValues[@"top"] floatValue];
|
|
779
|
+
float bottom = [gestureResponseDistanceValues[@"bottom"] floatValue];
|
|
780
|
+
|
|
781
|
+
// we check if any of the constraints are violated and return NO if so
|
|
782
|
+
return !(
|
|
783
|
+
(start != -1 && x < start) || (end != -1 && x > end) || (top != -1 && y < top) || (bottom != -1 && y > bottom));
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// By default, the header buttons that are not inside the native hit area
|
|
787
|
+
// cannot be clicked, so we check it by ourselves
|
|
788
|
+
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
|
789
|
+
{
|
|
790
|
+
if (CGRectContainsPoint(_controller.navigationBar.frame, point)) {
|
|
791
|
+
// headerConfig should be the first subview of the topmost screen
|
|
792
|
+
UIView *headerConfig = [[_reactSubviews.lastObject reactSubviews] firstObject];
|
|
793
|
+
if ([headerConfig isKindOfClass:[RNSScreenStackHeaderConfig class]]) {
|
|
794
|
+
UIView *headerHitTestResult = [headerConfig hitTest:point withEvent:event];
|
|
795
|
+
if (headerHitTestResult != nil) {
|
|
796
|
+
return headerHitTestResult;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return [super hitTest:point withEvent:event];
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
#if !TARGET_OS_TV
|
|
804
|
+
|
|
805
|
+
- (BOOL)isScrollViewPanGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
|
|
806
|
+
{
|
|
807
|
+
// NOTE: This hack is required to restore native behavior of edge swipe (interactive pop gesture)
|
|
808
|
+
// without this, on a screen with a scroll view, it's only possible to pop view by panning horizontally
|
|
809
|
+
// if even slightly diagonal (or if in motion), scroll view will scroll, and edge swipe will be cancelled
|
|
810
|
+
if (![[gestureRecognizer view] isKindOfClass:[UIScrollView class]]) {
|
|
811
|
+
return NO;
|
|
812
|
+
}
|
|
813
|
+
UIScrollView *scrollView = (UIScrollView *)gestureRecognizer.view;
|
|
814
|
+
return scrollView.panGestureRecognizer == gestureRecognizer;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// Custom method for compatibility with iOS < 13.4
|
|
818
|
+
// RNSScreenStackView is a UIGestureRecognizerDelegate for three types of gesture recognizers:
|
|
819
|
+
// RNSPanGestureRecognizer, RNSScreenEdgeGestureRecognizer, _UIParallaxTransitionPanGestureRecognizer
|
|
820
|
+
// Be careful when adding another type of gesture recognizer.
|
|
821
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePressOrTouchEvent:(NSObject *)event
|
|
822
|
+
{
|
|
823
|
+
RNSScreenView *topScreen = _reactSubviews.lastObject;
|
|
824
|
+
|
|
825
|
+
if (![topScreen isKindOfClass:[RNSScreenView class]] || !topScreen.gestureEnabled ||
|
|
826
|
+
_controller.viewControllers.count < 2) {
|
|
827
|
+
return NO;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// We want to pass events to RNSPanGestureRecognizer iff full screen swipe is enabled.
|
|
831
|
+
if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) {
|
|
832
|
+
return topScreen.fullScreenSwipeEnabled;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// RNSScreenEdgeGestureRecognizer || _UIParallaxTransitionPanGestureRecognizer
|
|
836
|
+
return YES;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePress:(UIPress *)press;
|
|
840
|
+
{
|
|
841
|
+
return [self gestureRecognizer:gestureRecognizer shouldReceivePressOrTouchEvent:press];
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
|
|
845
|
+
{
|
|
846
|
+
return [self gestureRecognizer:gestureRecognizer shouldReceivePressOrTouchEvent:touch];
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
|
|
850
|
+
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
|
|
851
|
+
{
|
|
852
|
+
if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]] &&
|
|
853
|
+
[self isScrollViewPanGestureRecognizer:otherGestureRecognizer]) {
|
|
854
|
+
RNSPanGestureRecognizer *panGestureRecognizer = (RNSPanGestureRecognizer *)gestureRecognizer;
|
|
855
|
+
BOOL isBackGesture = [panGestureRecognizer translationInView:panGestureRecognizer.view].x > 0 &&
|
|
856
|
+
_controller.viewControllers.count > 1;
|
|
857
|
+
|
|
858
|
+
if (gestureRecognizer.state == UIGestureRecognizerStateBegan || isBackGesture) {
|
|
859
|
+
return NO;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
return YES;
|
|
863
|
+
}
|
|
864
|
+
return NO;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
|
|
868
|
+
shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
|
|
869
|
+
{
|
|
870
|
+
return (
|
|
871
|
+
[gestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]] &&
|
|
872
|
+
[self isScrollViewPanGestureRecognizer:otherGestureRecognizer]);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
#endif // !TARGET_OS_TV
|
|
876
|
+
|
|
877
|
+
- (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex
|
|
878
|
+
{
|
|
879
|
+
if (![subview isKindOfClass:[RNSScreenView class]]) {
|
|
880
|
+
RCTLogError(@"ScreenStack only accepts children of type Screen");
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
subview.reactSuperview = self;
|
|
884
|
+
[_reactSubviews insertObject:subview atIndex:atIndex];
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
- (void)removeReactSubview:(RNSScreenView *)subview
|
|
888
|
+
{
|
|
889
|
+
subview.reactSuperview = nil;
|
|
890
|
+
[_reactSubviews removeObject:subview];
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
- (void)didUpdateReactSubviews
|
|
894
|
+
{
|
|
895
|
+
// we need to wait until children have their layout set. At this point they don't have the layout
|
|
896
|
+
// set yet, however the layout call is already enqueued on ui thread. Enqueuing update call on the
|
|
897
|
+
// ui queue will guarantee that the update will run after layout.
|
|
898
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
899
|
+
self->_hasLayout = YES;
|
|
900
|
+
[self maybeAddToParentAndUpdateContainer];
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
#ifdef RN_FABRIC_ENABLED
|
|
905
|
+
#pragma mark - Fabric specific
|
|
906
|
+
|
|
907
|
+
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
|
|
908
|
+
{
|
|
909
|
+
if (![childComponentView isKindOfClass:[RNSScreenView class]]) {
|
|
910
|
+
RCTLogError(@"ScreenStack only accepts children of type Screen");
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
RCTAssert(
|
|
915
|
+
childComponentView.reactSuperview == nil,
|
|
916
|
+
@"Attempt to mount already mounted component view. (parent: %@, child: %@, index: %@, existing parent: %@)",
|
|
917
|
+
self,
|
|
918
|
+
childComponentView,
|
|
919
|
+
@(index),
|
|
920
|
+
@([childComponentView.superview tag]));
|
|
921
|
+
|
|
922
|
+
[_reactSubviews insertObject:(RNSScreenView *)childComponentView atIndex:index];
|
|
923
|
+
((RNSScreenView *)childComponentView).reactSuperview = self;
|
|
924
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
925
|
+
[self maybeAddToParentAndUpdateContainer];
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
|
|
930
|
+
{
|
|
931
|
+
RNSScreenView *screenChildComponent = (RNSScreenView *)childComponentView;
|
|
932
|
+
// We should only do a snapshot of a screen that is on the top.
|
|
933
|
+
// We also check `_presentedModals` since if you push 2 modals, second one is not a "child" of _controller.
|
|
934
|
+
// Also, when dissmised with a gesture, the screen already is not under the window, so we don't need to apply
|
|
935
|
+
// snapshot.
|
|
936
|
+
if (screenChildComponent.window != nil &&
|
|
937
|
+
((screenChildComponent == _controller.visibleViewController.view && _presentedModals.count < 2) ||
|
|
938
|
+
screenChildComponent == [_presentedModals.lastObject view])) {
|
|
939
|
+
[screenChildComponent.controller setViewToSnapshot:_snapshot];
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
RCTAssert(
|
|
943
|
+
screenChildComponent.reactSuperview == self,
|
|
944
|
+
@"Attempt to unmount a view which is mounted inside different view. (parent: %@, child: %@, index: %@)",
|
|
945
|
+
self,
|
|
946
|
+
screenChildComponent,
|
|
947
|
+
@(index));
|
|
948
|
+
RCTAssert(
|
|
949
|
+
(_reactSubviews.count > index) && [_reactSubviews objectAtIndex:index] == childComponentView,
|
|
950
|
+
@"Attempt to unmount a view which has a different index. (parent: %@, child: %@, index: %@, actual index: %@, tag at index: %@)",
|
|
951
|
+
self,
|
|
952
|
+
screenChildComponent,
|
|
953
|
+
@(index),
|
|
954
|
+
@([_reactSubviews indexOfObject:screenChildComponent]),
|
|
955
|
+
@([[_reactSubviews objectAtIndex:index] tag]));
|
|
956
|
+
screenChildComponent.reactSuperview = nil;
|
|
957
|
+
[_reactSubviews removeObject:screenChildComponent];
|
|
958
|
+
[screenChildComponent removeFromSuperview];
|
|
959
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
960
|
+
[self maybeAddToParentAndUpdateContainer];
|
|
961
|
+
});
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
- (void)takeSnapshot
|
|
965
|
+
{
|
|
966
|
+
_snapshot = [_controller.visibleViewController.view snapshotViewAfterScreenUpdates:NO];
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
- (void)mountingTransactionWillMount:(facebook::react::MountingTransaction const &)transaction
|
|
970
|
+
withSurfaceTelemetry:(facebook::react::SurfaceTelemetry const &)surfaceTelemetry
|
|
971
|
+
{
|
|
972
|
+
for (auto mutation : transaction.getMutations()) {
|
|
973
|
+
if (mutation.type == facebook::react::ShadowViewMutation::Type::Remove &&
|
|
974
|
+
mutation.parentShadowView.componentName != nil &&
|
|
975
|
+
strcmp(mutation.parentShadowView.componentName, "RNSScreenStack") == 0) {
|
|
976
|
+
[self takeSnapshot];
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
- (void)prepareForRecycle
|
|
983
|
+
{
|
|
984
|
+
[super prepareForRecycle];
|
|
985
|
+
_reactSubviews = [NSMutableArray new];
|
|
986
|
+
|
|
987
|
+
for (UIViewController *controller in _presentedModals) {
|
|
988
|
+
[controller dismissViewControllerAnimated:NO completion:nil];
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
[_presentedModals removeAllObjects];
|
|
992
|
+
[self dismissOnReload];
|
|
993
|
+
[_controller willMoveToParentViewController:nil];
|
|
994
|
+
[_controller removeFromParentViewController];
|
|
995
|
+
[_controller setViewControllers:@[ [UIViewController new] ]];
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
+ (facebook::react::ComponentDescriptorProvider)componentDescriptorProvider
|
|
999
|
+
{
|
|
1000
|
+
return facebook::react::concreteComponentDescriptorProvider<facebook::react::RNSScreenStackComponentDescriptor>();
|
|
1001
|
+
}
|
|
1002
|
+
#else
|
|
1003
|
+
#pragma mark - Paper specific
|
|
1004
|
+
|
|
1005
|
+
- (void)invalidate
|
|
1006
|
+
{
|
|
1007
|
+
_invalidated = YES;
|
|
1008
|
+
for (UIViewController *controller in _presentedModals) {
|
|
1009
|
+
[controller dismissViewControllerAnimated:NO completion:nil];
|
|
1010
|
+
}
|
|
1011
|
+
[_presentedModals removeAllObjects];
|
|
1012
|
+
[_controller willMoveToParentViewController:nil];
|
|
1013
|
+
[_controller removeFromParentViewController];
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
#endif // RN_FABRIC_ENABLED
|
|
1017
|
+
|
|
734
1018
|
@end
|
|
735
1019
|
|
|
1020
|
+
#ifdef RN_FABRIC_ENABLED
|
|
1021
|
+
Class<RCTComponentViewProtocol> RNSScreenStackCls(void)
|
|
1022
|
+
{
|
|
1023
|
+
return RNSScreenStackView.class;
|
|
1024
|
+
}
|
|
1025
|
+
#endif
|
|
1026
|
+
|
|
736
1027
|
@implementation RNSScreenStackManager {
|
|
737
1028
|
NSPointerArray *_stacks;
|
|
738
1029
|
}
|
|
@@ -741,6 +1032,8 @@ RCT_EXPORT_MODULE()
|
|
|
741
1032
|
|
|
742
1033
|
RCT_EXPORT_VIEW_PROPERTY(onFinishTransitioning, RCTDirectEventBlock);
|
|
743
1034
|
|
|
1035
|
+
#ifdef RN_FABRIC_ENABLED
|
|
1036
|
+
#else
|
|
744
1037
|
- (UIView *)view
|
|
745
1038
|
{
|
|
746
1039
|
RNSScreenStackView *view = [[RNSScreenStackView alloc] initWithManager:self];
|
|
@@ -750,6 +1043,7 @@ RCT_EXPORT_VIEW_PROPERTY(onFinishTransitioning, RCTDirectEventBlock);
|
|
|
750
1043
|
[_stacks addPointer:(__bridge void *)view];
|
|
751
1044
|
return view;
|
|
752
1045
|
}
|
|
1046
|
+
#endif // RN_FABRIC_ENABLED
|
|
753
1047
|
|
|
754
1048
|
- (void)invalidate
|
|
755
1049
|
{
|