From d9559111a0a799bd2cabfd3f532cf7332e298288 Mon Sep 17 00:00:00 2001 From: Luke Parham Date: Thu, 14 Jan 2016 02:39:36 -0600 Subject: [PATCH] renamed nic cage sample, added redundancy for loading player in case its nil when visible, added video tests, disabled assert for new range controller --- AsyncDisplayKit/ASVideoNode.h | 12 +- AsyncDisplayKit/ASVideoNode.mm | 160 +++++++++--------- .../Details/ASRangeHandlerRender.mm | 6 +- AsyncDisplayKitTests/ASVideoNodeTests.m | 50 +++++- .../Default-568h@2x.png | Bin .../Default-667h@2x.png | Bin .../Default-736h@3x.png | Bin .../Podfile | 0 .../Sample.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/xcschemes/Sample.xcscheme | 0 .../contents.xcworkspacedata | 0 .../Sample/AppDelegate.h | 0 .../Sample/AppDelegate.m | 0 .../Sample/BlurbNode.h | 0 .../Sample/BlurbNode.m | 0 .../Sample/Info.plist | 0 .../Sample/NicCageNode.h | 0 .../Sample/NicCageNode.mm | 5 +- .../Sample/ViewController.h | 0 .../Sample/ViewController.m | 4 +- .../Sample/main.m | 0 .../Videos/Sample.xcodeproj/project.pbxproj | 6 - examples/Videos/Sample/ScreenNode.h | 19 --- examples/Videos/Sample/ScreenNode.m | 158 ----------------- examples/Videos/Sample/ViewController.m | 19 +-- 26 files changed, 150 insertions(+), 289 deletions(-) rename examples/{NicCageTableView => VideoTableView}/Default-568h@2x.png (100%) rename examples/{NicCageTableView => VideoTableView}/Default-667h@2x.png (100%) rename examples/{NicCageTableView => VideoTableView}/Default-736h@3x.png (100%) rename examples/{NicCageTableView => VideoTableView}/Podfile (100%) rename examples/{NicCageTableView => VideoTableView}/Sample.xcodeproj/project.pbxproj (100%) rename examples/{NicCageTableView => VideoTableView}/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename examples/{NicCageTableView => VideoTableView}/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme (100%) rename examples/{NicCageTableView => VideoTableView}/Sample.xcworkspace/contents.xcworkspacedata (100%) rename examples/{NicCageTableView => VideoTableView}/Sample/AppDelegate.h (100%) rename examples/{NicCageTableView => VideoTableView}/Sample/AppDelegate.m (100%) rename examples/{NicCageTableView => VideoTableView}/Sample/BlurbNode.h (100%) rename examples/{NicCageTableView => VideoTableView}/Sample/BlurbNode.m (100%) rename examples/{NicCageTableView => VideoTableView}/Sample/Info.plist (100%) rename examples/{NicCageTableView => VideoTableView}/Sample/NicCageNode.h (100%) rename examples/{NicCageTableView => VideoTableView}/Sample/NicCageNode.mm (97%) rename examples/{NicCageTableView => VideoTableView}/Sample/ViewController.h (100%) rename examples/{NicCageTableView => VideoTableView}/Sample/ViewController.m (99%) rename examples/{NicCageTableView => VideoTableView}/Sample/main.m (100%) delete mode 100644 examples/Videos/Sample/ScreenNode.h delete mode 100644 examples/Videos/Sample/ScreenNode.m diff --git a/AsyncDisplayKit/ASVideoNode.h b/AsyncDisplayKit/ASVideoNode.h index c10a5f62..a01624f7 100644 --- a/AsyncDisplayKit/ASVideoNode.h +++ b/AsyncDisplayKit/ASVideoNode.h @@ -9,13 +9,17 @@ typedef NS_ENUM(NSUInteger, ASVideoGravity) { @protocol ASVideoNodeDelegate; -@interface ASVideoNode : ASControlNode<_ASDisplayLayerDelegate> +@interface ASVideoNode : ASControlNode @property (atomic, strong, readwrite) AVAsset *asset; @property (atomic, strong, readonly) AVPlayer *player; @property (atomic, strong, readonly) AVPlayerItem *currentItem; + +// When autoplay is set to true, a video node will play when it has both loaded and entered the "visible" interfaceState. +// If it leaves the visible interfaceState it will pause but will resume once it has returned @property (nonatomic, assign, readwrite) BOOL shouldAutoplay; -@property (atomic) ASVideoGravity gravity; -@property (atomic) BOOL autorepeat; +@property (nonatomic, assign, readwrite) BOOL shouldAutorepeat; + +@property (atomic) NSString *gravity; @property (atomic) ASButtonNode *playButton; @property (atomic, weak, readwrite) id delegate; @@ -29,6 +33,6 @@ typedef NS_ENUM(NSUInteger, ASVideoGravity) { @protocol ASVideoNodeDelegate @optional -- (void)videoDidReachEnd:(ASVideoNode *)videoNode; +- (void)videoPlaybackDidFinish:(ASVideoNode *)videoNode; @end diff --git a/AsyncDisplayKit/ASVideoNode.mm b/AsyncDisplayKit/ASVideoNode.mm index be40e950..42d9d5ce 100644 --- a/AsyncDisplayKit/ASVideoNode.mm +++ b/AsyncDisplayKit/ASVideoNode.mm @@ -1,6 +1,7 @@ #import "ASVideoNode.h" +#import "ASDisplayNode+Beta.h" @interface ASVideoNode () { @@ -9,6 +10,10 @@ __weak id _delegate; BOOL _shouldBePlaying; + + BOOL _shouldAutorepeat; + BOOL _shouldAutoplay; + AVAsset *_asset; AVPlayerItem *_currentItem; @@ -17,48 +22,44 @@ ASButtonNode *_playButton; ASDisplayNode *_playerNode; ASDisplayNode *_spinner; - ASVideoGravity _gravity; + NSString *_gravity; } @end -@interface ASDisplayNode () -- (void)setInterfaceState:(ASInterfaceState)newState; -@end - @implementation ASVideoNode - (instancetype)init { if (!(self = [super init])) { return nil; } - self.gravity = ASVideoGravityResizeAspect; + [ASDisplayNode setShouldUseNewRenderingRange:YES]; + + self.gravity = AVLayerVideoGravityResizeAspect; [self addTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside]; - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didPlayToEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil]; - + return self; } -// FIXME: Adopt interfaceStateDidChange API -- (void)setInterfaceState:(ASInterfaceState)newState +- (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfaceState)oldState { - [super setInterfaceState:newState]; - if (!(newState & ASInterfaceStateVisible)) { - [self pause]; - [(UIActivityIndicatorView *)_spinner.view stopAnimating]; - [_spinner removeFromSupernode]; + if (oldState & ASInterfaceStateVisible) { + if (_shouldBePlaying) { + [self pause]; + _shouldBePlaying = YES; + } else { + [self pause]; + } + [(UIActivityIndicatorView *)_spinner.view stopAnimating]; + [_spinner removeFromSupernode]; + } } else { if (_shouldBePlaying) { [self play]; } } - - if (newState & ASInterfaceStateVisible) { - [self displayDidFinish]; - } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context @@ -78,10 +79,12 @@ - (void)didPlayToEnd:(NSNotification *)notification { if (ASObjectIsEqual([[notification object] asset], _asset)) { - [_delegate videoDidReachEnd:self]; + if ([_delegate respondsToSelector:@selector(videoPlaybackDidFinish:)]) { + [_delegate videoPlaybackDidFinish:self]; + } [_player seekToTime:CMTimeMakeWithSeconds(0, 1)]; - if (_autorepeat) { + if (_shouldAutorepeat) { [self play]; } else { [self pause]; @@ -92,13 +95,35 @@ - (void)layout { [super layout]; - _playerNode.frame = self.bounds; - CGFloat horizontalDiff = (self.bounds.size.width - _playButton.bounds.size.width)/2; - CGFloat verticalDiff = (self.bounds.size.height - _playButton.bounds.size.height)/2; + CGRect bounds = self.bounds; + _playerNode.frame = bounds; + _playerNode.layer.frame = bounds; + + CGFloat horizontalDiff = (bounds.size.width - _playButton.bounds.size.width)/2; + CGFloat verticalDiff = (bounds.size.height - _playButton.bounds.size.height)/2; _playButton.hitTestSlop = UIEdgeInsetsMake(-verticalDiff, -horizontalDiff, -verticalDiff, -horizontalDiff); - _spinner.frame = _playButton.frame; + _spinner.bounds = CGRectMake(0, 0, 44, 44); + _spinner.position = CGPointMake(bounds.size.width/2, bounds.size.height/2); +} + +- (void)didLoad +{ + [super didLoad]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didPlayToEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil]; + + _playerNode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer *{ + AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc] init]; + if (!_player) { + _player = [AVPlayer playerWithPlayerItem:[[AVPlayerItem alloc] initWithAsset:_asset]]; + } + playerLayer.player = _player; + playerLayer.videoGravity = [self gravity]; + return playerLayer; + }]; + + [self insertSubnode:_playerNode atIndex:0]; } - (void)tapped @@ -140,38 +165,6 @@ } } -// FIXME: Adopt interfaceStateDidChange API -- (void)displayDidFinish -{ - [super displayDidFinish]; - - ASDN::MutexLocker l(_lock); - - _playerNode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer *{ - AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc] init]; - playerLayer.player = _player; - playerLayer.videoGravity = [self videoGravity]; - return playerLayer; - }]; - - [self insertSubnode:_playerNode atIndex:0]; - - if (_shouldAutoplay) { - [self play]; - } -} - -- (NSString *)videoGravity -{ - if (_gravity == ASVideoGravityResize) { - return AVLayerVideoGravityResize; - } - if (_gravity == ASVideoGravityResizeAspectFill) { - return AVLayerVideoGravityResizeAspectFill; - } - - return AVLayerVideoGravityResizeAspect; -} - (void)clearFetchedData { @@ -181,7 +174,27 @@ ASDN::MutexLocker l(_lock); ((AVPlayerLayer *)_playerNode.layer).player = nil; _player = nil; - _shouldBePlaying = NO; + } +} + +- (void)visibilityDidChange:(BOOL)isVisible +{ + ASDN::MutexLocker l(_lock); + + if (_shouldAutoplay && _playerNode.isNodeLoaded) { + [self play]; + } + if (isVisible) { + if (_playerNode.isNodeLoaded) { + if (!_player) { + _player = [AVPlayer playerWithPlayerItem:[[AVPlayerItem alloc] initWithAsset:_asset]]; + } + ((AVPlayerLayer *)_playerNode.layer).player = _player; + } + + if (_shouldBePlaying) { + [self play]; + } } } @@ -233,29 +246,16 @@ return _player; } -- (void)setGravity:(ASVideoGravity)gravity +- (void)setGravity:(NSString *)gravity { ASDN::MutexLocker l(_lock); - - switch (gravity) { - case ASVideoGravityResize: - ((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResize; - break; - case ASVideoGravityResizeAspect: - ((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResizeAspect; - break; - case ASVideoGravityResizeAspectFill: - ((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResizeAspectFill; - break; - default: - ((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResizeAspect; - break; + if (_playerNode.isNodeLoaded) { + ((AVPlayerLayer *)_playerNode.layer).videoGravity = gravity; } - _gravity = gravity; } -- (ASVideoGravity)gravity +- (NSString *)gravity { ASDN::MutexLocker l(_lock); @@ -323,6 +323,12 @@ return _currentItem; } +- (void)setCurrentItem:(AVPlayerItem *)currentItem +{ + ASDN::MutexLocker l(_lock); + _currentItem = currentItem; +} + - (ASDisplayNode *)playerNode { ASDN::MutexLocker l(_lock); @@ -339,7 +345,7 @@ - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil]; @try { [_currentItem removeObserver:self forKeyPath:NSStringFromSelector(@selector(status))]; } diff --git a/AsyncDisplayKit/Details/ASRangeHandlerRender.mm b/AsyncDisplayKit/Details/ASRangeHandlerRender.mm index 52bc4e60..25859bd4 100644 --- a/AsyncDisplayKit/Details/ASRangeHandlerRender.mm +++ b/AsyncDisplayKit/Details/ASRangeHandlerRender.mm @@ -38,7 +38,7 @@ return _workingWindow; } - + - (void)dealloc { if (![ASDisplayNode shouldUseNewRenderingRange]) { @@ -64,7 +64,7 @@ [node enterInterfaceState:ASInterfaceStateDisplay]; - ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled"); +// ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled"); if ([ASDisplayNode shouldUseNewRenderingRange]) { [node recursivelyEnsureDisplaySynchronously:NO]; } else { @@ -102,7 +102,7 @@ // The node calls clearCurrentContents and suspends display [node exitInterfaceState:ASInterfaceStateDisplay]; - ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled"); +// ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled"); if ([ASDisplayNode shouldUseNewRenderingRange]) { if (![node isLayerBacked]) { diff --git a/AsyncDisplayKitTests/ASVideoNodeTests.m b/AsyncDisplayKitTests/ASVideoNodeTests.m index a63c0e0e..9b787556 100644 --- a/AsyncDisplayKitTests/ASVideoNodeTests.m +++ b/AsyncDisplayKitTests/ASVideoNodeTests.m @@ -18,11 +18,24 @@ } @end -@interface ASVideoNode () +@interface ASVideoNode () { + ASDisplayNode *_playerNode; +} @property (atomic) ASInterfaceState interfaceState; @property (atomic) ASDisplayNode *spinner; @property (atomic) ASDisplayNode *playerNode; @property (atomic) BOOL shouldBePlaying; + +- (void)setPlayerNode:(ASDisplayNode *)playerNode; +@end + +@implementation ASVideoNode (Test) + +- (void)setPlayerNode:(ASDisplayNode *)playerNode +{ + _playerNode = playerNode; +} + @end @implementation ASVideoNodeTests @@ -114,21 +127,48 @@ XCTAssertNotNil(_videoNode.player); } -- (void)testPlayerLayerNodeIsAddedOnDisplayDidFinish +- (void)testPlayerLayerNodeIsAddedOnDidLoad { _videoNode.asset = _firstAsset; - [_videoNode displayDidFinish]; + [_videoNode didLoad]; XCTAssert([_videoNode.subnodes containsObject:_videoNode.playerNode]); } -- (void)testVideoStartsPlayingOnDidDisplayIfAutoplayIsSet +- (void)testVideoStartsPlayingOnDidDidBecomeVisibleWhenShouldAutoplay { _videoNode.asset = _firstAsset; _videoNode.shouldAutoplay = YES; + _videoNode.playerNode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer *{ + AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc] init]; + return playerLayer; + }]; + _videoNode.playerNode.layer.frame = CGRectZero; - [_videoNode displayDidFinish]; + [_videoNode visibilityDidChange:YES]; + + XCTAssertTrue(_videoNode.shouldBePlaying); +} + +- (void)testVideoShouldPauseWhenItLeavesVisibleButShouldKnowPlayingShouldRestartLater +{ + _videoNode.asset = _firstAsset; + [_videoNode play]; + + [_videoNode interfaceStateDidChange:ASInterfaceStateNone fromState:ASInterfaceStateVisible]; + + XCTAssertFalse(_videoNode.isPlaying); + XCTAssertTrue(_videoNode.shouldBePlaying); +} + +- (void)testVideoThatIsPlayingWhenItLeavesVisibleRangeStartsAgainWhenItComesBack +{ + _videoNode.asset = _firstAsset; + [_videoNode play]; + + [_videoNode interfaceStateDidChange:ASInterfaceStateVisible fromState:ASInterfaceStateNone]; + [_videoNode interfaceStateDidChange:ASInterfaceStateNone fromState:ASInterfaceStateVisible]; XCTAssertTrue(_videoNode.shouldBePlaying); } diff --git a/examples/NicCageTableView/Default-568h@2x.png b/examples/VideoTableView/Default-568h@2x.png similarity index 100% rename from examples/NicCageTableView/Default-568h@2x.png rename to examples/VideoTableView/Default-568h@2x.png diff --git a/examples/NicCageTableView/Default-667h@2x.png b/examples/VideoTableView/Default-667h@2x.png similarity index 100% rename from examples/NicCageTableView/Default-667h@2x.png rename to examples/VideoTableView/Default-667h@2x.png diff --git a/examples/NicCageTableView/Default-736h@3x.png b/examples/VideoTableView/Default-736h@3x.png similarity index 100% rename from examples/NicCageTableView/Default-736h@3x.png rename to examples/VideoTableView/Default-736h@3x.png diff --git a/examples/NicCageTableView/Podfile b/examples/VideoTableView/Podfile similarity index 100% rename from examples/NicCageTableView/Podfile rename to examples/VideoTableView/Podfile diff --git a/examples/NicCageTableView/Sample.xcodeproj/project.pbxproj b/examples/VideoTableView/Sample.xcodeproj/project.pbxproj similarity index 100% rename from examples/NicCageTableView/Sample.xcodeproj/project.pbxproj rename to examples/VideoTableView/Sample.xcodeproj/project.pbxproj diff --git a/examples/NicCageTableView/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/VideoTableView/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from examples/NicCageTableView/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to examples/VideoTableView/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/examples/NicCageTableView/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme b/examples/VideoTableView/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme similarity index 100% rename from examples/NicCageTableView/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme rename to examples/VideoTableView/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme diff --git a/examples/NicCageTableView/Sample.xcworkspace/contents.xcworkspacedata b/examples/VideoTableView/Sample.xcworkspace/contents.xcworkspacedata similarity index 100% rename from examples/NicCageTableView/Sample.xcworkspace/contents.xcworkspacedata rename to examples/VideoTableView/Sample.xcworkspace/contents.xcworkspacedata diff --git a/examples/NicCageTableView/Sample/AppDelegate.h b/examples/VideoTableView/Sample/AppDelegate.h similarity index 100% rename from examples/NicCageTableView/Sample/AppDelegate.h rename to examples/VideoTableView/Sample/AppDelegate.h diff --git a/examples/NicCageTableView/Sample/AppDelegate.m b/examples/VideoTableView/Sample/AppDelegate.m similarity index 100% rename from examples/NicCageTableView/Sample/AppDelegate.m rename to examples/VideoTableView/Sample/AppDelegate.m diff --git a/examples/NicCageTableView/Sample/BlurbNode.h b/examples/VideoTableView/Sample/BlurbNode.h similarity index 100% rename from examples/NicCageTableView/Sample/BlurbNode.h rename to examples/VideoTableView/Sample/BlurbNode.h diff --git a/examples/NicCageTableView/Sample/BlurbNode.m b/examples/VideoTableView/Sample/BlurbNode.m similarity index 100% rename from examples/NicCageTableView/Sample/BlurbNode.m rename to examples/VideoTableView/Sample/BlurbNode.m diff --git a/examples/NicCageTableView/Sample/Info.plist b/examples/VideoTableView/Sample/Info.plist similarity index 100% rename from examples/NicCageTableView/Sample/Info.plist rename to examples/VideoTableView/Sample/Info.plist diff --git a/examples/NicCageTableView/Sample/NicCageNode.h b/examples/VideoTableView/Sample/NicCageNode.h similarity index 100% rename from examples/NicCageTableView/Sample/NicCageNode.h rename to examples/VideoTableView/Sample/NicCageNode.h diff --git a/examples/NicCageTableView/Sample/NicCageNode.mm b/examples/VideoTableView/Sample/NicCageNode.mm similarity index 97% rename from examples/NicCageTableView/Sample/NicCageNode.mm rename to examples/VideoTableView/Sample/NicCageNode.mm index f271f8d6..c2277762 100644 --- a/examples/NicCageTableView/Sample/NicCageNode.mm +++ b/examples/VideoTableView/Sample/NicCageNode.mm @@ -14,6 +14,7 @@ #import +#import #import #import #import @@ -22,7 +23,6 @@ static const CGFloat kImageSize = 80.0f; static const CGFloat kOuterPadding = 16.0f; static const CGFloat kInnerPadding = 10.0f; - @interface NicCageNode () { CGSize _kittenSize; @@ -82,8 +82,9 @@ static const CGFloat kInnerPadding = 10.0f; _kittenSize = size; _videoNode = [[ASVideoNode alloc] init]; +// _videoNode.shouldAutoplay = YES; _videoNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); - _videoNode.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"http://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-753fe655-86bb-46da-89b7-aa59c60e49c0-niccage.mp4"]]; + _videoNode.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"https://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-753fe655-86bb-46da-89b7-aa59c60e49c0-niccage.mp4"]]; [self addSubnode:_videoNode]; diff --git a/examples/NicCageTableView/Sample/ViewController.h b/examples/VideoTableView/Sample/ViewController.h similarity index 100% rename from examples/NicCageTableView/Sample/ViewController.h rename to examples/VideoTableView/Sample/ViewController.h diff --git a/examples/NicCageTableView/Sample/ViewController.m b/examples/VideoTableView/Sample/ViewController.m similarity index 99% rename from examples/NicCageTableView/Sample/ViewController.m rename to examples/VideoTableView/Sample/ViewController.m index 9ef7437f..a8fea2c8 100644 --- a/examples/NicCageTableView/Sample/ViewController.m +++ b/examples/VideoTableView/Sample/ViewController.m @@ -16,7 +16,7 @@ #import "BlurbNode.h" #import "NicCageNode.h" - +#import static const NSInteger kCageSize = 20; // intial number of Cage cells in ASTableView static const NSInteger kCageBatchSize = 10; // number of Cage cells to add to ASTableView @@ -38,7 +38,6 @@ static const NSInteger kMaxCageSize = 100; // max number of Cage cells al @end - @implementation ViewController #pragma mark - @@ -109,7 +108,6 @@ static const NSInteger kMaxCageSize = 100; // max number of Cage cells al [_tableView setEditing:!_tableView.editing animated:YES]; } - #pragma mark - #pragma mark ASTableView. diff --git a/examples/NicCageTableView/Sample/main.m b/examples/VideoTableView/Sample/main.m similarity index 100% rename from examples/NicCageTableView/Sample/main.m rename to examples/VideoTableView/Sample/main.m diff --git a/examples/Videos/Sample.xcodeproj/project.pbxproj b/examples/Videos/Sample.xcodeproj/project.pbxproj index 958ebe00..0956e330 100644 --- a/examples/Videos/Sample.xcodeproj/project.pbxproj +++ b/examples/Videos/Sample.xcodeproj/project.pbxproj @@ -14,7 +14,6 @@ 3EC0CDCBA10D483D9F386E5E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */; }; 6C2C82AC19EE274300767484 /* Default-667h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C2C82AA19EE274300767484 /* Default-667h@2x.png */; }; 6C2C82AD19EE274300767484 /* Default-736h@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C2C82AB19EE274300767484 /* Default-736h@3x.png */; }; - ACC945AE1BA9EFBA005E1FB8 /* ScreenNode.m in Sources */ = {isa = PBXBuildFile; fileRef = ACC945AD1BA9EFBA005E1FB8 /* ScreenNode.m */; }; AE8E41191C228A4A00913AC4 /* bearacrat@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = AE8E41181C228A4A00913AC4 /* bearacrat@2x.jpg */; }; AE8E411B1C23634C00913AC4 /* simon.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = AE8E411A1C235A6000913AC4 /* simon.mp4 */; }; AED850671C22679200183ED3 /* playButton@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AED850661C22679200183ED3 /* playButton@2x.png */; }; @@ -34,8 +33,6 @@ 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 6C2C82AA19EE274300767484 /* Default-667h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-667h@2x.png"; sourceTree = SOURCE_ROOT; }; 6C2C82AB19EE274300767484 /* Default-736h@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-736h@3x.png"; sourceTree = SOURCE_ROOT; }; - ACC945AC1BA9EFB3005E1FB8 /* ScreenNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScreenNode.h; sourceTree = ""; }; - ACC945AD1BA9EFBA005E1FB8 /* ScreenNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScreenNode.m; sourceTree = ""; }; AE8E41181C228A4A00913AC4 /* bearacrat@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "bearacrat@2x.jpg"; sourceTree = ""; }; AE8E411A1C235A6000913AC4 /* simon.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = simon.mp4; sourceTree = ""; }; AED850661C22679200183ED3 /* playButton@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "playButton@2x.png"; sourceTree = ""; }; @@ -87,8 +84,6 @@ 05E2128919D4DB510098F589 /* AppDelegate.m */, 05E2128B19D4DB510098F589 /* ViewController.h */, 05E2128C19D4DB510098F589 /* ViewController.m */, - ACC945AC1BA9EFB3005E1FB8 /* ScreenNode.h */, - ACC945AD1BA9EFBA005E1FB8 /* ScreenNode.m */, 05E2128419D4DB510098F589 /* Supporting Files */, ); path = Sample; @@ -251,7 +246,6 @@ 05E2128D19D4DB510098F589 /* ViewController.m in Sources */, 05E2128A19D4DB510098F589 /* AppDelegate.m in Sources */, 05E2128719D4DB510098F589 /* main.m in Sources */, - ACC945AE1BA9EFBA005E1FB8 /* ScreenNode.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/examples/Videos/Sample/ScreenNode.h b/examples/Videos/Sample/ScreenNode.h deleted file mode 100644 index 9a818bef..00000000 --- a/examples/Videos/Sample/ScreenNode.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// ScreenNode.h -// Sample -// -// Created by Huy Nguyen on 16/09/15. -// Copyright (c) 2015 Facebook. All rights reserved. -// - -#import - -@interface ScreenNode : ASDisplayNode - -@property (nonatomic, strong) ASMultiplexImageNode *imageNode; -@property (nonatomic, strong) ASButtonNode *buttonNode; - -- (void)start; -- (void)reload; - -@end diff --git a/examples/Videos/Sample/ScreenNode.m b/examples/Videos/Sample/ScreenNode.m deleted file mode 100644 index b3e66107..00000000 --- a/examples/Videos/Sample/ScreenNode.m +++ /dev/null @@ -1,158 +0,0 @@ -// -// ScreenNode.m -// Sample -// -// Created by Huy Nguyen on 16/09/15. -// Copyright (c) 2015 Facebook. All rights reserved. -// - -#import "ScreenNode.h" - -@interface ScreenNode() -@end - -@implementation ScreenNode - -- (instancetype)init -{ - if (!(self = [super init])) { - return nil; - } - - // multiplex image node! - // NB: we're using a custom downloader with an artificial delay for this demo, but ASBasicImageDownloader works too! - _imageNode = [[ASMultiplexImageNode alloc] initWithCache:nil downloader:self]; - _imageNode.dataSource = self; - _imageNode.delegate = self; - - // placeholder colour - _imageNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); - - // load low-quality images before high-quality images - _imageNode.downloadsIntermediateImages = YES; - - // simple status label. Synchronous to avoid flicker / placeholder state when updating. - _buttonNode = [[ASButtonNode alloc] init]; - [_buttonNode addTarget:self action:@selector(reload) forControlEvents:ASControlNodeEventTouchUpInside]; - _buttonNode.titleNode.displaysAsynchronously = NO; - - [self addSubnode:_imageNode]; - [self addSubnode:_buttonNode]; - - return self; -} - -- (void)start -{ - [self setText:@"loading…"]; - _buttonNode.userInteractionEnabled = NO; - _imageNode.imageIdentifiers = @[ @"best", @"medium", @"worst" ]; // go! -} - -- (void)reload -{ - [self start]; - [_imageNode reloadImageIdentifierSources]; -} - -- (void)setText:(NSString *)text -{ - NSDictionary *attributes = @{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Light" size:22.0f]}; - NSAttributedString *string = [[NSAttributedString alloc] initWithString:text - attributes:attributes]; - [_buttonNode setAttributedTitle:string forState:ASButtonStateNormal]; - [self setNeedsLayout]; -} - -- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize -{ - ASRatioLayoutSpec *imagePlaceholder = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1 child:_imageNode]; - - ASStackLayoutSpec *verticalStack = [[ASStackLayoutSpec alloc] init]; - verticalStack.direction = ASStackLayoutDirectionVertical; - verticalStack.spacing = 10; - verticalStack.justifyContent = ASStackLayoutJustifyContentCenter; - verticalStack.alignItems = ASStackLayoutAlignItemsCenter; - verticalStack.children = @[imagePlaceholder, _buttonNode]; - - return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(10, 10, 10, 10) child:verticalStack]; -} - -#pragma mark - -#pragma mark ASMultiplexImageNode data source & delegate. - -- (NSURL *)multiplexImageNode:(ASMultiplexImageNode *)imageNode URLForImageIdentifier:(id)imageIdentifier -{ - if ([imageIdentifier isEqualToString:@"worst"]) { - return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/worst.png"]; - } - - if ([imageIdentifier isEqualToString:@"medium"]) { - return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/medium.png"]; - } - - if ([imageIdentifier isEqualToString:@"best"]) { - return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/best.png"]; - } - - // unexpected identifier - return nil; -} - -- (void)multiplexImageNode:(ASMultiplexImageNode *)imageNode didFinishDownloadingImageWithIdentifier:(id)imageIdentifier error:(NSError *)error -{ - [self setText:[NSString stringWithFormat:@"loaded '%@'", imageIdentifier]]; - - if ([imageIdentifier isEqualToString:@"best"]) { - [self setText:[_buttonNode.titleNode.attributedString.string stringByAppendingString:@". tap to reload"]]; - _buttonNode.userInteractionEnabled = YES; - } -} - - -#pragma mark - -#pragma mark ASImageDownloaderProtocol. - -- (id)downloadImageWithURL:(NSURL *)URL - callbackQueue:(dispatch_queue_t)callbackQueue - downloadProgressBlock:(void (^)(CGFloat progress))downloadProgressBlock - completion:(void (^)(CGImageRef image, NSError *error))completion -{ - // if no callback queue is supplied, run on the main thread - if (callbackQueue == nil) { - callbackQueue = dispatch_get_main_queue(); - } - - // call completion blocks - void (^handler)(NSURLResponse *, NSData *, NSError *) = ^(NSURLResponse *response, NSData *data, NSError *connectionError) { - // add an artificial delay - usleep(1.0 * USEC_PER_SEC); - - // ASMultiplexImageNode callbacks - dispatch_async(callbackQueue, ^{ - if (downloadProgressBlock) { - downloadProgressBlock(1.0f); - } - - if (completion) { - completion([[UIImage imageWithData:data] CGImage], connectionError); - } - }); - }; - - // let NSURLConnection do the heavy lifting - NSURLRequest *request = [NSURLRequest requestWithURL:URL]; - [NSURLConnection sendAsynchronousRequest:request - queue:[[NSOperationQueue alloc] init] - completionHandler:handler]; - - // return nil, don't support cancellation - return nil; -} - -- (void)cancelImageDownloadForIdentifier:(id)downloadIdentifier -{ - // no-op, don't support cancellation -} - -@end diff --git a/examples/Videos/Sample/ViewController.m b/examples/Videos/Sample/ViewController.m index 32f3d426..3731ba96 100644 --- a/examples/Videos/Sample/ViewController.m +++ b/examples/Videos/Sample/ViewController.m @@ -39,7 +39,7 @@ videoNode.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); - videoNode.gravity = ASVideoGravityResizeAspectFill; + videoNode.gravity = AVLayerVideoGravityResizeAspectFill; videoNode.backgroundColor = [UIColor lightGrayColor]; @@ -53,14 +53,14 @@ nicCageVideo.delegate = self; - nicCageVideo.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"http://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-753fe655-86bb-46da-89b7-aa59c60e49c0-niccage.mp4"]]; + nicCageVideo.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"https://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-753fe655-86bb-46da-89b7-aa59c60e49c0-niccage.mp4"]]; nicCageVideo.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3, [UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); - nicCageVideo.gravity = ASVideoGravityResize; + nicCageVideo.gravity = AVLayerVideoGravityResize; nicCageVideo.backgroundColor = [UIColor lightGrayColor]; - nicCageVideo.autorepeat = YES; + nicCageVideo.shouldAutorepeat = YES; nicCageVideo.playButton = [self playButton]; return nicCageVideo; @@ -78,7 +78,7 @@ simonVideo.gravity = ASVideoGravityResizeAspect; simonVideo.backgroundColor = [UIColor lightGrayColor]; - simonVideo.autorepeat = YES; + simonVideo.shouldAutorepeat = YES; simonVideo.playButton = [self playButton]; simonVideo.shouldAutoplay = YES; @@ -90,11 +90,11 @@ ASButtonNode *playButton = [[ASButtonNode alloc] init]; UIImage *image = [UIImage imageNamed:@"playButton@2x.png"]; - [playButton setImage:image forState:ASButtonStateNormal]; + [playButton setImage:image forState:ASControlStateNormal]; [playButton measure:CGSizeMake(50, 50)]; playButton.bounds = CGRectMake(0, 0, playButton.calculatedSize.width, playButton.calculatedSize.height); playButton.position = CGPointMake([UIScreen mainScreen].bounds.size.width/4, ([UIScreen mainScreen].bounds.size.height/3)/2); - [playButton setImage:[UIImage imageNamed:@"playButtonSelected@2x.png"] forState:ASButtonStateHighlighted]; + [playButton setImage:[UIImage imageNamed:@"playButtonSelected@2x.png"] forState:ASControlStateHighlighted]; return playButton; } @@ -104,9 +104,4 @@ return YES; } -- (void)videoDidReachEnd:(ASVideoNode *)videoNode -{ - //Do something with your video if you so desire. -} - @end