Merge pull request #181 from sjchmiela/feature/support_fullscreen_mode

Support fullscreen mode
This commit is contained in:
Brent Vatne 2016-04-12 14:13:50 -04:00
commit 3c6da9782f
11 changed files with 252 additions and 3 deletions

View File

@ -1,10 +1,13 @@
#import "RCTView.h"
#import <AVFoundation/AVFoundation.h>
#import "AVKit/AVKit.h"
#import "UIView+FindUIViewController.h"
#import "RCTVideoPlayerViewController.h"
#import "RCTVideoPlayerViewControllerDelegate.h"
@class RCTEventDispatcher;
@interface RCTVideo : UIView
@interface RCTVideo : UIView <RCTVideoPlayerViewControllerDelegate>
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;

View File

@ -37,6 +37,8 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
BOOL _paused;
BOOL _repeat;
NSString * _resizeMode;
BOOL _fullscreenPlayerPresented;
UIViewController * _presentingViewController;
}
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
@ -69,7 +71,9 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
}
- (AVPlayerViewController*)createPlayerViewController:(AVPlayer*)player withPlayerItem:(AVPlayerItem*)playerItem {
AVPlayerViewController* playerLayer= [[AVPlayerViewController alloc] init];
RCTVideoPlayerViewController* playerLayer= [[RCTVideoPlayerViewController alloc] init];
playerLayer.showsPlaybackControls = NO;
playerLayer.rctDelegate = self;
playerLayer.view.frame = self.bounds;
playerLayer.player = _player;
playerLayer.view.frame = self.bounds;
@ -436,6 +440,54 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
_repeat = repeat;
}
- (BOOL)getFullscreen
{
return _fullscreenPlayerPresented;
}
- (void)setFullscreen:(BOOL)fullscreen
{
if( fullscreen && !_fullscreenPlayerPresented )
{
// Ensure player view controller is not null
if( !_playerViewController )
{
[self usePlayerViewController];
}
// Set presentation style to fullscreen
[_playerViewController setModalPresentationStyle:UIModalPresentationFullScreen];
// Find the nearest view controller
UIViewController *viewController = [self firstAvailableUIViewController];
if( !viewController )
{
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
viewController = keyWindow.rootViewController;
if( viewController.childViewControllers.count > 0 )
{
viewController = viewController.childViewControllers.lastObject;
}
}
if( viewController )
{
_presentingViewController = viewController;
[_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerWillPresent" body:@{@"target": self.reactTag}];
[viewController presentViewController:_playerViewController animated:true completion:^{
_playerViewController.showsPlaybackControls = YES;
_fullscreenPlayerPresented = fullscreen;
[_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerDidPresent" body:@{@"target": self.reactTag}];
}];
}
}
else if ( !fullscreen && _fullscreenPlayerPresented )
{
[self videoPlayerViewControllerWillDismiss:_playerViewController];
[_presentingViewController dismissViewControllerAnimated:true completion:^{
[self videoPlayerViewControllerDidDismiss:_playerViewController];
}];
}
}
- (void)usePlayerViewController
{
if( _player )
@ -478,6 +530,27 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
}
}
#pragma mark - RCTVideoPlayerViewControllerDelegate
- (void)videoPlayerViewControllerWillDismiss:(AVPlayerViewController *)playerViewController
{
if (_playerViewController == playerViewController && _fullscreenPlayerPresented)
{
[_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerWillDismiss" body:@{@"target": self.reactTag}];
}
}
- (void)videoPlayerViewControllerDidDismiss:(AVPlayerViewController *)playerViewController
{
if (_playerViewController == playerViewController && _fullscreenPlayerPresented)
{
_fullscreenPlayerPresented = false;
_presentingViewController = nil;
[self applyModifiers];
[_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerDidDismiss" body:@{@"target": self.reactTag}];
}
}
#pragma mark - React View Management
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex

View File

@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
31CAFB211CADA8CD009BCF6F /* UIView+FindUIViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 31CAFB201CADA8CD009BCF6F /* UIView+FindUIViewController.m */; };
31CAFB2F1CADC77F009BCF6F /* RCTVideoPlayerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 31CAFB2E1CADC77F009BCF6F /* RCTVideoPlayerViewController.m */; };
BBD49E3F1AC8DEF000610F8E /* RCTVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */; };
BBD49E401AC8DEF000610F8E /* RCTVideoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */; };
/* End PBXBuildFile section */
@ -25,6 +27,11 @@
/* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libRCTVideo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTVideo.a; sourceTree = BUILT_PRODUCTS_DIR; };
31CAFB1F1CADA8CD009BCF6F /* UIView+FindUIViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+FindUIViewController.h"; sourceTree = "<group>"; };
31CAFB201CADA8CD009BCF6F /* UIView+FindUIViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+FindUIViewController.m"; sourceTree = "<group>"; };
31CAFB2D1CADC77F009BCF6F /* RCTVideoPlayerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoPlayerViewController.h; sourceTree = "<group>"; };
31CAFB2E1CADC77F009BCF6F /* RCTVideoPlayerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVideoPlayerViewController.m; sourceTree = "<group>"; };
31CAFB301CAE6B5F009BCF6F /* RCTVideoPlayerViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoPlayerViewControllerDelegate.h; sourceTree = "<group>"; };
BBD49E391AC8DEF000610F8E /* RCTVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideo.h; sourceTree = "<group>"; };
BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVideo.m; sourceTree = "<group>"; };
BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoManager.h; sourceTree = "<group>"; };
@ -55,8 +62,13 @@
children = (
BBD49E391AC8DEF000610F8E /* RCTVideo.h */,
BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */,
31CAFB301CAE6B5F009BCF6F /* RCTVideoPlayerViewControllerDelegate.h */,
31CAFB2D1CADC77F009BCF6F /* RCTVideoPlayerViewController.h */,
31CAFB2E1CADC77F009BCF6F /* RCTVideoPlayerViewController.m */,
BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */,
BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */,
31CAFB1F1CADA8CD009BCF6F /* UIView+FindUIViewController.h */,
31CAFB201CADA8CD009BCF6F /* UIView+FindUIViewController.m */,
134814211AA4EA7D00B7C361 /* Products */,
);
sourceTree = "<group>";
@ -117,6 +129,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
31CAFB211CADA8CD009BCF6F /* UIView+FindUIViewController.m in Sources */,
31CAFB2F1CADC77F009BCF6F /* RCTVideoPlayerViewController.m in Sources */,
BBD49E3F1AC8DEF000610F8E /* RCTVideo.m in Sources */,
BBD49E401AC8DEF000610F8E /* RCTVideoManager.m in Sources */,
);

View File

@ -24,7 +24,11 @@ RCT_EXPORT_MODULE();
@"onVideoError",
@"onVideoProgress",
@"onVideoSeek",
@"onVideoEnd"
@"onVideoEnd",
@"onVideoFullscreenPlayerWillPresent",
@"onVideoFullscreenPlayerDidPresent",
@"onVideoFullscreenPlayerWillDismiss",
@"onVideoFullscreenPlayerDidDismiss"
];
}
@ -43,6 +47,7 @@ RCT_EXPORT_VIEW_PROPERTY(volume, float);
RCT_EXPORT_VIEW_PROPERTY(rate, float);
RCT_EXPORT_VIEW_PROPERTY(seek, float);
RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL);
- (NSDictionary *)constantsToExport
{

View File

@ -0,0 +1,15 @@
//
// RCTVideoPlayerViewController.h
// RCTVideo
//
// Created by Stanisław Chmiela on 31.03.2016.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <AVKit/AVKit.h>
#import "RCTVideo.h"
#import "RCTVideoPlayerViewControllerDelegate.h"
@interface RCTVideoPlayerViewController : AVPlayerViewController
@property (nonatomic, weak) id<RCTVideoPlayerViewControllerDelegate> rctDelegate;
@end

View File

@ -0,0 +1,28 @@
//
// RCTVideoPlayerViewController.m
// RCTVideo
//
// Created by Stanisław Chmiela on 31.03.2016.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "RCTVideoPlayerViewController.h"
@interface RCTVideoPlayerViewController ()
@end
@implementation RCTVideoPlayerViewController
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[_rctDelegate videoPlayerViewControllerDidDismiss:self];
}
- (void)viewWillDisappear:(BOOL)animated {
[_rctDelegate videoPlayerViewControllerWillDismiss:self];
[super viewWillDisappear:animated];
}
@end

View File

@ -0,0 +1,15 @@
//
// RCTVideoPlayerViewControllerDelegate.h
// RCTVideo
//
// Created by Stanisław Chmiela on 01.04.2016.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "AVKit/AVKit.h"
@protocol RCTVideoPlayerViewControllerDelegate <NSObject>
- (void)videoPlayerViewControllerWillDismiss:(AVPlayerViewController *)playerViewController;
- (void)videoPlayerViewControllerDidDismiss:(AVPlayerViewController *)playerViewController;
@end

View File

@ -0,0 +1,15 @@
//
// UIView+FindUIViewController.h
// RCTVideo
//
// Created by Stanisław Chmiela on 31.03.2016.
// Copyright © 2016 Facebook. All rights reserved.
//
// Source: http://stackoverflow.com/a/3732812/1123156
#import <UIKit/UIKit.h>
@interface UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController;
- (id) traverseResponderChainForUIViewController;
@end

View File

@ -0,0 +1,28 @@
//
// UIView+FindUIViewController.m
// RCTVideo
//
// Created by Stanisław Chmiela on 31.03.2016.
// Copyright © 2016 Facebook. All rights reserved.
//
// Source: http://stackoverflow.com/a/3732812/1123156
#import "UIView+FindUIViewController.h"
@implementation UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController {
// convenience function for casting and to "mask" the recursive function
return (UIViewController *)[self traverseResponderChainForUIViewController];
}
- (id) traverseResponderChainForUIViewController {
id nextResponder = [self nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]]) {
return nextResponder;
} else if ([nextResponder isKindOfClass:[UIView class]]) {
return [nextResponder traverseResponderChainForUIViewController];
} else {
return nil;
}
}
@end

View File

@ -21,6 +21,8 @@ export default class Video extends Component {
constructor(props, context) {
super(props, context);
this.seek = this.seek.bind(this);
this.presentFullscreenPlayer = this.presentFullscreenPlayer.bind(this);
this.dismissFullscreenPlayer = this.dismissFullscreenPlayer.bind(this);
this._assignRoot = this._assignRoot.bind(this);
this._onLoadStart = this._onLoadStart.bind(this);
this._onLoad = this._onLoad.bind(this);
@ -28,6 +30,10 @@ export default class Video extends Component {
this._onProgress = this._onProgress.bind(this);
this._onSeek = this._onSeek.bind(this);
this._onEnd = this._onEnd.bind(this);
this._onFullscreenPlayerWillPresent = this._onFullscreenPlayerWillPresent.bind(this);
this._onFullscreenPlayerDidPresent = this._onFullscreenPlayerDidPresent.bind(this);
this._onFullscreenPlayerWillDismiss = this._onFullscreenPlayerWillDismiss.bind(this);
this._onFullscreenPlayerDidDismiss = this._onFullscreenPlayerDidDismiss.bind(this);
}
setNativeProps(nativeProps) {
@ -38,6 +44,14 @@ export default class Video extends Component {
this.setNativeProps({ seek: time });
}
presentFullscreenPlayer() {
this.setNativeProps({ fullscreen: true });
}
dismissFullscreenPlayer() {
this.setNativeProps({ fullscreen: false });
}
_assignRoot(component) {
this._root = component;
}
@ -78,6 +92,30 @@ export default class Video extends Component {
}
}
_onFullscreenPlayerWillPresent(event) {
if (this.props.onFullscreenPlayerWillPresent) {
this.props.onFullscreenPlayerWillPresent(event.nativeEvent);
}
}
_onFullscreenPlayerDidPresent(event) {
if (this.props.onFullscreenPlayerDidPresent) {
this.props.onFullscreenPlayerDidPresent(event.nativeEvent);
}
}
_onFullscreenPlayerWillDismiss(event) {
if (this.props.onFullscreenPlayerWillDismiss) {
this.props.onFullscreenPlayerWillDismiss(event.nativeEvent);
}
}
_onFullscreenPlayerDidDismiss(event) {
if (this.props.onFullscreenPlayerDidDismiss) {
this.props.onFullscreenPlayerDidDismiss(event.nativeEvent);
}
}
render() {
const {
source,
@ -119,6 +157,10 @@ export default class Video extends Component {
onVideoProgress: this._onProgress,
onVideoSeek: this._onSeek,
onVideoEnd: this._onEnd,
onVideoFullscreenPlayerWillPresent: this._onFullscreenPlayerWillPresent,
onVideoFullscreenPlayerDidPresent: this._onFullscreenPlayerDidPresent,
onVideoFullscreenPlayerWillDismiss: this._onFullscreenPlayerWillDismiss,
onVideoFullscreenPlayerDidDismiss: this._onFullscreenPlayerDidDismiss,
});
return (
@ -134,6 +176,7 @@ Video.propTypes = {
/* Native only */
src: PropTypes.object,
seek: PropTypes.number,
fullscreen: PropTypes.bool,
/* Wrapper component */
source: PropTypes.object,
@ -151,6 +194,10 @@ Video.propTypes = {
onProgress: PropTypes.func,
onSeek: PropTypes.func,
onEnd: PropTypes.func,
onFullscreenPlayerWillPresent: PropTypes.func,
onFullscreenPlayerDidPresent: PropTypes.func,
onFullscreenPlayerWillDismiss: PropTypes.func,
onFullscreenPlayerDidDismiss: PropTypes.func,
/* Required by react-native */
scaleX: React.PropTypes.number,
@ -165,5 +212,6 @@ const RCTVideo = requireNativeComponent('RCTVideo', Video, {
nativeOnly: {
src: true,
seek: true,
fullscreen: true,
},
});

View File

@ -18,6 +18,11 @@
"RCTVideoManager.h",
"RCTVideoManager.m",
"README.md",
"UIView+FindUIViewController.h",
"UIView+FindUIViewController.m",
"RCTVideoPlayerViewController.h",
"RCTVideoPlayerViewController.m",
"RCTVideoPlayerViewControllerDelegate.h",
"Video.js",
"VideoResizeMode.js",
"react-native-video.podspec"