From d368ebfab2c389cc093f6a73e5c1021408cc6a73 Mon Sep 17 00:00:00 2001 From: Douglas Lowder Date: Tue, 27 Sep 2016 06:19:45 -0700 Subject: [PATCH] Apple TV support 1: existing Objective C code should compile for tvOS Summary: First commit for Apple TV support: changes to existing Objective-C code so that it will compile correctly for tvOS. Closes https://github.com/facebook/react-native/pull/9649 Differential Revision: D3916021 Pulled By: javache fbshipit-source-id: 34acc9daf3efff835ffe38c43ba5d4098a02c830 --- Examples/UIExplorer/UIExplorer/AppDelegate.m | 6 ++ .../FlexibleSizeExampleView.m | 2 + .../UIExplorerUnitTests/RCTFontTests.m | 4 ++ Libraries/Text/RCTTextView.m | 8 ++- Libraries/WebSocket/RCTWebSocketExecutor.m | 5 +- React/Base/RCTConvert.h | 4 ++ React/Base/RCTConvert.m | 4 ++ React/Base/RCTUtils.h | 8 --- React/Base/RCTUtils.m | 25 ------- React/Modules/RCTAlertManager.h | 8 +++ React/Modules/RCTAlertManager.m | 71 +++++------------- React/Modules/RCTAsyncLocalStorage.m | 8 +++ React/Modules/RCTDevLoadingView.m | 5 +- React/Modules/RCTDevMenu.m | 72 ++++++++----------- React/Modules/RCTKeyboardObserver.m | 8 +++ React/Modules/RCTRedBox.m | 5 +- React/Modules/RCTUIManager.m | 15 +++- React/Profiler/RCTProfile.m | 4 ++ React/Views/RCTComponentData.m | 2 + React/Views/RCTMapManager.m | 4 ++ React/Views/RCTModalHostView.m | 8 +++ React/Views/RCTModalHostViewController.h | 2 + React/Views/RCTModalHostViewController.m | 6 ++ React/Views/RCTNavigator.m | 13 +++- React/Views/RCTProgressViewManager.m | 2 + React/Views/RCTScrollView.m | 24 ++++++- React/Views/RCTTabBar.m | 6 ++ React/Views/RCTTabBarItem.m | 8 ++- React/Views/RCTWrapperViewController.m | 2 + 29 files changed, 197 insertions(+), 142 deletions(-) diff --git a/Examples/UIExplorer/UIExplorer/AppDelegate.m b/Examples/UIExplorer/UIExplorer/AppDelegate.m index 7ca8e039d..d56ac42a7 100644 --- a/Examples/UIExplorer/UIExplorer/AppDelegate.m +++ b/Examples/UIExplorer/UIExplorer/AppDelegate.m @@ -19,7 +19,9 @@ #import "RCTJavaScriptLoader.h" #import "RCTLinkingManager.h" #import "RCTRootView.h" +#if !TARGET_OS_TV #import "RCTPushNotificationManager.h" +#endif @interface AppDelegate() @@ -79,6 +81,8 @@ # pragma mark - Push Notifications +#if !TARGET_OS_TV + // Required to register for notifications - (void)application:(__unused UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { @@ -109,4 +113,6 @@ [RCTPushNotificationManager didReceiveLocalNotification:notification]; } +#endif + @end diff --git a/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m b/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m index 0465a14f6..c96e5798b 100644 --- a/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m +++ b/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m @@ -64,7 +64,9 @@ RCT_EXPORT_MODULE(); [_resizableRootView setSizeFlexibility:RCTRootViewSizeFlexibilityHeight]; _currentSizeTextView = [UITextView new]; +#ifndef TARGET_OS_TV _currentSizeTextView.editable = NO; +#endif _currentSizeTextView.text = @"Resizable view has not been resized yet"; _currentSizeTextView.textColor = [UIColor blackColor]; _currentSizeTextView.backgroundColor = [UIColor whiteColor]; diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTFontTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTFontTests.m index 749c18123..8ab997e8a 100644 --- a/Examples/UIExplorer/UIExplorerUnitTests/RCTFontTests.m +++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTFontTests.m @@ -63,11 +63,13 @@ - (void)testFamily { +#if !TARGET_OS_TV { UIFont *expected = [UIFont fontWithName:@"Cochin" size:14]; UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Cochin"}]; RCTAssertEqualFonts(expected, result); } +#endif { UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:14]; UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Helvetica Neue"}]; @@ -135,6 +137,7 @@ UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"HelveticaNeue-Bold", @"fontWeight": @"normal"}]; RCTAssertEqualFonts(expected, result); } +#if !TARGET_OS_TV { UIFont *expected = [UIFont fontWithName:@"Cochin-Bold" size:14]; UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Cochin", @"fontWeight": @"700"}]; @@ -145,6 +148,7 @@ UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Cochin", @"fontWeight": @"100"}]; RCTAssertEqualFonts(expected, result); } +#endif } - (void)testFamilyAndStyle diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m index 1125084b2..2b917492d 100644 --- a/Libraries/Text/RCTTextView.m +++ b/Libraries/Text/RCTTextView.m @@ -96,12 +96,16 @@ _textView = [[RCTUITextView alloc] initWithFrame:CGRectZero]; _textView.backgroundColor = [UIColor clearColor]; _textView.textColor = [UIColor blackColor]; +#if !TARGET_OS_TV _textView.scrollsToTop = NO; +#endif _textView.scrollEnabled = NO; _textView.delegate = self; _scrollView = [[UIScrollView alloc] initWithFrame:CGRectZero]; +#if !TARGET_OS_TV _scrollView.scrollsToTop = NO; +#endif [_scrollView addSubview:_textView]; [self addSubview:_scrollView]; @@ -283,11 +287,13 @@ static NSAttributedString *removeReactTagFromString(NSAttributedString *string) if (_placeholder) { _placeholderView = [[UITextView alloc] initWithFrame:self.bounds]; - _placeholderView.editable = NO; _placeholderView.userInteractionEnabled = NO; _placeholderView.backgroundColor = [UIColor clearColor]; _placeholderView.scrollEnabled = NO; +#if !TARGET_OS_TV + _placeholderView.editable = NO; _placeholderView.scrollsToTop = NO; +#endif _placeholderView.attributedText = [[NSAttributedString alloc] initWithString:_placeholder attributes:@{ NSFontAttributeName : (_textView.font ? _textView.font : [self defaultPlaceholderFont]), diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.m b/Libraries/WebSocket/RCTWebSocketExecutor.m index ccf7e6db3..64f3a174a 100644 --- a/Libraries/WebSocket/RCTWebSocketExecutor.m +++ b/Libraries/WebSocket/RCTWebSocketExecutor.m @@ -70,8 +70,11 @@ RCT_EXPORT_MODULE() [_socket setDelegateDispatchQueue:_jsQueue]; NSURL *startDevToolsURL = [NSURL URLWithString:@"/launch-js-devtools" relativeToURL:_url]; - [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] delegate:nil]; + NSURLSession *session = [NSURLSession sharedSession]; + NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] + completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){}]; + [dataTask resume]; if (![self connectToProxy]) { RCTLogError(@"Connection to %@ timed out. Are you running node proxy? If " "you are running on the device, check if you have the right IP " diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index 1dc204328..3a062eeff 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -72,10 +72,14 @@ typedef NSURL RCTFileURL; + (UIKeyboardType)UIKeyboardType:(id)json; + (UIKeyboardAppearance)UIKeyboardAppearance:(id)json; + (UIReturnKeyType)UIReturnKeyType:(id)json; +#if !TARGET_OS_TV + (UIDataDetectorTypes)UIDataDetectorTypes:(id)json; +#endif + (UIViewContentMode)UIViewContentMode:(id)json; +#if !TARGET_OS_TV + (UIBarStyle)UIBarStyle:(id)json; +#endif + (CGFloat)CGFloat:(id)json; + (CGPoint)CGPoint:(id)json; diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index 6b1997605..3c36ec604 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -330,6 +330,7 @@ RCT_ENUM_CONVERTER(UIKeyboardType, (@{ @"numeric": @(UIKeyboardTypeDecimalPad), }), UIKeyboardTypeDefault, integerValue) +#if !TARGET_OS_TV RCT_MULTI_ENUM_CONVERTER(UIDataDetectorTypes, (@{ @"phoneNumber": @(UIDataDetectorTypePhoneNumber), @"link": @(UIDataDetectorTypeLink), @@ -338,6 +339,7 @@ RCT_MULTI_ENUM_CONVERTER(UIDataDetectorTypes, (@{ @"none": @(UIDataDetectorTypeNone), @"all": @(UIDataDetectorTypeAll), }), UIDataDetectorTypePhoneNumber, unsignedLongLongValue) +#endif RCT_ENUM_CONVERTER(UIKeyboardAppearance, (@{ @"default": @(UIKeyboardAppearanceDefault), @@ -379,10 +381,12 @@ RCT_ENUM_CONVERTER(UIViewContentMode, (@{ @"stretch": @(UIViewContentModeScaleToFill), }), UIViewContentModeScaleAspectFill, integerValue) +#if !TARGET_OS_TV RCT_ENUM_CONVERTER(UIBarStyle, (@{ @"default": @(UIBarStyleDefault), @"black": @(UIBarStyleBlack), }), UIBarStyleDefault, integerValue) +#endif // TODO: normalise the use of w/width so we can do away with the alias values (#6566645) static void RCTConvertCGStructValue(const char *type, NSArray *fields, NSDictionary *aliases, CGFloat *result, id json) diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h index 30f2f4ae3..0a14ef34f 100644 --- a/React/Base/RCTUtils.h +++ b/React/Base/RCTUtils.h @@ -92,14 +92,6 @@ RCT_EXTERN UIViewController *__nullable RCTPresentedViewController(void); // Does this device support force touch (aka 3D Touch)? RCT_EXTERN BOOL RCTForceTouchAvailable(void); -// Return a UIAlertView initialized with the given values -// or nil if running in an app extension -RCT_EXTERN UIAlertView *__nullable RCTAlertView(NSString *title, - NSString *__nullable message, - id __nullable delegate, - NSString *__nullable cancelButtonTitle, - NSArray *__nullable otherButtonTitles); - // Create an NSError in the RCTErrorDomain RCT_EXTERN NSError *RCTErrorWithMessage(NSString *message); diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m index 2241a65d8..ff50a6479 100644 --- a/React/Base/RCTUtils.m +++ b/React/Base/RCTUtils.m @@ -493,31 +493,6 @@ BOOL RCTForceTouchAvailable(void) (RCTKeyWindow() ?: [UIView new]).traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable; } -UIAlertView *__nullable RCTAlertView(NSString *title, - NSString *__nullable message, - id __nullable delegate, - NSString *__nullable cancelButtonTitle, - NSArray *__nullable otherButtonTitles) -{ - if (RCTRunningInAppExtension()) { - RCTLogError(@"RCTAlertView is unavailable when running in an app extension"); - return nil; - } - - UIAlertView *alertView = [UIAlertView new]; - alertView.title = title; - alertView.message = message; - alertView.delegate = delegate; - if (cancelButtonTitle != nil) { - [alertView addButtonWithTitle:cancelButtonTitle]; - alertView.cancelButtonIndex = 0; - } - for (NSString *buttonTitle in otherButtonTitles) { - [alertView addButtonWithTitle:buttonTitle]; - } - return alertView; -} - NSError *RCTErrorWithMessage(NSString *message) { NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: message}; diff --git a/React/Modules/RCTAlertManager.h b/React/Modules/RCTAlertManager.h index 156531e39..e4247602c 100644 --- a/React/Modules/RCTAlertManager.h +++ b/React/Modules/RCTAlertManager.h @@ -12,6 +12,14 @@ #import "RCTBridgeModule.h" #import "RCTInvalidating.h" +typedef NS_ENUM(NSInteger, RCTAlertViewStyle) { + RCTAlertViewStyleDefault = 0, + RCTAlertViewStyleSecureTextInput, + RCTAlertViewStylePlainTextInput, + RCTAlertViewStyleLoginAndPasswordInput +}; + + @interface RCTAlertManager : NSObject @end diff --git a/React/Modules/RCTAlertManager.m b/React/Modules/RCTAlertManager.m index ac5338e6b..5a7c8abc5 100644 --- a/React/Modules/RCTAlertManager.m +++ b/React/Modules/RCTAlertManager.m @@ -16,22 +16,21 @@ @implementation RCTConvert (UIAlertViewStyle) -RCT_ENUM_CONVERTER(UIAlertViewStyle, (@{ - @"default": @(UIAlertViewStyleDefault), - @"secure-text": @(UIAlertViewStyleSecureTextInput), - @"plain-text": @(UIAlertViewStylePlainTextInput), - @"login-password": @(UIAlertViewStyleLoginAndPasswordInput), -}), UIAlertViewStyleDefault, integerValue) +RCT_ENUM_CONVERTER(RCTAlertViewStyle, (@{ + @"default": @(RCTAlertViewStyleDefault), + @"secure-text": @(RCTAlertViewStyleSecureTextInput), + @"plain-text": @(RCTAlertViewStylePlainTextInput), + @"login-password": @(RCTAlertViewStyleLoginAndPasswordInput), +}), RCTAlertViewStyleDefault, integerValue) @end -@interface RCTAlertManager() +@interface RCTAlertManager() @end @implementation RCTAlertManager { - NSMutableArray *_alerts; NSMutableArray *_alertControllers; NSMutableArray *_alertCallbacks; NSMutableArray *> *_alertButtonKeys; @@ -46,9 +45,6 @@ RCT_EXPORT_MODULE() - (void)invalidate { - for (UIAlertView *alert in _alerts) { - [alert dismissWithClickedButtonIndex:0 animated:YES]; - } for (UIAlertController *alertController in _alertControllers) { [alertController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; } @@ -73,7 +69,7 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args { NSString *title = [RCTConvert NSString:args[@"title"]]; NSString *message = [RCTConvert NSString:args[@"message"]]; - UIAlertViewStyle type = [RCTConvert UIAlertViewStyle:args[@"type"]]; + RCTAlertViewStyle type = [RCTConvert RCTAlertViewStyle:args[@"type"]]; NSArray *buttons = [RCTConvert NSDictionaryArray:args[@"buttons"]]; NSString *defaultValue = [RCTConvert NSString:args[@"defaultValue"]]; NSString *cancelButtonKey = [RCTConvert NSString:args[@"cancelButtonKey"]]; @@ -85,7 +81,7 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args } if (buttons.count == 0) { - if (type == UIAlertViewStyleDefault) { + if (type == RCTAlertViewStyleDefault) { buttons = @[@{@"0": RCTUIKitLocalizedString(@"OK")}]; cancelButtonKey = @"0"; } else { @@ -108,14 +104,14 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args message:nil preferredStyle:UIAlertControllerStyleAlert]; switch (type) { - case UIAlertViewStylePlainTextInput: { + case RCTAlertViewStylePlainTextInput: { [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.secureTextEntry = NO; textField.text = defaultValue; }]; break; } - case UIAlertViewStyleSecureTextInput: { + case RCTAlertViewStyleSecureTextInput: { [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.placeholder = RCTUIKitLocalizedString(@"Password"); textField.secureTextEntry = YES; @@ -123,7 +119,7 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args }]; break; } - case UIAlertViewStyleLoginAndPasswordInput: { + case RCTAlertViewStyleLoginAndPasswordInput: { [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.placeholder = RCTUIKitLocalizedString(@"Login"); textField.text = defaultValue; @@ -134,7 +130,7 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args }]; break; } - case UIAlertViewStyleDefault: + case RCTAlertViewStyleDefault: break; } @@ -156,11 +152,11 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args style:buttonStyle handler:^(__unused UIAlertAction *action) { switch (type) { - case UIAlertViewStylePlainTextInput: - case UIAlertViewStyleSecureTextInput: + case RCTAlertViewStylePlainTextInput: + case RCTAlertViewStyleSecureTextInput: callback(@[buttonKey, [alertController.textFields.firstObject text]]); break; - case UIAlertViewStyleLoginAndPasswordInput: { + case RCTAlertViewStyleLoginAndPasswordInput: { NSDictionary *loginCredentials = @{ @"login": [alertController.textFields.firstObject text], @"password": [alertController.textFields.lastObject text] @@ -168,7 +164,7 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args callback(@[buttonKey, loginCredentials]); break; } - case UIAlertViewStyleDefault: + case RCTAlertViewStyleDefault: callback(@[buttonKey]); break; } @@ -183,37 +179,4 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args [presentingController presentViewController:alertController animated:YES completion:nil]; } -#pragma mark - UIAlertViewDelegate - -- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex -{ - NSUInteger index = [_alerts indexOfObject:alertView]; - RCTAssert(index != NSNotFound, @"Dismissed alert was not recognised"); - - RCTResponseSenderBlock callback = _alertCallbacks[index]; - NSArray *buttonKeys = _alertButtonKeys[index]; - - switch (alertView.alertViewStyle) { - case UIAlertViewStylePlainTextInput: - case UIAlertViewStyleSecureTextInput: - callback(@[buttonKeys[buttonIndex], [alertView textFieldAtIndex:0].text]); - break; - case UIAlertViewStyleLoginAndPasswordInput: { - NSDictionary *loginCredentials = @{ - @"login": [alertView textFieldAtIndex:0].text, - @"password": [alertView textFieldAtIndex:1].text, - }; - callback(@[buttonKeys[buttonIndex], loginCredentials]); - break; - } - case UIAlertViewStyleDefault: - callback(@[buttonKeys[buttonIndex]]); - break; - } - - [_alerts removeObjectAtIndex:index]; - [_alertCallbacks removeObjectAtIndex:index]; - [_alertButtonKeys removeObjectAtIndex:index]; -} - @end diff --git a/React/Modules/RCTAsyncLocalStorage.m b/React/Modules/RCTAsyncLocalStorage.m index 6d150d076..e3972229e 100644 --- a/React/Modules/RCTAsyncLocalStorage.m +++ b/React/Modules/RCTAsyncLocalStorage.m @@ -67,7 +67,11 @@ static NSString *RCTGetStorageDirectory() static NSString *storageDirectory = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ +#if TARGET_OS_TV + storageDirectory = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; +#else storageDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; +#endif storageDirectory = [storageDirectory stringByAppendingPathComponent:RCTStorageDirectory]; }); return storageDirectory; @@ -214,6 +218,10 @@ RCT_EXPORT_MODULE() { RCTAssertThread(RCTGetMethodQueue(), @"Must be executed on storage thread"); +#if TARGET_OS_TV + RCTLogWarn(@"Persistent storage is not supported on tvOS, your data may be removed at any point.") +#endif + NSError *error = nil; if (!RCTHasCreatedStorageDirectory) { [[NSFileManager defaultManager] createDirectoryAtPath:RCTGetStorageDirectory() diff --git a/React/Modules/RCTDevLoadingView.m b/React/Modules/RCTDevLoadingView.m index f485124e9..0b7ee4996 100644 --- a/React/Modules/RCTDevLoadingView.m +++ b/React/Modules/RCTDevLoadingView.m @@ -76,8 +76,11 @@ RCT_EXPORT_METHOD(showMessage:(NSString *)message color:(UIColor *)color backgro if (!self->_window && !RCTRunningInTestEnvironment()) { CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width; self->_window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, screenWidth, 22)]; +#if TARGET_OS_TV + self->_window.windowLevel = UIWindowLevelNormal + 1; +#else self->_window.windowLevel = UIWindowLevelStatusBar + 1; - +#endif // set a root VC so rotation is supported self->_window.rootViewController = [UIViewController new]; diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m index 889ba847a..42fa68a6c 100644 --- a/React/Modules/RCTDevMenu.m +++ b/React/Modules/RCTDevMenu.m @@ -120,7 +120,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) @end -@interface RCTDevMenu () +@interface RCTDevMenu () @property (nonatomic, strong) Class executorClass; @@ -128,7 +128,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) @implementation RCTDevMenu { - UIActionSheet *_actionSheet; + UIAlertController *_actionSheet; NSUserDefaults *_defaults; NSMutableDictionary *_settings; NSURLSessionDataTask *_updateTask; @@ -409,7 +409,7 @@ RCT_EXPORT_MODULE() { _presentedItems = nil; [_updateTask cancel]; - [_actionSheet dismissWithClickedButtonIndex:_actionSheet.cancelButtonIndex animated:YES]; + [_actionSheet dismissViewControllerAnimated:YES completion:^(void){}]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } @@ -423,7 +423,7 @@ RCT_EXPORT_MODULE() - (void)toggle { if (_actionSheet) { - [_actionSheet dismissWithClickedButtonIndex:_actionSheet.cancelButtonIndex animated:YES]; + [_actionSheet dismissViewControllerAnimated:YES completion:^(void){}]; _actionSheet = nil; } else { [self show]; @@ -458,13 +458,11 @@ RCT_EXPORT_MODULE() Class jsDebuggingExecutorClass = objc_lookUpClass("RCTWebSocketExecutor"); if (!jsDebuggingExecutorClass) { [items addObject:[RCTDevMenuItem buttonItemWithTitle:[NSString stringWithFormat:@"%@ Debugger Unavailable", _webSocketExecutorName] handler:^{ - UIAlertView *alert = RCTAlertView( - [NSString stringWithFormat:@"%@ Debugger Unavailable", self->_webSocketExecutorName], - [NSString stringWithFormat:@"You need to include the RCTWebSocket library to enable %@ debugging", self->_webSocketExecutorName], - nil, - @"OK", - nil); - [alert show]; + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"%@ Debugger Unavailable", self->_webSocketExecutorName] + message:[NSString stringWithFormat:@"You need to include the RCTWebSocket library to enable %@ debugging", self->_webSocketExecutorName] + preferredStyle:UIAlertControllerStyleAlert]; + + [RCTPresentedViewController() presentViewController:alertController animated:YES completion:NULL]; }]]; } else { BOOL isDebuggingJS = _executorClass && _executorClass == jsDebuggingExecutorClass; @@ -514,55 +512,45 @@ RCT_EXPORT_METHOD(show) return; } - UIActionSheet *actionSheet = [UIActionSheet new]; - actionSheet.title = @"React Native: Development"; - actionSheet.delegate = self; - + _actionSheet = [UIAlertController alertControllerWithTitle:@"React Native: Development" + message:@"" + preferredStyle:UIAlertControllerStyleActionSheet]; NSArray *items = [self menuItems]; for (RCTDevMenuItem *item in items) { switch (item.type) { case RCTDevMenuTypeButton: { - [actionSheet addButtonWithTitle:item.title]; + [_actionSheet addAction:[UIAlertAction actionWithTitle:item.title + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) { + // Cancel button tappped. + [item callHandler]; + }]]; break; } case RCTDevMenuTypeToggle: { BOOL selected = [item.value boolValue]; - [actionSheet addButtonWithTitle:selected? item.selectedTitle : item.title]; + [_actionSheet addAction:[UIAlertAction actionWithTitle:(selected? item.selectedTitle : item.title) + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) { + BOOL value = [self->_settings[item.key] boolValue]; + [self updateSetting:item.key value:@(!value)]; // will call handler + }]]; + break; } } } - [actionSheet addButtonWithTitle:@"Cancel"]; - actionSheet.cancelButtonIndex = actionSheet.numberOfButtons - 1; + [_actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" + style:UIAlertActionStyleCancel + handler:^(UIAlertAction *action) { + }]]; - actionSheet.actionSheetStyle = UIBarStyleBlack; - [actionSheet showInView:RCTKeyWindow().rootViewController.view]; - _actionSheet = actionSheet; _presentedItems = items; + [RCTPresentedViewController() presentViewController:_actionSheet animated:YES completion:^(void){}]; } -- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex -{ - _actionSheet = nil; - if (buttonIndex == actionSheet.cancelButtonIndex) { - return; - } - RCTDevMenuItem *item = _presentedItems[buttonIndex]; - switch (item.type) { - case RCTDevMenuTypeButton: { - [item callHandler]; - break; - } - case RCTDevMenuTypeToggle: { - BOOL value = [_settings[item.key] boolValue]; - [self updateSetting:item.key value:@(!value)]; // will call handler - break; - } - } - return; -} RCT_EXPORT_METHOD(reload) { diff --git a/React/Modules/RCTKeyboardObserver.m b/React/Modules/RCTKeyboardObserver.m index d87570b63..84804ca19 100644 --- a/React/Modules/RCTKeyboardObserver.m +++ b/React/Modules/RCTKeyboardObserver.m @@ -19,6 +19,8 @@ RCT_EXPORT_MODULE() - (void)startObserving { +#if !TARGET_OS_TV + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; #define ADD_KEYBOARD_HANDLER(NAME, SELECTOR) \ @@ -33,6 +35,8 @@ RCT_EXPORT_MODULE() #undef ADD_KEYBOARD_HANDLER +#endif + } - (NSArray *)supportedEvents @@ -94,6 +98,9 @@ static NSString *RCTAnimationNameForCurve(UIViewAnimationCurve curve) static NSDictionary *RCTParseKeyboardNotification(NSNotification *notification) { +#if TARGET_OS_TV + return @{}; +#else NSDictionary *userInfo = notification.userInfo; CGRect beginFrame = [userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue]; CGRect endFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; @@ -106,4 +113,5 @@ static NSDictionary *RCTParseKeyboardNotification(NSNotification *notification) @"duration": @(duration * 1000.0), // ms @"easing": RCTAnimationNameForCurve(curve), }; +#endif } diff --git a/React/Modules/RCTRedBox.m b/React/Modules/RCTRedBox.m index 002032e3a..bc46c5b34 100644 --- a/React/Modules/RCTRedBox.m +++ b/React/Modules/RCTRedBox.m @@ -60,8 +60,10 @@ _stackTraceTableView.delegate = self; _stackTraceTableView.dataSource = self; _stackTraceTableView.backgroundColor = [UIColor clearColor]; +#if !TARGET_OS_TV _stackTraceTableView.separatorColor = [UIColor colorWithWhite:1 alpha:0.3]; _stackTraceTableView.separatorStyle = UITableViewCellSeparatorStyleNone; +#endif _stackTraceTableView.indicatorStyle = UIScrollViewIndicatorStyleWhite; [rootView addSubview:_stackTraceTableView]; @@ -175,9 +177,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) [fullStackTrace appendFormat:@" %@\n", [self formatFrameSource:stackFrame]]; } } - +#if !TARGET_OS_TV UIPasteboard *pb = [UIPasteboard generalPasteboard]; [pb setString:fullStackTrace]; +#endif } - (NSString *)formatFrameSource:(RCTJSStackFrame *)stackFrame diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index e8d91ae0c..1e35ca958 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -99,6 +99,7 @@ static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnim // `UIKeyboardWillChangeFrameNotification`s. + (void)initializeStatics { +#if !TARGET_OS_TV static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ [[NSNotificationCenter defaultCenter] addObserver:self @@ -106,12 +107,15 @@ static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnim name:UIKeyboardWillChangeFrameNotification object:nil]; }); +#endif } + (void)keyboardWillChangeFrame:(NSNotification *)notification { +#if !TARGET_OS_TV NSDictionary *userInfo = notification.userInfo; _currentKeyboardAnimationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]; +#endif } - (instancetype)initWithDuration:(NSTimeInterval)duration dictionary:(NSDictionary *)config @@ -225,8 +229,9 @@ static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnim NSDictionary *_componentDataByName; NSMutableSet> *_bridgeTransactionListeners; - +#if !TARGET_OS_TV UIInterfaceOrientation _currentInterfaceOrientation; +#endif } @synthesize bridge = _bridge; @@ -244,6 +249,7 @@ RCT_EXPORT_MODULE() - (void)interfaceOrientationWillChange:(NSNotification *)notification { +#if !TARGET_OS_TV UIInterfaceOrientation nextOrientation = [notification.userInfo[UIApplicationStatusBarOrientationUserInfoKey] integerValue]; @@ -260,6 +266,7 @@ RCT_EXPORT_MODULE() } _currentInterfaceOrientation = nextOrientation; +#endif } - (void)invalidate @@ -339,11 +346,13 @@ RCT_EXPORT_MODULE() selector:@selector(didReceiveNewContentSizeMultiplier) name:RCTAccessibilityManagerDidUpdateMultiplierNotification object:_bridge.accessibilityManager]; - +#if !TARGET_OS_TV [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(interfaceOrientationWillChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil]; +#endif + [RCTAnimation initializeStatics]; } @@ -1510,7 +1519,9 @@ RCT_EXPORT_METHOD(clearJSResponder) allJSConstants[name] = constantsNamespace; }]; +#if !TARGET_OS_TV _currentInterfaceOrientation = [RCTSharedApplication() statusBarOrientation]; +#endif [allJSConstants addEntriesFromDictionary:@{ @"customBubblingEventTypes": bubblingEvents, @"customDirectEventTypes": directEvents, diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m index 6e397397d..4d022ca24 100644 --- a/React/Profiler/RCTProfile.m +++ b/React/Profiler/RCTProfile.m @@ -381,6 +381,7 @@ void RCTProfileUnhookModules(RCTBridge *bridge) atomically:YES encoding:NSUTF8StringEncoding error:nil]; +#if !TARGET_OS_TV UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[[NSURL fileURLWithPath:outFile]] applicationActivities:nil]; activityViewController.completionHandler = ^(__unused NSString *activityType, __unused BOOL completed) { @@ -392,6 +393,7 @@ void RCTProfileUnhookModules(RCTBridge *bridge) animated:YES completion:nil]; }); +#endif }); } else { RCTProfileInit(RCTProfilingBridge()); @@ -753,6 +755,7 @@ void RCTProfileSendResult(RCTBridge *bridge, NSString *route, NSData *data) encoding:NSUTF8StringEncoding]; if (message.length) { +#if !TARGET_OS_TV dispatch_async(dispatch_get_main_queue(), ^{ [[[UIAlertView alloc] initWithTitle:@"Profile" message:message @@ -760,6 +763,7 @@ void RCTProfileSendResult(RCTBridge *bridge, NSString *route, NSData *data) cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; }); +#endif } } }]; diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m index b0d61fe86..e9adeb011 100644 --- a/React/Views/RCTComponentData.m +++ b/React/Views/RCTComponentData.m @@ -104,7 +104,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) UIView *view = [self.manager view]; view.reactTag = tag; +#if !TARGET_OS_TV view.multipleTouchEnabled = YES; +#endif view.userInteractionEnabled = YES; // required for touch handling view.layer.allowsGroupOpacity = YES; // required for touch handling return view; diff --git a/React/Views/RCTMapManager.m b/React/Views/RCTMapManager.m index 102b03d03..78fc2f094 100644 --- a/React/Views/RCTMapManager.m +++ b/React/Views/RCTMapManager.m @@ -149,6 +149,7 @@ RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap) } } +#if !TARGET_OS_TV - (void)mapView:(RCTMap *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState @@ -172,6 +173,7 @@ RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap) } } } +#endif //TARGET_OS_TV - (MKAnnotationView *)mapView:(RCTMap *)mapView viewForAnnotation:(RCTMapAnnotation *)annotation @@ -280,7 +282,9 @@ RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap) } } +#if !TARGET_OS_TV annotationView.draggable = annotation.draggable; +#endif return annotationView; } diff --git a/React/Views/RCTModalHostView.m b/React/Views/RCTModalHostView.m index a7bd40099..e41618161 100644 --- a/React/Views/RCTModalHostView.m +++ b/React/Views/RCTModalHostView.m @@ -25,7 +25,9 @@ RCTModalHostViewController *_modalViewController; RCTTouchHandler *_touchHandler; UIView *_reactSubview; +#if !TARGET_OS_TV UIInterfaceOrientation _lastKnownOrientation; +#endif } RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame) @@ -61,6 +63,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder) - (void)notifyForOrientationChange { +#if !TARGET_OS_TV if (!_onOrientationChange) { return; } @@ -77,6 +80,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder) @"orientation": isPortrait ? @"portrait" : @"landscape", }; _onOrientationChange(eventPayload); +#endif } - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex @@ -119,7 +123,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder) if (!_isPresented && self.window) { RCTAssert(self.reactViewController, @"Can't present modal view controller without a presenting view controller"); +#if !TARGET_OS_TV _modalViewController.supportedInterfaceOrientations = [self supportedOrientationsMask]; +#endif if ([self.animationType isEqualToString:@"fade"]) { _modalViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; } else if ([self.animationType isEqualToString:@"slide"]) { @@ -161,6 +167,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder) _modalViewController.modalPresentationStyle = transparent ? UIModalPresentationOverFullScreen : UIModalPresentationFullScreen; } +#if !TARGET_OS_TV - (UIInterfaceOrientationMask)supportedOrientationsMask { if (_supportedOrientations.count == 0) { @@ -187,5 +194,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder) } return supportedOrientations; } +#endif @end diff --git a/React/Views/RCTModalHostViewController.h b/React/Views/RCTModalHostViewController.h index f0a2e24d7..ebcb0dcd4 100644 --- a/React/Views/RCTModalHostViewController.h +++ b/React/Views/RCTModalHostViewController.h @@ -13,6 +13,8 @@ @property (nonatomic, copy) void (^boundsDidChangeBlock)(CGRect newBounds); +#if !TARGET_OS_TV @property (nonatomic, assign) UIInterfaceOrientationMask supportedInterfaceOrientations; +#endif @end diff --git a/React/Views/RCTModalHostViewController.m b/React/Views/RCTModalHostViewController.m index b50f660e1..73d0342ad 100644 --- a/React/Views/RCTModalHostViewController.m +++ b/React/Views/RCTModalHostViewController.m @@ -15,8 +15,10 @@ @implementation RCTModalHostViewController { CGRect _lastViewFrame; +#if !TARGET_OS_TV UIStatusBarStyle _preferredStatusBarStyle; BOOL _preferredStatusBarHidden; +#endif } - (instancetype)init @@ -25,8 +27,10 @@ return nil; } +#if !TARGET_OS_TV _preferredStatusBarStyle = [[UIApplication sharedApplication] statusBarStyle]; _preferredStatusBarHidden = [[UIApplication sharedApplication] isStatusBarHidden]; +#endif return self; } @@ -41,6 +45,7 @@ } } +#if !TARGET_OS_TV - (UIStatusBarStyle)preferredStatusBarStyle { return _preferredStatusBarStyle; @@ -50,6 +55,7 @@ { return _preferredStatusBarHidden; } +#endif #if RCT_DEV - (UIInterfaceOrientationMask)supportedInterfaceOrientations diff --git a/React/Views/RCTNavigator.m b/React/Views/RCTNavigator.m index ad1270e65..7bfb9f5e7 100644 --- a/React/Views/RCTNavigator.m +++ b/React/Views/RCTNavigator.m @@ -169,6 +169,7 @@ NSInteger kNeverProgressed = -10000; */ - (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item { +#if !TARGET_OS_TV if (self.interactivePopGestureRecognizer.state == UIGestureRecognizerStateBegan) { if (self.navigationLock == RCTNavigationLockNone) { self.navigationLock = RCTNavigationLockNative; @@ -180,7 +181,9 @@ NSInteger kNeverProgressed = -10000; // recognizer when we lock the navigation. RCTAssert(NO, @"Should never receive gesture start while JS locks navigator"); } - } else { + } else +#endif //TARGET_OS_TV + { if (self.navigationLock == RCTNavigationLockNone) { // Must be coming from native interaction, lock it - it will be unlocked // in `didMoveToNavigationController` @@ -348,19 +351,23 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) - (void)setInteractivePopGestureEnabled:(BOOL)interactivePopGestureEnabled { +#if !TARGET_OS_TV _interactivePopGestureEnabled = interactivePopGestureEnabled; _navigationController.interactivePopGestureRecognizer.delegate = self; _navigationController.interactivePopGestureRecognizer.enabled = interactivePopGestureEnabled; _popGestureState = interactivePopGestureEnabled ? RCTPopGestureStateEnabled : RCTPopGestureStateDisabled; +#endif } - (void)dealloc { +#if !TARGET_OS_TV if (_navigationController.interactivePopGestureRecognizer.delegate == self) { _navigationController.interactivePopGestureRecognizer.delegate = nil; } +#endif _navigationController.delegate = nil; [_navigationController removeFromParentViewController]; } @@ -422,7 +429,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) { if (_navigationController.navigationLock == RCTNavigationLockNone) { _navigationController.navigationLock = RCTNavigationLockJavaScript; +#if !TARGET_OS_TV _navigationController.interactivePopGestureRecognizer.enabled = NO; +#endif return YES; } return NO; @@ -435,7 +444,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) // Unless the pop gesture has been explicitly disabled (RCTPopGestureStateDisabled), // Set interactivePopGestureRecognizer.enabled to YES // If the popGestureState is RCTPopGestureStateDefault the default behavior will be maintained +#if !TARGET_OS_TV _navigationController.interactivePopGestureRecognizer.enabled = self.popGestureState != RCTPopGestureStateDisabled; +#endif } /** diff --git a/React/Views/RCTProgressViewManager.m b/React/Views/RCTProgressViewManager.m index 4e8e0d529..65fe2df3c 100644 --- a/React/Views/RCTProgressViewManager.m +++ b/React/Views/RCTProgressViewManager.m @@ -15,7 +15,9 @@ RCT_ENUM_CONVERTER(UIProgressViewStyle, (@{ @"default": @(UIProgressViewStyleDefault), +#if !TARGET_OS_TV @"bar": @(UIProgressViewStyleBar), +#endif }), UIProgressViewStyleDefault, integerValue) @end diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m index f36dc4eea..47c007928 100644 --- a/React/Views/RCTScrollView.m +++ b/React/Views/RCTScrollView.m @@ -14,7 +14,9 @@ #import "RCTConvert.h" #import "RCTEventDispatcher.h" #import "RCTLog.h" +#if !TARGET_OS_TV #import "RCTRefreshControl.h" +#endif #import "RCTUIManager.h" #import "RCTUtils.h" #import "UIView+Private.h" @@ -140,7 +142,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) @property (nonatomic, copy) NSIndexSet *stickyHeaderIndices; @property (nonatomic, assign) BOOL centerContent; +#if !TARGET_OS_TV @property (nonatomic, strong) RCTRefreshControl *rctRefreshControl; +#endif @end @@ -275,9 +279,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) CGFloat scrollTop = self.bounds.origin.y + self.contentInset.top; // If the RefreshControl is refreshing, remove it's height so sticky headers are // positioned properly when scrolling down while refreshing. +#if !TARGET_OS_TV if (_rctRefreshControl != nil && _rctRefreshControl.refreshing) { scrollTop -= _rctRefreshControl.frame.size.height; } +#endif // Find the section headers that need to be docked __block UIView *previousHeader = nil; @@ -358,6 +364,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) return [super hitTest:point withEvent:event]; } +#if !TARGET_OS_TV - (void)setRctRefreshControl:(RCTRefreshControl *)refreshControl { if (_rctRefreshControl) { @@ -366,6 +373,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) _rctRefreshControl = refreshControl; [self addSubview:_rctRefreshControl]; } +#endif //TARGET_OS_TV @end @@ -423,9 +431,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex { [super insertReactSubview:view atIndex:atIndex]; +#if !TARGET_OS_TV if ([view isKindOfClass:[RCTRefreshControl class]]) { [_scrollView setRctRefreshControl:(RCTRefreshControl *)view]; - } else { + } else +#endif + { RCTAssert(_contentView == nil, @"RCTScrollView may only contain a single subview"); _contentView = view; [_scrollView addSubview:view]; @@ -435,9 +446,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) - (void)removeReactSubview:(UIView *)subview { [super removeReactSubview:subview]; +#if !TARGET_OS_TV if ([subview isKindOfClass:[RCTRefreshControl class]]) { [_scrollView setRctRefreshControl:nil]; - } else { + } else +#endif + { RCTAssert(_contentView == subview, @"Attempted to remove non-existent subview"); _contentView = nil; } @@ -491,11 +505,13 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) _scrollView.frame = self.bounds; _scrollView.contentOffset = originalOffset; +#if !TARGET_OS_TV // Adjust the refresh control frame if the scrollview layout changes. RCTRefreshControl *refreshControl = _scrollView.rctRefreshControl; if (refreshControl && refreshControl.refreshing) { refreshControl.frame = (CGRect){_scrollView.contentOffset, {_scrollView.frame.size.width, refreshControl.frame.size.height}}; } +#endif [self updateClippedSubviews]; } @@ -926,9 +942,11 @@ RCT_SET_AND_PRESERVE_OFFSET(setIndicatorStyle, indicatorStyle, UIScrollViewIndic RCT_SET_AND_PRESERVE_OFFSET(setKeyboardDismissMode, keyboardDismissMode, UIScrollViewKeyboardDismissMode) RCT_SET_AND_PRESERVE_OFFSET(setMaximumZoomScale, maximumZoomScale, CGFloat) RCT_SET_AND_PRESERVE_OFFSET(setMinimumZoomScale, minimumZoomScale, CGFloat) -RCT_SET_AND_PRESERVE_OFFSET(setPagingEnabled, isPagingEnabled, BOOL) RCT_SET_AND_PRESERVE_OFFSET(setScrollEnabled, isScrollEnabled, BOOL) +#if !TARGET_OS_TV +RCT_SET_AND_PRESERVE_OFFSET(setPagingEnabled, isPagingEnabled, BOOL) RCT_SET_AND_PRESERVE_OFFSET(setScrollsToTop, scrollsToTop, BOOL) +#endif RCT_SET_AND_PRESERVE_OFFSET(setShowsHorizontalScrollIndicator, showsHorizontalScrollIndicator, BOOL) RCT_SET_AND_PRESERVE_OFFSET(setShowsVerticalScrollIndicator, showsVerticalScrollIndicator, BOOL) RCT_SET_AND_PRESERVE_OFFSET(setZoomScale, zoomScale, CGFloat); diff --git a/React/Views/RCTTabBar.m b/React/Views/RCTTabBar.m index e6cb93a5a..581277a72 100644 --- a/React/Views/RCTTabBar.m +++ b/React/Views/RCTTabBar.m @@ -151,12 +151,18 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) - (UITabBarItemPositioning)itemPositoning { +#if TARGET_OS_TV + return 0; +#else return _tabController.tabBar.itemPositioning; +#endif } - (void)setItemPositioning:(UITabBarItemPositioning)itemPositioning { +#if !TARGET_OS_TV _tabController.tabBar.itemPositioning = itemPositioning; +#endif } #pragma mark - UITabBarControllerDelegate diff --git a/React/Views/RCTTabBarItem.m b/React/Views/RCTTabBarItem.m index fdc0ee52c..0b4a0ca37 100644 --- a/React/Views/RCTTabBarItem.m +++ b/React/Views/RCTTabBarItem.m @@ -32,7 +32,9 @@ RCT_ENUM_CONVERTER(UITabBarSystemItem, (@{ @end -@implementation RCTTabBarItem +@implementation RCTTabBarItem{ + UITapGestureRecognizer *_selectRecognizer; +} @synthesize barItem = _barItem; @@ -84,7 +86,7 @@ RCT_ENUM_CONVERTER(UITabBarSystemItem, (@{ _barItem.selectedImage = oldItem.selectedImage; _barItem.badgeValue = oldItem.badgeValue; } - + if (_renderAsOriginal) { self.barItem.image = [_icon imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; } else { @@ -95,7 +97,7 @@ RCT_ENUM_CONVERTER(UITabBarSystemItem, (@{ - (void)setSelectedIcon:(UIImage *)selectedIcon { _selectedIcon = selectedIcon; - + if (_renderAsOriginal) { self.barItem.selectedImage = [_selectedIcon imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; } else { diff --git a/React/Views/RCTWrapperViewController.m b/React/Views/RCTWrapperViewController.m index 637e726c2..a26dcdfcf 100644 --- a/React/Views/RCTWrapperViewController.m +++ b/React/Views/RCTWrapperViewController.m @@ -124,7 +124,9 @@ static UIView *RCTFindNavBarShadowViewInView(UIView *view) UINavigationItem *item = self.navigationItem; item.title = _navItem.title; item.titleView = _navItem.titleImageView; +#if !TARGET_OS_TV item.backBarButtonItem = _navItem.backButtonItem; +#endif //TARGET_OS_TV item.leftBarButtonItem = _navItem.leftButtonItem; item.rightBarButtonItem = _navItem.rightButtonItem; }