VLCPlayerDisplayController.m 12.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*****************************************************************************
 * VLCPlayerDisplayController.m
 * 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 "VLCPlayerDisplayController.h"
#import "VLCPlaybackController.h"
15
#import "VLCMiniPlaybackView.h"
16
#import "VLCPlaybackNavigationController.h"
17 18

#if TARGET_OS_IOS
19
#import "VLCMovieViewController.h"
20 21
#else
#import "VLCFullscreenMovieTVViewController.h"
22
#endif
23 24 25 26

static NSString *const VLCPlayerDisplayControllerDisplayModeKey = @"VLCPlayerDisplayControllerDisplayMode";

@interface VLCPlayerDisplayController ()
27 28
@property (nonatomic, strong) UIViewController<VLCPlaybackControllerDelegate> *movieViewController;
@property (nonatomic, strong) UIView<VLCPlaybackControllerDelegate, VLCMiniPlaybackViewInterface> *miniPlaybackView;
29 30 31 32
@end

@implementation VLCPlayerDisplayController

33 34 35 36 37 38 39 40 41 42 43 44
+ (VLCPlayerDisplayController *)sharedInstance
{
    static VLCPlayerDisplayController *sharedInstance = nil;
    static dispatch_once_t pred;

    dispatch_once(&pred, ^{
        sharedInstance = [VLCPlayerDisplayController new];
    });

    return sharedInstance;
}

45 46
+ (void)initialize
{
Felix Paul Kühne's avatar
Felix Paul Kühne committed
47
    [[NSUserDefaults standardUserDefaults] registerDefaults:@{VLCPlayerDisplayControllerDisplayModeKey : @(VLCPlayerDisplayControllerDisplayModeFullscreen)}];
48 49
}

50
- (instancetype)init
51
{
52
    self = [super init];
53
    if (self) {
54 55 56 57
        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
        [notificationCenter addObserver:self selector:@selector(playbackDidStart:) name:VLCPlaybackControllerPlaybackDidStart object:nil];
        [notificationCenter addObserver:self selector:@selector(playbackDidFail:) name:VLCPlaybackControllerPlaybackDidFail object:nil];
        [notificationCenter addObserver:self selector:@selector(playbackDidStop:) name:VLCPlaybackControllerPlaybackDidStop object:nil];
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
    }
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self setupChildViewController];
}

#pragma mark - ChildViewController

- (void)setChildViewController:(UIViewController *)childViewController
{
    if (_childViewController) {
        [_childViewController willMoveToParentViewController:nil];
        [_childViewController.view removeFromSuperview];
        [_childViewController removeFromParentViewController];
    }
    _childViewController = childViewController;
    if (self.isViewLoaded) {
        [self setupChildViewController];
    }
}

- (void)setupChildViewController
{
    UIViewController *childViewController = self.childViewController;
91 92
    if (childViewController == nil)
        return;
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
    [self addChildViewController:childViewController];
    [self.view addSubview:childViewController.view];
    [childViewController didMoveToParentViewController:self];
}

#pragma mark - properties

- (VLCPlayerDisplayControllerDisplayMode)displayMode
{
    return [[NSUserDefaults standardUserDefaults] integerForKey:VLCPlayerDisplayControllerDisplayModeKey];
}

- (void)setDisplayMode:(VLCPlayerDisplayControllerDisplayMode)displayMode
{
    [[NSUserDefaults standardUserDefaults] setInteger:displayMode forKey:VLCPlayerDisplayControllerDisplayModeKey];
}

110 111 112 113 114 115 116 117 118 119
- (void)viewSafeAreaInsetsDidChange
{
    if (@available(iOS 11.0, *)) {
        [super viewSafeAreaInsetsDidChange];
        CGRect frame = _miniPlaybackView.frame;
        frame.size.height = 60.0 + self.view.safeAreaInsets.bottom;
        _miniPlaybackView.frame = frame;
    }
}

120 121 122 123 124 125 126
- (VLCPlaybackController *)playbackController {
    if (_playbackController == nil) {
        _playbackController = [VLCPlaybackController sharedInstance];
    }
    return _playbackController;
}

127
- (UIViewController<VLCPlaybackControllerDelegate> *)movieViewController
128 129
{
    if (!_movieViewController) {
130
#if TARGET_OS_IOS
131
        _movieViewController = [[VLCMovieViewController alloc] initWithNibName:nil bundle:nil];
132 133
#else
        _movieViewController = [[VLCFullscreenMovieTVViewController alloc] initWithNibName:nil bundle:nil];
134
#endif
135 136 137 138 139 140 141 142 143
        [VLCPlaybackController sharedInstance].delegate = _movieViewController;
    }
    return _movieViewController;
}

#pragma mark - Notification Handling

- (void)playbackDidStart:(NSNotification *)notification
{
144 145 146 147 148 149 150 151 152
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    BOOL enforceFullscreen = [[defaults objectForKey:kVLCSettingVideoFullscreenPlayback] boolValue];

    VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
    if (vpc.fullscreenSessionRequested && enforceFullscreen) {
        [self showFullscreenPlayback];
        return;
    }

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    switch (self.displayMode) {
        case VLCPlayerDisplayControllerDisplayModeFullscreen:
            [self _presentFullscreenPlaybackViewIfNeeded];
            break;
        case VLCPlayerDisplayControllerDisplayModeMiniplayer:
            [self _showHideMiniPlaybackView];
            break;
        default:
            break;
    }
}

- (void)playbackDidStop:(NSNotification *)notification
{
    [self dismissPlaybackView];
}

- (void)playbackDidFail:(NSNotification *)notification
{
    [self showPlaybackError];
}

#pragma mark - API

- (void)showFullscreenPlayback
{
    self.displayMode = VLCPlayerDisplayControllerDisplayModeFullscreen;
    [self _presentFullscreenPlaybackViewIfNeeded];
}

- (void)closeFullscreenPlayback
{
    [self _closeFullscreenPlayback];
    self.displayMode = VLCPlayerDisplayControllerDisplayModeMiniplayer;
    [self _showHideMiniPlaybackView];
}

#pragma mark - presentation handling
Felix Paul Kühne's avatar
Felix Paul Kühne committed
191

192 193 194 195 196
- (BOOL)shouldAnimate
{
    return [[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground;
}

197 198 199 200 201 202 203 204 205 206 207 208 209
- (void)pushPlaybackView
{
    switch (self.displayMode) {
        case VLCPlayerDisplayControllerDisplayModeFullscreen:
            [self _presentFullscreenPlaybackViewIfNeeded];
            break;
        case VLCPlayerDisplayControllerDisplayModeMiniplayer:
            [self _showHideMiniPlaybackView];
        default:
            break;
    }
}

210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
- (void)dismissPlaybackView
{
    switch (self.displayMode) {
        case VLCPlayerDisplayControllerDisplayModeFullscreen:
            [self _closeFullscreenPlayback];
            break;
        case VLCPlayerDisplayControllerDisplayModeMiniplayer:
            [self _showHideMiniPlaybackView];
        default:
            break;
    }
}

- (void)showPlaybackError
{
    NSString *failedString = NSLocalizedString(@"PLAYBACK_FAILED", nil);
226
#if TARGET_OS_IOS
227 228
    switch (self.displayMode) {
        case VLCPlayerDisplayControllerDisplayModeFullscreen:
229 230 231
            if ([self.movieViewController respondsToSelector:@selector(showStatusMessage:forPlaybackController:)]) {
                [self.movieViewController showStatusMessage:failedString forPlaybackController:nil];
            }
232 233 234
            break;
        case VLCPlayerDisplayControllerDisplayModeMiniplayer:
        default:
235

236 237 238 239 240
            [[[VLCAlertView alloc] initWithTitle:failedString
                                         message:nil
                                        delegate:nil
                               cancelButtonTitle:NSLocalizedString(@"BUTTON_OK", nil)
                               otherButtonTitles:nil] show];
241 242
            break;
    }
243 244 245 246 247 248 249 250 251 252 253 254
#else
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:failedString
                                                                   message:@""
                                                            preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_OK", nil)
                                                            style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction * action) {}];

    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];
#endif
255 256 257
}

#pragma mark - fullscreen player
Felix Paul Kühne's avatar
Felix Paul Kühne committed
258

259 260
- (void)_presentFullscreenPlaybackViewIfNeeded
{
261 262 263 264 265
    dispatch_async(dispatch_get_main_queue(), ^{
        if (!self.movieViewController.presentingViewController) {
            [self _presentMovieViewControllerAnimated:[self shouldAnimate]];
        }
    });
266 267 268 269
}

- (void)_closeFullscreenPlayback
{
270 271 272 273 274
    dispatch_async(dispatch_get_main_queue(), ^{
        BOOL animated = [self shouldAnimate];
        [self.movieViewController dismissViewControllerAnimated:animated completion:nil];
        [self _showHideMiniPlaybackView];
    });
275 276 277 278
}

- (void)_presentMovieViewControllerAnimated:(BOOL)animated
{
279
    UIViewController<VLCPlaybackControllerDelegate> *movieViewController = self.movieViewController;
280 281
    UINavigationController *navCon = [[VLCPlaybackNavigationController alloc] initWithRootViewController:movieViewController];
    [movieViewController prepareForMediaPlayback:self.playbackController];
282

283 284 285 286 287 288 289 290
    UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    [window.rootViewController presentViewController:navCon animated:animated completion:nil];
}

#pragma mark - miniplayer

- (void)_showHideMiniPlaybackView
{
291 292 293
#if TARGET_OS_TV
    return;
#else
294 295 296 297 298
    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(_showHideMiniPlaybackView) withObject:nil waitUntilDone:NO];
        return;
    }

299
    VLCPlaybackController *playbackController = [VLCPlaybackController sharedInstance];
300
    UIView<VLCPlaybackControllerDelegate, VLCMiniPlaybackViewInterface> *miniPlaybackView = self.miniPlaybackView;
301
    const NSTimeInterval animationDuration = 0.25;
302
    const BOOL activePlaybackSession = playbackController.isPlaying || playbackController.willPlay;
303 304
    const BOOL miniPlayerVisible = miniPlaybackView.visible;

305
    const CGRect viewRect = self.view.bounds;
306 307 308 309 310

    CGFloat miniPlayerHeight = 60.;
    if (@available(iOS 11.0, *)) {
        miniPlayerHeight += self.view.safeAreaInsets.bottom;
    }
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
    const CGRect miniPlayerFrameIn =  CGRectMake(0., viewRect.size.height-miniPlayerHeight, viewRect.size.width, miniPlayerHeight);
    const CGRect miniPlayerFrameOut = CGRectMake(0., viewRect.size.height, viewRect.size.width, miniPlayerHeight);

    BOOL needsShow = activePlaybackSession && !miniPlayerVisible;
    BOOL needsHide = !activePlaybackSession && miniPlayerVisible;

    if (self.editing) {
        needsHide = YES;
        needsShow = NO;
    }

    void (^completionBlock)(BOOL) = nil;
    if (needsShow) {
        if (!miniPlaybackView) {
            self.miniPlaybackView = miniPlaybackView = [[VLCMiniPlaybackView alloc] initWithFrame:miniPlayerFrameOut];
            miniPlaybackView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
            [self.view addSubview:miniPlaybackView];
        }
        miniPlaybackView.visible = YES;
    } else if (needsHide) {
        miniPlaybackView.visible = NO;
        completionBlock = ^(BOOL finished) {
333
            UIView<VLCPlaybackControllerDelegate, VLCMiniPlaybackViewInterface> *miniPlaybackView = self.miniPlaybackView;
334 335
            if (miniPlaybackView.visible == NO) {
                [miniPlaybackView removeFromSuperview];
336
                self.miniPlaybackView = nil;
337 338 339 340 341 342 343 344
            }
        };
    }
    //when switching between tableview and collectionview all subviews are removed, make sure to readd it when this happens
    if (!miniPlaybackView.superview && miniPlayerVisible) {
        [self.view addSubview:miniPlaybackView];
    }
    // either way update view
345
    [miniPlaybackView prepareForMediaPlayback:playbackController];
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362

    if (needsShow || needsHide) {
        UIViewController *childViewController = self.childViewController;

        const CGRect newMiniPlayerFrame = needsHide ? miniPlayerFrameOut : miniPlayerFrameIn;
        CGRect newChildViewFrame = childViewController.view.frame;
        newChildViewFrame.size.height = CGRectGetMinY(newMiniPlayerFrame)-CGRectGetMinY(newChildViewFrame);

        [UIView animateWithDuration:animationDuration
                              delay:animationDuration
                            options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction
                         animations:^{
                             miniPlaybackView.frame = newMiniPlayerFrame;
                             childViewController.view.frame = newChildViewFrame;
                         }
                         completion:completionBlock];
    }
363
#endif
364 365 366
}

@end