VLCFullscreenMovieTVViewController.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /*****************************************************************************
  2. * VLC for iOS
  3. *****************************************************************************
  4. * Copyright (c) 2015 VideoLAN. All rights reserved.
  5. * $Id$
  6. *
  7. * Authors: Felix Paul Kühne <fkuehne # videolan.org>
  8. *
  9. * Refer to the COPYING file of the official project for license.
  10. *****************************************************************************/
  11. #import "VLCFullscreenMovieTVViewController.h"
  12. #import "VLCPlaybackInfoTVViewController.h"
  13. #import "VLCPlaybackInfoTVAnimators.h"
  14. @interface VLCFullscreenMovieTVViewController (UIViewControllerTransitioningDelegate) <UIViewControllerTransitioningDelegate, UIGestureRecognizerDelegate>
  15. @end
  16. @interface VLCFullscreenMovieTVViewController ()
  17. @property (nonatomic) NSTimer *hidePlaybackControlsViewAfterDeleayTimer;
  18. @end
  19. @implementation VLCFullscreenMovieTVViewController
  20. + (instancetype)fullscreenMovieTVViewController
  21. {
  22. return [[self alloc] initWithNibName:nil bundle:nil];
  23. }
  24. - (void)viewDidLoad {
  25. [super viewDidLoad];
  26. self.extendedLayoutIncludesOpaqueBars = YES;
  27. self.edgesForExtendedLayout = UIRectEdgeAll;
  28. NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  29. [center addObserver:self
  30. selector:@selector(playbackDidStop:)
  31. name:VLCPlaybackControllerPlaybackDidStop
  32. object:nil];
  33. _movieView.userInteractionEnabled = NO;
  34. self.titleLabel.text = @"";
  35. self.transportBar.bufferStartFraction = 0.0;
  36. self.transportBar.bufferEndFraction = 1.0;
  37. self.transportBar.playbackFraction = 0.0;
  38. self.transportBar.scrubbingFraction = 0.0;
  39. self.dimmingView.alpha = 0.0;
  40. self.bottomOverlayView.alpha = 0.0;
  41. self.bufferingLabel.text = NSLocalizedString(@"PLEASE_WAIT", nil);
  42. // Panning and Swiping
  43. UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGesture:)];
  44. [self.view addGestureRecognizer:panGestureRecognizer];
  45. // Button presses
  46. UITapGestureRecognizer *playpauseGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(playPausePressed)];
  47. playpauseGesture.allowedPressTypes = @[@(UIPressTypePlayPause)];
  48. [self.view addGestureRecognizer:playpauseGesture];
  49. UITapGestureRecognizer *selectTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectButtonPressed:)];
  50. selectTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypeSelect)];
  51. [self.view addGestureRecognizer:selectTapGestureRecognizer];
  52. UITapGestureRecognizer *menuTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(menuButtonPressed:)];
  53. menuTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypeMenu)];
  54. menuTapGestureRecognizer.delegate = self;
  55. [self.view addGestureRecognizer:menuTapGestureRecognizer];
  56. UITapGestureRecognizer *upArrowRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showInfoVCIfNotScrubbing)];
  57. upArrowRecognizer.allowedPressTypes = @[@(UIPressTypeUpArrow)];
  58. [self.view addGestureRecognizer:upArrowRecognizer];
  59. }
  60. #pragma mark - view events
  61. - (void)viewWillAppear:(BOOL)animated
  62. {
  63. [super viewWillAppear:animated];
  64. VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
  65. vpc.delegate = self;
  66. [vpc recoverPlaybackState];
  67. }
  68. - (void)viewDidAppear:(BOOL)animated
  69. {
  70. [super viewDidAppear:animated];
  71. VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
  72. [vpc recoverDisplayedMetadata];
  73. vpc.videoOutputView = nil;
  74. vpc.videoOutputView = self.movieView;
  75. [[NSNotificationCenter defaultCenter] removeObserver:self];
  76. }
  77. - (void)viewWillDisappear:(BOOL)animated
  78. {
  79. VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
  80. if (vpc.videoOutputView == self.movieView) {
  81. vpc.videoOutputView = nil;
  82. }
  83. [vpc stopPlayback];
  84. [super viewWillDisappear:animated];
  85. }
  86. - (BOOL)canBecomeFirstResponder
  87. {
  88. return YES;
  89. }
  90. #pragma mark - UIActions
  91. - (void)playPausePressed
  92. {
  93. [self showPlaybackControlsIfNeededForUserInteraction];
  94. VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
  95. if (self.transportBar.scrubbing) {
  96. [self selectButtonPressed:nil];
  97. } else {
  98. [vpc playPause];
  99. }
  100. }
  101. - (void)panGesture:(UIPanGestureRecognizer *)panGestureRecognizer
  102. {
  103. [self showPlaybackControlsIfNeededForUserInteraction];
  104. VLCTransportBar *bar = self.transportBar;
  105. UIView *view = self.view;
  106. CGPoint translation = [panGestureRecognizer translationInView:view];
  107. if (!bar.scrubbing) {
  108. if (ABS(translation.x) > 150.0) {
  109. [self startScrubbing];
  110. } else if (translation.y > 200.0) {
  111. [self showInfoVCIfNotScrubbing];
  112. return;
  113. } else {
  114. return;
  115. }
  116. }
  117. const CGFloat scaleFactor = 8.0;
  118. CGFloat fractionInView = translation.x/CGRectGetWidth(view.bounds)/scaleFactor;
  119. translation.x = 0.0;
  120. [panGestureRecognizer setTranslation:translation inView:view];
  121. CGFloat scrubbingFraction = MAX(0.0, MIN(bar.scrubbingFraction + fractionInView,1.0));
  122. bar.scrubbingFraction = scrubbingFraction;
  123. [self updateTimeLabelsForScrubbingFraction:scrubbingFraction];
  124. }
  125. - (void)selectButtonPressed:(UITapGestureRecognizer *)recognizer
  126. {
  127. [self showPlaybackControlsIfNeededForUserInteraction];
  128. VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
  129. VLCTransportBar *bar = self.transportBar;
  130. if (bar.scrubbing) {
  131. bar.playbackFraction = bar.scrubbingFraction;
  132. [vpc.mediaPlayer setPosition:bar.scrubbingFraction];
  133. [self stopScrubbing];
  134. } else if(vpc.mediaPlayer.playing) {
  135. [vpc.mediaPlayer pause];
  136. }
  137. }
  138. - (void)menuButtonPressed:(UITapGestureRecognizer *)recognizer
  139. {
  140. VLCTransportBar *bar = self.transportBar;
  141. if (bar.scrubbing) {
  142. [UIView animateWithDuration:0.3 animations:^{
  143. bar.scrubbingFraction = bar.playbackFraction;
  144. [bar layoutIfNeeded];
  145. }];
  146. [self updateTimeLabelsForScrubbingFraction:bar.playbackFraction];
  147. [self stopScrubbing];
  148. [self hidePlaybackControlsIfNeededAfterDelay];
  149. }
  150. }
  151. - (void)showInfoVCIfNotScrubbing
  152. {
  153. if (self.transportBar.scrubbing) {
  154. return;
  155. }
  156. VLCPlaybackInfoTVViewController *infoController = [[VLCPlaybackInfoTVViewController alloc] initWithNibName:nil bundle:nil];
  157. infoController.transitioningDelegate = self;
  158. infoController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
  159. // TODO: configure with player info
  160. [self presentViewController:infoController animated:YES completion:nil];
  161. [self animatePlaybackControlsToVisibility:NO];
  162. }
  163. #pragma mark -
  164. - (void)updateTimeLabelsForScrubbingFraction:(CGFloat)scrubbingFraction
  165. {
  166. VLCTransportBar *bar = self.transportBar;
  167. VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
  168. // MAX 1, _ is ugly hack to prevent --:-- instead of 00:00
  169. int scrubbingTimeInt = MAX(1,vpc.mediaDuration*scrubbingFraction);
  170. VLCTime *scrubbingTime = [VLCTime timeWithInt:scrubbingTimeInt];
  171. bar.markerTimeLabel.text = [scrubbingTime stringValue];
  172. VLCTime *remainingTime = [VLCTime timeWithInt:(int)vpc.mediaDuration-scrubbingTime.intValue];
  173. bar.remainingTimeLabel.text = [remainingTime stringValue];
  174. }
  175. - (void)startScrubbing
  176. {
  177. VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
  178. self.transportBar.scrubbing = YES;
  179. [self updateDimmingView];
  180. if (vpc.isPlaying) {
  181. [vpc playPause];
  182. }
  183. }
  184. - (void)stopScrubbing
  185. {
  186. self.transportBar.scrubbing = NO;
  187. [self updateDimmingView];
  188. VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
  189. [vpc.mediaPlayer play];
  190. }
  191. - (void)updateDimmingView
  192. {
  193. BOOL shouldBeVisible = self.transportBar.scrubbing;
  194. BOOL isVisible = self.dimmingView.alpha == 1.0;
  195. if (shouldBeVisible != isVisible) {
  196. [UIView animateWithDuration:0.3 animations:^{
  197. self.dimmingView.alpha = shouldBeVisible ? 1.0 : 0.0;
  198. }];
  199. }
  200. }
  201. - (void)updateActivityIndicatorForState:(VLCMediaPlayerState)state {
  202. UIActivityIndicatorView *indicator = self.activityIndicator;
  203. switch (state) {
  204. case VLCMediaPlayerStateBuffering:
  205. if (!indicator.isAnimating) {
  206. self.activityIndicator.alpha = 1.0;
  207. [self.activityIndicator startAnimating];
  208. }
  209. break;
  210. default:
  211. if (indicator.isAnimating) {
  212. [self.activityIndicator stopAnimating];
  213. self.activityIndicator.alpha = 0.0;
  214. }
  215. break;
  216. }
  217. }
  218. #pragma mark - PlaybackControls
  219. - (void)fireHidePlaybackControlsIfNotPlayingTimer:(NSTimer *)timer
  220. {
  221. BOOL playing = [[VLCPlaybackController sharedInstance] isPlaying];
  222. if (playing) {
  223. [self animatePlaybackControlsToVisibility:NO];
  224. }
  225. }
  226. - (void)showPlaybackControlsIfNeededForUserInteraction
  227. {
  228. if (self.bottomOverlayView.alpha == 0.0) {
  229. [self animatePlaybackControlsToVisibility:YES];
  230. }
  231. [self hidePlaybackControlsIfNeededAfterDelay];
  232. }
  233. - (void)hidePlaybackControlsIfNeededAfterDelay
  234. {
  235. self.hidePlaybackControlsViewAfterDeleayTimer = [NSTimer scheduledTimerWithTimeInterval:3.0
  236. target:self
  237. selector:@selector(fireHidePlaybackControlsIfNotPlayingTimer:)
  238. userInfo:nil repeats:NO];
  239. }
  240. - (void)animatePlaybackControlsToVisibility:(BOOL)visible
  241. {
  242. NSTimeInterval duration = visible ? 0.3 : 1.0;
  243. CGFloat alpha = visible ? 1.0 : 0.0;
  244. [UIView animateWithDuration:duration
  245. animations:^{
  246. self.bottomOverlayView.alpha = alpha;
  247. }];
  248. }
  249. #pragma mark - Properties
  250. - (void)setHidePlaybackControlsViewAfterDeleayTimer:(NSTimer *)hidePlaybackControlsViewAfterDeleayTimer {
  251. [_hidePlaybackControlsViewAfterDeleayTimer invalidate];
  252. _hidePlaybackControlsViewAfterDeleayTimer = hidePlaybackControlsViewAfterDeleayTimer;
  253. }
  254. #pragma mark - playback controller delegation
  255. - (void)prepareForMediaPlayback:(VLCPlaybackController *)controller
  256. {
  257. APLog(@"%s", __PRETTY_FUNCTION__);
  258. }
  259. - (void)playbackDidStop:(NSNotification *)aNotification
  260. {
  261. [self dismissViewControllerAnimated:YES completion:nil];
  262. }
  263. - (void)mediaPlayerStateChanged:(VLCMediaPlayerState)currentState
  264. isPlaying:(BOOL)isPlaying
  265. currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
  266. currentMediaHasChapters:(BOOL)currentMediaHasChapters
  267. forPlaybackController:(VLCPlaybackController *)controller
  268. {
  269. [self updateActivityIndicatorForState:currentState];
  270. if (controller.isPlaying) {
  271. [self hidePlaybackControlsIfNeededAfterDelay];
  272. } else {
  273. [self showPlaybackControlsIfNeededForUserInteraction];
  274. }
  275. if (controller.isPlaying && !self.bufferingLabel.hidden) {
  276. [UIView animateWithDuration:.3 animations:^{
  277. self.bufferingLabel.hidden = YES;
  278. }];
  279. }
  280. }
  281. - (void)displayMetadataForPlaybackController:(VLCPlaybackController *)controller
  282. title:(NSString *)title
  283. artwork:(UIImage *)artwork
  284. artist:(NSString *)artist
  285. album:(NSString *)album
  286. audioOnly:(BOOL)audioOnly
  287. {
  288. self.titleLabel.text = title;
  289. }
  290. #pragma mark -
  291. - (void)playbackPositionUpdated:(VLCPlaybackController *)controller
  292. {
  293. VLCMediaPlayer *mediaPlayer = [VLCPlaybackController sharedInstance].mediaPlayer;
  294. // FIXME: hard coded state since the state in mediaPlayer is incorrectly still buffering
  295. [self updateActivityIndicatorForState:VLCMediaPlayerStatePlaying];
  296. VLCTransportBar *transportBar = self.transportBar;
  297. transportBar.remainingTimeLabel.text = [[mediaPlayer remainingTime] stringValue];
  298. transportBar.markerTimeLabel.text = [[mediaPlayer time] stringValue];
  299. transportBar.playbackFraction = mediaPlayer.position;
  300. }
  301. #pragma mark - gesture recognizer delegate
  302. - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
  303. if ([gestureRecognizer.allowedPressTypes containsObject:@(UIPressTypeMenu)]) {
  304. return self.transportBar.scrubbing;
  305. }
  306. return YES;
  307. }
  308. @end
  309. @implementation VLCFullscreenMovieTVViewController (UIViewControllerTransitioningDelegate)
  310. - (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
  311. {
  312. return [[VLCPlaybackInfoTVTransitioningAnimator alloc] init];
  313. }
  314. - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
  315. {
  316. return [[VLCPlaybackInfoTVTransitioningAnimator alloc] init];
  317. }
  318. @end