[ASVideoPlayerNode] fixes; Ability to add custom controls

This commit is contained in:
Erekle 2016-05-23 23:23:33 +04:00
parent 03f193c58b
commit 4ab0f1ec60
11 changed files with 270 additions and 92 deletions

View File

@ -443,10 +443,6 @@ static NSString * const kStatus = @"status";
_asset = asset; _asset = asset;
[self setNeedsDataFetch]; [self setNeedsDataFetch];
if (_shouldAutoplay) {
[self play];
}
} }
- (AVAsset *)asset - (AVAsset *)asset

View File

@ -31,15 +31,17 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign, readonly) CMTime duration; @property (nonatomic, assign, readonly) CMTime duration;
@property (nonatomic, assign) BOOL disableControls; @property (nonatomic, assign) BOOL controlsDisabled;
@property (nonatomic, assign, readonly) BOOL loadAssetWhenNodeBecomesVisible;
#pragma mark - ASVideoNode property proxy #pragma mark - ASVideoNode property proxy
/** /**
* When shouldAutoplay is set to true, a video node will play when it has both loaded and entered the "visible" interfaceState. * When shouldAutoplay 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. * If it leaves the visible interfaceState it will pause but will resume once it has returned.
*/ */
@property (nonatomic, assign, readwrite) BOOL shouldAutoplay; @property (nonatomic, assign, readwrite) BOOL shouldAutoPlay;
@property (nonatomic, assign, readwrite) BOOL shouldAutorepeat; @property (nonatomic, assign, readwrite) BOOL shouldAutoRepeat;
@property (nonatomic, assign, readwrite) BOOL muted; @property (nonatomic, assign, readwrite) BOOL muted;
@property (nonatomic, assign, readonly) ASVideoNodePlayerState playerState; @property (nonatomic, assign, readonly) ASVideoNodePlayerState playerState;
@property (nonatomic, assign, readwrite) BOOL shouldAggressivelyRecoverFromStall; @property (nonatomic, assign, readwrite) BOOL shouldAggressivelyRecoverFromStall;
@ -51,6 +53,8 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithUrl:(NSURL*)url; - (instancetype)initWithUrl:(NSURL*)url;
- (instancetype)initWithAsset:(AVAsset*)asset; - (instancetype)initWithAsset:(AVAsset*)asset;
- (instancetype)initWithUrl:(NSURL *)url loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible;
- (instancetype)initWithAsset:(AVAsset *)asset loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible;
#pragma mark - Public API #pragma mark - Public API
- (void)seekToTime:(CGFloat)percentComplete; - (void)seekToTime:(CGFloat)percentComplete;
@ -67,7 +71,16 @@ NS_ASSUME_NONNULL_BEGIN
* @abstract Delegate method invoked before creating controlbar controls * @abstract Delegate method invoked before creating controlbar controls
* @param videoPlayer * @param videoPlayer
*/ */
- (NSArray *)videoPlayerNodeNeededControls:(ASVideoPlayerNode*)videoPlayer; - (NSArray *)videoPlayerNodeNeededDefaultControls:(ASVideoPlayerNode*)videoPlayer;
/**
* @abstract Delegate method invoked before creating default controls, asks delegate for custom controls dictionary.
* This dictionary must constain only ASDisplayNode subclass objects.
* @param videoPlayer
* @discussion - This method is invoked only when developer implements videoPlayerNodeLayoutSpec:forControls:forMaximumSize:
* and gives ability to add custom constrols to ASVideoPlayerNode, for example mute button.
*/
- (NSDictionary *)videoPlayerNodeCustomControls:(ASVideoPlayerNode*)videoPlayer;
/** /**
* @abstract Delegate method invoked in layoutSpecThatFits: * @abstract Delegate method invoked in layoutSpecThatFits:
@ -106,7 +119,7 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark ASVideoNodeDelegate proxy methods #pragma mark ASVideoNodeDelegate proxy methods
/** /**
* @abstract Delegate method invoked when ASVideoPlayerNode playback time is taped. * @abstract Delegate method invoked when ASVideoPlayerNode is taped.
* @param videoPlayerNode The ASVideoPlayerNode that was tapped. * @param videoPlayerNode The ASVideoPlayerNode that was tapped.
*/ */
- (void)didTapVideoPlayerNode:(ASVideoPlayerNode *)videoPlayer; - (void)didTapVideoPlayerNode:(ASVideoPlayerNode *)videoPlayer;

View File

@ -18,7 +18,8 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
__weak id<ASVideoPlayerNodeDelegate> _delegate; __weak id<ASVideoPlayerNodeDelegate> _delegate;
struct { struct {
unsigned int delegateNeededControls:1; unsigned int delegateNeededDefaultControls:1;
unsigned int delegateCustomControls:1;
unsigned int delegateSpinnerTintColor:1; unsigned int delegateSpinnerTintColor:1;
unsigned int delegatePlaybackButtonTint:1; unsigned int delegatePlaybackButtonTint:1;
unsigned int delegateScrubberMaximumTrackTintColor:1; unsigned int delegateScrubberMaximumTrackTintColor:1;
@ -40,7 +41,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
ASVideoNode *_videoNode; ASVideoNode *_videoNode;
NSArray *_neededControls; NSArray *_neededDefaultControls;
NSMutableDictionary *_cachedControls; NSMutableDictionary *_cachedControls;
@ -51,13 +52,14 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
ASStackLayoutSpec *_controlFlexGrowSpacerSpec; ASStackLayoutSpec *_controlFlexGrowSpacerSpec;
ASDisplayNode *_spinnerNode; ASDisplayNode *_spinnerNode;
BOOL _loadAssetWhenNodeBecomesVisible;
BOOL _isSeeking; BOOL _isSeeking;
CMTime _duration; CMTime _duration;
BOOL _disableControls; BOOL _controlsDisabled;
BOOL _shouldAutoplay; BOOL _shouldAutoPlay;
BOOL _shouldAutorepeat; BOOL _shouldAutoRepeat;
BOOL _muted; BOOL _muted;
int32_t _periodicTimeObserverTimescale; int32_t _periodicTimeObserverTimescale;
NSString *_gravity; NSString *_gravity;
@ -89,6 +91,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
_url = url; _url = url;
_asset = [AVAsset assetWithURL:_url]; _asset = [AVAsset assetWithURL:_url];
_loadAssetWhenNodeBecomesVisible = YES;
[self _init]; [self _init];
@ -102,7 +105,36 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
} }
_asset = asset; _asset = asset;
_disableControls = NO; _loadAssetWhenNodeBecomesVisible = YES;
[self _init];
return self;
}
- (instancetype)initWithUrl:(NSURL *)url loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible
{
if (!(self = [super init])) {
return nil;
}
_url = url;
_asset = [AVAsset assetWithURL:_url];
_loadAssetWhenNodeBecomesVisible = loadAssetWhenNodeBecomesVisible;
[self _init];
return self;
}
- (instancetype)initWithAsset:(AVAsset *)asset loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible
{
if (!(self = [super init])) {
return nil;
}
_asset = asset;
_loadAssetWhenNodeBecomesVisible = loadAssetWhenNodeBecomesVisible;
[self _init]; [self _init];
@ -111,16 +143,15 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)_init - (void)_init
{ {
_defaultControlsColor = [UIColor whiteColor]; _defaultControlsColor = [UIColor whiteColor];
_cachedControls = [[NSMutableDictionary alloc] init]; _cachedControls = [[NSMutableDictionary alloc] init];
_videoNode = [[ASVideoNode alloc] init]; _videoNode = [[ASVideoNode alloc] init];
_videoNode.asset = _asset;
_videoNode.delegate = self; _videoNode.delegate = self;
if (_loadAssetWhenNodeBecomesVisible == NO) {
_videoNode.asset = _asset;
}
[self addSubnode:_videoNode]; [self addSubnode:_videoNode];
[self addObservers];
} }
- (void)didLoad - (void)didLoad
@ -132,10 +163,21 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
} }
} }
- (NSArray*)createControlElementArray - (void)visibilityDidChange:(BOOL)isVisible
{ {
if (_delegateFlags.delegateNeededControls) { [super visibilityDidChange:isVisible];
return [_delegate videoPlayerNodeNeededControls:self];
ASDN::MutexLocker l(_videoPlayerLock);
if (isVisible && _loadAssetWhenNodeBecomesVisible && _asset != _videoNode.asset) {
_videoNode.asset = _asset;
}
}
- (NSArray *)createDefaultControlElementArray
{
if (_delegateFlags.delegateNeededDefaultControls) {
return [_delegate videoPlayerNodeNeededDefaultControls:self];
} }
return @[ @(ASVideoPlayerNodeControlTypePlaybackButton), return @[ @(ASVideoPlayerNodeControlTypePlaybackButton),
@ -144,35 +186,25 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
@(ASVideoPlayerNodeControlTypeDurationText) ]; @(ASVideoPlayerNodeControlTypeDurationText) ];
} }
- (void)addObservers
{
}
- (void)removeObservers
{
}
#pragma mark - UI #pragma mark - UI
- (void)createControls - (void)createControls
{ {
ASDN::MutexLocker l(_videoPlayerLock); ASDN::MutexLocker l(_videoPlayerLock);
if (_disableControls) { if (_controlsDisabled) {
return; return;
} }
if (_neededControls == nil) { if (_neededDefaultControls == nil) {
_neededControls = [self createControlElementArray]; _neededDefaultControls = [self createDefaultControlElementArray];
} }
if (_cachedControls == nil) { if (_cachedControls == nil) {
_cachedControls = [[NSMutableDictionary alloc] init]; _cachedControls = [[NSMutableDictionary alloc] init];
} }
for (int i = 0; i < _neededControls.count; i++) { for (id object in _neededDefaultControls) {
ASVideoPlayerNodeControlType type = (ASVideoPlayerNodeControlType)[[_neededControls objectAtIndex:i] integerValue]; ASVideoPlayerNodeControlType type = (ASVideoPlayerNodeControlType)[object integerValue];
switch (type) { switch (type) {
case ASVideoPlayerNodeControlTypePlaybackButton: case ASVideoPlayerNodeControlTypePlaybackButton:
[self createPlaybackButton]; [self createPlaybackButton];
@ -194,6 +226,19 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
} }
} }
if (_delegateFlags.delegateCustomControls && _delegateFlags.delegateLayoutSpecForControls) {
NSDictionary *customControls = [_delegate videoPlayerNodeCustomControls:self];
for (id key in customControls) {
id node = customControls[key];
if (![node isKindOfClass:[ASDisplayNode class]]) {
continue;
}
[self addSubnode:node];
[_cachedControls setObject:node forKey:key];
}
}
ASPerformBlockOnMainThread(^{ ASPerformBlockOnMainThread(^{
ASDN::MutexLocker l(_videoPlayerLock); ASDN::MutexLocker l(_videoPlayerLock);
[self setNeedsLayout]; [self setNeedsLayout];
@ -246,7 +291,9 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
{ {
if (_elapsedTextNode == nil) { if (_elapsedTextNode == nil) {
_elapsedTextNode = [[ASTextNode alloc] init]; _elapsedTextNode = [[ASTextNode alloc] init];
_elapsedTextNode.attributedString = [self timeLabelAttributedStringForString:@"00:00" forControlType:ASVideoPlayerNodeControlTypeElapsedText]; _elapsedTextNode.attributedString = [self timeLabelAttributedStringForString:@"00:00"
forControlType:ASVideoPlayerNodeControlTypeElapsedText];
_elapsedTextNode.truncationMode = NSLineBreakByClipping;
[_cachedControls setObject:_elapsedTextNode forKey:@(ASVideoPlayerNodeControlTypeElapsedText)]; [_cachedControls setObject:_elapsedTextNode forKey:@(ASVideoPlayerNodeControlTypeElapsedText)];
} }
@ -257,7 +304,9 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
{ {
if (_durationTextNode == nil) { if (_durationTextNode == nil) {
_durationTextNode = [[ASTextNode alloc] init]; _durationTextNode = [[ASTextNode alloc] init];
_durationTextNode.attributedString = [self timeLabelAttributedStringForString:@"00:00" forControlType:ASVideoPlayerNodeControlTypeDurationText]; _durationTextNode.attributedString = [self timeLabelAttributedStringForString:@"00:00"
forControlType:ASVideoPlayerNodeControlTypeDurationText];
_durationTextNode.truncationMode = NSLineBreakByClipping;
[_cachedControls setObject:_durationTextNode forKey:@(ASVideoPlayerNodeControlTypeDurationText)]; [_cachedControls setObject:_durationTextNode forKey:@(ASVideoPlayerNodeControlTypeDurationText)];
} }
@ -317,14 +366,20 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)updateDurationTimeLabel - (void)updateDurationTimeLabel
{ {
NSString *formatedDuration = [self timeStringForCMTime:_duration forTimeLabelType:ASVideoPlayerNodeControlTypeDurationText]; if (!_durationTextNode) {
_durationTextNode.attributedString = [self timeLabelAttributedStringForString:formatedDuration forControlType:ASVideoPlayerNodeControlTypeDurationText]; return;
}
NSString *formattedDuration = [self timeStringForCMTime:_duration forTimeLabelType:ASVideoPlayerNodeControlTypeDurationText];
_durationTextNode.attributedString = [self timeLabelAttributedStringForString:formattedDuration forControlType:ASVideoPlayerNodeControlTypeDurationText];
} }
- (void)updateElapsedTimeLabel:(NSTimeInterval)seconds - (void)updateElapsedTimeLabel:(NSTimeInterval)seconds
{ {
NSString *formatedDuration = [self timeStringForCMTime:CMTimeMakeWithSeconds( seconds, _videoNode.periodicTimeObserverTimescale ) forTimeLabelType:ASVideoPlayerNodeControlTypeElapsedText]; if (!_elapsedTextNode) {
_elapsedTextNode.attributedString = [self timeLabelAttributedStringForString:formatedDuration forControlType:ASVideoPlayerNodeControlTypeElapsedText]; return;
}
NSString *formatteElapsed = [self timeStringForCMTime:CMTimeMakeWithSeconds( seconds, _videoNode.periodicTimeObserverTimescale ) forTimeLabelType:ASVideoPlayerNodeControlTypeElapsedText];
_elapsedTextNode.attributedString = [self timeLabelAttributedStringForString:formatteElapsed forControlType:ASVideoPlayerNodeControlTypeElapsedText];
} }
- (NSAttributedString*)timeLabelAttributedStringForString:(NSString*)string forControlType:(ASVideoPlayerNodeControlType)controlType - (NSAttributedString*)timeLabelAttributedStringForString:(NSString*)string forControlType:(ASVideoPlayerNodeControlType)controlType
@ -352,7 +407,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
[_delegate videoPlayerNode:self willChangeVideoNodeState:state toVideoNodeState:toState]; [_delegate videoPlayerNode:self willChangeVideoNodeState:state toVideoNodeState:toState];
} }
if (toState == ASVideoNodePlayerStateReadyToPlay && _durationTextNode) { if (toState == ASVideoNodePlayerStateReadyToPlay) {
_duration = _videoNode.currentItem.duration; _duration = _videoNode.currentItem.duration;
[self updateDurationTimeLabel]; [self updateDurationTimeLabel];
} }
@ -383,9 +438,6 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)videoNode:(ASVideoNode *)videoNode didPlayToTimeInterval:(NSTimeInterval)timeInterval - (void)videoNode:(ASVideoNode *)videoNode didPlayToTimeInterval:(NSTimeInterval)timeInterval
{ {
//TODO: ask Max about CMTime problem in ASVideoNode Header file
//as we said yesterday, we must use CMTime in ASVideoNode instead of NSTimeInterval
//when this will be done, must just proxy value to delegate
if (_delegateFlags.delegateVideoNodeDidPlayToTime) { if (_delegateFlags.delegateVideoNodeDidPlayToTime) {
[_delegate videoPlayerNode:self didPlayToTime:_videoNode.player.currentTime]; [_delegate videoPlayerNode:self didPlayToTime:_videoNode.player.currentTime];
} }
@ -415,12 +467,12 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
if (_delegateFlags.delegateDidTapVideoPlayerNode) { if (_delegateFlags.delegateDidTapVideoPlayerNode) {
[_delegate didTapVideoPlayerNode:self]; [_delegate didTapVideoPlayerNode:self];
} else { } else {
[self manageVideoNodePlayback]; [self togglePlayPause];
} }
} }
#pragma mark - Actions #pragma mark - Actions
- (void)manageVideoNodePlayback - (void)togglePlayPause
{ {
if (_videoNode.playerState == ASVideoNodePlayerStatePlaying) { if (_videoNode.playerState == ASVideoNodePlayerStatePlaying) {
[_videoNode pause]; [_videoNode pause];
@ -463,7 +515,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)didTapPlaybackButton:(ASControlNode*)node - (void)didTapPlaybackButton:(ASControlNode*)node
{ {
[self manageVideoNodePlayback]; [self togglePlayPause];
} }
- (void)beginSeek - (void)beginSeek
@ -491,7 +543,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
[_videoNode.player seekToTime:CMTimeMakeWithSeconds(seconds, _videoNode.periodicTimeObserverTimescale)]; [_videoNode.player seekToTime:CMTimeMakeWithSeconds(seconds, _videoNode.periodicTimeObserverTimescale)];
if (_videoNode.playerState != ASVideoNodePlayerStatePlaying) { if (_videoNode.playerState != ASVideoNodePlayerStatePlaying) {
[self manageVideoNodePlayback]; [self togglePlayPause];
} }
} }
@ -609,12 +661,17 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)setDelegate:(id<ASVideoPlayerNodeDelegate>)delegate - (void)setDelegate:(id<ASVideoPlayerNodeDelegate>)delegate
{ {
if (delegate == _delegate) {
return;
}
_delegate = delegate; _delegate = delegate;
if (_delegate == nil) { if (_delegate == nil) {
memset(&_delegateFlags, 0, sizeof(_delegateFlags)); memset(&_delegateFlags, 0, sizeof(_delegateFlags));
} else { } else {
_delegateFlags.delegateNeededControls = [_delegate respondsToSelector:@selector(videoPlayerNodeNeededControls:)]; _delegateFlags.delegateNeededDefaultControls = [_delegate respondsToSelector:@selector(videoPlayerNodeNeededDefaultControls:)];
_delegateFlags.delegateCustomControls = [_delegate respondsToSelector:@selector(videoPlayerNodeCustomControls:)];
_delegateFlags.delegateSpinnerTintColor = [_delegate respondsToSelector:@selector(videoPlayerNodeSpinnerTint:)]; _delegateFlags.delegateSpinnerTintColor = [_delegate respondsToSelector:@selector(videoPlayerNodeSpinnerTint:)];
_delegateFlags.delegateScrubberMaximumTrackTintColor = [_delegate respondsToSelector:@selector(videoPlayerNodeScrubberMaximumTrackTint:)]; _delegateFlags.delegateScrubberMaximumTrackTintColor = [_delegate respondsToSelector:@selector(videoPlayerNodeScrubberMaximumTrackTint:)];
_delegateFlags.delegateScrubberMinimumTrackTintColor = [_delegate respondsToSelector:@selector(videoPlayerNodeScrubberMinimumTrackTint:)]; _delegateFlags.delegateScrubberMinimumTrackTintColor = [_delegate respondsToSelector:@selector(videoPlayerNodeScrubberMinimumTrackTint:)];
@ -632,37 +689,53 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
} }
} }
- (void)setDisableControls:(BOOL)disableControls - (void)setControlsDisabled:(BOOL)controlsDisabled
{ {
_disableControls = disableControls; if (_controlsDisabled == controlsDisabled) {
return;
}
if (_disableControls && _cachedControls.count > 0) { _controlsDisabled = controlsDisabled;
if (_controlsDisabled && _cachedControls.count > 0) {
[self removeControls]; [self removeControls];
} else if (!_disableControls) { } else if (!_controlsDisabled) {
[self createControls]; [self createControls];
} }
} }
- (void)setShouldAutoplay:(BOOL)shouldAutoplay - (void)setShouldAutoPlay:(BOOL)shouldAutoPlay
{ {
_shouldAutoplay = shouldAutoplay; if (_shouldAutoPlay == shouldAutoPlay) {
_videoNode.shouldAutoplay = _shouldAutoplay; return;
}
_shouldAutoPlay = shouldAutoPlay;
_videoNode.shouldAutoplay = _shouldAutoPlay;
} }
- (void)setShouldAutorepeat:(BOOL)shouldAutorepeat - (void)setShouldAutoRepeat:(BOOL)shouldAutoRepeat
{ {
_shouldAutorepeat = shouldAutorepeat; if (_shouldAutoRepeat == shouldAutoRepeat) {
_videoNode.shouldAutorepeat = YES; return;
}
_shouldAutoRepeat = shouldAutoRepeat;
_videoNode.shouldAutorepeat = _shouldAutoRepeat;
} }
- (void)setMuted:(BOOL)muted - (void)setMuted:(BOOL)muted
{ {
if (_muted == muted) {
return;
}
_muted = muted; _muted = muted;
_videoNode.muted = _muted; _videoNode.muted = _muted;
} }
- (void)setPeriodicTimeObserverTimescale:(int32_t)periodicTimeObserverTimescale - (void)setPeriodicTimeObserverTimescale:(int32_t)periodicTimeObserverTimescale
{ {
if (_periodicTimeObserverTimescale == periodicTimeObserverTimescale) {
return;
}
_periodicTimeObserverTimescale = periodicTimeObserverTimescale; _periodicTimeObserverTimescale = periodicTimeObserverTimescale;
_videoNode.periodicTimeObserverTimescale = _periodicTimeObserverTimescale; _videoNode.periodicTimeObserverTimescale = _periodicTimeObserverTimescale;
} }
@ -677,6 +750,9 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)setGravity:(NSString *)gravity - (void)setGravity:(NSString *)gravity
{ {
if (_gravity == gravity) {
return;
}
_gravity = gravity; _gravity = gravity;
_videoNode.gravity = _gravity; _videoNode.gravity = _gravity;
} }
@ -693,6 +769,9 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)setShouldAggressivelyRecoverFromStall:(BOOL)shouldAggressivelyRecoverFromStall - (void)setShouldAggressivelyRecoverFromStall:(BOOL)shouldAggressivelyRecoverFromStall
{ {
if (_shouldAggressivelyRecoverFromStall == shouldAggressivelyRecoverFromStall) {
return;
}
_shouldAggressivelyRecoverFromStall = shouldAggressivelyRecoverFromStall; _shouldAggressivelyRecoverFromStall = shouldAggressivelyRecoverFromStall;
_videoNode.shouldAggressivelyRecoverFromStall = _shouldAggressivelyRecoverFromStall; _videoNode.shouldAggressivelyRecoverFromStall = _shouldAggressivelyRecoverFromStall;
} }
@ -719,11 +798,4 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
return videoDurationText; return videoDurationText;
} }
#pragma mark - Lifecycle
- (void)dealloc
{
[self removeObservers];
}
@end @end

View File

@ -19,6 +19,12 @@
8B0768BF1CE7C5A1002E1453 /* WindowWithStatusBarUnderlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B0768BE1CE7C5A1002E1453 /* WindowWithStatusBarUnderlay.m */; }; 8B0768BF1CE7C5A1002E1453 /* WindowWithStatusBarUnderlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B0768BE1CE7C5A1002E1453 /* WindowWithStatusBarUnderlay.m */; };
8B0768C51CE7C707002E1453 /* Utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B0768C41CE7C707002E1453 /* Utilities.m */; }; 8B0768C51CE7C707002E1453 /* Utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B0768C41CE7C707002E1453 /* Utilities.m */; };
8B0768C91CE7C889002E1453 /* VideoFeedNodeController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B0768C81CE7C889002E1453 /* VideoFeedNodeController.m */; }; 8B0768C91CE7C889002E1453 /* VideoFeedNodeController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B0768C81CE7C889002E1453 /* VideoFeedNodeController.m */; };
8B9075851CF386A400F924C1 /* ico-unmute.png in Resources */ = {isa = PBXBuildFile; fileRef = 8B90757F1CF386A400F924C1 /* ico-unmute.png */; };
8B9075861CF386A400F924C1 /* ico-unmute@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8B9075801CF386A400F924C1 /* ico-unmute@2x.png */; };
8B9075871CF386A400F924C1 /* ico-unmute@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8B9075811CF386A400F924C1 /* ico-unmute@3x.png */; };
8B9075881CF386A400F924C1 /* ico-mute.png in Resources */ = {isa = PBXBuildFile; fileRef = 8B9075821CF386A400F924C1 /* ico-mute.png */; };
8B9075891CF386A400F924C1 /* ico-mute@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8B9075831CF386A400F924C1 /* ico-mute@2x.png */; };
8B90758A1CF386A400F924C1 /* ico-mute@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8B9075841CF386A400F924C1 /* ico-mute@3x.png */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@ -42,6 +48,12 @@
8B0768C41CE7C707002E1453 /* Utilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Utilities.m; sourceTree = "<group>"; }; 8B0768C41CE7C707002E1453 /* Utilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Utilities.m; sourceTree = "<group>"; };
8B0768C71CE7C889002E1453 /* VideoFeedNodeController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoFeedNodeController.h; sourceTree = "<group>"; }; 8B0768C71CE7C889002E1453 /* VideoFeedNodeController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoFeedNodeController.h; sourceTree = "<group>"; };
8B0768C81CE7C889002E1453 /* VideoFeedNodeController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoFeedNodeController.m; sourceTree = "<group>"; }; 8B0768C81CE7C889002E1453 /* VideoFeedNodeController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoFeedNodeController.m; sourceTree = "<group>"; };
8B90757F1CF386A400F924C1 /* ico-unmute.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ico-unmute.png"; sourceTree = "<group>"; };
8B9075801CF386A400F924C1 /* ico-unmute@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ico-unmute@2x.png"; sourceTree = "<group>"; };
8B9075811CF386A400F924C1 /* ico-unmute@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ico-unmute@3x.png"; sourceTree = "<group>"; };
8B9075821CF386A400F924C1 /* ico-mute.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ico-mute.png"; sourceTree = "<group>"; };
8B9075831CF386A400F924C1 /* ico-mute@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ico-mute@2x.png"; sourceTree = "<group>"; };
8B9075841CF386A400F924C1 /* ico-mute@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ico-mute@3x.png"; sourceTree = "<group>"; };
A2092CAF5607B3863A3700A2 /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; A2092CAF5607B3863A3700A2 /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
CFD6AA1D30516C27DEE5602B /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; }; CFD6AA1D30516C27DEE5602B /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; };
E51646FF8D3676A1D826A5AE /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = "<group>"; }; E51646FF8D3676A1D826A5AE /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = "<group>"; };
@ -83,6 +95,7 @@
05E2128319D4DB510098F589 /* Sample */ = { 05E2128319D4DB510098F589 /* Sample */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
8B90757E1CF3869100F924C1 /* Icons */,
8B0768C61CE7C85F002E1453 /* Controller */, 8B0768C61CE7C85F002E1453 /* Controller */,
8B0768B91CE7B07E002E1453 /* Nodes */, 8B0768B91CE7B07E002E1453 /* Nodes */,
8B0768B51CE7ACE8002E1453 /* Models */, 8B0768B51CE7ACE8002E1453 /* Models */,
@ -155,6 +168,19 @@
path = Controller; path = Controller;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
8B90757E1CF3869100F924C1 /* Icons */ = {
isa = PBXGroup;
children = (
8B90757F1CF386A400F924C1 /* ico-unmute.png */,
8B9075801CF386A400F924C1 /* ico-unmute@2x.png */,
8B9075811CF386A400F924C1 /* ico-unmute@3x.png */,
8B9075821CF386A400F924C1 /* ico-mute.png */,
8B9075831CF386A400F924C1 /* ico-mute@2x.png */,
8B9075841CF386A400F924C1 /* ico-mute@3x.png */,
);
path = Icons;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@ -215,9 +241,15 @@
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
8B9075861CF386A400F924C1 /* ico-unmute@2x.png in Resources */,
8B9075881CF386A400F924C1 /* ico-mute.png in Resources */,
0585428019D4DBE100606EA6 /* Default-568h@2x.png in Resources */, 0585428019D4DBE100606EA6 /* Default-568h@2x.png in Resources */,
6C2C82AC19EE274300767484 /* Default-667h@2x.png in Resources */, 6C2C82AC19EE274300767484 /* Default-667h@2x.png in Resources */,
6C2C82AD19EE274300767484 /* Default-736h@3x.png in Resources */, 6C2C82AD19EE274300767484 /* Default-736h@3x.png in Resources */,
8B90758A1CF386A400F924C1 /* ico-mute@3x.png in Resources */,
8B9075851CF386A400F924C1 /* ico-unmute.png in Resources */,
8B9075871CF386A400F924C1 /* ico-unmute@3x.png in Resources */,
8B9075891CF386A400F924C1 /* ico-mute@2x.png in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -25,6 +25,7 @@
ASNetworkImageNode *_avatarNode; ASNetworkImageNode *_avatarNode;
ASVideoPlayerNode *_videoPlayerNode; ASVideoPlayerNode *_videoPlayerNode;
ASControlNode *_likeButtonNode; ASControlNode *_likeButtonNode;
ASButtonNode *_muteButtonNode;
} }
- (instancetype)initWithVideoObject:(VideoModel *)video - (instancetype)initWithVideoObject:(VideoModel *)video
@ -52,10 +53,16 @@
_likeButtonNode.backgroundColor = [UIColor redColor]; _likeButtonNode.backgroundColor = [UIColor redColor];
[self addSubnode:_likeButtonNode]; [self addSubnode:_likeButtonNode];
_videoPlayerNode = [[ASVideoPlayerNode alloc] initWithUrl:_videoModel.url]; _muteButtonNode = [[ASButtonNode alloc] init];
_muteButtonNode.preferredFrameSize = CGSizeMake(16.0, 22.0);
[_muteButtonNode addTarget:self action:@selector(didTapMuteButton) forControlEvents:ASControlNodeEventTouchUpInside];
_videoPlayerNode = [[ASVideoPlayerNode alloc] initWithUrl:_videoModel.url loadAssetWhenNodeBecomesVisible:YES];
_videoPlayerNode.delegate = self; _videoPlayerNode.delegate = self;
_videoPlayerNode.backgroundColor = [UIColor blackColor]; _videoPlayerNode.backgroundColor = [UIColor blackColor];
[self addSubnode:_videoPlayerNode]; [self addSubnode:_videoPlayerNode];
[self setMuteButtonIcon];
} }
return self; return self;
} }
@ -98,43 +105,101 @@
return verticalStack; return verticalStack;
} }
- (void)setMuteButtonIcon
{
if (_videoPlayerNode.muted) {
[_muteButtonNode setImage:[UIImage imageNamed:@"ico-mute"] forState:ASControlStateNormal];
} else {
[_muteButtonNode setImage:[UIImage imageNamed:@"ico-unmute"] forState:ASControlStateNormal];
}
}
- (void)didTapMuteButton
{
_videoPlayerNode.muted = !_videoPlayerNode.muted;
[self setMuteButtonIcon];
}
#pragma mark - ASVideoPlayerNodeDelegate #pragma mark - ASVideoPlayerNodeDelegate
- (void)didTapVideoPlayerNode:(ASVideoPlayerNode *)videoPlayer - (void)didTapVideoPlayerNode:(ASVideoPlayerNode *)videoPlayer
{ {
if (_videoPlayerNode.isPlaying) { if (_videoPlayerNode.playerState == ASVideoNodePlayerStatePlaying) {
NSLog(@"TRANSITION"); NSLog(@"TRANSITION");
_videoPlayerNode.controlsDisabled = !_videoPlayerNode.controlsDisabled;
[_videoPlayerNode pause]; [_videoPlayerNode pause];
} else { } else {
[_videoPlayerNode play]; [_videoPlayerNode play];
} }
} }
/*- (NSArray *)videoPlayerNodeNeededControls:(ASVideoPlayerNode *)videoPlayer - (NSDictionary *)videoPlayerNodeCustomControls:(ASVideoPlayerNode *)videoPlayer
{ {
return @[ @(ASVideoPlayerNodeControlTypePlaybackButton) ]; return @{
}*/ @"muteControl" : _muteButtonNode
};
/*- (ASLayoutSpec *)videoPlayerNodeLayoutSpec:(ASVideoPlayerNode *)videoPlayer forControls:(NSDictionary *)controls forMaximumSize:(CGSize)maxSize
{
NSMutableArray *bottomControls = [[NSMutableArray alloc] init];
ASDisplayNode *playbackButtonNode = controls[@(ASVideoPlayerNodeControlTypePlaybackButton)];
if (playbackButtonNode) {
[bottomControls addObject:playbackButtonNode];
} }
- (NSArray *)controlsForControlBar:(NSDictionary *)availableControls
{
NSMutableArray *controls = [[NSMutableArray alloc] init];
if (availableControls[ @(ASVideoPlayerNodeControlTypePlaybackButton) ]) {
[controls addObject:availableControls[ @(ASVideoPlayerNodeControlTypePlaybackButton) ]];
}
if (availableControls[ @(ASVideoPlayerNodeControlTypeElapsedText) ]) {
[controls addObject:availableControls[ @(ASVideoPlayerNodeControlTypeElapsedText) ]];
}
if (availableControls[ @(ASVideoPlayerNodeControlTypeScrubber) ]) {
[controls addObject:availableControls[ @(ASVideoPlayerNodeControlTypeScrubber) ]];
}
if (availableControls[ @(ASVideoPlayerNodeControlTypeDurationText) ]) {
[controls addObject:availableControls[ @(ASVideoPlayerNodeControlTypeDurationText) ]];
}
return controls;
}
#pragma mark - Layout
- (ASLayoutSpec*)videoPlayerNodeLayoutSpec:(ASVideoPlayerNode *)videoPlayer forControls:(NSDictionary *)controls forMaximumSize:(CGSize)maxSize
{
ASLayoutSpec *spacer = [[ASLayoutSpec alloc] init]; ASLayoutSpec *spacer = [[ASLayoutSpec alloc] init];
spacer.flexGrow = YES; spacer.flexGrow = YES;
UIEdgeInsets insets = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
if (controls[ @(ASVideoPlayerNodeControlTypeScrubber) ]) {
ASDisplayNode *scrubber = controls[ @(ASVideoPlayerNodeControlTypeScrubber) ];
scrubber.preferredFrameSize = CGSizeMake(maxSize.width, 44.0);
}
NSArray *controlBarControls = [self controlsForControlBar:controls];
NSMutableArray *topBarControls = [[NSMutableArray alloc] init];
//Our custom control
if (controls[@"muteControl"]) {
[topBarControls addObject:controls[@"muteControl"]];
}
ASStackLayoutSpec *topBarSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal
spacing:10.0
justifyContent:ASStackLayoutJustifyContentStart
alignItems:ASStackLayoutAlignItemsCenter
children:topBarControls];
ASInsetLayoutSpec *topBarInsetSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:topBarSpec];
ASStackLayoutSpec *controlbarSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal ASStackLayoutSpec *controlbarSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal
spacing:10.0 spacing:10.0
justifyContent:ASStackLayoutJustifyContentStart justifyContent:ASStackLayoutJustifyContentStart
alignItems:ASStackLayoutAlignItemsCenter alignItems:ASStackLayoutAlignItemsCenter
children:bottomControls]; children: controlBarControls ];
controlbarSpec.alignSelf = ASStackLayoutAlignSelfStretch; controlbarSpec.alignSelf = ASStackLayoutAlignSelfStretch;
UIEdgeInsets insets = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
ASInsetLayoutSpec *controlbarInsetSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:controlbarSpec]; ASInsetLayoutSpec *controlbarInsetSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:controlbarSpec];
@ -144,9 +209,9 @@
spacing:0.0 spacing:0.0
justifyContent:ASStackLayoutJustifyContentStart justifyContent:ASStackLayoutJustifyContentStart
alignItems:ASStackLayoutAlignItemsStart alignItems:ASStackLayoutAlignItemsStart
children:@[ spacer, controlbarInsetSpec ]]; children:@[topBarInsetSpec, spacer, controlbarInsetSpec]];
return mainVerticalStack; return mainVerticalStack;
}*/
}
@end @end