VLCAppDelegate.m 25.6 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * VLCAppDelegate.m
 * VLC for iOS
 *****************************************************************************
Felix Paul Kühne's avatar
Felix Paul Kühne committed
5
 * Copyright (c) 2013-2015 VideoLAN. All rights reserved.
6 7 8 9 10 11 12
 * $Id$
 *
 * Authors: Felix Paul Kühne <fkuehne # videolan.org>
 *          Gleb Pinigin <gpinigin # gmail.com>
 *          Jean-Romain Prévost <jr # 3on.fr>
 *          Luis Fernandes <zipleen # gmail.com>
 *          Carola Nitz <nitz.carola # googlemail.com>
13
 *          Tamas Timar <ttimar.vlc # gmail.com>
Tobias's avatar
Tobias committed
14
 *          Tobias Conradi <videolan # tobias-conradi.de>
15
 *          Soomin Lee <TheHungryBu # gmail.com>
16 17 18
 *
 * Refer to the COPYING file of the official project for license.
 *****************************************************************************/
Felix Paul Kühne's avatar
Felix Paul Kühne committed
19 20

#import "VLCAppDelegate.h"
Gleb Pinigin's avatar
Gleb Pinigin committed
21
#import "VLCMediaFileDiscoverer.h"
22
#import "NSString+SupportedMedia.h"
Felix Paul Kühne's avatar
Felix Paul Kühne committed
23
#import "UIDevice+VLC.h"
24
#import "VLCLibraryViewController.h"
25
#import "VLCHTTPUploaderController.h"
26
#import "VLCMigrationViewController.h"
Carola Nitz's avatar
Carola Nitz committed
27
#import <BoxSDK/BoxSDK.h>
28
#import "VLCPlaybackController.h"
29
#import "VLCPlaybackController+MediaLibrary.h"
30
#import "VLCPlayerDisplayController.h"
Tobias's avatar
Tobias committed
31
#import <MediaPlayer/MediaPlayer.h>
Felix Paul Kühne's avatar
Felix Paul Kühne committed
32
#import <HockeySDK/HockeySDK.h>
33
#import "VLCSidebarController.h"
Felix Paul Kühne's avatar
Felix Paul Kühne committed
34
#import "VLCActivityManager.h"
35 36
#import "VLCDropboxConstants.h"
#import <ObjectiveDropboxOfficial/ObjectiveDropboxOfficial.h>
37
#import "VLCPlaybackNavigationController.h"
38
#import "PAPasscodeViewController.h"
39
#import "VLC_iOS-Swift.h"
40 41

NSString *const VLCDropboxSessionWasAuthorized = @"VLCDropboxSessionWasAuthorized";
42

Felix Paul Kühne's avatar
Felix Paul Kühne committed
43 44
#define BETA_DISTRIBUTION 1

45 46
@interface VLCAppDelegate () <VLCMediaFileDiscovererDelegate>
{
47
    BOOL _isRunningMigration;
Carola Nitz's avatar
Carola Nitz committed
48
    BOOL _isComingFromHandoff;
49
    VLCWatchCommunication *_watchCommunication;
50
    VLCKeychainCoordinator *_keychainCoordinator;
Gleb Pinigin's avatar
Gleb Pinigin committed
51
}
52 53

@end
Felix Paul Kühne's avatar
Felix Paul Kühne committed
54 55 56

@implementation VLCAppDelegate

57 58 59 60
+ (void)initialize
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

61 62
    NSDictionary *appDefaults = @{kVLCSettingPasscodeAllowFaceID : @(1),
                                  kVLCSettingPasscodeAllowTouchID : @(1),
Felix Paul Kühne's avatar
Felix Paul Kühne committed
63 64 65
                                  kVLCSettingContinueAudioInBackgroundKey : @(YES),
                                  kVLCSettingStretchAudio : @(NO),
                                  kVLCSettingTextEncoding : kVLCSettingTextEncodingDefaultValue,
66
                                  kVLCSettingSkipLoopFilter : kVLCSettingSkipLoopFilterNonRef,
Felix Paul Kühne's avatar
Felix Paul Kühne committed
67 68 69 70 71
                                  kVLCSettingSubtitlesFont : kVLCSettingSubtitlesFontDefaultValue,
                                  kVLCSettingSubtitlesFontColor : kVLCSettingSubtitlesFontColorDefaultValue,
                                  kVLCSettingSubtitlesFontSize : kVLCSettingSubtitlesFontSizeDefaultValue,
                                  kVLCSettingSubtitlesBoldFont: kVLCSettingSubtitlesBoldFontDefaultValue,
                                  kVLCSettingDeinterlace : kVLCSettingDeinterlaceDefaultValue,
72
                                  kVLCSettingHardwareDecoding : kVLCSettingHardwareDecodingDefault,
Felix Paul Kühne's avatar
Felix Paul Kühne committed
73
                                  kVLCSettingNetworkCaching : kVLCSettingNetworkCachingDefaultValue,
74 75 76 77 78 79
                                  kVLCSettingVolumeGesture : @(YES),
                                  kVLCSettingPlayPauseGesture : @(YES),
                                  kVLCSettingBrightnessGesture : @(YES),
                                  kVLCSettingSeekGesture : @(YES),
                                  kVLCSettingCloseGesture : @(YES),
                                  kVLCSettingVariableJumpDuration : @(NO),
80
                                  kVLCSettingVideoFullscreenPlayback : @(YES),
81
                                  kVLCSettingContinuePlayback : @(1),
82
                                  kVLCSettingContinueAudioPlayback : @(1),
Felix Paul Kühne's avatar
Felix Paul Kühne committed
83 84 85 86 87
                                  kVLCSettingFTPTextEncoding : kVLCSettingFTPTextEncodingDefaultValue,
                                  kVLCSettingWiFiSharingIPv6 : kVLCSettingWiFiSharingIPv6DefaultValue,
                                  kVLCSettingEqualizerProfile : kVLCSettingEqualizerProfileDefaultValue,
                                  kVLCSettingPlaybackForwardSkipLength : kVLCSettingPlaybackForwardSkipLengthDefaultValue,
                                  kVLCSettingPlaybackBackwardSkipLength : kVLCSettingPlaybackBackwardSkipLengthDefaultValue,
88 89
                                  kVLCSettingOpenAppForPlayback : kVLCSettingOpenAppForPlaybackDefaultValue,
                                  kVLCAutomaticallyPlayNextItem : @(YES)};
90 91 92
    [defaults registerDefaults:appDefaults];
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
93 94
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
Felix Paul Kühne's avatar
Felix Paul Kühne committed
95
    BITHockeyManager *hockeyManager = [BITHockeyManager sharedHockeyManager];
96 97 98
    [hockeyManager configureWithBetaIdentifier:@"0114ca8e265244ce588d2ebd035c3577"
                                liveIdentifier:@"c95f4227dff96c61f8b3a46a25edc584"
                                      delegate:nil];
99
    [hockeyManager startManager];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
100

101 102 103
    // Configure Dropbox
    [DBClientsManager setupWithAppKey:kVLCDropboxAppKey];

104
    [self setupAppearence];
105

Felix Paul Kühne's avatar
Felix Paul Kühne committed
106 107
    // Init the HTTP Server and clean its cache
    [[VLCHTTPUploaderController sharedInstance] cleanCache];
108

Felix Paul Kühne's avatar
Felix Paul Kühne committed
109
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
110
    // enable crash preventer
111
    void (^setupBlock)() = ^{
112 113 114 115
        __weak typeof(self) weakSelf = self;
        UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:[[UIViewController alloc] init]];
        self.window.rootViewController = navCon;
        [self.window makeKeyAndVisible];
116 117 118
        [self validatePasscodeIfNeededWithCompletion:^{
            [weakSelf setupLibrary];
        }];
119

120
        BOOL spotlightEnabled = ![VLCKeychainCoordinator passcodeLockEnabled];
121
        [[MLMediaLibrary sharedMediaLibrary] setSpotlightIndexingEnabled:spotlightEnabled];
122 123
        [[MLMediaLibrary sharedMediaLibrary] applicationWillStart];

124
        VLCMediaFileDiscoverer *discoverer = [VLCMediaFileDiscoverer sharedInstance];
125 126
        NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        discoverer.directoryPath = [searchPaths firstObject];
127
        [discoverer addObserver:self];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
128
        [discoverer startDiscovering];
129 130 131
    };

    NSError *error = nil;
132 133

    if ([[MLMediaLibrary sharedMediaLibrary] libraryMigrationNeeded]){
134 135 136 137
        _isRunningMigration = YES;

        VLCMigrationViewController *migrationController = [[VLCMigrationViewController alloc] initWithNibName:@"VLCMigrationViewController" bundle:nil];
        migrationController.completionHandler = ^{
138

139 140 141 142
            //migrate
            setupBlock();
            _isRunningMigration = NO;
            [[MLMediaLibrary sharedMediaLibrary] updateMediaDatabase];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
143
            [[VLCMediaFileDiscoverer sharedInstance] updateMediaList];
144
        };
Felix Paul Kühne's avatar
Felix Paul Kühne committed
145

146 147
        self.window.rootViewController = migrationController;
        [self.window makeKeyAndVisible];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
148

149 150
    } else {
        if (error != nil) {
151
            APLog(@"removed persistentStore since it was corrupt");
152 153 154 155 156
            NSURL *storeURL = ((MLMediaLibrary *)[MLMediaLibrary sharedMediaLibrary]).persistentStoreURL;
            [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
        }
        setupBlock();
    }
157

Tobias's avatar
Tobias committed
158 159 160 161 162 163
    if ([VLCWatchCommunication isSupported]) {
        _watchCommunication = [VLCWatchCommunication sharedInstance];
        // TODO: push DB changes instead
        //    [_watchCommunication startRelayingNotificationName:NSManagedObjectContextDidSaveNotification object:nil];
        [_watchCommunication startRelayingNotificationName:VLCPlaybackControllerPlaybackMetadataDidChange object:nil];
    }
164

165
    /* add our static shortcut items the dynamic way to ease l10n and dynamic elements to be introduced later */
166
    if (@available(iOS 9, *)) {
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
        if (application.shortcutItems == nil || application.shortcutItems.count < 4) {
            UIApplicationShortcutItem *localLibraryItem = [[UIApplicationShortcutItem alloc] initWithType:kVLCApplicationShortcutLocalLibrary
                                                                                           localizedTitle:NSLocalizedString(@"SECTION_HEADER_LIBRARY",nil)
                                                                                        localizedSubtitle:nil
                                                                                                     icon:[UIApplicationShortcutIcon iconWithTemplateImageName:@"AllFiles"]
                                                                                                 userInfo:nil];
            UIApplicationShortcutItem *localServerItem = [[UIApplicationShortcutItem alloc] initWithType:kVLCApplicationShortcutLocalServers
                                                                                           localizedTitle:NSLocalizedString(@"LOCAL_NETWORK",nil)
                                                                                        localizedSubtitle:nil
                                                                                                     icon:[UIApplicationShortcutIcon iconWithTemplateImageName:@"Local"]
                                                                                                 userInfo:nil];
            UIApplicationShortcutItem *openNetworkStreamItem = [[UIApplicationShortcutItem alloc] initWithType:kVLCApplicationShortcutOpenNetworkStream
                                                                                           localizedTitle:NSLocalizedString(@"OPEN_NETWORK",nil)
                                                                                        localizedSubtitle:nil
                                                                                                     icon:[UIApplicationShortcutIcon iconWithTemplateImageName:@"OpenNetStream"]
                                                                                                 userInfo:nil];
            UIApplicationShortcutItem *cloudsItem = [[UIApplicationShortcutItem alloc] initWithType:kVLCApplicationShortcutClouds
                                                                                           localizedTitle:NSLocalizedString(@"CLOUD_SERVICES",nil)
                                                                                        localizedSubtitle:nil
                                                                                                     icon:[UIApplicationShortcutIcon iconWithTemplateImageName:@"iCloudIcon"]
                                                                                                 userInfo:nil];
            application.shortcutItems = @[localLibraryItem, localServerItem, openNetworkStreamItem, cloudsItem];
        }
    }

192 193
    return YES;
}
194

195 196 197 198 199 200 201 202 203 204 205 206 207 208
- (void)setupLibrary
{
    _libraryViewController = [[VLCLibraryViewController alloc] init];
    UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:_libraryViewController];

    VLCSidebarController *sidebarVC = [VLCSidebarController sharedInstance];
    sidebarVC.contentViewController = navCon;

    VLCPlayerDisplayController *playerDisplayController = [VLCPlayerDisplayController sharedInstance];
    playerDisplayController.childViewController = sidebarVC.fullViewController;

    _window.rootViewController = playerDisplayController;
}

209 210
- (void)setupAppearence
{
211
    UIColor *vlcOrange = [UIColor VLCOrangeTintColor];
212 213 214
    // Change the keyboard for UISearchBar
    [[UITextField appearance] setKeyboardAppearance:UIKeyboardAppearanceDark];
    // For the cursor
215
    [[UITextField appearance] setTintColor:vlcOrange];
216
    // Don't override the 'Cancel' button color in the search bar with the previous UITextField call. Use the default blue color
217
    [[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTitleTextAttributes:@{[UIColor whiteColor] : NSForegroundColorAttributeName} forState:UIControlStateNormal];
218

219
    [[UINavigationBar appearance] setBarTintColor:vlcOrange];
220
    [[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[VLCPlaybackNavigationController class]]] setBarTintColor: nil];
221
    [[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
222 223 224
    if (@available(iOS 11.0, *)) {
        [[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[UIDocumentBrowserViewController class]]] setTintColor: vlcOrange];
    }
225
    [[UINavigationBar appearance] setTitleTextAttributes: @{ NSForegroundColorAttributeName : [UIColor whiteColor] }];
226
    // For the edit selection indicators
227 228 229
    [[UITableView appearance] setTintColor:vlcOrange];
    [[UISwitch appearance] setOnTintColor:vlcOrange];
    [[UISearchBar appearance] setBarTintColor:vlcOrange];
230
    [[UISearchBar appearance] setTintColor:[UIColor whiteColor]];
231 232
}

233 234 235 236 237
- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

Carola Nitz's avatar
Carola Nitz committed
238 239
#pragma mark - Handoff

240 241
- (BOOL)application:(UIApplication *)application willContinueUserActivityWithType:(NSString *)userActivityType
{
242 243 244
    if ([userActivityType isEqualToString:kVLCUserActivityLibraryMode] ||
        [userActivityType isEqualToString:kVLCUserActivityPlaying] ||
        [userActivityType isEqualToString:kVLCUserActivityLibrarySelection])
Carola Nitz's avatar
Carola Nitz committed
245
        return YES;
246

Carola Nitz's avatar
Carola Nitz committed
247 248 249
    return NO;
}

250 251 252 253 254
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
 restorationHandler:(void (^)(NSArray *))restorationHandler
{
    NSString *userActivityType = userActivity.activityType;
255 256 257
    NSDictionary *dict = userActivity.userInfo;
    if([userActivityType isEqualToString:kVLCUserActivityLibraryMode] ||
       [userActivityType isEqualToString:kVLCUserActivityLibrarySelection]) {
Carola Nitz's avatar
Carola Nitz committed
258

259 260 261
        VLCLibraryMode libraryMode = (VLCLibraryMode)[(NSNumber *)dict[@"state"] integerValue];

        if (libraryMode <= VLCLibraryModeAllSeries) {
262 263
            [[VLCSidebarController sharedInstance] selectRowAtIndexPath:[NSIndexPath indexPathForRow:libraryMode inSection:0]
                                                         scrollPosition:UITableViewScrollPositionTop];
264
            [self.libraryViewController setLibraryMode:libraryMode];
265
        }
266

267
        [self.libraryViewController restoreUserActivityState:userActivity];
Carola Nitz's avatar
Carola Nitz committed
268
        _isComingFromHandoff = YES;
Carola Nitz's avatar
Carola Nitz committed
269
        return YES;
270
    } else {
Tobias's avatar
Tobias committed
271 272 273 274 275 276 277 278 279 280 281
        NSURL *uriRepresentation = nil;
        if ([userActivityType isEqualToString:CSSearchableItemActionType]) {
            uriRepresentation = [NSURL URLWithString:dict[CSSearchableItemActivityIdentifier]];
        } else {
            uriRepresentation = dict[@"playingmedia"];
        }

        if (!uriRepresentation) {
            return NO;
        }

282 283 284 285 286
        NSManagedObject *managedObject = [[MLMediaLibrary sharedMediaLibrary] objectForURIRepresentation:uriRepresentation];
        if (managedObject == nil) {
            APLog(@"%s file not found: %@",__PRETTY_FUNCTION__,userActivity);
            return NO;
        }
287 288 289
        [self validatePasscodeIfNeededWithCompletion:^{
            [[VLCPlaybackController sharedInstance] openMediaLibraryObject:managedObject];
        }];
290
        return YES;
Carola Nitz's avatar
Carola Nitz committed
291 292 293 294
    }
    return NO;
}

295 296 297
- (void)application:(UIApplication *)application
didFailToContinueUserActivityWithType:(NSString *)userActivityType
              error:(NSError *)error
Carola Nitz's avatar
Carola Nitz committed
298 299 300 301 302 303
{
    if (error.code != NSUserCancelledError){
        //TODO: present alert
    }
}

Carola Nitz's avatar
Carola Nitz committed
304
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
305
{
306 307 308 309 310 311 312 313 314 315 316
    __weak typeof(self) weakSelf = self;
    [self validatePasscodeIfNeededWithCompletion:^{
        if (!_libraryViewController) {
            [weakSelf setupLibrary];
        }
        [weakSelf openURL:url options:options];
    }];
    return YES;
}

- (BOOL)openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
317 318 319 320 321 322
    //Handles Dropbox Authorization flow.
    DBOAuthResult *authResult = [DBClientsManager handleRedirectURL:url];
    if (authResult != nil) {
        if ([authResult isSuccess]) {
            return YES;
        }
323
    }
324

325 326 327 328 329 330
    //Handles Google Authorization flow.
    if ([_currentGoogleAuthorizationFlow resumeAuthorizationFlowWithURL:url]) {
        _currentGoogleAuthorizationFlow = nil;
        return YES;
    }

331
    if (_libraryViewController && url != nil) {
332
        APLog(@"requested %@ to be opened", url);
333

334
        if (url.isFileURL) {
335 336 337 338 339 340
            VLCDocumentClass *subclass = [[VLCDocumentClass alloc] initWithFileURL:url];
            [subclass openWithCompletionHandler:^(BOOL success) {
                [self playWithURL:url completion:^(BOOL success) {
                    [subclass closeWithCompletionHandler:nil];
                }];
            }];
341 342 343 344 345
        } else if ([url.scheme isEqualToString:@"vlc-x-callback"] || [url.host isEqualToString:@"x-callback-url"]) {
            // URL confirmes to the x-callback-url specification
            // vlc-x-callback://x-callback-url/action?param=value&x-success=callback
            APLog(@"x-callback-url with host '%@' path '%@' parameters '%@'", url.host, url.path, url.query);
            NSString *action = [url.path stringByReplacingOccurrencesOfString:@"/" withString:@""];
346 347 348 349
            NSURL *movieURL;
            NSURL *successCallback;
            NSURL *errorCallback;
            NSString *fileName;
350 351 352 353 354
            for (NSString *entry in [url.query componentsSeparatedByString:@"&"]) {
                NSArray *keyvalue = [entry componentsSeparatedByString:@"="];
                if (keyvalue.count < 2) continue;
                NSString *key = keyvalue[0];
                NSString *value = [keyvalue[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
355 356

                if ([key isEqualToString:@"url"])
357
                    movieURL = [NSURL URLWithString:value];
358
                else if ([key isEqualToString:@"filename"])
359
                    fileName = value;
360
                else if ([key isEqualToString:@"x-success"])
361
                    successCallback = [NSURL URLWithString:value];
362 363
                else if ([key isEqualToString:@"x-error"])
                    errorCallback = [NSURL URLWithString:value];
364 365
            }
            if ([action isEqualToString:@"stream"] && movieURL) {
366 367 368
                [self playWithURL:movieURL completion:^(BOOL success) {
                    NSURL *callback = success ? successCallback : errorCallback;
                    if (@available(iOS 10, *)) {
369
                        [[UIApplication sharedApplication] openURL:callback options:@{} completionHandler:nil];
370 371 372 373
                    } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                        /* UIApplication's replacement calls require iOS 10 or later, which we can't enforce as of yet */
374
                        [[UIApplication sharedApplication] openURL:callback];
375 376 377
#pragma clang diagnostic pop
                    }
                }];
378
            }
379 380 381
            else if ([action isEqualToString:@"download"] && movieURL) {
                [self downloadMovieFromURL:movieURL fileNameOfMedia:fileName];
            }
Luis's avatar
Luis committed
382
        } else {
383 384 385 386 387 388 389 390 391
            NSString *receivedUrl = [url absoluteString];
            if ([receivedUrl length] > 6) {
                NSString *verifyVlcUrl = [receivedUrl substringToIndex:6];
                if ([verifyVlcUrl isEqualToString:@"vlc://"]) {
                    NSString *parsedString = [receivedUrl substringFromIndex:6];
                    NSUInteger location = [parsedString rangeOfString:@"//"].location;

                    /* Safari & al mangle vlc://http:// so fix this */
                    if (location != NSNotFound && [parsedString characterAtIndex:location - 1] != 0x3a) { // :
392
                        parsedString = [NSString stringWithFormat:@"%@://%@", [parsedString substringToIndex:location], [parsedString substringFromIndex:location+2]];
393 394 395 396 397 398
                    } else {
                        parsedString = [receivedUrl substringFromIndex:6];
                        if (![parsedString hasPrefix:@"http://"] && ![parsedString hasPrefix:@"https://"] && ![parsedString hasPrefix:@"ftp://"]) {
                            parsedString = [@"http://" stringByAppendingString:[receivedUrl substringFromIndex:6]];
                        }
                    }
399 400 401
                    url = [NSURL URLWithString:parsedString];
                }
            }
402 403
            [[VLCSidebarController sharedInstance] selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
                                                         scrollPosition:UITableViewScrollPositionNone];
404 405 406

            NSString *scheme = url.scheme;
            if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"] || [scheme isEqualToString:@"ftp"]) {
Felix Paul Kühne's avatar
Felix Paul Kühne committed
407
                VLCAlertView *alert = [[VLCAlertView alloc] initWithTitle:NSLocalizedString(@"OPEN_STREAM_OR_DOWNLOAD", nil) message:url.absoluteString cancelButtonTitle:NSLocalizedString(@"BUTTON_DOWNLOAD", nil) otherButtonTitles:@[NSLocalizedString(@"PLAY_BUTTON", nil)]];
408 409
                alert.completion = ^(BOOL cancelled, NSInteger buttonIndex) {
                    if (cancelled)
410
                        [self downloadMovieFromURL:url fileNameOfMedia:nil];
411
                    else {
412
                        [self playWithURL:url completion:nil];
413
                    }
414 415
                };
                [alert show];
416
            } else {
417
                [self playWithURL:url completion:nil];
418
            }
Luis's avatar
Luis committed
419
        }
420 421 422 423 424
        return YES;
    }
    return NO;
}

425 426 427 428 429
- (void)applicationWillEnterForeground:(UIApplication *)application
{
    [[MLMediaLibrary sharedMediaLibrary] applicationWillStart];
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
430 431
- (void)applicationWillResignActive:(UIApplication *)application
{
432 433 434 435 436 437 438 439 440 441 442 443 444 445
    //Touch ID is shown 
    if ([_window.rootViewController.presentedViewController isKindOfClass:[UINavigationController class]]){
        UINavigationController *navCon = (UINavigationController *)_window.rootViewController.presentedViewController;
        if ([navCon.topViewController isKindOfClass:[PAPasscodeViewController class]]){
            return;
        }
    }
    __weak typeof(self) weakself = self;
    [self validatePasscodeIfNeededWithCompletion:^{
        [weakself.libraryViewController updateViewContents];
        if ([VLCPlaybackController sharedInstance].isPlaying){
            [[VLCPlayerDisplayController sharedInstance] pushPlaybackView];
        }
    }];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
446 447 448 449 450
    [[MLMediaLibrary sharedMediaLibrary] applicationWillExit];
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
Carola Nitz's avatar
Carola Nitz committed
451
    if (!_isRunningMigration && !_isComingFromHandoff) {
452
        [[MLMediaLibrary sharedMediaLibrary] updateMediaDatabase];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
453
        [[VLCMediaFileDiscoverer sharedInstance] updateMediaList];
Carola Nitz's avatar
Carola Nitz committed
454 455
    } else if(_isComingFromHandoff) {
        _isComingFromHandoff = NO;
456
    }
Felix Paul Kühne's avatar
Felix Paul Kühne committed
457 458
}

459 460 461 462 463
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler
{
    [[VLCSidebarController sharedInstance] performActionForShortcutItem:shortcutItem];
}

Gleb Pinigin's avatar
Gleb Pinigin committed
464
#pragma mark - media discovering
465

466 467
- (void)mediaFileAdded:(NSString *)fileName loading:(BOOL)isLoading
{
Gleb Pinigin's avatar
Gleb Pinigin committed
468 469 470
    if (!isLoading) {
        MLMediaLibrary *sharedLibrary = [MLMediaLibrary sharedMediaLibrary];
        [sharedLibrary addFilePaths:@[fileName]];
471

Gleb Pinigin's avatar
Gleb Pinigin committed
472 473 474
        /* exclude media files from backup (QA1719) */
        NSURL *excludeURL = [NSURL fileURLWithPath:fileName];
        [excludeURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil];
475

Gleb Pinigin's avatar
Gleb Pinigin committed
476 477
        // TODO Should we update media db after adding new files?
        [sharedLibrary updateMediaDatabase];
478
        [_libraryViewController updateViewContents];
479 480 481
    }
}

482 483
- (void)mediaFileDeleted:(NSString *)name
{
Gleb Pinigin's avatar
Gleb Pinigin committed
484
    [[MLMediaLibrary sharedMediaLibrary] updateMediaDatabase];
485
    [_libraryViewController updateViewContents];
Gleb Pinigin's avatar
Gleb Pinigin committed
486 487
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
488
- (void)mediaFilesFoundRequiringAdditionToStorageBackend:(NSArray<NSString *> *)foundFiles
489 490 491 492 493
{
    [[MLMediaLibrary sharedMediaLibrary] addFilePaths:foundFiles];
    [[(VLCAppDelegate *)[UIApplication sharedApplication].delegate libraryViewController] updateViewContents];
}

494
#pragma mark - pass code validation
495 496 497 498 499 500 501
- (VLCKeychainCoordinator *)keychainCoordinator
{
    if (!_keychainCoordinator) {
        _keychainCoordinator = [[VLCKeychainCoordinator alloc] init];
    }
    return _keychainCoordinator;
}
502

503
- (void)validatePasscodeIfNeededWithCompletion:(void(^)(void))completion
504
{
505
    if ([VLCKeychainCoordinator passcodeLockEnabled]) {
506
        [[VLCPlayerDisplayController sharedInstance] dismissPlaybackView];
507
        [self.keychainCoordinator validatePasscodeWithCompletion:completion];
508
    } else {
509
        completion();
510
    }
511 512
}

513 514 515 516 517
#pragma mark - download handling

- (void)downloadMovieFromURL:(NSURL *)url
             fileNameOfMedia:(NSString *)fileName
{
518 519 520
    [[VLCDownloadViewController sharedInstance] addURLToDownloadList:url fileNameOfMedia:fileName];
    [[VLCSidebarController sharedInstance] selectRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:1]
                                                 scrollPosition:UITableViewScrollPositionNone];
521 522
}

Carola Nitz's avatar
Carola Nitz committed
523
#pragma mark - playback
524
- (void)playWithURL:(NSURL *)url completion:(void (^ __nullable)(BOOL success))completion
Carola Nitz's avatar
Carola Nitz committed
525 526 527 528
{
    VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
    vpc.fullscreenSessionRequested = YES;
    VLCMediaList *mediaList = [[VLCMediaList alloc] initWithArray:@[[VLCMedia mediaWithURL:url]]];
529
    [vpc playMediaList:mediaList firstIndex:0 subtitlesFilePath:nil completion:completion];
Carola Nitz's avatar
Carola Nitz committed
530 531
}

532
#pragma mark - watch stuff
533 534 535
- (void)application:(UIApplication *)application
handleWatchKitExtensionRequest:(NSDictionary *)userInfo
              reply:(void (^)(NSDictionary *))reply
536
{
Tobias's avatar
Tobias committed
537 538 539
    if ([VLCWatchCommunication isSupported]) {
        [self.watchCommunication session:[WCSession defaultSession] didReceiveMessage:userInfo replyHandler:reply];
    }
540 541
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
542
@end