[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;
[self setNeedsDataFetch];
if (_shouldAutoplay) {
[self play];
}
}
- (AVAsset *)asset

View File

@ -29,17 +29,19 @@ NS_ASSUME_NONNULL_BEGIN
@property (nullable, atomic, weak) id<ASVideoPlayerNodeDelegate> delegate;
@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
/**
* 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.
*/
@property (nonatomic, assign, readwrite) BOOL shouldAutoplay;
@property (nonatomic, assign, readwrite) BOOL shouldAutorepeat;
@property (nonatomic, assign, readwrite) BOOL shouldAutoPlay;
@property (nonatomic, assign, readwrite) BOOL shouldAutoRepeat;
@property (nonatomic, assign, readwrite) BOOL muted;
@property (nonatomic, assign, readonly) ASVideoNodePlayerState playerState;
@property (nonatomic, assign, readwrite) BOOL shouldAggressivelyRecoverFromStall;
@ -51,6 +53,8 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithUrl:(NSURL*)url;
- (instancetype)initWithAsset:(AVAsset*)asset;
- (instancetype)initWithUrl:(NSURL *)url loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible;
- (instancetype)initWithAsset:(AVAsset *)asset loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible;
#pragma mark - Public API
- (void)seekToTime:(CGFloat)percentComplete;
@ -67,7 +71,16 @@ NS_ASSUME_NONNULL_BEGIN
* @abstract Delegate method invoked before creating controlbar controls
* @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:
@ -106,7 +119,7 @@ NS_ASSUME_NONNULL_BEGIN
#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.
*/
- (void)didTapVideoPlayerNode:(ASVideoPlayerNode *)videoPlayer;

View File

@ -18,7 +18,8 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
__weak id<ASVideoPlayerNodeDelegate> _delegate;
struct {
unsigned int delegateNeededControls:1;
unsigned int delegateNeededDefaultControls:1;
unsigned int delegateCustomControls:1;
unsigned int delegateSpinnerTintColor:1;
unsigned int delegatePlaybackButtonTint:1;
unsigned int delegateScrubberMaximumTrackTintColor:1;
@ -40,7 +41,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
ASVideoNode *_videoNode;
NSArray *_neededControls;
NSArray *_neededDefaultControls;
NSMutableDictionary *_cachedControls;
@ -51,13 +52,14 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
ASStackLayoutSpec *_controlFlexGrowSpacerSpec;
ASDisplayNode *_spinnerNode;
BOOL _loadAssetWhenNodeBecomesVisible;
BOOL _isSeeking;
CMTime _duration;
BOOL _disableControls;
BOOL _controlsDisabled;
BOOL _shouldAutoplay;
BOOL _shouldAutorepeat;
BOOL _shouldAutoPlay;
BOOL _shouldAutoRepeat;
BOOL _muted;
int32_t _periodicTimeObserverTimescale;
NSString *_gravity;
@ -89,6 +91,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
_url = url;
_asset = [AVAsset assetWithURL:_url];
_loadAssetWhenNodeBecomesVisible = YES;
[self _init];
@ -102,7 +105,36 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
}
_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];
@ -111,16 +143,15 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)_init
{
_defaultControlsColor = [UIColor whiteColor];
_cachedControls = [[NSMutableDictionary alloc] init];
_videoNode = [[ASVideoNode alloc] init];
_videoNode.asset = _asset;
_videoNode.delegate = self;
if (_loadAssetWhenNodeBecomesVisible == NO) {
_videoNode.asset = _asset;
}
[self addSubnode:_videoNode];
[self addObservers];
}
- (void)didLoad
@ -132,10 +163,21 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
}
}
- (NSArray*)createControlElementArray
- (void)visibilityDidChange:(BOOL)isVisible
{
if (_delegateFlags.delegateNeededControls) {
return [_delegate videoPlayerNodeNeededControls:self];
[super visibilityDidChange:isVisible];
ASDN::MutexLocker l(_videoPlayerLock);
if (isVisible && _loadAssetWhenNodeBecomesVisible && _asset != _videoNode.asset) {
_videoNode.asset = _asset;
}
}
- (NSArray *)createDefaultControlElementArray
{
if (_delegateFlags.delegateNeededDefaultControls) {
return [_delegate videoPlayerNodeNeededDefaultControls:self];
}
return @[ @(ASVideoPlayerNodeControlTypePlaybackButton),
@ -144,35 +186,25 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
@(ASVideoPlayerNodeControlTypeDurationText) ];
}
- (void)addObservers
{
}
- (void)removeObservers
{
}
#pragma mark - UI
- (void)createControls
{
ASDN::MutexLocker l(_videoPlayerLock);
if (_disableControls) {
if (_controlsDisabled) {
return;
}
if (_neededControls == nil) {
_neededControls = [self createControlElementArray];
if (_neededDefaultControls == nil) {
_neededDefaultControls = [self createDefaultControlElementArray];
}
if (_cachedControls == nil) {
_cachedControls = [[NSMutableDictionary alloc] init];
}
for (int i = 0; i < _neededControls.count; i++) {
ASVideoPlayerNodeControlType type = (ASVideoPlayerNodeControlType)[[_neededControls objectAtIndex:i] integerValue];
for (id object in _neededDefaultControls) {
ASVideoPlayerNodeControlType type = (ASVideoPlayerNodeControlType)[object integerValue];
switch (type) {
case ASVideoPlayerNodeControlTypePlaybackButton:
[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(^{
ASDN::MutexLocker l(_videoPlayerLock);
[self setNeedsLayout];
@ -246,7 +291,9 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
{
if (_elapsedTextNode == nil) {
_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)];
}
@ -257,7 +304,9 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
{
if (_durationTextNode == nil) {
_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)];
}
@ -317,14 +366,20 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)updateDurationTimeLabel
{
NSString *formatedDuration = [self timeStringForCMTime:_duration forTimeLabelType:ASVideoPlayerNodeControlTypeDurationText];
_durationTextNode.attributedString = [self timeLabelAttributedStringForString:formatedDuration forControlType:ASVideoPlayerNodeControlTypeDurationText];
if (!_durationTextNode) {
return;
}
NSString *formattedDuration = [self timeStringForCMTime:_duration forTimeLabelType:ASVideoPlayerNodeControlTypeDurationText];
_durationTextNode.attributedString = [self timeLabelAttributedStringForString:formattedDuration forControlType:ASVideoPlayerNodeControlTypeDurationText];
}
- (void)updateElapsedTimeLabel:(NSTimeInterval)seconds
{
NSString *formatedDuration = [self timeStringForCMTime:CMTimeMakeWithSeconds( seconds, _videoNode.periodicTimeObserverTimescale ) forTimeLabelType:ASVideoPlayerNodeControlTypeElapsedText];
_elapsedTextNode.attributedString = [self timeLabelAttributedStringForString:formatedDuration forControlType:ASVideoPlayerNodeControlTypeElapsedText];
if (!_elapsedTextNode) {
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
@ -352,7 +407,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
[_delegate videoPlayerNode:self willChangeVideoNodeState:state toVideoNodeState:toState];
}
if (toState == ASVideoNodePlayerStateReadyToPlay && _durationTextNode) {
if (toState == ASVideoNodePlayerStateReadyToPlay) {
_duration = _videoNode.currentItem.duration;
[self updateDurationTimeLabel];
}
@ -383,9 +438,6 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (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) {
[_delegate videoPlayerNode:self didPlayToTime:_videoNode.player.currentTime];
}
@ -415,12 +467,12 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
if (_delegateFlags.delegateDidTapVideoPlayerNode) {
[_delegate didTapVideoPlayerNode:self];
} else {
[self manageVideoNodePlayback];
[self togglePlayPause];
}
}
#pragma mark - Actions
- (void)manageVideoNodePlayback
- (void)togglePlayPause
{
if (_videoNode.playerState == ASVideoNodePlayerStatePlaying) {
[_videoNode pause];
@ -463,7 +515,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)didTapPlaybackButton:(ASControlNode*)node
{
[self manageVideoNodePlayback];
[self togglePlayPause];
}
- (void)beginSeek
@ -491,7 +543,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
[_videoNode.player seekToTime:CMTimeMakeWithSeconds(seconds, _videoNode.periodicTimeObserverTimescale)];
if (_videoNode.playerState != ASVideoNodePlayerStatePlaying) {
[self manageVideoNodePlayback];
[self togglePlayPause];
}
}
@ -609,12 +661,17 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)setDelegate:(id<ASVideoPlayerNodeDelegate>)delegate
{
if (delegate == _delegate) {
return;
}
_delegate = delegate;
if (_delegate == nil) {
memset(&_delegateFlags, 0, sizeof(_delegateFlags));
} 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.delegateScrubberMaximumTrackTintColor = [_delegate respondsToSelector:@selector(videoPlayerNodeScrubberMaximumTrackTint:)];
_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];
} else if (!_disableControls) {
} else if (!_controlsDisabled) {
[self createControls];
}
}
- (void)setShouldAutoplay:(BOOL)shouldAutoplay
- (void)setShouldAutoPlay:(BOOL)shouldAutoPlay
{
_shouldAutoplay = shouldAutoplay;
_videoNode.shouldAutoplay = _shouldAutoplay;
if (_shouldAutoPlay == shouldAutoPlay) {
return;
}
_shouldAutoPlay = shouldAutoPlay;
_videoNode.shouldAutoplay = _shouldAutoPlay;
}
- (void)setShouldAutorepeat:(BOOL)shouldAutorepeat
- (void)setShouldAutoRepeat:(BOOL)shouldAutoRepeat
{
_shouldAutorepeat = shouldAutorepeat;
_videoNode.shouldAutorepeat = YES;
if (_shouldAutoRepeat == shouldAutoRepeat) {
return;
}
_shouldAutoRepeat = shouldAutoRepeat;
_videoNode.shouldAutorepeat = _shouldAutoRepeat;
}
- (void)setMuted:(BOOL)muted
{
if (_muted == muted) {
return;
}
_muted = muted;
_videoNode.muted = _muted;
}
- (void)setPeriodicTimeObserverTimescale:(int32_t)periodicTimeObserverTimescale
{
if (_periodicTimeObserverTimescale == periodicTimeObserverTimescale) {
return;
}
_periodicTimeObserverTimescale = periodicTimeObserverTimescale;
_videoNode.periodicTimeObserverTimescale = _periodicTimeObserverTimescale;
}
@ -677,6 +750,9 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)setGravity:(NSString *)gravity
{
if (_gravity == gravity) {
return;
}
_gravity = gravity;
_videoNode.gravity = _gravity;
}
@ -693,6 +769,9 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
- (void)setShouldAggressivelyRecoverFromStall:(BOOL)shouldAggressivelyRecoverFromStall
{
if (_shouldAggressivelyRecoverFromStall == shouldAggressivelyRecoverFromStall) {
return;
}
_shouldAggressivelyRecoverFromStall = shouldAggressivelyRecoverFromStall;
_videoNode.shouldAggressivelyRecoverFromStall = _shouldAggressivelyRecoverFromStall;
}
@ -719,11 +798,4 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
return videoDurationText;
}
#pragma mark - Lifecycle
- (void)dealloc
{
[self removeObservers];
}
@end

View File

@ -19,6 +19,12 @@
8B0768BF1CE7C5A1002E1453 /* WindowWithStatusBarUnderlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B0768BE1CE7C5A1002E1453 /* WindowWithStatusBarUnderlay.m */; };
8B0768C51CE7C707002E1453 /* Utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B0768C41CE7C707002E1453 /* Utilities.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 */
/* Begin PBXFileReference section */
@ -42,6 +48,12 @@
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>"; };
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; };
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>"; };
@ -83,6 +95,7 @@
05E2128319D4DB510098F589 /* Sample */ = {
isa = PBXGroup;
children = (
8B90757E1CF3869100F924C1 /* Icons */,
8B0768C61CE7C85F002E1453 /* Controller */,
8B0768B91CE7B07E002E1453 /* Nodes */,
8B0768B51CE7ACE8002E1453 /* Models */,
@ -155,6 +168,19 @@
path = Controller;
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 */
/* Begin PBXNativeTarget section */
@ -215,9 +241,15 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8B9075861CF386A400F924C1 /* ico-unmute@2x.png in Resources */,
8B9075881CF386A400F924C1 /* ico-mute.png in Resources */,
0585428019D4DBE100606EA6 /* Default-568h@2x.png in Resources */,
6C2C82AC19EE274300767484 /* Default-667h@2x.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;
};

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;
ASVideoPlayerNode *_videoPlayerNode;
ASControlNode *_likeButtonNode;
ASButtonNode *_muteButtonNode;
}
- (instancetype)initWithVideoObject:(VideoModel *)video
@ -52,10 +53,16 @@
_likeButtonNode.backgroundColor = [UIColor redColor];
[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.backgroundColor = [UIColor blackColor];
[self addSubnode:_videoPlayerNode];
[self setMuteButtonIcon];
}
return self;
}
@ -98,43 +105,101 @@
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
- (void)didTapVideoPlayerNode:(ASVideoPlayerNode *)videoPlayer
{
if (_videoPlayerNode.isPlaying) {
if (_videoPlayerNode.playerState == ASVideoNodePlayerStatePlaying) {
NSLog(@"TRANSITION");
_videoPlayerNode.controlsDisabled = !_videoPlayerNode.controlsDisabled;
[_videoPlayerNode pause];
} else {
[_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
- (NSArray *)controlsForControlBar:(NSDictionary *)availableControls
{
NSMutableArray *bottomControls = [[NSMutableArray alloc] init];
NSMutableArray *controls = [[NSMutableArray alloc] init];
ASDisplayNode *playbackButtonNode = controls[@(ASVideoPlayerNodeControlTypePlaybackButton)];
if (playbackButtonNode) {
[bottomControls addObject:playbackButtonNode];
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];
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
spacing:10.0
justifyContent:ASStackLayoutJustifyContentStart
alignItems:ASStackLayoutAlignItemsCenter
children:bottomControls];
children: controlBarControls ];
controlbarSpec.alignSelf = ASStackLayoutAlignSelfStretch;
UIEdgeInsets insets = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
ASInsetLayoutSpec *controlbarInsetSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:controlbarSpec];
@ -144,9 +209,9 @@
spacing:0.0
justifyContent:ASStackLayoutJustifyContentStart
alignItems:ASStackLayoutAlignItemsStart
children:@[ spacer, controlbarInsetSpec ]];
children:@[topBarInsetSpec, spacer, controlbarInsetSpec]];
return mainVerticalStack;
}*/
}
@end