VLCMovieViewController.m 59.3 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * VLCMovieViewController.m
 * VLC for iOS
 *****************************************************************************
5
 * Copyright (c) 2013-2015 VideoLAN. All rights reserved.
6 7 8 9
 * $Id$
 *
 * Authors: Felix Paul Kühne <fkuehne # videolan.org>
 *          Gleb Pinigin <gpinigin # gmail.com>
10 11
 *          Carola Nitz <caro # videolan.org>
 *          Tobias Conradi <videolan # tobias-conradi.de>
12 13 14
 *          Ahmad Harb <harb.dev.leb # gmail.com>
 *          Fabio Ritrovato <sephiroth87 # videolan.org>
 *          Pierre SAGASPE <pierre.sagaspe # me.com>
15 16 17 18
 *          Filipe Cabecinhas <vlc # filcab dot net>
 *          Marc Etcheverry <marc # taplightsoftware dot com>
 *          Christopher Loessl <cloessl # x-berg dot de>
 *          Sylver Bruneau <sylver.bruneau # gmail dot com>
19 20 21
 *
 * Refer to the COPYING file of the official project for license.
 *****************************************************************************/
Felix Paul Kühne's avatar
Felix Paul Kühne committed
22

23
#import "VLCMovieViewController.h"
24
#import "VLCExternalDisplayController.h"
25 26
#import "VLCTrackSelectorTableViewCell.h"
#import "VLCTrackSelectorHeaderView.h"
27
#import "VLCEqualizerView.h"
28
#import "VLCMultiSelectionMenuView.h"
29 30
#import "VLCPlaybackController.h"
#import "UIDevice+VLC.h"
31
#import "VLCTimeNavigationTitleView.h"
32 33

#import "VLCStatusLabel.h"
Felix Paul Kühne's avatar
Felix Paul Kühne committed
34

35 36
#define FORWARD_SWIPE_DURATION 30
#define BACKWARD_SWIPE_DURATION 10
37

38 39 40
#define TRACK_SELECTOR_TABLEVIEW_CELL @"track selector table view cell"
#define TRACK_SELECTOR_TABLEVIEW_SECTIONHEADER @"track selector table view section header"

41 42 43 44
#define LOCKCHECK \
if (_interfaceIsLocked) \
return

45 46 47 48 49 50 51
typedef NS_ENUM(NSInteger, VLCPanType) {
  VLCPanTypeNone,
  VLCPanTypeBrightness,
  VLCPanTypeSeek,
  VLCPanTypeVolume,
};

52
@interface VLCMovieViewController () <UIGestureRecognizerDelegate, UITableViewDataSource, UITableViewDelegate, VLCMultiSelectionViewDelegate, VLCEqualizerViewUIDelegate>
53
{
54 55 56 57 58 59 60 61
    BOOL _controlsHidden;
    BOOL _videoFiltersHidden;
    BOOL _playbackSpeedViewHidden;

    UIActionSheet *_subtitleActionSheet;
    UIActionSheet *_audiotrackActionSheet;

    NSTimer *_idleTimer;
62
    NSTimer *_sleepTimer;
63

64
    BOOL _viewAppeared;
65
    BOOL _displayRemainingTime;
66
    BOOL _positionSet;
67
    BOOL _playerIsSetup;
68
    BOOL _isScrubbing;
69
    BOOL _interfaceIsLocked;
70
    BOOL _switchingTracksNotChapters;
71
    BOOL _audioOnly;
72 73

    BOOL _swipeGesturesEnabled;
74
    BOOL _variableJumpDurationEnabled;
75
    UIPinchGestureRecognizer *_pinchRecognizer;
76
    VLCPanType _currentPanType;
77 78 79
    UIPanGestureRecognizer *_panRecognizer;
    UISwipeGestureRecognizer *_swipeRecognizerLeft;
    UISwipeGestureRecognizer *_swipeRecognizerRight;
80 81
    UISwipeGestureRecognizer *_swipeRecognizerUp;
    UISwipeGestureRecognizer *_swipeRecognizerDown;
82
    UITapGestureRecognizer *_tapRecognizer;
83
    UITapGestureRecognizer *_tapOnVideoRecognizer;
84 85 86

    UIView *_trackSelectorContainer;
    UITableView *_trackSelectorTableView;
87 88

    VLCEqualizerView *_equalizerView;
89
    VLCMultiSelectionMenuView *_multiSelectionView;
90 91 92 93

    UIView *_sleepTimerContainer;
    UIDatePicker *_sleepTimeDatePicker;

94
    NSInteger _mediaDuration;
95 96
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
97 98
@property (nonatomic, strong) UIPopoverController *masterPopoverController;
@property (nonatomic, strong) UIWindow *externalWindow;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
99 100
@end

101
@implementation VLCMovieViewController
Felix Paul Kühne's avatar
Felix Paul Kühne committed
102

103 104 105 106 107 108 109
+ (void)initialize
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSDictionary *appDefaults = @{kVLCShowRemainingTime : @(YES)};
    [defaults registerDefaults:appDefaults];
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
110 111
- (void)dealloc
{
112 113
    [[NSNotificationCenter defaultCenter] removeObserver:self];

114
    if (_tapRecognizer)
115
        [self.view removeGestureRecognizer:_tapRecognizer];
116
    if (_swipeRecognizerLeft)
117
        [self.view removeGestureRecognizer:_swipeRecognizerLeft];
118
    if (_swipeRecognizerRight)
119
        [self.view removeGestureRecognizer:_swipeRecognizerRight];
120 121 122 123
    if (_swipeRecognizerUp)
        [self.view removeGestureRecognizer:_swipeRecognizerUp];
    if (_swipeRecognizerDown)
        [self.view removeGestureRecognizer:_swipeRecognizerDown];
124
    if (_panRecognizer)
125
        [self.view removeGestureRecognizer:_panRecognizer];
126 127 128 129
    if (_pinchRecognizer)
        [self.view removeGestureRecognizer:_pinchRecognizer];
    [self.view removeGestureRecognizer:_tapOnVideoRecognizer];

130 131 132
    _tapRecognizer = nil;
    _swipeRecognizerLeft = nil;
    _swipeRecognizerRight = nil;
133 134
    _swipeRecognizerUp = nil;
    _swipeRecognizerDown = nil;
135
    _panRecognizer = nil;
136 137
    _pinchRecognizer = nil;
    _tapOnVideoRecognizer = nil;
138 139
}

140
- (void)viewDidLoad
Felix Paul Kühne's avatar
Felix Paul Kühne committed
141
{
142
    [super viewDidLoad];
143 144
    CGRect rect;

145 146
    self.wantsFullScreenLayout = YES;

147 148
    self.videoFilterView.hidden = YES;
    _videoFiltersHidden = YES;
149
    _hueLabel.text = NSLocalizedString(@"VFILTER_HUE", nil);
150 151
    _hueSlider.accessibilityLabel = _hueLabel.text;
    _hueSlider.isAccessibilityElement = YES;
152
    _contrastLabel.text = NSLocalizedString(@"VFILTER_CONTRAST", nil);
153 154
    _contrastSlider.accessibilityLabel = _contrastLabel.text;
    _contrastSlider.isAccessibilityElement = YES;
155
    _brightnessLabel.text = NSLocalizedString(@"VFILTER_BRIGHTNESS", nil);
156 157
    _brightnessSlider.accessibilityLabel = _brightnessLabel.text;
    _brightnessSlider.isAccessibilityElement = YES;
158
    _saturationLabel.text = NSLocalizedString(@"VFILTER_SATURATION", nil);
159 160
    _saturationSlider.accessibilityLabel = _saturationLabel.text;
    _saturationSlider.isAccessibilityElement = YES;
161
    _gammaLabel.text = NSLocalizedString(@"VFILTER_GAMMA", nil);
162 163
    _gammaSlider.accessibilityLabel = _gammaLabel.text;
    _gammaSlider.isAccessibilityElement = YES;
164
    _playbackSpeedLabel.text = NSLocalizedString(@"PLAYBACK_SPEED", nil);
165 166
    _playbackSpeedSlider.accessibilityLabel = _playbackSpeedLabel.text;
    _playbackSpeedSlider.isAccessibilityElement = YES;
167 168 169 170 171 172
    _audioDelayLabel.text = NSLocalizedString(@"AUDIO_DELAY", nil);
    _audioDelaySlider.accessibilityLabel = _audioDelayLabel.text;
    _audioDelaySlider.isAccessibilityElement = YES;
    _spuDelayLabel.text = NSLocalizedString(@"SPU_DELAY", nil);
    _spuDelaySlider.accessibilityLabel = _spuDelayLabel.text;
    _spuDelaySlider.isAccessibilityElement = YES;
173

174 175 176 177
    _trackSwitcherButton.accessibilityLabel = NSLocalizedString(@"OPEN_TRACK_PANEL", nil);
    _trackSwitcherButton.isAccessibilityElement = YES;
    _trackSwitcherButtonLandscape.accessibilityLabel = NSLocalizedString(@"OPEN_TRACK_PANEL", nil);
    _trackSwitcherButtonLandscape.isAccessibilityElement = YES;
178 179
    _playbackSpeedButton.accessibilityLabel = _playbackSpeedLabel.text;
    _playbackSpeedButton.isAccessibilityElement = YES;
180 181
    _playbackSpeedButtonLandscape.accessibilityLabel = _playbackSpeedLabel.text;
    _playbackSpeedButtonLandscape.isAccessibilityElement = YES;
182
    _videoFilterButton.accessibilityLabel = NSLocalizedString(@"VIDEO_FILTER", nil);
183
    _videoFilterButton.isAccessibilityElement = YES;
184
    _videoFilterButtonLandscape.accessibilityLabel = NSLocalizedString(@"VIDEO_FILTER", nil);
185
    _videoFilterButtonLandscape.isAccessibilityElement = YES;
186
    _resetVideoFilterButton.accessibilityLabel = NSLocalizedString(@"VIDEO_FILTER_RESET_BUTTON", nil);
187
    _resetVideoFilterButton.isAccessibilityElement = YES;
188
    _playPauseButton.accessibilityLabel = NSLocalizedString(@"PLAY_PAUSE_BUTTON", nil);
189
    _playPauseButton.isAccessibilityElement = YES;
190
    _playPauseButtonLandscape.accessibilityLabel = NSLocalizedString(@"PLAY_PAUSE_BUTTON", nil);
191
    _playPauseButtonLandscape.isAccessibilityElement = YES;
192
    _bwdButton.accessibilityLabel = NSLocalizedString(@"BWD_BUTTON", nil);
193
    _bwdButton.isAccessibilityElement = YES;
194
    _bwdButtonLandscape.accessibilityLabel = NSLocalizedString(@"BWD_BUTTON", nil);
195
    _bwdButtonLandscape.isAccessibilityElement = YES;
196
    _fwdButton.accessibilityLabel = NSLocalizedString(@"FWD_BUTTON", nil);
197
    _fwdButton.isAccessibilityElement = YES;
198
    _fwdButtonLandscape.accessibilityLabel = NSLocalizedString(@"FWD_BUTTON", nil);
199
    _fwdButtonLandscape.isAccessibilityElement = YES;
200 201 202
    _sleepTimerButton.accessibilityLabel = NSLocalizedString(@"BUTTON_SLEEP_TIMER", nil);
    _sleepTimerButton.isAccessibilityElement = YES;
    [_sleepTimerButton setTitle:NSLocalizedString(@"BUTTON_SLEEP_TIMER", nil) forState:UIControlStateNormal];
203 204
    if (!SYSTEM_RUNS_IOS7_OR_LATER)
        _sleepTimerButton.hidden = YES;
205

206 207 208 209 210 211
    _multiSelectionView = [[VLCMultiSelectionMenuView alloc] init];
    _multiSelectionView.delegate = self;
    _multiSelectionView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin;
    _multiSelectionView.hidden = YES;
    [self.view addSubview:_multiSelectionView];

212
    _scrubHelpLabel.text = NSLocalizedString(@"PLAYBACK_SCRUB_HELP", nil);
213

214 215
    self.playbackSpeedView.hidden = YES;
    _playbackSpeedViewHidden = YES;
216

217 218 219 220 221 222
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center addObserver:self selector:@selector(handleExternalScreenDidConnect:)
                   name:UIScreenDidConnectNotification object:nil];
    [center addObserver:self selector:@selector(handleExternalScreenDidDisconnect:)
                   name:UIScreenDidDisconnectNotification object:nil];

223 224
    _playingExternallyTitle.text = NSLocalizedString(@"PLAYING_EXTERNALLY_TITLE", nil);
    _playingExternallyDescription.text = NSLocalizedString(@"PLAYING_EXTERNALLY_DESC", nil);
225
    if ([[UIDevice currentDevice] hasExternalDisplay])
226
        [self showOnExternalDisplay];
227

228 229
    self.trackNameLabel.text = self.artistNameLabel.text = self.albumNameLabel.text = @"";

230
    _movieView.userInteractionEnabled = NO;
231 232 233
    _tapOnVideoRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleControlsVisible)];
    _tapOnVideoRecognizer.delegate = self;
    [self.view addGestureRecognizer:_tapOnVideoRecognizer];
234

235 236 237
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    _displayRemainingTime = [[defaults objectForKey:kVLCShowRemainingTime] boolValue];
    _swipeGesturesEnabled = [[defaults objectForKey:kVLCSettingPlaybackGestures] boolValue];
238
    _variableJumpDurationEnabled = [[defaults objectForKey:kVLCSettingVariableJumpDuration] boolValue];
239

240 241 242 243 244 245
    _pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)];
    _pinchRecognizer.delegate = self;
    [self.view addGestureRecognizer:_pinchRecognizer];

    _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapRecognized)];
    [_tapRecognizer setNumberOfTouchesRequired:2];
246 247

    _currentPanType = VLCPanTypeNone;
248 249 250 251 252 253 254 255
    _panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panRecognized:)];
    [_panRecognizer setMinimumNumberOfTouches:1];
    [_panRecognizer setMaximumNumberOfTouches:1];

    _swipeRecognizerLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRecognized:)];
    _swipeRecognizerLeft.direction = UISwipeGestureRecognizerDirectionLeft;
    _swipeRecognizerRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRecognized:)];
    _swipeRecognizerRight.direction = UISwipeGestureRecognizerDirectionRight;
256 257 258 259 260 261
    _swipeRecognizerUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRecognized:)];
    _swipeRecognizerUp.direction = UISwipeGestureRecognizerDirectionUp;
    _swipeRecognizerUp.numberOfTouchesRequired = 2;
    _swipeRecognizerDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRecognized:)];
    _swipeRecognizerDown.direction = UISwipeGestureRecognizerDirectionDown;
    _swipeRecognizerDown.numberOfTouchesRequired = 2;
262 263 264

    [self.view addGestureRecognizer:_swipeRecognizerLeft];
    [self.view addGestureRecognizer:_swipeRecognizerRight];
265 266
    [self.view addGestureRecognizer:_swipeRecognizerUp];
    [self.view addGestureRecognizer:_swipeRecognizerDown];
267 268 269 270
    [self.view addGestureRecognizer:_panRecognizer];
    [self.view addGestureRecognizer:_tapRecognizer];
    [_panRecognizer requireGestureRecognizerToFail:_swipeRecognizerLeft];
    [_panRecognizer requireGestureRecognizerToFail:_swipeRecognizerRight];
271 272
    [_panRecognizer requireGestureRecognizerToFail:_swipeRecognizerUp];
    [_panRecognizer requireGestureRecognizerToFail:_swipeRecognizerDown];
273 274 275 276

    _panRecognizer.delegate = self;
    _swipeRecognizerRight.delegate = self;
    _swipeRecognizerLeft.delegate = self;
277 278
    _swipeRecognizerUp.delegate = self;
    _swipeRecognizerDown.delegate = self;
279
    _tapRecognizer.delegate = self;
280

Felix Paul Kühne's avatar
Felix Paul Kühne committed
281
    if (SYSTEM_RUNS_IOS7_OR_LATER) {
282
        self.backButton.tintColor = [UIColor colorWithRed:(190.0f/255.0f) green:(190.0f/255.0f) blue:(190.0f/255.0f) alpha:1.];
283
        self.toolbar.tintColor = [UIColor whiteColor];
284
        self.toolbar.barStyle = UIBarStyleBlack;
285

286
        rect = self.resetVideoFilterButton.frame;
287 288
        rect.origin.y = rect.origin.y + 5.;
        self.resetVideoFilterButton.frame = rect;
289 290 291 292
        rect = self.toolbar.frame;
        rect.size.height = rect.size.height + rect.origin.y;
        rect.origin.y = 0;
        self.toolbar.frame = rect;
293 294
    } else {
        [self.toolbar setBackgroundImage:[UIImage imageNamed:@"seekbarBg"] forBarMetrics:UIBarMetricsDefault];
295 296 297
        [self.backButton setBackgroundImage:[UIImage imageNamed:@"playbackDoneButton"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
        [self.backButton setBackgroundImage:[UIImage imageNamed:@"playbackDoneButtonHighlight"] forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
    }
298

299
    /* FIXME: there is a saner iOS 6+ API for this! */
300
    /* this looks a bit weird, but we need to support iOS 5 and should show the same appearance */
301 302 303 304 305 306 307
    void (^initVolumeSlider)(MPVolumeView *) = ^(MPVolumeView *volumeView){
        UISlider *volumeSlider = nil;
        for (id aView in volumeView.subviews){
            if ([[[aView class] description] isEqualToString:@"MPVolumeSlider"]){
                volumeSlider = (UISlider *)aView;
                break;
            }
308
        }
309 310 311 312 313 314 315 316 317 318 319 320 321
        if (!SYSTEM_RUNS_IOS7_OR_LATER) {
            [volumeSlider setMinimumTrackImage:[[UIImage imageNamed:@"sliderminiValue"]resizableImageWithCapInsets:UIEdgeInsetsMake(0, 4, 0, 0)] forState:UIControlStateNormal];
            [volumeSlider setMaximumTrackImage:[[UIImage imageNamed:@"slidermaxValue"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 4)] forState:UIControlStateNormal];
            [volumeSlider setThumbImage:[UIImage imageNamed:@"volumeballslider"] forState:UIControlStateNormal];
        } else
            [volumeView setVolumeThumbImage:[UIImage imageNamed:@"modernSliderKnob"] forState:UIControlStateNormal];
        [volumeSlider addTarget:self
                         action:@selector(volumeSliderAction:)
               forControlEvents:UIControlEventValueChanged];
    };

    initVolumeSlider(self.volumeView);
    initVolumeSlider(self.volumeViewLandscape);
322

323
    _playerIsSetup = NO;
324

325 326
    [self.movieView setAccessibilityLabel:NSLocalizedString(@"VO_VIDEOPLAYER_TITLE", nil)];
    [self.movieView setAccessibilityHint:NSLocalizedString(@"VO_VIDEOPLAYER_DOUBLETAP", nil)];
327 328

    rect = self.view.frame;
329 330 331 332 333 334 335 336 337
    CGFloat width;
    CGFloat height;
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        width = 300.;
        height = 320.;
    } else {
        width = 450.;
        height = 470.;
    }
338

339
    _trackSelectorTableView = [[UITableView alloc] initWithFrame:CGRectMake(0., 0., width, height) style:UITableViewStylePlain];
340 341
    _trackSelectorTableView.delegate = self;
    _trackSelectorTableView.dataSource = self;
342
    _trackSelectorTableView.separatorColor = [UIColor clearColor];
343 344 345
    _trackSelectorTableView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
    [_trackSelectorTableView registerClass:[VLCTrackSelectorTableViewCell class] forCellReuseIdentifier:TRACK_SELECTOR_TABLEVIEW_CELL];
    [_trackSelectorTableView registerClass:[VLCTrackSelectorHeaderView class] forHeaderFooterViewReuseIdentifier:TRACK_SELECTOR_TABLEVIEW_SECTIONHEADER];
346
    _trackSelectorTableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
347

348
    _trackSelectorContainer = [[VLCFrostedGlasView alloc] initWithFrame:CGRectMake((rect.size.width - width) / 2., (rect.size.height - height) / 2., width, height)];
349
    [_trackSelectorContainer addSubview:_trackSelectorTableView];
350
    _trackSelectorContainer.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleHeight;
351 352 353 354 355 356
    _trackSelectorContainer.hidden = YES;

    if ([[UIDevice currentDevice] speedCategory] >= 3) {
        _trackSelectorTableView.opaque = NO;
        _trackSelectorTableView.backgroundColor = [UIColor clearColor];
    } else
357
        _trackSelectorTableView.backgroundColor = [UIColor blackColor];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
358
    _trackSelectorTableView.allowsMultipleSelection = YES;
359 360

    [self.view addSubview:_trackSelectorContainer];
361

362 363 364 365 366
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        _equalizerView = [[VLCEqualizerView alloc] initWithFrame:CGRectMake((rect.size.width - 450.) / 2., self.controllerPanel.frame.origin.y - 200., 450., 240.)];
    } else {
        _equalizerView = [[VLCEqualizerView alloc] initWithFrame:CGRectMake((rect.size.width - 450.) / 2., self.controllerPanel.frame.origin.y - 240., 450., 240.)];
    }
367
    _equalizerView.delegate = self.playbackController;
368
    _equalizerView.UIdelegate = self;
369 370 371
    _equalizerView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
    _equalizerView.hidden = YES;
    [self.view addSubview:_equalizerView];
372

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
    /* add sleep timer UI, requires iOS 7 or later */
    if (SYSTEM_RUNS_IOS7_OR_LATER) {
        _sleepTimerContainer = [[VLCFrostedGlasView alloc] initWithFrame:CGRectMake(0., 0., 300., 162.)];
        _sleepTimerContainer.center = self.view.center;
        _sleepTimerContainer.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;

        _sleepTimeDatePicker = [[UIDatePicker alloc] init];
        if ([[UIDevice currentDevice] speedCategory] >= 3) {
            _sleepTimeDatePicker.opaque = NO;
            _sleepTimeDatePicker.backgroundColor = [UIColor clearColor];
        } else
            _sleepTimeDatePicker.backgroundColor = [UIColor blackColor];
        _sleepTimeDatePicker.tintColor = [UIColor VLCLightTextColor];
        _sleepTimeDatePicker.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;
        [_sleepTimerContainer addSubview:_sleepTimeDatePicker];

        /* adapt the date picker style to suit our needs */
        [_sleepTimeDatePicker setValue:[UIColor whiteColor] forKeyPath:@"textColor"];
        SEL selector = NSSelectorFromString(@"setHighlightsToday:");
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDatePicker instanceMethodSignatureForSelector:selector]];
        BOOL no = NO;
        [invocation setSelector:selector];
        [invocation setArgument:&no atIndex:2];
        [invocation invokeWithTarget:_sleepTimeDatePicker];

        if (_sleepTimerContainer.subviews.count > 0) {
            NSArray *subviewsOfSubview = [_sleepTimeDatePicker.subviews[0] subviews];
            NSUInteger subviewCount = subviewsOfSubview.count;
            for (NSUInteger x = 0; x < subviewCount; x++) {
                if ([subviewsOfSubview[x] isKindOfClass:[UILabel class]])
                    [subviewsOfSubview[x] setTextColor:[UIColor VLCLightTextColor]];
            }
405
        }
406 407 408 409 410
        _sleepTimeDatePicker.datePickerMode = UIDatePickerModeCountDownTimer;
        _sleepTimeDatePicker.minuteInterval = 5;
        _sleepTimeDatePicker.minimumDate = [NSDate date];
        _sleepTimeDatePicker.countDownDuration = 1200.;
        [_sleepTimeDatePicker addTarget:self action:@selector(sleepTimerAction:) forControlEvents:UIControlEventValueChanged];
411

412 413
        [self.view addSubview:_sleepTimerContainer];
    }
414
}
Felix Paul Kühne's avatar
Felix Paul Kühne committed
415

416 417
- (void)viewWillAppear:(BOOL)animated
{
418
    [super viewWillAppear:animated];
419

420 421 422 423 424 425
    /* reset audio meta data views */
    self.artworkImageView.image = nil;
    self.trackNameLabel.text = nil;
    self.artistNameLabel.text = nil;
    self.albumNameLabel.text = nil;

426
    _swipeGesturesEnabled = [[[NSUserDefaults standardUserDefaults] objectForKey:kVLCSettingPlaybackGestures] boolValue];
427
    _variableJumpDurationEnabled = [[[NSUserDefaults standardUserDefaults] objectForKey:kVLCSettingVariableJumpDuration] boolValue];
428

429
    [self.navigationController setNavigationBarHidden:YES animated:YES];
430

Felix Paul Kühne's avatar
Felix Paul Kühne committed
431
    if (!SYSTEM_RUNS_IOS7_OR_LATER) {
432 433 434
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
            [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleBlackTranslucent;
    }
435

436
    VLCPlaybackController *vpc = self.playbackController;
437
    vpc.delegate = self;
438
    vpc.presentingMovieViewController = YES;
439
    [vpc recoverPlaybackState];
440 441

    [self setControlsHidden:NO animated:YES];
442 443 444 445 446
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
447
    _viewAppeared = YES;
448

449
    VLCPlaybackController *vpc = self.playbackController;
450
    [vpc recoverDisplayedMetadata];
451 452
    vpc.videoOutputView = nil;
    vpc.videoOutputView = self.movieView;
453 454
}

455 456
- (void)viewWillLayoutSubviews
{
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
    CGRect multiSelectionFrame;
    CGRect controllerPanelFrame;

    if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPhone) {
        controllerPanelFrame = _controllerPanel.frame;
        multiSelectionFrame = (CGRect){CGPointMake(0., 0.), [_multiSelectionView proposedDisplaySize]};
        multiSelectionFrame.origin.x = controllerPanelFrame.size.width - multiSelectionFrame.size.width;
        multiSelectionFrame.origin.y = controllerPanelFrame.origin.y - multiSelectionFrame.size.height;
        _multiSelectionView.frame = multiSelectionFrame;
        _multiSelectionView.showsEqualizer = YES;
        return;
    }

    CGSize viewSize = self.view.frame.size;

    if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
        [_controllerPanel removeFromSuperview];
        controllerPanelFrame = (CGRect){CGPointMake(0, viewSize.height - _controllerPanelLandscape.frame.size.height), CGSizeMake(viewSize.width, _controllerPanelLandscape.frame.size.height)};
        _controllerPanelLandscape.frame = controllerPanelFrame;
        [self.view addSubview:_controllerPanelLandscape];
        _multiSelectionView.showsEqualizer = YES;
        multiSelectionFrame = (CGRect){CGPointMake(0., 0.), [_multiSelectionView proposedDisplaySize]};
        multiSelectionFrame.origin.x = controllerPanelFrame.size.width - multiSelectionFrame.size.width;
        multiSelectionFrame.origin.y = controllerPanelFrame.origin.y - multiSelectionFrame.size.height;
    } else {
        [_controllerPanelLandscape removeFromSuperview];
        controllerPanelFrame = (CGRect){CGPointMake(0, viewSize.height - _controllerPanel.frame.size.height), CGSizeMake(viewSize.width, _controllerPanel.frame.size.height)};
        _controllerPanel.frame = controllerPanelFrame;
        [self.view addSubview:_controllerPanel];
        _multiSelectionView.showsEqualizer = NO;
        multiSelectionFrame = (CGRect){CGPointMake(0., 0.), [_multiSelectionView proposedDisplaySize]};
        multiSelectionFrame.origin.x = controllerPanelFrame.size.width - multiSelectionFrame.size.width;
        multiSelectionFrame.origin.y = controllerPanelFrame.origin.y - multiSelectionFrame.size.height;
490
    }
491 492

    _multiSelectionView.frame = multiSelectionFrame;
493 494
}

495
- (void)viewWillDisappear:(BOOL)animated
Felix Paul Kühne's avatar
Felix Paul Kühne committed
496
{
497
    VLCPlaybackController *vpc = self.playbackController;
498 499
    vpc.videoOutputView = nil;
    vpc.presentingMovieViewController = NO;
500

501
    _viewAppeared = NO;
502
    if (_idleTimer) {
503
        [_idleTimer invalidate];
504 505
        _idleTimer = nil;
    }
506
    [self.navigationController setNavigationBarHidden:NO animated:YES];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
507
    if (!SYSTEM_RUNS_IOS7_OR_LATER)
508
        [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleBlackOpaque;
509
    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
510
    [super viewWillDisappear:animated];
511

512 513 514 515 516 517
    // hide filter UI for next run
    if (!_videoFiltersHidden)
        _videoFiltersHidden = YES;

    if (!_playbackSpeedViewHidden)
        _playbackSpeedViewHidden = YES;
518 519

    [[NSUserDefaults standardUserDefaults] setBool:_displayRemainingTime forKey:kVLCShowRemainingTime];
520 521 522 523 524 525 526
}

- (BOOL)canBecomeFirstResponder
{
    return YES;
}

527 528
#pragma mark - controls visibility

529 530
- (void)handlePinchGesture:(UIPinchGestureRecognizer *)recognizer
{
531 532
    LOCKCHECK;

533 534 535
    if (!_swipeGesturesEnabled)
        return;

536 537 538 539
    if (recognizer.velocity < 0.)
        [self closePlayback:nil];
}

540 541
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
Felix Paul Kühne's avatar
Felix Paul Kühne committed
542
    if (touch.view != self.view)
543 544 545 546 547
        return NO;

    return YES;
}

548 549 550 551 552
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

553
- (void)setControlsHidden:(BOOL)hidden animated:(BOOL)animated
554
{
555
    _controlsHidden = hidden;
556
    CGFloat alpha = _controlsHidden? 0.0f: 1.0f;
557

558 559
    if (!_controlsHidden) {
        _controllerPanel.alpha = 0.0f;
560
        _controllerPanel.hidden = !_videoFiltersHidden;
561 562
        _controllerPanelLandscape.alpha = 0.0f;
        _controllerPanelLandscape.hidden = !_videoFiltersHidden;
563 564
        _toolbar.alpha = 0.0f;
        _toolbar.hidden = NO;
565 566
        _videoFilterView.alpha = 0.0f;
        _videoFilterView.hidden = _videoFiltersHidden;
567 568
        _playbackSpeedView.alpha = 0.0f;
        _playbackSpeedView.hidden = _playbackSpeedViewHidden;
569 570
        _trackSelectorContainer.alpha = 0.0f;
        _trackSelectorContainer.hidden = YES;
571 572
        _equalizerView.alpha = 0.0f;
        _equalizerView.hidden = YES;
573 574 575 576
        if (_sleepTimerContainer) {
            _sleepTimerContainer.alpha = 0.0f;
            _sleepTimerContainer.hidden = YES;
        }
577 578
        _multiSelectionView.alpha = 0.0f;
        _multiSelectionView.hidden = YES;
579 580 581 582

        _artistNameLabel.hidden = NO;
        _albumNameLabel.hidden = NO;
        _trackNameLabel.hidden = NO;
583
    }
584

585 586
    void (^animationBlock)() = ^() {
        _controllerPanel.alpha = alpha;
587
        _controllerPanelLandscape.alpha = alpha;
588
        _toolbar.alpha = alpha;
589
        _videoFilterView.alpha = alpha;
590
        _playbackSpeedView.alpha = alpha;
591
        _trackSelectorContainer.alpha = alpha;
592
        _equalizerView.alpha = alpha;
593
        _multiSelectionView.alpha = alpha;
594 595
        if (_sleepTimerContainer)
            _sleepTimerContainer.alpha = alpha;
596 597 598 599 600

        CGFloat metaInfoAlpha = _audioOnly ? 1.0f : alpha;
        _artistNameLabel.alpha = metaInfoAlpha;
        _albumNameLabel.alpha = metaInfoAlpha;
        _trackNameLabel.alpha = metaInfoAlpha;
601
    };
602

603
    void (^completionBlock)(BOOL finished) = ^(BOOL finished) {
604 605
        _controllerPanel.hidden = _videoFiltersHidden ? _controlsHidden : NO;
        _controllerPanelLandscape.hidden = _videoFiltersHidden ? _controlsHidden : NO;
606
        _toolbar.hidden = _controlsHidden;
607
        _videoFilterView.hidden = _videoFiltersHidden;
608
        _playbackSpeedView.hidden = _playbackSpeedViewHidden;
609
        _trackSelectorContainer.hidden = YES;
610
        _equalizerView.hidden = YES;
611 612
        if (_sleepTimerContainer)
            _sleepTimerContainer.hidden = YES;
613
        _multiSelectionView.hidden = YES;
614 615 616 617

        _artistNameLabel.hidden = _audioOnly ? NO : _controlsHidden;
        _albumNameLabel.hidden =  _audioOnly ? NO : _controlsHidden;
        _trackNameLabel.hidden =  _audioOnly ? NO : _controlsHidden;
618
    };
619

620 621
    UIStatusBarAnimation animationType = animated? UIStatusBarAnimationFade: UIStatusBarAnimationNone;
    NSTimeInterval animationDuration = animated? 0.3: 0.0;
622 623

    [[UIApplication sharedApplication] setStatusBarHidden:_viewAppeared ? _controlsHidden : NO withAnimation:animationType];
624
    [UIView animateWithDuration:animationDuration animations:animationBlock completion:completionBlock];
625

626
    _volumeView.hidden = _volumeViewLandscape.hidden = _controllerPanel.hidden;
627
}
628

629
- (void)toggleControlsVisible
630
{
631 632 633 634 635
    if (!_trackSelectorContainer.hidden) {
        for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers)
            [recognizer setEnabled:YES];
    }

636 637 638
    if (_controlsHidden && !_videoFiltersHidden)
        _videoFiltersHidden = YES;

639
    [self setControlsHidden:!_controlsHidden animated:YES];
640 641
}

642
- (void)_resetIdleTimer
643 644
{
    if (!_idleTimer)
645
        _idleTimer = [NSTimer scheduledTimerWithTimeInterval:4.
646 647 648 649 650
                                                      target:self
                                                    selector:@selector(idleTimerExceeded)
                                                    userInfo:nil
                                                     repeats:NO];
    else {
651 652
        if (fabs([_idleTimer.fireDate timeIntervalSinceNow]) < 4.)
            [_idleTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:4.]];
653 654 655 656 657 658 659
    }
}

- (void)idleTimerExceeded
{
    _idleTimer = nil;
    if (!_controlsHidden)
660
        [self toggleControlsVisible];
661

662 663 664 665 666 667
    if (!_videoFiltersHidden)
        _videoFiltersHidden = YES;

    if (!_playbackSpeedViewHidden)
        _playbackSpeedViewHidden = YES;

668 669
    if (self.scrubIndicatorView.hidden == NO)
        self.scrubIndicatorView.hidden = YES;
670 671
}

672 673
- (UIResponder *)nextResponder
{
674
    [self _resetIdleTimer];
675 676 677
    return [super nextResponder];
}

678 679 680 681
#pragma mark - controls

- (IBAction)closePlayback:(id)sender
{
682 683
    LOCKCHECK;

684
    [self presentingViewControllerShouldBeClosed:nil];
685 686
}

687 688
- (IBAction)positionSliderAction:(UISlider *)sender
{
689 690
    LOCKCHECK;

691 692 693
    /* we need to limit the number of events sent by the slider, since otherwise, the user
     * wouldn't see the I-frames when seeking on current mobile devices. This isn't a problem
     * within the Simulator, but especially on older ARMv7 devices, it's clearly noticeable. */
694
    [self performSelector:@selector(_setPositionForReal) withObject:nil afterDelay:0.3];
695
    if (_mediaDuration > 0) {
696 697
        VLCTime *newPosition = [VLCTime timeWithInt:(int)(sender.value * _mediaDuration)];
        [self.timeNavigationTitleView.timeDisplayButton setTitle:newPosition.stringValue forState:UIControlStateNormal];
698
        [self.timeNavigationTitleView setNeedsLayout];
699
        self.timeNavigationTitleView.timeDisplayButton.accessibilityLabel = [NSString stringWithFormat:@"%@: %@", NSLocalizedString(@"PLAYBACK_POSITION", nil), newPosition.stringValue];
700 701
        _positionSet = NO;
    }
702
    [self _resetIdleTimer];
703 704
}

705 706 707
- (void)_setPositionForReal
{
    if (!_positionSet) {
708 709
        self.playbackController.mediaPlayer.position = self.timeNavigationTitleView.positionSlider.value;
        [self.playbackController setNeedsMetadataUpdate];
710 711 712 713
        _positionSet = YES;
    }
}

714 715
- (IBAction)positionSliderTouchDown:(id)sender
{
716 717
    LOCKCHECK;

718 719
    [self _updateScrubLabel];
    self.scrubIndicatorView.hidden = NO;
720
    _isScrubbing = YES;
721 722 723 724
}

- (IBAction)positionSliderTouchUp:(id)sender
{
725 726
    LOCKCHECK;

727
    self.scrubIndicatorView.hidden = YES;
728
    _isScrubbing = NO;
729 730 731 732
}

- (void)_updateScrubLabel
{
733
    float speed = self.timeNavigationTitleView.positionSlider.scrubbingSpeed;
734
    if (speed == 1.)
735
        self.currentScrubSpeedLabel.text = NSLocalizedString(@"PLAYBACK_SCRUB_HIGH", nil);
736
    else if (speed == .5)
737
        self.currentScrubSpeedLabel.text = NSLocalizedString(@"PLAYBACK_SCRUB_HALF", nil);
738
    else if (speed == .25)
739
        self.currentScrubSpeedLabel.text = NSLocalizedString(@"PLAYBACK_SCRUB_QUARTER", nil);
740
    else
741
        self.currentScrubSpeedLabel.text = NSLocalizedString(@"PLAYBACK_SCRUB_FINE", nil);
742 743

    [self _resetIdleTimer];
744 745 746 747
}

- (IBAction)positionSliderDrag:(id)sender
{
748 749
    LOCKCHECK;

750 751 752
    [self _updateScrubLabel];
}

753 754
- (IBAction)volumeSliderAction:(id)sender
{
755 756
    LOCKCHECK;

757 758 759
    [self _resetIdleTimer];
}

760 761
#pragma mark - playback controller delegation

762 763 764 765 766 767 768 769
- (VLCPlaybackController *)playbackController
{
    if (!_playbackController) {
        _playbackController = [VLCPlaybackController sharedInstance];
    }
    return _playbackController;
}

770
- (void)playbackPositionUpdated:(VLCPlaybackController *)controller
771
{
772
    VLCMediaPlayer *mediaPlayer = controller.mediaPlayer;
773
    if (!_isScrubbing) {
774
        self.timeNavigationTitleView.positionSlider.value = [mediaPlayer position];
775 776
    }

777
    if (_displayRemainingTime)
778
        [self.timeNavigationTitleView.timeDisplayButton setTitle:[[mediaPlayer remainingTime] stringValue] forState:UIControlStateNormal];
779
    else
780
        [self.timeNavigationTitleView.timeDisplayButton setTitle:[[mediaPlayer time] stringValue] forState:UIControlStateNormal];
781
    [self.timeNavigationTitleView setNeedsLayout];
782 783
}

784
- (void)prepareForMediaPlayback:(VLCPlaybackController *)controller
785
{
786
    self.trackNameLabel.text = self.artistNameLabel.text = self.albumNameLabel.text = @"";
787 788 789
    self.timeNavigationTitleView.positionSlider.value = 0.;
    [self.timeNavigationTitleView.timeDisplayButton setTitle:@"" forState:UIControlStateNormal];
    self.timeNavigationTitleView.timeDisplayButton.accessibilityLabel = @"";
790 791 792 793 794
    if (![[UIDevice currentDevice] hasExternalDisplay])
        self.brightnessSlider.value = [UIScreen mainScreen].brightness * 2.;
    [_equalizerView reloadData];

    float playbackRate = controller.playbackRate;
795 796
    self.playbackSpeedSlider.value = log2(playbackRate);
    self.playbackSpeedIndicator.text = [NSString stringWithFormat:@"%.2fx", playbackRate];
797

798 799 800
    float audioDelay = controller.audioDelay;
    self.audioDelaySlider.value = audioDelay;
    self.audioDelayIndicator.text = [NSString stringWithFormat:@"%1.00f s", audioDelay];
801

802 803 804
    float subtitleDelay = controller.subtitleDelay;
    self.spuDelaySlider.value = subtitleDelay;
    self.spuDelayIndicator.text = [NSString stringWithFormat:@"%1.00f s", subtitleDelay];
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829

    [self _resetIdleTimer];
}

- (void)presentingViewControllerShouldBeClosed:(VLCPlaybackController *)controller
{
    [self setControlsHidden:NO animated:NO];
    [self.navigationController dismissViewControllerAnimated:YES completion:nil];
}

- (void)presentingViewControllerShouldBeClosedAfterADelay:(VLCPlaybackController *)controller
{
    [self performSelector:@selector(presentingViewControllerShouldBeClosed:) withObject:nil afterDelay:2.];
}

- (void)mediaPlayerStateChanged:(VLCMediaPlayerState)currentState
                      isPlaying:(BOOL)isPlaying
currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
        currentMediaHasChapters:(BOOL)currentMediaHasChapters
          forPlaybackController:(VLCPlaybackController *)controller
{
    if (currentState == VLCMediaPlayerStateBuffering)
        _mediaDuration = controller.mediaDuration;

    if (currentState == VLCMediaPlayerStateError)
830
        [self.statusLabel showStatusMessage:NSLocalizedString(@"PLAYBACK_FAILED", nil)];
831

832
    UIImage *playPauseImage = isPlaying ? [UIImage imageNamed:@"pauseIcon"] : [UIImage imageNamed:@"playIcon"];
Gleb Pinigin's avatar
Gleb Pinigin committed
833
    [_playPauseButton setImage:playPauseImage forState:UIControlStateNormal];
834
    [_playPauseButtonLandscape setImage:playPauseImage forState:UIControlStateNormal];
835

836
    if (currentMediaHasTrackToChooseFrom) {
837 838
        self.trackSwitcherButton.hidden = NO;
        self.trackSwitcherButtonLandscape.hidden = NO;
839
    } else {
840 841
        self.trackSwitcherButton.hidden = YES;
        self.trackSwitcherButtonLandscape.hidden = YES;
842
    }
843

844
    if (currentMediaHasChapters)
845 846 847
        _multiSelectionView.mediaHasChapters = YES;
    else
        _multiSelectionView.mediaHasChapters = NO;
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
}

- (void)showStatusMessage:(NSString *)statusMessage forPlaybackController:(VLCPlaybackController *)controller
{
    [self.statusLabel showStatusMessage:statusMessage];
}

- (void)displayMetadataForPlaybackController:(VLCPlaybackController *)controller
                                       title:(NSString *)title
                                     artwork:(UIImage *)artwork
                                      artist:(NSString *)artist
                                       album:(NSString *)album
                                   audioOnly:(BOOL)audioOnly
{
    if (!_viewAppeared)
        return;

    self.trackNameLabel.text = title;
    self.artworkImageView.image = artwork;
    if (!artwork) {
        self.artistNameLabel.text = artist;
        self.albumNameLabel.text = album;
    } else
        self.artistNameLabel.text = self.albumNameLabel.text = nil;
872

873 874 875
    self.timeNavigationTitleView.hideAspectRatio = audioOnly;
    self.timeNavigationTitleView.positionSlider.hidden = NO;

876
    self.videoFilterButton.hidden = audioOnly;
877 878

    _audioOnly = audioOnly;
879 880
}

881
- (IBAction)playPause
882
{
883 884
    LOCKCHECK;

885
    [self.playbackController playPause];
886 887 888 889
}

- (IBAction)forward:(id)sender
{
890 891
    LOCKCHECK;

892
    [self.playbackController forward];
893 894 895 896
}

- (IBAction)backward:(id)sender
{
897 898
    LOCKCHECK;

899
    [self.playbackController backward];
900 901
}

902
- (IBAction)switchTrack:(id)sender
903
{
904 905
    LOCKCHECK;

906 907 908 909 910 911 912 913 914 915 916 917 918 919
    if (_trackSelectorContainer.hidden == YES || _switchingTracksNotChapters == NO) {
        _switchingTracksNotChapters = YES;

        [_trackSelectorTableView reloadData];
        _trackSelectorContainer.hidden = NO;
        _trackSelectorContainer.alpha = 1.;

        if (!_playbackSpeedViewHidden)
            self.playbackSpeedView.hidden = _playbackSpeedViewHidden = YES;

        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
            if (!_controlsHidden) {
                self.controllerPanel.hidden = _controlsHidden = YES;
                self.controllerPanelLandscape.hidden = YES;
920
                self.toolbar.hidden = YES;
921 922 923 924
            }
        }

        self.videoFilterView.hidden = _videoFiltersHidden = YES;
925 926 927 928 929

        for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers)
            [recognizer setEnabled:NO];
        [_tapOnVideoRecognizer setEnabled:YES];

930 931 932 933 934 935
    } else {
        _trackSelectorContainer.hidden = YES;
        _switchingTracksNotChapters = NO;
    }
}

936 937
- (IBAction)toggleTimeDisplay:(id)sender
{
938 939
    LOCKCHECK;

940
    _displayRemainingTime = !_displayRemainingTime;
941

942 943
    [self _resetIdleTimer];
}
944

945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
- (IBAction)sleepTimer:(id)sender
{
    if (!_playbackSpeedViewHidden)
        self.playbackSpeedView.hidden = _playbackSpeedViewHidden = YES;

    if (_equalizerView.hidden == NO)
        _equalizerView.hidden = YES;

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        if (!_controlsHidden) {
            self.controllerPanel.hidden = _controlsHidden = YES;
            self.controllerPanelLandscape.hidden = YES;
        }
    }

    self.videoFilterView.hidden = _videoFiltersHidden = YES;
    _sleepTimerContainer.alpha = 1.;
    _sleepTimerContainer.hidden = NO;
}

- (IBAction)sleepTimerAction:(id)sender
{
    if (_sleepTimer) {
        [_sleepTimer invalidate];
        _sleepTimer = nil;
    }
    _sleepTimer = [NSTimer scheduledTimerWithTimeInterval:_sleepTimeDatePicker.countDownDuration target:self selector:@selector(closePlayback:) userInfo:nil repeats:NO];
}

974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
- (void)moreActions:(id)sender
{
    if (_multiSelectionView.hidden == NO) {
        [UIView animateWithDuration:.3
                         animations:^{
                             _multiSelectionView.hidden = YES;
                         }
                         completion:^(BOOL finished){
                         }];
        return;
    }

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
            _multiSelectionView.showsEqualizer = YES;
        else
            _multiSelectionView.showsEqualizer = NO;
    }

    CGRect workFrame = _multiSelectionView.frame;
    workFrame.size = [_multiSelectionView proposedDisplaySize];
    workFrame.origin.x = self.toolbar.frame.size.width - workFrame.size.width;

    _multiSelectionView.alpha = 1.0f;

    /* animate */
    _multiSelectionView.frame = CGRectMake(workFrame.origin.x, workFrame.origin.y + workFrame.size.height, workFrame.size.width, 0.);
    [UIView animateWithDuration:.3
                     animations:^{
                         _multiSelectionView.frame = workFrame;
                         _multiSelectionView.hidden = NO;
                     }
                     completion:^(BOOL finished){
                     }];
    [self _resetIdleTimer];
}

#pragma mark - multi-select delegation

- (void)toggleUILock
{
    _interfaceIsLocked = !_interfaceIsLocked;
1016 1017 1018 1019
    if (_interfaceIsLocked)
        _multiSelectionView.displayLock = YES;
    else
        _multiSelectionView.displayLock = NO;
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
}

- (void)toggleEqualizer
{
    LOCKCHECK;

    if (_equalizerView.hidden) {
        if (!_playbackSpeedViewHidden)
            self.playbackSpeedView.hidden = _playbackSpeedViewHidden = YES;

        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
            if (!_controlsHidden) {
                self.controllerPanel.hidden = _controlsHidden = YES;
                self.controllerPanelLandscape.hidden = YES;
                self.toolbar.hidden = YES;
            }
        }

        self.videoFilterView.hidden = _videoFiltersHidden = YES;
        _equalizerView.alpha = 1.;
        _equalizerView.hidden = NO;
    } else
        _equalizerView.hidden = YES;
}

- (void)toggleChapterAndTitleSelector
{
    LOCKCHECK;

    if (_trackSelectorContainer.hidden == YES || _switchingTracksNotChapters == YES) {
        _switchingTracksNotChapters = NO;

        [_trackSelectorTableView reloadData];
        _trackSelectorContainer.hidden = NO;
        _trackSelectorContainer.alpha = 1.;

        if (!_playbackSpeedViewHidden)
            self.playbackSpeedView.hidden = _playbackSpeedViewHidden = YES;

        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
            if (!_controlsHidden) {
                self.controllerPanel.hidden = _controlsHidden = YES;
                self.controllerPanelLandscape.hidden = YES;
            }
        }

        self.videoFilterView.hidden = _videoFiltersHidden = YES;
    } else {
        _trackSelectorContainer.hidden = YES;
    }
}

- (void)toggleRepeatMode
{
    LOCKCHECK;

1076
    VLCMediaListPlayer *listPlayer = self.playbackController.listPlayer;
1077 1078 1079

    if (listPlayer.repeatMode == VLCDoNotRepeat) {
        listPlayer.repeatMode = VLCRepeatCurrentItem;
1080 1081
        _multiSelectionView.displayRepeatOne = YES;
    } else {
1082
        listPlayer.repeatMode = VLCDoNotRepeat;
1083 1084 1085 1086
        _multiSelectionView.displayRepeatOne = NO;
    }
}

1087 1088 1089 1090 1091 1092 1093
- (void)toggleShuffleMode
{
    LOCKCHECK;

    // FIXME: missing implementation
}

1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
- (void)hideMenu
{
    [UIView animateWithDuration:.2
                     animations:^{
                         _multiSelectionView.hidden = YES;
                     }
                     completion:^(BOOL finished){
                     }];
    [self _resetIdleTimer];
}

1105 1106 1107 1108
#pragma mark - track selector table view
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    NSInteger ret = 0;
1109
    VLCMediaPlayer *mediaPlayer = self.playbackController.mediaPlayer;
1110

1111
    if (_switchingTracksNotChapters == YES) {
1112
        if (mediaPlayer.audioTrackIndexes.count > 2)
1113 1114
            ret++;

1115
        if (mediaPlayer.videoSubTitlesIndexes.count > 1)
1116 1117
            ret++;
    } else {
1118
        if ([mediaPlayer countOfTitles] > 1)
1119 1120
            ret++;

1121
        if ([mediaPlayer chaptersForTitleIndex:mediaPlayer.currentTitleIndex].count > 1)
1122 1123
            ret++;
    }
1124 1125

    return ret;
1126 1127
}

1128
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
1129
{
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
    UITableViewHeaderFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:TRACK_SELECTOR_TABLEVIEW_SECTIONHEADER];

    if (!view)
        view = [[VLCTrackSelectorHeaderView alloc] initWithReuseIdentifier:TRACK_SELECTOR_TABLEVIEW_SECTIONHEADER];

    return view;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
1140
    VLCMediaPlayer *mediaPlayer = self.playbackController.mediaPlayer;
1141

1142
    if (_switchingTracksNotChapters == YES) {
1143
        if (mediaPlayer.audioTrackIndexes.count > 2 && section == 0)
1144 1145
            return NSLocalizedString(@"CHOOSE_AUDIO_TRACK", nil);

1146
        if (mediaPlayer.videoSubTitlesIndexes.count > 1)
1147 1148
            return NSLocalizedString(@"CHOOSE_SUBTITLE_TRACK", nil);
    } else {
1149
        if ([mediaPlayer countOfTitles] > 1 && section == 0)
1150 1151
            return NSLocalizedString(@"CHOOSE_TITLE", nil);

1152
        if ([mediaPlayer chaptersForTitleIndex:mediaPlayer.currentTitleIndex].count > 1)
1153 1154
            return NSLocalizedString(@"CHOOSE_CHAPTER", nil);
    }
1155 1156 1157 1158 1159 1160

    return @"unknown track type";
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
1161
    VLCTrackSelectorTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:TRACK_SELECTOR_TABLEVIEW_CELL forIndexPath:indexPath];
1162 1163

    if (!cell)
1164
        cell = [[VLCTrackSelectorTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TRACK_SELECTOR_TABLEVIEW_CELL];
1165

1166
    NSInteger row = indexPath.row;
1167
    NSInteger section = indexPath.section;
1168
    VLCMediaPlayer *mediaPlayer = self.playbackController.mediaPlayer;
1169

1170 1171
    if (_switchingTracksNotChapters == YES) {
        NSArray *indexArray;
1172 1173
        if (mediaPlayer.audioTrackIndexes.count > 2 && section == 0) {
            indexArray = mediaPlayer.audioTrackIndexes;
1174

Tobias's avatar
Tobias committed
1175
            if ([indexArray indexOfObjectIdenticalTo:[NSNumber numberWithUnsignedInteger:mediaPlayer.currentAudioTrackIndex]] == row)
1176 1177 1178 1179
                [cell setShowsCurrentTrack:YES];
            else
                [cell setShowsCurrentTrack:NO];

1180
            cell.textLabel.text = [NSString stringWithFormat:@"%@", mediaPlayer.audioTrackNames[row]];
1181
        } else {
1182
            indexArray = mediaPlayer.videoSubTitlesIndexes;
1183

Tobias's avatar
Tobias committed
1184
            if ([indexArray indexOfObjectIdenticalTo:[NSNumber numberWithUnsignedInteger:mediaPlayer.currentVideoSubTitleIndex]] == row)
1185 1186 1187
                [cell setShowsCurrentTrack:YES];
            else
                [cell setShowsCurrentTrack:NO];
1188

1189
            cell.textLabel.text = [NSString stringWithFormat:@"%@", mediaPlayer.videoSubTitlesNames[row]];
1190
        }
1191
    } else {
1192 1193
        if ([mediaPlayer countOfTitles] > 1 && section == 0) {
            cell.textLabel.text = mediaPlayer.titles[row];
1194

1195
            if (row == mediaPlayer.currentTitleIndex)
1196 1197 1198