瀏覽代碼

Replace passcode view controller with a nice one

Gleb Pinigin 12 年之前
父節點
當前提交
51658bd1c0

+ 5 - 1
AspenProject/VLCAppDelegate.h

@@ -7,11 +7,13 @@
 //
 
 #import <UIKit/UIKit.h>
-#import "VLCPlaylistViewController.h"
 
+@class VLCPlaylistViewController;
+@class PAPasscodeViewController;
 @interface VLCAppDelegate : UIResponder <UIApplicationDelegate>
 {
     NSURL *_tempURL;
+    PAPasscodeViewController *_passcodeLockController;
 }
 
 - (void)updateMediaList;
@@ -22,4 +24,6 @@
 
 @property (nonatomic, strong) UINavigationController *navigationController;
 
+@property (nonatomic, retain) NSDate *nextPasscodeCheckDate;
+
 @end

+ 52 - 8
AspenProject/VLCAppDelegate.m

@@ -9,8 +9,14 @@
 #import "VLCAppDelegate.h"
 
 #import "VLCPlaylistViewController.h"
-
 #import "VLCMovieViewController.h"
+#import "PAPasscodeViewController.h"
+
+@interface VLCAppDelegate () <PAPasscodeViewControllerDelegate>
+
+@property (nonatomic) BOOL passcodeValidated;
+
+@end
 
 @implementation VLCAppDelegate
 
@@ -77,13 +83,7 @@
 
 - (void)applicationWillEnterForeground:(UIApplication *)application
 {
-    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
-    if (![[defaults objectForKey:@"Passcode"] isEqualToString:@""])
-        self.playlistViewController.passcodeValidated = NO;
-    else
-        self.playlistViewController.passcodeValidated = YES;
-
-    NSLog(@"applicationWillEnterForeground: %i", self.playlistViewController.passcodeValidated);
+    NSLog(@"applicationWillEnterForeground: %i", self.passcodeValidated);
 }
 
 - (void)applicationDidBecomeActive:(UIApplication *)application
@@ -91,6 +91,11 @@
     [self updateMediaList];
 }
 
+- (void)applicationDidEnterBackground:(UIApplication *)application
+{
+    [self validatePasscode]; // Lock library when going to background
+}
+
 - (void)applicationWillTerminate:(UIApplication *)application
 {
     // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
@@ -121,4 +126,43 @@
     [_playlistViewController updateViewContents];
 }
 
+#pragma mark - pass code validation
+
+- (void)validatePasscode
+{
+    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+    NSString *passcode = [defaults objectForKey:kVLCSettingPasscodeKey];
+    if ([passcode isEqualToString:@""]) {
+        self.passcodeValidated = YES;
+        return;
+    }
+    
+    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)PAPasscodeViewControllerDidCancel:(PAPasscodeViewController *)controller
+{
+    // TODO remove cancel button for Enter action
+}
+
+- (void)PAPasscodeViewControllerDidEnterPasscode:(PAPasscodeViewController *)controller
+{
+    // TODO add transition animation
+    self.window.rootViewController = self.navigationController;
+}
+
+- (void)PAPasscodeViewController:(PAPasscodeViewController *)controller didFailToEnterPasscode:(NSInteger)attempts
+{
+    // TODO handle error attempts
+}
+
 @end

+ 0 - 25
AspenProject/VLCPasscodeLockViewController.h

@@ -1,25 +0,0 @@
-//
-//  VLCPasscodeLockViewController.h
-//  VLC for iOS
-//
-//  Created by Felix Paul Kühne on 18.05.13.
-//  Copyright (c) 2013 VideoLAN. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface VLCPasscodeLockViewController : UIViewController
-{
-    NSString *_passcode;
-    NSString *_tmpPasscode;
-
-    NSUInteger _resetStage;
-}
-
-@property (nonatomic, strong) IBOutlet UILabel *enterPasscodeLabel;
-@property (nonatomic, strong) IBOutlet UITextField *enterCodeField;
-
-- (IBAction)textFieldValueChanged:(id)sender;
-- (void)resetPasscode;
-
-@end

+ 0 - 84
AspenProject/VLCPasscodeLockViewController.m

@@ -1,84 +0,0 @@
-//
-//  VLCPasscodeLockViewController.m
-//  VLC for iOS
-//
-//  Created by Felix Paul Kühne on 18.05.13.
-//  Copyright (c) 2013 VideoLAN. All rights reserved.
-//
-
-#import "VLCPasscodeLockViewController.h"
-#import "VLCAppDelegate.h"
-#import "VLCPlaylistViewController.h"
-
-@implementation VLCPasscodeLockViewController
-
-- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
-{
-    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
-    return self;
-}
-
-- (void)viewDidLoad
-{
-    [super viewDidLoad];
-
-    self.enterCodeField.secureTextEntry = YES;
-}
-
-- (void)viewWillAppear:(BOOL)animated
-{
-    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
-    _passcode = [defaults objectForKey:@"Passcode"];
-
-    self.enterPasscodeLabel.text = NSLocalizedString(@"ENTER_PASSCODE", @"");
-
-    [self.navigationController setNavigationBarHidden:YES animated:NO];
-    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
-        [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleBlackTranslucent;
-    self.enterCodeField.text = @"";
-    [self.enterCodeField becomeFirstResponder];
-    [super viewWillAppear:animated];
-}
-
-- (void)viewWillDisappear:(BOOL)animated
-{
-    [self.navigationController setNavigationBarHidden:NO animated:YES];
-    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleBlackOpaque;
-    [super viewWillDisappear:animated];
-}
-
-- (IBAction)textFieldValueChanged:(id)sender
-{
-    if (self.enterCodeField.text.length == 4) {
-        VLCAppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
-        if (_resetStage == 1) {
-            _tmpPasscode = self.enterCodeField.text;
-            self.enterCodeField.text = @"";
-            self.enterPasscodeLabel.text = NSLocalizedString(@"REENTER_PASSCODE", @"");
-            _resetStage = 2;
-        } else if (_resetStage == 2) {
-            if ([self.enterCodeField.text isEqualToString:_tmpPasscode]) {
-                NSUserDefaults *defaults;
-                [defaults setObject:@1 forKey:@"PasscodeProtection"];
-                [defaults setObject:_tmpPasscode forKey:@"Passcode"];
-                [defaults synchronize];
-                _passcode = _tmpPasscode;
-                _resetStage = 0;
-                appDelegate.playlistViewController.nextPasscodeCheckDate = [NSDate dateWithTimeIntervalSinceNow:300]; // five min
-                appDelegate.playlistViewController.passcodeValidated = YES;
-                [self.view removeFromSuperview];
-            }
-        } else if ([self.enterCodeField.text isEqualToString:_passcode]) {
-            appDelegate.playlistViewController.nextPasscodeCheckDate = [NSDate dateWithTimeIntervalSinceNow:300]; // five min
-            appDelegate.playlistViewController.passcodeValidated = YES;
-            [self.navigationController popViewControllerAnimated:YES];
-        }
-    }
-}
-
-- (void)resetPasscode
-{
-    _resetStage = 1;
-}
-
-@end

+ 1 - 0
AspenProject/VLCPlaylistGridView.m

@@ -8,6 +8,7 @@
 
 #import "VLCPlaylistGridView.h"
 #import "VLCAppDelegate.h"
+#import "VLCPlaylistViewController.h"
 
 @interface VLCPlaylistGridView (Hack)
 @property (nonatomic, retain) NSString *reuseIdentifier;

+ 0 - 6
AspenProject/VLCPlaylistViewController.h

@@ -11,7 +11,6 @@
 
 @class VLCMovieViewController;
 @class VLCAboutViewController;
-@class VLCPasscodeLockViewController;
 @class VLCAddMediaViewController;
 
 @interface VLCPlaylistViewController : UIViewController <AQGridViewDataSource, AQGridViewDelegate, UITableViewDataSource, UITableViewDelegate, UITabBarDelegate, UIPopoverControllerDelegate>
@@ -19,12 +18,8 @@
     BOOL _editMode;
 }
 
-@property (nonatomic, retain) NSDate *nextPasscodeCheckDate;
-@property (nonatomic) BOOL passcodeValidated;
-
 @property (nonatomic, strong) VLCMovieViewController *movieViewController;
 @property (nonatomic, strong) VLCAboutViewController *aboutViewController;
-@property (nonatomic, strong) VLCPasscodeLockViewController *passcodeLockViewController;
 @property (nonatomic, strong) VLCAddMediaViewController *addMediaViewController;
 
 @property (nonatomic, strong) UIPopoverController *addMediaPopoverController;
@@ -38,7 +33,6 @@
 
 - (IBAction)leftButtonAction:(id)sender;
 
-- (void)validatePasscode;
 - (void)updateViewContents;
 - (void)openMovieFromURL:(NSURL *)url;
 - (void)removeMediaObject:(MLFile *)mediaObject;

+ 0 - 19
AspenProject/VLCPlaylistViewController.m

@@ -11,7 +11,6 @@
 #import "VLCPlaylistTableViewCell.h"
 #import "VLCPlaylistGridView.h"
 #import "VLCAboutViewController.h"
-#import "VLCPasscodeLockViewController.h"
 #import "VLCAddMediaViewController.h"
 
 @interface VLCPlaylistViewController () {
@@ -65,8 +64,6 @@
     self.emptyLibraryLongDescriptionLabel.numberOfLines = 0;
     self.emptyLibraryLongDescriptionLabel.text = NSLocalizedString(@"EMPTY_LIBRARY_LONG", @"");
     [self.emptyLibraryLongDescriptionLabel sizeToFit];
-
-    self.passcodeLockViewController = [[VLCPasscodeLockViewController alloc] initWithNibName:@"VLCPasscodeLockViewController" bundle:nil];
 }
 
 - (void)viewWillAppear:(BOOL)animated
@@ -84,7 +81,6 @@
 
 - (void)viewDidAppear:(BOOL)animated
 {
-    [self validatePasscode];
     if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
         self.tableView.hidden = NO;
     else
@@ -123,21 +119,6 @@
     }
 }
 
-- (void)validatePasscode
-{
-    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
-    if ([[defaults objectForKey:@"Passcode"] isEqualToString:@""]) {
-        self.passcodeValidated = YES;
-        return;
-    }
-
-    if (!self.passcodeValidated) {
-        if ([self.nextPasscodeCheckDate earlierDate:[NSDate date]] == self.nextPasscodeCheckDate)
-            [self.navigationController pushViewController:self.passcodeLockViewController animated:YES];
-        else
-            self.passcodeValidated = YES;
-    }
-}
 
 - (void)updateViewContents
 {

+ 25 - 10
AspenProject/VLCSettingsViewController.m

@@ -8,10 +8,10 @@
 
 #import "VLCSettingsViewController.h"
 #import "VLCPlaylistViewController.h"
-#import "VLCPasscodeLockViewController.h"
+#import "PAPasscodeViewController.h"
 #import "VLCAppDelegate.h"
 
-@interface VLCSettingsViewController ()
+@interface VLCSettingsViewController () <PAPasscodeViewControllerDelegate>
 {
     NSArray *_userFacingTextEncodingNames;
     NSArray *_textEncodingNames;
@@ -67,14 +67,9 @@
 
     if (sender == self.passcodeLockSwitch) {
         if (self.passcodeLockSwitch.on) {
-            VLCAppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
-            if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
-                CGRect frame = self.view.frame;
-                frame.size.height -= 44.;
-                appDelegate.playlistViewController.passcodeLockViewController.view.frame = frame;
-            }
-            [self.view addSubview:appDelegate.playlistViewController.passcodeLockViewController.view];
-            [appDelegate.playlistViewController.passcodeLockViewController resetPasscode];
+            PAPasscodeViewController *passcodeLockController = [[PAPasscodeViewController alloc] initForAction:PasscodeActionSet];
+            passcodeLockController.delegate = self;
+            [self presentModalViewController:passcodeLockController animated:YES];
         } else {
             [defaults setObject:@0 forKey:kVLCSettingPasscodeOnKey];
         }
@@ -125,4 +120,24 @@
     return _textEncodingNames.count;
 }
 
+#pragma mark - PAPasscode delegate
+
+- (void)PAPasscodeViewControllerDidCancel:(PAPasscodeViewController *)controller
+{
+    self.passcodeLockSwitch.on = NO;
+    [controller dismissModalViewControllerAnimated:YES];
+}
+
+- (void)PAPasscodeViewControllerDidSetPasscode:(PAPasscodeViewController *)controller
+{
+    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+    [defaults setObject:@(1) forKey:kVLCSettingPasscodeOnKey];
+    [defaults setObject:controller.passcode forKey:kVLCSettingPasscodeKey];
+    [defaults synchronize];
+    VLCAppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
+    appDelegate.nextPasscodeCheckDate = [NSDate dateWithTimeIntervalSinceNow:300];
+    
+    [controller dismissModalViewControllerAnimated:YES];
+}
+
 @end

二進制
PAPasscode/Assets/papasscode_background.png


二進制
PAPasscode/Assets/papasscode_background@2x.png


二進制
PAPasscode/Assets/papasscode_failed_bg.png


二進制
PAPasscode/Assets/papasscode_failed_bg@2x.png


二進制
PAPasscode/Assets/papasscode_marker.png


二進制
PAPasscode/Assets/papasscode_marker@2x.png


+ 58 - 0
PAPasscode/PAPasscodeViewController.h

@@ -0,0 +1,58 @@
+//
+//  PAPasscodeViewController.h
+//  PAPasscode
+//
+//  Created by Denis Hennessy on 15/10/2012.
+//  Copyright (c) 2012 Peer Assembly. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef enum {
+    PasscodeActionSet,
+    PasscodeActionEnter,
+    PasscodeActionChange
+} PasscodeAction;
+
+@class PAPasscodeViewController;
+
+@protocol PAPasscodeViewControllerDelegate <NSObject>
+
+@optional
+
+- (void)PAPasscodeViewControllerDidCancel:(PAPasscodeViewController *)controller;
+- (void)PAPasscodeViewControllerDidChangePasscode:(PAPasscodeViewController *)controller;
+- (void)PAPasscodeViewControllerDidEnterAlternativePasscode:(PAPasscodeViewController *)controller;
+- (void)PAPasscodeViewControllerDidEnterPasscode:(PAPasscodeViewController *)controller;
+- (void)PAPasscodeViewControllerDidSetPasscode:(PAPasscodeViewController *)controller;
+- (void)PAPasscodeViewController:(PAPasscodeViewController *)controller didFailToEnterPasscode:(NSInteger)attempts;
+
+@end
+
+@interface PAPasscodeViewController : UIViewController {
+    UIView *contentView;
+    NSInteger phase;
+    UILabel *promptLabel;
+    UILabel *messageLabel;
+    UIImageView *failedImageView;
+    UILabel *failedAttemptsLabel;
+    UITextField *passcodeTextField;
+    UIImageView *digitImageViews[4];
+    UIImageView *snapshotImageView;
+}
+
+@property (strong) UIView *backgroundView;
+@property (readonly) PasscodeAction action;
+@property (weak) id<PAPasscodeViewControllerDelegate> delegate;
+@property (strong) NSString *alternativePasscode;
+@property (strong) NSString *passcode;
+@property (assign) BOOL simple;
+@property (assign) NSInteger failedAttempts;
+@property (strong) NSString *enterPrompt;
+@property (strong) NSString *confirmPrompt;
+@property (strong) NSString *changePrompt;
+@property (strong) NSString *message;
+
+- (id)initForAction:(PasscodeAction)action;
+
+@end

+ 387 - 0
PAPasscode/PAPasscodeViewController.m

@@ -0,0 +1,387 @@
+//
+//  PAPasscodeViewController.m
+//  PAPasscode
+//
+//  Created by Denis Hennessy on 15/10/2012.
+//  Copyright (c) 2012 Peer Assembly. All rights reserved.
+//
+
+#import <QuartzCore/QuartzCore.h>
+#import "PAPasscodeViewController.h"
+
+#define NAVBAR_HEIGHT   44
+#define PROMPT_HEIGHT   74
+#define DIGIT_SPACING   10
+#define DIGIT_WIDTH     61
+#define DIGIT_HEIGHT    53
+#define MARKER_WIDTH    16
+#define MARKER_HEIGHT   16
+#define MARKER_X        22
+#define MARKER_Y        18
+#define MESSAGE_HEIGHT  74
+#define FAILED_LCAP     19
+#define FAILED_RCAP     19
+#define FAILED_HEIGHT   26
+#define FAILED_MARGIN   10
+#define TEXTFIELD_MARGIN 8
+#define SLIDE_DURATION  0.3
+
+@interface PAPasscodeViewController ()
+- (void)cancel:(id)sender;
+- (void)handleFailedAttempt;
+- (void)handleCompleteField;
+- (void)passcodeChanged:(id)sender;
+- (void)resetFailedAttempts;
+- (void)showFailedAttempts;
+- (void)showScreenForPhase:(NSInteger)phase animated:(BOOL)animated;
+@end
+
+@implementation PAPasscodeViewController
+
+- (id)initForAction:(PasscodeAction)action {
+    self = [super init];
+    if (self) {
+        _action = action;
+        switch (action) {
+            case PasscodeActionSet:
+                self.title = NSLocalizedString(@"Set Passcode", nil);
+                _enterPrompt = NSLocalizedString(@"Enter a passcode", nil);
+                _confirmPrompt = NSLocalizedString(@"Re-enter your passcode", nil);
+                break;
+                
+            case PasscodeActionEnter:
+                self.title = NSLocalizedString(@"Enter Passcode", nil);
+                _enterPrompt = NSLocalizedString(@"Enter your passcode", nil);
+                break;
+                
+            case PasscodeActionChange:
+                self.title = NSLocalizedString(@"Change Passcode", nil);
+                _changePrompt = NSLocalizedString(@"Enter your old passcode", nil);
+                _enterPrompt = NSLocalizedString(@"Enter your new passcode", nil);
+                _confirmPrompt = NSLocalizedString(@"Re-enter your new passcode", nil);
+                break;
+        }
+        self.modalPresentationStyle = UIModalPresentationFormSheet;
+        _simple = YES;
+    }
+    return self;
+}
+
+- (void)loadView {
+    UIView *view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
+    view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
+
+    UINavigationBar *navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, view.bounds.size.width, NAVBAR_HEIGHT)];
+    navigationBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
+    navigationBar.items = @[self.navigationItem];
+    [view addSubview:navigationBar];
+    
+    contentView = [[UIView alloc] initWithFrame:CGRectMake(0, NAVBAR_HEIGHT, view.bounds.size.width, view.bounds.size.height-NAVBAR_HEIGHT)];
+    contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
+    if (_backgroundView) {
+        [contentView addSubview:_backgroundView];
+    }
+    contentView.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
+    [view addSubview:contentView];
+    
+    CGFloat panelWidth = DIGIT_WIDTH*4+DIGIT_SPACING*3;
+    if (_simple) {
+        UIView *digitPanel = [[UIView alloc] initWithFrame:CGRectMake(0, 0, panelWidth, DIGIT_HEIGHT)];
+        digitPanel.frame = CGRectOffset(digitPanel.frame, (contentView.bounds.size.width-digitPanel.bounds.size.width)/2, PROMPT_HEIGHT);
+        digitPanel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin;
+        [contentView addSubview:digitPanel];
+        
+        UIImage *backgroundImage = [UIImage imageNamed:@"papasscode_background"];
+        UIImage *markerImage = [UIImage imageNamed:@"papasscode_marker"];
+        CGFloat xLeft = 0;
+        for (int i=0;i<4;i++) {
+            UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:backgroundImage];
+            backgroundImageView.frame = CGRectOffset(backgroundImageView.frame, xLeft, 0);
+            [digitPanel addSubview:backgroundImageView];
+            digitImageViews[i] = [[UIImageView alloc] initWithImage:markerImage];
+            digitImageViews[i].autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin;
+            digitImageViews[i].frame = CGRectOffset(digitImageViews[i].frame, backgroundImageView.frame.origin.x+MARKER_X, MARKER_Y);
+            [digitPanel addSubview:digitImageViews[i]];
+            xLeft += DIGIT_SPACING + backgroundImage.size.width;
+        }
+        passcodeTextField = [[UITextField alloc] initWithFrame:digitPanel.frame];
+        passcodeTextField.hidden = YES;
+    } else {
+        UIView *passcodePanel = [[UIView alloc] initWithFrame:CGRectMake(0, 0, panelWidth, DIGIT_HEIGHT)];
+        passcodePanel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin;
+        passcodePanel.frame = CGRectOffset(passcodePanel.frame, (contentView.bounds.size.width-passcodePanel.bounds.size.width)/2, PROMPT_HEIGHT);
+        passcodePanel.frame = CGRectInset(passcodePanel.frame, TEXTFIELD_MARGIN, TEXTFIELD_MARGIN);
+        passcodePanel.layer.borderColor = [UIColor colorWithRed:0.65 green:0.67 blue:0.70 alpha:1.0].CGColor;
+        passcodePanel.layer.borderWidth = 1.0;
+        passcodePanel.layer.cornerRadius = 5.0;
+        passcodePanel.layer.shadowColor = [UIColor whiteColor].CGColor;
+        passcodePanel.layer.shadowOffset = CGSizeMake(0, 1);
+        passcodePanel.layer.shadowOpacity = 1.0;
+        passcodePanel.layer.shadowRadius = 1.0;
+        passcodePanel.backgroundColor = [UIColor whiteColor];
+        [contentView addSubview:passcodePanel];
+        passcodeTextField = [[UITextField alloc] initWithFrame:CGRectInset(passcodePanel.frame, 6, 6)];
+    }
+    passcodeTextField.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin;
+    passcodeTextField.borderStyle = UITextBorderStyleNone;
+    passcodeTextField.secureTextEntry = YES;
+    passcodeTextField.textColor = [UIColor colorWithRed:0.23 green:0.33 blue:0.52 alpha:1.0];
+    passcodeTextField.keyboardType = UIKeyboardTypeNumberPad;
+    [passcodeTextField addTarget:self action:@selector(passcodeChanged:) forControlEvents:UIControlEventEditingChanged];
+    [contentView addSubview:passcodeTextField];
+
+    promptLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, contentView.bounds.size.width, PROMPT_HEIGHT)];
+    promptLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
+    promptLabel.backgroundColor = [UIColor clearColor];
+    promptLabel.textColor = [UIColor colorWithRed:0.30 green:0.34 blue:0.42 alpha:1.0];
+    promptLabel.font = [UIFont boldSystemFontOfSize:17];
+    promptLabel.shadowColor = [UIColor whiteColor];
+    promptLabel.shadowOffset = CGSizeMake(0, 1);
+    promptLabel.textAlignment = UITextAlignmentCenter;
+    promptLabel.numberOfLines = 0;
+    [contentView addSubview:promptLabel];
+    
+    messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, PROMPT_HEIGHT+DIGIT_HEIGHT, contentView.bounds.size.width, MESSAGE_HEIGHT)];
+    messageLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
+    messageLabel.backgroundColor = [UIColor clearColor];
+    messageLabel.textColor = [UIColor colorWithRed:0.30 green:0.34 blue:0.42 alpha:1.0];
+    messageLabel.font = [UIFont systemFontOfSize:14];
+    messageLabel.shadowColor = [UIColor whiteColor];
+    messageLabel.shadowOffset = CGSizeMake(0, 1);
+    messageLabel.textAlignment = UITextAlignmentCenter;
+    messageLabel.numberOfLines = 0;
+	messageLabel.text = _message;
+    [contentView addSubview:messageLabel];
+        
+    UIImage *failedBg = [[UIImage imageNamed:@"papasscode_failed_bg"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, FAILED_LCAP, 0, FAILED_RCAP)];
+    failedImageView = [[UIImageView alloc] initWithImage:failedBg];
+    failedImageView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin;
+    failedImageView.hidden = YES;
+    [contentView addSubview:failedImageView];
+    
+    failedAttemptsLabel = [[UILabel alloc] initWithFrame:CGRectZero];
+    failedAttemptsLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin;
+    failedAttemptsLabel.backgroundColor = [UIColor clearColor];
+    failedAttemptsLabel.textColor = [UIColor whiteColor];
+    failedAttemptsLabel.font = [UIFont boldSystemFontOfSize:15];
+    failedAttemptsLabel.shadowColor = [UIColor blackColor];
+    failedAttemptsLabel.shadowOffset = CGSizeMake(0, -1);
+    failedAttemptsLabel.textAlignment = UITextAlignmentCenter;
+    failedAttemptsLabel.hidden = YES;
+    [contentView addSubview:failedAttemptsLabel];
+    
+    self.view = view;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    if ([_delegate respondsToSelector:@selector(PAPasscodeViewControllerDidCancel:)]) {
+        if (_simple) {
+            self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel:)];
+        } else {
+            self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel:)];
+        }
+    }
+    
+    if (_failedAttempts > 0) {
+        [self showFailedAttempts];
+    }
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    [self showScreenForPhase:0 animated:NO];
+    [passcodeTextField becomeFirstResponder];
+}
+
+- (NSUInteger)supportedInterfaceOrientations {
+    return UIInterfaceOrientationMaskPortrait|UIInterfaceOrientationMaskPortraitUpsideDown;
+}
+
+- (void)cancel:(id)sender {
+    [_delegate PAPasscodeViewControllerDidCancel:self];
+}
+
+#pragma mark - implementation helpers
+
+- (void)handleCompleteField {
+    NSString *text = passcodeTextField.text;
+    switch (_action) {
+        case PasscodeActionSet:
+            if (phase == 0) {
+                _passcode = text;
+                messageLabel.text = @"";
+                [self showScreenForPhase:1 animated:YES];
+            } else {
+                if ([text isEqualToString:_passcode]) {
+                    if ([_delegate respondsToSelector:@selector(PAPasscodeViewControllerDidSetPasscode:)]) {
+                        [_delegate PAPasscodeViewControllerDidSetPasscode:self];
+                    }
+                } else {
+                    [self showScreenForPhase:0 animated:YES];
+                    messageLabel.text = NSLocalizedString(@"Passcodes did not match. Try again.", nil);
+                }
+            }
+            break;
+            
+        case PasscodeActionEnter:
+            if ([text isEqualToString:_passcode]) {
+                [self resetFailedAttempts];
+                if ([_delegate respondsToSelector:@selector(PAPasscodeViewControllerDidEnterPasscode:)]) {
+                    [_delegate PAPasscodeViewControllerDidEnterPasscode:self];
+                }
+            } else {
+                if (_alternativePasscode && [text isEqualToString:_alternativePasscode]) {
+                    [self resetFailedAttempts];
+                    if ([_delegate respondsToSelector:@selector(PAPasscodeViewControllerDidEnterAlternativePasscode:)]) {
+                        [_delegate PAPasscodeViewControllerDidEnterAlternativePasscode:self];
+                    }
+                } else {
+                    [self handleFailedAttempt];
+                    [self showScreenForPhase:0 animated:NO];
+                }
+            }
+            break;
+            
+        case PasscodeActionChange:
+            if (phase == 0) {
+                if ([text isEqualToString:_passcode]) {
+                    [self resetFailedAttempts];
+                    [self showScreenForPhase:1 animated:YES];
+                } else {
+                    [self handleFailedAttempt];
+                    [self showScreenForPhase:0 animated:NO];
+                }
+            } else if (phase == 1) {
+                _passcode = text;
+                messageLabel.text = @"";
+                [self showScreenForPhase:2 animated:YES];
+            } else {
+                if ([text isEqualToString:_passcode]) {
+                    if ([_delegate respondsToSelector:@selector(PAPasscodeViewControllerDidChangePasscode:)]) {
+                        [_delegate PAPasscodeViewControllerDidChangePasscode:self];
+                    }
+                } else {
+                    [self showScreenForPhase:1 animated:YES];
+                    messageLabel.text = NSLocalizedString(@"Passcodes did not match. Try again.", nil);
+                }
+            }
+            break;
+    }
+}
+
+- (void)handleFailedAttempt {
+    _failedAttempts++;
+    [self showFailedAttempts];
+    if ([_delegate respondsToSelector:@selector(PAPasscodeViewController:didFailToEnterPasscode:)]) {
+        [_delegate PAPasscodeViewController:self didFailToEnterPasscode:_failedAttempts];
+    }
+}
+
+- (void)resetFailedAttempts {
+    messageLabel.hidden = NO;
+    failedImageView.hidden = YES;
+    failedAttemptsLabel.hidden = YES;
+    _failedAttempts = 0;
+}
+
+- (void)showFailedAttempts {
+    messageLabel.hidden = YES;
+    failedImageView.hidden = NO;
+    failedAttemptsLabel.hidden = NO;
+    if (_failedAttempts == 1) {
+        failedAttemptsLabel.text = NSLocalizedString(@"1 Failed Passcode Attempt", nil);
+    } else {
+        failedAttemptsLabel.text = [NSString stringWithFormat:NSLocalizedString(@"%d Failed Passcode Attempts", nil), _failedAttempts];
+    }
+    [failedAttemptsLabel sizeToFit];
+    CGFloat bgWidth = failedAttemptsLabel.bounds.size.width + FAILED_MARGIN*2;
+    CGFloat x = floor((contentView.bounds.size.width-bgWidth)/2);
+    CGFloat y = PROMPT_HEIGHT+DIGIT_HEIGHT+floor((MESSAGE_HEIGHT-FAILED_HEIGHT)/2);
+    failedImageView.frame = CGRectMake(x, y, bgWidth, FAILED_HEIGHT);
+    x = failedImageView.frame.origin.x+FAILED_MARGIN;
+    y = failedImageView.frame.origin.y+floor((failedImageView.bounds.size.height-failedAttemptsLabel.frame.size.height)/2);
+    failedAttemptsLabel.frame = CGRectMake(x, y, failedAttemptsLabel.bounds.size.width, failedAttemptsLabel.bounds.size.height);
+}
+
+- (void)passcodeChanged:(id)sender {
+    NSString *text = passcodeTextField.text;
+    if (_simple) {
+        if ([text length] > 4) {
+            text = [text substringToIndex:4];
+        }
+        for (int i=0;i<4;i++) {
+            digitImageViews[i].hidden = i >= [text length];
+        }
+        if ([text length] == 4) {
+            [self handleCompleteField];
+        }
+    } else {
+        self.navigationItem.rightBarButtonItem.enabled = [text length] > 0;
+    }
+}
+
+- (void)showScreenForPhase:(NSInteger)newPhase animated:(BOOL)animated {
+    CGFloat dir = (newPhase > phase) ? 1 : -1;
+    if (animated) {
+        UIGraphicsBeginImageContext(self.view.bounds.size);
+        [contentView.layer renderInContext:UIGraphicsGetCurrentContext()];
+        UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
+        UIGraphicsEndImageContext();
+        snapshotImageView = [[UIImageView alloc] initWithImage:snapshot];
+        snapshotImageView.frame = CGRectOffset(snapshotImageView.frame, -contentView.frame.size.width*dir, 0);
+        [contentView addSubview:snapshotImageView];
+    }
+    phase = newPhase;
+    passcodeTextField.text = @"";
+    if (!_simple) {
+        BOOL finalScreen = _action == PasscodeActionSet && phase == 1;
+        finalScreen |= _action == PasscodeActionEnter && phase == 0;
+        finalScreen |= _action == PasscodeActionChange && phase == 2;
+        if (finalScreen) {
+            self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(handleCompleteField)];
+        } else {
+            self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Next", nil) style:UIBarButtonItemStyleBordered target:self action:@selector(handleCompleteField)];
+        }
+        self.navigationItem.rightBarButtonItem.enabled = NO;
+    }
+    
+    switch (_action) {
+        case PasscodeActionSet:
+            if (phase == 0) {
+                promptLabel.text = _enterPrompt;
+            } else {
+                promptLabel.text = _confirmPrompt;
+            }
+            break;
+            
+        case PasscodeActionEnter:
+            promptLabel.text = _enterPrompt;
+            break;
+            
+        case PasscodeActionChange:
+            if (phase == 0) {
+                promptLabel.text = _changePrompt;
+            } else if (phase == 1) {
+                promptLabel.text = _enterPrompt;
+            } else {
+                promptLabel.text = _confirmPrompt;
+            }
+            break;
+    }
+    for (int i=0;i<4;i++) {
+        digitImageViews[i].hidden = YES;
+    }
+    if (animated) {
+        contentView.frame = CGRectOffset(contentView.frame, contentView.frame.size.width*dir, 0);
+        [UIView animateWithDuration:SLIDE_DURATION animations:^() {
+            contentView.frame = CGRectOffset(contentView.frame, -contentView.frame.size.width*dir, 0);
+        } completion:^(BOOL finished) {
+            [snapshotImageView removeFromSuperview];
+            snapshotImageView = nil;
+        }];
+    }
+}
+
+@end

+ 0 - 323
Resources/VLCPasscodeLockViewController.xib

@@ -1,323 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
-	<data>
-		<int key="IBDocument.SystemTarget">1296</int>
-		<string key="IBDocument.SystemVersion">12E52</string>
-		<string key="IBDocument.InterfaceBuilderVersion">3084</string>
-		<string key="IBDocument.AppKitVersion">1187.39</string>
-		<string key="IBDocument.HIToolboxVersion">626.00</string>
-		<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
-			<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-			<string key="NS.object.0">2083</string>
-		</object>
-		<array key="IBDocument.IntegratedClassDependencies">
-			<string>IBProxyObject</string>
-			<string>IBUIImageView</string>
-			<string>IBUILabel</string>
-			<string>IBUITextField</string>
-			<string>IBUIView</string>
-		</array>
-		<array key="IBDocument.PluginDependencies">
-			<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-		</array>
-		<object class="NSMutableDictionary" key="IBDocument.Metadata">
-			<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
-			<integer value="1" key="NS.object.0"/>
-		</object>
-		<array class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
-			<object class="IBProxyObject" id="372490531">
-				<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
-				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-			</object>
-			<object class="IBProxyObject" id="975951072">
-				<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
-				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-			</object>
-			<object class="IBUIView" id="191373211">
-				<reference key="NSNextResponder"/>
-				<int key="NSvFlags">274</int>
-				<array class="NSMutableArray" key="NSSubviews">
-					<object class="IBUIImageView" id="622847797">
-						<reference key="NSNextResponder" ref="191373211"/>
-						<int key="NSvFlags">293</int>
-						<string key="NSFrame">{{96, 20}, {128, 128}}</string>
-						<reference key="NSSuperview" ref="191373211"/>
-						<reference key="NSWindow"/>
-						<reference key="NSNextKeyView" ref="186196614"/>
-						<string key="NSReuseIdentifierKey">_NS:9</string>
-						<bool key="IBUIUserInteractionEnabled">NO</bool>
-						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-						<object class="NSCustomResource" key="IBUIImage">
-							<string key="NSClassName">NSImage</string>
-							<string key="NSResourceName">Aspen.png</string>
-						</object>
-					</object>
-					<object class="IBUILabel" id="186196614">
-						<reference key="NSNextResponder" ref="191373211"/>
-						<int key="NSvFlags">293</int>
-						<string key="NSFrame">{{20, 152}, {280, 21}}</string>
-						<reference key="NSSuperview" ref="191373211"/>
-						<reference key="NSWindow"/>
-						<reference key="NSNextKeyView" ref="39256385"/>
-						<string key="NSReuseIdentifierKey">_NS:9</string>
-						<bool key="IBUIOpaque">NO</bool>
-						<bool key="IBUIClipsSubviews">YES</bool>
-						<int key="IBUIContentMode">7</int>
-						<bool key="IBUIUserInteractionEnabled">NO</bool>
-						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-						<string key="IBUIText">Enter Passcode</string>
-						<object class="NSColor" key="IBUITextColor" id="623215458">
-							<int key="NSColorSpace">3</int>
-							<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
-						</object>
-						<nil key="IBUIHighlightedColor"/>
-						<int key="IBUIBaselineAdjustment">0</int>
-						<int key="IBUITextAlignment">1</int>
-						<object class="IBUIFontDescription" key="IBUIFontDescription" id="257375468">
-							<int key="type">2</int>
-							<double key="pointSize">17</double>
-						</object>
-						<object class="NSFont" key="IBUIFont" id="429128832">
-							<string key="NSName">Helvetica-Bold</string>
-							<double key="NSSize">17</double>
-							<int key="NSfFlags">16</int>
-						</object>
-						<bool key="IBUIAdjustsFontSizeToFit">NO</bool>
-					</object>
-					<object class="IBUITextField" id="39256385">
-						<reference key="NSNextResponder" ref="191373211"/>
-						<int key="NSvFlags">293</int>
-						<string key="NSFrame">{{80, 191}, {161, 30}}</string>
-						<reference key="NSSuperview" ref="191373211"/>
-						<reference key="NSWindow"/>
-						<reference key="NSNextKeyView"/>
-						<string key="NSReuseIdentifierKey">_NS:9</string>
-						<object class="NSColor" key="IBUIBackgroundColor">
-							<int key="NSColorSpace">3</int>
-							<bytes key="NSWhite">MC4zMzMzMzMzMzMzAA</bytes>
-						</object>
-						<bool key="IBUIOpaque">NO</bool>
-						<bool key="IBUIClipsSubviews">YES</bool>
-						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-						<int key="IBUIContentHorizontalAlignment">0</int>
-						<int key="IBUIContentVerticalAlignment">0</int>
-						<string key="IBUIText"/>
-						<int key="IBUIBorderStyle">3</int>
-						<reference key="IBUITextColor" ref="623215458"/>
-						<int key="IBUITextAlignment">1</int>
-						<float key="IBUIMinimumFontSize">17</float>
-						<object class="IBUITextInputTraits" key="IBUITextInputTraits">
-							<int key="IBUIAutocorrectionType">1</int>
-							<int key="IBUIKeyboardType">4</int>
-							<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-						</object>
-						<reference key="IBUIFontDescription" ref="257375468"/>
-						<reference key="IBUIFont" ref="429128832"/>
-					</object>
-				</array>
-				<string key="NSFrame">{{0, 20}, {320, 548}}</string>
-				<reference key="NSSuperview"/>
-				<reference key="NSWindow"/>
-				<reference key="NSNextKeyView" ref="622847797"/>
-				<object class="NSColor" key="IBUIBackgroundColor">
-					<int key="NSColorSpace">3</int>
-					<bytes key="NSWhite">MAA</bytes>
-				</object>
-				<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
-				<object class="IBUIScreenMetrics" key="IBUISimulatedDestinationMetrics">
-					<string key="IBUISimulatedSizeMetricsClass">IBUIScreenMetrics</string>
-					<object class="NSMutableDictionary" key="IBUINormalizedOrientationToSizeMap">
-						<bool key="EncodedWithXMLCoder">YES</bool>
-						<array key="dict.sortedKeys">
-							<integer value="1"/>
-							<integer value="3"/>
-						</array>
-						<array key="dict.values">
-							<string>{320, 568}</string>
-							<string>{568, 320}</string>
-						</array>
-					</object>
-					<string key="IBUITargetRuntime">IBCocoaTouchFramework</string>
-					<string key="IBUIDisplayName">Retina 4 Full Screen</string>
-					<int key="IBUIType">2</int>
-				</object>
-				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-			</object>
-		</array>
-		<object class="IBObjectContainer" key="IBDocument.Objects">
-			<array class="NSMutableArray" key="connectionRecords">
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchOutletConnection" key="connection">
-						<string key="label">view</string>
-						<reference key="source" ref="372490531"/>
-						<reference key="destination" ref="191373211"/>
-					</object>
-					<int key="connectionID">3</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchOutletConnection" key="connection">
-						<string key="label">enterCodeField</string>
-						<reference key="source" ref="372490531"/>
-						<reference key="destination" ref="39256385"/>
-					</object>
-					<int key="connectionID">32</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchOutletConnection" key="connection">
-						<string key="label">enterPasscodeLabel</string>
-						<reference key="source" ref="372490531"/>
-						<reference key="destination" ref="186196614"/>
-					</object>
-					<int key="connectionID">36</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchEventConnection" key="connection">
-						<string key="label">textFieldValueChanged:</string>
-						<reference key="source" ref="39256385"/>
-						<reference key="destination" ref="372490531"/>
-						<int key="IBEventType">13</int>
-					</object>
-					<int key="connectionID">31</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchEventConnection" key="connection">
-						<string key="label">textFieldValueChanged:</string>
-						<reference key="source" ref="39256385"/>
-						<reference key="destination" ref="372490531"/>
-						<int key="IBEventType">18</int>
-					</object>
-					<int key="connectionID">33</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchEventConnection" key="connection">
-						<string key="label">textFieldValueChanged:</string>
-						<reference key="source" ref="39256385"/>
-						<reference key="destination" ref="372490531"/>
-						<int key="IBEventType">17</int>
-					</object>
-					<int key="connectionID">34</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchEventConnection" key="connection">
-						<string key="label">textFieldValueChanged:</string>
-						<reference key="source" ref="39256385"/>
-						<reference key="destination" ref="372490531"/>
-						<int key="IBEventType">19</int>
-					</object>
-					<int key="connectionID">35</int>
-				</object>
-			</array>
-			<object class="IBMutableOrderedSet" key="objectRecords">
-				<array key="orderedObjects">
-					<object class="IBObjectRecord">
-						<int key="objectID">0</int>
-						<array key="object" id="0"/>
-						<reference key="children" ref="1000"/>
-						<nil key="parent"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1</int>
-						<reference key="object" ref="191373211"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="622847797"/>
-							<reference ref="186196614"/>
-							<reference ref="39256385"/>
-						</array>
-						<reference key="parent" ref="0"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">-1</int>
-						<reference key="object" ref="372490531"/>
-						<reference key="parent" ref="0"/>
-						<string key="objectName">File's Owner</string>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">-2</int>
-						<reference key="object" ref="975951072"/>
-						<reference key="parent" ref="0"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">18</int>
-						<reference key="object" ref="622847797"/>
-						<reference key="parent" ref="191373211"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">19</int>
-						<reference key="object" ref="186196614"/>
-						<reference key="parent" ref="191373211"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">20</int>
-						<reference key="object" ref="39256385"/>
-						<reference key="parent" ref="191373211"/>
-					</object>
-				</array>
-			</object>
-			<dictionary class="NSMutableDictionary" key="flattenedProperties">
-				<string key="-1.CustomClassName">VLCPasscodeLockViewController</string>
-				<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-				<string key="-2.CustomClassName">UIResponder</string>
-				<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-				<string key="1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-				<string key="18.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-				<string key="19.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-				<string key="20.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-			</dictionary>
-			<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
-			<nil key="activeLocalization"/>
-			<dictionary class="NSMutableDictionary" key="localizations"/>
-			<nil key="sourceID"/>
-			<int key="maxID">36</int>
-		</object>
-		<object class="IBClassDescriber" key="IBDocument.Classes">
-			<array class="NSMutableArray" key="referencedPartialClassDescriptions">
-				<object class="IBPartialClassDescription">
-					<string key="className">VLCPasscodeLockViewController</string>
-					<string key="superclassName">UIViewController</string>
-					<object class="NSMutableDictionary" key="actions">
-						<string key="NS.key.0">textFieldValueChanged:</string>
-						<string key="NS.object.0">id</string>
-					</object>
-					<object class="NSMutableDictionary" key="actionInfosByName">
-						<string key="NS.key.0">textFieldValueChanged:</string>
-						<object class="IBActionInfo" key="NS.object.0">
-							<string key="name">textFieldValueChanged:</string>
-							<string key="candidateClassName">id</string>
-						</object>
-					</object>
-					<dictionary class="NSMutableDictionary" key="outlets">
-						<string key="enterCodeField">UITextField</string>
-						<string key="enterPasscodeLabel">UILabel</string>
-					</dictionary>
-					<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
-						<object class="IBToOneOutletInfo" key="enterCodeField">
-							<string key="name">enterCodeField</string>
-							<string key="candidateClassName">UITextField</string>
-						</object>
-						<object class="IBToOneOutletInfo" key="enterPasscodeLabel">
-							<string key="name">enterPasscodeLabel</string>
-							<string key="candidateClassName">UILabel</string>
-						</object>
-					</dictionary>
-					<object class="IBClassDescriptionSource" key="sourceIdentifier">
-						<string key="majorKey">IBProjectSource</string>
-						<string key="minorKey">./Classes/VLCPasscodeLockViewController.h</string>
-					</object>
-				</object>
-			</array>
-		</object>
-		<int key="IBDocument.localizationMode">0</int>
-		<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
-		<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
-			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
-			<real value="1296" key="NS.object.0"/>
-		</object>
-		<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
-		<int key="IBDocument.defaultPropertyAccessControl">3</int>
-		<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
-			<string key="NS.key.0">Aspen.png</string>
-			<string key="NS.object.0">{512, 512}</string>
-		</object>
-		<string key="IBCocoaTouchPluginVersion">2083</string>
-	</data>
-</archive>

+ 46 - 10
VLC for iOS.xcodeproj/project.pbxproj

@@ -88,8 +88,6 @@
 		7D6B08C3174A831900A05173 /* vlc-xmas@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D6B08C1174A831900A05173 /* vlc-xmas@2x.png */; };
 		7D6B08C7174A910500A05173 /* mediaUnread@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D6B08C6174A910500A05173 /* mediaUnread@2x.png */; };
 		7D6B08C9174A927700A05173 /* mediaUnread.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D6B08C8174A927700A05173 /* mediaUnread.png */; };
-		7D6BA10E1747F26300C0E203 /* VLCPasscodeLockViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D6BA10C1747F26300C0E203 /* VLCPasscodeLockViewController.m */; };
-		7D6BA10F1747F26300C0E203 /* VLCPasscodeLockViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D6BA10D1747F26300C0E203 /* VLCPasscodeLockViewController.xib */; };
 		7D6BA1121748EA8300C0E203 /* playback_background.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D6BA1101748EA8300C0E203 /* playback_background.png */; };
 		7D6BA1131748EA8300C0E203 /* playback_background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D6BA1111748EA8300C0E203 /* playback_background@2x.png */; };
 		7D6BA1171748EFE100C0E203 /* VLCAddMediaViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D6BA1151748EFE100C0E203 /* VLCAddMediaViewController.m */; };
@@ -131,6 +129,13 @@
 		A79246C3170F114E0036AAF2 /* VLCPlaylistTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A79246BE170F114E0036AAF2 /* VLCPlaylistTableViewCell.xib */; };
 		A79246C5170F114E0036AAF2 /* VLCPlaylistViewController~iphone.xib in Resources */ = {isa = PBXBuildFile; fileRef = A79246C0170F114E0036AAF2 /* VLCPlaylistViewController~iphone.xib */; };
 		A79246C8170F11DF0036AAF2 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = A79246C6170F11DF0036AAF2 /* Localizable.strings */; };
+		A7A0E9F5174BA66000162F25 /* papasscode_background.png in Resources */ = {isa = PBXBuildFile; fileRef = A7A0E9ED174BA66000162F25 /* papasscode_background.png */; };
+		A7A0E9F6174BA66000162F25 /* papasscode_background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A7A0E9EE174BA66000162F25 /* papasscode_background@2x.png */; };
+		A7A0E9F7174BA66000162F25 /* papasscode_failed_bg.png in Resources */ = {isa = PBXBuildFile; fileRef = A7A0E9EF174BA66000162F25 /* papasscode_failed_bg.png */; };
+		A7A0E9F8174BA66000162F25 /* papasscode_failed_bg@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A7A0E9F0174BA66000162F25 /* papasscode_failed_bg@2x.png */; };
+		A7A0E9F9174BA66000162F25 /* papasscode_marker.png in Resources */ = {isa = PBXBuildFile; fileRef = A7A0E9F1174BA66000162F25 /* papasscode_marker.png */; };
+		A7A0E9FA174BA66000162F25 /* papasscode_marker@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A7A0E9F2174BA66000162F25 /* papasscode_marker@2x.png */; };
+		A7A0E9FB174BA66000162F25 /* PAPasscodeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A7A0E9F4174BA66000162F25 /* PAPasscodeViewController.m */; };
 		A7CB0DB11716F72600050CF3 /* PlayingExternally@2x~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = A7CB0DAD1716F72600050CF3 /* PlayingExternally@2x~iphone.png */; };
 		A7CB0DB21716F72600050CF3 /* PlayingExternally~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = A7CB0DAE1716F72600050CF3 /* PlayingExternally~iphone.png */; };
 		A7CB0DB31716F72600050CF3 /* PlayingExternally~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = A7CB0DAF1716F72600050CF3 /* PlayingExternally~ipad.png */; };
@@ -280,9 +285,6 @@
 		7D6B08C1174A831900A05173 /* vlc-xmas@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "vlc-xmas@2x.png"; sourceTree = "<group>"; };
 		7D6B08C6174A910500A05173 /* mediaUnread@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "mediaUnread@2x.png"; sourceTree = "<group>"; };
 		7D6B08C8174A927700A05173 /* mediaUnread.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = mediaUnread.png; sourceTree = "<group>"; };
-		7D6BA10B1747F26300C0E203 /* VLCPasscodeLockViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCPasscodeLockViewController.h; sourceTree = "<group>"; };
-		7D6BA10C1747F26300C0E203 /* VLCPasscodeLockViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCPasscodeLockViewController.m; sourceTree = "<group>"; };
-		7D6BA10D1747F26300C0E203 /* VLCPasscodeLockViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCPasscodeLockViewController.xib; path = ../Resources/VLCPasscodeLockViewController.xib; sourceTree = "<group>"; };
 		7D6BA1101748EA8300C0E203 /* playback_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = playback_background.png; sourceTree = "<group>"; };
 		7D6BA1111748EA8300C0E203 /* playback_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "playback_background@2x.png"; sourceTree = "<group>"; };
 		7D6BA1141748EFE100C0E203 /* VLCAddMediaViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCAddMediaViewController.h; sourceTree = "<group>"; };
@@ -340,6 +342,14 @@
 		A79246C0170F114E0036AAF2 /* VLCPlaylistViewController~iphone.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = "VLCPlaylistViewController~iphone.xib"; path = "Resources/VLCPlaylistViewController~iphone.xib"; sourceTree = SOURCE_ROOT; };
 		A79246C7170F11DF0036AAF2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
 		A79246C9170F11E40036AAF2 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
+		A7A0E9ED174BA66000162F25 /* papasscode_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = papasscode_background.png; sourceTree = "<group>"; };
+		A7A0E9EE174BA66000162F25 /* papasscode_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "papasscode_background@2x.png"; sourceTree = "<group>"; };
+		A7A0E9EF174BA66000162F25 /* papasscode_failed_bg.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = papasscode_failed_bg.png; sourceTree = "<group>"; };
+		A7A0E9F0174BA66000162F25 /* papasscode_failed_bg@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "papasscode_failed_bg@2x.png"; sourceTree = "<group>"; };
+		A7A0E9F1174BA66000162F25 /* papasscode_marker.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = papasscode_marker.png; sourceTree = "<group>"; };
+		A7A0E9F2174BA66000162F25 /* papasscode_marker@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "papasscode_marker@2x.png"; sourceTree = "<group>"; };
+		A7A0E9F3174BA66000162F25 /* PAPasscodeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PAPasscodeViewController.h; sourceTree = "<group>"; };
+		A7A0E9F4174BA66000162F25 /* PAPasscodeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PAPasscodeViewController.m; sourceTree = "<group>"; };
 		A7CB0DAD1716F72600050CF3 /* PlayingExternally@2x~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "PlayingExternally@2x~iphone.png"; sourceTree = "<group>"; };
 		A7CB0DAE1716F72600050CF3 /* PlayingExternally~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "PlayingExternally~iphone.png"; sourceTree = "<group>"; };
 		A7CB0DAF1716F72600050CF3 /* PlayingExternally~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "PlayingExternally~ipad.png"; sourceTree = "<group>"; };
@@ -640,6 +650,7 @@
 		7D94FCD216DE7D1000F2623B = {
 			isa = PBXGroup;
 			children = (
+				A7A0E9EB174BA66000162F25 /* PAPasscode */,
 				7D94FCE416DE7D1000F2623B /* AspenProject */,
 				CC1BBC441704936500A20CBF /* External VLC Libraries */,
 				7D94FCDD16DE7D1000F2623B /* Frameworks */,
@@ -703,8 +714,6 @@
 				7D6BA1151748EFE100C0E203 /* VLCAddMediaViewController.m */,
 				7D3EB015174A46FB002062C2 /* VLCHTTPFileDownloader.h */,
 				7D3EB016174A46FB002062C2 /* VLCHTTPFileDownloader.m */,
-				7D6BA10B1747F26300C0E203 /* VLCPasscodeLockViewController.h */,
-				7D6BA10C1747F26300C0E203 /* VLCPasscodeLockViewController.m */,
 				7D6BA11B17491F5F00C0E203 /* VLCSettingsViewController.h */,
 				7D6BA11C17491F5F00C0E203 /* VLCSettingsViewController.m */,
 				7D31CF061746AEF2005997E0 /* UI Elements */,
@@ -740,7 +749,6 @@
 				A79246BE170F114E0036AAF2 /* VLCPlaylistTableViewCell.xib */,
 				7DC87AF117413EE3009DC250 /* VLCPlaylistGridView.xib */,
 				7D33D41517182615008AF0E0 /* VLCMovieViewController~ipad.xib */,
-				7D6BA10D1747F26300C0E203 /* VLCPasscodeLockViewController.xib */,
 			);
 			name = XIBs;
 			sourceTree = "<group>";
@@ -798,6 +806,29 @@
 			path = Resources;
 			sourceTree = SOURCE_ROOT;
 		};
+		A7A0E9EB174BA66000162F25 /* PAPasscode */ = {
+			isa = PBXGroup;
+			children = (
+				A7A0E9EC174BA66000162F25 /* Assets */,
+				A7A0E9F3174BA66000162F25 /* PAPasscodeViewController.h */,
+				A7A0E9F4174BA66000162F25 /* PAPasscodeViewController.m */,
+			);
+			path = PAPasscode;
+			sourceTree = "<group>";
+		};
+		A7A0E9EC174BA66000162F25 /* Assets */ = {
+			isa = PBXGroup;
+			children = (
+				A7A0E9ED174BA66000162F25 /* papasscode_background.png */,
+				A7A0E9EE174BA66000162F25 /* papasscode_background@2x.png */,
+				A7A0E9EF174BA66000162F25 /* papasscode_failed_bg.png */,
+				A7A0E9F0174BA66000162F25 /* papasscode_failed_bg@2x.png */,
+				A7A0E9F1174BA66000162F25 /* papasscode_marker.png */,
+				A7A0E9F2174BA66000162F25 /* papasscode_marker@2x.png */,
+			);
+			path = Assets;
+			sourceTree = "<group>";
+		};
 		CC1BBC441704936500A20CBF /* External VLC Libraries */ = {
 			isa = PBXGroup;
 			children = (
@@ -913,7 +944,6 @@
 				7D10BCA91743FE7B00DA7059 /* speed@2x.png in Resources */,
 				A7035BBE174519600057DFA7 /* iTunesArtwork in Resources */,
 				A7035BC217451D4A0057DFA7 /* Aspen.png in Resources */,
-				7D6BA10F1747F26300C0E203 /* VLCPasscodeLockViewController.xib in Resources */,
 				7D6BA1121748EA8300C0E203 /* playback_background.png in Resources */,
 				7D6BA1131748EA8300C0E203 /* playback_background@2x.png in Resources */,
 				2915542317490A9C00B86CAD /* About.txt in Resources */,
@@ -934,6 +964,12 @@
 				7D6B08C3174A831900A05173 /* vlc-xmas@2x.png in Resources */,
 				7D6B08C7174A910500A05173 /* mediaUnread@2x.png in Resources */,
 				7D6B08C9174A927700A05173 /* mediaUnread.png in Resources */,
+				A7A0E9F5174BA66000162F25 /* papasscode_background.png in Resources */,
+				A7A0E9F6174BA66000162F25 /* papasscode_background@2x.png in Resources */,
+				A7A0E9F7174BA66000162F25 /* papasscode_failed_bg.png in Resources */,
+				A7A0E9F8174BA66000162F25 /* papasscode_failed_bg@2x.png in Resources */,
+				A7A0E9F9174BA66000162F25 /* papasscode_marker.png in Resources */,
+				A7A0E9FA174BA66000162F25 /* papasscode_marker@2x.png in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -966,7 +1002,6 @@
 				7DE480D1173FEA30003613E0 /* VLCCircularProgressIndicator.m in Sources */,
 				7DC87AEE17412A1F009DC250 /* VLCLinearProgressIndicator.m in Sources */,
 				7D31CF091746AF09005997E0 /* VLCStatusLabel.m in Sources */,
-				7D6BA10E1747F26300C0E203 /* VLCPasscodeLockViewController.m in Sources */,
 				2915540117490A1E00B86CAD /* DDData.m in Sources */,
 				2915540217490A1E00B86CAD /* DDNumber.m in Sources */,
 				2915540317490A1E00B86CAD /* DDRange.m in Sources */,
@@ -997,6 +1032,7 @@
 				7D6BA11E17491F5F00C0E203 /* VLCSettingsViewController.m in Sources */,
 				7D3EB012174A3530002062C2 /* Reachability.m in Sources */,
 				7D3EB017174A46FB002062C2 /* VLCHTTPFileDownloader.m in Sources */,
+				A7A0E9FB174BA66000162F25 /* PAPasscodeViewController.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};