react-native-tvos 0.66.3-1 → 0.66.3-2
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/AppleTV/TVFocusGuideView.js +30 -35
- package/Libraries/Components/AppleTV/TVViewPropTypes.js +0 -27
- package/Libraries/Components/Pressable/Pressable.js +2 -0
- package/Libraries/Components/View/ViewNativeComponent.js +6 -1
- package/Libraries/LogBox/UI/LogBoxButton.js +1 -0
- package/React/Base/RCTTVRemoteHandler.h +3 -0
- package/React/Base/RCTTVRemoteHandler.m +24 -0
- package/React/Fabric/Mounting/ComponentViews/Modal/RCTFabricModalHostViewController.mm +1 -1
- package/React/Fabric/Mounting/ComponentViews/Root/RCTRootComponentView.h +9 -0
- package/React/Fabric/Mounting/ComponentViews/Root/RCTRootComponentView.mm +18 -0
- package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h +4 -0
- package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +416 -2
- package/React/Fabric/Mounting/RCTComponentViewFactory.mm +2 -0
- package/React/Views/RCTTVView.h +5 -0
- package/React/Views/RCTTVView.m +16 -0
- package/React/Views/RCTViewManager.m +17 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactCommon/hermes/inspector/tools/msggen/yarn.lock +37 -73
- package/ReactCommon/react/renderer/components/view/ViewProps.cpp +28 -0
- package/ReactCommon/react/renderer/components/view/ViewProps.h +10 -0
- package/ReactCommon/react/renderer/components/view/primitives.h +34 -0
- package/ReactCommon/react/renderer/components/view/propsConversions.h +66 -0
- package/android/com/facebook/react/react-native/{0.66.3-1/react-native-0.66.3-1.aar → 0.66.3-2/react-native-0.66.3-2.aar} +0 -0
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.aar.md5 +1 -0
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.aar.sha1 +1 -0
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.aar.sha256 +1 -0
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.aar.sha512 +1 -0
- package/android/com/facebook/react/react-native/{0.66.3-1/react-native-0.66.3-1.module → 0.66.3-2/react-native-0.66.3-2.module} +16 -16
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.module.md5 +1 -0
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.module.sha1 +1 -0
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.module.sha256 +1 -0
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.module.sha512 +1 -0
- package/android/com/facebook/react/react-native/{0.66.3-1/react-native-0.66.3-1.pom → 0.66.3-2/react-native-0.66.3-2.pom} +1 -1
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.pom.md5 +1 -0
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.pom.sha1 +1 -0
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.pom.sha256 +1 -0
- package/android/com/facebook/react/react-native/0.66.3-2/react-native-0.66.3-2.pom.sha512 +1 -0
- package/android/com/facebook/react/react-native/maven-metadata.xml +4 -4
- package/android/com/facebook/react/react-native/maven-metadata.xml.md5 +1 -1
- package/android/com/facebook/react/react-native/maven-metadata.xml.sha1 +1 -1
- package/android/com/facebook/react/react-native/maven-metadata.xml.sha256 +1 -1
- package/android/com/facebook/react/react-native/maven-metadata.xml.sha512 +1 -1
- package/package.json +2 -2
- package/template/package.json +1 -1
- package/React/Views/RCTTVFocusGuideView.h +0 -22
- package/React/Views/RCTTVFocusGuideView.m +0 -60
- package/React/Views/RCTTVFocusGuideViewManager.h +0 -12
- package/React/Views/RCTTVFocusGuideViewManager.m +0 -30
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.aar.md5 +0 -1
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.aar.sha1 +0 -1
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.aar.sha256 +0 -1
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.aar.sha512 +0 -1
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.module.md5 +0 -1
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.module.sha1 +0 -1
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.module.sha256 +0 -1
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.module.sha512 +0 -1
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.pom.md5 +0 -1
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.pom.sha1 +0 -1
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.pom.sha256 +0 -1
- package/android/com/facebook/react/react-native/0.66.3-1/react-native-0.66.3-1.pom.sha512 +0 -1
|
@@ -13,10 +13,26 @@
|
|
|
13
13
|
#import <React/RCTAssert.h>
|
|
14
14
|
#import <React/RCTBorderDrawing.h>
|
|
15
15
|
#import <React/RCTConversions.h>
|
|
16
|
+
#import <React/RCTDefines.h>
|
|
17
|
+
#import <React/RCTLog.h>
|
|
18
|
+
|
|
19
|
+
#import <React/RCTRootComponentView.h>
|
|
20
|
+
|
|
16
21
|
#import <react/renderer/components/view/ViewComponentDescriptor.h>
|
|
17
22
|
#import <react/renderer/components/view/ViewEventEmitter.h>
|
|
18
23
|
#import <react/renderer/components/view/ViewProps.h>
|
|
19
24
|
|
|
25
|
+
typedef struct {
|
|
26
|
+
BOOL enabled;
|
|
27
|
+
float shiftDistanceX;
|
|
28
|
+
float shiftDistanceY;
|
|
29
|
+
float tiltAngle;
|
|
30
|
+
float magnification;
|
|
31
|
+
float pressMagnification;
|
|
32
|
+
float pressDuration;
|
|
33
|
+
float pressDelay;
|
|
34
|
+
} ParallaxProperties;
|
|
35
|
+
|
|
20
36
|
using namespace facebook::react;
|
|
21
37
|
|
|
22
38
|
@implementation RCTViewComponentView {
|
|
@@ -26,7 +42,16 @@ using namespace facebook::react;
|
|
|
26
42
|
BOOL _isJSResponder;
|
|
27
43
|
BOOL _removeClippedSubviews;
|
|
28
44
|
NSMutableArray<UIView *> *_reactSubviews;
|
|
45
|
+
BOOL _motionEffectsAdded;
|
|
46
|
+
UITapGestureRecognizer *_selectRecognizer;
|
|
29
47
|
NSSet<NSString *> *_Nullable _propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN;
|
|
48
|
+
ParallaxProperties _tvParallaxProperties;
|
|
49
|
+
BOOL _hasTVPreferredFocus;
|
|
50
|
+
UIView *_nextFocusUp;
|
|
51
|
+
UIView *_nextFocusDown;
|
|
52
|
+
UIView *_nextFocusLeft;
|
|
53
|
+
UIView *_nextFocusRight;
|
|
54
|
+
UIView *_nextFocusActiveTarget;
|
|
30
55
|
}
|
|
31
56
|
|
|
32
57
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
@@ -35,7 +60,18 @@ using namespace facebook::react;
|
|
|
35
60
|
static auto const defaultProps = std::make_shared<ViewProps const>();
|
|
36
61
|
_props = defaultProps;
|
|
37
62
|
_reactSubviews = [NSMutableArray new];
|
|
38
|
-
#if
|
|
63
|
+
#if TARGET_OS_TV
|
|
64
|
+
_tvParallaxProperties.enabled = NO;
|
|
65
|
+
_tvParallaxProperties.shiftDistanceX = 0.0f;
|
|
66
|
+
_tvParallaxProperties.shiftDistanceY = 0.0f;
|
|
67
|
+
_tvParallaxProperties.tiltAngle = 0.0f;
|
|
68
|
+
_tvParallaxProperties.magnification = 0.0f;
|
|
69
|
+
_tvParallaxProperties.pressMagnification = 0.0f;
|
|
70
|
+
_tvParallaxProperties.pressDuration = 0.0f;
|
|
71
|
+
_tvParallaxProperties.pressDelay = 0.0f;
|
|
72
|
+
self.focusGuide = [UIFocusGuide new];
|
|
73
|
+
[self addLayoutGuide:self.focusGuide];
|
|
74
|
+
#else
|
|
39
75
|
self.multipleTouchEnabled = YES;
|
|
40
76
|
#endif
|
|
41
77
|
}
|
|
@@ -60,7 +96,6 @@ using namespace facebook::react;
|
|
|
60
96
|
_contentView.frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
|
|
61
97
|
}
|
|
62
98
|
}
|
|
63
|
-
|
|
64
99
|
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
|
|
65
100
|
{
|
|
66
101
|
if (UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero)) {
|
|
@@ -80,6 +115,290 @@ using namespace facebook::react;
|
|
|
80
115
|
_backgroundColor = backgroundColor;
|
|
81
116
|
}
|
|
82
117
|
|
|
118
|
+
#if TARGET_OS_TV
|
|
119
|
+
|
|
120
|
+
#pragma mark - Apple TV methods
|
|
121
|
+
|
|
122
|
+
- (RCTRootComponentView *)containingRootView
|
|
123
|
+
{
|
|
124
|
+
UIView *rootview = self;
|
|
125
|
+
if ([rootview class] == [RCTRootComponentView class]) {
|
|
126
|
+
return (RCTRootComponentView *)rootview;
|
|
127
|
+
}
|
|
128
|
+
do {
|
|
129
|
+
rootview = [rootview superview];
|
|
130
|
+
} while (([rootview class] != [RCTRootComponentView class]) && rootview != nil);
|
|
131
|
+
return (RCTRootComponentView *)rootview;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
- (void)addFocusDestinations:(NSArray*)destinations {
|
|
135
|
+
|
|
136
|
+
self.focusGuide.preferredFocusEnvironments = destinations;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
- (void)sendFocusNotification:(__unused UIFocusUpdateContext *)context
|
|
140
|
+
{
|
|
141
|
+
[self sendNotificationWithEventType:@"focus"];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
- (void)sendBlurNotification:(__unused UIFocusUpdateContext *)context
|
|
145
|
+
{
|
|
146
|
+
[self sendNotificationWithEventType:@"blur"];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
- (void)sendSelectNotification:(UIGestureRecognizer *)recognizer
|
|
150
|
+
{
|
|
151
|
+
[self sendNotificationWithEventType:@"select"];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
- (void)sendNotificationWithEventType:(NSString * __nonnull)eventType
|
|
155
|
+
{
|
|
156
|
+
[[NSNotificationCenter defaultCenter] postNotificationName:@"RCTTVNavigationEventNotification"
|
|
157
|
+
object:@{
|
|
158
|
+
@"eventType":eventType,
|
|
159
|
+
@"tag":@([self tag]),
|
|
160
|
+
@"target":@([self tag])
|
|
161
|
+
}];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
- (void)handleSelect:(__unused UIGestureRecognizer *)r
|
|
165
|
+
{
|
|
166
|
+
if (_tvParallaxProperties.enabled == YES) {
|
|
167
|
+
float magnification = _tvParallaxProperties.magnification;
|
|
168
|
+
float pressMagnification = _tvParallaxProperties.pressMagnification;
|
|
169
|
+
|
|
170
|
+
// Duration of press animation
|
|
171
|
+
float pressDuration = _tvParallaxProperties.pressDuration;
|
|
172
|
+
|
|
173
|
+
// Delay of press animation
|
|
174
|
+
float pressDelay = _tvParallaxProperties.pressDelay;
|
|
175
|
+
|
|
176
|
+
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:pressDelay]];
|
|
177
|
+
|
|
178
|
+
[UIView animateWithDuration:(pressDuration/2)
|
|
179
|
+
animations:^{
|
|
180
|
+
self.transform = CGAffineTransformMakeScale(pressMagnification, pressMagnification);
|
|
181
|
+
}
|
|
182
|
+
completion:^(__unused BOOL finished1){
|
|
183
|
+
[UIView animateWithDuration:(pressDuration/2)
|
|
184
|
+
animations:^{
|
|
185
|
+
self.transform = CGAffineTransformMakeScale(magnification, magnification);
|
|
186
|
+
}
|
|
187
|
+
completion:^(__unused BOOL finished2) {
|
|
188
|
+
[self sendSelectNotification:r];
|
|
189
|
+
}];
|
|
190
|
+
}];
|
|
191
|
+
|
|
192
|
+
} else {
|
|
193
|
+
[self sendSelectNotification:r];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
- (void)addParallaxMotionEffects
|
|
198
|
+
{
|
|
199
|
+
if(!_tvParallaxProperties.enabled) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if(_motionEffectsAdded == YES) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Size of shift movements
|
|
208
|
+
CGFloat const shiftDistanceX = _tvParallaxProperties.shiftDistanceX;
|
|
209
|
+
CGFloat const shiftDistanceY = _tvParallaxProperties.shiftDistanceY;
|
|
210
|
+
|
|
211
|
+
// Make horizontal movements shift the centre left and right
|
|
212
|
+
UIInterpolatingMotionEffect *xShift =
|
|
213
|
+
[[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x"
|
|
214
|
+
type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
|
|
215
|
+
xShift.minimumRelativeValue = @(shiftDistanceX * -1.0f);
|
|
216
|
+
xShift.maximumRelativeValue = @(shiftDistanceX);
|
|
217
|
+
|
|
218
|
+
// Make vertical movements shift the centre up and down
|
|
219
|
+
UIInterpolatingMotionEffect *yShift =
|
|
220
|
+
[[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y"
|
|
221
|
+
type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
|
|
222
|
+
yShift.minimumRelativeValue = @(shiftDistanceY * -1.0f);
|
|
223
|
+
yShift.maximumRelativeValue = @(shiftDistanceY);
|
|
224
|
+
|
|
225
|
+
// Size of tilt movements
|
|
226
|
+
CGFloat const tiltAngle = _tvParallaxProperties.tiltAngle;
|
|
227
|
+
|
|
228
|
+
// Now make horizontal movements effect a rotation about the Y axis for side-to-side rotation.
|
|
229
|
+
UIInterpolatingMotionEffect *xTilt =
|
|
230
|
+
[[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"layer.transform"
|
|
231
|
+
type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
|
|
232
|
+
|
|
233
|
+
// CATransform3D value for minimumRelativeValue
|
|
234
|
+
CATransform3D transMinimumTiltAboutY = CATransform3DIdentity;
|
|
235
|
+
transMinimumTiltAboutY.m34 = 1.0 / 500;
|
|
236
|
+
transMinimumTiltAboutY = CATransform3DRotate(transMinimumTiltAboutY, tiltAngle * -1.0, 0, 1, 0);
|
|
237
|
+
|
|
238
|
+
// CATransform3D value for minimumRelativeValue
|
|
239
|
+
CATransform3D transMaximumTiltAboutY = CATransform3DIdentity;
|
|
240
|
+
transMaximumTiltAboutY.m34 = 1.0 / 500;
|
|
241
|
+
transMaximumTiltAboutY = CATransform3DRotate(transMaximumTiltAboutY, tiltAngle, 0, 1, 0);
|
|
242
|
+
|
|
243
|
+
// Set the transform property boundaries for the interpolation
|
|
244
|
+
xTilt.minimumRelativeValue = [NSValue valueWithCATransform3D:transMinimumTiltAboutY];
|
|
245
|
+
xTilt.maximumRelativeValue = [NSValue valueWithCATransform3D:transMaximumTiltAboutY];
|
|
246
|
+
|
|
247
|
+
// Now make vertical movements effect a rotation about the X axis for up and down rotation.
|
|
248
|
+
UIInterpolatingMotionEffect *yTilt =
|
|
249
|
+
[[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"layer.transform"
|
|
250
|
+
type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
|
|
251
|
+
|
|
252
|
+
// CATransform3D value for minimumRelativeValue
|
|
253
|
+
CATransform3D transMinimumTiltAboutX = CATransform3DIdentity;
|
|
254
|
+
transMinimumTiltAboutX.m34 = 1.0 / 500;
|
|
255
|
+
transMinimumTiltAboutX = CATransform3DRotate(transMinimumTiltAboutX, tiltAngle * -1.0, 1, 0, 0);
|
|
256
|
+
|
|
257
|
+
// CATransform3D value for minimumRelativeValue
|
|
258
|
+
CATransform3D transMaximumTiltAboutX = CATransform3DIdentity;
|
|
259
|
+
transMaximumTiltAboutX.m34 = 1.0 / 500;
|
|
260
|
+
transMaximumTiltAboutX = CATransform3DRotate(transMaximumTiltAboutX, tiltAngle, 1, 0, 0);
|
|
261
|
+
|
|
262
|
+
// Set the transform property boundaries for the interpolation
|
|
263
|
+
yTilt.minimumRelativeValue = [NSValue valueWithCATransform3D:transMinimumTiltAboutX];
|
|
264
|
+
yTilt.maximumRelativeValue = [NSValue valueWithCATransform3D:transMaximumTiltAboutX];
|
|
265
|
+
|
|
266
|
+
// Add all of the motion effects to this group
|
|
267
|
+
self.motionEffects = @[ xShift, yShift, xTilt, yTilt ];
|
|
268
|
+
|
|
269
|
+
float magnification = _tvParallaxProperties.magnification;
|
|
270
|
+
|
|
271
|
+
[UIView animateWithDuration:0.2 animations:^{
|
|
272
|
+
self.transform = CGAffineTransformScale(self.transform, magnification, magnification);
|
|
273
|
+
}];
|
|
274
|
+
|
|
275
|
+
_motionEffectsAdded = YES;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
- (void)removeParallaxMotionEffects
|
|
279
|
+
{
|
|
280
|
+
if(_motionEffectsAdded == NO) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
[UIView animateWithDuration:0.2 animations:^{
|
|
285
|
+
float magnification = self->_tvParallaxProperties.magnification;
|
|
286
|
+
BOOL enabled = self->_tvParallaxProperties.enabled;
|
|
287
|
+
if (enabled && magnification) {
|
|
288
|
+
self.transform = CGAffineTransformScale(self.transform, 1.0/magnification, 1.0/magnification);
|
|
289
|
+
}
|
|
290
|
+
}];
|
|
291
|
+
|
|
292
|
+
for (UIMotionEffect *effect in [self.motionEffects copy]){
|
|
293
|
+
[self removeMotionEffect:effect];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
_motionEffectsAdded = NO;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
- (BOOL)isUserInteractionEnabled
|
|
301
|
+
{
|
|
302
|
+
return YES;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
- (BOOL)canBecomeFocused
|
|
306
|
+
{
|
|
307
|
+
return _props->isTVSelectable;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
- (NSArray<id<UIFocusEnvironment>> *)preferredFocusEnvironments {
|
|
311
|
+
if (_nextFocusActiveTarget == nil) return [super preferredFocusEnvironments];
|
|
312
|
+
UIView * nextFocusActiveTarget = _nextFocusActiveTarget;
|
|
313
|
+
_nextFocusActiveTarget = nil;
|
|
314
|
+
NSArray<id<UIFocusEnvironment>> * focusEnvironment = @[nextFocusActiveTarget];
|
|
315
|
+
return focusEnvironment;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
- (BOOL) shouldUpdateFocusInContext:(UIFocusUpdateContext *)context {
|
|
319
|
+
if (self.isFocused) {
|
|
320
|
+
if (_nextFocusUp != nil && context.focusHeading == UIFocusHeadingUp) {
|
|
321
|
+
self->_nextFocusActiveTarget = _nextFocusUp;
|
|
322
|
+
[self setNeedsFocusUpdate];
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
if (_nextFocusDown != nil && context.focusHeading == UIFocusHeadingDown) {
|
|
326
|
+
self->_nextFocusActiveTarget = _nextFocusDown;
|
|
327
|
+
[self setNeedsFocusUpdate];
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
if (_nextFocusLeft != nil && context.focusHeading == UIFocusHeadingLeft) {
|
|
331
|
+
self->_nextFocusActiveTarget = _nextFocusLeft;
|
|
332
|
+
[self setNeedsFocusUpdate];
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
if (_nextFocusRight != nil && context.focusHeading == UIFocusHeadingRight) {
|
|
336
|
+
self->_nextFocusActiveTarget = _nextFocusRight;
|
|
337
|
+
[self setNeedsFocusUpdate];
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
self->_nextFocusActiveTarget = nil;
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
self->_nextFocusActiveTarget = nil;
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
|
|
348
|
+
{
|
|
349
|
+
if (context.previouslyFocusedView == context.nextFocusedView) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (context.nextFocusedView == self && self.isUserInteractionEnabled ) {
|
|
353
|
+
[self becomeFirstResponder];
|
|
354
|
+
[coordinator addCoordinatedAnimations:^(void){
|
|
355
|
+
[self addParallaxMotionEffects];
|
|
356
|
+
[self sendFocusNotification:context];
|
|
357
|
+
} completion:^(void){}];
|
|
358
|
+
} else {
|
|
359
|
+
[coordinator addCoordinatedAnimations:^(void){
|
|
360
|
+
[self removeParallaxMotionEffects];
|
|
361
|
+
[self sendBlurNotification:context];
|
|
362
|
+
} completion:^(void){}];
|
|
363
|
+
[self resignFirstResponder];
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
#endif
|
|
368
|
+
|
|
369
|
+
#pragma mark - Native Commands
|
|
370
|
+
|
|
371
|
+
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
|
|
372
|
+
{
|
|
373
|
+
NSLog(@"RCTViewComponentView handleCommand: %@", commandName);
|
|
374
|
+
if ([commandName isEqualToString:@"setDestinations"]) {
|
|
375
|
+
#if TARGET_OS_TV
|
|
376
|
+
if ([args count] != 1) {
|
|
377
|
+
RCTLogError(
|
|
378
|
+
@"%@ command %@ received %d arguments, expected %d.", @"View", commandName, (int)[args count], 1);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (!RCTValidateTypeOfViewCommandArgument(args[0], [NSArray class], @"number", @"View", commandName, @"1st")) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
NSArray *destinationTags = (NSArray<NSNumber *> *)args[0];
|
|
385
|
+
NSMutableArray *destinations = [NSMutableArray new];
|
|
386
|
+
RCTRootComponentView *rootView = [self containingRootView];
|
|
387
|
+
for (NSNumber *tag in destinationTags) {
|
|
388
|
+
UIView *view = [rootView viewWithTag:[tag intValue]];
|
|
389
|
+
if (view != nil) {
|
|
390
|
+
[destinations addObject:view];
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
[self addFocusDestinations:destinations];
|
|
394
|
+
return;
|
|
395
|
+
#endif
|
|
396
|
+
}
|
|
397
|
+
#if RCT_DEBUG
|
|
398
|
+
RCTLogError(@"%@ received command %@, which is not a supported command.", @"View", commandName);
|
|
399
|
+
#endif
|
|
400
|
+
}
|
|
401
|
+
|
|
83
402
|
#pragma mark - RCTComponentViewProtocol
|
|
84
403
|
|
|
85
404
|
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
@@ -361,11 +680,87 @@ using namespace facebook::react;
|
|
|
361
680
|
self.accessibilityIdentifier = RCTNSStringFromString(newViewProps.testId);
|
|
362
681
|
}
|
|
363
682
|
|
|
683
|
+
#if TARGET_OS_TV
|
|
684
|
+
// `isTVSelectable`
|
|
685
|
+
if (oldViewProps.isTVSelectable != newViewProps.isTVSelectable) {
|
|
686
|
+
if (newViewProps.isTVSelectable) {
|
|
687
|
+
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
|
|
688
|
+
action:@selector(handleSelect:)];
|
|
689
|
+
recognizer.allowedPressTypes = @[ @(UIPressTypeSelect) ];
|
|
690
|
+
_selectRecognizer = recognizer;
|
|
691
|
+
[self addGestureRecognizer:_selectRecognizer];
|
|
692
|
+
} else {
|
|
693
|
+
if (_selectRecognizer) {
|
|
694
|
+
[self removeGestureRecognizer:_selectRecognizer];
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
// `tvParallaxProperties
|
|
699
|
+
if (oldViewProps.tvParallaxProperties != newViewProps.tvParallaxProperties) {
|
|
700
|
+
_tvParallaxProperties.enabled = newViewProps.tvParallaxProperties.enabled.has_value() ?
|
|
701
|
+
newViewProps.tvParallaxProperties.enabled.value() :
|
|
702
|
+
newViewProps.isTVSelectable;
|
|
703
|
+
_tvParallaxProperties.shiftDistanceX = [self getFloat:newViewProps.tvParallaxProperties.shiftDistanceX orDefault:2.0];
|
|
704
|
+
_tvParallaxProperties.shiftDistanceY = [self getFloat:newViewProps.tvParallaxProperties.shiftDistanceY orDefault:2.0];
|
|
705
|
+
_tvParallaxProperties.tiltAngle = [self getFloat:newViewProps.tvParallaxProperties.tiltAngle orDefault:0.05];
|
|
706
|
+
_tvParallaxProperties.magnification = [self getFloat:newViewProps.tvParallaxProperties.magnification orDefault:1.0];
|
|
707
|
+
_tvParallaxProperties.pressMagnification = [self getFloat:newViewProps.tvParallaxProperties.pressMagnification orDefault:1.0];
|
|
708
|
+
_tvParallaxProperties.pressDuration = [self getFloat:newViewProps.tvParallaxProperties.pressDuration orDefault:0.3];
|
|
709
|
+
_tvParallaxProperties.pressDelay = [self getFloat:newViewProps.tvParallaxProperties.pressDelay orDefault:0.0];
|
|
710
|
+
}
|
|
711
|
+
// `hasTVPreferredFocus
|
|
712
|
+
if (oldViewProps.hasTVPreferredFocus != newViewProps.hasTVPreferredFocus) {
|
|
713
|
+
_hasTVPreferredFocus = newViewProps.hasTVPreferredFocus;
|
|
714
|
+
}
|
|
715
|
+
// `nextFocusUp`
|
|
716
|
+
if (oldViewProps.nextFocusUp != newViewProps.nextFocusUp) {
|
|
717
|
+
if (newViewProps.nextFocusUp.has_value()) {
|
|
718
|
+
UIView *rootView = [self containingRootView];
|
|
719
|
+
_nextFocusUp = [rootView viewWithTag:newViewProps.nextFocusUp.value()];
|
|
720
|
+
} else {
|
|
721
|
+
_nextFocusUp = nil;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
// `nextFocusDown`
|
|
725
|
+
if (oldViewProps.nextFocusDown != newViewProps.nextFocusDown) {
|
|
726
|
+
if (newViewProps.nextFocusDown.has_value()) {
|
|
727
|
+
UIView *rootView = [self containingRootView];
|
|
728
|
+
_nextFocusDown = [rootView viewWithTag:newViewProps.nextFocusDown.value()];
|
|
729
|
+
} else {
|
|
730
|
+
_nextFocusDown = nil;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
// `nextFocusLeft`
|
|
734
|
+
if (oldViewProps.nextFocusLeft != newViewProps.nextFocusLeft) {
|
|
735
|
+
if (newViewProps.nextFocusLeft.has_value()) {
|
|
736
|
+
UIView *rootView = [self containingRootView];
|
|
737
|
+
_nextFocusLeft = [rootView viewWithTag:newViewProps.nextFocusLeft.value()];
|
|
738
|
+
} else {
|
|
739
|
+
_nextFocusLeft = nil;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
// `nextFocusRight`
|
|
743
|
+
if (oldViewProps.nextFocusRight != newViewProps.nextFocusRight) {
|
|
744
|
+
if (newViewProps.nextFocusRight.has_value()) {
|
|
745
|
+
UIView *rootView = [self containingRootView];
|
|
746
|
+
_nextFocusRight = [rootView viewWithTag:newViewProps.nextFocusRight.value()];
|
|
747
|
+
} else {
|
|
748
|
+
_nextFocusRight = nil;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
#endif
|
|
752
|
+
|
|
753
|
+
|
|
364
754
|
_needsInvalidateLayer = _needsInvalidateLayer || needsInvalidateLayer;
|
|
365
755
|
|
|
366
756
|
_props = std::static_pointer_cast<ViewProps const>(props);
|
|
367
757
|
}
|
|
368
758
|
|
|
759
|
+
- (float)getFloat:(better::optional<float>)property orDefault:(float)defaultValue
|
|
760
|
+
{
|
|
761
|
+
return property.has_value() ? (float)property.value() : defaultValue;
|
|
762
|
+
}
|
|
763
|
+
|
|
369
764
|
- (void)updateEventEmitter:(EventEmitter::Shared const &)eventEmitter
|
|
370
765
|
{
|
|
371
766
|
assert(std::dynamic_pointer_cast<ViewEventEmitter const>(eventEmitter));
|
|
@@ -389,6 +784,25 @@ using namespace facebook::react;
|
|
|
389
784
|
if (_contentView) {
|
|
390
785
|
_contentView.frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
|
|
391
786
|
}
|
|
787
|
+
|
|
788
|
+
#if TARGET_OS_TV
|
|
789
|
+
[self.focusGuide.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
|
|
790
|
+
[self.focusGuide.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES;
|
|
791
|
+
[self.focusGuide.widthAnchor constraintEqualToAnchor:self.widthAnchor].active = YES;
|
|
792
|
+
[self.focusGuide.heightAnchor constraintEqualToAnchor:self.heightAnchor].active = YES;
|
|
793
|
+
|
|
794
|
+
if (_hasTVPreferredFocus) {
|
|
795
|
+
RCTRootComponentView *rootview = [self containingRootView];
|
|
796
|
+
if (rootview != nil && rootview.reactPreferredFocusedView != self) {
|
|
797
|
+
rootview.reactPreferredFocusedView = self;
|
|
798
|
+
[rootview setNeedsFocusUpdate];
|
|
799
|
+
[rootview updateFocusIfNeeded];
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
#endif
|
|
804
|
+
|
|
805
|
+
|
|
392
806
|
}
|
|
393
807
|
|
|
394
808
|
- (BOOL)isJSResponder
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
#import "RCTFabricComponentsPlugins.h"
|
|
31
31
|
#import "RCTImageComponentView.h"
|
|
32
32
|
#import "RCTLegacyViewManagerInteropComponentView.h"
|
|
33
|
+
#import "RCTModalHostViewComponentView.h"
|
|
33
34
|
#import "RCTMountingTransactionObserving.h"
|
|
34
35
|
#import "RCTParagraphComponentView.h"
|
|
35
36
|
#import "RCTRootComponentView.h"
|
|
@@ -73,6 +74,7 @@ static Class<RCTComponentViewProtocol> RCTComponentViewClassWithName(const char
|
|
|
73
74
|
[componentViewFactory registerComponentViewClass:[RCTViewComponentView class]];
|
|
74
75
|
[componentViewFactory registerComponentViewClass:[RCTParagraphComponentView class]];
|
|
75
76
|
[componentViewFactory registerComponentViewClass:[RCTTextInputComponentView class]];
|
|
77
|
+
[componentViewFactory registerComponentViewClass:[RCTModalHostViewComponentView class]];
|
|
76
78
|
|
|
77
79
|
Class<RCTComponentViewProtocol> imageClass = RCTComponentViewClassWithName("Image");
|
|
78
80
|
[componentViewFactory registerComponentViewClass:imageClass];
|
package/React/Views/RCTTVView.h
CHANGED
package/React/Views/RCTTVView.m
CHANGED
|
@@ -375,4 +375,20 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused)
|
|
|
375
375
|
}
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
+
- (void)addFocusGuide:(NSArray*)destinations {
|
|
379
|
+
|
|
380
|
+
UIView *origin = [self reactSuperview];
|
|
381
|
+
if (self.focusGuide == nil && origin != nil) {
|
|
382
|
+
self.focusGuide = [UIFocusGuide new];
|
|
383
|
+
[self addLayoutGuide:self.focusGuide];
|
|
384
|
+
|
|
385
|
+
[self.focusGuide.widthAnchor constraintEqualToAnchor:origin.widthAnchor].active = YES;
|
|
386
|
+
[self.focusGuide.heightAnchor constraintEqualToAnchor:origin.heightAnchor].active = YES;
|
|
387
|
+
[self.focusGuide.topAnchor constraintEqualToAnchor:origin.topAnchor].active = YES;
|
|
388
|
+
[self.focusGuide.leftAnchor constraintEqualToAnchor:origin.leftAnchor].active = YES;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
self.focusGuide.preferredFocusEnvironments = destinations;
|
|
392
|
+
}
|
|
393
|
+
|
|
378
394
|
@end
|
|
@@ -435,4 +435,21 @@ RCT_EXPORT_SHADOW_PROPERTY(onLayout, RCTDirectEventBlock)
|
|
|
435
435
|
|
|
436
436
|
RCT_EXPORT_SHADOW_PROPERTY(direction, YGDirection)
|
|
437
437
|
|
|
438
|
+
#if TARGET_OS_TV
|
|
439
|
+
RCT_EXPORT_METHOD(setDestinations : (nonnull NSNumber *)viewTag reactTags : (NSArray<NSNumber *> *)destinationTags)
|
|
440
|
+
{
|
|
441
|
+
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
442
|
+
RCTTVView *view = (RCTTVView *)viewRegistry[viewTag];
|
|
443
|
+
NSMutableArray* destinations = [NSMutableArray array];
|
|
444
|
+
for (NSNumber * tag in destinationTags) {
|
|
445
|
+
RCTTVView *destination = (RCTTVView*)viewRegistry[tag];
|
|
446
|
+
if (destination != nil) {
|
|
447
|
+
[destinations addObject:destination];
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
[view addFocusGuide:destinations];
|
|
451
|
+
}];
|
|
452
|
+
}
|
|
453
|
+
#endif
|
|
454
|
+
|
|
438
455
|
@end
|