VLCAppDelegate.m 12.3 KB
Newer Older
Felix Paul Kühne's avatar
Felix Paul Kühne committed
1 2 3 4 5 6 7
//
//  VLCAppDelegate.m
//  AspenProject
//
//  Created by Felix Paul Kühne on 27.02.13.
//  Copyright (c) 2013 VideoLAN. All rights reserved.
//
8 9
//  Refer to the COPYING file of the official project for license.
//
Felix Paul Kühne's avatar
Felix Paul Kühne committed
10 11

#import "VLCAppDelegate.h"
Gleb Pinigin's avatar
Gleb Pinigin committed
12
#import "VLCMediaFileDiscoverer.h"
13
#import "NSString+SupportedMedia.h"
14
#import "UIDevice+SpeedCategory.h"
Felix Paul Kühne's avatar
Felix Paul Kühne committed
15 16

#import "VLCPlaylistViewController.h"
17
#import "VLCMovieViewController.h"
18
#import "PAPasscodeViewController.h"
19
#import "UINavigationController+Theme.h"
20
#import "VLCHTTPUploaderController.h"
21
#import "VLCMenuTableViewController.h"
22

23 24
#define PASSCODE_CHECK_INTERVAL 300

Gleb Pinigin's avatar
Gleb Pinigin committed
25
@interface VLCAppDelegate () <PAPasscodeViewControllerDelegate, VLCMediaFileDiscovererDelegate> {
Gleb Pinigin's avatar
Gleb Pinigin committed
26
    PAPasscodeViewController *_passcodeLockController;
Gleb Pinigin's avatar
Gleb Pinigin committed
27
    VLCDropboxTableViewController *_dropboxTableViewController;
28
    VLCDownloadViewController *_downloadViewController;
29
    int _idleCounter;
30
    VLCMovieViewController *_movieViewController;
Gleb Pinigin's avatar
Gleb Pinigin committed
31
}
32 33 34 35

@property (nonatomic) BOOL passcodeValidated;

@end
Felix Paul Kühne's avatar
Felix Paul Kühne committed
36 37 38

@implementation VLCAppDelegate

39 40 41 42
+ (void)initialize
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

43 44 45 46 47
    NSNumber *skipLoopFilterDefaultValue;
    int deviceSpeedCategory = [[UIDevice currentDevice] speedCategory];
    if (deviceSpeedCategory < 3)
        skipLoopFilterDefaultValue = kVLCSettingSkipLoopFilterNonKey;
    else
48
        skipLoopFilterDefaultValue = kVLCSettingSkipLoopFilterNonRef;
49

50
    NSDictionary *appDefaults = @{kVLCSettingPasscodeKey : @"", kVLCSettingPasscodeOnKey : @(NO), kVLCSettingContinueAudioInBackgroundKey : @(YES), kVLCSettingStretchAudio : @(NO), kVLCSettingTextEncoding : kVLCSettingTextEncodingDefaultValue, kVLCSettingSkipLoopFilter : skipLoopFilterDefaultValue, kVLCSettingSubtitlesFont : kVLCSettingSubtitlesFontDefaultValue, kVLCSettingSubtitlesFontColor : kVLCSettingSubtitlesFontColorDefaultValue, kVLCSettingSubtitlesFontSize : kVLCSettingSubtitlesFontSizeDefaultValue, kVLCSettingDeinterlace : kVLCSettingDeinterlaceDefaultValue};
51 52 53 54

    [defaults registerDefaults:appDefaults];
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
55 56
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
57 58 59
    // Init the HTTP Server
    self.uploadController = [[VLCHTTPUploaderController alloc] init];

60 61 62
    // enable crash preventer
    [[MLMediaLibrary sharedMediaLibrary] applicationWillStart];

Felix Paul Kühne's avatar
Felix Paul Kühne committed
63
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
64

65
    _playlistViewController = [[VLCPlaylistViewController alloc] init];
66 67
    UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:_playlistViewController];
    [navCon loadTheme];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
68

69
    _revealController = [[GHRevealViewController alloc] initWithNibName:nil bundle:nil];
70
    _revealController.wantsFullScreenLayout = YES;
71 72
    _menuViewController = [[VLCMenuTableViewController alloc] initWithNibName:nil bundle:nil];
    _revealController.sidebarViewController = _menuViewController;
73
    _revealController.contentViewController = navCon;
74

75
    self.window.rootViewController = self.revealController;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
76
    [self.window makeKeyAndVisible];
77

Gleb Pinigin's avatar
Gleb Pinigin committed
78 79 80
    VLCMediaFileDiscoverer *discoverer = [VLCMediaFileDiscoverer sharedInstance];
    [discoverer addObserver:self];
    [discoverer startDiscovering:[self directoryPath]];
81

82
    [self validatePasscode];
83

Felix Paul Kühne's avatar
Felix Paul Kühne committed
84 85 86
    return YES;
}

87 88
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
89 90 91 92 93
    if ([[DBSession sharedSession] handleOpenURL:url]) {
        [self.dropboxTableViewController updateViewAfterSessionChange];
        return YES;
    }

94 95
    if (_playlistViewController && url != nil) {
        APLog(@"%@ requested %@ to be opened", sourceApplication, url);
96

97
        if (url.isFileURL) {
98 99 100 101 102 103 104 105 106
            NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
            NSString *directoryPath = searchPaths[0];
            NSURL *destinationURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", directoryPath, url.lastPathComponent]];
            NSError *theError;
            [[NSFileManager defaultManager] moveItemAtURL:url toURL:destinationURL error:&theError];
            if (theError.code != noErr)
                APLog(@"saving the file failed (%i): %@", theError.code, theError.localizedDescription);

            [self updateMediaList];
Luis's avatar
Luis committed
107 108
        } else {
            NSURL *parsedUrl = [self parseOpenURL:url];
109
            [self.menuViewController selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionNone];
110
            [self.playlistViewController performSelector:@selector(openMovieFromURL:) withObject:parsedUrl afterDelay:kGHRevealSidebarDefaultAnimationDuration];
Luis's avatar
Luis committed
111
        }
112 113 114 115 116
        return YES;
    }
    return NO;
}

Luis's avatar
Luis committed
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
- (NSURL *)parseOpenURL:(NSURL *)url
{
    NSString *receivedUrl = [url absoluteString];
    if ([receivedUrl length] > 6) {
        NSString *verifyVlcUrl = [receivedUrl substringToIndex:6];
        if ([verifyVlcUrl isEqualToString:@"vlc://"]) {
            NSString *parsedString = [receivedUrl substringFromIndex:6];

            // "url decode" so we can parse http:// links
            parsedString = [parsedString stringByReplacingOccurrencesOfString:@"+"withString:@" "];
            parsedString = [parsedString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

            // add http:// if nothing is there
            NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:(NSTextCheckingTypes)NSTextCheckingTypeLink error:nil];
            NSUInteger parsedStringLength = [parsedString length];
            NSUInteger numberOfUrlMatches = [detector numberOfMatchesInString:parsedString options:0 range:NSMakeRange(0, parsedStringLength)];
            if (numberOfUrlMatches == 0) {
                parsedString = [@"http://" stringByAppendingString:parsedString];
            }

            NSURL *targetUrl = [NSURL URLWithString:parsedString];
            return targetUrl;
        }
    }
    return url;
}

144 145 146
- (void)applicationWillEnterForeground:(UIApplication *)application
{
    [[MLMediaLibrary sharedMediaLibrary] applicationWillStart];
147
    [self validatePasscode];
148 149
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
150 151
- (void)applicationWillResignActive:(UIApplication *)application
{
152
    self.nextPasscodeCheckDate = [NSDate dateWithTimeIntervalSinceNow:PASSCODE_CHECK_INTERVAL];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
153 154 155 156 157
    [[MLMediaLibrary sharedMediaLibrary] applicationWillExit];
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
158
    [[MLMediaLibrary sharedMediaLibrary] updateMediaDatabase];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
159 160 161
    [self updateMediaList];
}

162 163 164 165 166
- (void)applicationWillTerminate:(UIApplication *)application
{
    [[NSUserDefaults standardUserDefaults] synchronize];
}

Gleb Pinigin's avatar
Gleb Pinigin committed
167 168 169 170 171
#pragma mark - properties

- (VLCDropboxTableViewController *)dropboxTableViewController
{
    if (_dropboxTableViewController == nil) {
172
        _dropboxTableViewController = [[VLCDropboxTableViewController alloc] initWithNibName:nil bundle:nil];
Gleb Pinigin's avatar
Gleb Pinigin committed
173 174 175 176 177
    }

    return _dropboxTableViewController;
}

178 179 180 181 182 183 184 185 186
- (VLCDownloadViewController *)downloadViewController
{
    if (_downloadViewController == nil) {
        _downloadViewController = [[VLCDownloadViewController alloc] init];
    }

    return _downloadViewController;
}

Gleb Pinigin's avatar
Gleb Pinigin committed
187
#pragma mark - media discovering
188

Gleb Pinigin's avatar
Gleb Pinigin committed
189 190 191 192
- (void)mediaFileAdded:(NSString *)fileName loading:(BOOL)isLoading {
    if (!isLoading) {
        MLMediaLibrary *sharedLibrary = [MLMediaLibrary sharedMediaLibrary];
        [sharedLibrary addFilePaths:@[fileName]];
193

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

Gleb Pinigin's avatar
Gleb Pinigin committed
198 199
        // TODO Should we update media db after adding new files?
        [sharedLibrary updateMediaDatabase];
200
        [_playlistViewController updateViewContents];
201 202 203
    }
}

Gleb Pinigin's avatar
Gleb Pinigin committed
204 205 206 207 208
- (void)mediaFileDeleted:(NSString *)name {
    [[MLMediaLibrary sharedMediaLibrary] updateMediaDatabase];
    [_playlistViewController updateViewContents];
}

209 210 211
#pragma mark - media list methods

- (NSString *)directoryPath
Felix Paul Kühne's avatar
Felix Paul Kühne committed
212
{
213
#define LOCAL_PLAYBACK_HACK 0
Felix Paul Kühne's avatar
Felix Paul Kühne committed
214 215 216
#if LOCAL_PLAYBACK_HACK && TARGET_IPHONE_SIMULATOR
    NSString *directoryPath = @"/Users/fkuehne/Desktop/VideoLAN docs/Clips/sel/";
#else
217
    NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
Felix Paul Kühne's avatar
Felix Paul Kühne committed
218
    NSString *directoryPath = searchPaths[0];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
219
#endif
220 221 222 223 224 225 226

    return directoryPath;
}

- (void)updateMediaList
{
    NSString *directoryPath = [self directoryPath];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
227 228
    NSArray *foundFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directoryPath error:nil];
    NSMutableArray *filePaths = [NSMutableArray arrayWithCapacity:[foundFiles count]];
229
    NSURL *fileURL;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
230
    for (NSString *fileName in foundFiles) {
231
        if ([fileName isSupportedMediaFormat] || [fileName isSupportedAudioMediaFormat]) {
Felix Paul Kühne's avatar
Felix Paul Kühne committed
232
            [filePaths addObject:[directoryPath stringByAppendingPathComponent:fileName]];
233 234

            /* exclude media files from backup (QA1719) */
235
            fileURL = [NSURL fileURLWithPath:[directoryPath stringByAppendingPathComponent:fileName]];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
236
            [fileURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
237 238 239
        }
    }
    [[MLMediaLibrary sharedMediaLibrary] addFilePaths:filePaths];
240
    [_playlistViewController updateViewContents];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
241 242
}

243 244 245 246 247 248
#pragma mark - pass code validation

- (void)validatePasscode
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *passcode = [defaults objectForKey:kVLCSettingPasscodeKey];
249
    if ([passcode isEqualToString:@""] || ![[defaults objectForKey:kVLCSettingPasscodeOnKey] boolValue]) {
250 251 252
        self.passcodeValidated = YES;
        return;
    }
253

254 255 256 257 258 259 260 261 262 263 264 265 266
    if (!self.passcodeValidated) {
        if ([self.nextPasscodeCheckDate earlierDate:[NSDate date]] == self.nextPasscodeCheckDate) {
            _passcodeLockController = [[PAPasscodeViewController alloc] initForAction:PasscodeActionEnter];
            _passcodeLockController.delegate = self;
            _passcodeLockController.passcode = passcode;
            self.window.rootViewController = _passcodeLockController;
        } else
            self.passcodeValidated = YES;
    }
}

- (void)PAPasscodeViewControllerDidEnterPasscode:(PAPasscodeViewController *)controller
{
267
    // TODO add transition animation, i.e. fade
268
    self.nextPasscodeCheckDate = [NSDate dateWithTimeIntervalSinceNow:PASSCODE_CHECK_INTERVAL];
269
    self.window.rootViewController = self.revealController;
270 271 272 273 274 275 276
}

- (void)PAPasscodeViewController:(PAPasscodeViewController *)controller didFailToEnterPasscode:(NSInteger)attempts
{
    // TODO handle error attempts
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
#pragma mark - idle timer preventer
- (void)disableIdleTimer
{
    _idleCounter++;
    if ([UIApplication sharedApplication].idleTimerDisabled == NO)
        [UIApplication sharedApplication].idleTimerDisabled = YES;
}

- (void)activateIdleTimer
{
    _idleCounter--;
    if (_idleCounter < 1)
        [UIApplication sharedApplication].idleTimerDisabled = NO;
}

292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
#pragma mark - playback view handling

- (void)openMediaFromManagedObject:(NSManagedObject *)mediaObject
{
    if (!_movieViewController)
        _movieViewController = [[VLCMovieViewController alloc] initWithNibName:nil bundle:nil];

    if ([mediaObject isKindOfClass:[MLFile class]])
        _movieViewController.mediaItem = (MLFile *)mediaObject;
    else if ([mediaObject isKindOfClass:[MLAlbumTrack class]])
        _movieViewController.mediaItem = [(MLAlbumTrack*)mediaObject files].anyObject;
    else if ([mediaObject isKindOfClass:[MLShowEpisode class]])
        _movieViewController.mediaItem = [(MLShowEpisode*)mediaObject files].anyObject;

    UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:_movieViewController];
    navCon.modalPresentationStyle = UIModalPresentationFullScreen;
    [self.window.rootViewController presentViewController:navCon animated:YES completion:nil];
}

- (void)openMovieFromURL:(NSURL *)url
{
    if (!_movieViewController)
        _movieViewController = [[VLCMovieViewController alloc] initWithNibName:nil bundle:nil];

    _movieViewController.url = url;

    UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:_movieViewController];
    navCon.modalPresentationStyle = UIModalPresentationFullScreen;
    [self.window.rootViewController presentViewController:navCon animated:YES completion:nil];
}

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