react-native-tvos 0.85.0-0rc5 → 0.85.2-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/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +1 -0
- package/Libraries/Components/ScrollView/ScrollView.d.ts +7 -0
- package/Libraries/Components/ScrollView/ScrollView.js +6 -0
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +2 -0
- package/Libraries/Components/ScrollView/ScrollViewNativeComponentType.js +1 -0
- package/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +5 -1
- package/Libraries/Components/TextInput/TextInput.flow.js +1 -0
- package/Libraries/Core/ReactNativeVersion.js +2 -2
- package/README.md +52 -0
- package/React/Base/RCTVersion.m +2 -2
- package/React/CoreModules/RCTDevLoadingView.mm +17 -0
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.h +1 -0
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm +78 -0
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +32 -6
- package/React/Views/ScrollView/RCTScrollViewManager.m +1 -0
- package/ReactAndroid/build.gradle.kts +2 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android.kt +5 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkEventUtil.kt +8 -0
- package/ReactAndroid/src/main/java/com/facebook/react/modules/network/RequestBodyUtil.kt +2 -0
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/views/common/UiModeUtils.kt +20 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +57 -8
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.kt +5 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +48 -2
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.kt +5 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java +28 -3
- package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt +5 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputSubmitEditingEvent.kt +6 -1
- package/ReactCommon/React-Fabric.podspec +1 -0
- package/ReactCommon/cxxreact/ReactNativeVersion.h +3 -3
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +2 -2
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h +9 -1
- package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm +3 -1
- package/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.cpp +4 -1
- package/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp +58 -25
- package/ReactCommon/react/renderer/animationbackend/AnimationBackend.h +9 -0
- package/ReactCommon/react/renderer/animationbackend/AnimationChoreographer.h +5 -0
- package/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.cpp +10 -0
- package/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.h +1 -0
- package/ReactCommon/react/renderer/uimanager/UIManagerAnimationBackend.h +1 -0
- package/package.json +9 -9
- package/scripts/codegen/generate-artifacts-executor/generateAppDependencyProvider.js +4 -4
- package/scripts/codegen/generate-artifacts-executor/generateCustomURLHandlers.js +3 -3
- package/scripts/codegen/generate-artifacts-executor/generateNativeCode.js +2 -3
- package/scripts/codegen/generate-artifacts-executor/generatePackageSwift.js +2 -2
- package/scripts/codegen/generate-artifacts-executor/generateRCTModuleProviders.js +3 -2
- package/scripts/codegen/generate-artifacts-executor/generateRCTThirdPartyComponents.js +3 -2
- package/scripts/codegen/generate-artifacts-executor/generateReactCodegenPodspec.js +2 -2
- package/scripts/codegen/generate-artifacts-executor/generateUnstableModulesRequiringMainQueueSetupProvider.js +3 -3
- package/scripts/codegen/generate-artifacts-executor/utils.js +48 -0
- package/src/private/featureflags/ReactNativeFeatureFlags.js +2 -2
- package/types/public/ReactNativeTVTypes.d.ts +8 -0
|
@@ -754,6 +754,13 @@ export interface ScrollViewProps
|
|
|
754
754
|
*/
|
|
755
755
|
removeClippedSubviews?: boolean | undefined;
|
|
756
756
|
|
|
757
|
+
/**
|
|
758
|
+
* (TV only)
|
|
759
|
+
* When false, the scroll view will jump to the correct offset without animation
|
|
760
|
+
* when focus changes. Defaults to true.
|
|
761
|
+
*/
|
|
762
|
+
scrollAnimationEnabled?: boolean | undefined;
|
|
763
|
+
|
|
757
764
|
/**
|
|
758
765
|
* When true, shows a horizontal scroll indicator.
|
|
759
766
|
*/
|
|
@@ -670,6 +670,12 @@ type ScrollViewBaseProps = Readonly<{
|
|
|
670
670
|
* true.
|
|
671
671
|
*/
|
|
672
672
|
removeClippedSubviews?: ?boolean,
|
|
673
|
+
/**
|
|
674
|
+
* (TV only)
|
|
675
|
+
* When false, the scroll view will jump to the correct offset without animation
|
|
676
|
+
* when focus changes. Defaults to true.
|
|
677
|
+
*/
|
|
678
|
+
scrollAnimationEnabled?: ?boolean,
|
|
673
679
|
/**
|
|
674
680
|
* A RefreshControl component, used to provide pull-to-refresh
|
|
675
681
|
* functionality for the ScrollView. Only works for vertical ScrollViews
|
|
@@ -76,6 +76,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
|
|
|
76
76
|
borderTopRightRadius: true,
|
|
77
77
|
borderLeftColor: colorAttribute,
|
|
78
78
|
snapToItemPadding: true,
|
|
79
|
+
scrollAnimationEnabled: true,
|
|
79
80
|
pointerEvents: true,
|
|
80
81
|
isInvertedVirtualizedList: true,
|
|
81
82
|
scrollsChildToFocus: true,
|
|
@@ -142,6 +143,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
|
|
|
142
143
|
scrollsToTop: true,
|
|
143
144
|
showsHorizontalScrollIndicator: true,
|
|
144
145
|
showsVerticalScrollIndicator: true,
|
|
146
|
+
scrollAnimationEnabled: true,
|
|
145
147
|
showsScrollIndex: true,
|
|
146
148
|
snapToItemPadding: true,
|
|
147
149
|
snapToAlignment: true,
|
|
@@ -73,6 +73,7 @@ export type ScrollViewNativeProps = Readonly<{
|
|
|
73
73
|
snapToItemPadding?: ?number,
|
|
74
74
|
sendMomentumEvents?: ?boolean,
|
|
75
75
|
showsHorizontalScrollIndicator?: ?boolean,
|
|
76
|
+
scrollAnimationEnabled?: ?boolean,
|
|
76
77
|
showsScrollIndex?: ?boolean,
|
|
77
78
|
showsVerticalScrollIndicator?: ?boolean,
|
|
78
79
|
snapToAlignment?: ?('start' | 'center' | 'end' | 'item'),
|
|
@@ -402,7 +402,11 @@ export type AndroidTextInputNativeProps = Readonly<{
|
|
|
402
402
|
* Invalid if `multiline={true}` is specified.
|
|
403
403
|
*/
|
|
404
404
|
onSubmitEditing?: ?BubblingEventHandler<
|
|
405
|
-
Readonly<{
|
|
405
|
+
Readonly<{
|
|
406
|
+
target: Int32,
|
|
407
|
+
text: string,
|
|
408
|
+
action?: 'submit' | 'next' | 'previous',
|
|
409
|
+
}>,
|
|
406
410
|
>,
|
|
407
411
|
|
|
408
412
|
/**
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
export default class ReactNativeVersion {
|
|
29
29
|
static major: number = 0;
|
|
30
30
|
static minor: number = 85;
|
|
31
|
-
static patch: number =
|
|
32
|
-
static prerelease: string | null = '
|
|
31
|
+
static patch: number = 2;
|
|
32
|
+
static prerelease: string | null = '0';
|
|
33
33
|
|
|
34
34
|
static getVersionString(): string {
|
|
35
35
|
return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
|
package/README.md
CHANGED
|
@@ -262,6 +262,58 @@ class Game2048 extends React.Component {
|
|
|
262
262
|
|
|
263
263
|
- _TVTextScrollView_: On Apple TV, a ScrollView will not scroll unless there are focusable items inside it or above/below it. This component works on both Apple TV and Android TV, using native code to allow scrolling using swipe gestures from the remote control.
|
|
264
264
|
|
|
265
|
+
- _ScrollView snap alignment_: The existing `snapToAlignment` prop has been extended with a new `'item'` value that enables per-item snap alignment on TV. Instead of snapping all items uniformly to `'start'`, `'center'`, or `'end'`, each child can specify its own alignment via the `scrollSnapAlign` View prop. Optional padding can be applied with `snapToItemPadding` on the ScrollView.
|
|
266
|
+
|
|
267
|
+
| Prop (ScrollView) | Value | Description |
|
|
268
|
+
|---|---|---|
|
|
269
|
+
| snapToAlignment | `'item'` | Enables per-item snap alignment (TV only). Requires `snapToInterval` to be set. |
|
|
270
|
+
| snapToItemPadding | number? | Extra padding (in dp/pt) applied around items when snapping. Only used with `snapToAlignment="item"`. |
|
|
271
|
+
|
|
272
|
+
| Prop (View) | Value | Description |
|
|
273
|
+
|---|---|---|
|
|
274
|
+
| scrollSnapAlign | `'start'` \| `'center'` \| `'end'` | Controls where this item snaps inside its parent ScrollView. Only used when the parent has `snapToAlignment="item"`. |
|
|
275
|
+
|
|
276
|
+
```jsx
|
|
277
|
+
<ScrollView
|
|
278
|
+
horizontal
|
|
279
|
+
snapToInterval={300}
|
|
280
|
+
snapToAlignment="item"
|
|
281
|
+
snapToItemPadding={20}>
|
|
282
|
+
<Pressable scrollSnapAlign="start" style={{width: 300}}>
|
|
283
|
+
<Text>Snaps to start</Text>
|
|
284
|
+
</Pressable>
|
|
285
|
+
<Pressable scrollSnapAlign="center" style={{width: 200}}>
|
|
286
|
+
<Text>Snaps to center</Text>
|
|
287
|
+
</Pressable>
|
|
288
|
+
<Pressable scrollSnapAlign="end" style={{width: 300}}>
|
|
289
|
+
<Text>Snaps to end</Text>
|
|
290
|
+
</Pressable>
|
|
291
|
+
</ScrollView>
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
- _ScrollView animation control_: The `scrollAnimationEnabled` prop allows disabling scroll animations when focus changes on TV. When set to `false`, the scroll view jumps instantly to the focused item instead of animating. This only affects TV platforms and has no effect on mobile.
|
|
295
|
+
|
|
296
|
+
| Prop (ScrollView) | Value | Description |
|
|
297
|
+
|---|---|---|
|
|
298
|
+
| scrollAnimationEnabled | boolean? | When `false`, disables animated scrolling on focus change. Defaults to `true`. TV only. |
|
|
299
|
+
|
|
300
|
+
```jsx
|
|
301
|
+
<ScrollView horizontal scrollAnimationEnabled={false}>
|
|
302
|
+
<Pressable style={{width: 300}}><Text>Item 1</Text></Pressable>
|
|
303
|
+
<Pressable style={{width: 300}}><Text>Item 2</Text></Pressable>
|
|
304
|
+
<Pressable style={{width: 300}}><Text>Item 3</Text></Pressable>
|
|
305
|
+
</ScrollView>
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
- _Interaction with existing ScrollView props_: The TV scroll props build on top of existing React Native ScrollView behavior. Here is how they interact:
|
|
309
|
+
|
|
310
|
+
- `snapToAlignment="item"` does not require `snapToInterval` to be set. It works as a standalone snapping mode where each child's `scrollSnapAlign` determines the snap position. If `snapToInterval` is also set, the interval is applied as an additional constraint after the item offset is computed.
|
|
311
|
+
- `snapToAlignment="item"` should not be combined with `pagingEnabled`. Both attempt to control scroll positioning independently, which leads to unpredictable behavior. Use one or the other.
|
|
312
|
+
- `snapToStart` and `snapToEnd` work independently of `snapToAlignment="item"`. They control edge behavior during swipe/drag momentum (whether the scroll view snaps to the first or last position), but do not affect focus driven item snapping.
|
|
313
|
+
- `scrollAnimationEnabled={false}` disables all scroll animations, including programmatic `scrollTo({animated: true})` calls. When disabled, all scrolling is instant.
|
|
314
|
+
- `decelerationRate` has no effect when `scrollAnimationEnabled={false}`, since there is no animation to decelerate.
|
|
315
|
+
- `scrollAnimationEnabled` and `snapToAlignment="item"` work well together. Snapping still occurs, but instantly instead of animated.
|
|
316
|
+
|
|
265
317
|
- _VirtualizedList_: We extend `VirtualizedList` to make virtualization work well with focus management in mind. All of the improvements that we made are automatically available to all the VirtualizedList based components such as `FlatList`.
|
|
266
318
|
- Defaults: VirtualizeList contents are automatically wrapped with a `TVFocusGuideView` with `trapFocus*` properties enabled depending on the orientation of the list. This default makes sure that focus doesn't leave the list accidentally due to a virtualization issue etc. until reaching the beginning or the end of the list.
|
|
267
319
|
- New Props:
|
package/React/Base/RCTVersion.m
CHANGED
|
@@ -23,8 +23,8 @@ NSDictionary* RCTGetReactNativeVersion(void)
|
|
|
23
23
|
__rnVersion = @{
|
|
24
24
|
RCTVersionMajor: @(0),
|
|
25
25
|
RCTVersionMinor: @(85),
|
|
26
|
-
RCTVersionPatch: @(
|
|
27
|
-
RCTVersionPrerelease: @"
|
|
26
|
+
RCTVersionPatch: @(2),
|
|
27
|
+
RCTVersionPrerelease: @"0",
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
return __rnVersion;
|
|
@@ -51,10 +51,27 @@ RCT_EXPORT_MODULE()
|
|
|
51
51
|
selector:@selector(hide)
|
|
52
52
|
name:RCTJavaScriptDidFailToLoadNotification
|
|
53
53
|
object:nil];
|
|
54
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
55
|
+
selector:@selector(hide)
|
|
56
|
+
name:@"RCTInstanceDidLoadBundle"
|
|
57
|
+
object:nil];
|
|
54
58
|
}
|
|
55
59
|
return self;
|
|
56
60
|
}
|
|
57
61
|
|
|
62
|
+
- (void)dealloc
|
|
63
|
+
{
|
|
64
|
+
[self clearInitialMessageDelay];
|
|
65
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
66
|
+
UIWindow *window = _window;
|
|
67
|
+
_window = nil;
|
|
68
|
+
if (window) {
|
|
69
|
+
RCTExecuteOnMainQueue(^{
|
|
70
|
+
window.hidden = YES;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
58
75
|
+ (void)setEnabled:(BOOL)enabled
|
|
59
76
|
{
|
|
60
77
|
RCTDevLoadingViewSetEnabled(enabled);
|
|
@@ -52,6 +52,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
52
52
|
@property (nonatomic, assign) BOOL snapToEnd;
|
|
53
53
|
@property (nonatomic, copy) NSArray<NSNumber *> *snapToOffsets;
|
|
54
54
|
@property (nonatomic, assign) BOOL scrollSnapEnabled;
|
|
55
|
+
@property (nonatomic, assign) BOOL scrollAnimationEnabled;
|
|
55
56
|
|
|
56
57
|
/*
|
|
57
58
|
* Makes `setContentOffset:` method no-op when given `block` is executed.
|
|
@@ -9,6 +9,28 @@
|
|
|
9
9
|
#import <React/RCTUtils.h>
|
|
10
10
|
#import <react/utils/FloatComparison.h>
|
|
11
11
|
|
|
12
|
+
#if TARGET_OS_TV
|
|
13
|
+
// Layer subclass that can block all animations when scrollAnimationEnabled is NO.
|
|
14
|
+
// This intercepts animations at the point they're added to the layer, which catches
|
|
15
|
+
// all animation sources: UIView animations, focus coordinator animations, and
|
|
16
|
+
// Core Animation implicit/explicit animations.
|
|
17
|
+
@interface RCTScrollViewLayer : CALayer
|
|
18
|
+
@property (nonatomic, assign) BOOL blockAnimations;
|
|
19
|
+
@end
|
|
20
|
+
|
|
21
|
+
@implementation RCTScrollViewLayer
|
|
22
|
+
|
|
23
|
+
- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key
|
|
24
|
+
{
|
|
25
|
+
if (_blockAnimations) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
[super addAnimation:anim forKey:key];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@end
|
|
32
|
+
#endif
|
|
33
|
+
|
|
12
34
|
@interface RCTEnhancedScrollView () <UIScrollViewDelegate>
|
|
13
35
|
@end
|
|
14
36
|
|
|
@@ -17,6 +39,13 @@
|
|
|
17
39
|
BOOL _isSetContentOffsetDisabled;
|
|
18
40
|
}
|
|
19
41
|
|
|
42
|
+
#if TARGET_OS_TV
|
|
43
|
+
+ (Class)layerClass
|
|
44
|
+
{
|
|
45
|
+
return [RCTScrollViewLayer class];
|
|
46
|
+
}
|
|
47
|
+
#endif
|
|
48
|
+
|
|
20
49
|
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
|
|
21
50
|
{
|
|
22
51
|
if ([key isEqualToString:@"delegate"]) {
|
|
@@ -28,9 +57,18 @@
|
|
|
28
57
|
return [super automaticallyNotifiesObserversForKey:key];
|
|
29
58
|
}
|
|
30
59
|
|
|
60
|
+
- (void)setScrollAnimationEnabled:(BOOL)scrollAnimationEnabled
|
|
61
|
+
{
|
|
62
|
+
_scrollAnimationEnabled = scrollAnimationEnabled;
|
|
63
|
+
#if TARGET_OS_TV
|
|
64
|
+
((RCTScrollViewLayer *)self.layer).blockAnimations = !scrollAnimationEnabled;
|
|
65
|
+
#endif
|
|
66
|
+
}
|
|
67
|
+
|
|
31
68
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
32
69
|
{
|
|
33
70
|
if (self = [super initWithFrame:frame]) {
|
|
71
|
+
_scrollAnimationEnabled = YES;
|
|
34
72
|
// We set the default behavior to "never" so that iOS
|
|
35
73
|
// doesn't do weird things to UIScrollView insets automatically
|
|
36
74
|
// and keeps it as an opt-in behavior.
|
|
@@ -102,6 +140,46 @@
|
|
|
102
140
|
RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y"));
|
|
103
141
|
}
|
|
104
142
|
|
|
143
|
+
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
|
|
144
|
+
{
|
|
145
|
+
if (_isSetContentOffsetDisabled) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
#if TARGET_OS_TV
|
|
149
|
+
animated = animated && _scrollAnimationEnabled;
|
|
150
|
+
#endif
|
|
151
|
+
[super setContentOffset:CGPointMake(
|
|
152
|
+
RCTSanitizeNaNValue(contentOffset.x, @"scrollView.contentOffset.x"),
|
|
153
|
+
RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y"))
|
|
154
|
+
animated:animated];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
|
|
158
|
+
{
|
|
159
|
+
#if TARGET_OS_TV
|
|
160
|
+
animated = animated && _scrollAnimationEnabled;
|
|
161
|
+
#endif
|
|
162
|
+
[super scrollRectToVisible:rect animated:animated];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
#if TARGET_OS_TV
|
|
166
|
+
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context
|
|
167
|
+
withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
|
|
168
|
+
{
|
|
169
|
+
if (_scrollAnimationEnabled) {
|
|
170
|
+
[super didUpdateFocusInContext:context withAnimationCoordinator:coordinator];
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// When scrollAnimationEnabled is NO, don't call super and don't scroll here.
|
|
175
|
+
// RCTScrollViewComponentView.didUpdateFocusInContext handles all scrolling
|
|
176
|
+
// (both snap and non-snap cases) when animation is disabled. Scrolling here
|
|
177
|
+
// as well would cause conflicts — e.g. at the end of a snapToInterval list,
|
|
178
|
+
// this method computes a "just make visible" position while the component view
|
|
179
|
+
// computes the correct snapped position, causing a bounce effect.
|
|
180
|
+
}
|
|
181
|
+
#endif
|
|
182
|
+
|
|
105
183
|
- (void)setFrame:(CGRect)frame
|
|
106
184
|
{
|
|
107
185
|
[super setFrame:frame];
|
|
@@ -434,6 +434,9 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
434
434
|
|
|
435
435
|
scrollView.snapToStart = newScrollViewProps.snapToStart;
|
|
436
436
|
scrollView.snapToEnd = newScrollViewProps.snapToEnd;
|
|
437
|
+
#if TARGET_OS_TV
|
|
438
|
+
scrollView.scrollAnimationEnabled = newScrollViewProps.scrollAnimationEnabled;
|
|
439
|
+
#endif
|
|
437
440
|
|
|
438
441
|
if (oldScrollViewProps.snapToOffsets != newScrollViewProps.snapToOffsets) {
|
|
439
442
|
NSMutableArray<NSNumber *> *snapToOffsets = [NSMutableArray array];
|
|
@@ -1252,7 +1255,7 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
1252
1255
|
? CGPointMake(targetOffset, scrollView.contentOffset.y)
|
|
1253
1256
|
: CGPointMake(scrollView.contentOffset.x, targetOffset);
|
|
1254
1257
|
self.preferredContentOffset = targetContentOffset;
|
|
1255
|
-
[_scrollView setContentOffset:targetContentOffset animated:
|
|
1258
|
+
[_scrollView setContentOffset:targetContentOffset animated:scrollProps.scrollAnimationEnabled];
|
|
1256
1259
|
}
|
|
1257
1260
|
|
|
1258
1261
|
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context
|
|
@@ -1261,7 +1264,18 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
1261
1264
|
self.preferredContentOffset = NO_PREFERRED_CONTENT_OFFSET;
|
|
1262
1265
|
const auto &scrollProps = static_cast<const ScrollViewProps &>(*_props);
|
|
1263
1266
|
BOOL hasItemSnapAlignment = scrollProps.snapToAlignment == ScrollViewSnapToAlignment::Item;
|
|
1264
|
-
if (context.previouslyFocusedView == context.nextFocusedView
|
|
1267
|
+
if (context.previouslyFocusedView == context.nextFocusedView) {
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
if (!_props->isTVSelectable && !hasItemSnapAlignment) {
|
|
1271
|
+
if (!scrollProps.scrollAnimationEnabled && [context.nextFocusedView isDescendantOfView:_scrollView]) {
|
|
1272
|
+
// When animations are disabled and there's no snap alignment, manually scroll
|
|
1273
|
+
// the focused view into view instantly. We can't let UIScrollView's default
|
|
1274
|
+
// focus handling do this because it uses deceleration (timer-based) that can't
|
|
1275
|
+
// be blocked by the animation-blocking layer.
|
|
1276
|
+
CGRect targetRect = [context.nextFocusedView convertRect:context.nextFocusedView.bounds toView:_scrollView];
|
|
1277
|
+
[_scrollView scrollRectToVisible:targetRect animated:NO];
|
|
1278
|
+
}
|
|
1265
1279
|
return;
|
|
1266
1280
|
}
|
|
1267
1281
|
if (_props->isTVSelectable && context.nextFocusedView == self) {
|
|
@@ -1429,10 +1443,16 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
1429
1443
|
limitedOffset = MAX(limitedOffset, 0.0);
|
|
1430
1444
|
limitedOffset = MIN(limitedOffset, maxOffset);
|
|
1431
1445
|
|
|
1432
|
-
|
|
1446
|
+
const auto &scrollProps = static_cast<const ScrollViewProps &>(*self->_props);
|
|
1447
|
+
if (scrollProps.scrollAnimationEnabled) {
|
|
1448
|
+
[UIView animateWithDuration:[self swipeDuration] animations:^{
|
|
1449
|
+
self.scrollView.contentOffset =
|
|
1450
|
+
CGPointMake(self.scrollView.contentOffset.x, limitedOffset);
|
|
1451
|
+
}];
|
|
1452
|
+
} else {
|
|
1433
1453
|
self.scrollView.contentOffset =
|
|
1434
1454
|
CGPointMake(self.scrollView.contentOffset.x, limitedOffset);
|
|
1435
|
-
}
|
|
1455
|
+
}
|
|
1436
1456
|
});
|
|
1437
1457
|
}
|
|
1438
1458
|
|
|
@@ -1453,10 +1473,16 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
1453
1473
|
limitedOffset = MAX(limitedOffset, 0.0);
|
|
1454
1474
|
limitedOffset = MIN(limitedOffset, maxOffset);
|
|
1455
1475
|
|
|
1456
|
-
|
|
1476
|
+
const auto &scrollProps = static_cast<const ScrollViewProps &>(*self->_props);
|
|
1477
|
+
if (scrollProps.scrollAnimationEnabled) {
|
|
1478
|
+
[UIView animateWithDuration:[self swipeDuration] animations:^{
|
|
1479
|
+
self.scrollView.contentOffset =
|
|
1480
|
+
CGPointMake(limitedOffset, self.scrollView.contentOffset.y);
|
|
1481
|
+
}];
|
|
1482
|
+
} else {
|
|
1457
1483
|
self.scrollView.contentOffset =
|
|
1458
1484
|
CGPointMake(limitedOffset, self.scrollView.contentOffset.y);
|
|
1459
|
-
}
|
|
1485
|
+
}
|
|
1460
1486
|
});
|
|
1461
1487
|
}
|
|
1462
1488
|
|
|
@@ -106,6 +106,7 @@ RCT_EXPORT_VIEW_PROPERTY(onMomentumScrollEnd, RCTDirectEventBlock)
|
|
|
106
106
|
RCT_EXPORT_VIEW_PROPERTY(inverted, BOOL)
|
|
107
107
|
#if TARGET_OS_TV
|
|
108
108
|
RCT_EXPORT_VIEW_PROPERTY(showsScrollIndex, BOOL)
|
|
109
|
+
RCT_EXPORT_VIEW_PROPERTY(scrollAnimationEnabled, BOOL)
|
|
109
110
|
#endif
|
|
110
111
|
RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustsScrollIndicatorInsets, BOOL)
|
|
111
112
|
RCT_EXPORT_VIEW_PROPERTY(contentInsetAdjustmentBehavior, UIScrollViewContentInsetAdjustmentBehavior)
|
|
@@ -102,6 +102,8 @@ val preparePrefab by
|
|
|
102
102
|
Pair("../ReactCommon/hermes/inspector-modern/", "hermes/inspector-modern/"),
|
|
103
103
|
// fabricjni
|
|
104
104
|
Pair("src/main/jni/react/fabric", "react/fabric/"),
|
|
105
|
+
// uimanagerjni
|
|
106
|
+
Pair("src/main/jni/react/uimanager", "react/uimanager/"),
|
|
105
107
|
// glog
|
|
106
108
|
Pair(File(buildDir, "third-party-ndk/glog/exported/").absolutePath, ""),
|
|
107
109
|
// jsiinpsector
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @generated SignedSource<<
|
|
7
|
+
* @generated SignedSource<<404cef70d58d40565506ab37a4697da8>>
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -57,7 +57,7 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
|
|
57
57
|
|
|
58
58
|
override fun enableCppPropsIteratorSetter(): Boolean = false
|
|
59
59
|
|
|
60
|
-
override fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean =
|
|
60
|
+
override fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean = false
|
|
61
61
|
|
|
62
62
|
override fun enableDestroyShadowTreeRevisionAsync(): Boolean = false
|
|
63
63
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @generated SignedSource<<
|
|
7
|
+
* @generated SignedSource<<2452c003ffcba8e20b7cd40c68e05e3d>>
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -23,6 +23,8 @@ public open class ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android :
|
|
|
23
23
|
// We could use JNI to get the defaults from C++,
|
|
24
24
|
// but that is more expensive than just duplicating the defaults here.
|
|
25
25
|
|
|
26
|
+
override fun cxxNativeAnimatedEnabled(): Boolean = true
|
|
27
|
+
|
|
26
28
|
override fun enableAccessibilityOrder(): Boolean = true
|
|
27
29
|
|
|
28
30
|
override fun enableSwiftUIBasedFilters(): Boolean = true
|
|
@@ -30,4 +32,6 @@ public open class ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android :
|
|
|
30
32
|
override fun fixTextClippingAndroid15useBoundsForWidth(): Boolean = true
|
|
31
33
|
|
|
32
34
|
override fun preventShadowTreeCommitExhaustion(): Boolean = true
|
|
35
|
+
|
|
36
|
+
override fun useSharedAnimatedBackend(): Boolean = true
|
|
33
37
|
}
|
|
@@ -19,6 +19,7 @@ import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
|
|
|
19
19
|
import java.io.IOException
|
|
20
20
|
import java.net.SocketTimeoutException
|
|
21
21
|
import okhttp3.Headers
|
|
22
|
+
import okhttp3.MultipartBody
|
|
22
23
|
import okhttp3.RequestBody
|
|
23
24
|
import okio.Buffer
|
|
24
25
|
|
|
@@ -263,6 +264,13 @@ internal object NetworkEventUtil {
|
|
|
263
264
|
return "[Preview unavailable]"
|
|
264
265
|
}
|
|
265
266
|
|
|
267
|
+
// MultipartBody does not propagate isOneShot() from its parts, so check each
|
|
268
|
+
// part explicitly. Reading a one-shot part here would drain the underlying
|
|
269
|
+
// stream and cause the real request to fail.
|
|
270
|
+
if (body is MultipartBody && body.parts().any { it.body().isOneShot() }) {
|
|
271
|
+
return "[Preview unavailable]"
|
|
272
|
+
}
|
|
273
|
+
|
|
266
274
|
return try {
|
|
267
275
|
val buffer = Buffer()
|
|
268
276
|
body.writeTo(buffer)
|
|
@@ -7,12 +7,32 @@
|
|
|
7
7
|
|
|
8
8
|
package com.facebook.react.views.common
|
|
9
9
|
|
|
10
|
+
import android.app.UiModeManager
|
|
10
11
|
import android.content.Context
|
|
11
12
|
import android.content.res.Configuration
|
|
12
13
|
|
|
13
14
|
/** Utility object providing static methods for working with UI mode properties from Context. */
|
|
14
15
|
internal object UiModeUtils {
|
|
15
16
|
|
|
17
|
+
private var isTVDeviceCached: Boolean? = null
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Determines whether the device is a TV (Android TV / Fire TV).
|
|
21
|
+
* The result is cached after the first call.
|
|
22
|
+
*
|
|
23
|
+
* @param context The context to check the UI mode from
|
|
24
|
+
* @return true if the device is running in television mode, false otherwise
|
|
25
|
+
*/
|
|
26
|
+
@JvmStatic
|
|
27
|
+
fun isTVDevice(context: Context): Boolean {
|
|
28
|
+
return isTVDeviceCached ?: run {
|
|
29
|
+
val uiModeManager = context.getSystemService(Context.UI_MODE_SERVICE) as? UiModeManager
|
|
30
|
+
val result = uiModeManager?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION
|
|
31
|
+
isTVDeviceCached = result
|
|
32
|
+
result
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
16
36
|
/**
|
|
17
37
|
* Determines whether the current UI mode is dark mode
|
|
18
38
|
*
|