浏览代码

add support for IR remote scanning when playing and jump forward/backward when paused

Tobias Conradi 9 年之前
父节点
当前提交
9edf0334b6

+ 137 - 2
VLC for Apple TV/Playback/VLCFullscreenMovieTVViewController.m

@@ -14,6 +14,13 @@
 #import "VLCPlaybackInfoTVAnimators.h"
 #import "VLCPlaybackInfoTVAnimators.h"
 #import "VLCIRTVTapGestureRecognizer.h"
 #import "VLCIRTVTapGestureRecognizer.h"
 
 
+typedef NS_ENUM(NSInteger, VLCPlayerScanState)
+{
+    VLCPlayerScanStateNone,
+    VLCPlayerScanStateForward2,
+    VLCPlayerScanStateForward4,
+};
+
 @interface VLCFullscreenMovieTVViewController (UIViewControllerTransitioningDelegate) <UIViewControllerTransitioningDelegate, UIGestureRecognizerDelegate>
 @interface VLCFullscreenMovieTVViewController (UIViewControllerTransitioningDelegate) <UIViewControllerTransitioningDelegate, UIGestureRecognizerDelegate>
 @end
 @end
 
 
@@ -21,6 +28,8 @@
 
 
 @property (nonatomic) NSTimer *hidePlaybackControlsViewAfterDeleayTimer;
 @property (nonatomic) NSTimer *hidePlaybackControlsViewAfterDeleayTimer;
 @property (nonatomic) VLCPlaybackInfoTVViewController *infoViewController;
 @property (nonatomic) VLCPlaybackInfoTVViewController *infoViewController;
+@property (nonatomic) NSNumber *scanSavedPlaybackRate;
+@property (nonatomic) VLCPlayerScanState scanState;
 @end
 @end
 
 
 @implementation VLCFullscreenMovieTVViewController
 @implementation VLCFullscreenMovieTVViewController
@@ -82,6 +91,13 @@
     downArrowRecognizer.allowedPressTypes = @[@(UIPressTypeDownArrow)];
     downArrowRecognizer.allowedPressTypes = @[@(UIPressTypeDownArrow)];
     [self.view addGestureRecognizer:downArrowRecognizer];
     [self.view addGestureRecognizer:downArrowRecognizer];
 
 
+    UITapGestureRecognizer *leftArrowRecognizer = [[VLCIRTVTapGestureRecognizer alloc] initWithTarget:self action:@selector(handleIRPressLeft)];
+    leftArrowRecognizer.allowedPressTypes = @[@(UIPressTypeLeftArrow)];
+    [self.view addGestureRecognizer:leftArrowRecognizer];
+
+    UITapGestureRecognizer *rightArrowRecognizer = [[VLCIRTVTapGestureRecognizer alloc] initWithTarget:self action:@selector(handleIRPressRight)];
+    rightArrowRecognizer.allowedPressTypes = @[@(UIPressTypeRightArrow)];
+    [self.view addGestureRecognizer:rightArrowRecognizer];
 }
 }
 
 
 - (void)didReceiveMemoryWarning
 - (void)didReceiveMemoryWarning
@@ -135,6 +151,8 @@
 {
 {
     [self showPlaybackControlsIfNeededForUserInteraction];
     [self showPlaybackControlsIfNeededForUserInteraction];
 
 
+    [self setScanState:VLCPlayerScanStateNone];
+
     VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
     VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
     if (self.transportBar.scrubbing) {
     if (self.transportBar.scrubbing) {
         [self selectButtonPressed:nil];
         [self selectButtonPressed:nil];
@@ -171,6 +189,7 @@
         }
         }
     }
     }
     [self showPlaybackControlsIfNeededForUserInteraction];
     [self showPlaybackControlsIfNeededForUserInteraction];
+    [self setScanState:VLCPlayerScanStateNone];
 
 
 
 
     const CGFloat scaleFactor = 8.0;
     const CGFloat scaleFactor = 8.0;
@@ -199,6 +218,7 @@
 - (void)selectButtonPressed:(UITapGestureRecognizer *)recognizer
 - (void)selectButtonPressed:(UITapGestureRecognizer *)recognizer
 {
 {
     [self showPlaybackControlsIfNeededForUserInteraction];
     [self showPlaybackControlsIfNeededForUserInteraction];
+    [self setScanState:VLCPlayerScanStateNone];
 
 
     VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
     VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
     VLCTransportBar *bar = self.transportBar;
     VLCTransportBar *bar = self.transportBar;
@@ -236,7 +256,122 @@
     [self animatePlaybackControlsToVisibility:NO];
     [self animatePlaybackControlsToVisibility:NO];
 }
 }
 
 
-#pragma mark - 
+- (void)handleIRPressLeft
+{
+    [self showPlaybackControlsIfNeededForUserInteraction];
+    BOOL paused = ![VLCPlaybackController sharedInstance].isPlaying;
+    if (paused) {
+        [self jumpBackward];
+    } else
+    {
+        [self scanForwardPrevious];
+    }
+}
+
+- (void)handleIRPressRight
+{
+    [self showPlaybackControlsIfNeededForUserInteraction];
+    BOOL paused = ![VLCPlaybackController sharedInstance].isPlaying;
+    if (paused) {
+        [self jumpForward];
+    } else {
+        [self scanForwardNext];
+    }
+}
+
+#pragma mark -
+static const NSInteger VLCJumpInterval = 10000; // 10 seconds
+- (void)jumpForward
+{
+    [self jumpInterval:VLCJumpInterval];
+}
+- (void)jumpBackward
+{
+    [self jumpInterval:-VLCJumpInterval];
+}
+
+- (void)jumpInterval:(NSInteger)interval
+{
+    NSInteger duration = [VLCPlaybackController sharedInstance].mediaDuration;
+    if (duration==0) {
+        return;
+    }
+    CGFloat intervalFraction = ((CGFloat)interval)/((CGFloat)duration);
+    VLCTransportBar *bar = self.transportBar;
+    bar.scrubbing = YES;
+    CGFloat currentFraction = bar.scrubbingFraction;
+    currentFraction += intervalFraction;
+    bar.scrubbingFraction = currentFraction;
+    [self updateTimeLabelsForScrubbingFraction:currentFraction];
+}
+
+- (void)scanForwardNext
+{
+    VLCPlayerScanState nextState = self.scanState;
+    switch (self.scanState) {
+        case VLCPlayerScanStateNone:
+            nextState = VLCPlayerScanStateForward2;
+            break;
+        case VLCPlayerScanStateForward2:
+            nextState = VLCPlayerScanStateForward4;
+            break;
+        case VLCPlayerScanStateForward4:
+            return;
+        default:
+            return;
+    }
+    [self setScanState:nextState];
+}
+
+- (void)scanForwardPrevious
+{
+    VLCPlayerScanState nextState = self.scanState;
+    switch (self.scanState) {
+        case VLCPlayerScanStateNone:
+            return;
+        case VLCPlayerScanStateForward2:
+            nextState = VLCPlayerScanStateNone;
+            break;
+        case VLCPlayerScanStateForward4:
+            nextState = VLCPlayerScanStateForward2;
+            break;
+        default:
+            return;
+    }
+    [self setScanState:nextState];
+}
+
+
+- (void)setScanState:(VLCPlayerScanState)scanState
+{
+    if (_scanState == VLCPlayerScanStateNone) {
+        self.scanSavedPlaybackRate = @([VLCPlaybackController sharedInstance].playbackRate);
+    }
+    _scanState = scanState;
+    float rate = 1.0;
+    VLCTransportBarHint hint = VLCTransportBarHintNone;
+    switch (scanState) {
+        case VLCPlayerScanStateForward2:
+            rate = 2.0;
+            hint = VLCTransportBarHintScanForward;
+            break;
+        case VLCPlayerScanStateForward4:
+            rate = 4.0;
+            hint = VLCTransportBarHintScanForward;
+            break;
+
+        case VLCPlayerScanStateNone:
+        default:
+            rate = self.scanSavedPlaybackRate.floatValue ?: 1.0;
+            hint = VLCTransportBarHintNone;
+            self.scanSavedPlaybackRate = nil;
+            break;
+    }
+
+    [VLCPlaybackController sharedInstance].playbackRate = rate;
+    [self.transportBar setHint:hint];
+}
+#pragma mark -
 
 
 - (void)updateTimeLabelsForScrubbingFraction:(CGFloat)scrubbingFraction
 - (void)updateTimeLabelsForScrubbingFraction:(CGFloat)scrubbingFraction
 {
 {
@@ -395,7 +530,7 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
 
 
 - (void)playbackPositionUpdated:(VLCPlaybackController *)controller
 - (void)playbackPositionUpdated:(VLCPlaybackController *)controller
 {
 {
-    VLCMediaPlayer *mediaPlayer = [VLCPlaybackController sharedInstance].mediaPlayer;
+    VLCMediaPlayer *mediaPlayer = controller.mediaPlayer;
     // FIXME: hard coded state since the state in mediaPlayer is incorrectly still buffering
     // FIXME: hard coded state since the state in mediaPlayer is incorrectly still buffering
     [self updateActivityIndicatorForState:VLCMediaPlayerStatePlaying];
     [self updateActivityIndicatorForState:VLCMediaPlayerStatePlaying];
 
 

+ 9 - 0
VLC for Apple TV/Playback/VLCTransportBar.h

@@ -13,6 +13,13 @@
 
 
 NS_ASSUME_NONNULL_BEGIN
 NS_ASSUME_NONNULL_BEGIN
 
 
+typedef NS_ENUM(NSUInteger, VLCTransportBarHint) {
+    VLCTransportBarHintNone,
+    VLCTransportBarHintScanForward,
+    VLCTransportBarHintJumpForward10,
+    VLCTransportBarHintJumpBackward10,
+};
+
 IB_DESIGNABLE @interface VLCTransportBar : UIView
 IB_DESIGNABLE @interface VLCTransportBar : UIView
 @property (nonatomic) IBInspectable CGFloat bufferStartFraction;
 @property (nonatomic) IBInspectable CGFloat bufferStartFraction;
 @property (nonatomic) IBInspectable CGFloat bufferEndFraction;
 @property (nonatomic) IBInspectable CGFloat bufferEndFraction;
@@ -22,6 +29,8 @@ IB_DESIGNABLE @interface VLCTransportBar : UIView
 
 
 @property (nonatomic, readonly) UILabel *markerTimeLabel;
 @property (nonatomic, readonly) UILabel *markerTimeLabel;
 @property (nonatomic, readonly) UILabel *remainingTimeLabel;
 @property (nonatomic, readonly) UILabel *remainingTimeLabel;
+
+-(void)setHint:(VLCTransportBarHint)hint;
 @end
 @end
 
 
 NS_ASSUME_NONNULL_END
 NS_ASSUME_NONNULL_END

+ 70 - 1
VLC for Apple TV/Playback/VLCTransportBar.m

@@ -16,6 +16,9 @@
 @property (nonatomic) VLCBufferingBar *bufferingBar;
 @property (nonatomic) VLCBufferingBar *bufferingBar;
 @property (nonatomic) UIView *playbackPositionMarker;
 @property (nonatomic) UIView *playbackPositionMarker;
 @property (nonatomic) UIView *scrubbingPostionMarker;
 @property (nonatomic) UIView *scrubbingPostionMarker;
+
+@property (nonatomic) UIImageView *leftHintImageView;
+@property (nonatomic) UIImageView *rightHintImageView;
 @end
 @end
 
 
 @implementation VLCTransportBar
 @implementation VLCTransportBar
@@ -54,7 +57,7 @@ static inline void sharedSetup(VLCTransportBar *self) {
     UIFont *font = [UIFont monospacedDigitSystemFontOfSize:size weight:UIFontWeightSemibold];
     UIFont *font = [UIFont monospacedDigitSystemFontOfSize:size weight:UIFontWeightSemibold];
     UIColor *textColor = [UIColor whiteColor];
     UIColor *textColor = [UIColor whiteColor];
 
 
-    UILabel *markerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
+    UILabel *markerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
     markerLabel.font = font;
     markerLabel.font = font;
     markerLabel.textColor = textColor;
     markerLabel.textColor = textColor;
     [self addSubview:markerLabel];
     [self addSubview:markerLabel];
@@ -65,6 +68,18 @@ static inline void sharedSetup(VLCTransportBar *self) {
     remainingLabel.textColor = textColor;
     remainingLabel.textColor = textColor;
     [self addSubview:remainingLabel];
     [self addSubview:remainingLabel];
     self->_remainingTimeLabel = remainingLabel;
     self->_remainingTimeLabel = remainingLabel;
+
+
+    CGFloat iconLength = 32.0;
+    CGRect imageRect = CGRectMake(0, 0, iconLength, iconLength);
+
+    UIImageView *leftHintImageView = [[UIImageView alloc] initWithFrame:imageRect];
+    [self addSubview:leftHintImageView];
+    self.leftHintImageView = leftHintImageView;
+
+    UIImageView *rightHintImageView = [[UIImageView alloc] initWithFrame:imageRect];
+    [self addSubview:rightHintImageView];
+    self.rightHintImageView = rightHintImageView;
 }
 }
 
 
 - (instancetype)initWithFrame:(CGRect)frame
 - (instancetype)initWithFrame:(CGRect)frame
@@ -107,6 +122,50 @@ static inline void sharedSetup(VLCTransportBar *self) {
     [self setNeedsLayout];
     [self setNeedsLayout];
 }
 }
 
 
+- (UIImage *)imageForHint:(VLCTransportBarHint)hint
+{
+    NSString *imageName = nil;
+    switch (hint) {
+        case VLCTransportBarHintScanForward:
+            imageName = @"NowPlayingFastForward.png";
+            break;
+        case VLCTransportBarHintJumpForward10:
+            imageName = @"NowPlayingSkip10Forward.png";
+            break;
+        case VLCTransportBarHintJumpBackward10:
+            imageName = @"NowPlayingSkip10Backward.png";
+            break;
+        default:
+			break;
+	}
+    if (imageName) {
+        // FIXME: TODO: don't use the images from AVKit
+        NSBundle *bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/AVKit.framework"];
+        return [UIImage imageNamed:imageName inBundle:bundle compatibleWithTraitCollection:nil];
+    }
+    return nil;
+}
+- (void)setHint:(VLCTransportBarHint)hint
+{
+    UIImage *leftImage = nil;
+    UIImage *rightImage = nil;
+	switch (hint) {
+        case VLCTransportBarHintScanForward:
+        case VLCTransportBarHintJumpForward10:
+            rightImage = [self imageForHint:hint];
+			break;
+        case VLCTransportBarHintJumpBackward10:
+            leftImage = [self imageForHint:hint];
+            break;
+        default:
+			break;
+	}
+
+    // TODO: add animations
+    self.leftHintImageView.image = leftImage;
+    self.rightHintImageView.image = rightImage;
+}
+
 - (void)layoutSubviews {
 - (void)layoutSubviews {
     [super layoutSubviews];
     [super layoutSubviews];
     const CGRect bounds = self.bounds;
     const CGRect bounds = self.bounds;
@@ -137,6 +196,16 @@ static inline void sharedSetup(VLCTransportBar *self) {
     timeLabelCenter.x = self.scrubbingPostionMarker.center.x;
     timeLabelCenter.x = self.scrubbingPostionMarker.center.x;
     markerLabel.center = timeLabelCenter;
     markerLabel.center = timeLabelCenter;
 
 
+    CGRect markerLabelFrame = markerLabel.frame;
+
+    UIImageView *leftHint = self.leftHintImageView;
+    CGFloat leftImageSize = CGRectGetWidth(leftHint.bounds);
+    leftHint.center = CGPointMake(CGRectGetMinX(markerLabelFrame)-leftImageSize, timeLabelCenter.y);
+
+    UIImageView *rightHint = self.rightHintImageView;
+    CGFloat rightImageSize = CGRectGetWidth(rightHint.bounds);
+    rightHint.center = CGPointMake(CGRectGetMaxX(markerLabelFrame)+rightImageSize, timeLabelCenter.y);
+
     CGFloat remainingAlfa = CGRectIntersectsRect(markerLabel.frame, remainingLabelFrame) ? 0.0 : 1.0;
     CGFloat remainingAlfa = CGRectIntersectsRect(markerLabel.frame, remainingLabelFrame) ? 0.0 : 1.0;
     remainingLabel.alpha = remainingAlfa;
     remainingLabel.alpha = remainingAlfa;
 }
 }