react-native-tvos 0.77.2-2 → 0.77.3-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/Libraries/Core/ReactNativeVersion.js +2 -2
- package/Libraries/Network/RCTDataRequestHandler.mm +17 -3
- package/Libraries/Network/RCTFileRequestHandler.mm +17 -3
- package/React/Base/RCTVersion.m +2 -2
- package/React/DevSupport/RCTPausedInDebuggerOverlayController.mm +3 -5
- package/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm +18 -4
- package/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm +8 -7
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +22 -3
- package/React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm +1 -1
- package/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm +1 -1
- package/React/Fabric/Surface/RCTFabricSurface.mm +1 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/publish.gradle +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +13 -8
- package/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.kt +3 -16
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.kt +13 -0
- package/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +0 -3
- package/ReactAndroid/src/main/java/com/facebook/react/uimanager/style/BorderRadiusStyle.kt +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt +43 -0
- package/ReactCommon/React-FabricComponents.podspec +1 -1
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/ReactCommon/react/renderer/components/modal/CMakeLists.txt +4 -1
- package/ReactCommon/react/renderer/components/modal/ModalHostViewComponentDescriptor.h +3 -2
- package/ReactCommon/react/renderer/components/modal/ModalHostViewState.h +4 -12
- package/ReactCommon/react/renderer/components/modal/ModalHostViewUtils.h +2 -2
- package/ReactCommon/react/renderer/components/modal/ModalHostViewUtils.mm +1 -1
- package/ReactCommon/react/renderer/components/modal/platform/android/JReactModalHostView.h +38 -0
- package/ReactCommon/react/renderer/components/modal/platform/android/ModalHostViewUtils.cpp +18 -0
- package/ReactCommon/react/renderer/components/modal/platform/cxx/ModalHostViewUtils.cpp +17 -0
- package/ReactCommon/react/renderer/components/scrollview/ScrollEvent.cpp +33 -0
- package/ReactCommon/react/renderer/components/scrollview/ScrollEvent.h +17 -0
- package/ReactCommon/react/renderer/components/scrollview/ScrollViewEventEmitter.cpp +3 -2
- package/ReactCommon/react/renderer/components/scrollview/ScrollViewEventEmitter.h +2 -1
- package/ReactCommon/react/runtime/TimerManager.cpp +6 -4
- package/ReactCommon/react/runtime/TimerManager.h +3 -1
- package/ReactCommon/react/runtime/tests/cxx/ReactInstanceTest.cpp +9 -5
- package/package.json +10 -10
- package/sdks/hermesc/osx-bin/hermes +0 -0
- package/sdks/hermesc/osx-bin/hermesc +0 -0
- package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
- package/sdks/hermesc/win64-bin/msvcp140.dll +0 -0
- package/sdks/hermesc/win64-bin/vcruntime140.dll +0 -0
- package/sdks/hermesc/win64-bin/vcruntime140_1.dll +0 -0
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
#import <React/RCTDataRequestHandler.h>
|
|
9
9
|
#import <ReactCommon/RCTTurboModule.h>
|
|
10
10
|
|
|
11
|
+
#import <mutex>
|
|
12
|
+
|
|
11
13
|
#import "RCTNetworkPlugins.h"
|
|
12
14
|
|
|
13
15
|
@interface RCTDataRequestHandler () <RCTTurboModule>
|
|
@@ -15,14 +17,22 @@
|
|
|
15
17
|
|
|
16
18
|
@implementation RCTDataRequestHandler {
|
|
17
19
|
NSOperationQueue *_queue;
|
|
20
|
+
std::mutex _operationHandlerMutexLock;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
RCT_EXPORT_MODULE()
|
|
21
24
|
|
|
22
25
|
- (void)invalidate
|
|
23
26
|
{
|
|
24
|
-
|
|
25
|
-
_queue
|
|
27
|
+
std::lock_guard<std::mutex> lock(_operationHandlerMutexLock);
|
|
28
|
+
if (_queue) {
|
|
29
|
+
for (NSOperation *operation in _queue.operations) {
|
|
30
|
+
if (!operation.isCancelled && !operation.isFinished) {
|
|
31
|
+
[operation cancel];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
_queue = nil;
|
|
35
|
+
}
|
|
26
36
|
}
|
|
27
37
|
|
|
28
38
|
- (BOOL)canHandleRequest:(NSURLRequest *)request
|
|
@@ -32,6 +42,7 @@ RCT_EXPORT_MODULE()
|
|
|
32
42
|
|
|
33
43
|
- (NSOperation *)sendRequest:(NSURLRequest *)request withDelegate:(id<RCTURLRequestDelegate>)delegate
|
|
34
44
|
{
|
|
45
|
+
std::lock_guard<std::mutex> lock(_operationHandlerMutexLock);
|
|
35
46
|
// Lazy setup
|
|
36
47
|
if (!_queue) {
|
|
37
48
|
_queue = [NSOperationQueue new];
|
|
@@ -69,7 +80,10 @@ RCT_EXPORT_MODULE()
|
|
|
69
80
|
|
|
70
81
|
- (void)cancelRequest:(NSOperation *)op
|
|
71
82
|
{
|
|
72
|
-
|
|
83
|
+
std::lock_guard<std::mutex> lock(_operationHandlerMutexLock);
|
|
84
|
+
if (!op.isCancelled && !op.isFinished) {
|
|
85
|
+
[op cancel];
|
|
86
|
+
}
|
|
73
87
|
}
|
|
74
88
|
|
|
75
89
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
#import <React/RCTFileRequestHandler.h>
|
|
9
9
|
|
|
10
|
+
#import <mutex>
|
|
11
|
+
|
|
10
12
|
#import <MobileCoreServices/MobileCoreServices.h>
|
|
11
13
|
|
|
12
14
|
#import <React/RCTUtils.h>
|
|
@@ -19,14 +21,22 @@
|
|
|
19
21
|
|
|
20
22
|
@implementation RCTFileRequestHandler {
|
|
21
23
|
NSOperationQueue *_fileQueue;
|
|
24
|
+
std::mutex _operationHandlerMutexLock;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
RCT_EXPORT_MODULE()
|
|
25
28
|
|
|
26
29
|
- (void)invalidate
|
|
27
30
|
{
|
|
28
|
-
|
|
29
|
-
_fileQueue
|
|
31
|
+
std::lock_guard<std::mutex> lock(_operationHandlerMutexLock);
|
|
32
|
+
if (_fileQueue) {
|
|
33
|
+
for (NSOperation *operation in _fileQueue.operations) {
|
|
34
|
+
if (!operation.isCancelled && !operation.isFinished) {
|
|
35
|
+
[operation cancel];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
_fileQueue = nil;
|
|
39
|
+
}
|
|
30
40
|
}
|
|
31
41
|
|
|
32
42
|
- (BOOL)canHandleRequest:(NSURLRequest *)request
|
|
@@ -36,6 +46,7 @@ RCT_EXPORT_MODULE()
|
|
|
36
46
|
|
|
37
47
|
- (NSOperation *)sendRequest:(NSURLRequest *)request withDelegate:(id<RCTURLRequestDelegate>)delegate
|
|
38
48
|
{
|
|
49
|
+
std::lock_guard<std::mutex> lock(_operationHandlerMutexLock);
|
|
39
50
|
// Lazy setup
|
|
40
51
|
if (!_fileQueue) {
|
|
41
52
|
_fileQueue = [NSOperationQueue new];
|
|
@@ -83,7 +94,10 @@ RCT_EXPORT_MODULE()
|
|
|
83
94
|
|
|
84
95
|
- (void)cancelRequest:(NSOperation *)op
|
|
85
96
|
{
|
|
86
|
-
|
|
97
|
+
std::lock_guard<std::mutex> lock(_operationHandlerMutexLock);
|
|
98
|
+
if (!op.isCancelled && !op.isFinished) {
|
|
99
|
+
[op cancel];
|
|
100
|
+
}
|
|
87
101
|
}
|
|
88
102
|
|
|
89
103
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
package/React/Base/RCTVersion.m
CHANGED
|
@@ -23,8 +23,8 @@ NSDictionary* RCTGetReactNativeVersion(void)
|
|
|
23
23
|
__rnVersion = @{
|
|
24
24
|
RCTVersionMajor: @(0),
|
|
25
25
|
RCTVersionMinor: @(77),
|
|
26
|
-
RCTVersionPatch: @(
|
|
27
|
-
RCTVersionPrerelease: @"
|
|
26
|
+
RCTVersionPatch: @(3),
|
|
27
|
+
RCTVersionPrerelease: @"0",
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
return __rnVersion;
|
|
@@ -54,13 +54,11 @@
|
|
|
54
54
|
]];
|
|
55
55
|
|
|
56
56
|
UIButton *resumeButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
57
|
-
|
|
57
|
+
UIImage *image = [UIImage systemImageNamed:@"forward.frame.fill"];
|
|
58
|
+
[resumeButton setImage:image forState:UIControlStateNormal];
|
|
59
|
+
[resumeButton setImage:image forState:UIControlStateDisabled];
|
|
58
60
|
resumeButton.tintColor = [UIColor colorWithRed:0.37 green:0.37 blue:0.37 alpha:1];
|
|
59
61
|
|
|
60
|
-
resumeButton.configurationUpdateHandler = ^(UIButton *button) {
|
|
61
|
-
button.imageView.tintAdjustmentMode = UIViewTintAdjustmentModeNormal;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
62
|
resumeButton.enabled = NO;
|
|
65
63
|
[NSLayoutConstraint activateConstraints:@[
|
|
66
64
|
[resumeButton.widthAnchor constraintEqualToConstant:48],
|
|
@@ -170,10 +170,24 @@ static NSString *const kRCTLegacyInteropChildIndexKey = @"index";
|
|
|
170
170
|
|
|
171
171
|
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
|
|
172
172
|
{
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
173
|
+
if (_adapter && index == _adapter.paperView.reactSubviews.count) {
|
|
174
|
+
// This is a new child view that is being added to the end of the children array.
|
|
175
|
+
// After the children is added, we need to call didUpdateReactSubviews to make sure that it is rendered.
|
|
176
|
+
// Without this change, the new child will not be rendered right away because the didUpdateReactSubviews is not
|
|
177
|
+
// called and the `finalizeUpdate` is not invoked.
|
|
178
|
+
if ([childComponentView isKindOfClass:[RCTLegacyViewManagerInteropComponentView class]]) {
|
|
179
|
+
UIView *target = ((RCTLegacyViewManagerInteropComponentView *)childComponentView).contentView;
|
|
180
|
+
[_adapter.paperView insertReactSubview:target atIndex:index];
|
|
181
|
+
} else {
|
|
182
|
+
[_adapter.paperView insertReactSubview:childComponentView atIndex:index];
|
|
183
|
+
}
|
|
184
|
+
[_adapter.paperView didUpdateReactSubviews];
|
|
185
|
+
} else {
|
|
186
|
+
[_viewsToBeMounted addObject:@{
|
|
187
|
+
kRCTLegacyInteropChildIndexKey : [NSNumber numberWithInteger:index],
|
|
188
|
+
kRCTLegacyInteropChildComponentKey : childComponentView
|
|
189
|
+
}];
|
|
190
|
+
}
|
|
177
191
|
}
|
|
178
192
|
|
|
179
193
|
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
|
|
@@ -118,7 +118,6 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct(
|
|
|
118
118
|
BOOL _shouldAnimatePresentation;
|
|
119
119
|
BOOL _shouldPresent;
|
|
120
120
|
BOOL _isPresented;
|
|
121
|
-
UIView *_modalContentsSnapshot;
|
|
122
121
|
#if TARGET_OS_TV
|
|
123
122
|
UITapGestureRecognizer *_menuButtonGestureRecognizer;
|
|
124
123
|
RCTTVRemoteHandler *_tvRemoteHandler;
|
|
@@ -144,12 +143,16 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct(
|
|
|
144
143
|
|
|
145
144
|
#if TARGET_OS_TV
|
|
146
145
|
- (void)menuButtonPressed {
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
_isPresented = NO;
|
|
147
|
+
// To animate dismissal of view controller, snapshot of
|
|
148
|
+
// view hierarchy needs to be added to the UIViewController.
|
|
149
|
+
UIView *snapshot = [self.viewController.view snapshotViewAfterScreenUpdates:NO];
|
|
150
|
+
if (_shouldPresent) {
|
|
151
|
+
[self.viewController.view addSubview:snapshot];
|
|
152
|
+
}
|
|
149
153
|
[self dismissViewController:self.viewController
|
|
150
154
|
animated:_shouldAnimatePresentation
|
|
151
155
|
completion:^{
|
|
152
|
-
[snapshot removeFromSuperview];
|
|
153
156
|
auto eventEmitter = [self modalEventEmitter];
|
|
154
157
|
if (eventEmitter) {
|
|
155
158
|
eventEmitter->onDismiss(ModalHostViewEventEmitter::OnDismiss{});
|
|
@@ -196,7 +199,6 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct(
|
|
|
196
199
|
animated:(BOOL)animated
|
|
197
200
|
completion:(void (^)(void))completion
|
|
198
201
|
{
|
|
199
|
-
_modalContentsSnapshot = [self.viewController.view snapshotViewAfterScreenUpdates:NO];
|
|
200
202
|
[modalViewController dismissViewControllerAnimated:animated completion:completion];
|
|
201
203
|
}
|
|
202
204
|
|
|
@@ -222,8 +224,7 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct(
|
|
|
222
224
|
_isPresented = NO;
|
|
223
225
|
// To animate dismissal of view controller, snapshot of
|
|
224
226
|
// view hierarchy needs to be added to the UIViewController.
|
|
225
|
-
UIView *snapshot =
|
|
226
|
-
|
|
227
|
+
UIView *snapshot = [self.viewController.view snapshotViewAfterScreenUpdates:NO];
|
|
227
228
|
if (_shouldPresent) {
|
|
228
229
|
[self.viewController.view addSubview:snapshot];
|
|
229
230
|
}
|
|
@@ -565,6 +565,17 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
565
565
|
return metrics;
|
|
566
566
|
}
|
|
567
567
|
|
|
568
|
+
- (ScrollViewEventEmitter::EndDragMetrics)_scrollViewMetricsWithVelocity:(CGPoint)velocity
|
|
569
|
+
andTargetContentOffset:(CGPoint)targetContentOffset
|
|
570
|
+
{
|
|
571
|
+
ScrollViewEventEmitter::EndDragMetrics metrics = [self _scrollViewMetrics];
|
|
572
|
+
metrics.targetContentOffset.x = targetContentOffset.x;
|
|
573
|
+
metrics.targetContentOffset.y = targetContentOffset.y;
|
|
574
|
+
metrics.velocity.x = velocity.x;
|
|
575
|
+
metrics.velocity.y = velocity.y;
|
|
576
|
+
return metrics;
|
|
577
|
+
}
|
|
578
|
+
|
|
568
579
|
- (void)_updateStateWithContentOffset
|
|
569
580
|
{
|
|
570
581
|
if (!_state) {
|
|
@@ -620,6 +631,14 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
620
631
|
targetContentOffset->y = scrollView.contentOffset.y + travel * _endDraggingSensitivityMultiplier;
|
|
621
632
|
}
|
|
622
633
|
}
|
|
634
|
+
|
|
635
|
+
if (!_eventEmitter) {
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
auto metrics = [self _scrollViewMetricsWithVelocity:velocity andTargetContentOffset:*targetContentOffset];
|
|
640
|
+
|
|
641
|
+
static_cast<const ScrollViewEventEmitter &>(*_eventEmitter).onScrollEndDrag(metrics);
|
|
623
642
|
}
|
|
624
643
|
|
|
625
644
|
- (BOOL)touchesShouldCancelInContentView:(__unused UIView *)view
|
|
@@ -690,8 +709,6 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
690
709
|
return;
|
|
691
710
|
}
|
|
692
711
|
|
|
693
|
-
static_cast<const ScrollViewEventEmitter &>(*_eventEmitter).onScrollEndDrag([self _scrollViewMetrics]);
|
|
694
|
-
|
|
695
712
|
[self _updateStateWithContentOffset];
|
|
696
713
|
|
|
697
714
|
if (!decelerate) {
|
|
@@ -788,7 +805,9 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
788
805
|
return;
|
|
789
806
|
}
|
|
790
807
|
|
|
791
|
-
|
|
808
|
+
auto metrics = [self _scrollViewMetricsWithVelocity:{} andTargetContentOffset:{}];
|
|
809
|
+
static_cast<const ScrollViewEventEmitter &>(*_eventEmitter).onScrollEndDrag(metrics);
|
|
810
|
+
|
|
792
811
|
[self _updateStateWithContentOffset];
|
|
793
812
|
}
|
|
794
813
|
|
|
@@ -68,7 +68,7 @@ using namespace facebook::react;
|
|
|
68
68
|
const auto &newSwitchProps = static_cast<const SwitchProps &>(*props);
|
|
69
69
|
|
|
70
70
|
// `value`
|
|
71
|
-
if (oldSwitchProps.value != newSwitchProps.value) {
|
|
71
|
+
if (!_isInitialValueSet || oldSwitchProps.value != newSwitchProps.value) {
|
|
72
72
|
BOOL shouldAnimate = _isInitialValueSet == YES;
|
|
73
73
|
[_switchView setOn:newSwitchProps.value animated:shouldAnimate];
|
|
74
74
|
}
|
|
@@ -223,7 +223,7 @@ UITextContentType RCTUITextContentTypeFromString(const std::string &contentType)
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 170000 /* __IPHONE_17_0 */
|
|
226
|
-
if (@available(iOS 17.0, *)) {
|
|
226
|
+
if (@available(iOS 17.0, tvOS 17.0, *)) {
|
|
227
227
|
[mutableContentTypeMap addEntriesFromDictionary:@{
|
|
228
228
|
@"creditCardExpiration" : UITextContentTypeCreditCardExpiration,
|
|
229
229
|
@"creditCardExpirationMonth" : UITextContentTypeCreditCardExpirationMonth,
|
|
@@ -143,6 +143,7 @@ using namespace facebook::react;
|
|
|
143
143
|
|
|
144
144
|
if (!_view) {
|
|
145
145
|
_view = [[RCTSurfaceView alloc] initWithSurface:(RCTSurface *)self];
|
|
146
|
+
[self _updateLayoutContext];
|
|
146
147
|
_touchHandler = [RCTSurfaceTouchHandler new];
|
|
147
148
|
[_touchHandler attachToView:_view];
|
|
148
149
|
}
|
|
@@ -20,7 +20,7 @@ def sonatypeUsername = findProperty('SONATYPE_USERNAME')
|
|
|
20
20
|
def sonatypePassword = findProperty('SONATYPE_PASSWORD')
|
|
21
21
|
|
|
22
22
|
def reactAndroidProjectDir = project(':packages:react-native:ReactAndroid').projectDir
|
|
23
|
-
def mavenTempLocalUrl = 'file:///
|
|
23
|
+
def mavenTempLocalUrl = 'file:///var/folders/xp/yw_lp59x05d2mp0g0n2f_d240000gn/T/eas-build-workingdir/build/maven_local'
|
|
24
24
|
// Rewritten when copying this to ReactAndroid/publish.gradle
|
|
25
25
|
|
|
26
26
|
publishing {
|
|
@@ -1409,14 +1409,14 @@ public class ReactInstanceManager {
|
|
|
1409
1409
|
new RuntimeException(
|
|
1410
1410
|
"detachRootViewFromInstance called with ReactRootView with invalid id"));
|
|
1411
1411
|
}
|
|
1412
|
-
|
|
1413
|
-
clearReactRoot(reactRoot);
|
|
1414
1412
|
} else {
|
|
1415
1413
|
reactContext
|
|
1416
1414
|
.getCatalystInstance()
|
|
1417
1415
|
.getJSModule(AppRegistry.class)
|
|
1418
1416
|
.unmountApplicationComponentAtRootTag(reactRoot.getRootViewTag());
|
|
1419
1417
|
}
|
|
1418
|
+
|
|
1419
|
+
clearReactRoot(reactRoot);
|
|
1420
1420
|
}
|
|
1421
1421
|
|
|
1422
1422
|
@ThreadConfined(UI)
|
|
@@ -171,7 +171,7 @@ public class FabricUIManager
|
|
|
171
171
|
private final CopyOnWriteArrayList<UIManagerListener> mListeners = new CopyOnWriteArrayList<>();
|
|
172
172
|
|
|
173
173
|
private boolean mMountNotificationScheduled = false;
|
|
174
|
-
private
|
|
174
|
+
private List<Integer> mSurfaceIdsWithPendingMountNotification = new ArrayList<>();
|
|
175
175
|
|
|
176
176
|
@ThreadConfined(UI)
|
|
177
177
|
@NonNull
|
|
@@ -1261,12 +1261,15 @@ public class FabricUIManager
|
|
|
1261
1261
|
|
|
1262
1262
|
// Collect surface IDs for all the mount items
|
|
1263
1263
|
for (MountItem mountItem : mountItems) {
|
|
1264
|
-
if (mountItem != null
|
|
1265
|
-
|
|
1264
|
+
if (mountItem != null
|
|
1265
|
+
&& !mSurfaceIdsWithPendingMountNotification.contains(mountItem.getSurfaceId())) {
|
|
1266
|
+
mSurfaceIdsWithPendingMountNotification.add(mountItem.getSurfaceId());
|
|
1266
1267
|
}
|
|
1267
1268
|
}
|
|
1268
1269
|
|
|
1269
|
-
if (!mMountNotificationScheduled && !
|
|
1270
|
+
if (!mMountNotificationScheduled && !mSurfaceIdsWithPendingMountNotification.isEmpty()) {
|
|
1271
|
+
mMountNotificationScheduled = true;
|
|
1272
|
+
|
|
1270
1273
|
// Notify mount when the effects are visible and prevent mount hooks to
|
|
1271
1274
|
// delay paint.
|
|
1272
1275
|
UiThreadUtil.getUiThreadHandler()
|
|
@@ -1276,17 +1279,19 @@ public class FabricUIManager
|
|
|
1276
1279
|
public void run() {
|
|
1277
1280
|
mMountNotificationScheduled = false;
|
|
1278
1281
|
|
|
1282
|
+
// Create a copy in case mount hooks trigger more mutations
|
|
1283
|
+
final List<Integer> surfaceIdsToReportMount =
|
|
1284
|
+
mSurfaceIdsWithPendingMountNotification;
|
|
1285
|
+
mSurfaceIdsWithPendingMountNotification = new ArrayList<>();
|
|
1286
|
+
|
|
1279
1287
|
final @Nullable FabricUIManagerBinding binding = mBinding;
|
|
1280
1288
|
if (binding == null || mDestroyed) {
|
|
1281
|
-
mMountedSurfaceIds.clear();
|
|
1282
1289
|
return;
|
|
1283
1290
|
}
|
|
1284
1291
|
|
|
1285
|
-
for (int surfaceId :
|
|
1292
|
+
for (int surfaceId : surfaceIdsToReportMount) {
|
|
1286
1293
|
binding.reportMount(surfaceId);
|
|
1287
1294
|
}
|
|
1288
|
-
|
|
1289
|
-
mMountedSurfaceIds.clear();
|
|
1290
1295
|
}
|
|
1291
1296
|
});
|
|
1292
1297
|
}
|
|
@@ -13,8 +13,6 @@ import android.os.Build
|
|
|
13
13
|
import android.view.View
|
|
14
14
|
import android.view.WindowInsetsController
|
|
15
15
|
import android.view.WindowManager
|
|
16
|
-
import androidx.core.view.ViewCompat
|
|
17
|
-
import androidx.core.view.WindowInsetsCompat
|
|
18
16
|
import com.facebook.common.logging.FLog
|
|
19
17
|
import com.facebook.fbreact.specs.NativeStatusBarManagerAndroidSpec
|
|
20
18
|
import com.facebook.react.bridge.GuardedRunnable
|
|
@@ -23,6 +21,7 @@ import com.facebook.react.bridge.ReactApplicationContext
|
|
|
23
21
|
import com.facebook.react.bridge.UiThreadUtil
|
|
24
22
|
import com.facebook.react.common.ReactConstants
|
|
25
23
|
import com.facebook.react.module.annotations.ReactModule
|
|
24
|
+
import com.facebook.react.uimanager.DisplayMetricsHolder.getStatusBarHeightPx
|
|
26
25
|
import com.facebook.react.uimanager.PixelUtil
|
|
27
26
|
import com.facebook.react.views.view.setStatusBarTranslucency
|
|
28
27
|
import com.facebook.react.views.view.setStatusBarVisibility
|
|
@@ -34,29 +33,17 @@ public class StatusBarModule(reactContext: ReactApplicationContext?) :
|
|
|
34
33
|
|
|
35
34
|
@Suppress("DEPRECATION")
|
|
36
35
|
override fun getTypedExportedConstants(): Map<String, Any> {
|
|
36
|
+
val currentActivity = reactApplicationContext.currentActivity
|
|
37
37
|
val statusBarColor =
|
|
38
38
|
currentActivity?.window?.statusBarColor?.let { color ->
|
|
39
39
|
String.format("#%06X", 0xFFFFFF and color)
|
|
40
40
|
} ?: "black"
|
|
41
41
|
return mapOf(
|
|
42
|
-
HEIGHT_KEY to PixelUtil.toDIPFromPixel(getStatusBarHeightPx()),
|
|
42
|
+
HEIGHT_KEY to PixelUtil.toDIPFromPixel(getStatusBarHeightPx(currentActivity).toFloat()),
|
|
43
43
|
DEFAULT_BACKGROUND_COLOR_KEY to statusBarColor,
|
|
44
44
|
)
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
@Suppress("DEPRECATION")
|
|
48
|
-
private fun getStatusBarHeightPx(): Float {
|
|
49
|
-
val windowInsets =
|
|
50
|
-
currentActivity?.window?.decorView?.let(ViewCompat::getRootWindowInsets) ?: return 0f
|
|
51
|
-
return windowInsets
|
|
52
|
-
.getInsets(
|
|
53
|
-
WindowInsetsCompat.Type.statusBars() or
|
|
54
|
-
WindowInsetsCompat.Type.navigationBars() or
|
|
55
|
-
WindowInsetsCompat.Type.displayCutout())
|
|
56
|
-
.top
|
|
57
|
-
.toFloat()
|
|
58
|
-
}
|
|
59
|
-
|
|
60
47
|
@Suppress("DEPRECATION")
|
|
61
48
|
override fun setColor(colorDouble: Double, animated: Boolean) {
|
|
62
49
|
val color = colorDouble.toInt()
|
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
package com.facebook.react.uimanager
|
|
9
9
|
|
|
10
|
+
import android.app.Activity
|
|
10
11
|
import android.content.Context
|
|
11
12
|
import android.util.DisplayMetrics
|
|
12
13
|
import android.view.WindowManager
|
|
14
|
+
import androidx.core.view.ViewCompat
|
|
15
|
+
import androidx.core.view.WindowInsetsCompat
|
|
13
16
|
import com.facebook.react.bridge.WritableMap
|
|
14
17
|
import com.facebook.react.bridge.WritableNativeMap
|
|
15
18
|
|
|
@@ -99,4 +102,14 @@ public object DisplayMetricsHolder {
|
|
|
99
102
|
putDouble("fontScale", fontScale)
|
|
100
103
|
putDouble("densityDpi", displayMetrics.densityDpi.toDouble())
|
|
101
104
|
}
|
|
105
|
+
|
|
106
|
+
internal fun getStatusBarHeightPx(activity: Activity?): Int {
|
|
107
|
+
val windowInsets = activity?.window?.decorView?.let(ViewCompat::getRootWindowInsets) ?: return 0
|
|
108
|
+
return windowInsets
|
|
109
|
+
.getInsets(
|
|
110
|
+
WindowInsetsCompat.Type.statusBars() or
|
|
111
|
+
WindowInsetsCompat.Type.navigationBars() or
|
|
112
|
+
WindowInsetsCompat.Type.displayCutout())
|
|
113
|
+
.top
|
|
114
|
+
}
|
|
102
115
|
}
|
|
@@ -136,10 +136,10 @@ public data class BorderRadiusStyle(
|
|
|
136
136
|
(startStart ?: topStart ?: topLeft ?: uniform)?.resolve(width, height)
|
|
137
137
|
?: zeroRadii,
|
|
138
138
|
bottomLeft =
|
|
139
|
-
(endEnd ?:
|
|
139
|
+
(endEnd ?: bottomEnd ?: bottomRight ?: uniform)?.resolve(width, height)
|
|
140
140
|
?: zeroRadii,
|
|
141
141
|
bottomRight =
|
|
142
|
-
(startEnd ?:
|
|
142
|
+
(startEnd ?: bottomStart ?: bottomLeft ?: uniform)?.resolve(width, height)
|
|
143
143
|
?: zeroRadii,
|
|
144
144
|
width = width,
|
|
145
145
|
height = height,
|
|
@@ -40,6 +40,8 @@ import com.facebook.react.common.ReactConstants
|
|
|
40
40
|
import com.facebook.react.common.annotations.VisibleForTesting
|
|
41
41
|
import com.facebook.react.config.ReactFeatureFlags
|
|
42
42
|
import com.facebook.react.modules.core.ReactAndroidHWInputDeviceHelper
|
|
43
|
+
import com.facebook.react.uimanager.DisplayMetricsHolder
|
|
44
|
+
import com.facebook.react.uimanager.DisplayMetricsHolder.getStatusBarHeightPx
|
|
43
45
|
import com.facebook.react.uimanager.JSPointerDispatcher
|
|
44
46
|
import com.facebook.react.uimanager.JSTouchDispatcher
|
|
45
47
|
import com.facebook.react.uimanager.PixelUtil.pxToDp
|
|
@@ -52,6 +54,7 @@ import com.facebook.react.views.common.ContextUtils
|
|
|
52
54
|
import com.facebook.react.views.view.setStatusBarTranslucency
|
|
53
55
|
import com.facebook.react.views.modal.ReactModalHostView.DialogRootViewGroup
|
|
54
56
|
import com.facebook.react.views.view.ReactViewGroup
|
|
57
|
+
import com.facebook.yoga.annotations.DoNotStrip
|
|
55
58
|
import java.util.Objects
|
|
56
59
|
|
|
57
60
|
|
|
@@ -118,6 +121,7 @@ public class ReactModalHostView(context: ThemedReactContext) :
|
|
|
118
121
|
|
|
119
122
|
init {
|
|
120
123
|
context.addLifecycleEventListener(this)
|
|
124
|
+
initStatusBarHeight(context)
|
|
121
125
|
dialogRootViewGroup = DialogRootViewGroup(context)
|
|
122
126
|
}
|
|
123
127
|
|
|
@@ -214,6 +218,15 @@ public class ReactModalHostView(context: ThemedReactContext) :
|
|
|
214
218
|
|
|
215
219
|
private fun getCurrentActivity(): Activity? = (context as ThemedReactContext).currentActivity
|
|
216
220
|
|
|
221
|
+
private fun isFlagSecureSet(activity: Activity?): Boolean {
|
|
222
|
+
if (activity == null) {
|
|
223
|
+
return false
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
val flags = activity.window.attributes.flags
|
|
227
|
+
return (flags and WindowManager.LayoutParams.FLAG_SECURE) != 0
|
|
228
|
+
}
|
|
229
|
+
|
|
217
230
|
/**
|
|
218
231
|
* showOrUpdate will display the Dialog. It is called by the manager once all properties are set
|
|
219
232
|
* because we need to know all of them before creating the Dialog. It is also smart during updates
|
|
@@ -309,6 +322,11 @@ public class ReactModalHostView(context: ThemedReactContext) :
|
|
|
309
322
|
if (hardwareAccelerated) {
|
|
310
323
|
newDialog.window?.addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
|
|
311
324
|
}
|
|
325
|
+
val flagSecureSet = isFlagSecureSet(currentActivity)
|
|
326
|
+
if (flagSecureSet) {
|
|
327
|
+
newDialog.window?.setFlags(
|
|
328
|
+
WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
|
|
329
|
+
}
|
|
312
330
|
if (currentActivity?.isFinishing == false) {
|
|
313
331
|
newDialog.show()
|
|
314
332
|
updateSystemAppearance()
|
|
@@ -404,6 +422,30 @@ public class ReactModalHostView(context: ThemedReactContext) :
|
|
|
404
422
|
public fun onRequestClose(dialog: DialogInterface?)
|
|
405
423
|
}
|
|
406
424
|
|
|
425
|
+
private companion object {
|
|
426
|
+
private const val TAG = "ReactModalHost"
|
|
427
|
+
|
|
428
|
+
// We store the status bar height to be able to properly position
|
|
429
|
+
// the modal on the first render.
|
|
430
|
+
private var statusBarHeight = 0
|
|
431
|
+
|
|
432
|
+
private fun initStatusBarHeight(reactContext: ReactContext) {
|
|
433
|
+
statusBarHeight = getStatusBarHeightPx(reactContext.currentActivity)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
@JvmStatic
|
|
437
|
+
@DoNotStrip
|
|
438
|
+
private fun getScreenDisplayMetricsWithoutInsets(): Long {
|
|
439
|
+
val displayMetrics = DisplayMetricsHolder.getScreenDisplayMetrics()
|
|
440
|
+
return encodeFloatsToLong(
|
|
441
|
+
displayMetrics.widthPixels.toFloat().pxToDp(),
|
|
442
|
+
(displayMetrics.heightPixels - statusBarHeight).toFloat().pxToDp())
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
private fun encodeFloatsToLong(width: Float, height: Float): Long =
|
|
446
|
+
(width.toRawBits().toLong()) shl 32 or (height.toRawBits().toLong())
|
|
447
|
+
}
|
|
448
|
+
|
|
407
449
|
/**
|
|
408
450
|
* DialogRootViewGroup is the ViewGroup which contains all the children of a Modal. It gets all
|
|
409
451
|
* child information forwarded from [ReactModalHostView] and uses that to create children. It is
|
|
@@ -417,6 +459,7 @@ public class ReactModalHostView(context: ThemedReactContext) :
|
|
|
417
459
|
*/
|
|
418
460
|
public class DialogRootViewGroup internal constructor(context: Context?) :
|
|
419
461
|
ReactViewGroup(context), RootView {
|
|
462
|
+
|
|
420
463
|
internal var stateWrapper: StateWrapper? = null
|
|
421
464
|
internal var eventDispatcher: EventDispatcher? = null
|
|
422
465
|
|
|
@@ -112,7 +112,7 @@ Pod::Spec.new do |s|
|
|
|
112
112
|
ss.subspec "modal" do |sss|
|
|
113
113
|
sss.dependency folly_dep_name, folly_version
|
|
114
114
|
sss.compiler_flags = folly_compiler_flags
|
|
115
|
-
sss.source_files = "react/renderer/components/modal
|
|
115
|
+
sss.source_files = "react/renderer/components/modal/*.{m,mm,cpp,h}"
|
|
116
116
|
sss.exclude_files = "react/renderer/components/modal/tests"
|
|
117
117
|
sss.header_dir = "react/renderer/components/modal"
|
|
118
118
|
end
|
|
@@ -17,8 +17,8 @@ namespace facebook::react {
|
|
|
17
17
|
constexpr struct {
|
|
18
18
|
int32_t Major = 0;
|
|
19
19
|
int32_t Minor = 77;
|
|
20
|
-
int32_t Patch =
|
|
21
|
-
std::string_view Prerelease = "
|
|
20
|
+
int32_t Patch = 3;
|
|
21
|
+
std::string_view Prerelease = "0";
|
|
22
22
|
} ReactNativeVersion;
|
|
23
23
|
|
|
24
24
|
} // namespace facebook::react
|
|
@@ -14,7 +14,10 @@ add_compile_options(
|
|
|
14
14
|
-Wpedantic
|
|
15
15
|
-DLOG_TAG=\"Fabric\")
|
|
16
16
|
|
|
17
|
-
file(GLOB rrc_modal_SRC CONFIGURE_DEPENDS
|
|
17
|
+
file(GLOB rrc_modal_SRC CONFIGURE_DEPENDS
|
|
18
|
+
*.cpp
|
|
19
|
+
platform/android/*.cpp)
|
|
20
|
+
|
|
18
21
|
add_library(rrc_modal STATIC ${rrc_modal_SRC})
|
|
19
22
|
|
|
20
23
|
target_include_directories(rrc_modal PUBLIC ${REACT_COMMON_DIR})
|
|
@@ -30,8 +30,9 @@ class ModalHostViewComponentDescriptor final
|
|
|
30
30
|
*shadowNode.getState())
|
|
31
31
|
.getData();
|
|
32
32
|
|
|
33
|
-
layoutableShadowNode.setSize(
|
|
34
|
-
|
|
33
|
+
layoutableShadowNode.setSize(Size{
|
|
34
|
+
.width = stateData.screenSize.width,
|
|
35
|
+
.height = stateData.screenSize.height});
|
|
35
36
|
layoutableShadowNode.setPositionType(YGPositionTypeAbsolute);
|
|
36
37
|
|
|
37
38
|
ConcreteComponentDescriptor::adopt(shadowNode);
|
|
@@ -9,15 +9,12 @@
|
|
|
9
9
|
|
|
10
10
|
#include <react/renderer/core/graphicsConversions.h>
|
|
11
11
|
#include <react/renderer/graphics/Float.h>
|
|
12
|
+
#include "ModalHostViewUtils.h"
|
|
12
13
|
|
|
13
14
|
#ifdef ANDROID
|
|
14
15
|
#include <folly/dynamic.h>
|
|
15
16
|
#endif
|
|
16
17
|
|
|
17
|
-
#if defined(__APPLE__) && TARGET_OS_IOS
|
|
18
|
-
#include "ModalHostViewUtils.h"
|
|
19
|
-
#endif
|
|
20
|
-
|
|
21
18
|
namespace facebook::react {
|
|
22
19
|
|
|
23
20
|
/*
|
|
@@ -27,12 +24,7 @@ class ModalHostViewState final {
|
|
|
27
24
|
public:
|
|
28
25
|
using Shared = std::shared_ptr<const ModalHostViewState>;
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
ModalHostViewState() : screenSize(RCTModalHostViewScreenSize()) {
|
|
32
|
-
#else
|
|
33
|
-
ModalHostViewState(){
|
|
34
|
-
#endif
|
|
35
|
-
};
|
|
27
|
+
ModalHostViewState() : screenSize(ModalHostViewScreenSize()) {}
|
|
36
28
|
ModalHostViewState(Size screenSize_) : screenSize(screenSize_){};
|
|
37
29
|
|
|
38
30
|
#ifdef ANDROID
|
|
@@ -40,8 +32,8 @@ class ModalHostViewState final {
|
|
|
40
32
|
const ModalHostViewState& previousState,
|
|
41
33
|
folly::dynamic data)
|
|
42
34
|
: screenSize(Size{
|
|
43
|
-
(Float)data["screenWidth"].getDouble(),
|
|
44
|
-
(Float)data["screenHeight"].getDouble()}){};
|
|
35
|
+
.width = (Float)data["screenWidth"].getDouble(),
|
|
36
|
+
.height = (Float)data["screenHeight"].getDouble()}){};
|
|
45
37
|
#endif
|
|
46
38
|
|
|
47
39
|
const Size screenSize{};
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
#pragma once
|
|
9
9
|
|
|
10
|
-
#include <react/renderer/
|
|
10
|
+
#include <react/renderer/graphics/Size.h>
|
|
11
11
|
|
|
12
12
|
namespace facebook::react {
|
|
13
13
|
|
|
14
|
-
Size
|
|
14
|
+
Size ModalHostViewScreenSize(void);
|
|
15
15
|
|
|
16
16
|
} // namespace facebook::react
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <fbjni/fbjni.h>
|
|
11
|
+
#include <react/renderer/graphics/Size.h>
|
|
12
|
+
|
|
13
|
+
namespace facebook::react {
|
|
14
|
+
|
|
15
|
+
class JReactModalHostView
|
|
16
|
+
: public facebook::jni::JavaClass<JReactModalHostView> {
|
|
17
|
+
public:
|
|
18
|
+
static auto constexpr kJavaDescriptor =
|
|
19
|
+
"Lcom/facebook/react/views/modal/ReactModalHostView;";
|
|
20
|
+
|
|
21
|
+
static Size getDisplayMetrics() {
|
|
22
|
+
static auto method =
|
|
23
|
+
JReactModalHostView::javaClassStatic()->getStaticMethod<jlong()>(
|
|
24
|
+
"getScreenDisplayMetricsWithoutInsets");
|
|
25
|
+
auto result = method(javaClassStatic());
|
|
26
|
+
|
|
27
|
+
// Inspired from yogaMeassureToSize from conversions.h
|
|
28
|
+
int32_t wBits = 0xFFFFFFFF & (result >> 32);
|
|
29
|
+
int32_t hBits = 0xFFFFFFFF & result;
|
|
30
|
+
|
|
31
|
+
auto* measuredWidth = reinterpret_cast<float*>(&wBits);
|
|
32
|
+
auto* measuredHeight = reinterpret_cast<float*>(&hBits);
|
|
33
|
+
|
|
34
|
+
return Size{.width = *measuredWidth, .height = *measuredHeight};
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include <react/renderer/components/modal/ModalHostViewUtils.h>
|
|
9
|
+
#include <react/renderer/graphics/Size.h>
|
|
10
|
+
#include "JReactModalHostView.h"
|
|
11
|
+
|
|
12
|
+
namespace facebook::react {
|
|
13
|
+
|
|
14
|
+
Size ModalHostViewScreenSize() {
|
|
15
|
+
return JReactModalHostView::getDisplayMetrics();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include <react/renderer/components/modal/ModalHostViewUtils.h>
|
|
9
|
+
#include <react/renderer/graphics/Size.h>
|
|
10
|
+
|
|
11
|
+
namespace facebook::react {
|
|
12
|
+
|
|
13
|
+
Size ModalHostViewScreenSize() {
|
|
14
|
+
return Size{0, 0};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
} // namespace facebook::react
|
|
@@ -76,6 +76,39 @@ EventPayloadType ScrollEvent::getType() const {
|
|
|
76
76
|
return EventPayloadType::ScrollEvent;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
jsi::Value ScrollEndDragEvent::asJSIValue(jsi::Runtime& runtime) const {
|
|
80
|
+
auto payload = ScrollEvent::asJSIValue(runtime).asObject(runtime);
|
|
81
|
+
|
|
82
|
+
{
|
|
83
|
+
auto targetContentOffsetObj = jsi::Object(runtime);
|
|
84
|
+
targetContentOffsetObj.setProperty(runtime, "x", targetContentOffset.x);
|
|
85
|
+
targetContentOffsetObj.setProperty(runtime, "y", targetContentOffset.y);
|
|
86
|
+
payload.setProperty(runtime, "targetContentOffset", targetContentOffsetObj);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
{
|
|
90
|
+
auto velocityObj = jsi::Object(runtime);
|
|
91
|
+
velocityObj.setProperty(runtime, "x", velocity.x);
|
|
92
|
+
velocityObj.setProperty(runtime, "y", velocity.y);
|
|
93
|
+
payload.setProperty(runtime, "velocity", velocityObj);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return payload;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
folly::dynamic ScrollEndDragEvent::asDynamic() const {
|
|
100
|
+
auto metrics = ScrollEvent::asDynamic();
|
|
101
|
+
|
|
102
|
+
auto targetContentOffsetObj = folly::dynamic::object(
|
|
103
|
+
"x", targetContentOffset.x)("y", targetContentOffset.y);
|
|
104
|
+
metrics["targetContentOffset"] = std::move(targetContentOffsetObj);
|
|
105
|
+
|
|
106
|
+
auto velocityObj = folly::dynamic::object("x", velocity.x)("y", velocity.y);
|
|
107
|
+
metrics["velocity"] = std::move(velocityObj);
|
|
108
|
+
|
|
109
|
+
return metrics;
|
|
110
|
+
};
|
|
111
|
+
|
|
79
112
|
#if RN_DEBUG_STRING_CONVERTIBLE
|
|
80
113
|
|
|
81
114
|
std::string getDebugName(const ScrollEvent& /*scrollEvent*/) {
|
|
@@ -37,6 +37,23 @@ struct ScrollEvent : public EventPayload {
|
|
|
37
37
|
EventPayloadType getType() const override;
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
+
struct ScrollEndDragEvent : public ScrollEvent {
|
|
41
|
+
Point targetContentOffset;
|
|
42
|
+
Point velocity;
|
|
43
|
+
|
|
44
|
+
ScrollEndDragEvent() = default;
|
|
45
|
+
|
|
46
|
+
ScrollEndDragEvent(const ScrollEvent& scrollEvent)
|
|
47
|
+
: ScrollEvent(scrollEvent), targetContentOffset({}), velocity({}) {}
|
|
48
|
+
|
|
49
|
+
folly::dynamic asDynamic() const;
|
|
50
|
+
|
|
51
|
+
/*
|
|
52
|
+
* EventPayload implementations
|
|
53
|
+
*/
|
|
54
|
+
jsi::Value asJSIValue(jsi::Runtime& runtime) const override;
|
|
55
|
+
};
|
|
56
|
+
|
|
40
57
|
#if RN_DEBUG_STRING_CONVERTIBLE
|
|
41
58
|
|
|
42
59
|
std::string getDebugName(const ScrollEvent& scrollEvent);
|
|
@@ -25,8 +25,9 @@ void ScrollViewEventEmitter::onScrollBeginDrag(
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
void ScrollViewEventEmitter::onScrollEndDrag(
|
|
28
|
-
const
|
|
29
|
-
|
|
28
|
+
const ScrollEndDragEvent& scrollEvent) const {
|
|
29
|
+
dispatchEvent(
|
|
30
|
+
"scrollEndDrag", std::make_shared<ScrollEndDragEvent>(scrollEvent));
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
void ScrollViewEventEmitter::onMomentumScrollBegin(
|
|
@@ -21,10 +21,11 @@ class ScrollViewEventEmitter : public ViewEventEmitter {
|
|
|
21
21
|
using ViewEventEmitter::ViewEventEmitter;
|
|
22
22
|
|
|
23
23
|
using Metrics = ScrollEvent;
|
|
24
|
+
using EndDragMetrics = ScrollEndDragEvent;
|
|
24
25
|
|
|
25
26
|
void onScroll(const ScrollEvent& scrollEvent) const;
|
|
26
27
|
void onScrollBeginDrag(const ScrollEvent& scrollEvent) const;
|
|
27
|
-
void onScrollEndDrag(const
|
|
28
|
+
void onScrollEndDrag(const ScrollEndDragEvent& scrollEvent) const;
|
|
28
29
|
void onMomentumScrollBegin(const ScrollEvent& scrollEvent) const;
|
|
29
30
|
void onMomentumScrollEnd(const ScrollEvent& scrollEvent) const;
|
|
30
31
|
void onScrollToTop(const ScrollEvent& scrollEvent) const;
|
|
@@ -300,8 +300,9 @@ void TimerManager::attachGlobals(jsi::Runtime& runtime) {
|
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
if (!args[0].isObject() || !args[0].asObject(rt).isFunction(rt)) {
|
|
303
|
-
// Do not throw any error to match web spec
|
|
304
|
-
|
|
303
|
+
// Do not throw any error to match web spec; instead return 0, an
|
|
304
|
+
// invalid timer id
|
|
305
|
+
return 0;
|
|
305
306
|
}
|
|
306
307
|
|
|
307
308
|
auto callback = args[0].getObject(rt).getFunction(rt);
|
|
@@ -358,8 +359,9 @@ void TimerManager::attachGlobals(jsi::Runtime& runtime) {
|
|
|
358
359
|
}
|
|
359
360
|
|
|
360
361
|
if (!args[0].isObject() || !args[0].asObject(rt).isFunction(rt)) {
|
|
361
|
-
throw
|
|
362
|
-
|
|
362
|
+
// Do not throw any error to match web spec; instead return 0, an
|
|
363
|
+
// invalid timer id
|
|
364
|
+
return 0;
|
|
363
365
|
}
|
|
364
366
|
auto callback = args[0].getObject(rt).getFunction(rt);
|
|
365
367
|
auto delay = count > 1
|
|
@@ -93,7 +93,9 @@ class TimerManager {
|
|
|
93
93
|
|
|
94
94
|
// Each timeout that is registered on this queue gets a sequential id. This
|
|
95
95
|
// is the global count from which those are assigned.
|
|
96
|
-
|
|
96
|
+
// As per WHATWG HTML 8.6.1 (Timers) ids must be greater than zero, i.e. start
|
|
97
|
+
// at 1
|
|
98
|
+
TimerHandle timerIndex_{1};
|
|
97
99
|
|
|
98
100
|
// The React Native microtask queue is used to back public APIs including
|
|
99
101
|
// `queueMicrotask`, `clearImmediate`, and `setImmediate` (which is used by
|
|
@@ -266,7 +266,9 @@ TEST_F(ReactInstanceTest, testSetTimeoutWithoutDelay) {
|
|
|
266
266
|
EXPECT_CALL(
|
|
267
267
|
*mockRegistry_,
|
|
268
268
|
createTimer(_, 0)); // If delay is not provided, it should use 0
|
|
269
|
-
eval("setTimeout(() => {});");
|
|
269
|
+
auto val = eval("setTimeout(() => {});");
|
|
270
|
+
expectNoError();
|
|
271
|
+
EXPECT_EQ(val.asNumber(), 1); // First timer id should start at 1
|
|
270
272
|
}
|
|
271
273
|
|
|
272
274
|
TEST_F(ReactInstanceTest, testSetTimeoutWithPassThroughArgs) {
|
|
@@ -298,8 +300,9 @@ TEST_F(ReactInstanceTest, testSetTimeoutWithInvalidArgs) {
|
|
|
298
300
|
getErrorMessage("setTimeout();"),
|
|
299
301
|
"setTimeout must be called with at least one argument (the function to call).");
|
|
300
302
|
|
|
301
|
-
eval("setTimeout('invalid')
|
|
303
|
+
auto val = eval("setTimeout('invalid')");
|
|
302
304
|
expectNoError();
|
|
305
|
+
EXPECT_EQ(val.asNumber(), 0);
|
|
303
306
|
|
|
304
307
|
eval("setTimeout(() => {}, 'invalid');");
|
|
305
308
|
expectNoError();
|
|
@@ -416,9 +419,10 @@ TEST_F(ReactInstanceTest, testSetIntervalWithInvalidArgs) {
|
|
|
416
419
|
EXPECT_EQ(
|
|
417
420
|
getErrorMessage("setInterval();"),
|
|
418
421
|
"setInterval must be called with at least one argument (the function to call).");
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
+
|
|
423
|
+
auto val = eval("setInterval('invalid', 100)");
|
|
424
|
+
expectNoError();
|
|
425
|
+
EXPECT_EQ(val.asNumber(), 0);
|
|
422
426
|
}
|
|
423
427
|
|
|
424
428
|
TEST_F(ReactInstanceTest, testClearInterval) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-tvos",
|
|
3
|
-
"version": "0.77.
|
|
3
|
+
"version": "0.77.3-0",
|
|
4
4
|
"description": "A framework for building native apps using React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -112,13 +112,13 @@
|
|
|
112
112
|
},
|
|
113
113
|
"dependencies": {
|
|
114
114
|
"@jest/create-cache-key-function": "^29.6.3",
|
|
115
|
-
"@react-native/assets-registry": "0.77.
|
|
116
|
-
"@react-native/codegen": "0.77.
|
|
117
|
-
"@react-native/community-cli-plugin": "0.77.
|
|
118
|
-
"@react-native/gradle-plugin": "0.77.
|
|
119
|
-
"@react-native/js-polyfills": "0.77.
|
|
120
|
-
"@react-native/normalize-colors": "0.77.
|
|
121
|
-
"@react-native-tvos/virtualized-lists": "0.77.
|
|
115
|
+
"@react-native/assets-registry": "0.77.3",
|
|
116
|
+
"@react-native/codegen": "0.77.3",
|
|
117
|
+
"@react-native/community-cli-plugin": "0.77.3",
|
|
118
|
+
"@react-native/gradle-plugin": "0.77.3",
|
|
119
|
+
"@react-native/js-polyfills": "0.77.3",
|
|
120
|
+
"@react-native/normalize-colors": "0.77.3",
|
|
121
|
+
"@react-native-tvos/virtualized-lists": "0.77.3-0",
|
|
122
122
|
"abort-controller": "^3.0.0",
|
|
123
123
|
"anser": "^1.4.9",
|
|
124
124
|
"ansi-regex": "^5.0.0",
|
|
@@ -134,8 +134,8 @@
|
|
|
134
134
|
"jest-environment-node": "^29.6.3",
|
|
135
135
|
"jsc-android": "^250231.0.0",
|
|
136
136
|
"memoize-one": "^5.0.0",
|
|
137
|
-
"metro-runtime": "^0.81.
|
|
138
|
-
"metro-source-map": "^0.81.
|
|
137
|
+
"metro-runtime": "^0.81.5",
|
|
138
|
+
"metro-source-map": "^0.81.5",
|
|
139
139
|
"nullthrows": "^1.1.1",
|
|
140
140
|
"pretty-format": "^29.7.0",
|
|
141
141
|
"promise": "^8.3.0",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|