diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 3569f18eee..8d5e02ea5d 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -339,8 +339,6 @@ 9F06E5CD1B4CAF4200F015D8 /* ASCollectionViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.m */; }; A2763D791CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */; }; A2763D7A1CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */; }; - A2763D7B1CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = A2763D781CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.m */; }; - A2763D7C1CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = A2763D781CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.m */; }; A32FEDD51C501B6A004F642A /* ASTextKitFontSizeAdjuster.h in Headers */ = {isa = PBXBuildFile; fileRef = A32FEDD31C501B6A004F642A /* ASTextKitFontSizeAdjuster.h */; settings = {ATTRIBUTES = (Public, ); }; }; A373200F1C571B730011FC94 /* ASTextNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = A373200E1C571B050011FC94 /* ASTextNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; A37320101C571B740011FC94 /* ASTextNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = A373200E1C571B050011FC94 /* ASTextNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -751,7 +749,7 @@ 257754BB1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitCoreTextAdditions.h; path = TextKit/ASTextKitCoreTextAdditions.h; sourceTree = ""; }; 257754BC1BEE458E00737CA5 /* ASTextNodeTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextNodeTypes.h; path = TextKit/ASTextNodeTypes.h; sourceTree = ""; }; 257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASTextNodeWordKerner.m; path = TextKit/ASTextNodeWordKerner.m; sourceTree = ""; }; - 25E327541C16819500A2170C /* ASPagerNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASPagerNode.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 25E327541C16819500A2170C /* ASPagerNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASPagerNode.h; sourceTree = ""; }; 25E327551C16819500A2170C /* ASPagerNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ASPagerNode.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 2911485B1A77147A005D0878 /* ASControlNodeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASControlNodeTests.m; sourceTree = ""; }; 292C59991A956527007E5DD6 /* ASLayoutRangeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutRangeType.h; sourceTree = ""; }; diff --git a/AsyncDisplayKit/ASVideoNode.mm b/AsyncDisplayKit/ASVideoNode.mm index ad417115e7..6d572ce113 100644 --- a/AsyncDisplayKit/ASVideoNode.mm +++ b/AsyncDisplayKit/ASVideoNode.mm @@ -28,6 +28,7 @@ static UIViewContentMode ASContentModeFromVideoGravity(NSString *videoGravity) { static void *ASVideoNodeContext = &ASVideoNodeContext; static NSString * const kPlaybackLikelyToKeepUpKey = @"playbackLikelyToKeepUp"; +static NSString * const kplaybackBufferEmpty = @"playbackBufferEmpty"; static NSString * const kStatus = @"status"; @interface ASVideoNode () @@ -121,6 +122,7 @@ static NSString * const kStatus = @"status"; { [playerItem addObserver:self forKeyPath:kStatus options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:ASVideoNodeContext]; [playerItem addObserver:self forKeyPath:kPlaybackLikelyToKeepUpKey options:NSKeyValueObservingOptionNew context:ASVideoNodeContext]; + [playerItem addObserver:self forKeyPath:kplaybackBufferEmpty options:NSKeyValueObservingOptionNew context:ASVideoNodeContext]; NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter addObserver:self selector:@selector(didPlayToEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem]; @@ -133,6 +135,7 @@ static NSString * const kStatus = @"status"; @try { [playerItem removeObserver:self forKeyPath:kStatus context:ASVideoNodeContext]; [playerItem removeObserver:self forKeyPath:kPlaybackLikelyToKeepUpKey context:ASVideoNodeContext]; + [playerItem removeObserver:self forKeyPath:kplaybackBufferEmpty context:ASVideoNodeContext]; } @catch (NSException * __unused exception) { NSLog(@"Unnecessary KVO removal"); @@ -236,8 +239,7 @@ static NSString * const kStatus = @"status"; if ([keyPath isEqualToString:kStatus]) { if ([change[NSKeyValueChangeNewKey] integerValue] == AVPlayerItemStatusReadyToPlay) { - [_spinner removeFromSupernode]; - _spinner = nil; + [self removeSpinner]; // If we don't yet have a placeholder image update it now that we should have data available for it if (_placeholderImageNode.image == nil) { [self generatePlaceholderImage]; @@ -250,6 +252,10 @@ static NSString * const kStatus = @"status"; if (_shouldBePlaying && [change[NSKeyValueChangeNewKey] boolValue] == true && ASInterfaceStateIncludesVisible(self.interfaceState)) { [self play]; // autoresume after buffer catches up } + } else if ([keyPath isEqualToString:kplaybackBufferEmpty]) { + if (_shouldBePlaying && [change[NSKeyValueChangeNewKey] boolValue] == true && ASInterfaceStateIncludesVisible(self.interfaceState)) { + [self showSpinner]; // show spinner and set ASVideoNodePlayerStateLoading + } } } @@ -471,19 +477,9 @@ static NSString * const kStatus = @"status"; _playButton.alpha = 0.0; }]; if (![self ready]) { - if (!_spinner) { - _spinner = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{ - UIActivityIndicatorView *spinnnerView = [[UIActivityIndicatorView alloc] init]; - spinnnerView.color = [UIColor whiteColor]; - - return spinnnerView; - }]; - - [self addSubnode:_spinner]; - } - self.playerState = ASVideoNodePlayerStateLoading; - [(UIActivityIndicatorView *)_spinner.view startAnimating]; + [self showSpinner]; }else{ + [self removeSpinner]; self.playerState = ASVideoNodePlayerStatePlaying; } } @@ -493,6 +489,35 @@ static NSString * const kStatus = @"status"; return _currentPlayerItem.status == AVPlayerItemStatusReadyToPlay; } +- (void)showSpinner +{ + ASDN::MutexLocker l(_videoLock); + + if (!_spinner) { + _spinner = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{ + UIActivityIndicatorView *spinnnerView = [[UIActivityIndicatorView alloc] init]; + spinnnerView.color = [UIColor whiteColor]; + + return spinnnerView; + }]; + + [self addSubnode:_spinner]; + } + self.playerState = ASVideoNodePlayerStateLoading; + [(UIActivityIndicatorView *)_spinner.view startAnimating]; +} + +- (void)removeSpinner +{ + ASDN::MutexLocker l(_videoLock); + + if(!_spinner) { + return; + } + [_spinner removeFromSupernode]; + _spinner = nil; +} + - (void)pause { ASDN::MutexLocker l(_videoLock); @@ -501,7 +526,7 @@ static NSString * const kStatus = @"status"; } self.playerState = ASVideoNodePlayerStatePaused; [_player pause]; - [((UIActivityIndicatorView *)_spinner.view) stopAnimating]; + [self removeSpinner]; _shouldBePlaying = NO; [UIView animateWithDuration:0.15 animations:^{ _playButton.alpha = 1.0; diff --git a/examples/Videos/Sample/ViewController.m b/examples/Videos/Sample/ViewController.m index 159f3ac53b..b78845e1c3 100644 --- a/examples/Videos/Sample/ViewController.m +++ b/examples/Videos/Sample/ViewController.m @@ -110,6 +110,8 @@ if(videoNode == self.guitarVideoNode){ if(videoNode.playerState == ASVideoNodePlayerStatePlaying){ [videoNode pause]; + }else if(videoNode.playerState == ASVideoNodePlayerStateLoading) { + [videoNode pause]; }else{ [videoNode play]; }