Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.

Commit 6dc15ff

Browse files
committed
added delegate method for video did finish, moved layer creation to after view displays, rearranged spinner logic, added tests
1 parent e318285 commit 6dc15ff

5 files changed

Lines changed: 194 additions & 85 deletions

File tree

AsyncDisplayKit/ASVideoNode.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,28 @@ typedef NS_ENUM(NSUInteger, ASVideoGravity) {
77
ASVideoGravityResize
88
};
99

10+
@protocol ASVideoNodeDelegate;
11+
1012
@interface ASVideoNode : ASControlNode<_ASDisplayLayerDelegate>
1113
@property (atomic, strong, readwrite) AVAsset *asset;
14+
@property (atomic, strong, readonly) AVPlayer *player;
15+
@property (atomic, strong, readonly) AVPlayerItem *currentItem;
1216
@property (nonatomic, assign, readwrite) BOOL shouldAutoplay;
1317
@property (atomic) ASVideoGravity gravity;
1418
@property (atomic) BOOL autorepeat;
1519
@property (atomic) ASButtonNode *playButton;
16-
@property (atomic) AVPlayer *player;
20+
21+
@property (atomic, weak, readwrite) id<ASVideoNodeDelegate> delegate;
1722

1823
- (void)play;
1924
- (void)pause;
2025

21-
@end
26+
- (BOOL)isPlaying;
2227

23-
@protocol ASVideoNodeDelegate <NSObject>
2428
@end
2529

26-
@protocol ASVideoNodeDataSource <NSObject>
30+
@protocol ASVideoNodeDelegate <NSObject>
2731
@optional
28-
- (ASButtonNode *)playButtonForVideoNode:(ASVideoNode *)videoNode;
29-
- (UIImage *)thumbnailForVideoNode:(ASVideoNode *) videoNode;
30-
- (NSURL *)thumbnailURLForVideoNode:(ASVideoNode *)videoNode;
32+
- (void)videoDidReachEnd:(ASVideoNode *)videoNode;
3133
@end
34+

AsyncDisplayKit/ASVideoNode.mm

Lines changed: 98 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ @interface ASVideoNode ()
66
{
77
ASDN::RecursiveMutex _lock;
88

9-
__weak id<ASVideoNodeDataSource> _dataSource;
10-
9+
__weak id<ASVideoNodeDelegate> _delegate;
10+
1111
BOOL _shouldBePlaying;
1212
AVAsset *_asset;
13+
1314
AVPlayerItem *_currentItem;
15+
AVPlayer *_player;
16+
1417
ASButtonNode *_playButton;
1518
ASDisplayNode *_playerNode;
1619
ASDisplayNode *_spinner;
20+
ASVideoGravity _gravity;
1721
}
1822

1923
@end
@@ -28,13 +32,6 @@ - (instancetype)init
2832
{
2933
if (!(self = [super init])) { return nil; }
3034

31-
_playerNode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer *{
32-
AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc] init];
33-
playerLayer.player = [[AVPlayer alloc] init];
34-
return playerLayer;
35-
}];
36-
[self addSubnode:_playerNode];
37-
3835
self.gravity = ASVideoGravityResizeAspect;
3936

4037
[self addTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside];
@@ -51,12 +48,17 @@ - (void)setInterfaceState:(ASInterfaceState)newState
5148

5249
if (!(newState & ASInterfaceStateVisible)) {
5350
[self pause];
51+
[(UIActivityIndicatorView *)_spinner.view stopAnimating];
5452
[_spinner removeFromSupernode];
5553
} else {
5654
if (_shouldBePlaying) {
5755
[self play];
5856
}
5957
}
58+
59+
if (newState & ASInterfaceStateVisible) {
60+
[self displayDidFinish];
61+
}
6062
}
6163

6264
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
@@ -76,7 +78,8 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
7678
- (void)didPlayToEnd:(NSNotification *)notification
7779
{
7880
if (ASObjectIsEqual([[notification object] asset], _asset)) {
79-
[[((AVPlayerLayer *)_playerNode.layer) player] seekToTime:CMTimeMakeWithSeconds(0, 1)];
81+
[_delegate videoDidReachEnd:self];
82+
[_player seekToTime:CMTimeMakeWithSeconds(0, 1)];
8083

8184
if (_autorepeat) {
8285
[self play];
@@ -90,6 +93,12 @@ - (void)layout
9093
{
9194
[super layout];
9295
_playerNode.frame = self.bounds;
96+
97+
CGFloat horizontalDiff = (self.bounds.size.width - _playButton.bounds.size.width)/2;
98+
CGFloat verticalDiff = (self.bounds.size.height - _playButton.bounds.size.height)/2;
99+
_playButton.hitTestSlop = UIEdgeInsetsMake(-verticalDiff, -horizontalDiff, -verticalDiff, -horizontalDiff);
100+
101+
_spinner.frame = _playButton.frame;
93102
}
94103

95104
- (void)tapped
@@ -123,29 +132,61 @@ - (void)fetchData
123132
_currentItem = [[AVPlayerItem alloc] initWithAsset:_asset];
124133
[_currentItem addObserver:self forKeyPath:NSStringFromSelector(@selector(status)) options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL];
125134

126-
if (((AVPlayerLayer *)_playerNode.layer).player) {
127-
[((AVPlayerLayer *)_playerNode.layer).player replaceCurrentItemWithPlayerItem:_currentItem];
135+
if (_player) {
136+
[_player replaceCurrentItemWithPlayerItem:_currentItem];
128137
} else {
129-
((AVPlayerLayer *)_playerNode.layer).player = [[AVPlayer alloc] initWithPlayerItem:_currentItem];
138+
_player = [[AVPlayer alloc] initWithPlayerItem:_currentItem];
130139
}
131-
132140
}
141+
}
142+
143+
// FIXME: Adopt interfaceStateDidChange API
144+
- (void)displayDidFinish
145+
{
146+
[super displayDidFinish];
147+
148+
ASDN::MutexLocker l(_lock);
149+
150+
_playerNode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer *{
151+
AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc] init];
152+
playerLayer.player = _player;
153+
playerLayer.videoGravity = [self videoGravity];
154+
return playerLayer;
155+
}];
156+
157+
[self insertSubnode:_playerNode atIndex:0];
158+
133159
if (_shouldAutoplay) {
134160
[self play];
135161
}
136162
}
137163

164+
- (NSString *)videoGravity
165+
{
166+
if (_gravity == ASVideoGravityResize) {
167+
return AVLayerVideoGravityResize;
168+
}
169+
if (_gravity == ASVideoGravityResizeAspectFill) {
170+
return AVLayerVideoGravityResizeAspectFill;
171+
}
172+
173+
return AVLayerVideoGravityResizeAspect;
174+
}
175+
138176
- (void)clearFetchedData
139177
{
140178
[super clearFetchedData];
141179

142180
{
143181
ASDN::MutexLocker l(_lock);
144182
((AVPlayerLayer *)_playerNode.layer).player = nil;
183+
_player = nil;
145184
_shouldBePlaying = NO;
146185
}
147186
}
148187

188+
#pragma mark - Video Properties
189+
149190
- (void)setPlayButton:(ASButtonNode *)playButton
150191
{
151192
ASDN::MutexLocker l(_lock);
@@ -174,6 +215,7 @@ - (void)setAsset:(AVAsset *)asset
174215

175216
_asset = asset;
176217

218+
// FIXME: Adopt -setNeedsFetchData when it is available
177219
if (self.interfaceState & ASInterfaceStateFetchData) {
178220
[self fetchData];
179221
}
@@ -185,6 +227,12 @@ - (AVAsset *)asset
185227
return _asset;
186228
}
187229

230+
- (AVPlayer *)player
231+
{
232+
ASDN::MutexLocker l(_lock);
233+
return _player;
234+
}
235+
188236
- (void)setGravity:(ASVideoGravity)gravity
189237
{
190238
ASDN::MutexLocker l(_lock);
@@ -203,77 +251,92 @@ - (void)setGravity:(ASVideoGravity)gravity
203251
((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResizeAspect;
204252
break;
205253
}
254+
255+
_gravity = gravity;
206256
}
207257

208258
- (ASVideoGravity)gravity
209259
{
210260
ASDN::MutexLocker l(_lock);
211261

212-
if (ASObjectIsEqual(((AVPlayerLayer *)_playerNode.layer).contentsGravity, AVLayerVideoGravityResize)) {
213-
return ASVideoGravityResize;
214-
}
215-
if (ASObjectIsEqual(((AVPlayerLayer *)_playerNode.layer).contentsGravity, AVLayerVideoGravityResizeAspectFill)) {
216-
return ASVideoGravityResizeAspectFill;
217-
}
218-
219-
return ASVideoGravityResizeAspect;
262+
return _gravity;
220263
}
221264

265+
#pragma mark - Video Playback
266+
222267
- (void)play
223268
{
224269
ASDN::MutexLocker l(_lock);
225270

226271
if (!_spinner) {
227272
_spinner = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{
228-
UIActivityIndicatorView *spinnnerView = [[UIActivityIndicatorView alloc] initWithFrame:_playButton.frame];
273+
UIActivityIndicatorView *spinnnerView = [[UIActivityIndicatorView alloc] init];
229274
spinnnerView.color = [UIColor whiteColor];
230-
[spinnnerView startAnimating];
231275

232276
return spinnnerView;
233277
}];
234278
}
235279

236-
if (![self ready]) {
237-
[self addSubnode:_spinner];
238-
}
239-
240-
[[((AVPlayerLayer *)_playerNode.layer) player] play];
280+
[_player play];
241281
_shouldBePlaying = YES;
242282
_playButton.alpha = 0.0;
243-
// if ([self ready] && ![self.subnodes containsObject:_spinner]) {
244-
// }
283+
284+
if (![self ready] && _shouldBePlaying && (self.interfaceState & ASInterfaceStateVisible)) {
285+
[self addSubnode:_spinner];
286+
[(UIActivityIndicatorView *)_spinner.view startAnimating];
287+
}
245288
}
246289

247290
- (BOOL)ready
248291
{
249-
return [((AVPlayerLayer *)_playerNode.layer) player].currentItem.status == AVPlayerItemStatusReadyToPlay;
292+
return _currentItem.status == AVPlayerItemStatusReadyToPlay;
250293
}
251294

252295
- (void)pause
253296
{
254297
ASDN::MutexLocker l(_lock);
255298

256-
[[((AVPlayerLayer *)_playerNode.layer) player] pause];
299+
[_player pause];
257300
[((UIActivityIndicatorView *)_spinner.view) stopAnimating];
258301
_shouldBePlaying = NO;
259302
_playButton.alpha = 1.0;
260303
}
261304

262-
- (AVPlayerItem *)currentItem
305+
- (BOOL)isPlaying
263306
{
264-
return _currentItem;
307+
ASDN::MutexLocker l(_lock);
308+
309+
return (_player.rate > 0 && !_player.error);
265310
}
266311

312+
#pragma mark - Property Accessors for Tests
313+
267314
- (ASDisplayNode *)spinner
268315
{
316+
ASDN::MutexLocker l(_lock);
269317
return _spinner;
270318
}
271319

272320
- (AVPlayerItem *)curentItem
273321
{
322+
ASDN::MutexLocker l(_lock);
274323
return _currentItem;
275324
}
276325

326+
- (ASDisplayNode *)playerNode
327+
{
328+
ASDN::MutexLocker l(_lock);
329+
return _playerNode;
330+
}
331+
332+
- (BOOL)shouldBePlaying
333+
{
334+
ASDN::MutexLocker l(_lock);
335+
return _shouldBePlaying;
336+
}
337+
338+
#pragma mark - Lifecycle
339+
277340
- (void)dealloc
278341
{
279342
[[NSNotificationCenter defaultCenter] removeObserver:self];

0 commit comments

Comments
 (0)