From 7e8c3e241f8a0fddbab91bb348489d4e6b10bb7e Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Mon, 25 Dec 2017 19:38:43 -0500 Subject: [PATCH 01/20] [tvOS] Fixes errors when building against tvOS SDK --- Source/ASMultiplexImageNode.mm | 3 +++ Source/ASTableView.mm | 8 +++++++- Source/Private/TextExperiment/String/ASTextAttribute.m | 2 ++ .../TextExperiment/Utility/NSAttributedString+ASText.h | 2 +- .../TextExperiment/Utility/NSAttributedString+ASText.m | 2 ++ .../TextExperiment/Utility/NSParagraphStyle+ASText.m | 6 +++++- Source/TextKit/ASTextKitCoreTextAdditions.m | 2 ++ Source/tvOS/ASImageNode+tvOS.m | 1 + 8 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Source/ASMultiplexImageNode.mm b/Source/ASMultiplexImageNode.mm index dc689d829..c3a6f3f32 100644 --- a/Source/ASMultiplexImageNode.mm +++ b/Source/ASMultiplexImageNode.mm @@ -16,7 +16,10 @@ // #import + +#if TARGET_OS_TVOS #import +#endif #import #import diff --git a/Source/ASTableView.mm b/Source/ASTableView.mm index 4d9d01f81..999da9de1 100644 --- a/Source/ASTableView.mm +++ b/Source/ASTableView.mm @@ -116,8 +116,9 @@ - (void)setElement:(ASCollectionElement *)element self.backgroundColor = node.backgroundColor; self.selectionStyle = node.selectionStyle; self.selectedBackgroundView = node.selectedBackgroundView; +#if TARGET_OS_IOS self.separatorInset = node.separatorInset; - self.selectionStyle = node.selectionStyle; +#endif self.accessoryType = node.accessoryType; // the following ensures that we clip the entire cell to it's bounds if node.clipsToBounds is set (the default) @@ -918,6 +919,7 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa ASCellNode *node = [_dataController.visibleMap elementForItemAtIndexPath:indexPath].node; CGFloat height = node.calculatedSize.height; +#if TARGET_OS_IOS /** * Weirdly enough, Apple expects the return value here to _include_ the height * of the separator, if there is one! So if our node wants to be 43.5, we need @@ -927,6 +929,8 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa if (tableView.separatorStyle != UITableViewCellSeparatorStyleNone) { height += 1.0 / ASScreenScale(); } +#endif + return height; } @@ -1754,6 +1758,7 @@ - (BOOL)dataController:(ASDataController *)dataController presentedSizeForElemen } CGRect rect = [self rectForRowAtIndexPath:indexPath]; +#if TARGET_OS_IOS /** * Weirdly enough, Apple expects the return value in tableView:heightForRowAtIndexPath: to _include_ the height * of the separator, if there is one! So if rectForRow would return 44.0 we need to use 43.5. @@ -1761,6 +1766,7 @@ - (BOOL)dataController:(ASDataController *)dataController presentedSizeForElemen if (self.separatorStyle != UITableViewCellSeparatorStyleNone) { rect.size.height -= 1.0 / ASScreenScale(); } +#endif return (fabs(rect.size.height - size.height) < FLT_EPSILON); } diff --git a/Source/Private/TextExperiment/String/ASTextAttribute.m b/Source/Private/TextExperiment/String/ASTextAttribute.m index 084bdcf82..c20502156 100755 --- a/Source/Private/TextExperiment/String/ASTextAttribute.m +++ b/Source/Private/TextExperiment/String/ASTextAttribute.m @@ -63,7 +63,9 @@ ASTextAttributeType ASTextAttributeGetType(NSString *name){ dic[(id)kCTSuperscriptAttributeName] = UIKit; //it's a CoreText attrubite, but only supported by UIKit... dic[NSVerticalGlyphFormAttributeName] = All; dic[(id)kCTGlyphInfoAttributeName] = CoreText_ASText; +#if TARGET_OS_IOS dic[(id)kCTCharacterShapeAttributeName] = CoreText_ASText; +#endif dic[(id)kCTRunDelegateAttributeName] = CoreText_ASText; dic[(id)kCTBaselineClassAttributeName] = CoreText_ASText; dic[(id)kCTBaselineInfoAttributeName] = CoreText_ASText; diff --git a/Source/Private/TextExperiment/Utility/NSAttributedString+ASText.h b/Source/Private/TextExperiment/Utility/NSAttributedString+ASText.h index 9fc8ec222..ef4739240 100755 --- a/Source/Private/TextExperiment/Utility/NSAttributedString+ASText.h +++ b/Source/Private/TextExperiment/Utility/NSAttributedString+ASText.h @@ -1270,7 +1270,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)as_setSuperscript:(nullable NSNumber *)superscript range:(NSRange)range; - (void)as_setGlyphInfo:(nullable CTGlyphInfoRef)glyphInfo range:(NSRange)range; -- (void)as_setCharacterShape:(nullable NSNumber *)characterShape range:(NSRange)range; +- (void)as_setCharacterShape:(nullable NSNumber *)characterShape range:(NSRange)range __TVOS_PROHIBITED; - (void)as_setRunDelegate:(nullable CTRunDelegateRef)runDelegate range:(NSRange)range; - (void)as_setBaselineClass:(nullable CFStringRef)baselineClass range:(NSRange)range; - (void)as_setBaselineInfo:(nullable CFDictionaryRef)baselineInfo range:(NSRange)range; diff --git a/Source/Private/TextExperiment/Utility/NSAttributedString+ASText.m b/Source/Private/TextExperiment/Utility/NSAttributedString+ASText.m index d67dd15d2..049bec930 100755 --- a/Source/Private/TextExperiment/Utility/NSAttributedString+ASText.m +++ b/Source/Private/TextExperiment/Utility/NSAttributedString+ASText.m @@ -600,7 +600,9 @@ - (BOOL)as_canDrawWithUIKit { dispatch_once(&onceToken, ^{ failSet = [NSMutableSet new]; [failSet addObject:(id)kCTGlyphInfoAttributeName]; +#if TARGET_OS_IOS [failSet addObject:(id)kCTCharacterShapeAttributeName]; +#endif [failSet addObject:(id)kCTLanguageAttributeName]; [failSet addObject:(id)kCTRunDelegateAttributeName]; [failSet addObject:(id)kCTBaselineClassAttributeName]; diff --git a/Source/Private/TextExperiment/Utility/NSParagraphStyle+ASText.m b/Source/Private/TextExperiment/Utility/NSParagraphStyle+ASText.m index 3401fcc82..e6420cf7a 100755 --- a/Source/Private/TextExperiment/Utility/NSParagraphStyle+ASText.m +++ b/Source/Private/TextExperiment/Utility/NSParagraphStyle+ASText.m @@ -25,6 +25,7 @@ + (NSParagraphStyle *)as_styleWithCTStyle:(CTParagraphStyleRef)CTStyle { NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; +#if TARGET_OS_IOS #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" CGFloat lineSpacing; @@ -32,6 +33,7 @@ + (NSParagraphStyle *)as_styleWithCTStyle:(CTParagraphStyleRef)CTStyle { style.lineSpacing = lineSpacing; } #pragma clang diagnostic pop +#endif CGFloat paragraphSpacing; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierParagraphSpacing, sizeof(CGFloat), ¶graphSpacing)) { @@ -117,7 +119,9 @@ - (CTParagraphStyleRef)as_CTStyle CF_RETURNS_RETAINED { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" CGFloat lineSpacing = self.lineSpacing; - set[count].spec = kCTParagraphStyleSpecifierLineSpacing; +#if TARGET_OS_IOS + set[count].spec = kCTParagraphStyleSpecifierMaximumLineSpacing; +#endif set[count].valueSize = sizeof(CGFloat); set[count].value = &lineSpacing; count++; diff --git a/Source/TextKit/ASTextKitCoreTextAdditions.m b/Source/TextKit/ASTextKitCoreTextAdditions.m index 05935db5c..15fa2529e 100644 --- a/Source/TextKit/ASTextKitCoreTextAdditions.m +++ b/Source/TextKit/ASTextKitCoreTextAdditions.m @@ -228,6 +228,7 @@ + (instancetype)paragraphStyleWithCTParagraphStyle:(CTParagraphStyleRef)coreText if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierMinimumLineHeight, sizeof(minimumLineHeight), &minimumLineHeight)) newParagraphStyle.minimumLineHeight = minimumLineHeight; +#if TARGET_OS_IOS // kCTParagraphStyleSpecifierLineSpacing -> lineSpacing // Note that kCTParagraphStyleSpecifierLineSpacing is deprecated and will die soon. We should not be using it. #pragma clang diagnostic push @@ -236,6 +237,7 @@ + (instancetype)paragraphStyleWithCTParagraphStyle:(CTParagraphStyleRef)coreText if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierLineSpacing, sizeof(lineSpacing), &lineSpacing)) newParagraphStyle.lineSpacing = lineSpacing; #pragma clang diagnostic pop +#endif // kCTParagraphStyleSpecifierParagraphSpacing -> paragraphSpacing CGFloat paragraphSpacing; diff --git a/Source/tvOS/ASImageNode+tvOS.m b/Source/tvOS/ASImageNode+tvOS.m index d3da889c5..51a5d484a 100644 --- a/Source/tvOS/ASImageNode+tvOS.m +++ b/Source/tvOS/ASImageNode+tvOS.m @@ -18,6 +18,7 @@ #import #if TARGET_OS_TV #import +#import #import #import From bd9fd57621817c0d185f5ef1e8f777f90e185379 Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Mon, 25 Dec 2017 19:46:22 -0500 Subject: [PATCH 02/20] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40c83558f..a3828d5dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## master * Add your own contributions to the next release on the line below this with your name. +- [tvOS] Fixes errors when building against tvOS SDK [Alex Hill](https://github.com/alexhillc) [#728](https://github.com/TextureGroup/Texture/pull/728) - [ASNetworkImageNode] Deprecates .URLs in favor of .URL [Garrett Moon](https://github.com/garrettmoon) [#699](https://github.com/TextureGroup/Texture/pull/699) - [iOS11] Update project settings and fix errors [Eke](https://github.com/Eke) [#676](https://github.com/TextureGroup/Texture/pull/676) - [ASCollectionView] Improve performance and behavior of rotation / bounds changes. [Scott Goodson](https://github.com/appleguy) [#431](https://github.com/TextureGroup/Texture/pull/431) From 46f541214afae86bbd7b14e2f1c86eddff5dae58 Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Mon, 25 Dec 2017 21:40:54 -0500 Subject: [PATCH 03/20] [tvOS] Fixes implicit conversion between UIViewAnimationCurve + UIViewAnimationOptions --- Source/tvOS/ASControlNode+tvOS.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/tvOS/ASControlNode+tvOS.m b/Source/tvOS/ASControlNode+tvOS.m index 35acbc045..528b9419b 100644 --- a/Source/tvOS/ASControlNode+tvOS.m +++ b/Source/tvOS/ASControlNode+tvOS.m @@ -25,11 +25,11 @@ @implementation ASControlNode (tvOS) #pragma mark - tvOS - (void)pressDown { - [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationCurveLinear animations:^{ + [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ [self setPressedState]; } completion:^(BOOL finished) { if (finished) { - [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationCurveLinear animations:^{ + [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ [self setFocusedState]; } completion:nil]; } From 6b903821f302893933945cfc29d5677e2047a689 Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Wed, 27 Dec 2017 12:20:27 -0500 Subject: [PATCH 04/20] Enable tvOS deployment target in Texture.podspec (for CI) --- Texture.podspec | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Texture.podspec b/Texture.podspec index 73e904772..e5768d21b 100644 --- a/Texture.podspec +++ b/Texture.podspec @@ -15,9 +15,7 @@ Pod::Spec.new do |spec| spec.requires_arc = true spec.ios.deployment_target = '8.0' - - # Uncomment when fixed: issues with tvOS build for release 2.0 - # spec.tvos.deployment_target = '9.0' + spec.tvos.deployment_target = '9.0' # Subspecs spec.subspec 'Core' do |core| From b1b582a8f0d529f63cc827c79c8118b201b918b8 Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Thu, 28 Dec 2017 11:52:40 -0500 Subject: [PATCH 05/20] [ASMultiplexImageNode] Fixes typo --- Source/ASMultiplexImageNode.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ASMultiplexImageNode.mm b/Source/ASMultiplexImageNode.mm index c3a6f3f32..9c4694b72 100644 --- a/Source/ASMultiplexImageNode.mm +++ b/Source/ASMultiplexImageNode.mm @@ -17,7 +17,7 @@ #import -#if TARGET_OS_TVOS +#if TARGET_OS_IOS #import #endif From 7759cf791aea267d82a81826973f8e34f3bb2dd5 Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Thu, 28 Dec 2017 14:47:29 -0500 Subject: [PATCH 06/20] [tvOS] Fixes warnings related to @available guards in Xcode 9 [ASMultiplexImageNode] Enables support for Photos framework on tvOS 10+ [ASMultiplexImageNode] Fixes comment depth [ASAvailability] Adjust logic in AS_AVAILABLE_IOS_TVOS to account for both versions Adjusts API_AVAILABLE to minimum deployment target --- Source/ASCollectionView.mm | 2 +- Source/ASImageNode+AnimatedImage.mm | 2 +- Source/ASMultiplexImageNode.h | 14 +-- Source/ASMultiplexImageNode.mm | 97 ++++++++++--------- Source/Base/ASAvailability.h | 8 +- .../Details/ASPhotosFrameworkImageRequest.h | 1 + Source/Details/_ASDisplayViewAccessiblity.mm | 4 +- Source/Private/ASDisplayNode+UIViewBridge.mm | 6 +- Source/Private/_ASPendingState.mm | 2 +- 9 files changed, 71 insertions(+), 65 deletions(-) diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index 4efe9a75d..c011f3145 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -273,7 +273,7 @@ - (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionV // Experiments done by Instagram show that this option being YES (default) // when unused causes a significant hit to scroll performance. // https://github.com/Instagram/IGListKit/issues/318 - if (AS_AVAILABLE_IOS(10)) { + if (AS_AVAILABLE_IOS_TVOS(10, 10)) { super.prefetchingEnabled = NO; } diff --git a/Source/ASImageNode+AnimatedImage.mm b/Source/ASImageNode+AnimatedImage.mm index 246ee49cc2..a9ef4d33f 100644 --- a/Source/ASImageNode+AnimatedImage.mm +++ b/Source/ASImageNode+AnimatedImage.mm @@ -322,7 +322,7 @@ - (void)displayLinkFired:(CADisplayLink *)displayLink CFTimeInterval timeBetweenLastFire; if (self.lastDisplayLinkFire == 0) { timeBetweenLastFire = 0; - } else if (AS_AVAILABLE_IOS(10)){ + } else if (AS_AVAILABLE_IOS_TVOS(10, 10)) { timeBetweenLastFire = displayLink.targetTimestamp - displayLink.timestamp; } else { timeBetweenLastFire = CACurrentMediaTime() - self.lastDisplayLinkFire; diff --git a/Source/ASMultiplexImageNode.h b/Source/ASMultiplexImageNode.h index 15baced60..9b2649e8a 100644 --- a/Source/ASMultiplexImageNode.h +++ b/Source/ASMultiplexImageNode.h @@ -131,14 +131,12 @@ typedef NS_ENUM(NSUInteger, ASMultiplexImageNodeErrorCode) { */ @property (nonatomic, assign, readwrite) BOOL shouldRenderProgressImages; -#if TARGET_OS_IOS /** * @abstract The image manager that this image node should use when requesting images from the Photos framework. If this is `nil` (the default), then `PHImageManager.defaultManager` is used. * @see `+[NSURL URLWithAssetLocalIdentifier:targetSize:contentMode:options:]` below. */ -@property (nullable, nonatomic, strong) PHImageManager *imageManager; -#endif +@property (nullable, nonatomic, strong) PHImageManager *imageManager API_AVAILABLE(ios(9.0), tvos(10.0)); @end @@ -245,7 +243,6 @@ didFinishDownloadingImageWithIdentifier:(ASImageIdentifier)imageIdentifier */ - (nullable NSURL *)multiplexImageNode:(ASMultiplexImageNode *)imageNode URLForImageIdentifier:(ASImageIdentifier)imageIdentifier; -#if TARGET_OS_IOS /** * @abstract A PHAsset for the specific asset local identifier * @param imageNode The sender. @@ -256,12 +253,10 @@ didFinishDownloadingImageWithIdentifier:(ASImageIdentifier)imageIdentifier * @note This method may be called from any thread. * @return A PHAsset corresponding to `assetLocalIdentifier`, or nil if none is available. */ -- (nullable PHAsset *)multiplexImageNode:(ASMultiplexImageNode *)imageNode assetForLocalIdentifier:(NSString *)assetLocalIdentifier; -#endif +- (nullable PHAsset *)multiplexImageNode:(ASMultiplexImageNode *)imageNode assetForLocalIdentifier:(NSString *)assetLocalIdentifier API_AVAILABLE(ios(9.0), tvos(10.0)); @end -#pragma mark - -#if TARGET_OS_IOS +#pragma mark - @interface NSURL (ASPhotosFrameworkURLs) /** @@ -275,9 +270,8 @@ didFinishDownloadingImageWithIdentifier:(ASImageIdentifier)imageIdentifier + (NSURL *)URLWithAssetLocalIdentifier:(NSString *)assetLocalIdentifier targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode - options:(PHImageRequestOptions *)options AS_WARN_UNUSED_RESULT; + options:(PHImageRequestOptions *)options AS_WARN_UNUSED_RESULT API_AVAILABLE(ios(9.0), tvos(10.0)); @end -#endif NS_ASSUME_NONNULL_END diff --git a/Source/ASMultiplexImageNode.mm b/Source/ASMultiplexImageNode.mm index 9c4694b72..d6b1c695e 100644 --- a/Source/ASMultiplexImageNode.mm +++ b/Source/ASMultiplexImageNode.mm @@ -139,6 +139,7 @@ - (void)_fetchImageWithIdentifierFromCache:(id)imageIdentifier URL:(NSURL *)imag @param completionBlock The block to be performed when the image has been loaded, if possible. May not be nil. */ - (void)_loadALAssetWithIdentifier:(id)imageIdentifier URL:(NSURL *)assetURL completion:(void (^)(UIImage *image, NSError *error))completionBlock; +#endif /** @abstract Loads the image corresponding to the given image request from the Photos framework. @@ -146,8 +147,8 @@ - (void)_loadALAssetWithIdentifier:(id)imageIdentifier URL:(NSURL *)assetURL com @param request The photos image request to load. May not be nil. @param completionBlock The block to be performed when the image has been loaded, if possible. May not be nil. */ -- (void)_loadPHAssetWithRequest:(ASPhotosFrameworkImageRequest *)request identifier:(id)imageIdentifier completion:(void (^)(UIImage *image, NSError *error))completionBlock; -#endif +- (void)_loadPHAssetWithRequest:(ASPhotosFrameworkImageRequest *)request identifier:(id)imageIdentifier completion:(void (^)(UIImage *image, NSError *error))completionBlock API_AVAILABLE(ios(9.0), tvos(10.0)); + /** @abstract Downloads the image corresponding to the given imageIdentifier from the given URL. @param imageIdentifier The identifier for the image to be downloaded. May not be nil. @@ -348,9 +349,9 @@ - (void)setDataSource:(id )dataSource _dataSource = dataSource; _dataSourceFlags.image = [_dataSource respondsToSelector:@selector(multiplexImageNode:imageForImageIdentifier:)]; _dataSourceFlags.URL = [_dataSource respondsToSelector:@selector(multiplexImageNode:URLForImageIdentifier:)]; - #if TARGET_OS_IOS - _dataSourceFlags.asset = [_dataSource respondsToSelector:@selector(multiplexImageNode:assetForLocalIdentifier:)]; - #endif + if (AS_AVAILABLE_IOS_TVOS(8, 10)) { + _dataSourceFlags.asset = [_dataSource respondsToSelector:@selector(multiplexImageNode:assetForLocalIdentifier:)]; + } } @@ -619,7 +620,7 @@ - (void)_loadNextImage return; } - #if TARGET_OS_IOS +#if TARGET_OS_IOS // If it's an assets-library URL, we need to fetch it from the assets library. if ([[nextImageURL scheme] isEqualToString:kAssetsLibraryURLScheme]) { // Load the asset. @@ -627,48 +628,54 @@ - (void)_loadNextImage as_log_verbose(ASImageLoadingLog(), "Acquired image from assets library for %@ %@", weakSelf, nextImageIdentifier); finishedLoadingBlock(downloadedImage, nextImageIdentifier, error); }]; + + return; } - // Likewise, if it's a iOS 8 Photo asset, we need to fetch it accordingly. - else if (ASPhotosFrameworkImageRequest *request = [ASPhotosFrameworkImageRequest requestWithURL:nextImageURL]) { - [self _loadPHAssetWithRequest:request identifier:nextImageIdentifier completion:^(UIImage *image, NSError *error) { - as_log_verbose(ASImageLoadingLog(), "Acquired image from Photos for %@ %@", weakSelf, nextImageIdentifier); - finishedLoadingBlock(image, nextImageIdentifier, error); - }]; +#endif + + if (AS_AVAILABLE_IOS_TVOS(8, 10)) { + // Likewise, if it's a iOS 8 Photo asset, we need to fetch it accordingly. + if (ASPhotosFrameworkImageRequest *request = [ASPhotosFrameworkImageRequest requestWithURL:nextImageURL]) { + [self _loadPHAssetWithRequest:request identifier:nextImageIdentifier completion:^(UIImage *image, NSError *error) { + as_log_verbose(ASImageLoadingLog(), "Acquired image from Photos for %@ %@", weakSelf, nextImageIdentifier); + finishedLoadingBlock(image, nextImageIdentifier, error); + }]; + + return; + } } - #endif - else // Otherwise, it's a web URL that we can download. - { - // First, check the cache. - [self _fetchImageWithIdentifierFromCache:nextImageIdentifier URL:nextImageURL completion:^(UIImage *imageFromCache) { + + // Otherwise, it's a web URL that we can download. + // First, check the cache. + [self _fetchImageWithIdentifierFromCache:nextImageIdentifier URL:nextImageURL completion:^(UIImage *imageFromCache) { + __typeof__(self) strongSelf = weakSelf; + if (!strongSelf) + return; + + // If we had a cache-hit, we're done. + if (imageFromCache) { + as_log_verbose(ASImageLoadingLog(), "Acquired image from cache for %@ id: %@ img: %@", strongSelf, nextImageIdentifier, imageFromCache); + finishedLoadingBlock(imageFromCache, nextImageIdentifier, nil); + return; + } + + // If the next image to load has changed, bail. + if (!ASObjectIsEqual([strongSelf _nextImageIdentifierToDownload], nextImageIdentifier)) { + finishedLoadingBlock(nil, nil, [NSError errorWithDomain:ASMultiplexImageNodeErrorDomain code:ASMultiplexImageNodeErrorCodeBestImageIdentifierChanged userInfo:nil]); + return; + } + + // Otherwise, we've got to download it. + [strongSelf _downloadImageWithIdentifier:nextImageIdentifier URL:nextImageURL completion:^(UIImage *downloadedImage, NSError *error) { __typeof__(self) strongSelf = weakSelf; - if (!strongSelf) - return; - - // If we had a cache-hit, we're done. - if (imageFromCache) { - as_log_verbose(ASImageLoadingLog(), "Acquired image from cache for %@ id: %@ img: %@", strongSelf, nextImageIdentifier, imageFromCache); - finishedLoadingBlock(imageFromCache, nextImageIdentifier, nil); - return; - } - - // If the next image to load has changed, bail. - if (!ASObjectIsEqual([strongSelf _nextImageIdentifierToDownload], nextImageIdentifier)) { - finishedLoadingBlock(nil, nil, [NSError errorWithDomain:ASMultiplexImageNodeErrorDomain code:ASMultiplexImageNodeErrorCodeBestImageIdentifierChanged userInfo:nil]); - return; + if (downloadedImage) { + as_log_verbose(ASImageLoadingLog(), "Acquired image from download for %@ id: %@ img: %@", strongSelf, nextImageIdentifier, downloadedImage); + } else { + as_log_error(ASImageLoadingLog(), "Error downloading image for %@ id: %@ err: %@", strongSelf, nextImageIdentifier, error); } - - // Otherwise, we've got to download it. - [strongSelf _downloadImageWithIdentifier:nextImageIdentifier URL:nextImageURL completion:^(UIImage *downloadedImage, NSError *error) { - __typeof__(self) strongSelf = weakSelf; - if (downloadedImage) { - as_log_verbose(ASImageLoadingLog(), "Acquired image from download for %@ id: %@ img: %@", strongSelf, nextImageIdentifier, downloadedImage); - } else { - as_log_error(ASImageLoadingLog(), "Error downloading image for %@ id: %@ err: %@", strongSelf, nextImageIdentifier, error); - } - finishedLoadingBlock(downloadedImage, nextImageIdentifier, error); - }]; + finishedLoadingBlock(downloadedImage, nextImageIdentifier, error); }]; - } + }]; } #if TARGET_OS_IOS - (void)_loadALAssetWithIdentifier:(id)imageIdentifier URL:(NSURL *)assetURL completion:(void (^)(UIImage *image, NSError *error))completionBlock @@ -689,7 +696,7 @@ - (void)_loadALAssetWithIdentifier:(id)imageIdentifier URL:(NSURL *)assetURL com completionBlock(nil, error); }]; } - +#endif - (void)_loadPHAssetWithRequest:(ASPhotosFrameworkImageRequest *)request identifier:(id)imageIdentifier completion:(void (^)(UIImage *image, NSError *error))completionBlock { ASDisplayNodeAssertNotNil(imageIdentifier, @"imageIdentifier is required"); @@ -777,7 +784,7 @@ - (void)_loadPHAssetWithRequest:(ASPhotosFrameworkImageRequest *)request identif _phImageRequestOperation = newImageRequestOp; [phImageRequestQueue addOperation:newImageRequestOp]; } -#endif + - (void)_fetchImageWithIdentifierFromCache:(id)imageIdentifier URL:(NSURL *)imageURL completion:(void (^)(UIImage *image))completionBlock { ASDisplayNodeAssertNotNil(imageIdentifier, @"imageIdentifier is required"); diff --git a/Source/Base/ASAvailability.h b/Source/Base/ASAvailability.h index 6a80e274a..77ac35b29 100644 --- a/Source/Base/ASAvailability.h +++ b/Source/Base/ASAvailability.h @@ -41,9 +41,13 @@ // Use __builtin_available if we're on Xcode >= 9, AS_AT_LEAST otherwise. #if __has_builtin(__builtin_available) - #define AS_AVAILABLE_IOS(ver) __builtin_available(iOS ver, *) + #define AS_AVAILABLE_IOS(ver) __builtin_available(iOS ver, *) + #define AS_AVAILABLE_TVOS(ver) __builtin_available(tvOS ver, *) + #define AS_AVAILABLE_IOS_TVOS(ver1, ver2) __builtin_available(iOS ver1, tvOS ver2, *) #else - #define AS_AVAILABLE_IOS(ver) AS_AT_LEAST_IOS##ver + #define AS_AVAILABLE_IOS(ver) AS_AT_LEAST_IOS##ver + #define AS_AVAILABLE_TVOS(ver) AS_AT_LEAST_IOS##ver + #define AS_AVAILABLE_IOS_TVOS(ver1, ver2) AS_AT_LEAST_IOS##ver1 || AS_AT_LEAST_IOS##ver2 #endif // If Yoga is available, make it available anywhere we use ASAvailability. diff --git a/Source/Details/ASPhotosFrameworkImageRequest.h b/Source/Details/ASPhotosFrameworkImageRequest.h index 1ecd07dec..fd75448af 100644 --- a/Source/Details/ASPhotosFrameworkImageRequest.h +++ b/Source/Details/ASPhotosFrameworkImageRequest.h @@ -26,6 +26,7 @@ extern NSString *const ASPhotosURLScheme; @abstract Use ASPhotosFrameworkImageRequest to encapsulate all the information needed to request an image from the Photos framework and store it in a URL. */ +API_AVAILABLE(ios(9.0), tvos(10.0)) @interface ASPhotosFrameworkImageRequest : NSObject - (instancetype)initWithAssetIdentifier:(NSString *)assetIdentifier NS_DESIGNATED_INITIALIZER; diff --git a/Source/Details/_ASDisplayViewAccessiblity.mm b/Source/Details/_ASDisplayViewAccessiblity.mm index 734cf2b7f..6b34c89a2 100644 --- a/Source/Details/_ASDisplayViewAccessiblity.mm +++ b/Source/Details/_ASDisplayViewAccessiblity.mm @@ -85,7 +85,7 @@ + (ASAccessibilityElement *)accessibilityElementWithContainer:(UIView *)containe accessibilityElement.accessibilityValue = node.accessibilityValue; accessibilityElement.accessibilityTraits = node.accessibilityTraits; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 - if (AS_AVAILABLE_IOS(11)) { + if (AS_AVAILABLE_IOS_TVOS(11, 11)) { accessibilityElement.accessibilityAttributedLabel = node.accessibilityAttributedLabel; accessibilityElement.accessibilityAttributedHint = node.accessibilityAttributedHint; accessibilityElement.accessibilityAttributedValue = node.accessibilityAttributedValue; @@ -179,7 +179,7 @@ static void CollectAccessibilityElementsForContainer(ASDisplayNode *container, _ SortAccessibilityElements(labeledNodes); #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 - if (AS_AVAILABLE_IOS(11)) { + if (AS_AVAILABLE_IOS_TVOS(11, 11)) { NSArray *attributedLabels = [labeledNodes valueForKey:@"accessibilityAttributedLabel"]; NSMutableAttributedString *attributedLabel = [NSMutableAttributedString new]; [attributedLabels enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { diff --git a/Source/Private/ASDisplayNode+UIViewBridge.mm b/Source/Private/ASDisplayNode+UIViewBridge.mm index cf07bd700..4de4ed510 100644 --- a/Source/Private/ASDisplayNode+UIViewBridge.mm +++ b/Source/Private/ASDisplayNode+UIViewBridge.mm @@ -940,7 +940,7 @@ - (void)setAccessibilityLabel:(NSString *)accessibilityLabel _bridge_prologue_write; _setAccessibilityToViewAndProperty(_accessibilityLabel, accessibilityLabel, accessibilityLabel, accessibilityLabel); #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 - if (AS_AVAILABLE_IOS(11)) { + if (AS_AVAILABLE_IOS_TVOS(11, 11)) { NSAttributedString *accessibilityAttributedLabel = accessibilityLabel ? [[NSAttributedString alloc] initWithString:accessibilityLabel] : nil; _setAccessibilityToViewAndProperty(_accessibilityAttributedLabel, accessibilityAttributedLabel, accessibilityAttributedLabel, accessibilityAttributedLabel); } @@ -973,7 +973,7 @@ - (void)setAccessibilityHint:(NSString *)accessibilityHint _bridge_prologue_write; _setAccessibilityToViewAndProperty(_accessibilityHint, accessibilityHint, accessibilityHint, accessibilityHint); #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 - if (AS_AVAILABLE_IOS(11)) { + if (AS_AVAILABLE_IOS_TVOS(11, 11)) { NSAttributedString *accessibilityAttributedHint = accessibilityHint ? [[NSAttributedString alloc] initWithString:accessibilityHint] : nil; _setAccessibilityToViewAndProperty(_accessibilityAttributedHint, accessibilityAttributedHint, accessibilityAttributedHint, accessibilityAttributedHint); } @@ -1007,7 +1007,7 @@ - (void)setAccessibilityValue:(NSString *)accessibilityValue _bridge_prologue_write; _setAccessibilityToViewAndProperty(_accessibilityValue, accessibilityValue, accessibilityValue, accessibilityValue); #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 - if (AS_AVAILABLE_IOS(11)) { + if (AS_AVAILABLE_IOS_TVOS(11, 11)) { NSAttributedString *accessibilityAttributedValue = accessibilityValue ? [[NSAttributedString alloc] initWithString:accessibilityValue] : nil; _setAccessibilityToViewAndProperty(_accessibilityAttributedValue, accessibilityAttributedValue, accessibilityAttributedValue, accessibilityAttributedValue); } diff --git a/Source/Private/_ASPendingState.mm b/Source/Private/_ASPendingState.mm index 4374401d8..21f6abead 100644 --- a/Source/Private/_ASPendingState.mm +++ b/Source/Private/_ASPendingState.mm @@ -1223,7 +1223,7 @@ + (_ASPendingState *)pendingViewStateFromView:(UIView *)view pendingState.accessibilityHint = view.accessibilityHint; pendingState.accessibilityValue = view.accessibilityValue; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 - if (AS_AVAILABLE_IOS(11)) { + if (AS_AVAILABLE_IOS_TVOS(11, 11)) { pendingState.accessibilityAttributedLabel = view.accessibilityAttributedLabel; pendingState.accessibilityAttributedHint = view.accessibilityAttributedHint; pendingState.accessibilityAttributedValue = view.accessibilityAttributedValue; From 8dbcc514a07b2c9227817bbd23a970dd13e3be13 Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Thu, 28 Dec 2017 16:52:24 -0500 Subject: [PATCH 07/20] [ASAvailability] Update AS_AVAILABLE_XXX fallbacks to function more like the built-in solution (more accurately target OS by checking target) Change AS_AVAILABLE_IOS -> AS_AVAILABLE_IOS_TVOS in places that shoud allow for both [ASAvailability] Simplify AS_AVAILABLE_IOS_TVOS --- Source/ASCollectionView.mm | 2 +- Source/Base/ASAvailability.h | 6 +++--- Source/Base/ASLog.h | 10 +++++----- Source/Details/ASTraitCollection.m | 2 +- Source/Private/_ASPendingState.mm | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index c011f3145..c614f6084 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -1974,7 +1974,7 @@ - (ASRangeController *)rangeController /// The UIKit version of this method is only available on iOS >= 9 - (NSArray *)asdk_indexPathsForVisibleSupplementaryElementsOfKind:(NSString *)kind { - if (AS_AVAILABLE_IOS(9)) { + if (AS_AVAILABLE_IOS_TVOS(9, 9)) { return [self indexPathsForVisibleSupplementaryElementsOfKind:kind]; } diff --git a/Source/Base/ASAvailability.h b/Source/Base/ASAvailability.h index 77ac35b29..eb6af2ac2 100644 --- a/Source/Base/ASAvailability.h +++ b/Source/Base/ASAvailability.h @@ -45,9 +45,9 @@ #define AS_AVAILABLE_TVOS(ver) __builtin_available(tvOS ver, *) #define AS_AVAILABLE_IOS_TVOS(ver1, ver2) __builtin_available(iOS ver1, tvOS ver2, *) #else - #define AS_AVAILABLE_IOS(ver) AS_AT_LEAST_IOS##ver - #define AS_AVAILABLE_TVOS(ver) AS_AT_LEAST_IOS##ver - #define AS_AVAILABLE_IOS_TVOS(ver1, ver2) AS_AT_LEAST_IOS##ver1 || AS_AT_LEAST_IOS##ver2 + #define AS_AVAILABLE_IOS(ver) (TARGET_OS_IOS && AS_AT_LEAST_IOS##ver) + #define AS_AVAILABLE_TVOS(ver) (TARGET_OS_TV && AS_AT_LEAST_IOS##ver) + #define AS_AVAILABLE_IOS_TVOS(ver1, ver2) (AS_AVAILABLE_IOS(ver1) || AS_AVAILABLE_TVOS(ver2)) #endif // If Yoga is available, make it available anywhere we use ASAvailability. diff --git a/Source/Base/ASLog.h b/Source/Base/ASLog.h index c6aba76ba..e87404631 100644 --- a/Source/Base/ASLog.h +++ b/Source/Base/ASLog.h @@ -132,7 +132,7 @@ ASDISPLAYNODE_EXTERN_C_END #define as_log_create(subsystem, category) ({ \ os_log_t __val; \ -if (AS_AVAILABLE_IOS(9)) { \ +if (AS_AVAILABLE_IOS_TVOS(9, 9)) { \ __val = os_log_create(subsystem, category); \ } else { \ __val = (os_log_t)0; \ @@ -141,28 +141,28 @@ __val; \ }) #define as_log_debug(log, format, ...) \ -if (AS_AVAILABLE_IOS(9)) { \ +if (AS_AVAILABLE_IOS_TVOS(9, 9)) { \ os_log_debug(log, format, ##__VA_ARGS__); \ } else { \ (void)0; \ } \ #define as_log_info(log, format, ...) \ -if (AS_AVAILABLE_IOS(9)) { \ +if (AS_AVAILABLE_IOS_TVOS(9, 9)) { \ os_log_info(log, format, ##__VA_ARGS__); \ } else { \ (void)0; \ } \ #define as_log_error(log, format, ...) \ -if (AS_AVAILABLE_IOS(9)) { \ +if (AS_AVAILABLE_IOS_TVOS(9, 9)) { \ os_log_error(log, format, ##__VA_ARGS__); \ } else { \ (void)0; \ } \ #define as_log_fault(log, format, ...) \ -if (AS_AVAILABLE_IOS(9)) { \ +if (AS_AVAILABLE_IOS_TVOS(9, 9)) { \ os_log_fault(log, format, ##__VA_ARGS__); \ } else { \ (void)0; \ diff --git a/Source/Details/ASTraitCollection.m b/Source/Details/ASTraitCollection.m index 04eaea608..1309b9265 100644 --- a/Source/Details/ASTraitCollection.m +++ b/Source/Details/ASTraitCollection.m @@ -67,7 +67,7 @@ BOOL ASPrimitiveTraitCollectionIsEqualToASPrimitiveTraitCollection(ASPrimitiveTr // Named so as not to conflict with a hidden Apple function, in case compiler decides not to inline ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUIUserInterfaceIdiom(UIUserInterfaceIdiom idiom) { - if (AS_AVAILABLE_IOS(9)) { + if (AS_AVAILABLE_IOS_TVOS(9, 9)) { switch (idiom) { case UIUserInterfaceIdiomTV: return @"TV"; diff --git a/Source/Private/_ASPendingState.mm b/Source/Private/_ASPendingState.mm index 21f6abead..ea8834f70 100644 --- a/Source/Private/_ASPendingState.mm +++ b/Source/Private/_ASPendingState.mm @@ -295,7 +295,7 @@ - (instancetype)init accessibilityActivationPoint = CGPointZero; accessibilityPath = nil; edgeAntialiasingMask = (kCALayerLeftEdge | kCALayerRightEdge | kCALayerTopEdge | kCALayerBottomEdge); - if (AS_AVAILABLE_IOS(9)) { + if (AS_AVAILABLE_IOS_TVOS(9, 9)) { semanticContentAttribute = UISemanticContentAttributeUnspecified; } @@ -1051,7 +1051,7 @@ - (void)applyToView:(UIView *)view withSpecialPropertiesHandling:(BOOL)specialPr if (flags.setOpaque) ASDisplayNodeAssert(layer.opaque == opaque, @"Didn't set opaque as desired"); - if (AS_AVAILABLE_IOS(9)) { + if (AS_AVAILABLE_IOS_TVOS(9, 9)) { if (flags.setSemanticContentAttribute) { view.semanticContentAttribute = semanticContentAttribute; } @@ -1215,7 +1215,7 @@ + (_ASPendingState *)pendingViewStateFromView:(UIView *)view pendingState.allowsGroupOpacity = layer.allowsGroupOpacity; pendingState.allowsEdgeAntialiasing = layer.allowsEdgeAntialiasing; pendingState.edgeAntialiasingMask = layer.edgeAntialiasingMask; - if (AS_AVAILABLE_IOS(9)) { + if (AS_AVAILABLE_IOS_TVOS(9, 9)) { pendingState.semanticContentAttribute = view.semanticContentAttribute; } pendingState.isAccessibilityElement = view.isAccessibilityElement; From 6607bda5da4ccb26e29b1c7c4f98b8265823f05c Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Thu, 28 Dec 2017 17:30:37 -0500 Subject: [PATCH 08/20] [ASControlNode] Adds missing 'super' call in -[ASControlNode didLoad] when targeting tvOS --- Source/ASControlNode.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/ASControlNode.mm b/Source/ASControlNode.mm index fdd1155e7..51dc7e60b 100644 --- a/Source/ASControlNode.mm +++ b/Source/ASControlNode.mm @@ -103,6 +103,8 @@ - (instancetype)init #if TARGET_OS_TV - (void)didLoad { + [super didLoad]; + // On tvOS all controls, such as buttons, interact with the focus system even if they don't have a target set on them. // Here we add our own internal tap gesture to handle this behaviour. self.userInteractionEnabled = YES; From 14a8e91cddd0a032bd40d598a11f217304cffa0e Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Fri, 29 Dec 2017 12:44:53 -0500 Subject: [PATCH 09/20] Fix API_AVAILABLE iOS requirement --- Source/ASMultiplexImageNode.h | 6 +++--- Source/ASMultiplexImageNode.mm | 2 +- Source/Details/ASPhotosFrameworkImageRequest.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/ASMultiplexImageNode.h b/Source/ASMultiplexImageNode.h index 9b2649e8a..b3aa331e7 100644 --- a/Source/ASMultiplexImageNode.h +++ b/Source/ASMultiplexImageNode.h @@ -136,7 +136,7 @@ typedef NS_ENUM(NSUInteger, ASMultiplexImageNodeErrorCode) { * @see `+[NSURL URLWithAssetLocalIdentifier:targetSize:contentMode:options:]` below. */ -@property (nullable, nonatomic, strong) PHImageManager *imageManager API_AVAILABLE(ios(9.0), tvos(10.0)); +@property (nullable, nonatomic, strong) PHImageManager *imageManager API_AVAILABLE(ios(8.0), tvos(10.0)); @end @@ -253,7 +253,7 @@ didFinishDownloadingImageWithIdentifier:(ASImageIdentifier)imageIdentifier * @note This method may be called from any thread. * @return A PHAsset corresponding to `assetLocalIdentifier`, or nil if none is available. */ -- (nullable PHAsset *)multiplexImageNode:(ASMultiplexImageNode *)imageNode assetForLocalIdentifier:(NSString *)assetLocalIdentifier API_AVAILABLE(ios(9.0), tvos(10.0)); +- (nullable PHAsset *)multiplexImageNode:(ASMultiplexImageNode *)imageNode assetForLocalIdentifier:(NSString *)assetLocalIdentifier API_AVAILABLE(ios(8.0), tvos(10.0)); @end #pragma mark - @@ -270,7 +270,7 @@ didFinishDownloadingImageWithIdentifier:(ASImageIdentifier)imageIdentifier + (NSURL *)URLWithAssetLocalIdentifier:(NSString *)assetLocalIdentifier targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode - options:(PHImageRequestOptions *)options AS_WARN_UNUSED_RESULT API_AVAILABLE(ios(9.0), tvos(10.0)); + options:(PHImageRequestOptions *)options AS_WARN_UNUSED_RESULT API_AVAILABLE(ios(8.0), tvos(10.0)); @end diff --git a/Source/ASMultiplexImageNode.mm b/Source/ASMultiplexImageNode.mm index d6b1c695e..7e8081baa 100644 --- a/Source/ASMultiplexImageNode.mm +++ b/Source/ASMultiplexImageNode.mm @@ -147,7 +147,7 @@ - (void)_loadALAssetWithIdentifier:(id)imageIdentifier URL:(NSURL *)assetURL com @param request The photos image request to load. May not be nil. @param completionBlock The block to be performed when the image has been loaded, if possible. May not be nil. */ -- (void)_loadPHAssetWithRequest:(ASPhotosFrameworkImageRequest *)request identifier:(id)imageIdentifier completion:(void (^)(UIImage *image, NSError *error))completionBlock API_AVAILABLE(ios(9.0), tvos(10.0)); +- (void)_loadPHAssetWithRequest:(ASPhotosFrameworkImageRequest *)request identifier:(id)imageIdentifier completion:(void (^)(UIImage *image, NSError *error))completionBlock API_AVAILABLE(ios(8.0), tvos(10.0)); /** @abstract Downloads the image corresponding to the given imageIdentifier from the given URL. diff --git a/Source/Details/ASPhotosFrameworkImageRequest.h b/Source/Details/ASPhotosFrameworkImageRequest.h index fd75448af..54f55047a 100644 --- a/Source/Details/ASPhotosFrameworkImageRequest.h +++ b/Source/Details/ASPhotosFrameworkImageRequest.h @@ -26,7 +26,7 @@ extern NSString *const ASPhotosURLScheme; @abstract Use ASPhotosFrameworkImageRequest to encapsulate all the information needed to request an image from the Photos framework and store it in a URL. */ -API_AVAILABLE(ios(9.0), tvos(10.0)) +API_AVAILABLE(ios(8.0), tvos(10.0)) @interface ASPhotosFrameworkImageRequest : NSObject - (instancetype)initWithAssetIdentifier:(NSString *)assetIdentifier NS_DESIGNATED_INITIALIZER; From bcdae3fc84b7ea6877e00f3ba756498b1b08163e Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Fri, 29 Dec 2017 22:40:25 -0500 Subject: [PATCH 10/20] [ASDisplayNode] Fixes last of the linker warnings related to category overrides. Removes methods already implemented in ASDisplayNode+UIViewBridge category. [ASControlNode] Moves tvOS category declaration to ASControlNode header [ASImageNode] Moves tvOS category declaration to ASImageNode header [ASControlNode+Private] Adds private category for ASControlNode to access private selectors --- Source/ASControlNode.h | 9 +++-- Source/ASControlNode.mm | 3 +- Source/ASDisplayNode.mm | 34 ------------------- Source/ASImageNode.h | 5 +++ .../ASControlNode+Private.h} | 10 +++--- Source/tvOS/ASControlNode+tvOS.m | 7 ++-- Source/tvOS/ASImageNode+tvOS.h | 24 ------------- Source/tvOS/ASImageNode+tvOS.m | 3 +- 8 files changed, 24 insertions(+), 71 deletions(-) rename Source/{tvOS/ASControlNode+tvOS.h => Private/ASControlNode+Private.h} (89%) delete mode 100644 Source/tvOS/ASImageNode+tvOS.h diff --git a/Source/ASControlNode.h b/Source/ASControlNode.h index e08f0650f..879cb501d 100644 --- a/Source/ASControlNode.h +++ b/Source/ASControlNode.h @@ -141,12 +141,17 @@ static UIControlState const ASControlStateSelected ASDISPLAYNODE_DEPRECATED_MSG( @param event The event which triggered these control actions. May be nil. */ - (void)sendActionsForControlEvents:(ASControlNodeEvent)controlEvents withEvent:(nullable UIEvent *)event; +@end + #if TARGET_OS_TV +@interface ASControlNode (tvOS) + /** - @abstract How the node looks when it isn't focused. Exposed here so that subclasses can override. + @abstract How the node looks when it isn't focused. */ - (void)setDefaultFocusAppearance; -#endif + @end +#endif NS_ASSUME_NONNULL_END diff --git a/Source/ASControlNode.mm b/Source/ASControlNode.mm index 51dc7e60b..702161721 100644 --- a/Source/ASControlNode.mm +++ b/Source/ASControlNode.mm @@ -16,6 +16,7 @@ // #import +#import #import #import #import @@ -108,7 +109,7 @@ - (void)didLoad // On tvOS all controls, such as buttons, interact with the focus system even if they don't have a target set on them. // Here we add our own internal tap gesture to handle this behaviour. self.userInteractionEnabled = YES; - UITapGestureRecognizer *tapGestureRec = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pressDown)]; + UITapGestureRecognizer *tapGestureRec = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_pressDown)]; tapGestureRec.allowedPressTypes = @[@(UIPressTypeSelect)]; [self.view addGestureRecognizer:tapGestureRec]; } diff --git a/Source/ASDisplayNode.mm b/Source/ASDisplayNode.mm index 3a537ca4b..0a8aceb48 100644 --- a/Source/ASDisplayNode.mm +++ b/Source/ASDisplayNode.mm @@ -3469,40 +3469,6 @@ - (void)asyncTraitCollectionDidChange { // Subclass override } - -#if TARGET_OS_TV -#pragma mark - UIFocusEnvironment Protocol (tvOS) - -- (void)setNeedsFocusUpdate -{ - -} - -- (void)updateFocusIfNeeded -{ - -} - -- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context -{ - return NO; -} - -- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator -{ - -} - -- (UIView *)preferredFocusedView -{ - if (self.nodeLoaded) { - return self.view; - } else { - return nil; - } -} -#endif - @end #pragma mark - ASDisplayNode (Debugging) diff --git a/Source/ASImageNode.h b/Source/ASImageNode.h index 547044c7d..99ef57549 100644 --- a/Source/ASImageNode.h +++ b/Source/ASImageNode.h @@ -141,6 +141,11 @@ typedef UIImage * _Nullable (^asimagenode_modification_block_t)(UIImage *image); @end +#if TARGET_OS_TV +@interface ASImageNode (tvOS) +@end +#endif + @interface ASImageNode (AnimatedImage) /** diff --git a/Source/tvOS/ASControlNode+tvOS.h b/Source/Private/ASControlNode+Private.h similarity index 89% rename from Source/tvOS/ASControlNode+tvOS.h rename to Source/Private/ASControlNode+Private.h index cd05078a7..f3249c11c 100644 --- a/Source/tvOS/ASControlNode+tvOS.h +++ b/Source/Private/ASControlNode+Private.h @@ -1,5 +1,5 @@ // -// ASControlNode+tvOS.h +// ASControlNode+Private.h // Texture // // Copyright (c) 2014-present, Facebook, Inc. All rights reserved. @@ -15,10 +15,12 @@ // http://www.apache.org/licenses/LICENSE-2.0 // -#if TARGET_OS_TV #import -@interface ASControlNode (tvOS) +@interface ASControlNode (Private) -@end +#if TARGET_OS_TV +- (void)_pressDown; #endif + +@end diff --git a/Source/tvOS/ASControlNode+tvOS.m b/Source/tvOS/ASControlNode+tvOS.m index 528b9419b..d145d40ad 100644 --- a/Source/tvOS/ASControlNode+tvOS.m +++ b/Source/tvOS/ASControlNode+tvOS.m @@ -15,15 +15,14 @@ // http://www.apache.org/licenses/LICENSE-2.0 // -#import - #if TARGET_OS_TV -#import +#import +#import @implementation ASControlNode (tvOS) #pragma mark - tvOS -- (void)pressDown +- (void)_pressDown { [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ [self setPressedState]; diff --git a/Source/tvOS/ASImageNode+tvOS.h b/Source/tvOS/ASImageNode+tvOS.h deleted file mode 100644 index d808db10a..000000000 --- a/Source/tvOS/ASImageNode+tvOS.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// ASImageNode+tvOS.h -// Texture -// -// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. -// This source code is licensed under the BSD-style license found in the -// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional -// grant of patent rights can be found in the PATENTS file in the same directory. -// -// Modifications to this file made after 4/13/2017 are: Copyright (c) 2017-present, -// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// - -#if TARGET_OS_TV -#import - -@interface ASImageNode (tvOS) -@end -#endif - diff --git a/Source/tvOS/ASImageNode+tvOS.m b/Source/tvOS/ASImageNode+tvOS.m index 51a5d484a..2e22754ae 100644 --- a/Source/tvOS/ASImageNode+tvOS.m +++ b/Source/tvOS/ASImageNode+tvOS.m @@ -15,9 +15,8 @@ // http://www.apache.org/licenses/LICENSE-2.0 // -#import #if TARGET_OS_TV -#import +#import #import #import From 9673a83e56b4eb653f52e5c6d2ed364d27a78443 Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Sat, 30 Dec 2017 11:10:23 -0500 Subject: [PATCH 11/20] [NSParagraphStyle+ASText] Fixes typo related to testing --- .../TextExperiment/Utility/NSParagraphStyle+ASText.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Private/TextExperiment/Utility/NSParagraphStyle+ASText.m b/Source/Private/TextExperiment/Utility/NSParagraphStyle+ASText.m index e6420cf7a..2374e4021 100755 --- a/Source/Private/TextExperiment/Utility/NSParagraphStyle+ASText.m +++ b/Source/Private/TextExperiment/Utility/NSParagraphStyle+ASText.m @@ -116,16 +116,16 @@ - (CTParagraphStyleRef)as_CTStyle CF_RETURNS_RETAINED { CTParagraphStyleSetting set[kCTParagraphStyleSpecifierCount] = { }; int count = 0; +#if TARGET_OS_IOS #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" CGFloat lineSpacing = self.lineSpacing; -#if TARGET_OS_IOS - set[count].spec = kCTParagraphStyleSpecifierMaximumLineSpacing; -#endif + set[count].spec = kCTParagraphStyleSpecifierLineSpacing; set[count].valueSize = sizeof(CGFloat); set[count].value = &lineSpacing; count++; #pragma clang diagnostic pop +#endif CGFloat paragraphSpacing = self.paragraphSpacing; set[count].spec = kCTParagraphStyleSpecifierParagraphSpacing; From bf9aa78afbc85eee262426737c438a51496eb7f4 Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Sat, 30 Dec 2017 11:17:14 -0500 Subject: [PATCH 12/20] [ASControlNode] Re-add helpful comment --- Source/ASControlNode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ASControlNode.h b/Source/ASControlNode.h index 879cb501d..7896b93eb 100644 --- a/Source/ASControlNode.h +++ b/Source/ASControlNode.h @@ -147,7 +147,7 @@ static UIControlState const ASControlStateSelected ASDISPLAYNODE_DEPRECATED_MSG( @interface ASControlNode (tvOS) /** - @abstract How the node looks when it isn't focused. + @abstract How the node looks when it isn't focused. Exposed here so that subclasses can override. */ - (void)setDefaultFocusAppearance; From 8eb2dbec5a1a8e87eb593a117489b39f82a31c1e Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Fri, 5 Jan 2018 21:10:01 -0500 Subject: [PATCH 13/20] [ASTextKitCoreTextAdditions] Adds mappings for kCTParagraphStyleSpecifierMinimumLineSpacing, kCTParagraphStyleSpecifierMaximumLineSpacing, kCTParagraphStyleSpecifierLineSpacingAdjustment when mapping CTParagraphStyle onto NSParagraphStyle [ASTextNode] Uses CoreText-cleansed attributed string when assigning ascender/descender to avoid crash when a CTParagraphStyle is passed as an attribute --- Source/ASTextNode.mm | 8 +++--- Source/TextKit/ASTextKitCoreTextAdditions.m | 29 ++++++++++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/Source/ASTextNode.mm b/Source/ASTextNode.mm index e5338f521..35cbb223f 100644 --- a/Source/ASTextNode.mm +++ b/Source/ASTextNode.mm @@ -447,10 +447,10 @@ - (void)setAttributedText:(NSAttributedString *)attributedText // Since truncation text matches style of attributedText, invalidate it now. [self _invalidateTruncationText]; - NSUInteger length = attributedText.length; + NSUInteger length = _attributedText.length; if (length > 0) { - self.style.ascender = [[self class] ascenderWithAttributedString:attributedText]; - self.style.descender = [[attributedText attribute:NSFontAttributeName atIndex:attributedText.length - 1 effectiveRange:NULL] descender]; + self.style.ascender = [[self class] ascenderWithAttributedString:_attributedText]; + self.style.descender = [[_attributedText attribute:NSFontAttributeName atIndex:length - 1 effectiveRange:NULL] descender]; } // Tell the display node superclasses that the cached layout is incorrect now @@ -461,7 +461,7 @@ - (void)setAttributedText:(NSAttributedString *)attributedText // Accessiblity - self.accessibilityLabel = attributedText.string; + self.accessibilityLabel = _attributedText.string; self.isAccessibilityElement = (length != 0); // We're an accessibility element by default if there is a string. } diff --git a/Source/TextKit/ASTextKitCoreTextAdditions.m b/Source/TextKit/ASTextKitCoreTextAdditions.m index 15fa2529e..d6022ff08 100644 --- a/Source/TextKit/ASTextKitCoreTextAdditions.m +++ b/Source/TextKit/ASTextKitCoreTextAdditions.m @@ -39,6 +39,7 @@ BOOL ASAttributeWithNameIsUnsupportedCoreTextAttribute(NSString *attributeName) kCTBaselineInfoAttributeName, kCTBaselineReferenceInfoAttributeName, kCTUnderlineColorAttributeName, + kCTParagraphStyleAttributeName, nil]; }); return [coreTextAttributes containsObject:attributeName]; @@ -227,17 +228,33 @@ + (instancetype)paragraphStyleWithCTParagraphStyle:(CTParagraphStyleRef)coreText CGFloat minimumLineHeight; if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierMinimumLineHeight, sizeof(minimumLineHeight), &minimumLineHeight)) newParagraphStyle.minimumLineHeight = minimumLineHeight; - + + CGFloat lineSpacing = 0; #if TARGET_OS_IOS - // kCTParagraphStyleSpecifierLineSpacing -> lineSpacing - // Note that kCTParagraphStyleSpecifierLineSpacing is deprecated and will die soon. We should not be using it. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - CGFloat lineSpacing; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierLineSpacing, sizeof(lineSpacing), &lineSpacing)) - newParagraphStyle.lineSpacing = lineSpacing; + // kCTParagraphStyleSpecifierLineSpacing -> lineSpacing + // Note that kCTParagraphStyleSpecifierLineSpacing is deprecated and will die soon. We should not be using it. + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierLineSpacing, sizeof(lineSpacing), &lineSpacing)) + newParagraphStyle.lineSpacing = lineSpacing; #pragma clang diagnostic pop #endif + + // Attempt to weakly map the following onto -[NSParagraphStyle lineSpacing]: + // - kCTParagraphStyleSpecifierMinimumLineSpacing + // - kCTParagraphStyleSpecifierMaximumLineSpacing + // - kCTParagraphStyleSpecifierLineSpacingAdjustment + if (fabs(lineSpacing) <= FLT_EPSILON && + CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierMinimumLineSpacing, sizeof(lineSpacing), &lineSpacing)) + newParagraphStyle.lineSpacing = lineSpacing; + + if (fabs(lineSpacing) <= FLT_EPSILON && + CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierMaximumLineSpacing, sizeof(lineSpacing), &lineSpacing)) + newParagraphStyle.lineSpacing = lineSpacing; + + if (fabs(lineSpacing) <= FLT_EPSILON && + CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof(lineSpacing), &lineSpacing)) + newParagraphStyle.lineSpacing = lineSpacing; // kCTParagraphStyleSpecifierParagraphSpacing -> paragraphSpacing CGFloat paragraphSpacing; From 3da014a496c35417fb646f4bf84d3be50b696613 Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Sat, 13 Jan 2018 10:28:38 -0800 Subject: [PATCH 14/20] [AsyncDisplayKit] Update project file to include new/deleted files --- AsyncDisplayKit.xcodeproj/project.pbxproj | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 3a4b1c534..d73d74abc 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -133,9 +133,7 @@ 690C35621E055C5D00069B91 /* ASDimensionInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 690C35601E055C5D00069B91 /* ASDimensionInternal.mm */; }; 690C35641E055C7B00069B91 /* ASDimensionInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 690C35631E055C7B00069B91 /* ASDimensionInternal.h */; settings = {ATTRIBUTES = (Public, ); }; }; 690ED58E1E36BCA6000627C0 /* ASLayoutElementStylePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 690ED58D1E36BCA6000627C0 /* ASLayoutElementStylePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 690ED5961E36D118000627C0 /* ASControlNode+tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 690ED5921E36D118000627C0 /* ASControlNode+tvOS.h */; settings = {ATTRIBUTES = (Private, ); }; }; 690ED5981E36D118000627C0 /* ASControlNode+tvOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 690ED5931E36D118000627C0 /* ASControlNode+tvOS.m */; }; - 690ED5991E36D118000627C0 /* ASImageNode+tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 690ED5941E36D118000627C0 /* ASImageNode+tvOS.h */; settings = {ATTRIBUTES = (Private, ); }; }; 690ED59B1E36D118000627C0 /* ASImageNode+tvOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 690ED5951E36D118000627C0 /* ASImageNode+tvOS.m */; }; 692510141E74FB44003F2DD0 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 692510131E74FB44003F2DD0 /* Default-568h@2x.png */; }; 692BE8D71E36B65B00C86D87 /* ASLayoutSpecPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 692BE8D61E36B65B00C86D87 /* ASLayoutSpecPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -469,6 +467,7 @@ E5E2D72E1EA780C4005C24C6 /* ASCollectionGalleryLayoutDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = E5E2D72D1EA780C4005C24C6 /* ASCollectionGalleryLayoutDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; E5E2D7301EA780DF005C24C6 /* ASCollectionGalleryLayoutDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = E5E2D72F1EA780DF005C24C6 /* ASCollectionGalleryLayoutDelegate.mm */; }; F711994E1D20C21100568860 /* ASDisplayNodeExtrasTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F711994D1D20C21100568860 /* ASDisplayNodeExtrasTests.m */; }; + FA4FAF15200A850200E735BD /* ASControlNode+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = FA4FAF14200A850200E735BD /* ASControlNode+Private.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -663,9 +662,7 @@ 690C35601E055C5D00069B91 /* ASDimensionInternal.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDimensionInternal.mm; sourceTree = ""; }; 690C35631E055C7B00069B91 /* ASDimensionInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDimensionInternal.h; sourceTree = ""; }; 690ED58D1E36BCA6000627C0 /* ASLayoutElementStylePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutElementStylePrivate.h; sourceTree = ""; }; - 690ED5921E36D118000627C0 /* ASControlNode+tvOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASControlNode+tvOS.h"; sourceTree = ""; }; 690ED5931E36D118000627C0 /* ASControlNode+tvOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ASControlNode+tvOS.m"; sourceTree = ""; }; - 690ED5941E36D118000627C0 /* ASImageNode+tvOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASImageNode+tvOS.h"; sourceTree = ""; }; 690ED5951E36D118000627C0 /* ASImageNode+tvOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ASImageNode+tvOS.m"; sourceTree = ""; }; 692510131E74FB44003F2DD0 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 692BE8D61E36B65B00C86D87 /* ASLayoutSpecPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutSpecPrivate.h; sourceTree = ""; }; @@ -970,6 +967,7 @@ E5E2D72F1EA780DF005C24C6 /* ASCollectionGalleryLayoutDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASCollectionGalleryLayoutDelegate.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; F711994D1D20C21100568860 /* ASDisplayNodeExtrasTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDisplayNodeExtrasTests.m; sourceTree = ""; }; + FA4FAF14200A850200E735BD /* ASControlNode+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASControlNode+Private.h"; sourceTree = ""; }; FB07EABBCF28656C6297BC2D /* Pods-AsyncDisplayKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1406,6 +1404,7 @@ CC2E317F1DAC353700EEE891 /* ASCollectionView+Undeprecated.h */, CC0F885A1E42807F00576FED /* ASCollectionViewFlowLayoutInspector.h */, CC0F88591E42807F00576FED /* ASCollectionViewFlowLayoutInspector.m */, + FA4FAF14200A850200E735BD /* ASControlNode+Private.h */, 9F98C0231DBDF2A300476D92 /* ASControlTargetAction.h */, 9F98C0241DBDF2A300476D92 /* ASControlTargetAction.m */, 8B0768B11CE752EC002E1453 /* ASDefaultPlaybackButton.h */, @@ -1513,9 +1512,7 @@ 690ED5911E36D118000627C0 /* tvOS */ = { isa = PBXGroup; children = ( - 690ED5921E36D118000627C0 /* ASControlNode+tvOS.h */, 690ED5931E36D118000627C0 /* ASControlNode+tvOS.m */, - 690ED5941E36D118000627C0 /* ASImageNode+tvOS.h */, 690ED5951E36D118000627C0 /* ASImageNode+tvOS.m */, ); path = tvOS; @@ -1868,6 +1865,7 @@ 9C70F20F1CDBE9FF007D6C76 /* ASLayoutManager.h in Headers */, 6947B0C31E36B5040007C478 /* ASStackPositionedLayout.h in Headers */, DBABFAFC1C6A8D2F0039EA4A /* _ASTransitionContext.h in Headers */, + FA4FAF15200A850200E735BD /* ASControlNode+Private.h in Headers */, B350624F1B010EFD0018CF92 /* ASDisplayNode+DebugTiming.h in Headers */, CC57EAF71E3939350034C595 /* ASCollectionView+Undeprecated.h in Headers */, B35062521B010EFD0018CF92 /* ASDisplayNodeInternal.h in Headers */, @@ -1883,14 +1881,12 @@ DEC146B71C37A16A004A0EE7 /* ASCollectionInternal.h in Headers */, 68B8A4E21CBDB958007E4543 /* ASWeakProxy.h in Headers */, 9F98C0271DBE29FC00476D92 /* ASControlTargetAction.h in Headers */, - 690ED5961E36D118000627C0 /* ASControlNode+tvOS.h in Headers */, 695943401D70815300B0EE1F /* ASDisplayNodeLayout.h in Headers */, 0442850E1BAA64EC00D16268 /* ASTwoDimensionalArrayUtils.h in Headers */, DE8BEAC21C2DF3FC00D57C12 /* ASDelegateProxy.h in Headers */, B350623E1B010EFD0018CF92 /* _ASAsyncTransactionContainer+Private.h in Headers */, AC6145411D8AFAE8003D62A2 /* ASSection.h in Headers */, 8BBBAB8C1CEBAF1700107FC6 /* ASDefaultPlaybackButton.h in Headers */, - 690ED5991E36D118000627C0 /* ASImageNode+tvOS.h in Headers */, 254C6B741BF94DF4003EC431 /* ASTextNodeWordKerner.h in Headers */, 698DFF441E36B6C9002891F1 /* ASStackLayoutSpecUtilities.h in Headers */, CCF18FF41D2575E300DF5895 /* NSIndexSet+ASHelpers.h in Headers */, From fdf22d62a1dfe7597ef015d578a83151c02be3d2 Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Sat, 13 Jan 2018 10:29:20 -0800 Subject: [PATCH 15/20] [ASControlNode+tvOS] Add missing Foundation import (whoops!) [ASImageNode+tvOS] Add missing Foundation import (whoops!) --- Source/tvOS/ASControlNode+tvOS.m | 1 + Source/tvOS/ASImageNode+tvOS.m | 1 + 2 files changed, 2 insertions(+) diff --git a/Source/tvOS/ASControlNode+tvOS.m b/Source/tvOS/ASControlNode+tvOS.m index d145d40ad..77e541862 100644 --- a/Source/tvOS/ASControlNode+tvOS.m +++ b/Source/tvOS/ASControlNode+tvOS.m @@ -15,6 +15,7 @@ // http://www.apache.org/licenses/LICENSE-2.0 // +#import #if TARGET_OS_TV #import #import diff --git a/Source/tvOS/ASImageNode+tvOS.m b/Source/tvOS/ASImageNode+tvOS.m index 2e22754ae..9482fdc8c 100644 --- a/Source/tvOS/ASImageNode+tvOS.m +++ b/Source/tvOS/ASImageNode+tvOS.m @@ -15,6 +15,7 @@ // http://www.apache.org/licenses/LICENSE-2.0 // +#import #if TARGET_OS_TV #import #import From 2d6d0a709ee1c62acc3583852fe16970ba8d5934 Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Sat, 13 Jan 2018 10:30:05 -0800 Subject: [PATCH 16/20] Update podspec to only link AssetsLibrary framework on iOS --- Texture.podspec | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Texture.podspec b/Texture.podspec index e5768d21b..d90148bbc 100644 --- a/Texture.podspec +++ b/Texture.podspec @@ -11,7 +11,9 @@ Pod::Spec.new do |spec| spec.documentation_url = 'http://texturegroup.org/appledoc/' - spec.weak_frameworks = 'Photos','MapKit','AssetsLibrary' + spec.ios.weak_frameworks = 'AssetsLibrary' + spec.weak_frameworks = 'Photos','MapKit' + spec.requires_arc = true spec.ios.deployment_target = '8.0' From c7462f670f47224494774298f439295258b964cc Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Mon, 15 Jan 2018 21:57:01 -0800 Subject: [PATCH 17/20] [ASTextKitCoreTextAdditions] If kCTParagraphStyleAttributeName key-value evaluates to an NSParagraphStyle, pass through to cleansed attributes. This fixes a bug that would occur if a CTParagraphStyle was passed as an attribute _alone_ (would not be caught by unsupported attributes check) --- Source/TextKit/ASTextKitCoreTextAdditions.m | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Source/TextKit/ASTextKitCoreTextAdditions.m b/Source/TextKit/ASTextKitCoreTextAdditions.m index d6022ff08..1dfb0984b 100644 --- a/Source/TextKit/ASTextKitCoreTextAdditions.m +++ b/Source/TextKit/ASTextKitCoreTextAdditions.m @@ -98,8 +98,13 @@ BOOL ASAttributeWithNameIsUnsupportedCoreTextAttribute(NSString *attributeName) cleanAttributes[NSForegroundColorAttributeName] = [UIColor colorWithCGColor:(CGColorRef)coreTextValue]; } // kCTParagraphStyleAttributeName -> NSParagraphStyleAttributeName - else if ([coreTextKey isEqualToString:(NSString *)kCTParagraphStyleAttributeName] && ![coreTextValue isKindOfClass:[NSParagraphStyle class]]) { - cleanAttributes[NSParagraphStyleAttributeName] = [NSParagraphStyle paragraphStyleWithCTParagraphStyle:(CTParagraphStyleRef)coreTextValue]; + else if ([coreTextKey isEqualToString:(NSString *)kCTParagraphStyleAttributeName]) { + if ([coreTextValue isKindOfClass:[NSParagraphStyle class]]) { + cleanAttributes[NSParagraphStyleAttributeName] = (NSParagraphStyle *)coreTextValue; + } + else { + cleanAttributes[NSParagraphStyleAttributeName] = [NSParagraphStyle paragraphStyleWithCTParagraphStyle:(CTParagraphStyleRef)coreTextValue]; + } } // kCTStrokeWidthAttributeName -> NSStrokeWidthAttributeName else if ([coreTextKey isEqualToString:(NSString *)kCTStrokeWidthAttributeName]) { From 91dcb2014a42eaf1f6fb6201bedff109166318de Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Tue, 16 Jan 2018 09:40:44 -0800 Subject: [PATCH 18/20] [ASMultiplexImageNode] Bump availability check to support < Xcode 9 --- Source/ASMultiplexImageNode.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ASMultiplexImageNode.mm b/Source/ASMultiplexImageNode.mm index f2423f483..fef8fd3ea 100644 --- a/Source/ASMultiplexImageNode.mm +++ b/Source/ASMultiplexImageNode.mm @@ -349,7 +349,7 @@ - (void)setDataSource:(id )dataSource _dataSource = dataSource; _dataSourceFlags.image = [_dataSource respondsToSelector:@selector(multiplexImageNode:imageForImageIdentifier:)]; _dataSourceFlags.URL = [_dataSource respondsToSelector:@selector(multiplexImageNode:URLForImageIdentifier:)]; - if (AS_AVAILABLE_IOS_TVOS(8, 10)) { + if (AS_AVAILABLE_IOS_TVOS(9, 10)) { _dataSourceFlags.asset = [_dataSource respondsToSelector:@selector(multiplexImageNode:assetForLocalIdentifier:)]; } } From 305b443810c80cb8d8ac460d5bb78861f195d39f Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Tue, 16 Jan 2018 12:06:26 -0800 Subject: [PATCH 19/20] [ASTraitCollection] Fixes typo that was causing build to fail --- Source/Details/ASTraitCollection.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Details/ASTraitCollection.m b/Source/Details/ASTraitCollection.m index dba756baf..8755fc57c 100644 --- a/Source/Details/ASTraitCollection.m +++ b/Source/Details/ASTraitCollection.m @@ -286,7 +286,7 @@ + (instancetype)traitCollectionWithHorizontalSizeClass:(UIUserInterfaceSizeClass userInterfaceIdiom:userInterfaceIdiom forceTouchCapability:forceTouchCapability layoutDirection:layoutDirection - userInterfaceStyle:userIntefaceStyle + userInterfaceStyle:userInterfaceStyle preferredContentSizeCategory:preferredContentSizeCategory containerSize:windowSize]; } From ebbf5122187892f6dba11cd0bb67947e450e074e Mon Sep 17 00:00:00 2001 From: Alex Hill Date: Fri, 23 Feb 2018 17:58:25 -0800 Subject: [PATCH 20/20] Clean up formatting to adhere to character/line limit + braces --- Source/TextKit/ASTextKitCoreTextAdditions.m | 93 +++++++++++++++++---- 1 file changed, 77 insertions(+), 16 deletions(-) diff --git a/Source/TextKit/ASTextKitCoreTextAdditions.m b/Source/TextKit/ASTextKitCoreTextAdditions.m index 1dfb0984b..7f48aff71 100644 --- a/Source/TextKit/ASTextKitCoreTextAdditions.m +++ b/Source/TextKit/ASTextKitCoreTextAdditions.m @@ -176,8 +176,9 @@ + (instancetype)paragraphStyleWithCTParagraphStyle:(CTParagraphStyleRef)coreText { NSMutableParagraphStyle *newParagraphStyle = [[NSMutableParagraphStyle alloc] init]; - if (!coreTextParagraphStyle) + if (!coreTextParagraphStyle) { return newParagraphStyle; + } // The following paragraph style specifiers are not supported on NSParagraphStyle. Should they become available, we should add them. /* @@ -196,43 +197,75 @@ + (instancetype)paragraphStyleWithCTParagraphStyle:(CTParagraphStyleRef)coreText // kCTParagraphStyleSpecifierAlignment -> alignment CTTextAlignment coreTextAlignment; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierAlignment, sizeof(coreTextAlignment), &coreTextAlignment)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierAlignment, + sizeof(coreTextAlignment), + &coreTextAlignment)) { newParagraphStyle.alignment = NSTextAlignmentFromCTTextAlignment(coreTextAlignment); + } // kCTParagraphStyleSpecifierFirstLineHeadIndent -> firstLineHeadIndent CGFloat firstLineHeadIndent; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierFirstLineHeadIndent, sizeof(firstLineHeadIndent), &firstLineHeadIndent)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierFirstLineHeadIndent, + sizeof(firstLineHeadIndent), + &firstLineHeadIndent)) { newParagraphStyle.firstLineHeadIndent = firstLineHeadIndent; + } // kCTParagraphStyleSpecifierHeadIndent -> headIndent CGFloat headIndent; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierHeadIndent, sizeof(headIndent), &headIndent)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierHeadIndent, + sizeof(headIndent), + &headIndent)) { newParagraphStyle.headIndent = headIndent; + } // kCTParagraphStyleSpecifierTailIndent -> tailIndent CGFloat tailIndent; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierTailIndent, sizeof(tailIndent), &tailIndent)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierTailIndent, + sizeof(tailIndent), + &tailIndent)) { newParagraphStyle.tailIndent = tailIndent; + } // kCTParagraphStyleSpecifierLineBreakMode -> lineBreakMode CTLineBreakMode coreTextLineBreakMode; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierLineBreakMode, sizeof(coreTextLineBreakMode), &coreTextLineBreakMode)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierLineBreakMode, + sizeof(coreTextLineBreakMode), + &coreTextLineBreakMode)) { newParagraphStyle.lineBreakMode = (NSLineBreakMode)coreTextLineBreakMode; // They're the same enum. + } // kCTParagraphStyleSpecifierLineHeightMultiple -> lineHeightMultiple CGFloat lineHeightMultiple; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierLineHeightMultiple, sizeof(lineHeightMultiple), &lineHeightMultiple)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierLineHeightMultiple, + sizeof(lineHeightMultiple), + &lineHeightMultiple)) { newParagraphStyle.lineHeightMultiple = lineHeightMultiple; + } // kCTParagraphStyleSpecifierMaximumLineHeight -> maximumLineHeight CGFloat maximumLineHeight; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierMaximumLineHeight, sizeof(maximumLineHeight), &maximumLineHeight)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierMaximumLineHeight, + sizeof(maximumLineHeight), + &maximumLineHeight)) { newParagraphStyle.maximumLineHeight = maximumLineHeight; + } // kCTParagraphStyleSpecifierMinimumLineHeight -> minimumLineHeight CGFloat minimumLineHeight; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierMinimumLineHeight, sizeof(minimumLineHeight), &minimumLineHeight)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierMinimumLineHeight, + sizeof(minimumLineHeight), + &minimumLineHeight)) { newParagraphStyle.minimumLineHeight = minimumLineHeight; + } CGFloat lineSpacing = 0; #if TARGET_OS_IOS @@ -240,8 +273,12 @@ + (instancetype)paragraphStyleWithCTParagraphStyle:(CTParagraphStyleRef)coreText #pragma clang diagnostic ignored "-Wdeprecated-declarations" // kCTParagraphStyleSpecifierLineSpacing -> lineSpacing // Note that kCTParagraphStyleSpecifierLineSpacing is deprecated and will die soon. We should not be using it. - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierLineSpacing, sizeof(lineSpacing), &lineSpacing)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierLineSpacing, + sizeof(lineSpacing), + &lineSpacing)) { newParagraphStyle.lineSpacing = lineSpacing; + } #pragma clang diagnostic pop #endif @@ -250,31 +287,55 @@ + (instancetype)paragraphStyleWithCTParagraphStyle:(CTParagraphStyleRef)coreText // - kCTParagraphStyleSpecifierMaximumLineSpacing // - kCTParagraphStyleSpecifierLineSpacingAdjustment if (fabs(lineSpacing) <= FLT_EPSILON && - CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierMinimumLineSpacing, sizeof(lineSpacing), &lineSpacing)) + CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierMinimumLineSpacing, + sizeof(lineSpacing), + &lineSpacing)) { newParagraphStyle.lineSpacing = lineSpacing; + } if (fabs(lineSpacing) <= FLT_EPSILON && - CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierMaximumLineSpacing, sizeof(lineSpacing), &lineSpacing)) + CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierMaximumLineSpacing, + sizeof(lineSpacing), + &lineSpacing)) { newParagraphStyle.lineSpacing = lineSpacing; + } if (fabs(lineSpacing) <= FLT_EPSILON && - CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof(lineSpacing), &lineSpacing)) + CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierLineSpacingAdjustment, + sizeof(lineSpacing), + &lineSpacing)) { newParagraphStyle.lineSpacing = lineSpacing; + } // kCTParagraphStyleSpecifierParagraphSpacing -> paragraphSpacing CGFloat paragraphSpacing; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierParagraphSpacing, sizeof(paragraphSpacing), ¶graphSpacing)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierParagraphSpacing, + sizeof(paragraphSpacing), + ¶graphSpacing)) { newParagraphStyle.paragraphSpacing = paragraphSpacing; + } // kCTParagraphStyleSpecifierParagraphSpacingBefore -> paragraphSpacingBefore CGFloat paragraphSpacingBefore; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierParagraphSpacingBefore, sizeof(paragraphSpacingBefore), ¶graphSpacingBefore)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierParagraphSpacingBefore, + sizeof(paragraphSpacingBefore), + ¶graphSpacingBefore)) { newParagraphStyle.paragraphSpacingBefore = paragraphSpacingBefore; + } // kCTParagraphStyleSpecifierBaseWritingDirection -> baseWritingDirection CTWritingDirection coreTextBaseWritingDirection; - if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, kCTParagraphStyleSpecifierBaseWritingDirection, sizeof(coreTextBaseWritingDirection), &coreTextBaseWritingDirection)) + if (CTParagraphStyleGetValueForSpecifier(coreTextParagraphStyle, + kCTParagraphStyleSpecifierBaseWritingDirection, + sizeof(coreTextBaseWritingDirection), + &coreTextBaseWritingDirection)) { newParagraphStyle.baseWritingDirection = (NSWritingDirection)coreTextBaseWritingDirection; // They're the same enum. + } return newParagraphStyle; }