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

Commit d955911

Browse files
committed
renamed nic cage sample, added redundancy for loading player in case its nil when visible, added video tests, disabled assert for new range controller
1 parent 579313f commit d955911

26 files changed

Lines changed: 150 additions & 289 deletions

AsyncDisplayKit/ASVideoNode.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@ typedef NS_ENUM(NSUInteger, ASVideoGravity) {
99

1010
@protocol ASVideoNodeDelegate;
1111

12-
@interface ASVideoNode : ASControlNode<_ASDisplayLayerDelegate>
12+
@interface ASVideoNode : ASControlNode
1313
@property (atomic, strong, readwrite) AVAsset *asset;
1414
@property (atomic, strong, readonly) AVPlayer *player;
1515
@property (atomic, strong, readonly) AVPlayerItem *currentItem;
16+
17+
// When autoplay is set to true, a video node will play when it has both loaded and entered the "visible" interfaceState.
18+
// If it leaves the visible interfaceState it will pause but will resume once it has returned
1619
@property (nonatomic, assign, readwrite) BOOL shouldAutoplay;
17-
@property (atomic) ASVideoGravity gravity;
18-
@property (atomic) BOOL autorepeat;
20+
@property (nonatomic, assign, readwrite) BOOL shouldAutorepeat;
21+
22+
@property (atomic) NSString *gravity;
1923
@property (atomic) ASButtonNode *playButton;
2024

2125
@property (atomic, weak, readwrite) id<ASVideoNodeDelegate> delegate;
@@ -29,6 +33,6 @@ typedef NS_ENUM(NSUInteger, ASVideoGravity) {
2933

3034
@protocol ASVideoNodeDelegate <NSObject>
3135
@optional
32-
- (void)videoDidReachEnd:(ASVideoNode *)videoNode;
36+
- (void)videoPlaybackDidFinish:(ASVideoNode *)videoNode;
3337
@end
3438

AsyncDisplayKit/ASVideoNode.mm

Lines changed: 83 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22

33
#import "ASVideoNode.h"
4+
#import "ASDisplayNode+Beta.h"
45

56
@interface ASVideoNode ()
67
{
@@ -9,6 +10,10 @@ @interface ASVideoNode ()
910
__weak id<ASVideoNodeDelegate> _delegate;
1011

1112
BOOL _shouldBePlaying;
13+
14+
BOOL _shouldAutorepeat;
15+
BOOL _shouldAutoplay;
16+
1217
AVAsset *_asset;
1318

1419
AVPlayerItem *_currentItem;
@@ -17,48 +22,44 @@ @interface ASVideoNode ()
1722
ASButtonNode *_playButton;
1823
ASDisplayNode *_playerNode;
1924
ASDisplayNode *_spinner;
20-
ASVideoGravity _gravity;
25+
NSString *_gravity;
2126
}
2227

2328
@end
2429

25-
@interface ASDisplayNode ()
26-
- (void)setInterfaceState:(ASInterfaceState)newState;
27-
@end
28-
2930
@implementation ASVideoNode
3031

3132
- (instancetype)init
3233
{
3334
if (!(self = [super init])) { return nil; }
3435

35-
self.gravity = ASVideoGravityResizeAspect;
36+
[ASDisplayNode setShouldUseNewRenderingRange:YES];
3637

37-
[self addTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside];
38-
39-
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didPlayToEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
38+
self.gravity = AVLayerVideoGravityResizeAspect;
4039

40+
[self addTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside];
41+
4142
return self;
4243
}
4344

44-
// FIXME: Adopt interfaceStateDidChange API
45-
- (void)setInterfaceState:(ASInterfaceState)newState
45+
- (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfaceState)oldState
4646
{
47-
[super setInterfaceState:newState];
48-
4947
if (!(newState & ASInterfaceStateVisible)) {
50-
[self pause];
51-
[(UIActivityIndicatorView *)_spinner.view stopAnimating];
52-
[_spinner removeFromSupernode];
48+
if (oldState & ASInterfaceStateVisible) {
49+
if (_shouldBePlaying) {
50+
[self pause];
51+
_shouldBePlaying = YES;
52+
} else {
53+
[self pause];
54+
}
55+
[(UIActivityIndicatorView *)_spinner.view stopAnimating];
56+
[_spinner removeFromSupernode];
57+
}
5358
} else {
5459
if (_shouldBePlaying) {
5560
[self play];
5661
}
5762
}
58-
59-
if (newState & ASInterfaceStateVisible) {
60-
[self displayDidFinish];
61-
}
6263
}
6364

6465
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
@@ -78,10 +79,12 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
7879
- (void)didPlayToEnd:(NSNotification *)notification
7980
{
8081
if (ASObjectIsEqual([[notification object] asset], _asset)) {
81-
[_delegate videoDidReachEnd:self];
82+
if ([_delegate respondsToSelector:@selector(videoPlaybackDidFinish:)]) {
83+
[_delegate videoPlaybackDidFinish:self];
84+
}
8285
[_player seekToTime:CMTimeMakeWithSeconds(0, 1)];
8386

84-
if (_autorepeat) {
87+
if (_shouldAutorepeat) {
8588
[self play];
8689
} else {
8790
[self pause];
@@ -92,13 +95,35 @@ - (void)didPlayToEnd:(NSNotification *)notification
9295
- (void)layout
9396
{
9497
[super layout];
95-
_playerNode.frame = self.bounds;
9698

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+
CGRect bounds = self.bounds;
100+
_playerNode.frame = bounds;
101+
_playerNode.layer.frame = bounds;
102+
103+
CGFloat horizontalDiff = (bounds.size.width - _playButton.bounds.size.width)/2;
104+
CGFloat verticalDiff = (bounds.size.height - _playButton.bounds.size.height)/2;
99105
_playButton.hitTestSlop = UIEdgeInsetsMake(-verticalDiff, -horizontalDiff, -verticalDiff, -horizontalDiff);
100106

101-
_spinner.frame = _playButton.frame;
107+
_spinner.bounds = CGRectMake(0, 0, 44, 44);
108+
_spinner.position = CGPointMake(bounds.size.width/2, bounds.size.height/2);
109+
}
110+
111+
- (void)didLoad
112+
{
113+
[super didLoad];
114+
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didPlayToEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
115+
116+
_playerNode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer *{
117+
AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc] init];
118+
if (!_player) {
119+
_player = [AVPlayer playerWithPlayerItem:[[AVPlayerItem alloc] initWithAsset:_asset]];
120+
}
121+
playerLayer.player = _player;
122+
playerLayer.videoGravity = [self gravity];
123+
return playerLayer;
124+
}];
125+
126+
[self insertSubnode:_playerNode atIndex:0];
102127
}
103128

104129
- (void)tapped
@@ -140,38 +165,6 @@ - (void)fetchData
140165
}
141166
}
142167

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-
159-
if (_shouldAutoplay) {
160-
[self play];
161-
}
162-
}
163-
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-
}
175168

176169
- (void)clearFetchedData
177170
{
@@ -181,7 +174,27 @@ - (void)clearFetchedData
181174
ASDN::MutexLocker l(_lock);
182175
((AVPlayerLayer *)_playerNode.layer).player = nil;
183176
_player = nil;
184-
_shouldBePlaying = NO;
177+
}
178+
}
179+
180+
- (void)visibilityDidChange:(BOOL)isVisible
181+
{
182+
ASDN::MutexLocker l(_lock);
183+
184+
if (_shouldAutoplay && _playerNode.isNodeLoaded) {
185+
[self play];
186+
}
187+
if (isVisible) {
188+
if (_playerNode.isNodeLoaded) {
189+
if (!_player) {
190+
_player = [AVPlayer playerWithPlayerItem:[[AVPlayerItem alloc] initWithAsset:_asset]];
191+
}
192+
((AVPlayerLayer *)_playerNode.layer).player = _player;
193+
}
194+
195+
if (_shouldBePlaying) {
196+
[self play];
197+
}
185198
}
186199
}
187200

@@ -233,29 +246,16 @@ - (AVPlayer *)player
233246
return _player;
234247
}
235248

236-
- (void)setGravity:(ASVideoGravity)gravity
249+
- (void)setGravity:(NSString *)gravity
237250
{
238251
ASDN::MutexLocker l(_lock);
239-
240-
switch (gravity) {
241-
case ASVideoGravityResize:
242-
((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResize;
243-
break;
244-
case ASVideoGravityResizeAspect:
245-
((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResizeAspect;
246-
break;
247-
case ASVideoGravityResizeAspectFill:
248-
((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResizeAspectFill;
249-
break;
250-
default:
251-
((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResizeAspect;
252-
break;
252+
if (_playerNode.isNodeLoaded) {
253+
((AVPlayerLayer *)_playerNode.layer).videoGravity = gravity;
253254
}
254-
255255
_gravity = gravity;
256256
}
257257

258-
- (ASVideoGravity)gravity
258+
- (NSString *)gravity
259259
{
260260
ASDN::MutexLocker l(_lock);
261261

@@ -323,6 +323,12 @@ - (AVPlayerItem *)curentItem
323323
return _currentItem;
324324
}
325325

326+
- (void)setCurrentItem:(AVPlayerItem *)currentItem
327+
{
328+
ASDN::MutexLocker l(_lock);
329+
_currentItem = currentItem;
330+
}
331+
326332
- (ASDisplayNode *)playerNode
327333
{
328334
ASDN::MutexLocker l(_lock);
@@ -339,7 +345,7 @@ - (BOOL)shouldBePlaying
339345

340346
- (void)dealloc
341347
{
342-
[[NSNotificationCenter defaultCenter] removeObserver:self];
348+
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
343349
@try {
344350
[_currentItem removeObserver:self forKeyPath:NSStringFromSelector(@selector(status))];
345351
}

AsyncDisplayKit/Details/ASRangeHandlerRender.mm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ - (UIWindow *)workingWindow
3838

3939
return _workingWindow;
4040
}
41-
41+
4242
- (void)dealloc
4343
{
4444
if (![ASDisplayNode shouldUseNewRenderingRange]) {
@@ -64,7 +64,7 @@ - (void)node:(ASDisplayNode *)node enteredRangeOfType:(ASLayoutRangeType)rangeTy
6464
[node enterInterfaceState:ASInterfaceStateDisplay];
6565

6666

67-
ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled");
67+
// ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled");
6868
if ([ASDisplayNode shouldUseNewRenderingRange]) {
6969
[node recursivelyEnsureDisplaySynchronously:NO];
7070
} else {
@@ -102,7 +102,7 @@ - (void)node:(ASDisplayNode *)node exitedRangeOfType:(ASLayoutRangeType)rangeTyp
102102
// The node calls clearCurrentContents and suspends display
103103
[node exitInterfaceState:ASInterfaceStateDisplay];
104104

105-
ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled");
105+
// ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled");
106106

107107
if ([ASDisplayNode shouldUseNewRenderingRange]) {
108108
if (![node isLayerBacked]) {

AsyncDisplayKitTests/ASVideoNodeTests.m

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,24 @@ @interface ASVideoNodeTests : XCTestCase
1818
}
1919
@end
2020

21-
@interface ASVideoNode ()
21+
@interface ASVideoNode () {
22+
ASDisplayNode *_playerNode;
23+
}
2224
@property (atomic) ASInterfaceState interfaceState;
2325
@property (atomic) ASDisplayNode *spinner;
2426
@property (atomic) ASDisplayNode *playerNode;
2527
@property (atomic) BOOL shouldBePlaying;
28+
29+
- (void)setPlayerNode:(ASDisplayNode *)playerNode;
30+
@end
31+
32+
@implementation ASVideoNode (Test)
33+
34+
- (void)setPlayerNode:(ASDisplayNode *)playerNode
35+
{
36+
_playerNode = playerNode;
37+
}
38+
2639
@end
2740

2841
@implementation ASVideoNodeTests
@@ -114,21 +127,48 @@ - (void)testPlayerIsCreatedInFetchData
114127
XCTAssertNotNil(_videoNode.player);
115128
}
116129

117-
- (void)testPlayerLayerNodeIsAddedOnDisplayDidFinish
130+
- (void)testPlayerLayerNodeIsAddedOnDidLoad
118131
{
119132
_videoNode.asset = _firstAsset;
120133

121-
[_videoNode displayDidFinish];
134+
[_videoNode didLoad];
122135

123136
XCTAssert([_videoNode.subnodes containsObject:_videoNode.playerNode]);
124137
}
125138

126-
- (void)testVideoStartsPlayingOnDidDisplayIfAutoplayIsSet
139+
- (void)testVideoStartsPlayingOnDidDidBecomeVisibleWhenShouldAutoplay
127140
{
128141
_videoNode.asset = _firstAsset;
129142
_videoNode.shouldAutoplay = YES;
143+
_videoNode.playerNode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer *{
144+
AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc] init];
145+
return playerLayer;
146+
}];
147+
_videoNode.playerNode.layer.frame = CGRectZero;
148+
149+
[_videoNode visibilityDidChange:YES];
150+
151+
XCTAssertTrue(_videoNode.shouldBePlaying);
152+
}
153+
154+
- (void)testVideoShouldPauseWhenItLeavesVisibleButShouldKnowPlayingShouldRestartLater
155+
{
156+
_videoNode.asset = _firstAsset;
157+
[_videoNode play];
158+
159+
[_videoNode interfaceStateDidChange:ASInterfaceStateNone fromState:ASInterfaceStateVisible];
160+
161+
XCTAssertFalse(_videoNode.isPlaying);
162+
XCTAssertTrue(_videoNode.shouldBePlaying);
163+
}
164+
165+
- (void)testVideoThatIsPlayingWhenItLeavesVisibleRangeStartsAgainWhenItComesBack
166+
{
167+
_videoNode.asset = _firstAsset;
168+
[_videoNode play];
130169

131-
[_videoNode displayDidFinish];
170+
[_videoNode interfaceStateDidChange:ASInterfaceStateVisible fromState:ASInterfaceStateNone];
171+
[_videoNode interfaceStateDidChange:ASInterfaceStateNone fromState:ASInterfaceStateVisible];
132172

133173
XCTAssertTrue(_videoNode.shouldBePlaying);
134174
}
File renamed without changes.
File renamed without changes.
File renamed without changes.

examples/NicCageTableView/Sample.xcodeproj/project.pbxproj renamed to examples/VideoTableView/Sample.xcodeproj/project.pbxproj

File renamed without changes.

examples/NicCageTableView/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata renamed to examples/VideoTableView/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata

File renamed without changes.

0 commit comments

Comments
 (0)