VLCFullscreenMovieTVViewController.m 14 KB

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