Merge branch 'master' of https://code.grnet.gr/git/pithos-ios
[pithos-ios] / Classes / PasscodeViewController.m
1 //
2 //  PasscodeViewController.m
3 //  OpenStack
4 //
5 //  Created by Mike Mayo on 10/26/10.
6 //  The OpenStack project is provided under the Apache 2.0 license.
7 //
8
9 #import "PasscodeViewController.h"
10 #import "UIViewController+Conveniences.h"
11 #import "UIColor+MoreColors.h"
12 #import "Keychain.h"
13 #import "PasscodeLockViewController.h"
14 #import "SettingsViewController.h"
15 #import <QuartzCore/QuartzCore.h>
16 #import "Archiver.h"
17 #import "RootViewController.h"
18 #import "OpenStackAccount.h"
19 #import "OpenStackAppDelegate.h"
20
21 @implementation PasscodeViewController
22
23 @synthesize mode, passcodeLockViewController, settingsViewController, rootViewController;
24
25 #pragma mark - View lifecycle
26
27 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
28     return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
29 }
30
31 - (void)viewDidLoad {
32     [super viewDidLoad];
33     simplePasscodeOn = [[Keychain getStringForKey:@"passcode_lock_simple_passcode_on"] isEqualToString:@"YES"];
34     passcodeLockOn = [[Keychain getStringForKey:@"passcode_lock_passcode_on"] isEqualToString:@"YES"];
35     eraseData = [[Keychain getStringForKey:@"passcode_lock_erase_data_on"] isEqualToString:@"YES"];
36     
37     if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
38         viewWidth = 540.0;
39     } else {
40         viewWidth = 320.0;
41     }
42 }
43
44 - (void)viewWillAppear:(BOOL)animated {
45     [super viewWillAppear:animated];
46     
47     enterPasscodeTextField = [self allocAndInitPasscodeTextField];
48     setPasscodeTextField = [self allocAndInitPasscodeTextField];
49     confirmPasscodeTextField = [self allocAndInitPasscodeTextField];
50     
51     tableViews = [[NSMutableArray alloc] init];
52     textFields = [[NSMutableArray alloc] init];
53     squares = [[NSMutableArray alloc] init];
54     
55     if (mode == kModeSetPasscode || mode == kModeChangePasscode) {
56         // we're setting the passcode, so add possibly all of the table views
57         if (passcodeLockOn) {
58             enterPasscodeTableView.tableHeaderView = [self passwordHeaderViewForTextField:enterPasscodeTextField];
59             [tableViews addObject:enterPasscodeTableView];
60             [textFields addObject:enterPasscodeTextField];
61             if (simplePasscodeOn) {
62                 [squares addObject:[self createSquares]];
63                 for (int i = 0; i < [[squares lastObject] count]; i++) {
64                     [enterPasscodeTableView.tableHeaderView addSubview:[[squares lastObject] objectAtIndex:i]];
65                 }
66             }
67         }
68         setPasscodeTableView.tableHeaderView = [self passwordHeaderViewForTextField:setPasscodeTextField];
69         [tableViews addObject:setPasscodeTableView];
70         [textFields addObject:setPasscodeTextField];
71         if (simplePasscodeOn) {
72             [squares addObject:[self createSquares]];
73             for (int i = 0; i < [[squares lastObject] count]; i++) {
74                 [setPasscodeTableView.tableHeaderView addSubview:[[squares lastObject] objectAtIndex:i]];
75             }
76         }
77         confirmPasscodeTableView.tableHeaderView = [self passwordHeaderViewForTextField:confirmPasscodeTextField];
78         [tableViews addObject:confirmPasscodeTableView];
79         [textFields addObject:confirmPasscodeTextField];
80         if (simplePasscodeOn) {
81             [squares addObject:[self createSquares]];
82             for (int i = 0; i < [[squares lastObject] count]; i++) {
83                 [confirmPasscodeTableView.tableHeaderView addSubview:[[squares lastObject] objectAtIndex:i]];
84             }
85         }
86     } else {
87         enterPasscodeTableView.tableHeaderView = [self passwordHeaderViewForTextField:enterPasscodeTextField];
88         [tableViews addObject:enterPasscodeTableView];
89         [textFields addObject:enterPasscodeTextField];
90         if (simplePasscodeOn) {
91             [squares addObject:[self createSquares]];
92             for (int i = 0; i < [[squares lastObject] count]; i++) {
93                 [enterPasscodeTableView.tableHeaderView addSubview:[[squares lastObject] objectAtIndex:i]];
94             }
95         }
96     }
97     
98     [self.view addSubview:[tableViews objectAtIndex:0]];
99     
100     // shift any extra table views away
101     for (int i = 1; i < [tableViews count]; i++) {
102         UITableView *tableView = [tableViews objectAtIndex:i];
103         tableView.frame = CGRectMake(tableView.frame.origin.x + viewWidth, tableView.frame.origin.y, tableView.frame.size.width, tableView.frame.size.height);
104         [self.view addSubview:tableView];
105     }
106     
107     if (!simplePasscodeOn) {
108         if (tableIndex == [tableViews count] - 1) {
109             [self addDoneButton];
110         } else {
111             [self addNextButton];
112         }
113     }
114     
115     [[textFields objectAtIndex:0] becomeFirstResponder];
116     [[tableViews objectAtIndex:0] reloadData];
117     [[textFields objectAtIndex:[tableViews count] - 1] setReturnKeyType:UIReturnKeyDone];
118     
119     // table looks all screwy on iPad at first, so shuffle around to get the drawing right
120     // yes, i know this is a dirty hack.
121     if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
122         if ([tableViews count] > 1) {
123             [self moveToNextTableView];
124             [self moveToPreviousTableView];
125         } else {
126             UITableView *tv = [tableViews objectAtIndex:0];
127             tv.frame = CGRectMake(tv.frame.origin.x, tv.frame.origin.y, 768.0, 960.0);
128         }
129     }
130 }
131
132 #pragma mark - Memory management
133
134 - (void)dealloc {
135     
136     [enterPasscodeTextField release];
137     [setPasscodeTextField release];
138     [confirmPasscodeTextField release];
139     [tableViews release];
140     [textFields release];
141     [squares release];
142     [passcodeLockViewController release];
143     [settingsViewController release];
144     [rootViewController release];
145     [super dealloc];
146 }
147
148 #pragma mark - Internal
149
150 - (UITextField *)allocAndInitPasscodeTextField {
151     UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(29.0, 13.0, 271.0, 24.0)];
152     textField.text = @"";
153     textField.textColor = [UIColor value1DetailTextLabelColor];
154     textField.secureTextEntry = YES;
155     textField.delegate = self;
156     textField.keyboardAppearance = UIKeyboardAppearanceAlert;
157     return textField;
158 }
159
160 - (UIView *)passwordHeaderViewForTextField:(UITextField *)textField {
161     if (simplePasscodeOn) {
162         textField.keyboardType = UIKeyboardTypeNumberPad;
163         // hide the text field and add it to the view.  we'll use the squares, but we need a text field
164         textField.hidden = YES;
165         [self.view addSubview:textField];
166     } else {
167         textField.keyboardType = UIKeyboardTypeDefault;
168         textField.returnKeyType = UIReturnKeyNext;
169     }
170     
171     UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, viewWidth, 70.0)] autorelease];
172     UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 27.5, viewWidth, 30.0)];
173     headerLabel.textColor = [UIColor tableViewHeaderColor];
174     headerLabel.backgroundColor = [UIColor clearColor];
175     headerLabel.textAlignment = UITextAlignmentCenter;
176     headerLabel.font = [UIFont boldSystemFontOfSize:17.0];
177     headerLabel.shadowOffset = CGSizeMake(0, 1.0);
178     headerLabel.shadowColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
179     
180     if ([textField isEqual:enterPasscodeTextField]) {
181         NSString *text = @"1 Failed Passcode Attempt";
182         CGSize size = [text sizeWithFont:[UIFont boldSystemFontOfSize:14.0]];
183         failedAttemptsView = [[UIView alloc] initWithFrame:CGRectMake((viewWidth - (size.width + 36.0)) / 2, 147.5, size.width + 36.0, size.height + 10.0)];
184         failedAttemptsLabel = [[UILabel alloc] initWithFrame:CGRectMake((viewWidth - (size.width + 36.0)) / 2, 147.5, size.width + 36.0, size.height + 10.0)];
185         failedAttemptsLabel.backgroundColor = [UIColor clearColor];
186         failedAttemptsLabel.textColor = [UIColor whiteColor];
187         failedAttemptsLabel.text = text;
188         failedAttemptsLabel.font = [UIFont boldSystemFontOfSize:14.0];
189         failedAttemptsLabel.textAlignment = UITextAlignmentCenter;
190         failedAttemptsLabel.shadowOffset = CGSizeMake(0, -1.0);
191         failedAttemptsLabel.shadowColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
192         failedAttemptsView.layer.cornerRadius = 14;
193         failedAttemptsView.layer.borderWidth = 1.0;
194         failedAttemptsView.layer.borderColor = [[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.25] CGColor];
195         
196         failedAttemptsLabel.hidden = YES;
197         failedAttemptsView.hidden = YES;
198         
199         CAGradientLayer *gradient = [CAGradientLayer layer];
200         gradient.frame = failedAttemptsView.bounds;
201         gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithRed:0.714 green:0.043 blue:0.043 alpha:1.0] CGColor],
202                            (id)[[UIColor colorWithRed:0.761 green:0.192 blue:0.192 alpha:1.0] CGColor], nil];
203         [failedAttemptsView.layer insertSublayer:gradient atIndex:1];
204         failedAttemptsView.layer.masksToBounds = YES;
205         
206         [headerView addSubview:failedAttemptsView];
207         [headerView addSubview:failedAttemptsLabel];
208         
209         [failedAttemptsView release];
210         [failedAttemptsLabel release];
211     } else if ([textField isEqual:setPasscodeTextField]) {
212         passcodeConfirmationWarningLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 146.5, viewWidth, 30.0)];
213         passcodeConfirmationWarningLabel.textColor = [UIColor tableViewHeaderColor];
214         passcodeConfirmationWarningLabel.backgroundColor = [UIColor clearColor];
215         passcodeConfirmationWarningLabel.textAlignment = UITextAlignmentCenter;
216         passcodeConfirmationWarningLabel.font = [UIFont systemFontOfSize:14.0];
217         passcodeConfirmationWarningLabel.shadowOffset = CGSizeMake(0, 1.0);
218         passcodeConfirmationWarningLabel.shadowColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
219         passcodeConfirmationWarningLabel.text = @"";
220         passcodeConfirmationWarningLabel.numberOfLines = 0;
221         passcodeConfirmationWarningLabel.lineBreakMode = UILineBreakModeWordWrap;
222         [headerView addSubview:passcodeConfirmationWarningLabel];
223     }
224     
225     if (mode == kModeSetPasscode) {
226         self.navigationItem.title = @"Set Passcode";
227         [self addCancelButton];
228         if ([textField isEqual:enterPasscodeTextField]) {
229             headerLabel.text = @"Enter your passcode";
230         } else if ([textField isEqual:setPasscodeTextField]) {
231             headerLabel.text = @"Enter a passcode";
232             [self addCancelButton];
233         } else if ([textField isEqual:confirmPasscodeTextField]) {
234             headerLabel.text = @"Re-enter your passcode";
235         }
236     } else if (mode == kModeDisablePasscode) {
237         self.navigationItem.title = @"Turn off Passcode";
238         [self addCancelButton];
239         headerLabel.text = @"Enter your passcode";
240     } else if (mode == kModeChangePasscode) {
241         self.navigationItem.title = @"Change Passcode";
242         [self addCancelButton];
243         if ([textField isEqual:enterPasscodeTextField]) {
244             headerLabel.text = @"Enter your old passcode";
245         } else if ([textField isEqual:setPasscodeTextField]) {
246             headerLabel.text = @"Enter your new passcode";
247         } else {
248             headerLabel.text = @"Re-enter your new passcode";
249         }
250     } else {
251         self.navigationItem.title = @"Enter Passcode";
252         headerLabel.text = @"Enter your passcode";
253     }
254     
255     [headerView addSubview:headerLabel];
256     [headerLabel release];
257     
258     return headerView;
259 }
260
261 - (NSArray *)createSquares {
262     NSMutableArray *squareViews = [[NSMutableArray alloc] initWithCapacity:4];
263     NSInteger squareX = 23.0;
264     if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
265         squareX = 133.0;
266     }
267     
268     for (int i = 0; i < 4; i++) {
269         UIImageView *square = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"passcode_square_empty.png"]];
270         square.frame = CGRectMake(squareX, 74.0, 61.0, 53.0);
271         [squareViews addObject:square];
272         [square release];
273         squareX += 71.0;
274     }
275     return [NSArray arrayWithArray:squareViews];
276 }
277
278 - (void)moveToNextTableView {
279     tableIndex += 1;
280     UITableView *oldTableView = [tableViews objectAtIndex:tableIndex - 1];
281     UITableView *newTableView = [tableViews objectAtIndex:tableIndex];
282     newTableView.frame = CGRectMake(oldTableView.frame.origin.x + viewWidth, oldTableView.frame.origin.y, oldTableView.frame.size.width, oldTableView.frame.size.height);
283     
284     if (simplePasscodeOn) {
285         for (int i = 0; i < 4; i++) {
286             [[[squares objectAtIndex:tableIndex] objectAtIndex:i] setImage:[UIImage imageNamed:@"passcode_square_empty.png"]];
287         }
288     }
289     
290     [UIView animateWithDuration:0.25 animations:^{
291         oldTableView.frame = CGRectMake(oldTableView.frame.origin.x - viewWidth, oldTableView.frame.origin.y, oldTableView.frame.size.width, oldTableView.frame.size.height);
292         newTableView.frame = self.view.frame;
293     }];
294     
295     if (!simplePasscodeOn) {
296         if (tableIndex == [tableViews count] - 1) {
297             [self addDoneButton];
298         } else {
299             [self addNextButton];
300         }
301     }
302     
303     [[textFields objectAtIndex:tableIndex - 1] resignFirstResponder];
304     [[textFields objectAtIndex:tableIndex] becomeFirstResponder];
305 }
306
307 - (void)moveToPreviousTableView {
308     tableIndex -= 1;
309     UITableView *oldTableView = [tableViews objectAtIndex:tableIndex + 1];
310     UITableView *newTableView = [tableViews objectAtIndex:tableIndex];
311     newTableView.frame = CGRectMake(oldTableView.frame.origin.x - viewWidth, oldTableView.frame.origin.y, oldTableView.frame.size.width, oldTableView.frame.size.height);
312     
313     if (simplePasscodeOn) {
314         for (int i = 0; i < 4; i++) {
315             [[[squares objectAtIndex:tableIndex] objectAtIndex:i] setImage:[UIImage imageNamed:@"passcode_square_empty.png"]];
316         }
317     }
318     
319     [UIView animateWithDuration:0.25 animations:^{
320         oldTableView.frame = CGRectMake(oldTableView.frame.origin.x + viewWidth, oldTableView.frame.origin.y, oldTableView.frame.size.width, oldTableView.frame.size.height);
321         newTableView.frame = self.view.frame;
322     }];
323     
324     if (!simplePasscodeOn) {
325         if (tableIndex == [tableViews count] - 1) {
326             [self addDoneButton];
327         } else {
328             [self addNextButton];
329         }
330     }
331     
332     [[textFields objectAtIndex:tableIndex + 1] resignFirstResponder];
333     [[textFields objectAtIndex:tableIndex] becomeFirstResponder];
334 }
335
336 - (void)incrementAndShowFailedAttemptsLabel {
337     enterPasscodeTextField.text = @"";
338     if (simplePasscodeOn) {
339         for (int i = 0; i < 4; i++) {
340             [[[squares objectAtIndex:tableIndex] objectAtIndex:i] setImage:[UIImage imageNamed:@"passcode_square_empty.png"]];
341         }
342     }
343     
344     failedAttemptsCount += 1;
345     if (failedAttemptsCount == 1) {
346         failedAttemptsLabel.text = @"1 Failed Passcode Attempt";
347     } else {
348         failedAttemptsLabel.text = [NSString stringWithFormat:@"%i Failed Passcode Attempts", failedAttemptsCount];
349     }
350     CGSize size = [failedAttemptsLabel.text sizeWithFont:[UIFont boldSystemFontOfSize:14.0]];
351     failedAttemptsView.frame = CGRectMake((viewWidth - (size.width + 36.0)) / 2, 147.5, size.width + 36.0, size.height + 10.0);
352     failedAttemptsLabel.frame = CGRectMake((viewWidth - (size.width + 36.0)) / 2, 147.5, size.width + 36.0, size.height + 10.0);
353     
354     CAGradientLayer *gradient = [CAGradientLayer layer];
355     gradient.frame = failedAttemptsView.bounds;
356     gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithRed:0.714 green:0.043 blue:0.043 alpha:1.0] CGColor],
357                        (id)[[UIColor colorWithRed:0.761 green:0.192 blue:0.192 alpha:1.0] CGColor], nil];
358     [failedAttemptsView.layer insertSublayer:gradient atIndex:0];
359     failedAttemptsView.layer.masksToBounds = YES;
360     
361     failedAttemptsLabel.hidden = NO;
362     failedAttemptsView.hidden = NO;
363     
364     if (failedAttemptsCount == 10 && eraseData) {
365         [Archiver deleteEverything];
366         [OpenStackAccount persist:[NSMutableArray array]];
367         if ([Keychain setString:@"NO" forKey:@"passcode_lock_passcode_on"]) {
368             [Keychain setString:@"" forKey:@"passcode_lock_passcode"];
369         }
370         [self dismissModalViewControllerAnimated:YES];
371         if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
372             [UIView animateWithDuration:0.5 delay:0.25 options:0 animations:^{
373                 OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
374                 for (UIViewController *svc in app.splitViewController.viewControllers) {
375                     svc.view.alpha = 1.0;
376                 }
377             } completion:^(BOOL finished){}];
378         }
379         
380         [self alert:@"" message:@"You have entered an incorrect passcode too many times. All account data in this app have been deleted."];
381         if (self.rootViewController) {
382             [[self.rootViewController navigationController] popToRootViewControllerAnimated:NO];
383             [[self.rootViewController tableView] reloadData];
384         }
385     }
386 }
387
388 #pragma mark - UITableViewDataSource
389
390 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
391     return simplePasscodeOn ? 0 : 1;
392 }
393
394 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
395     return 1;
396 }
397
398 - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
399     static NSString *CellIdentifier = @"Cell";
400     
401     UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
402     if (cell == nil) {
403         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
404         cell.selectionStyle = UITableViewCellSelectionStyleNone;
405     }
406     
407     // Configure the cell...
408     if ([aTableView isEqual:enterPasscodeTableView]) {
409         cell.accessoryView = enterPasscodeTextField;
410     } else if ([aTableView isEqual:setPasscodeTableView]) {
411         cell.accessoryView = setPasscodeTextField;
412     } else if ([aTableView isEqual:confirmPasscodeTableView]) {
413         cell.accessoryView = confirmPasscodeTextField;
414     }
415     
416     return cell;
417 }
418
419 #pragma mark - UITextFieldDelegate
420
421 //- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
422 //    // we don't want iPad users to be able to dismiss the keyboard at all
423 //    return NO;
424 //}
425
426 - (BOOL)textFieldShouldReturn:(UITextField *)textField {
427     if ([textField isEqual:[textFields lastObject]]) {
428         [self doneButtonPressed:nil];
429     } else {
430         [self nextButtonPressed:nil];
431     }
432     return NO;
433 }
434
435 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
436     // if we're in simple passcode mode, update the squares to show entered numbers
437     if (simplePasscodeOn) {
438         NSString *result = [textField.text stringByReplacingCharactersInRange:range withString:string];
439         
440         // we're setting here and returning no since i'm messing with the responder chain.
441         // otherwise the last character will become the first character of the next textField
442         textField.text = result;
443         
444         for (int i = 0; i < 4; i++) {
445             UIImageView *square = [[squares objectAtIndex:tableIndex] objectAtIndex:i];
446             if (i < [result length]) {
447                 square.image = [UIImage imageNamed:@"passcode_square_filled.png"];
448             } else {
449                 square.image = [UIImage imageNamed:@"passcode_square_empty.png"];
450             }
451         }
452         
453         // if we're at 4 characters, it could be time to move on to confirming
454         if ([result length] == 4) {
455             if (mode == kModeDisablePasscode) {
456                 NSString *passcode = [Keychain getStringForKey:@"passcode_lock_passcode"];
457                 if ([enterPasscodeTextField.text isEqualToString:passcode]) {
458                     if ([Keychain setString:@"NO" forKey:@"passcode_lock_passcode_on"]) {
459                         [Keychain setString:@"" forKey:@"passcode_lock_passcode"];
460                     }
461                     [self.passcodeLockViewController.tableView reloadData];
462                     [self.settingsViewController.tableView reloadData];
463                     [self dismissModalViewControllerAnimated:YES];
464                 } else {
465                     [self incrementAndShowFailedAttemptsLabel];
466                 }
467             } else if (mode == kModeEnterPasscode) {
468                 NSString *passcode = [Keychain getStringForKey:@"passcode_lock_passcode"];
469                 if ([enterPasscodeTextField.text isEqualToString:passcode]) {
470                     if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
471                         [UIView animateWithDuration:0.5 delay:0.25 options:0 animations:^{
472                             OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
473                             for (UIViewController *svc in app.splitViewController.viewControllers) {
474                                 svc.view.alpha = 1.0;
475                             }
476                         } completion:^(BOOL finished){}];
477                     }
478                     [self dismissModalViewControllerAnimated:YES];
479                 } else {
480                     [self incrementAndShowFailedAttemptsLabel];
481                 }
482             } else if (mode == kModeChangePasscode) {
483                 NSString *passcode = [Keychain getStringForKey:@"passcode_lock_passcode"];
484                 if ([textField isEqual:enterPasscodeTextField]) {
485                     if ([passcode isEqualToString:enterPasscodeTextField.text]) {
486                         [self moveToNextTableView];
487                     } else {
488                         [self incrementAndShowFailedAttemptsLabel];
489                     }
490                 } else if ([textField isEqual:setPasscodeTextField]) {
491                     if ([passcode isEqualToString:setPasscodeTextField.text]) {
492                         setPasscodeTextField.text = @"";
493                         for (int i = 0; i < 4; i++) {
494                             [[[squares objectAtIndex:tableIndex] objectAtIndex:i] setImage:[UIImage imageNamed:@"passcode_square_empty.png"]];
495                         }
496                         passcodeConfirmationWarningLabel.text = @"Enter a different passcode. Cannot re-use the same passcode.";
497                         passcodeConfirmationWarningLabel.frame = CGRectMake(0.0, 131.5, viewWidth, 60.0);
498                     } else {
499                         passcodeConfirmationWarningLabel.text = @"";
500                         passcodeConfirmationWarningLabel.frame = CGRectMake(0.0, 146.5, viewWidth, 30.0);
501                         [self moveToNextTableView];
502                     }
503                 } else if ([textField isEqual:confirmPasscodeTextField]) {
504                     if (![confirmPasscodeTextField.text isEqualToString:setPasscodeTextField.text]) {
505                         confirmPasscodeTextField.text = @"";
506                         setPasscodeTextField.text = @"";
507                         passcodeConfirmationWarningLabel.text = @"Passcodes did not match. Try again.";
508                         [self moveToPreviousTableView];
509                     } else {
510                         if ([Keychain setString:setPasscodeTextField.text forKey:@"passcode_lock_passcode"]) {
511                             [Keychain setString:@"YES" forKey:@"passcode_lock_passcode_on"];
512                         }
513                         [self.passcodeLockViewController.tableView reloadData];
514                         [self.settingsViewController.tableView reloadData];
515                         [self dismissModalViewControllerAnimated:YES];
516                     }
517                 }
518             } else if ([textField isEqual:setPasscodeTextField]) {
519                 [self moveToNextTableView];
520             } else if ([textField isEqual:confirmPasscodeTextField]) {
521                 if (![confirmPasscodeTextField.text isEqualToString:setPasscodeTextField.text]) {
522                     confirmPasscodeTextField.text = @"";
523                     setPasscodeTextField.text = @"";
524                     passcodeConfirmationWarningLabel.text = @"Passcodes did not match. Try again.";
525                     [self moveToPreviousTableView];
526                 } else {
527                     if ([Keychain setString:setPasscodeTextField.text forKey:@"passcode_lock_passcode"]) {
528                         [Keychain setString:@"YES" forKey:@"passcode_lock_passcode_on"];
529                     }
530                     [self.passcodeLockViewController.tableView reloadData];
531                     [self.settingsViewController.tableView reloadData];
532                     [self dismissModalViewControllerAnimated:YES];
533                 }
534             }
535         }
536         
537         return NO;
538     }
539     
540     return YES;
541 }
542
543 #pragma mark - Button Handlers
544
545 - (void)nextButtonPressed:(id)sender {
546     UITextField *textField = [textFields objectAtIndex:tableIndex];
547     if (![textField.text isEqualToString:@""]) {
548         if (mode == kModeSetPasscode) {
549             if ([textField isEqual:setPasscodeTextField]) {
550                 [self moveToNextTableView];
551             } else if ([textField isEqual:confirmPasscodeTextField]) {
552                 if (![confirmPasscodeTextField.text isEqualToString:setPasscodeTextField.text]) {
553                     confirmPasscodeTextField.text = @"";
554                     setPasscodeTextField.text = @"";
555                     passcodeConfirmationWarningLabel.text = @"Passcodes did not match. Try again.";
556                     [self moveToPreviousTableView];
557                 } else {
558                     if ([Keychain setString:setPasscodeTextField.text forKey:@"passcode_lock_passcode"]) {
559                         [Keychain setString:@"YES" forKey:@"passcode_lock_passcode_on"];
560                     }
561                     [self.passcodeLockViewController.tableView reloadData];
562                     [self.settingsViewController.tableView reloadData];
563                     [self dismissModalViewControllerAnimated:YES];
564                 }
565             }            
566         } else if (mode == kModeChangePasscode) {
567             NSString *passcode = [Keychain getStringForKey:@"passcode_lock_passcode"];
568             if ([textField isEqual:enterPasscodeTextField]) {
569                 if ([passcode isEqualToString:enterPasscodeTextField.text]) {
570                     [self moveToNextTableView];
571                 } else {
572                     [self incrementAndShowFailedAttemptsLabel];
573                 }
574             } else if ([textField isEqual:setPasscodeTextField]) {
575                 if ([passcode isEqualToString:setPasscodeTextField.text]) {
576                     setPasscodeTextField.text = @"";
577                     passcodeConfirmationWarningLabel.text = @"Enter a different passcode. Cannot re-use the same passcode.";
578                     passcodeConfirmationWarningLabel.frame = CGRectMake(0.0, 131.5, viewWidth, 60.0);
579                 } else {
580                     passcodeConfirmationWarningLabel.text = @"";
581                     passcodeConfirmationWarningLabel.frame = CGRectMake(0.0, 146.5, viewWidth, 30.0);
582                     [self moveToNextTableView];
583                 }
584             } else if ([textField isEqual:confirmPasscodeTextField]) {
585                 if (![confirmPasscodeTextField.text isEqualToString:setPasscodeTextField.text]) {
586                     confirmPasscodeTextField.text = @"";
587                     setPasscodeTextField.text = @"";
588                     passcodeConfirmationWarningLabel.text = @"Passcodes did not match. Try again.";
589                     [self moveToPreviousTableView];
590                 } else {
591                     if ([Keychain setString:setPasscodeTextField.text forKey:@"passcode_lock_passcode"]) {
592                         [Keychain setString:@"YES" forKey:@"passcode_lock_passcode_on"];
593                     }
594                     [self.passcodeLockViewController.tableView reloadData];
595                     [self.settingsViewController.tableView reloadData];
596                     [self dismissModalViewControllerAnimated:YES];
597                 }
598             }
599         }
600     }    
601 }
602
603 - (void)doneButtonPressed:(id)sender {
604     UITextField *textField = [textFields objectAtIndex:tableIndex];
605     if (mode == kModeEnterPasscode) {
606         NSString *passcode = [Keychain getStringForKey:@"passcode_lock_passcode"];
607         if ([enterPasscodeTextField.text isEqualToString:passcode]) {
608             if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
609                 [UIView animateWithDuration:0.5 delay:0.25 options:0 animations:^{
610                     OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
611                     for (UIViewController *svc in app.splitViewController.viewControllers) {
612                         svc.view.alpha = 1.0;
613                     }
614                 } completion:^(BOOL finished){}];
615             }
616             [self dismissModalViewControllerAnimated:YES];
617         } else { 
618             [self incrementAndShowFailedAttemptsLabel];
619         }
620     } else if (mode == kModeSetPasscode) {
621         if ([textField isEqual:setPasscodeTextField]) {
622             [self moveToNextTableView];
623         } else if ([textField isEqual:confirmPasscodeTextField]) {
624             if (![confirmPasscodeTextField.text isEqualToString:setPasscodeTextField.text]) {
625                 confirmPasscodeTextField.text = @"";
626                 setPasscodeTextField.text = @"";
627                 passcodeConfirmationWarningLabel.text = @"Passcodes did not match. Try again.";
628                 [self moveToPreviousTableView];
629             } else {
630                 if ([Keychain setString:setPasscodeTextField.text forKey:@"passcode_lock_passcode"]) {
631                     [Keychain setString:@"YES" forKey:@"passcode_lock_passcode_on"];
632                 }
633                 [self.passcodeLockViewController.tableView reloadData];
634                 [self.settingsViewController.tableView reloadData];
635                 [self dismissModalViewControllerAnimated:YES];
636             }
637         }            
638     } else if (mode == kModeChangePasscode) {
639         NSString *passcode = [Keychain getStringForKey:@"passcode_lock_passcode"];
640         if ([textField isEqual:enterPasscodeTextField]) {
641             if ([passcode isEqualToString:enterPasscodeTextField.text]) {
642                 [self moveToNextTableView];
643             } else {
644                 [self incrementAndShowFailedAttemptsLabel];
645             }
646         } else if ([textField isEqual:setPasscodeTextField]) {
647             if ([passcode isEqualToString:setPasscodeTextField.text]) {
648                 setPasscodeTextField.text = @"";
649                 passcodeConfirmationWarningLabel.text = @"Enter a different passcode. Cannot re-use the same passcode.";
650                 passcodeConfirmationWarningLabel.frame = CGRectMake(0.0, 131.5, viewWidth, 60.0);
651             } else {
652                 passcodeConfirmationWarningLabel.text = @"";
653                 passcodeConfirmationWarningLabel.frame = CGRectMake(0.0, 146.5, viewWidth, 30.0);
654                 [self moveToNextTableView];
655             }
656         } else if ([textField isEqual:confirmPasscodeTextField]) {
657             if (![confirmPasscodeTextField.text isEqualToString:setPasscodeTextField.text]) {
658                 confirmPasscodeTextField.text = @"";
659                 setPasscodeTextField.text = @"";
660                 passcodeConfirmationWarningLabel.text = @"Passcodes did not match. Try again.";
661                 [self moveToPreviousTableView];
662             } else {
663                 if ([Keychain setString:setPasscodeTextField.text forKey:@"passcode_lock_passcode"]) {
664                     [Keychain setString:@"YES" forKey:@"passcode_lock_passcode_on"];
665                 }
666                 [self.passcodeLockViewController.tableView reloadData];
667                 [self.settingsViewController.tableView reloadData];
668                 [self dismissModalViewControllerAnimated:YES];
669             }
670         }
671     } else if (mode == kModeDisablePasscode) {
672         NSString *passcode = [Keychain getStringForKey:@"passcode_lock_passcode"];
673         if ([enterPasscodeTextField.text isEqualToString:passcode]) {
674             if ([Keychain setString:@"NO" forKey:@"passcode_lock_passcode_on"]) {
675                 [Keychain setString:@"" forKey:@"passcode_lock_passcode"];
676             }
677             [self.passcodeLockViewController.tableView reloadData];
678             [self.settingsViewController.tableView reloadData];
679             [self dismissModalViewControllerAnimated:YES];
680         } else { 
681             [self incrementAndShowFailedAttemptsLabel];
682         }
683     }
684 }
685
686 @end