VLCAppDelegate.m 10.3 KB
Newer Older
Felix Paul Kühne's avatar
Felix Paul Kühne committed
1 2 3 4 5 6 7 8 9
//
//  VLCAppDelegate.m
//  AspenProject
//
//  Created by Felix Paul Kühne on 27.02.13.
//  Copyright (c) 2013 VideoLAN. All rights reserved.
//

#import "VLCAppDelegate.h"
10
#import "DirectoryWatcher.h"
11
#import "NSString+SupportedMedia.h"
Felix Paul Kühne's avatar
Felix Paul Kühne committed
12 13

#import "VLCPlaylistViewController.h"
14
#import "VLCMovieViewController.h"
15 16
#import "PAPasscodeViewController.h"

17
@interface VLCAppDelegate () <PAPasscodeViewControllerDelegate, DirectoryWatcherDelegate> {
Gleb Pinigin's avatar
Gleb Pinigin committed
18 19
    NSURL *_tempURL;
    PAPasscodeViewController *_passcodeLockController;
Gleb Pinigin's avatar
Gleb Pinigin committed
20
    VLCDropboxTableViewController *_dropboxTableViewController;
21 22 23 24

    DirectoryWatcher *_directoryWatcher;
    NSTimer *_addMediaTimer;
    NSMutableDictionary *_addedFiles;
Gleb Pinigin's avatar
Gleb Pinigin committed
25
}
26 27 28 29

@property (nonatomic) BOOL passcodeValidated;

@end
Felix Paul Kühne's avatar
Felix Paul Kühne committed
30 31 32

@implementation VLCAppDelegate

33 34 35 36
+ (void)initialize
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

37
    NSDictionary *appDefaults = @{kVLCSettingPasscodeKey : @"", kVLCSettingPasscodeOnKey : @(NO), kVLCSettingContinueAudioInBackgroundKey : @(YES), kVLCSettingStretchAudio : @(NO), kVLCSettingTextEncoding : kVLCSettingTextEncodingDefaultValue};
38 39 40 41

    [defaults registerDefaults:appDefaults];
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
42 43
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
Felix Paul Kühne's avatar
Felix Paul Kühne committed
44
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
45

46
    _playlistViewController = [[VLCPlaylistViewController alloc] init];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
47

Felix Paul Kühne's avatar
Felix Paul Kühne committed
48
    self.navigationController = [[UINavigationController alloc] initWithRootViewController:_playlistViewController];
49 50
    UINavigationBar *navBar = self.navigationController.navigationBar;
    [navBar setBackgroundImage:[UIImage imageNamed:@"navBarBackground"] forBarMetrics:UIBarMetricsDefault];
51 52
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
        [navBar setBackgroundImage:[UIImage imageNamed:@"navBarBackgroundPhoneLandscape"] forBarMetrics:UIBarMetricsLandscapePhone];
53 54
    navBar.barStyle = UIBarStyleBlack;

55
    self.window.rootViewController = self.navigationController;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
56
    [self.window makeKeyAndVisible];
57

Gleb Pinigin's avatar
Gleb Pinigin committed
58
    _directoryWatcher = [DirectoryWatcher watchFolderWithPath:[self directoryPath] delegate:self];
59

60
    [self validatePasscode];
61

Felix Paul Kühne's avatar
Felix Paul Kühne committed
62 63 64
    return YES;
}

65 66
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
67 68 69 70 71
    if ([[DBSession sharedSession] handleOpenURL:url]) {
        [self.dropboxTableViewController updateViewAfterSessionChange];
        return YES;
    }

72 73
    if (_playlistViewController && url != nil) {
        APLog(@"%@ requested %@ to be opened", sourceApplication, url);
74

75
        if (url.isFileURL) {
76 77 78 79 80
            UIAlertView * alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"SAVE_FILE", @"") message:[NSString stringWithFormat:NSLocalizedString(@"SAVE_FILE_LONG", @""), url.lastPathComponent] delegate:self cancelButtonTitle:NSLocalizedString(@"BUTTON_CANCEL", @"") otherButtonTitles:NSLocalizedString(@"BUTTON_SAVE", @""), nil];
            _tempURL = url;
            [alert show];
        } else
            [_playlistViewController openMovieFromURL:url];
81 82 83 84 85
        return YES;
    }
    return NO;
}

86 87 88 89
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == 1) {
        NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
Felix Paul Kühne's avatar
Felix Paul Kühne committed
90
        NSString *directoryPath = searchPaths[0];
91
        NSURL *destinationURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", directoryPath, _tempURL.lastPathComponent]];
92 93
        NSError *theError;
        [[NSFileManager defaultManager] copyItemAtURL:_tempURL toURL:destinationURL error:&theError];
94 95
        if (theError.code != noErr)
            APLog(@"saving the file failed (%i): %@", theError.code, theError.localizedDescription);
96 97

        [self updateMediaList];
98 99
    } else
        [_playlistViewController openMovieFromURL:_tempURL];
100 101
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
102 103 104 105 106 107 108
- (void)applicationWillResignActive:(UIApplication *)application
{
    [[MLMediaLibrary sharedMediaLibrary] applicationWillExit];
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
109
    APLog(@"applicationWillEnterForeground: %i", self.passcodeValidated);
Felix Paul Kühne's avatar
Felix Paul Kühne committed
110 111 112 113 114 115 116
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [self updateMediaList];
}

117 118 119 120 121
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [self validatePasscode]; // Lock library when going to background
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
122 123 124 125 126
- (void)applicationWillTerminate:(UIApplication *)application
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

Gleb Pinigin's avatar
Gleb Pinigin committed
127 128 129 130 131
#pragma mark - properties

- (VLCDropboxTableViewController *)dropboxTableViewController
{
    if (_dropboxTableViewController == nil) {
132
        _dropboxTableViewController = [[VLCDropboxTableViewController alloc] initWithNibName:nil bundle:nil];
Gleb Pinigin's avatar
Gleb Pinigin committed
133 134 135 136 137
    }

    return _dropboxTableViewController;
}

138 139 140 141 142 143 144 145 146 147 148 149 150
#pragma mark - directory watcher delegate

- (void)addFileTimerFired
{
    NSArray *allKeys = [_addedFiles allKeys];
    for (NSString *fileURL in allKeys) {
        NSDictionary *attribs = [[NSFileManager defaultManager] attributesOfItemAtPath:fileURL error:nil];

        NSNumber *prevFetchedSize = [_addedFiles objectForKey:fileURL];
        NSNumber *updatedSize = [attribs objectForKey:NSFileSize];
        if ([prevFetchedSize compare:updatedSize] == NSOrderedSame) {
            [_addedFiles removeObjectForKey:fileURL];
            [[MLMediaLibrary sharedMediaLibrary] addFilePaths:@[fileURL]];
Gleb Pinigin's avatar
Gleb Pinigin committed
151

152 153 154
            /* exclude media files from backup (QA1719) */
            NSURL *excludeURL = [NSURL fileURLWithPath:fileURL];
            [excludeURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil];
Gleb Pinigin's avatar
Gleb Pinigin committed
155

156
            // TODO Should we update media db after adding new files?
Gleb Pinigin's avatar
Gleb Pinigin committed
157
            [[MLMediaLibrary sharedMediaLibrary] updateMediaDatabase];
158 159 160 161 162
            [_playlistViewController updateViewContents];
        } else {
            [_addedFiles setObject:updatedSize forKey:fileURL];
        }
    }
163

164 165 166 167 168 169 170 171 172 173 174
    if (_addedFiles.count == 0) {
        [_addMediaTimer invalidate];
        _addMediaTimer = nil;
    }
}

- (void)directoryDidChange:(DirectoryWatcher *)folderWatcher
{
    NSArray *foundFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self directoryPath] error:nil];
    NSMutableArray *matchedFiles = [NSMutableArray arrayWithCapacity:foundFiles.count];
    for (NSString *fileName in foundFiles) {
175
        if ([fileName isSupportedMediaFormat]) {
176 177 178 179 180 181
            [matchedFiles addObject:[[self directoryPath] stringByAppendingPathComponent:fileName]];
        }
    }

    NSArray *mediaFiles = [MLFile allFiles];
    if (mediaFiles.count > matchedFiles.count) { // File was deleted
182 183
        [[MLMediaLibrary sharedMediaLibrary] updateMediaDatabase];
        [_playlistViewController updateViewContents];
184 185

    } else if (mediaFiles.count < matchedFiles.count) { // File was added
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
        NSMutableArray *addedFiles = [NSMutableArray array];
        for (NSString *fileName in matchedFiles) {
            NSURL *fileURL = [NSURL fileURLWithPath:fileName];

            BOOL found = NO;
            for (MLFile *mediaFile in mediaFiles) {
                if ([mediaFile.url isEqualToString:fileURL.absoluteString]) {
                    found = YES;
                }
            }

            if (!found) {
                [addedFiles addObject:fileName];
            }
        }
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216

        _addedFiles = [NSMutableDictionary dictionaryWithCapacity:[addedFiles count]];
        for (NSString *fileURL in addedFiles) {
            [_addedFiles setObject:@(0) forKey:fileURL];
        }

        _addMediaTimer = [NSTimer scheduledTimerWithTimeInterval:2. target:self
                                                        selector:@selector(addFileTimerFired)
                                                        userInfo:nil repeats:YES];

    }
}

#pragma mark - media list methods

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

    return directoryPath;
}

- (void)updateMediaList
{
    NSString *directoryPath = [self directoryPath];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
232 233
    NSArray *foundFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directoryPath error:nil];
    NSMutableArray *filePaths = [NSMutableArray arrayWithCapacity:[foundFiles count]];
234
    NSURL *fileURL;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
235
    for (NSString *fileName in foundFiles) {
236
        if ([fileName isSupportedMediaFormat]) {
Felix Paul Kühne's avatar
Felix Paul Kühne committed
237
            [filePaths addObject:[directoryPath stringByAppendingPathComponent:fileName]];
238 239

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

248 249 250 251 252 253
#pragma mark - pass code validation

- (void)validatePasscode
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *passcode = [defaults objectForKey:kVLCSettingPasscodeKey];
254
    if ([passcode isEqualToString:@""] || ![[defaults objectForKey:kVLCSettingPasscodeOnKey] boolValue]) {
255 256 257
        self.passcodeValidated = YES;
        return;
    }
258

259 260 261 262 263 264 265 266 267 268 269 270 271
    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
{
272 273
    // TODO add transition animation, i.e. fade
    self.nextPasscodeCheckDate = [NSDate dateWithTimeIntervalSinceNow:300];
274 275 276 277 278 279 280 281
    self.window.rootViewController = self.navigationController;
}

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

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