Browse Source

add custom transport bar which reassembles the AVPlayer transport bar

Tobias Conradi 9 years ago
parent
commit
3cdf652db7

+ 1 - 0
Sources/VLCFrostedGlasView.m

@@ -59,6 +59,7 @@
     _effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
     _effectView.frame = self.bounds;
     _effectView.clipsToBounds = YES;
+    _effectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
     [self insertSubview:_effectView atIndex:0];
 #endif
 }

+ 22 - 0
VLC for Apple TV/VLCBufferingBar.h

@@ -0,0 +1,22 @@
+/*****************************************************************************
+ * VLC for iOS
+ *****************************************************************************
+ * Copyright (c) 2015 VideoLAN. All rights reserved.
+ * $Id$
+ *
+ * Authors: Tobias Conradi <videolan # tobias-conradi.de>
+ *
+ * Refer to the COPYING file of the official project for license.
+ *****************************************************************************/
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+@interface VLCBufferingBar : UIView
+@property (nonatomic) CGFloat bufferStartFraction;
+@property (nonatomic) CGFloat bufferEndFraction;
+
+@property (nonatomic) UIColor *bufferColor;
+@property (nonatomic) UIColor *borderColor;
+@end
+NS_ASSUME_NONNULL_END

+ 89 - 0
VLC for Apple TV/VLCBufferingBar.m

@@ -0,0 +1,89 @@
+/*****************************************************************************
+ * VLC for iOS
+ *****************************************************************************
+ * Copyright (c) 2015 VideoLAN. All rights reserved.
+ * $Id$
+ *
+ * Authors: Tobias Conradi <videolan # tobias-conradi.de>
+ *
+ * Refer to the COPYING file of the official project for license.
+ *****************************************************************************/
+
+#import "VLCBufferingBar.h"
+@interface VLCBufferingBar()
+@property (nonatomic) CAShapeLayer *borderLayer;
+@property (nonatomic) CAShapeLayer *fillLayer;
+@property (nonatomic) CAShapeLayer *fillMaskLayer;
+
+@end
+
+@implementation VLCBufferingBar
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    self = [super initWithFrame:frame];
+    if (self) {
+
+        _borderColor = [UIColor lightGrayColor];
+        _bufferColor = [UIColor lightGrayColor];
+
+        _borderLayer = [CAShapeLayer layer];
+        _borderLayer.lineWidth = 2.0;
+        _borderLayer.fillColor = [UIColor clearColor].CGColor;
+        _borderLayer.strokeColor = _borderColor.CGColor;
+
+        [self.layer addSublayer:_borderLayer];
+
+        _fillLayer = [CAShapeLayer layer];
+        _fillLayer.fillColor = _bufferColor.CGColor;
+
+        _fillMaskLayer = [CAShapeLayer layer];
+        _fillMaskLayer.fillColor = [UIColor blackColor].CGColor;
+        _fillLayer.mask = _fillMaskLayer;
+
+        [self.layer addSublayer:_fillLayer];
+
+    }
+    return self;
+}
+
+- (void)setBufferColor:(UIColor *)bufferColor {
+    _bufferColor = bufferColor;
+    self.fillLayer.fillColor = bufferColor.CGColor;
+}
+- (void)setBorderColor:(UIColor *)borderColor {
+    _borderColor = borderColor;
+    self.borderLayer.strokeColor = borderColor.CGColor;
+}
+
+- (void)setBufferStartFraction:(CGFloat)bufferStartFraction {
+    _bufferStartFraction = bufferStartFraction;
+    [self setNeedsLayout];
+}
+- (void)setBufferEndFraction:(CGFloat)bufferEndFraction {
+    _bufferEndFraction = bufferEndFraction;
+    [self setNeedsLayout];
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGRect bounds = self.bounds;
+    CGFloat inset = self.borderLayer.lineWidth/2.0;
+    CGRect borderRect = CGRectInset(bounds, inset, inset);
+    CGFloat cornerRadius = CGRectGetMidY(bounds); // bounds is correct (flatter)
+    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:borderRect cornerRadius:cornerRadius];
+    self.borderLayer.path = path.CGPath;
+
+    CGRect bufferRect = CGRectMake(CGRectGetWidth(bounds)*self.bufferStartFraction,
+                                   0,
+                                   CGRectGetWidth(bounds)*(self.bufferEndFraction-self.bufferStartFraction),
+                                   CGRectGetHeight(bounds));
+    UIBezierPath *bufferPath = [UIBezierPath bezierPathWithRect:bufferRect];
+    self.fillLayer.path = bufferPath.CGPath;
+    self.borderLayer.frame = bounds;
+    self.fillLayer.frame = bounds;
+    self.fillMaskLayer.frame = bounds;
+    self.fillMaskLayer.path = path.CGPath;
+}
+@end
+

+ 2 - 3
VLC for Apple TV/VLCFullscreenMovieTVViewController.h

@@ -12,15 +12,14 @@
 #import <UIKit/UIKit.h>
 
 #import "VLCPlaybackController.h"
+#import "VLCTransportBar.h"
 
 @interface VLCFullscreenMovieTVViewController : UIViewController <VLCPlaybackControllerDelegate>
 
 @property (readwrite, nonatomic, weak) IBOutlet UIView *movieView;
 
 @property (readwrite, nonatomic, weak) IBOutlet UIView *bottomOverlayView;
-@property (readwrite, nonatomic, weak) IBOutlet UIProgressView *playbackProgressView;
-@property (readwrite, nonatomic, weak) IBOutlet UILabel *playedTimeLabel;
-@property (readwrite, nonatomic, weak) IBOutlet UILabel *remainingTimeLabel;
+@property (readwrite, nonatomic, weak) IBOutlet VLCTransportBar *transportBar;
 @property (readwrite, nonatomic, weak) IBOutlet UILabel *titleLabel;
 @property (readwrite, nonatomic, weak) IBOutlet UILabel *bufferingLabel;
 @property (readwrite, nonatomic, weak) IBOutlet UIActivityIndicatorView *activityIndicator;

+ 12 - 5
VLC for Apple TV/VLCFullscreenMovieTVViewController.m

@@ -40,8 +40,13 @@
     _movieView.userInteractionEnabled = NO;
     _playerIsSetup = NO;
 
-    self.titleLabel.text = self.remainingTimeLabel.text = self.playedTimeLabel.text = @"";
-    self.playbackProgressView.progress = .0;
+    self.titleLabel.text = @"";
+
+    self.transportBar.bufferStartFraction = 0.0;
+    self.transportBar.bufferEndFraction = 1.0;
+    self.transportBar.playbackFraction = 0.0;
+    self.transportBar.scrubbingFraction = 0.0;
+
     self.bottomOverlayView.hidden = YES;
 
     UITapGestureRecognizer *playpauseGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(playPausePressed)];
@@ -156,9 +161,11 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
 - (void)playbackPositionUpdated:(VLCPlaybackController *)controller
 {
     VLCMediaPlayer *mediaPlayer = [VLCPlaybackController sharedInstance].mediaPlayer;
-    self.remainingTimeLabel.text = [[mediaPlayer remainingTime] stringValue];
-    self.playedTimeLabel.text = [[mediaPlayer time] stringValue];
-    self.playbackProgressView.progress = mediaPlayer.position;
+
+    VLCTransportBar *transportBar = self.transportBar;
+    transportBar.remainingTimeLabel.text = [[mediaPlayer remainingTime] stringValue];
+    transportBar.markerTimeLabel.text = [[mediaPlayer time] stringValue];
+    transportBar.playbackFraction = mediaPlayer.position;
 }
 
 @end

+ 21 - 34
VLC for Apple TV/VLCFullscreenMovieTVViewController.xib

@@ -9,11 +9,9 @@
                 <outlet property="bottomOverlayView" destination="SzB-KN-vRr" id="HdG-qX-fha"/>
                 <outlet property="bufferingLabel" destination="yaX-qU-D4t" id="pDV-iQ-eaa"/>
                 <outlet property="movieView" destination="SpU-aa-czI" id="zKW-zZ-hB6"/>
-                <outlet property="playbackProgressView" destination="b0E-Da-d7m" id="ZKe-aD-o2c"/>
-                <outlet property="playedTimeLabel" destination="Qph-m8-iCR" id="iRZ-62-zrZ"/>
                 <outlet property="preferredFocusedView" destination="iN0-l3-epB" id="obT-bV-VZv"/>
-                <outlet property="remainingTimeLabel" destination="rIg-pG-JWA" id="kfd-Dm-yho"/>
                 <outlet property="titleLabel" destination="epY-iV-5FH" id="7pR-09-6Fu"/>
+                <outlet property="transportBar" destination="CO6-ze-V9M" id="ogH-U0-9Vy"/>
                 <outlet property="view" destination="iN0-l3-epB" id="Eym-vH-oyN"/>
             </connections>
         </placeholder>
@@ -41,46 +39,35 @@
                     <nil key="highlightedColor"/>
                 </label>
                 <view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SzB-KN-vRr" customClass="VLCFrostedGlasView">
-                    <rect key="frame" x="0.0" y="940" width="1920" height="140"/>
+                    <rect key="frame" x="0.0" y="886" width="1920" height="194"/>
                     <subviews>
-                        <progressView opaque="NO" contentMode="scaleToFill" semanticContentAttribute="playback" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="b0E-Da-d7m">
-                            <rect key="frame" x="200" y="95" width="1520" height="10"/>
-                            <animations/>
-                        </progressView>
-                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" semanticContentAttribute="playback" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qph-m8-iCR">
-                            <rect key="frame" x="200" y="59" width="57" height="28"/>
-                            <animations/>
-                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption2"/>
-                            <color key="textColor" red="1" green="1" blue="1" alpha="0.59999999999999998" colorSpace="calibratedRGB"/>
-                            <nil key="highlightedColor"/>
-                        </label>
-                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" semanticContentAttribute="playback" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rIg-pG-JWA">
-                            <rect key="frame" x="1663" y="59" width="57" height="28"/>
-                            <animations/>
-                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption2"/>
-                            <color key="textColor" red="1" green="1" blue="1" alpha="0.59999999999999998" colorSpace="calibratedRGB"/>
-                            <nil key="highlightedColor"/>
-                        </label>
-                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="epY-iV-5FH">
-                            <rect key="frame" x="890" y="18" width="140" height="69"/>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="epY-iV-5FH">
+                            <rect key="frame" x="890" y="10" width="140" height="69"/>
                             <animations/>
+                            <constraints>
+                                <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="69" id="Cum-M9-lbH"/>
+                            </constraints>
                             <fontDescription key="fontDescription" style="UICTFontTextStyleTitle2"/>
                             <color key="textColor" red="1" green="1" blue="1" alpha="0.59999999999999998" colorSpace="calibratedRGB"/>
                             <nil key="highlightedColor"/>
                         </label>
+                        <view opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="CO6-ze-V9M" customClass="VLCTransportBar">
+                            <rect key="frame" x="90" y="94" width="1740" height="10"/>
+                            <animations/>
+                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="10" id="N7R-Ku-vGb"/>
+                            </constraints>
+                        </view>
                     </subviews>
                     <animations/>
                     <constraints>
-                        <constraint firstItem="b0E-Da-d7m" firstAttribute="top" secondItem="Qph-m8-iCR" secondAttribute="bottom" constant="8" id="4qM-OU-y9L"/>
-                        <constraint firstItem="rIg-pG-JWA" firstAttribute="trailing" secondItem="b0E-Da-d7m" secondAttribute="trailing" id="5Uf-62-xBp"/>
-                        <constraint firstAttribute="height" constant="140" id="JGE-bn-jF2"/>
-                        <constraint firstItem="epY-iV-5FH" firstAttribute="centerX" secondItem="b0E-Da-d7m" secondAttribute="centerX" id="RlC-TU-YCu"/>
-                        <constraint firstItem="b0E-Da-d7m" firstAttribute="top" secondItem="rIg-pG-JWA" secondAttribute="bottom" constant="8" id="Rxy-4w-OCf"/>
-                        <constraint firstAttribute="bottom" secondItem="b0E-Da-d7m" secondAttribute="bottom" constant="35" id="WRo-pW-Bul"/>
-                        <constraint firstItem="b0E-Da-d7m" firstAttribute="top" secondItem="epY-iV-5FH" secondAttribute="bottom" constant="8" id="bje-0n-PKO"/>
-                        <constraint firstAttribute="trailing" secondItem="b0E-Da-d7m" secondAttribute="trailing" constant="200" id="c2a-IL-fc2"/>
-                        <constraint firstItem="b0E-Da-d7m" firstAttribute="leading" secondItem="SzB-KN-vRr" secondAttribute="leading" constant="200" id="jpi-SZ-I5c"/>
-                        <constraint firstItem="Qph-m8-iCR" firstAttribute="leading" secondItem="b0E-Da-d7m" secondAttribute="leading" id="vJ1-lG-BUr"/>
+                        <constraint firstItem="CO6-ze-V9M" firstAttribute="top" secondItem="epY-iV-5FH" secondAttribute="bottom" constant="15" id="3KL-US-KZa"/>
+                        <constraint firstItem="CO6-ze-V9M" firstAttribute="leading" secondItem="SzB-KN-vRr" secondAttribute="leading" constant="90" id="6fm-9L-qPq"/>
+                        <constraint firstItem="epY-iV-5FH" firstAttribute="top" secondItem="SzB-KN-vRr" secondAttribute="top" constant="10" id="92r-mU-afS"/>
+                        <constraint firstItem="epY-iV-5FH" firstAttribute="centerX" secondItem="SzB-KN-vRr" secondAttribute="centerX" id="HiD-5l-FVo"/>
+                        <constraint firstAttribute="trailing" secondItem="CO6-ze-V9M" secondAttribute="trailing" constant="90" id="iA4-Us-HaM"/>
+                        <constraint firstAttribute="bottom" secondItem="CO6-ze-V9M" secondAttribute="bottom" constant="90" id="qW9-4Q-Y5z"/>
                     </constraints>
                 </view>
             </subviews>

+ 11 - 7
VLC for Apple TV/VLCPlaybackControlsFocusView.h

@@ -1,10 +1,14 @@
-//
-//  VLCPlaybackControlsFocusView.h
-//  VLC for iOS
-//
-//  Created by Tobias Conradi on 28.10.15.
-//  Copyright © 2015 VideoLAN. All rights reserved.
-//
+/*****************************************************************************
+ * VLC for iOS
+ *****************************************************************************
+ * Copyright (c) 2015 VideoLAN. All rights reserved.
+ * $Id$
+ *
+ * Authors: Tobias Conradi <videolan # tobias-conradi.de>
+ *
+ * Refer to the COPYING file of the official project for license.
+ *****************************************************************************/
+
 
 #import <UIKit/UIKit.h>
 

+ 10 - 7
VLC for Apple TV/VLCPlaybackControlsFocusView.m

@@ -1,10 +1,13 @@
-//
-//  VLCPlaybackControlsFocusView.m
-//  VLC for iOS
-//
-//  Created by Tobias Conradi on 28.10.15.
-//  Copyright © 2015 VideoLAN. All rights reserved.
-//
+/*****************************************************************************
+ * VLC for iOS
+ *****************************************************************************
+ * Copyright (c) 2015 VideoLAN. All rights reserved.
+ * $Id$
+ *
+ * Authors: Tobias Conradi <videolan # tobias-conradi.de>
+ *
+ * Refer to the COPYING file of the official project for license.
+ *****************************************************************************/
 
 #import "VLCPlaybackControlsFocusView.h"
 

+ 27 - 0
VLC for Apple TV/VLCTransportBar.h

@@ -0,0 +1,27 @@
+/*****************************************************************************
+ * VLC for iOS
+ *****************************************************************************
+ * Copyright (c) 2015 VideoLAN. All rights reserved.
+ * $Id$
+ *
+ * Authors: Tobias Conradi <videolan # tobias-conradi.de>
+ *
+ * Refer to the COPYING file of the official project for license.
+ *****************************************************************************/
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+IB_DESIGNABLE @interface VLCTransportBar : UIView
+@property (nonatomic) IBInspectable CGFloat bufferStartFraction;
+@property (nonatomic) IBInspectable CGFloat bufferEndFraction;
+@property (nonatomic) IBInspectable CGFloat playbackFraction;
+@property (nonatomic) IBInspectable CGFloat scrubbingFraction;
+@property (nonatomic, getter=isScrubbing) IBInspectable BOOL scrubbing;
+
+@property (nonatomic, readonly) UILabel *markerTimeLabel;
+@property (nonatomic, readonly) UILabel *remainingTimeLabel;
+@end
+
+NS_ASSUME_NONNULL_END

+ 165 - 0
VLC for Apple TV/VLCTransportBar.m

@@ -0,0 +1,165 @@
+/*****************************************************************************
+ * VLC for iOS
+ *****************************************************************************
+ * Copyright (c) 2015 VideoLAN. All rights reserved.
+ * $Id$
+ *
+ * Authors: Tobias Conradi <videolan # tobias-conradi.de>
+ *
+ * Refer to the COPYING file of the official project for license.
+ *****************************************************************************/
+
+#import "VLCTransportBar.h"
+#import "VLCBufferingBar.h"
+
+@interface VLCTransportBar ()
+@property (nonatomic) VLCBufferingBar *bufferingBar;
+@property (nonatomic) UIView *playbackPositionMarker;
+@property (nonatomic) UIView *scrubbingPostionMarker;
+@end
+
+@implementation VLCTransportBar
+
+static const CGFloat VLCTransportBarMarkerWidth = 2.0;
+
+static inline void sharedSetup(VLCTransportBar *self) {
+    CGRect bounds = self.bounds;
+
+    // Bar:
+    VLCBufferingBar *bar = [[VLCBufferingBar alloc] initWithFrame:bounds];
+    UIColor *barColor =  [UIColor lightGrayColor];
+    bar.bufferColor = barColor;
+    bar.borderColor = barColor;
+    bar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+    bar.bufferStartFraction = self.bufferStartFraction;
+    bar.bufferEndFraction = self.bufferEndFraction;
+    self.bufferingBar = bar;
+    [self addSubview:bar];
+
+    // Marker:
+    UIColor *markerColor = [UIColor whiteColor];
+    UIView *playbackMarker = [[UIView alloc] initWithFrame:CGRectMake(0, 0, VLCTransportBarMarkerWidth, CGRectGetHeight(bounds))];
+    playbackMarker.autoresizingMask = UIViewAutoresizingFlexibleHeight;
+    playbackMarker.backgroundColor = markerColor;
+    [self addSubview:playbackMarker];
+    self.playbackPositionMarker = playbackMarker;
+
+    UIView *scrubbingMarker = [[UIView alloc] initWithFrame:CGRectMake(0, 0, VLCTransportBarMarkerWidth, CGRectGetHeight(bounds))];
+    [self addSubview:scrubbingMarker];
+    scrubbingMarker.backgroundColor = markerColor;
+    self.scrubbingPostionMarker = scrubbingMarker;
+
+    // Labels:
+    CGFloat size = [UIFont preferredFontForTextStyle:UIFontTextStyleCallout].pointSize;
+    UIFont *font = [UIFont monospacedDigitSystemFontOfSize:size weight:UIFontWeightSemibold];
+    UIColor *textColor = [UIColor whiteColor];
+
+    UILabel *markerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
+    markerLabel.font = font;
+    markerLabel.textColor = textColor;
+    [self addSubview:markerLabel];
+    self->_markerTimeLabel = markerLabel;
+
+    UILabel *remainingLabel = [[UILabel alloc] initWithFrame:CGRectZero];
+    remainingLabel.font = font;
+    remainingLabel.textColor = textColor;
+    [self addSubview:remainingLabel];
+    self->_remainingTimeLabel = remainingLabel;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    self = [super initWithFrame:frame];
+    if (self) {
+        sharedSetup(self);
+    }
+    return self;
+}
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    sharedSetup(self);
+}
+
+- (void)setBufferStartFraction:(CGFloat)bufferStartFraction {
+    _bufferStartFraction = bufferStartFraction;
+    self.bufferingBar.bufferStartFraction = bufferStartFraction;
+}
+- (void)setBufferEndFraction:(CGFloat)bufferEndFraction {
+    _bufferEndFraction = bufferEndFraction;
+    self.bufferingBar.bufferEndFraction = bufferEndFraction;
+}
+- (void)setPlaybackFraction:(CGFloat)playbackFraction {
+    _playbackFraction = playbackFraction;
+    if (!self.scrubbing) {
+        [self setScrubbingFraction:playbackFraction];
+    }
+    [self setNeedsLayout];
+}
+- (void)setScrubbingFraction:(CGFloat)scrubbingFraction {
+    _scrubbingFraction = scrubbingFraction;
+    [self setNeedsLayout];
+}
+- (void)setScrubbing:(BOOL)scrubbing {
+    _scrubbing = scrubbing;
+    [self setNeedsLayout];
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    const CGRect bounds = self.bounds;
+    const CGFloat width = CGRectGetWidth(bounds)-VLCTransportBarMarkerWidth;
+
+    self.playbackPositionMarker.center = CGPointMake(width*self.playbackFraction+VLCTransportBarMarkerWidth/2.0,
+                                                     CGRectGetMidY(bounds));
+
+
+    const BOOL withThumbnail = NO;
+    const CGRect scrubberFrame = scrubbingMarkerFrameForBounds_fraction_withThumb(bounds,
+                                                                                  self.scrubbingFraction,
+                                                                                  withThumbnail);
+    self.scrubbingPostionMarker.frame = scrubberFrame;
+
+
+    UILabel *remainingLabel = self.remainingTimeLabel;
+    [remainingLabel sizeToFit];
+    CGRect remainingLabelFrame = remainingLabel.frame;
+    remainingLabelFrame.origin.y = CGRectGetMaxY(bounds)+15.0;
+    remainingLabelFrame.origin.x = width-CGRectGetWidth(remainingLabelFrame);
+    remainingLabel.frame = remainingLabelFrame;
+
+    UILabel *markerLabel = self.markerTimeLabel;
+    [markerLabel sizeToFit];
+
+    CGPoint timeLabelCenter = remainingLabel.center;
+    timeLabelCenter.x = self.scrubbingPostionMarker.center.x;
+    markerLabel.center = timeLabelCenter;
+
+    CGFloat remainingAlfa = CGRectIntersectsRect(markerLabel.frame, remainingLabelFrame) ? 0.0 : 1.0;
+    remainingLabel.alpha = remainingAlfa;
+}
+
+
+static CGRect scrubbingMarkerFrameForBounds_fraction_withThumb(CGRect bounds, CGFloat fraction, BOOL withThumbnail) {
+    const CGFloat width = CGRectGetWidth(bounds)-VLCTransportBarMarkerWidth;
+    const CGFloat height = CGRectGetHeight(bounds);
+
+    // when scrubbing marker is 4x instead of 3x bar heigt
+    const CGFloat scrubbingHeight = height * (withThumbnail ? 4.0 : 3.0);
+
+    // x position is always center of marker == view width * fraction
+    const CGFloat scrubbingXPosition = width*fraction;
+    CGFloat scrubbingYPosition = 0;
+    if (withThumbnail) {
+        // scrubbing marker bottom and bar buttom are same
+        scrubbingYPosition = height-scrubbingHeight;
+    } else {
+        // scrubbing marker y center == bar y center
+        scrubbingYPosition = height/2.0 - scrubbingHeight/2.0;
+    }
+    return CGRectMake(scrubbingXPosition,
+                      scrubbingYPosition,
+                      VLCTransportBarMarkerWidth,
+                      scrubbingHeight);
+}
+
+@end

+ 12 - 0
VLC for iOS.xcodeproj/project.pbxproj

@@ -321,6 +321,8 @@
 		DD7110F01AF38B2B00854776 /* MLMediaLibrary+playlist.m in Sources */ = {isa = PBXBuildFile; fileRef = DD7110EF1AF38B2B00854776 /* MLMediaLibrary+playlist.m */; };
 		DD7BA2631B680C8E002D9F54 /* MediaLibraryKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD7BA2601B680C1B002D9F54 /* MediaLibraryKit.framework */; };
 		DD7BA2641B680C8E002D9F54 /* MediaLibraryKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DD7BA2601B680C1B002D9F54 /* MediaLibraryKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		DD8095D61BE3C3BA0065D8E1 /* VLCTransportBar.m in Sources */ = {isa = PBXBuildFile; fileRef = DD8095D51BE3C3BA0065D8E1 /* VLCTransportBar.m */; };
+		DD8095DB1BE3C42F0065D8E1 /* VLCBufferingBar.m in Sources */ = {isa = PBXBuildFile; fileRef = DD8095DA1BE3C42F0065D8E1 /* VLCBufferingBar.m */; };
 		DD8F84311B00EB3B0009138A /* VLCPlaybackController+MediaLibrary.m in Sources */ = {isa = PBXBuildFile; fileRef = DD8F84301B00EB3B0009138A /* VLCPlaybackController+MediaLibrary.m */; };
 		DDAD5C2B1BB999CA006AFD3B /* VLCMovieViewControlPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = DDAD5C2A1BB999CA006AFD3B /* VLCMovieViewControlPanel.xib */; };
 		DDB7C6A41BAEB28200E6570E /* WKInterfaceController+VLCConnectionAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = DD9FBE761BAD6BB600FFE77A /* WKInterfaceController+VLCConnectionAlert.m */; };
@@ -976,6 +978,10 @@
 		DD7110EE1AF38B2B00854776 /* MLMediaLibrary+playlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MLMediaLibrary+playlist.h"; sourceTree = "<group>"; };
 		DD7110EF1AF38B2B00854776 /* MLMediaLibrary+playlist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MLMediaLibrary+playlist.m"; sourceTree = "<group>"; };
 		DD7BA2601B680C1B002D9F54 /* MediaLibraryKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MediaLibraryKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		DD8095D41BE3C3BA0065D8E1 /* VLCTransportBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCTransportBar.h; sourceTree = "<group>"; };
+		DD8095D51BE3C3BA0065D8E1 /* VLCTransportBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCTransportBar.m; sourceTree = "<group>"; };
+		DD8095D91BE3C42F0065D8E1 /* VLCBufferingBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCBufferingBar.h; sourceTree = "<group>"; };
+		DD8095DA1BE3C42F0065D8E1 /* VLCBufferingBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCBufferingBar.m; sourceTree = "<group>"; };
 		DD8C8F9F1B676C0900B3C4EE /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
 		DD8C8FA01B676C0F00B3C4EE /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
 		DD8C8FA11B676C1700B3C4EE /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -1863,6 +1869,10 @@
 			children = (
 				DD3EABED1BE14720003668DA /* VLCPlaybackControlsFocusView.h */,
 				DD3EABEE1BE14720003668DA /* VLCPlaybackControlsFocusView.m */,
+				DD8095D91BE3C42F0065D8E1 /* VLCBufferingBar.h */,
+				DD8095DA1BE3C42F0065D8E1 /* VLCBufferingBar.m */,
+				DD8095D41BE3C3BA0065D8E1 /* VLCTransportBar.h */,
+				DD8095D51BE3C3BA0065D8E1 /* VLCTransportBar.m */,
 				7DEC8BDB1BD67899006E1093 /* VLCFullscreenMovieTVViewController.h */,
 				7DEC8BDC1BD67899006E1093 /* VLCFullscreenMovieTVViewController.m */,
 			);
@@ -2660,6 +2670,7 @@
 				7DC71D211BC83058001FACAA /* VLCAppSharesTVViewController.m in Sources */,
 				DDEAECBF1BDEBF6700756C83 /* VLCNetworkServerLoginInformation.m in Sources */,
 				DD3EFF381BDEBCE500B68579 /* VLCLocalNetworkServiceNetService.m in Sources */,
+				DD8095D61BE3C3BA0065D8E1 /* VLCTransportBar.m in Sources */,
 				DDEAECF71BDFEB0200756C83 /* VLCLocalNetworkServerTVCell.m in Sources */,
 				DDDEA6AF1BE027FA000BB7A2 /* VLCServerBrowsingTVTableViewController.m in Sources */,
 				DD3EFF461BDEBCE500B68579 /* VLCLocalNetworkServiceBrowserManualConnect.m in Sources */,
@@ -2697,6 +2708,7 @@
 				7D1329441BA1F10100BE647E /* AppleTVAppDelegate.m in Sources */,
 				7D1329411BA1F10100BE647E /* main.m in Sources */,
 				7DC71D291BC83590001FACAA /* UIColor+Presets.m in Sources */,
+				DD8095DB1BE3C42F0065D8E1 /* VLCBufferingBar.m in Sources */,
 				7D4408591BDA8DCA0080FB42 /* VLCBoxController.m in Sources */,
 				DD3EAC0A1BE2192A003668DA /* VLCServerBrowsingController.m in Sources */,
 				DD3EFF341BDEBCE500B68579 /* VLCLocalNetworkServiceBrowserMediaDiscoverer.m in Sources */,