@lodev09/react-native-true-sheet 3.7.3 → 3.7.4-beta.1
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/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +0 -4
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +29 -30
- package/android/src/main/java/com/lodev09/truesheet/core/RNScreensFragmentObserver.kt +65 -14
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +4 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +13 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +11 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +12 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +10 -0
- package/ios/TrueSheetContainerView.mm +7 -15
- package/ios/TrueSheetContentView.h +2 -2
- package/ios/TrueSheetContentView.mm +84 -89
- package/ios/TrueSheetHeaderView.mm +1 -3
- package/ios/TrueSheetView.mm +72 -14
- package/ios/TrueSheetViewController.h +0 -15
- package/ios/TrueSheetViewController.mm +76 -146
- package/ios/core/RNScreensEventObserver.h +43 -0
- package/ios/core/RNScreensEventObserver.mm +119 -0
- package/ios/core/TrueSheetBlurView.mm +26 -22
- package/ios/utils/LayoutUtil.h +23 -0
- package/ios/utils/LayoutUtil.mm +28 -3
- package/lib/module/TrueSheet.js +16 -5
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/typescript/src/TrueSheet.d.ts +4 -0
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/TrueSheet.tsx +16 -3
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
BOOL _isDragging;
|
|
35
35
|
BOOL _isTransitioning;
|
|
36
36
|
BOOL _isTrackingPositionFromLayout;
|
|
37
|
+
BOOL _isWillDismissEmitted;
|
|
37
38
|
|
|
38
39
|
__weak TrueSheetViewController *_parentSheetController;
|
|
39
40
|
|
|
@@ -57,11 +58,12 @@
|
|
|
57
58
|
_lastPosition = 0;
|
|
58
59
|
_isDragging = NO;
|
|
59
60
|
_isPresented = NO;
|
|
61
|
+
_isTransitioning = NO;
|
|
62
|
+
_isWillDismissEmitted = NO;
|
|
60
63
|
_pendingContentSizeChange = NO;
|
|
61
64
|
_activeDetentIndex = -1;
|
|
62
65
|
_pendingDetentIndex = -1;
|
|
63
66
|
|
|
64
|
-
_isTransitioning = NO;
|
|
65
67
|
_transitionFakeView = [UIView new];
|
|
66
68
|
_isTrackingPositionFromLayout = NO;
|
|
67
69
|
|
|
@@ -165,6 +167,9 @@
|
|
|
165
167
|
[super viewDidLoad];
|
|
166
168
|
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
|
|
167
169
|
|
|
170
|
+
_blurView = [[TrueSheetBlurView alloc] init];
|
|
171
|
+
[_blurView addToView:self.view];
|
|
172
|
+
|
|
168
173
|
_grabberView = [[TrueSheetGrabberView alloc] init];
|
|
169
174
|
_grabberView.hidden = YES;
|
|
170
175
|
[_grabberView addToView:self.view];
|
|
@@ -181,23 +186,16 @@
|
|
|
181
186
|
UIViewController *presenter = self.presentingViewController;
|
|
182
187
|
if ([presenter isKindOfClass:[TrueSheetViewController class]]) {
|
|
183
188
|
_parentSheetController = (TrueSheetViewController *)presenter;
|
|
184
|
-
|
|
185
|
-
[_parentSheetController.delegate viewControllerWillBlur];
|
|
186
|
-
}
|
|
189
|
+
[_parentSheetController.delegate viewControllerWillBlur];
|
|
187
190
|
}
|
|
188
191
|
|
|
189
192
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
CGFloat detent = [self detentValueForIndex:index];
|
|
194
|
-
|
|
195
|
-
[self.delegate viewControllerWillPresentAtIndex:index position:position detent:detent];
|
|
196
|
-
}
|
|
193
|
+
NSInteger index = self.currentDetentIndex;
|
|
194
|
+
CGFloat position = self.currentPosition;
|
|
195
|
+
CGFloat detent = [self detentValueForIndex:index];
|
|
197
196
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
197
|
+
[self.delegate viewControllerWillPresentAtIndex:index position:position detent:detent];
|
|
198
|
+
[self.delegate viewControllerWillFocus];
|
|
201
199
|
});
|
|
202
200
|
}
|
|
203
201
|
|
|
@@ -208,22 +206,13 @@
|
|
|
208
206
|
[super viewDidAppear:animated];
|
|
209
207
|
|
|
210
208
|
if (!_isPresented) {
|
|
211
|
-
|
|
212
|
-
if ([_parentSheetController.delegate respondsToSelector:@selector(viewControllerDidBlur)]) {
|
|
213
|
-
[_parentSheetController.delegate viewControllerDidBlur];
|
|
214
|
-
}
|
|
215
|
-
}
|
|
209
|
+
[_parentSheetController.delegate viewControllerDidBlur];
|
|
216
210
|
|
|
217
211
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if ([self.delegate respondsToSelector:@selector(viewControllerDidFocus)]) {
|
|
225
|
-
[self.delegate viewControllerDidFocus];
|
|
226
|
-
}
|
|
212
|
+
NSInteger index = [self currentDetentIndex];
|
|
213
|
+
CGFloat detent = [self detentValueForIndex:index];
|
|
214
|
+
[self.delegate viewControllerDidPresentAtIndex:index position:self.currentPosition detent:detent];
|
|
215
|
+
[self.delegate viewControllerDidFocus];
|
|
227
216
|
|
|
228
217
|
[self emitChangePositionDelegateWithPosition:self.currentPosition realtime:NO debug:@"did present"];
|
|
229
218
|
});
|
|
@@ -237,52 +226,46 @@
|
|
|
237
226
|
return self.presentingViewController == nil || self.isBeingDismissed;
|
|
238
227
|
}
|
|
239
228
|
|
|
240
|
-
- (void)
|
|
241
|
-
|
|
229
|
+
- (void)emitWillDismissEvents {
|
|
230
|
+
if (self.isDismissing && !_isWillDismissEmitted) {
|
|
231
|
+
_isWillDismissEmitted = YES;
|
|
242
232
|
|
|
233
|
+
[self.delegate viewControllerWillBlur];
|
|
234
|
+
[self.delegate viewControllerWillDismiss];
|
|
235
|
+
[_parentSheetController.delegate viewControllerWillFocus];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
- (void)emitDidDismissEvents {
|
|
243
240
|
if (self.isDismissing) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
[self.delegate viewControllerWillBlur];
|
|
247
|
-
}
|
|
241
|
+
_isPresented = NO;
|
|
242
|
+
_isWillDismissEmitted = NO;
|
|
248
243
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
});
|
|
244
|
+
[_parentSheetController.delegate viewControllerDidFocus];
|
|
245
|
+
_parentSheetController = nil;
|
|
253
246
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
[_parentSheetController.delegate viewControllerWillFocus];
|
|
257
|
-
}
|
|
258
|
-
}
|
|
247
|
+
[self.delegate viewControllerDidBlur];
|
|
248
|
+
[self.delegate viewControllerDidDismiss];
|
|
259
249
|
}
|
|
260
|
-
|
|
261
|
-
[self setupTransitionTracker];
|
|
262
250
|
}
|
|
263
251
|
|
|
264
|
-
- (void)
|
|
265
|
-
[super
|
|
266
|
-
|
|
267
|
-
if (self.isDismissing) {
|
|
268
|
-
_isPresented = NO;
|
|
269
|
-
_activeDetentIndex = -1;
|
|
252
|
+
- (void)viewWillDisappear:(BOOL)animated {
|
|
253
|
+
[super viewWillDisappear:animated];
|
|
270
254
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
255
|
+
// Dispatch to allow pan gesture to set _isDragging before checking
|
|
256
|
+
// handleTransitionTracker will emit when sheet is transitioning to dismiss
|
|
257
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
258
|
+
if (!self->_isDragging) {
|
|
259
|
+
[self emitWillDismissEvents];
|
|
276
260
|
}
|
|
261
|
+
});
|
|
277
262
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
263
|
+
[self setupTransitionTracker];
|
|
264
|
+
}
|
|
281
265
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
266
|
+
- (void)viewDidDisappear:(BOOL)animated {
|
|
267
|
+
[super viewDidDisappear:animated];
|
|
268
|
+
[self emitDidDismissEvents];
|
|
286
269
|
}
|
|
287
270
|
|
|
288
271
|
- (void)viewWillLayoutSubviews {
|
|
@@ -309,21 +292,17 @@
|
|
|
309
292
|
- (void)viewDidLayoutSubviews {
|
|
310
293
|
[super viewDidLayoutSubviews];
|
|
311
294
|
|
|
312
|
-
|
|
313
|
-
[self.delegate viewControllerDidChangeSize:self.view.frame.size];
|
|
314
|
-
}
|
|
295
|
+
[self.delegate viewControllerDidChangeSize:self.view.frame.size];
|
|
315
296
|
|
|
316
297
|
if (_pendingDetentIndex >= 0) {
|
|
317
298
|
NSInteger pendingIndex = _pendingDetentIndex;
|
|
318
299
|
_pendingDetentIndex = -1;
|
|
319
300
|
|
|
320
301
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
[self emitChangePositionDelegateWithPosition:self.currentPosition realtime:NO debug:@"pending detent change"];
|
|
326
|
-
}
|
|
302
|
+
[self storeResolvedPositionForIndex:pendingIndex];
|
|
303
|
+
CGFloat detent = [self detentValueForIndex:pendingIndex];
|
|
304
|
+
[self.delegate viewControllerDidChangeDetent:pendingIndex position:self.currentPosition detent:detent];
|
|
305
|
+
[self emitChangePositionDelegateWithPosition:self.currentPosition realtime:NO debug:@"pending detent change"];
|
|
327
306
|
});
|
|
328
307
|
}
|
|
329
308
|
|
|
@@ -382,9 +361,7 @@
|
|
|
382
361
|
NSInteger index = self.currentDetentIndex;
|
|
383
362
|
CGFloat detent = [self detentValueForIndex:index];
|
|
384
363
|
|
|
385
|
-
|
|
386
|
-
[self.delegate viewControllerDidDrag:gesture.state index:index position:self.currentPosition detent:detent];
|
|
387
|
-
}
|
|
364
|
+
[self.delegate viewControllerDidDrag:gesture.state index:index position:self.currentPosition detent:detent];
|
|
388
365
|
|
|
389
366
|
switch (gesture.state) {
|
|
390
367
|
case UIGestureRecognizerStateBegan:
|
|
@@ -449,7 +426,10 @@
|
|
|
449
426
|
|
|
450
427
|
if (self.currentPosition >= self.screenHeight) {
|
|
451
428
|
CGFloat position = fmax(_lastPosition, layerPosition);
|
|
429
|
+
|
|
430
|
+
[self emitWillDismissEvents];
|
|
452
431
|
[self emitChangePositionDelegateWithPosition:position realtime:YES debug:@"transition out"];
|
|
432
|
+
|
|
453
433
|
} else {
|
|
454
434
|
CGFloat position = fmax(self.currentPosition, layerPosition);
|
|
455
435
|
[self emitChangePositionDelegateWithPosition:position realtime:YES debug:@"transition in"];
|
|
@@ -472,9 +452,7 @@
|
|
|
472
452
|
|
|
473
453
|
CGFloat index = [self interpolatedIndexForPosition:position];
|
|
474
454
|
CGFloat detent = [self interpolatedDetentForPosition:position];
|
|
475
|
-
|
|
476
|
-
[self.delegate viewControllerDidChangePosition:index position:position detent:detent realtime:realtime];
|
|
477
|
-
}
|
|
455
|
+
[self.delegate viewControllerDidChangePosition:index position:position detent:detent realtime:realtime];
|
|
478
456
|
}
|
|
479
457
|
}
|
|
480
458
|
|
|
@@ -671,32 +649,6 @@
|
|
|
671
649
|
}
|
|
672
650
|
|
|
673
651
|
- (void)setupBackground {
|
|
674
|
-
#if RNTS_IPHONE_OS_VERSION_AVAILABLE(26_1)
|
|
675
|
-
BOOL useBackgroundEffect = NO;
|
|
676
|
-
if (@available(iOS 26.1, *)) {
|
|
677
|
-
useBackgroundEffect = !self.isDesignCompatibilityMode;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
// iOS 26.1+: use native backgroundEffect when only backgroundBlur is set (no backgroundColor)
|
|
681
|
-
// Fall back to TrueSheetBlurView when blur intensity is set (not 100%) since
|
|
682
|
-
// sheet.backgroundEffect doesn't support intensity control
|
|
683
|
-
if (@available(iOS 26.1, *)) {
|
|
684
|
-
if (useBackgroundEffect) {
|
|
685
|
-
BOOL hasCustomIntensity = self.blurIntensity && [self.blurIntensity floatValue] < 100;
|
|
686
|
-
if (!self.backgroundColor && self.backgroundBlur && self.backgroundBlur.length > 0) {
|
|
687
|
-
if (hasCustomIntensity) {
|
|
688
|
-
// Clear native effect to allow custom blur view with intensity
|
|
689
|
-
self.sheet.backgroundEffect = [UIColorEffect effectWithColor:[UIColor clearColor]];
|
|
690
|
-
} else {
|
|
691
|
-
UIBlurEffectStyle style = [BlurUtil blurEffectStyleFromString:self.backgroundBlur];
|
|
692
|
-
self.sheet.backgroundEffect = [UIBlurEffect effectWithStyle:style];
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
#endif
|
|
699
|
-
|
|
700
652
|
NSString *effectiveBackgroundBlur = self.backgroundBlur;
|
|
701
653
|
if (@available(iOS 26.0, *)) {
|
|
702
654
|
// iOS 26+ has default liquid glass effect
|
|
@@ -704,28 +656,23 @@
|
|
|
704
656
|
effectiveBackgroundBlur = @"system-material";
|
|
705
657
|
}
|
|
706
658
|
|
|
707
|
-
BOOL
|
|
659
|
+
BOOL hasBlur = effectiveBackgroundBlur && effectiveBackgroundBlur.length > 0;
|
|
708
660
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
if (effectiveBackgroundBlur && effectiveBackgroundBlur.length > 0) {
|
|
715
|
-
if (!_blurView) {
|
|
716
|
-
_blurView = [[TrueSheetBlurView alloc] init];
|
|
717
|
-
[_blurView addToView:self.view];
|
|
718
|
-
}
|
|
719
|
-
_blurView.backgroundBlur = effectiveBackgroundBlur;
|
|
720
|
-
_blurView.blurIntensity = self.blurIntensity;
|
|
721
|
-
_blurView.blurInteraction = self.blurInteraction;
|
|
722
|
-
[_blurView applyBlurEffect];
|
|
723
|
-
}
|
|
661
|
+
_blurView.backgroundBlur = hasBlur ? effectiveBackgroundBlur : nil;
|
|
662
|
+
_blurView.blurIntensity = self.blurIntensity;
|
|
663
|
+
_blurView.blurInteraction = self.blurInteraction;
|
|
664
|
+
[_blurView applyBlurEffect];
|
|
724
665
|
|
|
725
666
|
#if RNTS_IPHONE_OS_VERSION_AVAILABLE(26_1)
|
|
726
667
|
if (@available(iOS 26.1, *)) {
|
|
727
|
-
if (
|
|
728
|
-
|
|
668
|
+
if (!self.isDesignCompatibilityMode) {
|
|
669
|
+
if (self.backgroundColor) {
|
|
670
|
+
self.sheet.backgroundEffect = [UIColorEffect effectWithColor:self.backgroundColor];
|
|
671
|
+
} else if (hasBlur) {
|
|
672
|
+
self.sheet.backgroundEffect = [UIColorEffect effectWithColor:[UIColor clearColor]];
|
|
673
|
+
} else {
|
|
674
|
+
self.sheet.backgroundEffect = nil;
|
|
675
|
+
}
|
|
729
676
|
return;
|
|
730
677
|
}
|
|
731
678
|
}
|
|
@@ -788,31 +735,14 @@
|
|
|
788
735
|
|
|
789
736
|
- (void)sheetPresentationControllerDidChangeSelectedDetentIdentifier:
|
|
790
737
|
(UISheetPresentationController *)sheetPresentationController {
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
#pragma mark - RNSLifecycleListenerProtocol
|
|
803
|
-
|
|
804
|
-
#if RNS_LIFECYCLE_LISTENER_PROTOCOL_AVAILABLE
|
|
805
|
-
|
|
806
|
-
- (void)screenWillDisappear:(UIViewController *)screen isPresenterUnmounting:(BOOL)isPresenterUnmounting {
|
|
807
|
-
// Skip if not presented, being dismissed, or if the presenter (modal) itself is being unmounted
|
|
808
|
-
if (!_isPresented || self.isBeingDismissed || isPresenterUnmounting) {
|
|
809
|
-
return;
|
|
810
|
-
}
|
|
811
|
-
if ([self.delegate respondsToSelector:@selector(viewControllerDidDetectScreenDisappear)]) {
|
|
812
|
-
[self.delegate viewControllerDidDetectScreenDisappear];
|
|
813
|
-
}
|
|
738
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
739
|
+
NSInteger index = self.currentDetentIndex;
|
|
740
|
+
if (index >= 0) {
|
|
741
|
+
CGFloat detent = [self detentValueForIndex:index];
|
|
742
|
+
[self.delegate viewControllerDidChangeDetent:index position:self.currentPosition detent:detent];
|
|
743
|
+
}
|
|
744
|
+
});
|
|
814
745
|
}
|
|
815
|
-
#endif
|
|
816
746
|
|
|
817
747
|
#pragma mark - RNSDismissibleModalProtocol
|
|
818
748
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by Jovanni Lo (@lodev09)
|
|
3
|
+
// Copyright (c) 2024-present. All rights reserved.
|
|
4
|
+
//
|
|
5
|
+
// This source code is licensed under the MIT license found in the
|
|
6
|
+
// LICENSE file in the root directory of this source tree.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
10
|
+
|
|
11
|
+
#import <UIKit/UIKit.h>
|
|
12
|
+
#import <react/renderer/components/TrueSheetSpec/TrueSheetViewState.h>
|
|
13
|
+
|
|
14
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
15
|
+
|
|
16
|
+
@class TrueSheetView;
|
|
17
|
+
|
|
18
|
+
@protocol RNScreensEventObserverDelegate <NSObject>
|
|
19
|
+
|
|
20
|
+
- (void)presenterScreenWillDisappear;
|
|
21
|
+
- (void)presenterScreenWillAppear;
|
|
22
|
+
|
|
23
|
+
@end
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Observes react-native-screens lifecycle events via C++ EventDispatcher.
|
|
27
|
+
* Detects when the presenting screen unmounts while sheet is presented.
|
|
28
|
+
*/
|
|
29
|
+
@interface RNScreensEventObserver : NSObject
|
|
30
|
+
|
|
31
|
+
@property (nonatomic, weak) TrueSheetView<RNScreensEventObserverDelegate> *delegate;
|
|
32
|
+
|
|
33
|
+
- (void)startObservingWithState:(const facebook::react::TrueSheetViewState &)state;
|
|
34
|
+
- (void)stopObserving;
|
|
35
|
+
|
|
36
|
+
- (void)capturePresenterScreenFromView:(UIView *)view;
|
|
37
|
+
- (BOOL)shouldDismissForScreenTag:(NSInteger)screenTag;
|
|
38
|
+
|
|
39
|
+
@end
|
|
40
|
+
|
|
41
|
+
NS_ASSUME_NONNULL_END
|
|
42
|
+
|
|
43
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by Jovanni Lo (@lodev09)
|
|
3
|
+
// Copyright (c) 2024-present. All rights reserved.
|
|
4
|
+
//
|
|
5
|
+
// This source code is licensed under the MIT license found in the
|
|
6
|
+
// LICENSE file in the root directory of this source tree.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
10
|
+
|
|
11
|
+
#import "RNScreensEventObserver.h"
|
|
12
|
+
#import "TrueSheetView.h"
|
|
13
|
+
|
|
14
|
+
#import <react/renderer/core/EventDispatcher.h>
|
|
15
|
+
#import <react/renderer/core/ShadowNodeFamily.h>
|
|
16
|
+
|
|
17
|
+
using namespace facebook::react;
|
|
18
|
+
|
|
19
|
+
@implementation RNScreensEventObserver {
|
|
20
|
+
std::weak_ptr<const EventDispatcher> _eventDispatcher;
|
|
21
|
+
std::shared_ptr<const EventListener> _eventListener;
|
|
22
|
+
NSInteger _presenterScreenTag;
|
|
23
|
+
__weak UIViewController *_presenterScreenController;
|
|
24
|
+
BOOL _dismissedByNavigation;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
- (instancetype)init {
|
|
28
|
+
if (self = [super init]) {
|
|
29
|
+
_presenterScreenTag = 0;
|
|
30
|
+
_presenterScreenController = nil;
|
|
31
|
+
}
|
|
32
|
+
return self;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
- (void)dealloc {
|
|
36
|
+
[self stopObserving];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
- (void)startObservingWithState:(const TrueSheetViewState &)state {
|
|
40
|
+
if (!_eventDispatcher.expired()) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (auto dispatcherPtr = state.getEventDispatcher().lock()) {
|
|
45
|
+
_eventDispatcher = state.getEventDispatcher();
|
|
46
|
+
|
|
47
|
+
__weak RNScreensEventObserver *weakSelf = self;
|
|
48
|
+
|
|
49
|
+
_eventListener = std::make_shared<const EventListener>([weakSelf](const RawEvent &event) {
|
|
50
|
+
RNScreensEventObserver *strongSelf = weakSelf;
|
|
51
|
+
if (!strongSelf) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (auto family = event.shadowNodeFamily.lock()) {
|
|
56
|
+
Tag screenTag = family->getTag();
|
|
57
|
+
|
|
58
|
+
if (event.type == "topWillDisappear") {
|
|
59
|
+
if ([strongSelf shouldDismissForScreenTag:screenTag]) {
|
|
60
|
+
strongSelf->_dismissedByNavigation = YES;
|
|
61
|
+
[strongSelf.delegate presenterScreenWillDisappear];
|
|
62
|
+
}
|
|
63
|
+
} else if (event.type == "topWillAppear") {
|
|
64
|
+
if (screenTag == strongSelf->_presenterScreenTag && strongSelf->_dismissedByNavigation) {
|
|
65
|
+
strongSelf->_dismissedByNavigation = NO;
|
|
66
|
+
[strongSelf.delegate presenterScreenWillAppear];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
dispatcherPtr->addListener(_eventListener);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
- (void)stopObserving {
|
|
78
|
+
if (_eventListener) {
|
|
79
|
+
if (auto dispatcher = _eventDispatcher.lock()) {
|
|
80
|
+
dispatcher->removeListener(_eventListener);
|
|
81
|
+
}
|
|
82
|
+
_eventListener = nullptr;
|
|
83
|
+
}
|
|
84
|
+
_eventDispatcher.reset();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
- (void)capturePresenterScreenFromView:(UIView *)view {
|
|
88
|
+
_presenterScreenTag = 0;
|
|
89
|
+
_presenterScreenController = nil;
|
|
90
|
+
|
|
91
|
+
for (UIView *current = view.superview; current; current = current.superview) {
|
|
92
|
+
NSString *className = NSStringFromClass([current class]);
|
|
93
|
+
|
|
94
|
+
if ([className isEqualToString:@"RNSScreenView"]) {
|
|
95
|
+
_presenterScreenTag = current.tag;
|
|
96
|
+
for (UIResponder *r = current.nextResponder; r; r = r.nextResponder) {
|
|
97
|
+
if ([r isKindOfClass:[UIViewController class]]) {
|
|
98
|
+
_presenterScreenController = (UIViewController *)r;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
- (BOOL)shouldDismissForScreenTag:(NSInteger)screenTag {
|
|
108
|
+
if (_presenterScreenTag != screenTag) {
|
|
109
|
+
return NO;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Skip if screen is still top of nav stack (e.g. modal dismiss - sheet dismisses naturally with modal)
|
|
113
|
+
// Dismiss if a new screen was pushed or popped
|
|
114
|
+
return _presenterScreenController.navigationController.topViewController != _presenterScreenController;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@end
|
|
118
|
+
|
|
119
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
@@ -34,41 +34,45 @@
|
|
|
34
34
|
[parentView insertSubview:self atIndex:0];
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
- (void)clearAnimator {
|
|
38
|
+
if (_blurAnimator) {
|
|
39
|
+
[_blurAnimator stopAnimation:YES];
|
|
40
|
+
_blurAnimator = nil;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
37
44
|
- (void)applyBlurEffect {
|
|
38
45
|
self.userInteractionEnabled = self.blurInteraction;
|
|
39
46
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
if (!self.backgroundBlur || self.backgroundBlur.length == 0) {
|
|
48
|
+
[self clearAnimator];
|
|
49
|
+
self.effect = nil;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
UIBlurEffectStyle style = [BlurUtil blurEffectStyleFromString:self.backgroundBlur];
|
|
54
|
+
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:style];
|
|
55
|
+
|
|
56
|
+
CGFloat intensity =
|
|
57
|
+
(self.blurIntensity && [self.blurIntensity floatValue] >= 0) ? [self.blurIntensity floatValue] / 100.0 : 1.0;
|
|
44
58
|
|
|
59
|
+
if (intensity >= 1.0) {
|
|
60
|
+
[self clearAnimator];
|
|
61
|
+
self.effect = blurEffect;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!_blurAnimator) {
|
|
45
66
|
__weak __typeof(self) weakSelf = self;
|
|
46
67
|
_blurAnimator = [[UIViewPropertyAnimator alloc] initWithDuration:1.0
|
|
47
68
|
curve:UIViewAnimationCurveLinear
|
|
48
69
|
animations:^{
|
|
49
70
|
weakSelf.effect = blurEffect;
|
|
50
71
|
}];
|
|
51
|
-
_blurAnimator.pausesOnCompletion = YES;
|
|
52
72
|
}
|
|
53
73
|
|
|
54
|
-
|
|
55
|
-
CGFloat intensity =
|
|
56
|
-
(self.blurIntensity && [self.blurIntensity floatValue] >= 0) ? [self.blurIntensity floatValue] / 100.0 : 1.0;
|
|
74
|
+
_blurAnimator.pausesOnCompletion = YES;
|
|
57
75
|
_blurAnimator.fractionComplete = intensity;
|
|
58
76
|
}
|
|
59
77
|
|
|
60
|
-
- (void)willMoveToSuperview:(UIView *)newSuperview {
|
|
61
|
-
[super willMoveToSuperview:newSuperview];
|
|
62
|
-
|
|
63
|
-
// Clean up when removed from superview
|
|
64
|
-
if (!newSuperview) {
|
|
65
|
-
if (_blurAnimator) {
|
|
66
|
-
[_blurAnimator stopAnimation:YES];
|
|
67
|
-
_blurAnimator = nil;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
self.effect = nil;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
78
|
@end
|
package/ios/utils/LayoutUtil.h
CHANGED
|
@@ -40,6 +40,29 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
40
40
|
*/
|
|
41
41
|
+ (void)pinView:(UIView *)view toParentView:(UIView *)parentView withTopView:(UIView *)topView edges:(UIRectEdge)edges;
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Pins a view to its parent view with insets
|
|
45
|
+
* @param view The view to pin
|
|
46
|
+
* @param parentView The parent view to pin to
|
|
47
|
+
* @param edges The edges to pin (UIRectEdge flags)
|
|
48
|
+
* @param insets The insets to apply to each edge
|
|
49
|
+
*/
|
|
50
|
+
+ (void)pinView:(UIView *)view toParentView:(UIView *)parentView edges:(UIRectEdge)edges insets:(UIEdgeInsets)insets;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Pins a view to its parent view with its top edge anchored below a top sibling view, with insets
|
|
54
|
+
* @param view The view to pin
|
|
55
|
+
* @param parentView The parent view to pin to
|
|
56
|
+
* @param topView The view to position below (top sibling)
|
|
57
|
+
* @param edges The edges to pin to parent (excluding top, which is pinned to topView)
|
|
58
|
+
* @param insets The insets to apply to each edge
|
|
59
|
+
*/
|
|
60
|
+
+ (void)pinView:(UIView *)view
|
|
61
|
+
toParentView:(UIView *)parentView
|
|
62
|
+
withTopView:(UIView *)topView
|
|
63
|
+
edges:(UIRectEdge)edges
|
|
64
|
+
insets:(UIEdgeInsets)insets;
|
|
65
|
+
|
|
43
66
|
/**
|
|
44
67
|
* Unpins a view by removing its constraints and re-enabling autoresizing mask translation
|
|
45
68
|
* @param view The view to unpin
|
package/ios/utils/LayoutUtil.mm
CHANGED
|
@@ -38,7 +38,32 @@
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
+ (void)pinView:(UIView *)view toParentView:(UIView *)parentView edges:(UIRectEdge)edges insets:(UIEdgeInsets)insets {
|
|
42
|
+
view.translatesAutoresizingMaskIntoConstraints = NO;
|
|
43
|
+
|
|
44
|
+
if (edges & UIRectEdgeTop) {
|
|
45
|
+
[view.topAnchor constraintEqualToAnchor:parentView.topAnchor constant:insets.top].active = YES;
|
|
46
|
+
}
|
|
47
|
+
if (edges & UIRectEdgeBottom) {
|
|
48
|
+
[view.bottomAnchor constraintEqualToAnchor:parentView.bottomAnchor constant:-insets.bottom].active = YES;
|
|
49
|
+
}
|
|
50
|
+
if (edges & UIRectEdgeLeft) {
|
|
51
|
+
[view.leadingAnchor constraintEqualToAnchor:parentView.leadingAnchor constant:insets.left].active = YES;
|
|
52
|
+
}
|
|
53
|
+
if (edges & UIRectEdgeRight) {
|
|
54
|
+
[view.trailingAnchor constraintEqualToAnchor:parentView.trailingAnchor constant:-insets.right].active = YES;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
41
58
|
+ (void)pinView:(UIView *)view toParentView:(UIView *)parentView withTopView:(UIView *)topView edges:(UIRectEdge)edges {
|
|
59
|
+
[self pinView:view toParentView:parentView withTopView:topView edges:edges insets:UIEdgeInsetsZero];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
+ (void)pinView:(UIView *)view
|
|
63
|
+
toParentView:(UIView *)parentView
|
|
64
|
+
withTopView:(UIView *)topView
|
|
65
|
+
edges:(UIRectEdge)edges
|
|
66
|
+
insets:(UIEdgeInsets)insets {
|
|
42
67
|
view.translatesAutoresizingMaskIntoConstraints = NO;
|
|
43
68
|
|
|
44
69
|
// Pin top edge to bottom of top sibling
|
|
@@ -46,13 +71,13 @@
|
|
|
46
71
|
|
|
47
72
|
// Pin other edges to parent based on edges parameter
|
|
48
73
|
if (edges & UIRectEdgeBottom) {
|
|
49
|
-
[view.bottomAnchor constraintEqualToAnchor:parentView.bottomAnchor].active = YES;
|
|
74
|
+
[view.bottomAnchor constraintEqualToAnchor:parentView.bottomAnchor constant:-insets.bottom].active = YES;
|
|
50
75
|
}
|
|
51
76
|
if (edges & UIRectEdgeLeft) {
|
|
52
|
-
[view.leadingAnchor constraintEqualToAnchor:parentView.leadingAnchor].active = YES;
|
|
77
|
+
[view.leadingAnchor constraintEqualToAnchor:parentView.leadingAnchor constant:insets.left].active = YES;
|
|
53
78
|
}
|
|
54
79
|
if (edges & UIRectEdgeRight) {
|
|
55
|
-
[view.trailingAnchor constraintEqualToAnchor:parentView.trailingAnchor].active = YES;
|
|
80
|
+
[view.trailingAnchor constraintEqualToAnchor:parentView.trailingAnchor constant:-insets.right].active = YES;
|
|
56
81
|
}
|
|
57
82
|
}
|
|
58
83
|
|