Clean up old UI.
[ADDED] Password strength to type cells. [FIXED] Lots of misc UI fixes. [ADDED] Footer links in pull-down.
This commit is contained in:
		@@ -1,41 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
 | 
			
		||||
 *
 | 
			
		||||
 * See the enclosed file LICENSE for license information (LGPLv3). If you did
 | 
			
		||||
 * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 *
 | 
			
		||||
 * @author   Maarten Billemont <lhunath@lyndir.com>
 | 
			
		||||
 * @license  http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//  MPAppViewController
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 2012-08-31.
 | 
			
		||||
//  Copyright 2012 lhunath (Maarten Billemont). All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import "MPAppViewController.h"
 | 
			
		||||
 | 
			
		||||
@implementation MPAppViewController {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)gorillas:(UIButton *)sender {
 | 
			
		||||
 | 
			
		||||
    MPCheckpoint( MPCheckpointApp, @{
 | 
			
		||||
            @"app" : @"gorillas"
 | 
			
		||||
    } );
 | 
			
		||||
 | 
			
		||||
    [UIApp openURL:[NSURL URLWithString:@"http://itunes.apple.com/app/lyndir/gorillas/id302275459?mt=8"]];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)deblock:(UIButton *)sender {
 | 
			
		||||
 | 
			
		||||
    MPCheckpoint( MPCheckpointApp, @{
 | 
			
		||||
            @"app" : @"deblock"
 | 
			
		||||
    } );
 | 
			
		||||
 | 
			
		||||
    [UIApp openURL:[NSURL URLWithString:@"http://itunes.apple.com/app/lyndir/deblock/id325058485?mt=8"]];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
 | 
			
		||||
 *
 | 
			
		||||
 * See the enclosed file LICENSE for license information (LGPLv3). If you did
 | 
			
		||||
 * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 *
 | 
			
		||||
 * @author   Maarten Billemont <lhunath@lyndir.com>
 | 
			
		||||
 * @license  http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//  MPAppsViewController
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 2012-08-31.
 | 
			
		||||
//  Copyright 2012 lhunath (Maarten Billemont). All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
 | 
			
		||||
@interface MPAppsViewController : UIViewController<UIPageViewControllerDataSource, UIPageViewControllerDelegate>
 | 
			
		||||
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIImageView *pagePositionView;
 | 
			
		||||
 | 
			
		||||
- (IBAction)exit;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,117 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
 | 
			
		||||
 *
 | 
			
		||||
 * See the enclosed file LICENSE for license information (LGPLv3). If you did
 | 
			
		||||
 * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 *
 | 
			
		||||
 * @author   Maarten Billemont <lhunath@lyndir.com>
 | 
			
		||||
 * @license  http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//  MPAppsViewController
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 2012-08-31.
 | 
			
		||||
//  Copyright 2012 lhunath (Maarten Billemont). All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import "MPAppsViewController.h"
 | 
			
		||||
 | 
			
		||||
@interface MPAppsViewController()
 | 
			
		||||
 | 
			
		||||
@property(nonatomic, strong) NSMutableArray *pageVCs;
 | 
			
		||||
@property(nonatomic, strong) UIPageViewController *pageViewController;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
@implementation MPAppsViewController {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@synthesize pagePositionView = _pagePositionView;
 | 
			
		||||
@synthesize pageVCs = _pageVCs;
 | 
			
		||||
@synthesize pageViewController = _pageViewController;
 | 
			
		||||
 | 
			
		||||
- (void)viewDidLoad {
 | 
			
		||||
 | 
			
		||||
    self.pageVCs = [NSMutableArray array];
 | 
			
		||||
    UIViewController *vc;
 | 
			
		||||
    @try {
 | 
			
		||||
        for (NSUInteger p = 0;
 | 
			
		||||
             (vc = [self.storyboard instantiateViewControllerWithIdentifier:PearlString( @"MPAppViewController_%lu", (long)p )]);
 | 
			
		||||
             ++p)
 | 
			
		||||
            [self.pageVCs addObject:vc];
 | 
			
		||||
    }
 | 
			
		||||
    @catch (NSException *e) {
 | 
			
		||||
        if (![e.name isEqualToString:NSInvalidArgumentException])
 | 
			
		||||
            [e raise];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
 | 
			
		||||
                                                              navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
 | 
			
		||||
                                                                            options:nil];
 | 
			
		||||
    self.pageViewController.dataSource = self;
 | 
			
		||||
    self.pageViewController.delegate = self;
 | 
			
		||||
    self.pageViewController.view.frame = CGRectFromOriginWithSize( CGPointZero, self.pagePositionView.bounds.size );
 | 
			
		||||
    [self addChildViewController:self.pageViewController];
 | 
			
		||||
    [self.pagePositionView addSubview:self.pageViewController.view];
 | 
			
		||||
    [self.pageViewController didMoveToParentViewController:self];
 | 
			
		||||
 | 
			
		||||
    [super viewDidLoad];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)viewWillAppear:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    [UIApp setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
 | 
			
		||||
    MPCheckpoint( MPCheckpointApps, nil );
 | 
			
		||||
 | 
			
		||||
    [self.pageViewController setViewControllers:@[ (self.pageVCs)[1] ] direction:UIPageViewControllerNavigationDirectionForward
 | 
			
		||||
                                       animated:NO completion:nil];
 | 
			
		||||
 | 
			
		||||
    [super viewWillAppear:animated];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)viewDidAppear:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    [self.pageViewController setViewControllers:@[ (self.pageVCs)[0] ] direction:UIPageViewControllerNavigationDirectionForward
 | 
			
		||||
                                       animated:YES completion:nil];
 | 
			
		||||
 | 
			
		||||
    [super viewDidAppear:animated];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)viewWillDisappear:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    [UIApp setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
 | 
			
		||||
 | 
			
		||||
    [super viewWillDisappear:animated];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
 | 
			
		||||
 | 
			
		||||
    return UIInterfaceOrientationPortrait;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL)shouldAutorotate {
 | 
			
		||||
 | 
			
		||||
    return NO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
 | 
			
		||||
      viewControllerBeforeViewController:(UIViewController *)viewController {
 | 
			
		||||
 | 
			
		||||
    NSUInteger vcIndex = [self.pageVCs indexOfObject:viewController];
 | 
			
		||||
    return (self.pageVCs)[(vcIndex + [self.pageVCs count] - 1) % self.pageVCs.count];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
 | 
			
		||||
       viewControllerAfterViewController:(UIViewController *)viewController {
 | 
			
		||||
 | 
			
		||||
    NSUInteger vcIndex = [self.pageVCs indexOfObject:viewController];
 | 
			
		||||
    return (self.pageVCs)[(vcIndex + 1) % self.pageVCs.count];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)exit {
 | 
			
		||||
 | 
			
		||||
    [self dismissViewControllerAnimated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -206,13 +206,11 @@ const long MPAvatarAdd = 10000;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (self.mode) {
 | 
			
		||||
 | 
			
		||||
            case MPAvatarModeLowered: {
 | 
			
		||||
 | 
			
		||||
                self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height;
 | 
			
		||||
                self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultLow;
 | 
			
		||||
                self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow;
 | 
			
		||||
                self.nameToCenterConstraint.priority = UILayoutPriorityDefaultLow;
 | 
			
		||||
                [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height];
 | 
			
		||||
                [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                self.nameContainer.alpha = self.visibility;
 | 
			
		||||
                self.nameContainer.backgroundColor = [UIColor clearColor];
 | 
			
		||||
                self.avatarImageView.alpha = self.visibility / 0.7f + 0.3f;
 | 
			
		||||
@@ -220,10 +218,10 @@ const long MPAvatarAdd = 10000;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case MPAvatarModeRaisedButInactive: {
 | 
			
		||||
                self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height;
 | 
			
		||||
                self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultHigh;
 | 
			
		||||
                self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow;
 | 
			
		||||
                self.nameToCenterConstraint.priority = UILayoutPriorityDefaultLow;
 | 
			
		||||
                [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height];
 | 
			
		||||
                [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                self.nameContainer.alpha = self.visibility;
 | 
			
		||||
                self.nameContainer.backgroundColor = [UIColor clearColor];
 | 
			
		||||
                self.avatarImageView.alpha = 0;
 | 
			
		||||
@@ -231,10 +229,10 @@ const long MPAvatarAdd = 10000;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case MPAvatarModeRaisedAndActive: {
 | 
			
		||||
                self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height;
 | 
			
		||||
                self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultHigh;
 | 
			
		||||
                self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow;
 | 
			
		||||
                self.nameToCenterConstraint.priority = UILayoutPriorityDefaultHigh;
 | 
			
		||||
                [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height];
 | 
			
		||||
                [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                self.nameContainer.alpha = self.visibility;
 | 
			
		||||
                self.nameContainer.backgroundColor = [UIColor blackColor];
 | 
			
		||||
                self.avatarImageView.alpha = 1;
 | 
			
		||||
@@ -242,10 +240,10 @@ const long MPAvatarAdd = 10000;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case MPAvatarModeRaisedAndHidden: {
 | 
			
		||||
                self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height;
 | 
			
		||||
                self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultHigh;
 | 
			
		||||
                self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow;
 | 
			
		||||
                self.nameToCenterConstraint.priority = UILayoutPriorityDefaultHigh;
 | 
			
		||||
                [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height];
 | 
			
		||||
                [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                self.nameContainer.alpha = 0;
 | 
			
		||||
                self.nameContainer.backgroundColor = [UIColor blackColor];
 | 
			
		||||
                self.avatarImageView.alpha = 0;
 | 
			
		||||
@@ -253,20 +251,16 @@ const long MPAvatarAdd = 10000;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case MPAvatarModeRaisedAndMinimized: {
 | 
			
		||||
                self.avatarSizeConstraint.constant = 36;
 | 
			
		||||
                self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultLow;
 | 
			
		||||
                self.avatarToTopConstraint.priority = UILayoutPriorityDefaultHigh;
 | 
			
		||||
                self.nameToCenterConstraint.priority = UILayoutPriorityDefaultHigh;
 | 
			
		||||
                [self.avatarSizeConstraint layoutWithConstant:36];
 | 
			
		||||
                [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                self.nameContainer.alpha = 0;
 | 
			
		||||
                self.nameContainer.backgroundColor = [UIColor blackColor];
 | 
			
		||||
                self.avatarImageView.alpha = 1;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        [self.avatarSizeConstraint apply];
 | 
			
		||||
        [self.avatarRaisedConstraint apply];
 | 
			
		||||
        [self.avatarToTopConstraint apply];
 | 
			
		||||
        [self.nameToCenterConstraint apply];
 | 
			
		||||
 | 
			
		||||
        // Avatar minimized.
 | 
			
		||||
        if (self.mode == MPAvatarModeRaisedAndMinimized)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
 | 
			
		||||
 *
 | 
			
		||||
 * See the enclosed file LICENSE for license information (LGPLv3). If you did
 | 
			
		||||
 * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 *
 | 
			
		||||
 * @author   Maarten Billemont <lhunath@lyndir.com>
 | 
			
		||||
 * @license  http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//  MPElementListAllViewController
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 2013-01-31.
 | 
			
		||||
//  Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
 | 
			
		||||
#import "MPElementListController.h"
 | 
			
		||||
 | 
			
		||||
@interface MPElementListAllViewController : MPElementListController
 | 
			
		||||
 | 
			
		||||
- (IBAction)close:(id)sender;
 | 
			
		||||
- (IBAction)add:(id)sender;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,188 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
 | 
			
		||||
 *
 | 
			
		||||
 * See the enclosed file LICENSE for license information (LGPLv3). If you did
 | 
			
		||||
 * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 *
 | 
			
		||||
 * @author   Maarten Billemont <lhunath@lyndir.com>
 | 
			
		||||
 * @license  http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//  MPElementListAllViewController
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 2013-01-31.
 | 
			
		||||
//  Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import "MPElementListAllViewController.h"
 | 
			
		||||
#import "MPiOSAppDelegate.h"
 | 
			
		||||
#import "MPAppDelegate_Store.h"
 | 
			
		||||
 | 
			
		||||
#define MPElementUpgradeOldContentKey @"MPElementUpgradeOldContentKey"
 | 
			
		||||
#define MPElementUpgradeNewContentKey @"MPElementUpgradeNewContentKey"
 | 
			
		||||
 | 
			
		||||
@implementation MPElementListAllViewController
 | 
			
		||||
 | 
			
		||||
- (BOOL)prefersStatusBarHidden {
 | 
			
		||||
 | 
			
		||||
    return NO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (UIStatusBarStyle)preferredStatusBarStyle {
 | 
			
		||||
 | 
			
		||||
    return UIStatusBarStyleLightContent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)viewWillAppear:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    [super viewWillAppear:animated];
 | 
			
		||||
 | 
			
		||||
    if ([self.filter isEqualToString:MPElementListFilterNone]) {
 | 
			
		||||
        self.navigationItem.title = @"All Sites";
 | 
			
		||||
        self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
 | 
			
		||||
                initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add:)];
 | 
			
		||||
    }
 | 
			
		||||
    else if ([self.filter isEqualToString:MPElementListFilterOutdated]) {
 | 
			
		||||
        self.navigationItem.title = @"Outdated";
 | 
			
		||||
        self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
 | 
			
		||||
                initWithTitle:@"Upgrade All" style:UIBarButtonItemStyleBordered target:self action:@selector(upgradeAll:)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [self updateData];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)close:(id)sender {
 | 
			
		||||
 | 
			
		||||
    [self dismissViewControllerAnimated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)add:(id)sender {
 | 
			
		||||
 | 
			
		||||
    [PearlAlert showAlertWithTitle:@"Add Site" message:nil viewStyle:UIAlertViewStylePlainTextInput initAlert:nil
 | 
			
		||||
                 tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                     if (alert.cancelButtonIndex == buttonIndex)
 | 
			
		||||
                         return;
 | 
			
		||||
 | 
			
		||||
                     __weak MPElementListAllViewController *wSelf = self;
 | 
			
		||||
                     [[MPiOSAppDelegate get] addElementNamed:[alert textFieldAtIndex:0].text completion:^(MPElementEntity *element) {
 | 
			
		||||
                         if (element)
 | 
			
		||||
                             PearlMainQueue( ^{
 | 
			
		||||
                                 [wSelf.delegate didSelectElement:element];
 | 
			
		||||
                                 [wSelf close:nil];
 | 
			
		||||
                             } );
 | 
			
		||||
                     }];
 | 
			
		||||
                 }
 | 
			
		||||
                       cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonOkay, nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)upgradeAll:(id)sender {
 | 
			
		||||
 | 
			
		||||
    [PearlAlert showAlertWithTitle:@"Upgrading All Sites"
 | 
			
		||||
                           message:@"You are about to upgrade all outdated sites.  This will cause passwords to change.  "
 | 
			
		||||
                                           @"Afterwards, you can get an overview of the changes."
 | 
			
		||||
                         viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:
 | 
			
		||||
            ^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                if (buttonIndex == [alert cancelButtonIndex])
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                PearlOverlay *activity = [PearlOverlay showProgressOverlayWithTitle:@"Upgrading Sites"];
 | 
			
		||||
                [self performUpgradeAllWithCompletion:^(BOOL success, NSDictionary *changes) {
 | 
			
		||||
                    dispatch_async( dispatch_get_main_queue(), ^{
 | 
			
		||||
                        [self showUpgradeChanges:changes];
 | 
			
		||||
                        [activity cancelOverlayAnimated:YES];
 | 
			
		||||
                    } );
 | 
			
		||||
                }];
 | 
			
		||||
            }          cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)performUpgradeAllWithCompletion:(void (^)(BOOL success, NSDictionary *changes))completion {
 | 
			
		||||
 | 
			
		||||
    [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
 | 
			
		||||
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
 | 
			
		||||
        fetchRequest.fetchBatchSize = 20;
 | 
			
		||||
 | 
			
		||||
        NSError *error = nil;
 | 
			
		||||
        NSArray *elements = [moc executeFetchRequest:fetchRequest error:&error];
 | 
			
		||||
        if (!elements) {
 | 
			
		||||
            err(@"Failed to fetch outdated sites for upgrade: %@", error);
 | 
			
		||||
            completion( NO, nil );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        MPKey *key = [MPAppDelegate_Shared get].key;
 | 
			
		||||
        NSMutableDictionary *elementChanges = [NSMutableDictionary dictionaryWithCapacity:[elements count]];
 | 
			
		||||
        for (MPElementEntity *element in elements) {
 | 
			
		||||
            id oldContent = [element.algorithm resolveContentForElement:element usingKey:key];
 | 
			
		||||
            [element migrateExplicitly:YES];
 | 
			
		||||
            id newContent = [element.algorithm resolveContentForElement:element usingKey:key];
 | 
			
		||||
 | 
			
		||||
            if (!(element.type & MPElementFeatureDevicePrivate) && (!oldContent || ![oldContent isEqual:newContent]))
 | 
			
		||||
                elementChanges[element.name] = @{
 | 
			
		||||
                        MPElementUpgradeOldContentKey : oldContent,
 | 
			
		||||
                        MPElementUpgradeNewContentKey : newContent,
 | 
			
		||||
                };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [moc saveToStore];
 | 
			
		||||
        completion( YES, elementChanges );
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)showUpgradeChanges:(NSDictionary *)changes {
 | 
			
		||||
 | 
			
		||||
    if (![changes count])
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    NSMutableString *formattedChanges = [NSMutableString new];
 | 
			
		||||
    for (NSString *changedElementName in changes) {
 | 
			
		||||
        NSDictionary *elementChanges = changes[changedElementName];
 | 
			
		||||
        id oldContent = elementChanges[MPElementUpgradeOldContentKey];
 | 
			
		||||
        id newContent = elementChanges[MPElementUpgradeNewContentKey];
 | 
			
		||||
        [formattedChanges appendFormat:@"%@: %@ -> %@\n", changedElementName, oldContent, newContent];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [PearlAlert showAlertWithTitle:@"Sites Upgraded"
 | 
			
		||||
                           message:PearlString( @"This upgrade has caused %lu passwords to change.\n"
 | 
			
		||||
                                   @"To make updating the actual passwords of these accounts easier, "
 | 
			
		||||
                                   @"you can email a summary of these changes to yourself.", (unsigned long)[changes count] )
 | 
			
		||||
                         viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
        if (buttonIndex == [alert cancelButtonIndex])
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        [PearlEMail sendEMailTo:nil fromVC:self subject:@"[Master Password] Upgrade Changes" body:formattedChanges];
 | 
			
		||||
    }                  cancelTitle:@"Don't Email" otherTitles:@"Send Email", nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSFetchedResultsController *)fetchedResultsControllerByUses {
 | 
			
		||||
 | 
			
		||||
    return nil;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)configureFetchRequest:(NSFetchRequest *)fetchRequest {
 | 
			
		||||
 | 
			
		||||
    fetchRequest.fetchBatchSize = 10;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
 | 
			
		||||
 | 
			
		||||
    return nil;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
 | 
			
		||||
 | 
			
		||||
    return nil;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    [super tableView:tableView didSelectRowAtIndexPath:indexPath];
 | 
			
		||||
    [self close:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,253 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
 | 
			
		||||
	<data>
 | 
			
		||||
		<int key="IBDocument.SystemTarget">1552</int>
 | 
			
		||||
		<string key="IBDocument.SystemVersion">12D78</string>
 | 
			
		||||
		<string key="IBDocument.InterfaceBuilderVersion">3084</string>
 | 
			
		||||
		<string key="IBDocument.AppKitVersion">1187.37</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>IBUITableViewCell</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="IBUITableViewCell" id="1072502652">
 | 
			
		||||
				<reference key="NSNextResponder"/>
 | 
			
		||||
				<int key="NSvFlags">1280</int>
 | 
			
		||||
				<array class="NSMutableArray" key="NSSubviews">
 | 
			
		||||
					<object class="IBUIView" id="70825627">
 | 
			
		||||
						<reference key="NSNextResponder" ref="1072502652"/>
 | 
			
		||||
						<int key="NSvFlags">1280</int>
 | 
			
		||||
						<array class="NSMutableArray" key="NSSubviews">
 | 
			
		||||
							<object class="IBUILabel" id="169671678">
 | 
			
		||||
								<reference key="NSNextResponder" ref="70825627"/>
 | 
			
		||||
								<int key="NSvFlags">1280</int>
 | 
			
		||||
								<object class="NSPSMatrix" key="NSFrameMatrix"/>
 | 
			
		||||
								<string key="NSFrame">{{10, 4}, {38, 22}}</string>
 | 
			
		||||
								<reference key="NSSuperview" ref="70825627"/>
 | 
			
		||||
								<reference key="NSNextKeyView" ref="35578451"/>
 | 
			
		||||
								<object class="NSColor" key="IBUIBackgroundColor" id="801193159">
 | 
			
		||||
									<int key="NSColorSpace">3</int>
 | 
			
		||||
									<bytes key="NSWhite">MCAwAA</bytes>
 | 
			
		||||
								</object>
 | 
			
		||||
								<bool key="IBUIOpaque">NO</bool>
 | 
			
		||||
								<bool key="IBUIClipsSubviews">YES</bool>
 | 
			
		||||
								<int key="IBUIContentMode">7</int>
 | 
			
		||||
								<bool key="IBUIMultipleTouchEnabled">YES</bool>
 | 
			
		||||
								<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
 | 
			
		||||
								<string key="IBUIText">Title</string>
 | 
			
		||||
								<object class="NSColor" key="IBUITextColor">
 | 
			
		||||
									<int key="NSColorSpace">3</int>
 | 
			
		||||
									<bytes key="NSWhite">MQA</bytes>
 | 
			
		||||
								</object>
 | 
			
		||||
								<object class="NSColor" key="IBUIHighlightedColor" id="748798155">
 | 
			
		||||
									<int key="NSColorSpace">1</int>
 | 
			
		||||
									<bytes key="NSRGB">MSAxIDEAA</bytes>
 | 
			
		||||
								</object>
 | 
			
		||||
								<int key="IBUIBaselineAdjustment">0</int>
 | 
			
		||||
								<object class="IBUIFontDescription" key="IBUIFontDescription">
 | 
			
		||||
									<int key="type">2</int>
 | 
			
		||||
									<double key="pointSize">18</double>
 | 
			
		||||
								</object>
 | 
			
		||||
								<object class="NSFont" key="IBUIFont">
 | 
			
		||||
									<string key="NSName">Helvetica-Bold</string>
 | 
			
		||||
									<double key="NSSize">18</double>
 | 
			
		||||
									<int key="NSfFlags">16</int>
 | 
			
		||||
								</object>
 | 
			
		||||
								<bool key="IBUIAdjustsFontSizeToFit">NO</bool>
 | 
			
		||||
							</object>
 | 
			
		||||
							<object class="IBUILabel" id="35578451">
 | 
			
		||||
								<reference key="NSNextResponder" ref="70825627"/>
 | 
			
		||||
								<int key="NSvFlags">1280</int>
 | 
			
		||||
								<object class="NSPSMatrix" key="NSFrameMatrix"/>
 | 
			
		||||
								<string key="NSFrame">{{10, 26}, {47, 18}}</string>
 | 
			
		||||
								<reference key="NSSuperview" ref="70825627"/>
 | 
			
		||||
								<reference key="IBUIBackgroundColor" ref="801193159"/>
 | 
			
		||||
								<bool key="IBUIOpaque">NO</bool>
 | 
			
		||||
								<bool key="IBUIClipsSubviews">YES</bool>
 | 
			
		||||
								<int key="IBUIContentMode">7</int>
 | 
			
		||||
								<bool key="IBUIMultipleTouchEnabled">YES</bool>
 | 
			
		||||
								<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
 | 
			
		||||
								<string key="IBUIText">Subtitle</string>
 | 
			
		||||
								<object class="NSColor" key="IBUITextColor">
 | 
			
		||||
									<int key="NSColorSpace">3</int>
 | 
			
		||||
									<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
 | 
			
		||||
								</object>
 | 
			
		||||
								<reference key="IBUIHighlightedColor" ref="748798155"/>
 | 
			
		||||
								<int key="IBUIBaselineAdjustment">0</int>
 | 
			
		||||
								<object class="IBUIFontDescription" key="IBUIFontDescription">
 | 
			
		||||
									<int key="type">1</int>
 | 
			
		||||
									<double key="pointSize">14</double>
 | 
			
		||||
								</object>
 | 
			
		||||
								<object class="NSFont" key="IBUIFont">
 | 
			
		||||
									<string key="NSName">Helvetica</string>
 | 
			
		||||
									<double key="NSSize">14</double>
 | 
			
		||||
									<int key="NSfFlags">16</int>
 | 
			
		||||
								</object>
 | 
			
		||||
								<bool key="IBUIAdjustsFontSizeToFit">NO</bool>
 | 
			
		||||
							</object>
 | 
			
		||||
						</array>
 | 
			
		||||
						<object class="NSPSMatrix" key="NSFrameMatrix"/>
 | 
			
		||||
						<string key="NSFrameSize">{320, 47}</string>
 | 
			
		||||
						<reference key="NSSuperview" ref="1072502652"/>
 | 
			
		||||
						<reference key="NSNextKeyView" ref="169671678"/>
 | 
			
		||||
						<reference key="IBUIBackgroundColor" ref="801193159"/>
 | 
			
		||||
						<bool key="IBUIOpaque">NO</bool>
 | 
			
		||||
						<bool key="IBUIClipsSubviews">YES</bool>
 | 
			
		||||
						<int key="IBUIContentMode">4</int>
 | 
			
		||||
						<bool key="IBUIMultipleTouchEnabled">YES</bool>
 | 
			
		||||
						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
 | 
			
		||||
					</object>
 | 
			
		||||
				</array>
 | 
			
		||||
				<object class="NSPSMatrix" key="NSFrameMatrix"/>
 | 
			
		||||
				<string key="NSFrameSize">{320, 48}</string>
 | 
			
		||||
				<reference key="NSSuperview"/>
 | 
			
		||||
				<reference key="NSNextKeyView" ref="70825627"/>
 | 
			
		||||
				<object class="NSColor" key="IBUIBackgroundColor">
 | 
			
		||||
					<int key="NSColorSpace">3</int>
 | 
			
		||||
					<bytes key="NSWhite">MAA</bytes>
 | 
			
		||||
				</object>
 | 
			
		||||
				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
 | 
			
		||||
				<bool key="IBUIHidesAccessoryWhenEditing">NO</bool>
 | 
			
		||||
				<int key="IBUIIndentationLevel">1</int>
 | 
			
		||||
				<float key="IBUIIndentationWidth">0.0</float>
 | 
			
		||||
				<reference key="IBUIContentView" ref="70825627"/>
 | 
			
		||||
				<string key="IBUIReuseIdentifier">MPElementListCell</string>
 | 
			
		||||
				<integer value="3" key="IBUIStyle"/>
 | 
			
		||||
				<reference key="IBUITextLabel" ref="169671678"/>
 | 
			
		||||
				<reference key="IBUIDetailTextLabel" ref="35578451"/>
 | 
			
		||||
			</object>
 | 
			
		||||
			<object class="IBUIImageView" id="410525493">
 | 
			
		||||
				<nil key="NSNextResponder"/>
 | 
			
		||||
				<int key="NSvFlags">274</int>
 | 
			
		||||
				<string key="NSFrameSize">{320, 48}</string>
 | 
			
		||||
				<string key="NSReuseIdentifierKey">_NS:9</string>
 | 
			
		||||
				<reference key="IBUIBackgroundColor" ref="801193159"/>
 | 
			
		||||
				<bool key="IBUIUserInteractionEnabled">NO</bool>
 | 
			
		||||
				<string key="IBUIContentStretch">{{0.10000000000000001, 0.10000000000000001}, {0.79999999999999982, 0.79999999999999982}}</string>
 | 
			
		||||
				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
 | 
			
		||||
				<object class="NSCustomResource" key="IBUIImage">
 | 
			
		||||
					<string key="NSClassName">NSImage</string>
 | 
			
		||||
					<string key="NSResourceName">ui_list_middle.png</string>
 | 
			
		||||
				</object>
 | 
			
		||||
			</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="1072502652"/>
 | 
			
		||||
					</object>
 | 
			
		||||
					<int key="connectionID">11</int>
 | 
			
		||||
				</object>
 | 
			
		||||
				<object class="IBConnectionRecord">
 | 
			
		||||
					<object class="IBCocoaTouchOutletConnection" key="connection">
 | 
			
		||||
						<string key="label">backgroundView</string>
 | 
			
		||||
						<reference key="source" ref="1072502652"/>
 | 
			
		||||
						<reference key="destination" ref="410525493"/>
 | 
			
		||||
					</object>
 | 
			
		||||
					<int key="connectionID">10</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="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">4</int>
 | 
			
		||||
						<reference key="object" ref="1072502652"/>
 | 
			
		||||
						<array class="NSMutableArray" key="children">
 | 
			
		||||
							<reference ref="35578451"/>
 | 
			
		||||
							<reference ref="169671678"/>
 | 
			
		||||
						</array>
 | 
			
		||||
						<reference key="parent" ref="0"/>
 | 
			
		||||
					</object>
 | 
			
		||||
					<object class="IBObjectRecord">
 | 
			
		||||
						<int key="objectID">5</int>
 | 
			
		||||
						<reference key="object" ref="35578451"/>
 | 
			
		||||
						<reference key="parent" ref="1072502652"/>
 | 
			
		||||
					</object>
 | 
			
		||||
					<object class="IBObjectRecord">
 | 
			
		||||
						<int key="objectID">6</int>
 | 
			
		||||
						<reference key="object" ref="169671678"/>
 | 
			
		||||
						<reference key="parent" ref="1072502652"/>
 | 
			
		||||
					</object>
 | 
			
		||||
					<object class="IBObjectRecord">
 | 
			
		||||
						<int key="objectID">8</int>
 | 
			
		||||
						<reference key="object" ref="410525493"/>
 | 
			
		||||
						<reference key="parent" ref="0"/>
 | 
			
		||||
					</object>
 | 
			
		||||
				</array>
 | 
			
		||||
			</object>
 | 
			
		||||
			<dictionary class="NSMutableDictionary" key="flattenedProperties">
 | 
			
		||||
				<string key="-1.CustomClassName">UIViewController</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="4.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
 | 
			
		||||
				<reference key="4.IBUserGuides" ref="0"/>
 | 
			
		||||
				<boolean value="NO" key="4.showNotes"/>
 | 
			
		||||
				<string key="5.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
 | 
			
		||||
				<reference key="5.IBUserGuides" ref="0"/>
 | 
			
		||||
				<boolean value="NO" key="5.showNotes"/>
 | 
			
		||||
				<string key="6.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
 | 
			
		||||
				<reference key="6.IBUserGuides" ref="0"/>
 | 
			
		||||
				<boolean value="NO" key="6.showNotes"/>
 | 
			
		||||
				<string key="8.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">11</int>
 | 
			
		||||
		</object>
 | 
			
		||||
		<object class="IBClassDescriber" key="IBDocument.Classes"/>
 | 
			
		||||
		<int key="IBDocument.localizationMode">0</int>
 | 
			
		||||
		<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
 | 
			
		||||
		<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
 | 
			
		||||
		<int key="IBDocument.defaultPropertyAccessControl">3</int>
 | 
			
		||||
		<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
 | 
			
		||||
			<string key="NS.key.0">ui_list_middle.png</string>
 | 
			
		||||
			<string key="NS.object.0">{300, 34}</string>
 | 
			
		||||
		</object>
 | 
			
		||||
		<string key="IBCocoaTouchPluginVersion">2083</string>
 | 
			
		||||
	</data>
 | 
			
		||||
</archive>
 | 
			
		||||
@@ -1,21 +0,0 @@
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
 | 
			
		||||
#import "MPElementListDelegate.h"
 | 
			
		||||
 | 
			
		||||
#define MPElementListFilterNone @"MPElementListFilterNone"
 | 
			
		||||
#define MPElementListFilterOutdated @"MPElementListFilterOutdated"
 | 
			
		||||
 | 
			
		||||
@interface MPElementListController : UITableViewController<NSFetchedResultsControllerDelegate>
 | 
			
		||||
 | 
			
		||||
@property(weak, nonatomic) IBOutlet id<MPElementListDelegate> delegate;
 | 
			
		||||
@property(strong, nonatomic) NSString *filter;
 | 
			
		||||
 | 
			
		||||
@property(readonly) NSFetchedResultsController *fetchedResultsControllerByUses;
 | 
			
		||||
@property(readonly) NSFetchedResultsController *fetchedResultsControllerByLastUsed;
 | 
			
		||||
@property(readonly) NSDateFormatter *dateFormatter;
 | 
			
		||||
 | 
			
		||||
- (void)updateData;
 | 
			
		||||
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atTableIndexPath:(NSIndexPath *)indexPath;
 | 
			
		||||
- (void)customTableViewUpdates;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,279 +0,0 @@
 | 
			
		||||
#import "MPElementListController.h"
 | 
			
		||||
 | 
			
		||||
#import "MPAppDelegate_Store.h"
 | 
			
		||||
#import "MPiOSAppDelegate.h"
 | 
			
		||||
 | 
			
		||||
@interface MPElementListController()
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
@implementation MPElementListController {
 | 
			
		||||
 | 
			
		||||
    NSFetchedResultsController *_fetchedResultsControllerByUses;
 | 
			
		||||
    NSFetchedResultsController *_fetchedResultsControllerByLastUsed;
 | 
			
		||||
    NSDateFormatter *_dateFormatter;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)viewDidLoad {
 | 
			
		||||
 | 
			
		||||
    [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil
 | 
			
		||||
                                                       queue:[NSOperationQueue mainQueue] usingBlock:
 | 
			
		||||
            ^(NSNotification *note) {
 | 
			
		||||
                [self updateData];
 | 
			
		||||
            }];
 | 
			
		||||
 | 
			
		||||
    [super viewDidLoad];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSFetchedResultsController *)fetchedResultsControllerByLastUsed {
 | 
			
		||||
 | 
			
		||||
    NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must be accessed from the main thread.");
 | 
			
		||||
 | 
			
		||||
    if (!_fetchedResultsControllerByLastUsed) {
 | 
			
		||||
        NSManagedObjectContext *context = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
 | 
			
		||||
        if (!context)
 | 
			
		||||
            return nil;
 | 
			
		||||
 | 
			
		||||
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
 | 
			
		||||
        fetchRequest.sortDescriptors = @[ [[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector(lastUsed) ) ascending:NO] ];
 | 
			
		||||
        [self configureFetchRequest:fetchRequest];
 | 
			
		||||
        _fetchedResultsControllerByLastUsed = [[NSFetchedResultsController alloc]
 | 
			
		||||
                initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
 | 
			
		||||
        _fetchedResultsControllerByLastUsed.delegate = self;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return _fetchedResultsControllerByLastUsed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSFetchedResultsController *)fetchedResultsControllerByUses {
 | 
			
		||||
 | 
			
		||||
    NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must be accessed from the main thread.");
 | 
			
		||||
 | 
			
		||||
    if (!_fetchedResultsControllerByUses) {
 | 
			
		||||
        NSManagedObjectContext *context = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
 | 
			
		||||
        if (!context)
 | 
			
		||||
            return nil;
 | 
			
		||||
 | 
			
		||||
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
 | 
			
		||||
        fetchRequest.sortDescriptors = @[ [[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector(uses_) ) ascending:NO] ];
 | 
			
		||||
        [self configureFetchRequest:fetchRequest];
 | 
			
		||||
        _fetchedResultsControllerByUses = [[NSFetchedResultsController alloc]
 | 
			
		||||
                initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
 | 
			
		||||
        _fetchedResultsControllerByUses.delegate = self;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return _fetchedResultsControllerByUses;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)configureFetchRequest:(NSFetchRequest *)fetchRequest {
 | 
			
		||||
 | 
			
		||||
    fetchRequest.fetchLimit = 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSDateFormatter *)dateFormatter {
 | 
			
		||||
 | 
			
		||||
    if (!_dateFormatter)
 | 
			
		||||
        (_dateFormatter = [NSDateFormatter new]).dateStyle = NSDateFormatterShortStyle;
 | 
			
		||||
 | 
			
		||||
    return _dateFormatter;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)updateData {
 | 
			
		||||
 | 
			
		||||
    MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:self.fetchedResultsControllerByLastUsed.managedObjectContext];
 | 
			
		||||
    if (!activeUser) {
 | 
			
		||||
        _fetchedResultsControllerByLastUsed = nil;
 | 
			
		||||
        _fetchedResultsControllerByUses = nil;
 | 
			
		||||
        [self.tableView reloadData];
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Build predicate.
 | 
			
		||||
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user == %@", activeUser];
 | 
			
		||||
 | 
			
		||||
    // Add query predicate.
 | 
			
		||||
    UISearchBar *searchBar = self.searchDisplayController.searchBar;
 | 
			
		||||
    if (searchBar) {
 | 
			
		||||
        NSString *query = [searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
 | 
			
		||||
        if (!query)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
 | 
			
		||||
                @[ predicate, [NSPredicate predicateWithFormat:@"name BEGINSWITH[cd] %@", query] ]];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add filter predicate.
 | 
			
		||||
    if ([self.filter isEqualToString:MPElementListFilterOutdated])
 | 
			
		||||
        predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
 | 
			
		||||
                @[ [NSPredicate predicateWithFormat:@"requiresExplicitMigration_ == YES"], predicate ]];
 | 
			
		||||
 | 
			
		||||
    // Fetch
 | 
			
		||||
    NSError *error;
 | 
			
		||||
    self.fetchedResultsControllerByLastUsed.fetchRequest.predicate = predicate;
 | 
			
		||||
    self.fetchedResultsControllerByUses.fetchRequest.predicate = predicate;
 | 
			
		||||
    if (self.fetchedResultsControllerByLastUsed && ![self.fetchedResultsControllerByLastUsed performFetch:&error])
 | 
			
		||||
    err(@"Couldn't fetch elements: %@", error);
 | 
			
		||||
    if (self.fetchedResultsControllerByUses && ![self.fetchedResultsControllerByUses performFetch:&error])
 | 
			
		||||
    err(@"Couldn't fetch elements: %@", error);
 | 
			
		||||
 | 
			
		||||
    [self.tableView reloadData];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)customTableViewUpdates {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// See MP-14, also crashes easily on internal assertions etc..
 | 
			
		||||
//- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
 | 
			
		||||
//
 | 
			
		||||
//    [self.tableView beginUpdates];
 | 
			
		||||
//}
 | 
			
		||||
//
 | 
			
		||||
//- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
 | 
			
		||||
//       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
 | 
			
		||||
//
 | 
			
		||||
//    switch (type) {
 | 
			
		||||
//
 | 
			
		||||
//        case NSFetchedResultsChangeInsert:
 | 
			
		||||
//            [self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ]
 | 
			
		||||
//                                  withRowAnimation:UITableViewRowAnimationAutomatic];
 | 
			
		||||
//            break;
 | 
			
		||||
//
 | 
			
		||||
//        case NSFetchedResultsChangeDelete:
 | 
			
		||||
//            [self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
 | 
			
		||||
//                                  withRowAnimation:UITableViewRowAnimationAutomatic];
 | 
			
		||||
//            break;
 | 
			
		||||
//
 | 
			
		||||
//        case NSFetchedResultsChangeUpdate:
 | 
			
		||||
//            [self.tableView reloadRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
 | 
			
		||||
//                                  withRowAnimation:UITableViewRowAnimationAutomatic];
 | 
			
		||||
//            break;
 | 
			
		||||
//
 | 
			
		||||
//        case NSFetchedResultsChangeMove:
 | 
			
		||||
//            [self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
 | 
			
		||||
//                                  withRowAnimation:UITableViewRowAnimationAutomatic];
 | 
			
		||||
//            [self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ]
 | 
			
		||||
//                                  withRowAnimation:UITableViewRowAnimationAutomatic];
 | 
			
		||||
//            break;
 | 
			
		||||
//    }
 | 
			
		||||
//}
 | 
			
		||||
 | 
			
		||||
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
 | 
			
		||||
 | 
			
		||||
//    [self customTableViewUpdates];
 | 
			
		||||
//    [self.tableView endUpdates];
 | 
			
		||||
 | 
			
		||||
    [self.tableView reloadData];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 | 
			
		||||
 | 
			
		||||
    return 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 | 
			
		||||
 | 
			
		||||
    if (section == 0)
 | 
			
		||||
        return (NSInteger)[[[self.fetchedResultsControllerByLastUsed sections] lastObject] numberOfObjects];
 | 
			
		||||
 | 
			
		||||
    if (section == 1)
 | 
			
		||||
        return (NSInteger)[[[self.fetchedResultsControllerByUses sections] lastObject] numberOfObjects];
 | 
			
		||||
 | 
			
		||||
    Throw(@"Unsupported section: %ld", (long)section);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MPElementListCell"];
 | 
			
		||||
    if (!cell)
 | 
			
		||||
        cell = (UITableViewCell *)[[UIViewController alloc] initWithNibName:@"MPElementListCellView" bundle:nil].view;
 | 
			
		||||
 | 
			
		||||
    [self configureCell:cell inTableView:tableView atTableIndexPath:indexPath];
 | 
			
		||||
 | 
			
		||||
    return cell;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atTableIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    MPElementEntity *element = [self elementForTableIndexPath:indexPath];
 | 
			
		||||
 | 
			
		||||
    cell.textLabel.text = element.name;
 | 
			
		||||
    cell.detailTextLabel.text = PearlString( @"%lu views, last on %@: %@",
 | 
			
		||||
            (unsigned long)element.uses, [self.dateFormatter stringFromDate:element.lastUsed],
 | 
			
		||||
                                            [element.algorithm shortNameOfType:element.type] );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSIndexPath *)tableIndexPathForFetchController:(NSFetchedResultsController *)fetchedResultsController
 | 
			
		||||
                                        indexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    if (fetchedResultsController == self.fetchedResultsControllerByLastUsed)
 | 
			
		||||
        return [NSIndexPath indexPathForRow:indexPath.row inSection:0];
 | 
			
		||||
    if (fetchedResultsController == self.fetchedResultsControllerByUses)
 | 
			
		||||
        return [NSIndexPath indexPathForRow:indexPath.row inSection:1];
 | 
			
		||||
 | 
			
		||||
    Throw(@"Unknown fetched results controller: %@, for index path: %@", fetchedResultsController, indexPath);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSIndexPath *)fetchedIndexPathForTableIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    return [NSIndexPath indexPathForRow:indexPath.row inSection:0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (MPElementEntity *)elementForTableIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    if (indexPath.section == 0)
 | 
			
		||||
        return [self.fetchedResultsControllerByLastUsed objectAtIndexPath:[self fetchedIndexPathForTableIndexPath:indexPath]];
 | 
			
		||||
 | 
			
		||||
    if (indexPath.section == 1)
 | 
			
		||||
        return [self.fetchedResultsControllerByUses objectAtIndexPath:[self fetchedIndexPathForTableIndexPath:indexPath]];
 | 
			
		||||
 | 
			
		||||
    Throw(@"Unsupported section: %ld", (long)indexPath.section);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    [self.delegate didSelectElement:[self elementForTableIndexPath:indexPath]];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
 | 
			
		||||
 | 
			
		||||
    if (section == 0)
 | 
			
		||||
        return @"Most Recently Used";
 | 
			
		||||
 | 
			
		||||
    if (section == 1)
 | 
			
		||||
        return @"Most Commonly Used";
 | 
			
		||||
 | 
			
		||||
    Throw(@"Unsupported section: %ld", (long)section);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
 | 
			
		||||
 | 
			
		||||
    return @[ @"recency", @"uses" ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
 | 
			
		||||
 | 
			
		||||
    return index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
 | 
			
		||||
forRowAtIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    if (editingStyle == UITableViewCellEditingStyleDelete) {
 | 
			
		||||
        NSManagedObjectID *elementOID = [self elementForTableIndexPath:indexPath].objectID;
 | 
			
		||||
        [MPiOSAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
 | 
			
		||||
            MPElementEntity *element = [MPElementEntity existingObjectWithID:elementOID inContext:context];
 | 
			
		||||
            if (!element)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            inf(@"Deleting element: %@", element.name);
 | 
			
		||||
            [context deleteObject:element];
 | 
			
		||||
            [context saveToStore];
 | 
			
		||||
 | 
			
		||||
            MPCheckpoint( MPCheckpointDeleteElement, @{
 | 
			
		||||
                    @"type"    : NilToNSNull(element.typeName),
 | 
			
		||||
                    @"version" : @(element.version)
 | 
			
		||||
            } );
 | 
			
		||||
        }];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
 | 
			
		||||
 *
 | 
			
		||||
 * See the enclosed file LICENSE for license information (LGPLv3). If you did
 | 
			
		||||
 * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 *
 | 
			
		||||
 * @author   Maarten Billemont <lhunath@lyndir.com>
 | 
			
		||||
 * @license  http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//  MPElementListDelegate
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 2013-01-31.
 | 
			
		||||
//  Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import "MPElementEntity.h"
 | 
			
		||||
 | 
			
		||||
@protocol MPElementListDelegate<NSObject>
 | 
			
		||||
 | 
			
		||||
- (void)didSelectElement:(MPElementEntity *)element;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,19 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  MPSearchDelegate.h
 | 
			
		||||
//  MasterPassword
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 04/01/12.
 | 
			
		||||
//  Copyright (c) 2012 Lyndir. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
#import "MPElementListController.h"
 | 
			
		||||
 | 
			
		||||
@interface MPElementListSearchController : MPElementListController<UISearchBarDelegate, UISearchDisplayDelegate>
 | 
			
		||||
 | 
			
		||||
@property(strong, nonatomic) UILabel *tipView;
 | 
			
		||||
 | 
			
		||||
@property(strong, nonatomic) IBOutlet UISearchDisplayController *searchDisplayController;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *searchTipContainer;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,247 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  MPSearchDelegate.m
 | 
			
		||||
//  MasterPassword
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 04/01/12.
 | 
			
		||||
//  Copyright (c) 2012 Lyndir. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import "MPElementListSearchController.h"
 | 
			
		||||
#import "MPMainViewController.h"
 | 
			
		||||
#import "MPiOSAppDelegate.h"
 | 
			
		||||
#import "MPAppDelegate_Store.h"
 | 
			
		||||
 | 
			
		||||
@interface MPElementListSearchController()
 | 
			
		||||
 | 
			
		||||
@property(nonatomic) BOOL newSiteSectionWasNeeded;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
@implementation MPElementListSearchController
 | 
			
		||||
 | 
			
		||||
@synthesize searchDisplayController;
 | 
			
		||||
 | 
			
		||||
- (id)init {
 | 
			
		||||
 | 
			
		||||
    if (!(self = [super init]))
 | 
			
		||||
        return nil;
 | 
			
		||||
 | 
			
		||||
    self.tipView = [[UILabel alloc] initWithFrame:CGRectMake( 0, 0, 320, 170 )];
 | 
			
		||||
    self.tipView.textAlignment = NSTextAlignmentCenter;
 | 
			
		||||
    self.tipView.backgroundColor = [UIColor clearColor];
 | 
			
		||||
    self.tipView.textColor = [UIColor lightTextColor];
 | 
			
		||||
    self.tipView.shadowColor = [UIColor blackColor];
 | 
			
		||||
    self.tipView.shadowOffset = CGSizeMake( 0, -1 );
 | 
			
		||||
    self.tipView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
 | 
			
		||||
                                    | UIViewAutoresizingFlexibleBottomMargin;
 | 
			
		||||
    self.tipView.numberOfLines = 0;
 | 
			
		||||
    self.tipView.font = [UIFont systemFontOfSize:14];
 | 
			
		||||
    self.tipView.text =
 | 
			
		||||
            @"Tip:\n"
 | 
			
		||||
                    @"Name your sites by their domain name:\n"
 | 
			
		||||
                    @"apple.com, twitter.com\n\n"
 | 
			
		||||
                    @"For email accounts, use the address:\n"
 | 
			
		||||
                    @"john@apple.com, john@gmail.com";
 | 
			
		||||
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)searchBarBookmarkButtonClicked:(UISearchBar *)searchBar {
 | 
			
		||||
 | 
			
		||||
    [((MPMainViewController *)self.delegate) performSegueWithIdentifier:@"MP_AllSites" sender:MPElementListFilterNone];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
 | 
			
		||||
 | 
			
		||||
    // Simulate a tap on the first visible row.
 | 
			
		||||
    UITableView *tableView = self.searchDisplayController.searchResultsTableView;
 | 
			
		||||
    for (NSInteger section = 0; section < [self numberOfSectionsInTableView:tableView]; ++section) {
 | 
			
		||||
 | 
			
		||||
        if (![self tableView:tableView numberOfRowsInSection:section])
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        [self tableView:tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
 | 
			
		||||
 | 
			
		||||
    controller.searchBar.text = @"";
 | 
			
		||||
 | 
			
		||||
    [UIView animateWithDuration:0.2f animations:^{
 | 
			
		||||
        self.searchTipContainer.alpha = 0;
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
 | 
			
		||||
 | 
			
		||||
    [self updateData];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
 | 
			
		||||
 | 
			
		||||
    controller.searchBar.prompt = nil;
 | 
			
		||||
    controller.searchBar.searchResultsButtonSelected = NO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView {
 | 
			
		||||
 | 
			
		||||
    tableView.backgroundColor = [UIColor blackColor];
 | 
			
		||||
    tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
 | 
			
		||||
    tableView.rowHeight = 48.0f;
 | 
			
		||||
 | 
			
		||||
    self.tableView = tableView;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
 | 
			
		||||
 | 
			
		||||
    [self updateData];
 | 
			
		||||
    return NO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)updateData {
 | 
			
		||||
 | 
			
		||||
    [super updateData];
 | 
			
		||||
 | 
			
		||||
    UISearchBar *searchBar = self.searchDisplayController.searchBar;
 | 
			
		||||
    CGRect searchBarFrame = searchBar.frame;
 | 
			
		||||
    [searchBar.superview enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
 | 
			
		||||
 | 
			
		||||
        if ([subview isKindOfClass:[UIControl class]] &&
 | 
			
		||||
            CGPointEqualToPoint(
 | 
			
		||||
                        CGPointDistanceBetweenCGPoints( searchBarFrame.origin, subview.frame.origin ),
 | 
			
		||||
                        CGPointMake( 0, searchBarFrame.size.height ) )) {
 | 
			
		||||
            dispatch_async( dispatch_get_main_queue(), ^{
 | 
			
		||||
                [self.tipView removeFromSuperview];
 | 
			
		||||
                [subview addSubview:self.tipView];
 | 
			
		||||
            } );
 | 
			
		||||
 | 
			
		||||
            *stop = YES;
 | 
			
		||||
        }
 | 
			
		||||
    }                           recurse:NO];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL)newSiteSectionNeeded {
 | 
			
		||||
 | 
			
		||||
    NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
 | 
			
		||||
    if (![query length])
 | 
			
		||||
        return NO;
 | 
			
		||||
 | 
			
		||||
    __block BOOL hasExactQueryMatch = NO;
 | 
			
		||||
    id<NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsControllerByUses sections] lastObject];
 | 
			
		||||
    [[sectionInfo objects] enumerateObjectsUsingBlock:^(id obj_, NSUInteger idx_, BOOL *stop_) {
 | 
			
		||||
        if ([[obj_ name] isEqualToString:query]) {
 | 
			
		||||
            hasExactQueryMatch = YES;
 | 
			
		||||
            *stop_ = YES;
 | 
			
		||||
        }
 | 
			
		||||
    }];
 | 
			
		||||
    if (hasExactQueryMatch)
 | 
			
		||||
        return NO;
 | 
			
		||||
 | 
			
		||||
    sectionInfo = [[self.fetchedResultsControllerByLastUsed sections] lastObject];
 | 
			
		||||
    [[sectionInfo objects] enumerateObjectsUsingBlock:^(id obj_, NSUInteger idx_, BOOL *stop_) {
 | 
			
		||||
        if ([[obj_ name] isEqualToString:query]) {
 | 
			
		||||
            hasExactQueryMatch = YES;
 | 
			
		||||
            *stop_ = YES;
 | 
			
		||||
        }
 | 
			
		||||
    }];
 | 
			
		||||
    if (hasExactQueryMatch)
 | 
			
		||||
        return NO;
 | 
			
		||||
 | 
			
		||||
    return YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)customTableViewUpdates {
 | 
			
		||||
 | 
			
		||||
    BOOL newSiteSectionIsNeeded = [self newSiteSectionNeeded];
 | 
			
		||||
    if (newSiteSectionIsNeeded && !self.newSiteSectionWasNeeded)
 | 
			
		||||
        [self.tableView insertSections:[NSIndexSet indexSetWithIndex:2]
 | 
			
		||||
                      withRowAnimation:UITableViewRowAnimationAutomatic];
 | 
			
		||||
    else if (!newSiteSectionIsNeeded && self.newSiteSectionWasNeeded)
 | 
			
		||||
        [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:2]
 | 
			
		||||
                      withRowAnimation:UITableViewRowAnimationAutomatic];
 | 
			
		||||
    self.newSiteSectionWasNeeded = newSiteSectionIsNeeded;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 | 
			
		||||
 | 
			
		||||
    NSInteger sectionCount = [super numberOfSectionsInTableView:tableView];
 | 
			
		||||
    if ([self newSiteSectionNeeded])
 | 
			
		||||
        ++sectionCount;
 | 
			
		||||
 | 
			
		||||
    return sectionCount;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 | 
			
		||||
 | 
			
		||||
    if (section < [super numberOfSectionsInTableView:tableView])
 | 
			
		||||
            // Section is one of super's sections.
 | 
			
		||||
        return [super tableView:tableView numberOfRowsInSection:section];
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atTableIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    if (indexPath.section < [super numberOfSectionsInTableView:tableView]) {
 | 
			
		||||
        // Section is one of super's sections.
 | 
			
		||||
        [super configureCell:cell inTableView:tableView atTableIndexPath:indexPath];
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // "New" section
 | 
			
		||||
    NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
 | 
			
		||||
    cell.textLabel.text = query;
 | 
			
		||||
    cell.detailTextLabel.text = PearlString( @"New site: %@",
 | 
			
		||||
    [MPAlgorithmDefault shortNameOfType:[[MPiOSAppDelegate get] activeUserForMainThread].defaultType] );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    if (indexPath.section < [super numberOfSectionsInTableView:tableView]) {
 | 
			
		||||
        // Section is one of super's sections.
 | 
			
		||||
        [super tableView:tableView didSelectRowAtIndexPath:indexPath];
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // "New" section.
 | 
			
		||||
    NSString *siteName
 | 
			
		||||
            = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
 | 
			
		||||
 | 
			
		||||
    [PearlAlert showAlertWithTitle:@"New Site"
 | 
			
		||||
                           message:PearlString( @"Do you want to create a new site named:\n%@", siteName )
 | 
			
		||||
                         viewStyle:UIAlertViewStyleDefault
 | 
			
		||||
                         initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
 | 
			
		||||
 | 
			
		||||
        if (buttonIndex == [alert cancelButtonIndex])
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        __weak MPElementListController *wSelf = self;
 | 
			
		||||
        [[MPiOSAppDelegate get] addElementNamed:siteName completion:^(MPElementEntity *element) {
 | 
			
		||||
            if (element)
 | 
			
		||||
                PearlMainQueue( ^{
 | 
			
		||||
                    [wSelf.delegate didSelectElement:element];
 | 
			
		||||
                } );
 | 
			
		||||
        }];
 | 
			
		||||
    }                  cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
 | 
			
		||||
 | 
			
		||||
    if (section < [super numberOfSectionsInTableView:tableView])
 | 
			
		||||
            // Section is one of super's sections.
 | 
			
		||||
        return [super tableView:tableView titleForHeaderInSection:section];
 | 
			
		||||
 | 
			
		||||
    return @"Create";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
 | 
			
		||||
forRowAtIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    if (indexPath.section < [super numberOfSectionsInTableView:tableView])
 | 
			
		||||
            // Section is one of super's sections.
 | 
			
		||||
        [super tableView:tableView commitEditingStyle:editingStyle forRowAtIndexPath:indexPath];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,74 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  MPMainViewController.h
 | 
			
		||||
//  MasterPassword
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 24/11/11.
 | 
			
		||||
//  Copyright (c) 2011 Lyndir. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <MessageUI/MessageUI.h>
 | 
			
		||||
#import "MPTypeViewController.h"
 | 
			
		||||
#import "MPElementListSearchController.h"
 | 
			
		||||
 | 
			
		||||
@interface MPMainViewController : UIViewController<MPTypeDelegate, UITextFieldDelegate, MPElementListDelegate, UIWebViewDelegate, UIGestureRecognizerDelegate>
 | 
			
		||||
 | 
			
		||||
@property(assign, nonatomic) BOOL siteInfoHidden;
 | 
			
		||||
@property(strong, nonatomic) IBOutlet MPElementListSearchController *searchDelegate;
 | 
			
		||||
@property(strong, nonatomic) IBOutlet UIPanGestureRecognizer *pullDownGesture;
 | 
			
		||||
@property(strong, nonatomic) IBOutlet UIPanGestureRecognizer *pullUpGesture;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UITextField *contentField;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIButton *typeButton;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIWebView *helpView;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *siteName;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *passwordCounter;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIButton *passwordIncrementer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIButton *passwordEdit;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIButton *passwordUpgrade;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *contentContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *displayContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *helpContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *contentTipContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *loginNameTipContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *alertContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *alertTitle;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UITextView *alertBody;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *contentTipBody;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *loginNameTipBody;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIImageView *toolTipEditIcon;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *searchTipContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *actionsTipContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *typeTipContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *toolTipContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *toolTipBody;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *loginNameContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UITextField *loginNameField;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIButton *passwordUser;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *outdatedAlertContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIImageView *outdatedAlertBack;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIButton *outdatedAlertCloseButton;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIImageView *pullUpView;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIImageView *pullDownView;
 | 
			
		||||
 | 
			
		||||
@property(copy, nonatomic) void (^contentTipCleanup)(BOOL finished);
 | 
			
		||||
@property(copy, nonatomic) void (^toolTipCleanup)(BOOL finished);
 | 
			
		||||
 | 
			
		||||
- (IBAction)copyContent;
 | 
			
		||||
- (IBAction)incrementPasswordCounter;
 | 
			
		||||
- (IBAction)resetPasswordCounter:(UILongPressGestureRecognizer *)sender;
 | 
			
		||||
- (IBAction)editLoginName:(UILongPressGestureRecognizer *)sender;
 | 
			
		||||
- (IBAction)editPassword;
 | 
			
		||||
- (IBAction)closeAlert;
 | 
			
		||||
- (IBAction)upgradePassword;
 | 
			
		||||
- (IBAction)action:(UIBarButtonItem *)sender;
 | 
			
		||||
- (IBAction)toggleUser;
 | 
			
		||||
- (IBAction)searchOutdatedElements;
 | 
			
		||||
- (IBAction)closeOutdatedAlert;
 | 
			
		||||
- (IBAction)infoOutdatedAlert;
 | 
			
		||||
 | 
			
		||||
- (void)toggleHelpAnimated:(BOOL)animated;
 | 
			
		||||
- (void)setHelpHidden:(BOOL)hidden animated:(BOOL)animated;
 | 
			
		||||
- (void)setHelpChapter:(NSString *)chapter;
 | 
			
		||||
- (IBAction)panHelpDown:(UIPanGestureRecognizer *)sender;
 | 
			
		||||
- (IBAction)panHelpUp:(UIPanGestureRecognizer *)sender;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,887 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  MPMainViewController.m
 | 
			
		||||
//  MasterPassword
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 24/11/11.
 | 
			
		||||
//  Copyright (c) 2011 Lyndir. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import "MPMainViewController.h"
 | 
			
		||||
#import "MPiOSAppDelegate.h"
 | 
			
		||||
#import "MPAppDelegate_Store.h"
 | 
			
		||||
#import "MPElementListAllViewController.h"
 | 
			
		||||
 | 
			
		||||
@interface MPMainViewController()
 | 
			
		||||
 | 
			
		||||
@property(nonatomic) BOOL suppressOutdatedAlert;
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
@implementation MPMainViewController {
 | 
			
		||||
    NSManagedObjectID *_activeElementOID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - View lifecycle
 | 
			
		||||
 | 
			
		||||
- (BOOL)shouldAutorotate {
 | 
			
		||||
 | 
			
		||||
    return YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSUInteger)supportedInterfaceOrientations {
 | 
			
		||||
 | 
			
		||||
    return UIInterfaceOrientationMaskAllButUpsideDown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
 | 
			
		||||
 | 
			
		||||
    return UIInterfaceOrientationPortrait;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
 | 
			
		||||
 | 
			
		||||
    [self updateHelpHiddenAnimated:NO];
 | 
			
		||||
    [self updateUserHiddenAnimated:NO];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
 | 
			
		||||
 | 
			
		||||
    if ([[segue identifier] isEqualToString:@"MP_ChooseType"])
 | 
			
		||||
        ((MPTypeViewController *)[segue destinationViewController]).delegate = self;
 | 
			
		||||
    if ([[segue identifier] isEqualToString:@"MP_AllSites"]) {
 | 
			
		||||
        ((MPElementListAllViewController *)[[segue destinationViewController] topViewController]).delegate = self;
 | 
			
		||||
        ((MPElementListAllViewController *)[[segue destinationViewController] topViewController]).filter = sender;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)viewDidLoad {
 | 
			
		||||
 | 
			
		||||
    self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui_background"]];
 | 
			
		||||
 | 
			
		||||
    self.alertBody.text = nil;
 | 
			
		||||
    self.toolTipEditIcon.hidden = YES;
 | 
			
		||||
 | 
			
		||||
    [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:self queue:nil usingBlock:
 | 
			
		||||
            ^(NSNotification *note) {
 | 
			
		||||
                self.suppressOutdatedAlert = NO;
 | 
			
		||||
            }];
 | 
			
		||||
    [[NSNotificationCenter defaultCenter] addObserverForName:MPElementUpdatedNotification object:nil
 | 
			
		||||
                                                       queue:[NSOperationQueue mainQueue] usingBlock:
 | 
			
		||||
            ^(NSNotification *note) {
 | 
			
		||||
                MPElementEntity *activeElement = [self activeElementForMainThread];
 | 
			
		||||
                if (activeElement.type & MPElementTypeClassStored &&
 | 
			
		||||
                    ![[activeElement.algorithm resolveContentForElement:activeElement usingKey:[MPAppDelegate_Shared get].key] length])
 | 
			
		||||
                    [self showToolTip:@"Tap        to set a password." withIcon:self.toolTipEditIcon];
 | 
			
		||||
                if (activeElement.requiresExplicitMigration)
 | 
			
		||||
                    [self showToolTip:@"Password outdated. Tap to upgrade it." withIcon:nil];
 | 
			
		||||
            }];
 | 
			
		||||
    [[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil
 | 
			
		||||
                                                       queue:[NSOperationQueue mainQueue] usingBlock:
 | 
			
		||||
            ^(NSNotification *note) {
 | 
			
		||||
                BOOL animated = [(note.userInfo)[@"animated"] boolValue];
 | 
			
		||||
 | 
			
		||||
                _activeElementOID = nil;
 | 
			
		||||
                self.suppressOutdatedAlert = NO;
 | 
			
		||||
                [self updateAnimated:NO];
 | 
			
		||||
 | 
			
		||||
                [[[PearlSheet activeSheets] copy] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
 | 
			
		||||
                    [obj cancelSheetAnimated:NO];
 | 
			
		||||
                }];
 | 
			
		||||
                if (![self.navigationController presentedViewController])
 | 
			
		||||
                    [self.navigationController popToRootViewControllerAnimated:animated];
 | 
			
		||||
                else
 | 
			
		||||
                    [self.navigationController dismissViewControllerAnimated:animated completion:^{
 | 
			
		||||
                        [self.navigationController popToRootViewControllerAnimated:animated];
 | 
			
		||||
                    }];
 | 
			
		||||
            }];
 | 
			
		||||
    [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil
 | 
			
		||||
                                                       queue:[NSOperationQueue mainQueue] usingBlock:
 | 
			
		||||
            ^(NSNotification *note) {
 | 
			
		||||
                if (!self.activeElementForMainThread)
 | 
			
		||||
                    [self didSelectElement:nil];
 | 
			
		||||
            }];
 | 
			
		||||
 | 
			
		||||
    [super viewDidLoad];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)viewWillAppear:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    if (![super respondsToSelector:@selector(prefersStatusBarHidden)])
 | 
			
		||||
        [UIApp setStatusBarHidden:NO withAnimation:animated? UIStatusBarAnimationSlide: UIStatusBarAnimationNone];
 | 
			
		||||
    [self.navigationController setNavigationBarHidden:NO animated:animated];
 | 
			
		||||
 | 
			
		||||
    MPElementEntity *activeElement = [self activeElementForMainThread];
 | 
			
		||||
    if (activeElement.user != [[MPiOSAppDelegate get] activeUserForMainThread])
 | 
			
		||||
        _activeElementOID = nil;
 | 
			
		||||
 | 
			
		||||
    self.searchDisplayController.searchBar.text = nil;
 | 
			
		||||
    self.alertContainer.hidden = NO;
 | 
			
		||||
    self.outdatedAlertContainer.hidden = NO;
 | 
			
		||||
    self.searchTipContainer.hidden = NO;
 | 
			
		||||
    self.actionsTipContainer.hidden = NO;
 | 
			
		||||
    self.typeTipContainer.hidden = NO;
 | 
			
		||||
    self.toolTipContainer.hidden = NO;
 | 
			
		||||
    self.contentTipContainer.hidden = NO;
 | 
			
		||||
    self.loginNameTipContainer.hidden = NO;
 | 
			
		||||
 | 
			
		||||
    [self updateAnimated:NO];
 | 
			
		||||
 | 
			
		||||
    [super viewWillAppear:animated];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)viewDidAppear:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    inf(@"Main will appear");
 | 
			
		||||
 | 
			
		||||
    [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
 | 
			
		||||
        MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
 | 
			
		||||
        if ([MPAlgorithmDefault migrateUser:activeUser inContext:moc] && !self.suppressOutdatedAlert)
 | 
			
		||||
            [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
                self.outdatedAlertContainer.alpha = 1;
 | 
			
		||||
                self.suppressOutdatedAlert = YES;
 | 
			
		||||
            }];
 | 
			
		||||
        [moc saveToStore];
 | 
			
		||||
    }];
 | 
			
		||||
 | 
			
		||||
    if (![[MPiOSConfig get].actionsTipShown boolValue])
 | 
			
		||||
        [UIView animateWithDuration:animated? 0.3f: 0 animations:^{
 | 
			
		||||
            self.actionsTipContainer.alpha = 1;
 | 
			
		||||
        }                completion:^(BOOL finished) {
 | 
			
		||||
            if (!finished)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            [MPiOSConfig get].actionsTipShown = @YES;
 | 
			
		||||
 | 
			
		||||
            dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ), dispatch_get_main_queue(), ^{
 | 
			
		||||
                [UIView animateWithDuration:0.2f animations:^{
 | 
			
		||||
                    self.actionsTipContainer.alpha = 0;
 | 
			
		||||
                }                completion:^(BOOL finished_) {
 | 
			
		||||
                    if (!_activeElementOID)
 | 
			
		||||
                        [UIView animateWithDuration:animated? 0.3f: 0 animations:^{
 | 
			
		||||
                            self.searchTipContainer.alpha = 1;
 | 
			
		||||
                        }];
 | 
			
		||||
                }];
 | 
			
		||||
            } );
 | 
			
		||||
        }];
 | 
			
		||||
 | 
			
		||||
    [super viewDidAppear:animated];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)viewWillDisappear:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    inf(@"Main will disappear.");
 | 
			
		||||
    [super viewWillDisappear:animated];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)updateAnimated:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    if (animated) {
 | 
			
		||||
        [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
            [self updateAnimated:NO];
 | 
			
		||||
        }];
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MPElementEntity *activeElement = [self activeElementForMainThread];
 | 
			
		||||
    [self setHelpChapter:activeElement? @"2": @"1"];
 | 
			
		||||
    [self updateHelpHiddenAnimated:NO];
 | 
			
		||||
 | 
			
		||||
    self.passwordCounter.alpha = 0;
 | 
			
		||||
    self.passwordIncrementer.alpha = 0;
 | 
			
		||||
    self.passwordEdit.alpha = 0;
 | 
			
		||||
    self.passwordUpgrade.alpha = 0;
 | 
			
		||||
    self.passwordUser.alpha = 0;
 | 
			
		||||
    self.displayContainer.alpha = 0;
 | 
			
		||||
 | 
			
		||||
    if (activeElement) {
 | 
			
		||||
        self.passwordUser.alpha = 0.5f;
 | 
			
		||||
        self.displayContainer.alpha = 1.0f;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (activeElement.requiresExplicitMigration)
 | 
			
		||||
        self.passwordUpgrade.alpha = 0.5f;
 | 
			
		||||
 | 
			
		||||
    else {
 | 
			
		||||
        if (activeElement.type & MPElementTypeClassGenerated) {
 | 
			
		||||
            self.passwordCounter.alpha = 0.5f;
 | 
			
		||||
            self.passwordIncrementer.alpha = 0.5f;
 | 
			
		||||
        }
 | 
			
		||||
        else if (activeElement.type & MPElementTypeClassStored)
 | 
			
		||||
            self.passwordEdit.alpha = 0.5f;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    self.siteName.text = activeElement.name;
 | 
			
		||||
 | 
			
		||||
    self.typeButton.alpha = activeElement? 1: 0;
 | 
			
		||||
    [self.typeButton setTitle:activeElement.typeName
 | 
			
		||||
                     forState:UIControlStateNormal];
 | 
			
		||||
 | 
			
		||||
    if ([activeElement isKindOfClass:[MPElementGeneratedEntity class]])
 | 
			
		||||
        self.passwordCounter.text = PearlString( @"%lu", (unsigned long)((MPElementGeneratedEntity *)activeElement).counter );
 | 
			
		||||
 | 
			
		||||
    self.contentField.enabled = NO;
 | 
			
		||||
    self.contentField.text = @"";
 | 
			
		||||
    if (activeElement.name && ![activeElement isDeleted])
 | 
			
		||||
        [activeElement.algorithm resolveContentForElement:activeElement usingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) {
 | 
			
		||||
            dispatch_async( dispatch_get_main_queue(), ^{
 | 
			
		||||
                self.contentField.text = result;
 | 
			
		||||
            } );
 | 
			
		||||
        }];
 | 
			
		||||
 | 
			
		||||
    self.loginNameField.enabled = NO;
 | 
			
		||||
    self.loginNameField.text = activeElement.loginName;
 | 
			
		||||
    self.siteInfoHidden = !activeElement || ([[MPiOSConfig get].siteInfoHidden boolValue] && (activeElement.loginName == nil));
 | 
			
		||||
    [self updateUserHiddenAnimated:NO];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)toggleHelpAnimated:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    [self setHelpHidden:![[MPiOSConfig get].helpHidden boolValue] animated:animated];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)setHelpHidden:(BOOL)hidden animated:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    [MPiOSConfig get].helpHidden = @(hidden);
 | 
			
		||||
    [self updateHelpHiddenAnimated:animated];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)updateHelpHiddenAnimated:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    if (animated) {
 | 
			
		||||
        [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
            [self updateHelpHiddenAnimated:NO];
 | 
			
		||||
        }];
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    self.pullUpView.hidden = ![[MPiOSConfig get].helpHidden boolValue];
 | 
			
		||||
    self.pullDownView.hidden = [[MPiOSConfig get].helpHidden boolValue];
 | 
			
		||||
 | 
			
		||||
    if ([[MPiOSConfig get].helpHidden boolValue]) {
 | 
			
		||||
        self.contentContainer.frame = CGRectSetHeight( self.contentContainer.frame, self.view.bounds.size.height - 44 /* search bar */);
 | 
			
		||||
        self.helpContainer.frame = CGRectSetY( self.helpContainer.frame, self.view.bounds.size.height - 20 /* pull-up */);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        self.contentContainer.frame = CGRectSetHeight( self.contentContainer.frame, 225 );
 | 
			
		||||
        [self.helpContainer setFrameFromCurrentSizeAndParentPaddingTop:CGFLOAT_MAX right:0 bottom:0 left:0];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)toggleUser {
 | 
			
		||||
 | 
			
		||||
    [self toggleUserAnimated:YES];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)toggleUserAnimated:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    [MPiOSConfig get].siteInfoHidden = @(!self.siteInfoHidden);
 | 
			
		||||
    self.siteInfoHidden = [[MPiOSConfig get].siteInfoHidden boolValue];
 | 
			
		||||
    [self updateUserHiddenAnimated:animated];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)updateUserHiddenAnimated:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    if (animated) {
 | 
			
		||||
        [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
            [self updateUserHiddenAnimated:NO];
 | 
			
		||||
        }];
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (self.siteInfoHidden) {
 | 
			
		||||
        self.displayContainer.frame = CGRectSetHeight( self.displayContainer.frame, 87 );
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        self.displayContainer.frame = CGRectSetHeight( self.displayContainer.frame, 137 );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)setHelpChapter:(NSString *)chapter {
 | 
			
		||||
 | 
			
		||||
    MPCheckpoint( MPCheckpointHelpChapter, @{
 | 
			
		||||
            @"chapter" : NilToNSNull(chapter)
 | 
			
		||||
    } );
 | 
			
		||||
 | 
			
		||||
    dispatch_async( dispatch_get_main_queue(), ^{
 | 
			
		||||
        NSURL *url = [NSURL URLWithString:[@"#" stringByAppendingString:chapter]
 | 
			
		||||
                            relativeToURL:[[NSBundle mainBundle] URLForResource:@"help" withExtension:@"html"]];
 | 
			
		||||
        [self.helpView loadRequest:[NSURLRequest requestWithURL:url]];
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)panHelpDown:(UIPanGestureRecognizer *)sender {
 | 
			
		||||
 | 
			
		||||
    CGFloat targetY = MIN(self.view.bounds.size.height - 20, 246 + [sender translationInView:self.helpContainer].y);
 | 
			
		||||
    BOOL hideHelp = YES;
 | 
			
		||||
    if (targetY <= 246) {
 | 
			
		||||
        hideHelp = NO;
 | 
			
		||||
        targetY = 246;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    self.helpContainer.frame = CGRectSetY( self.helpContainer.frame, targetY );
 | 
			
		||||
 | 
			
		||||
    if (sender.state == UIGestureRecognizerStateEnded)
 | 
			
		||||
        [self setHelpHidden:hideHelp animated:YES];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)panHelpUp:(UIPanGestureRecognizer *)sender {
 | 
			
		||||
 | 
			
		||||
    CGFloat targetY = MAX(246, self.view.bounds.size.height - 20 + [sender translationInView:self.helpContainer].y);
 | 
			
		||||
    BOOL hideHelp = NO;
 | 
			
		||||
    if (targetY >= self.view.bounds.size.height - 20) {
 | 
			
		||||
        hideHelp = YES;
 | 
			
		||||
        targetY = self.view.bounds.size.height - 20;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    self.helpContainer.frame = CGRectSetY( self.helpContainer.frame, targetY );
 | 
			
		||||
 | 
			
		||||
    if (sender.state == UIGestureRecognizerStateEnded)
 | 
			
		||||
        [self setHelpHidden:hideHelp animated:YES];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)webViewDidFinishLoad:(UIWebView *)webView {
 | 
			
		||||
 | 
			
		||||
    MPElementEntity *activeElement = [self activeElementForMainThread];
 | 
			
		||||
    NSString *error = [self.helpView stringByEvaluatingJavaScriptFromString:
 | 
			
		||||
            PearlString( @"setClass('%@');", activeElement.typeClassName )];
 | 
			
		||||
    if (error.length)
 | 
			
		||||
    err(@"helpView.setClass: %@", error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)showContentTip:(NSString *)message withIcon:(UIImageView *)icon {
 | 
			
		||||
 | 
			
		||||
    dispatch_async( dispatch_get_main_queue(), ^{
 | 
			
		||||
        if (self.contentTipCleanup)
 | 
			
		||||
            self.contentTipCleanup( NO );
 | 
			
		||||
 | 
			
		||||
        __weak MPMainViewController *wSelf = self;
 | 
			
		||||
        self.contentTipBody.text = message;
 | 
			
		||||
        self.contentTipCleanup = ^(BOOL finished) {
 | 
			
		||||
            icon.hidden = YES;
 | 
			
		||||
            wSelf.contentTipCleanup = nil;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        icon.hidden = NO;
 | 
			
		||||
        [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
            self.contentTipContainer.alpha = 1;
 | 
			
		||||
        }                completion:^(BOOL finished) {
 | 
			
		||||
            if (finished) {
 | 
			
		||||
                dispatch_time_t popTime = dispatch_time( DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC );
 | 
			
		||||
                dispatch_after( popTime, dispatch_get_main_queue(), ^(void) {
 | 
			
		||||
                    [UIView animateWithDuration:0.2f animations:^{
 | 
			
		||||
                        self.contentTipContainer.alpha = 0;
 | 
			
		||||
                    }                completion:self.contentTipCleanup];
 | 
			
		||||
                } );
 | 
			
		||||
            }
 | 
			
		||||
        }];
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)showLoginNameTip:(NSString *)message {
 | 
			
		||||
 | 
			
		||||
    dispatch_async( dispatch_get_main_queue(), ^{
 | 
			
		||||
        self.loginNameTipBody.text = message;
 | 
			
		||||
 | 
			
		||||
        [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
            self.loginNameTipContainer.alpha = 1;
 | 
			
		||||
        }                completion:^(BOOL finished) {
 | 
			
		||||
            if (finished) {
 | 
			
		||||
                dispatch_time_t popTime = dispatch_time( DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC );
 | 
			
		||||
                dispatch_after( popTime, dispatch_get_main_queue(), ^(void) {
 | 
			
		||||
                    [UIView animateWithDuration:0.2f animations:^{
 | 
			
		||||
                        self.loginNameTipContainer.alpha = 0;
 | 
			
		||||
                    }];
 | 
			
		||||
                } );
 | 
			
		||||
            }
 | 
			
		||||
        }];
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)showToolTip:(NSString *)message withIcon:(UIImageView *)icon {
 | 
			
		||||
 | 
			
		||||
    dispatch_async( dispatch_get_main_queue(), ^{
 | 
			
		||||
        if (self.toolTipCleanup)
 | 
			
		||||
            self.toolTipCleanup( NO );
 | 
			
		||||
 | 
			
		||||
        __weak MPMainViewController *wSelf = self;
 | 
			
		||||
        self.toolTipBody.text = message;
 | 
			
		||||
        self.toolTipCleanup = ^(BOOL finished) {
 | 
			
		||||
            icon.hidden = YES;
 | 
			
		||||
            wSelf.toolTipCleanup = nil;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        icon.hidden = NO;
 | 
			
		||||
        [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
            self.toolTipContainer.alpha = 1;
 | 
			
		||||
        }                completion:^(BOOL finished) {
 | 
			
		||||
            if (finished) {
 | 
			
		||||
                dispatch_time_t popTime = dispatch_time( DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC );
 | 
			
		||||
                dispatch_after( popTime, dispatch_get_main_queue(), ^(void) {
 | 
			
		||||
                    [UIView animateWithDuration:0.2f animations:^{
 | 
			
		||||
                        self.toolTipContainer.alpha = 0;
 | 
			
		||||
                    }                completion:self.toolTipCleanup];
 | 
			
		||||
                } );
 | 
			
		||||
            }
 | 
			
		||||
        }];
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
 | 
			
		||||
 | 
			
		||||
    dispatch_async( dispatch_get_main_queue(), ^{
 | 
			
		||||
        self.alertTitle.text = title;
 | 
			
		||||
        NSRange scrollRange = NSMakeRange( self.alertBody.text.length, message.length );
 | 
			
		||||
        if ([self.alertBody.text length])
 | 
			
		||||
            self.alertBody.text = [NSString stringWithFormat:@"%@\n\n---\n\n%@", self.alertBody.text, message];
 | 
			
		||||
        else
 | 
			
		||||
            self.alertBody.text = message;
 | 
			
		||||
        [self.alertBody scrollRangeToVisible:scrollRange];
 | 
			
		||||
 | 
			
		||||
        [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
            self.alertContainer.alpha = 1;
 | 
			
		||||
        }];
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - Protocols
 | 
			
		||||
 | 
			
		||||
- (IBAction)copyContent {
 | 
			
		||||
 | 
			
		||||
    MPElementEntity *activeElement = [self activeElementForMainThread];
 | 
			
		||||
    inf(@"Copying password for: %@", activeElement.name);
 | 
			
		||||
    MPCheckpoint( MPCheckpointCopyToPasteboard, @{
 | 
			
		||||
            @"type"      : NilToNSNull(activeElement.typeName),
 | 
			
		||||
            @"version"   : @(activeElement.version),
 | 
			
		||||
            @"emergency" : @NO
 | 
			
		||||
    } );
 | 
			
		||||
 | 
			
		||||
    [activeElement.algorithm resolveContentForElement:activeElement usingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) {
 | 
			
		||||
        if (!result)
 | 
			
		||||
                // Nothing to copy.
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        [UIPasteboard generalPasteboard].string = result;
 | 
			
		||||
        [self showContentTip:@"Copied!" withIcon:nil];
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)copyLoginName:(UITapGestureRecognizer *)sender {
 | 
			
		||||
 | 
			
		||||
    MPElementEntity *activeElement = [self activeElementForMainThread];
 | 
			
		||||
    if (!activeElement.loginName)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    inf(@"Copying user name for: %@", activeElement.name);
 | 
			
		||||
    [UIPasteboard generalPasteboard].string = activeElement.loginName;
 | 
			
		||||
 | 
			
		||||
    [self showLoginNameTip:@"Copied!"];
 | 
			
		||||
 | 
			
		||||
    MPCheckpoint( MPCheckpointCopyLoginNameToPasteboard, @{
 | 
			
		||||
            @"type"    : NilToNSNull(activeElement.typeName),
 | 
			
		||||
            @"version" : @(activeElement.version)
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)incrementPasswordCounter {
 | 
			
		||||
 | 
			
		||||
    [self changeActiveElementWithWarning:
 | 
			
		||||
            @"You are incrementing the site's password counter.\n\n"
 | 
			
		||||
                    @"If you continue, a new password will be generated for this site.  "
 | 
			
		||||
                    @"You will then need to update your account's old password to this newly generated password.\n\n"
 | 
			
		||||
                    @"You can reset the counter by holding down on this button."
 | 
			
		||||
                                      do:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) {
 | 
			
		||||
                                          if (![activeElement isKindOfClass:[MPElementGeneratedEntity class]]) {
 | 
			
		||||
                                              // Not of a type that supports a password counter.
 | 
			
		||||
                                              err(@"Cannot increment password counter: Element is not generated: %@", activeElement.name);
 | 
			
		||||
                                              return NO;
 | 
			
		||||
                                          }
 | 
			
		||||
                                          MPElementGeneratedEntity *activeGeneratedElement = (MPElementGeneratedEntity *)activeElement;
 | 
			
		||||
 | 
			
		||||
                                          inf(@"Incrementing password counter for: %@", activeGeneratedElement.name);
 | 
			
		||||
                                          ++activeGeneratedElement.counter;
 | 
			
		||||
 | 
			
		||||
                                          MPCheckpoint( MPCheckpointIncrementPasswordCounter, @{
 | 
			
		||||
                                                  @"type"    : NilToNSNull(activeGeneratedElement.typeName),
 | 
			
		||||
                                                  @"version" : @(activeGeneratedElement.version),
 | 
			
		||||
                                                  @"counter" : @(activeGeneratedElement.counter)
 | 
			
		||||
                                          } );
 | 
			
		||||
                                          return YES;
 | 
			
		||||
                                      }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)resetPasswordCounter:(UILongPressGestureRecognizer *)sender {
 | 
			
		||||
 | 
			
		||||
    if (sender.state != UIGestureRecognizerStateBegan)
 | 
			
		||||
            // Only fire when the gesture was first detected.
 | 
			
		||||
        return;
 | 
			
		||||
    MPElementEntity *activeElement = [self activeElementForMainThread];
 | 
			
		||||
    if (![activeElement isKindOfClass:[MPElementGeneratedEntity class]]) {
 | 
			
		||||
        // Not of a type that supports a password counter.
 | 
			
		||||
        err(@"Cannot reset password counter: Element is not generated: %@", activeElement.name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    else if (((MPElementGeneratedEntity *)activeElement).counter == 1)
 | 
			
		||||
            // Counter has initial value, no point resetting.
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    [self changeActiveElementWithWarning:
 | 
			
		||||
            @"You are resetting the site's password counter.\n\n"
 | 
			
		||||
                    @"If you continue, the site's password will change back to its original value.  "
 | 
			
		||||
                    @"You will then need to update your account's password back to this original value."
 | 
			
		||||
                                      do:^BOOL(MPElementEntity *activeElement_, NSManagedObjectContext *context) {
 | 
			
		||||
                                          inf(@"Resetting password counter for: %@", activeElement_.name);
 | 
			
		||||
                                          ((MPElementGeneratedEntity *)activeElement_).counter = 1;
 | 
			
		||||
 | 
			
		||||
                                          MPCheckpoint( MPCheckpointResetPasswordCounter, @{
 | 
			
		||||
                                                  @"type"    : NilToNSNull(activeElement_.typeName),
 | 
			
		||||
                                                  @"version" : @(activeElement_.version)
 | 
			
		||||
                                          } );
 | 
			
		||||
                                          return YES;
 | 
			
		||||
                                      }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)editLoginName:(UILongPressGestureRecognizer *)sender {
 | 
			
		||||
 | 
			
		||||
    if (sender.state != UIGestureRecognizerStateBegan)
 | 
			
		||||
            // Only fire when the gesture was first detected.
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    MPElementEntity *activeElement = [self activeElementForMainThread];
 | 
			
		||||
    if (!activeElement)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    self.loginNameField.enabled = YES;
 | 
			
		||||
    [self.loginNameField becomeFirstResponder];
 | 
			
		||||
 | 
			
		||||
    MPCheckpoint( MPCheckpointEditLoginName, @{
 | 
			
		||||
            @"type"    : NilToNSNull(activeElement.typeName),
 | 
			
		||||
            @"version" : @(activeElement.version)
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)changeActiveElementWithWarning:(NSString *)warning
 | 
			
		||||
                                    do:(BOOL (^)(MPElementEntity *activeElement, NSManagedObjectContext *context))task {
 | 
			
		||||
 | 
			
		||||
    [PearlAlert showAlertWithTitle:@"Password Change" message:warning viewStyle:UIAlertViewStyleDefault
 | 
			
		||||
                         initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
        if (buttonIndex == [alert cancelButtonIndex])
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        [self changeActiveElementWithoutWarningDo:task];
 | 
			
		||||
    }                  cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)changeActiveElementWithoutWarningDo:(BOOL (^)(MPElementEntity *, NSManagedObjectContext *context))task {
 | 
			
		||||
 | 
			
		||||
    [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
        MPElementEntity *activeElement = [self activeElementInContext:context];
 | 
			
		||||
        if (!activeElement)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        MPKey *key = [MPAppDelegate_Shared get].key;
 | 
			
		||||
        NSString *oldPassword = [activeElement.algorithm resolveContentForElement:activeElement usingKey:key];
 | 
			
		||||
        if (!task( activeElement, context ))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        activeElement = [self activeElementInContext:context];
 | 
			
		||||
        NSString *newPassword = [activeElement.algorithm resolveContentForElement:activeElement usingKey:key];
 | 
			
		||||
 | 
			
		||||
        // Save.
 | 
			
		||||
        [context saveToStore];
 | 
			
		||||
 | 
			
		||||
        // Update the UI.
 | 
			
		||||
        dispatch_async( dispatch_get_main_queue(), ^{
 | 
			
		||||
            [self updateAnimated:YES];
 | 
			
		||||
 | 
			
		||||
            // Show new and old password.
 | 
			
		||||
            if ([oldPassword length] && ![oldPassword isEqualToString:newPassword])
 | 
			
		||||
                [self showAlertWithTitle:@"Password Changed!"
 | 
			
		||||
                                 message:PearlString( @"The password for %@ has changed.\n\n"
 | 
			
		||||
                                         @"IMPORTANT:\n"
 | 
			
		||||
                                         @"Don't forget to update the site with your new password! "
 | 
			
		||||
                                         @"Your old password was:\n"
 | 
			
		||||
                                         @"%@", activeElement.name, oldPassword )];
 | 
			
		||||
        } );
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (MPElementEntity *)activeElementForMainThread {
 | 
			
		||||
 | 
			
		||||
    return [self activeElementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (MPElementEntity *)activeElementInContext:(NSManagedObjectContext *)moc {
 | 
			
		||||
 | 
			
		||||
    if (!_activeElementOID)
 | 
			
		||||
        return nil;
 | 
			
		||||
 | 
			
		||||
    NSError *error;
 | 
			
		||||
    MPElementEntity *activeElement = (MPElementEntity *)[moc existingObjectWithID:_activeElementOID error:&error];
 | 
			
		||||
    if (!activeElement)
 | 
			
		||||
    err(@"Couldn't retrieve active element: %@", error);
 | 
			
		||||
 | 
			
		||||
    return activeElement;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)editPassword {
 | 
			
		||||
 | 
			
		||||
    MPElementEntity *activeElement = [self activeElementForMainThread];
 | 
			
		||||
    if (!(activeElement.type & MPElementTypeClassStored)) {
 | 
			
		||||
        // Not of a type that supports editing the content.
 | 
			
		||||
        err(@"Cannot edit content: Element is not stored: %@", activeElement.name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    self.contentField.enabled = YES;
 | 
			
		||||
    [self.contentField becomeFirstResponder];
 | 
			
		||||
 | 
			
		||||
    MPCheckpoint( MPCheckpointEditPassword, @{
 | 
			
		||||
            @"type"    : NilToNSNull(activeElement.typeName),
 | 
			
		||||
            @"version" : @(activeElement.version)
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)upgradePassword {
 | 
			
		||||
 | 
			
		||||
    MPElementEntity *activeElement = [self activeElementForMainThread];
 | 
			
		||||
    if (!activeElement)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    NSString *warning = activeElement.type & MPElementTypeClassGenerated?
 | 
			
		||||
                        @"You are upgrading the site.\n\n"
 | 
			
		||||
                                @"This upgrade improves the site's compatibility with the latest version of Master Password.\n\n"
 | 
			
		||||
                                @"Your password will change and you will need to update your site's account."
 | 
			
		||||
                        :
 | 
			
		||||
                        @"You are upgrading the site.\n\n"
 | 
			
		||||
                                @"This upgrade improves the site's compatibility with the latest version of Master Password.";
 | 
			
		||||
 | 
			
		||||
    [self changeActiveElementWithWarning:warning do:
 | 
			
		||||
            ^BOOL(MPElementEntity *activeElement_, NSManagedObjectContext *context) {
 | 
			
		||||
                inf(@"Explicitly migrating element: %@", activeElement_);
 | 
			
		||||
                [activeElement_ migrateExplicitly:YES];
 | 
			
		||||
 | 
			
		||||
                MPCheckpoint( MPCheckpointExplicitMigration, @{
 | 
			
		||||
                        @"type"    : NilToNSNull(activeElement_.typeName),
 | 
			
		||||
                        @"version" : @(activeElement_.version)
 | 
			
		||||
                } );
 | 
			
		||||
                return YES;
 | 
			
		||||
            }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)searchOutdatedElements {
 | 
			
		||||
 | 
			
		||||
    [self performSegueWithIdentifier:@"MP_AllSites" sender:MPElementListFilterOutdated];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)closeAlert {
 | 
			
		||||
 | 
			
		||||
    [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
        self.alertContainer.alpha = 0;
 | 
			
		||||
    }                completion:^(BOOL finished) {
 | 
			
		||||
        if (finished)
 | 
			
		||||
            self.alertBody.text = nil;
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)closeOutdatedAlert {
 | 
			
		||||
 | 
			
		||||
    [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
        self.outdatedAlertContainer.alpha = 0;
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)infoOutdatedAlert {
 | 
			
		||||
 | 
			
		||||
    [self setHelpChapter:@"outdated"];
 | 
			
		||||
    [self setHelpHidden:NO animated:YES];
 | 
			
		||||
    [self closeOutdatedAlert];
 | 
			
		||||
    self.suppressOutdatedAlert = NO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)action:(id)sender {
 | 
			
		||||
 | 
			
		||||
    [PearlSheet showSheetWithTitle:nil viewStyle:UIActionSheetStyleAutomatic
 | 
			
		||||
                         initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
 | 
			
		||||
        if (buttonIndex == [sheet cancelButtonIndex])
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        switch (buttonIndex - [sheet firstOtherButtonIndex]) {
 | 
			
		||||
            case 0: {
 | 
			
		||||
                inf(@"Action: FAQ");
 | 
			
		||||
                [self setHelpChapter:@"faq"];
 | 
			
		||||
                [self setHelpHidden:NO animated:YES];
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case 2: {
 | 
			
		||||
                inf(@"Action: Preferences");
 | 
			
		||||
                [self performSegueWithIdentifier:@"MP_UserProfile" sender:self];
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case 3: {
 | 
			
		||||
                inf(@"Action: Other Apps");
 | 
			
		||||
                [self performSegueWithIdentifier:@"MP_OtherApps" sender:self];
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
//#if defined(ADHOC) && defined(TESTFLIGHT_SDK_VERSION)
 | 
			
		||||
//                         case 4: {
 | 
			
		||||
//                             inf(@"Action: Feedback via TestFlight");
 | 
			
		||||
//                             [TestFlight openFeedbackView];
 | 
			
		||||
//                             break;
 | 
			
		||||
//                         }
 | 
			
		||||
//#else
 | 
			
		||||
            case 4: {
 | 
			
		||||
                inf(@"Action: Feedback via Mail");
 | 
			
		||||
                [[MPiOSAppDelegate get] showFeedbackWithLogs:YES forVC:self];
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
//#endif
 | 
			
		||||
 | 
			
		||||
            default: {
 | 
			
		||||
                wrn(@"Unsupported action: %ld", (long)(buttonIndex - [sheet firstOtherButtonIndex]));
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
                       cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil otherTitles:
 | 
			
		||||
            @"FAQ",
 | 
			
		||||
            @"Overview",
 | 
			
		||||
            @"User Profile",
 | 
			
		||||
            @"Other Apps",
 | 
			
		||||
            @"Feedback",
 | 
			
		||||
            nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (MPElementType)selectedType {
 | 
			
		||||
 | 
			
		||||
    return [self selectedElement].type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (MPElementEntity *)selectedElement {
 | 
			
		||||
 | 
			
		||||
    return [self activeElementForMainThread];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)didSelectType:(MPElementType)type {
 | 
			
		||||
 | 
			
		||||
    [self changeActiveElementWithWarning:
 | 
			
		||||
            @"You are about to change the type of this password.\n\n"
 | 
			
		||||
                    @"If you continue, the password for this site will change.  "
 | 
			
		||||
                    @"You will need to update your account's old password to the new one."
 | 
			
		||||
                                      do:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) {
 | 
			
		||||
                                          _activeElementOID = [[MPiOSAppDelegate get] changeElement:activeElement saveInContext:context
 | 
			
		||||
                                                                                             toType:type].objectID;
 | 
			
		||||
                                          return YES;
 | 
			
		||||
                                      }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)didSelectElement:(MPElementEntity *)element {
 | 
			
		||||
 | 
			
		||||
    inf(@"Selected: %@", element.name);
 | 
			
		||||
    _activeElementOID = element.objectID;
 | 
			
		||||
    [self closeAlert];
 | 
			
		||||
 | 
			
		||||
    if (element) {
 | 
			
		||||
        [self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) {
 | 
			
		||||
            if ([activeElement use] == 1)
 | 
			
		||||
                [self showAlertWithTitle:@"New Site" message:
 | 
			
		||||
                        PearlString( @"You've just created a password for %@.\n\n"
 | 
			
		||||
                                @"IMPORTANT:\n"
 | 
			
		||||
                                @"Go to %@ and set or change the password for your account to the password above.\n"
 | 
			
		||||
                                @"Do this right away: if you forget, you may have trouble remembering which password to use to log into the site later on.",
 | 
			
		||||
                                activeElement.name, activeElement.name )];
 | 
			
		||||
            return YES;
 | 
			
		||||
        }];
 | 
			
		||||
 | 
			
		||||
        if (![[MPiOSConfig get].typeTipShown boolValue])
 | 
			
		||||
            [UIView animateWithDuration:0.5f animations:^{
 | 
			
		||||
                self.typeTipContainer.alpha = 1;
 | 
			
		||||
            }                completion:^(BOOL finished) {
 | 
			
		||||
                if (finished) {
 | 
			
		||||
                    [MPiOSConfig get].typeTipShown = PearlBool(YES);
 | 
			
		||||
 | 
			
		||||
                    dispatch_after(
 | 
			
		||||
                            dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ), dispatch_get_main_queue(), ^{
 | 
			
		||||
                                [UIView animateWithDuration:0.2f animations:^{
 | 
			
		||||
                                    self.typeTipContainer.alpha = 0;
 | 
			
		||||
                                }];
 | 
			
		||||
                            } );
 | 
			
		||||
                }
 | 
			
		||||
            }];
 | 
			
		||||
 | 
			
		||||
        MPCheckpoint( MPCheckpointUseType, @{
 | 
			
		||||
                @"type"    : NilToNSNull(element.typeName),
 | 
			
		||||
                @"version" : @(element.version)
 | 
			
		||||
        } );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [self.searchDisplayController setActive:NO animated:YES];
 | 
			
		||||
    self.searchDisplayController.searchBar.text = element.name;
 | 
			
		||||
 | 
			
		||||
    [self updateAnimated:YES];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
 | 
			
		||||
 | 
			
		||||
    if (textField == self.contentField)
 | 
			
		||||
        [self.contentField resignFirstResponder];
 | 
			
		||||
    if (textField == self.loginNameField)
 | 
			
		||||
        [self.loginNameField resignFirstResponder];
 | 
			
		||||
 | 
			
		||||
    return YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)textFieldDidEndEditing:(UITextField *)textField {
 | 
			
		||||
 | 
			
		||||
    if (textField == self.contentField) {
 | 
			
		||||
        self.contentField.enabled = NO;
 | 
			
		||||
        MPElementEntity *activeElement = [self activeElementForMainThread];
 | 
			
		||||
        MPKey *key = [MPAppDelegate_Shared get].key;
 | 
			
		||||
        if (![activeElement isKindOfClass:[MPElementStoredEntity class]]) {
 | 
			
		||||
            // Not of a type whose content can be edited.
 | 
			
		||||
            err(@"Cannot update element content: Element is not stored: %@", activeElement.name);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        else if ([[activeElement.algorithm resolveContentForElement:activeElement usingKey:key] isEqual:self.contentField.text])
 | 
			
		||||
                // Content hasn't changed.
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        [self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement_, NSManagedObjectContext *context) {
 | 
			
		||||
            [activeElement_.algorithm saveContent:self.contentField.text toElement:activeElement_ usingKey:key];
 | 
			
		||||
            return YES;
 | 
			
		||||
        }];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (textField == self.loginNameField) {
 | 
			
		||||
        self.loginNameField.enabled = NO;
 | 
			
		||||
        if (![[MPiOSConfig get].loginNameTipShown boolValue]) {
 | 
			
		||||
            [self showLoginNameTip:@"Tap to copy or hold to edit."];
 | 
			
		||||
            [MPiOSConfig get].loginNameTipShown = @YES;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) {
 | 
			
		||||
            if ([self.loginNameField.text length])
 | 
			
		||||
                activeElement.loginName = self.loginNameField.text;
 | 
			
		||||
            else
 | 
			
		||||
                activeElement.loginName = nil;
 | 
			
		||||
 | 
			
		||||
            return YES;
 | 
			
		||||
        }];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
 | 
			
		||||
 navigationType:(UIWebViewNavigationType)navigationType {
 | 
			
		||||
 | 
			
		||||
    if (navigationType == UIWebViewNavigationTypeLinkClicked) {
 | 
			
		||||
        if ([[[request URL] query] isEqualToString:@"outdated"]) {
 | 
			
		||||
            [self searchOutdatedElements];
 | 
			
		||||
            return NO;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UIApp openURL:[request URL]];
 | 
			
		||||
        return NO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -9,17 +9,15 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//  MPAppViewController
 | 
			
		||||
//  MPNavigationController.h
 | 
			
		||||
//  MPNavigationController
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 2012-08-31.
 | 
			
		||||
//  Copyright 2012 lhunath (Maarten Billemont). All rights reserved.
 | 
			
		||||
//  Created by lhunath on 2014-06-03.
 | 
			
		||||
//  Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
 | 
			
		||||
@interface MPAppViewController : UIViewController
 | 
			
		||||
 | 
			
		||||
- (IBAction)gorillas:(UIButton *)sender;
 | 
			
		||||
- (IBAction)deblock:(UIButton *)sender;
 | 
			
		||||
 | 
			
		||||
@interface MPNavigationController : UINavigationController
 | 
			
		||||
@end
 | 
			
		||||
							
								
								
									
										30
									
								
								MasterPassword/ObjC/iOS/MPNavigationController.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								MasterPassword/ObjC/iOS/MPNavigationController.m
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
 | 
			
		||||
 *
 | 
			
		||||
 * See the enclosed file LICENSE for license information (LGPLv3). If you did
 | 
			
		||||
 * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 *
 | 
			
		||||
 * @author   Maarten Billemont <lhunath@lyndir.com>
 | 
			
		||||
 * @license  http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//  MPNavigationController.h
 | 
			
		||||
//  MPNavigationController
 | 
			
		||||
//
 | 
			
		||||
//  Created by lhunath on 2014-06-03.
 | 
			
		||||
//  Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import "MPNavigationController.h"
 | 
			
		||||
#import "MPWebViewController.h"
 | 
			
		||||
 | 
			
		||||
@implementation MPNavigationController
 | 
			
		||||
 | 
			
		||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
 | 
			
		||||
 | 
			
		||||
    if ([segue.identifier isEqualToString:@"web"])
 | 
			
		||||
        ((MPWebViewController *)segue.destinationViewController).initialURL = [NSURL URLWithString:@"http://thanks.lhunath.com"];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -45,6 +45,7 @@ typedef NS_ENUM (NSUInteger, MPContentFieldMode) {
 | 
			
		||||
- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock;
 | 
			
		||||
- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock;
 | 
			
		||||
 | 
			
		||||
- (void)willBeginDragging;
 | 
			
		||||
- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 
 | 
			
		||||
@@ -152,6 +152,9 @@
 | 
			
		||||
    resultBlock( nil );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)willBeginDragging {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context {
 | 
			
		||||
 | 
			
		||||
    return [[MPiOSAppDelegate get] changeElement:element saveInContext:context toType:self.type];
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@
 | 
			
		||||
 | 
			
		||||
@interface MPPasswordLargeGeneratedCell : MPPasswordLargeCell
 | 
			
		||||
 | 
			
		||||
@property(strong, nonatomic) IBOutlet UILabel *strengthLabel;
 | 
			
		||||
@property(strong, nonatomic) IBOutlet UILabel *counterLabel;
 | 
			
		||||
@property(strong, nonatomic) IBOutlet UIButton *counterButton;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
 | 
			
		||||
 *
 | 
			
		||||
 * See the enclosed file LICENSE for license information (LGPLv3). If you did
 | 
			
		||||
 * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 *
 | 
			
		||||
 * @author   Maarten Billemont <lhunath@lyndir.com>
 | 
			
		||||
 * @license  http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
 */
 | 
			
		||||
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
 | 
			
		||||
*
 | 
			
		||||
* See the enclosed file LICENSE for license information (LGPLv3). If you did
 | 
			
		||||
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
*
 | 
			
		||||
* @author   Maarten Billemont <lhunath@lyndir.com>
 | 
			
		||||
* @license  http://www.gnu.org/licenses/lgpl-3.0.txt
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//  MPPasswordLargeGeneratedCell.h
 | 
			
		||||
@@ -21,6 +21,11 @@
 | 
			
		||||
#import "MPAppDelegate_Store.h"
 | 
			
		||||
#import "MPPasswordTypesCell.h"
 | 
			
		||||
 | 
			
		||||
@interface MPPasswordLargeGeneratedCell()
 | 
			
		||||
 | 
			
		||||
@property(nonatomic, weak) NSTimer *hideStrengthTimer;
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
@implementation MPPasswordLargeGeneratedCell
 | 
			
		||||
 | 
			
		||||
- (void)awakeFromNib {
 | 
			
		||||
@@ -28,10 +33,40 @@
 | 
			
		||||
    [super awakeFromNib];
 | 
			
		||||
 | 
			
		||||
    UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc]
 | 
			
		||||
            initWithTarget:self action:@selector(doResetCounterRecognizer:)];
 | 
			
		||||
            initWithTarget:self action:@selector( doResetCounterRecognizer: )];
 | 
			
		||||
    [self.counterButton addGestureRecognizer:gestureRecognizer];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)prepareForReuse {
 | 
			
		||||
 | 
			
		||||
    [super prepareForReuse];
 | 
			
		||||
 | 
			
		||||
    self.strengthLabel.alpha = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)willBeginDragging {
 | 
			
		||||
 | 
			
		||||
    [super willBeginDragging];
 | 
			
		||||
 | 
			
		||||
    [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
        self.strengthLabel.alpha = 1;
 | 
			
		||||
    }];
 | 
			
		||||
 | 
			
		||||
    [self.hideStrengthTimer invalidate];
 | 
			
		||||
    self.hideStrengthTimer = [NSTimer scheduledTimerWithTimeInterval:1 block:^(NSTimer *timer) {
 | 
			
		||||
        [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
            self.strengthLabel.alpha = 0;
 | 
			
		||||
        }];
 | 
			
		||||
    }                                                        repeats:NO];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)update {
 | 
			
		||||
 | 
			
		||||
    [super update];
 | 
			
		||||
 | 
			
		||||
    self.counterLabel.alpha = self.counterButton.alpha = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)updateWithElement:(MPElementEntity *)mainElement {
 | 
			
		||||
 | 
			
		||||
    [super updateWithElement:mainElement];
 | 
			
		||||
@@ -42,24 +77,18 @@
 | 
			
		||||
    else
 | 
			
		||||
        self.counterLabel.text = @"1";
 | 
			
		||||
 | 
			
		||||
    if (!mainElement || mainElement.requiresExplicitMigration) {
 | 
			
		||||
        self.counterLabel.alpha = 0;
 | 
			
		||||
        self.counterButton.alpha = 0;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        self.counterLabel.alpha = 1;
 | 
			
		||||
        self.counterButton.alpha = 1;
 | 
			
		||||
    }
 | 
			
		||||
    if (mainElement && !mainElement.requiresExplicitMigration)
 | 
			
		||||
        self.counterLabel.alpha = self.counterButton.alpha = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
 | 
			
		||||
- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void ( ^ )(NSString *))resultBlock {
 | 
			
		||||
 | 
			
		||||
    PearlNotMainQueue( ^{
 | 
			
		||||
        resultBlock( [MPAlgorithmDefault generateContentNamed:siteName ofType:self.type withCounter:1 usingKey:key] );
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
 | 
			
		||||
- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void ( ^ )(NSString *))resultBlock {
 | 
			
		||||
 | 
			
		||||
    id<MPAlgorithm> algorithm = element.algorithm;
 | 
			
		||||
    NSString *siteName = element.name;
 | 
			
		||||
@@ -103,7 +132,7 @@
 | 
			
		||||
 | 
			
		||||
- (void)doResetCounterRecognizer:(UILongPressGestureRecognizer *)gestureRecognizer {
 | 
			
		||||
 | 
			
		||||
    if (gestureRecognizer.state != UIGestureRecognizerStateEnded)
 | 
			
		||||
    if (gestureRecognizer.state != UIGestureRecognizerStateRecognized)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
@@ -123,6 +152,38 @@
 | 
			
		||||
 | 
			
		||||
#pragma mark - Properties
 | 
			
		||||
 | 
			
		||||
- (void)setType:(MPElementType)type {
 | 
			
		||||
 | 
			
		||||
    [super setType:type];
 | 
			
		||||
 | 
			
		||||
    switch (type) {
 | 
			
		||||
        case MPElementTypeGeneratedMaximum:
 | 
			
		||||
            self.strengthLabel.text = @"> age of the universe";
 | 
			
		||||
            break;
 | 
			
		||||
        case MPElementTypeGeneratedLong:
 | 
			
		||||
            self.strengthLabel.text = @"196 billion years";
 | 
			
		||||
            break;
 | 
			
		||||
        case MPElementTypeGeneratedMedium:
 | 
			
		||||
            self.strengthLabel.text = @"5 months";
 | 
			
		||||
            break;
 | 
			
		||||
        case MPElementTypeGeneratedBasic:
 | 
			
		||||
            self.strengthLabel.text = @"12 days";
 | 
			
		||||
            break;
 | 
			
		||||
        case MPElementTypeGeneratedShort:
 | 
			
		||||
            self.strengthLabel.text = @"trivial";
 | 
			
		||||
            break;
 | 
			
		||||
        case MPElementTypeGeneratedPIN:
 | 
			
		||||
            self.strengthLabel.text = @"trivial";
 | 
			
		||||
            break;
 | 
			
		||||
        case MPElementTypeStoredPersonal:
 | 
			
		||||
            self.strengthLabel.text = @"";
 | 
			
		||||
            break;
 | 
			
		||||
        case MPElementTypeStoredDevicePrivate:
 | 
			
		||||
            self.strengthLabel.text = @"";
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (MPElementGeneratedEntity *)generatedElementInContext:(NSManagedObjectContext *)context {
 | 
			
		||||
 | 
			
		||||
    return [self generatedElement:[[MPPasswordTypesCell findAsSuperviewOf:self] elementInContext:context]];
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
 | 
			
		||||
@implementation MPPasswordTypesCell {
 | 
			
		||||
    NSManagedObjectID *_elementOID;
 | 
			
		||||
    BOOL _scrolling;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - Lifecycle
 | 
			
		||||
@@ -110,7 +111,9 @@
 | 
			
		||||
        [cell updateWithTransientSite:self.transientSite];
 | 
			
		||||
    else
 | 
			
		||||
        [cell updateWithElement:self.mainElement];
 | 
			
		||||
    dbg( @"cell %d, contentFieldMode: %d", indexPath.item, cell.contentFieldMode );
 | 
			
		||||
 | 
			
		||||
    if (_scrolling)
 | 
			
		||||
        [cell willBeginDragging];
 | 
			
		||||
 | 
			
		||||
    return cell;
 | 
			
		||||
}
 | 
			
		||||
@@ -189,6 +192,13 @@
 | 
			
		||||
 | 
			
		||||
#pragma mark - UIScrollViewDelegate
 | 
			
		||||
 | 
			
		||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
 | 
			
		||||
    
 | 
			
		||||
    _scrolling = YES;
 | 
			
		||||
    for (MPPasswordLargeCell *cell in [self.contentCollectionView visibleCells])
 | 
			
		||||
        [cell willBeginDragging];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity
 | 
			
		||||
              targetContentOffset:(inout CGPoint *)targetContentOffset {
 | 
			
		||||
 | 
			
		||||
@@ -202,12 +212,14 @@
 | 
			
		||||
 | 
			
		||||
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
 | 
			
		||||
 | 
			
		||||
    _scrolling = NO;
 | 
			
		||||
    if (scrollView == self.contentCollectionView && !decelerate)
 | 
			
		||||
        [self saveContentType];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
 | 
			
		||||
 | 
			
		||||
    _scrolling = NO;
 | 
			
		||||
    if (scrollView == self.contentCollectionView)
 | 
			
		||||
        [self saveContentType];
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -408,11 +408,8 @@ referenceSizeForHeaderInSection:(NSInteger)section {
 | 
			
		||||
    _active = active;
 | 
			
		||||
 | 
			
		||||
    [UIView animateWithDuration:animated? 0.4f: 0 animations:^{
 | 
			
		||||
        self.navigationBarToTopConstraint.priority = active? 1: UILayoutPriorityDefaultHigh;
 | 
			
		||||
        self.passwordsToBottomConstraint.priority = active? 1: UILayoutPriorityDefaultHigh;
 | 
			
		||||
 | 
			
		||||
        [self.navigationBarToTopConstraint apply];
 | 
			
		||||
        [self.passwordsToBottomConstraint apply];
 | 
			
		||||
        [self.navigationBarToTopConstraint layoutWithPriority:active? 1: UILayoutPriorityDefaultHigh];
 | 
			
		||||
        [self.passwordsToBottomConstraint layoutWithPriority:active? 1: UILayoutPriorityDefaultHigh];
 | 
			
		||||
    }                completion:completion];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -38,9 +38,8 @@
 | 
			
		||||
                                                              metrics:nil views:NSDictionaryOfVariableBindings(popdownView)];
 | 
			
		||||
 | 
			
		||||
        [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
            passwordsVC.popdownToTopConstraint.priority = 1;
 | 
			
		||||
            [passwordsVC.popdownToTopConstraint apply];
 | 
			
		||||
        }                completion:^(BOOL finished) {
 | 
			
		||||
            [passwordsVC.popdownToTopConstraint layoutWithPriority:1];
 | 
			
		||||
        } completion:^(BOOL finished) {
 | 
			
		||||
            if (finished)
 | 
			
		||||
                [popdownVC didMoveToParentViewController:passwordsVC];
 | 
			
		||||
        }];
 | 
			
		||||
@@ -51,8 +50,7 @@
 | 
			
		||||
 | 
			
		||||
        [popdownVC willMoveToParentViewController:nil];
 | 
			
		||||
        [UIView animateWithDuration:0.3f delay:0 options:UIViewAnimationOptionOverrideInheritedDuration animations:^{
 | 
			
		||||
            passwordsVC.popdownToTopConstraint.priority = UILayoutPriorityDefaultHigh;
 | 
			
		||||
            [passwordsVC.popdownToTopConstraint apply];
 | 
			
		||||
            [passwordsVC.popdownToTopConstraint layoutWithPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
        }                completion:^(BOOL finished) {
 | 
			
		||||
            if (finished) {
 | 
			
		||||
                [popdownVC.view removeFromSuperview];
 | 
			
		||||
 
 | 
			
		||||
@@ -24,5 +24,9 @@
 | 
			
		||||
- (IBAction)previousAvatar:(id)sender;
 | 
			
		||||
- (IBAction)nextAvatar:(id)sender;
 | 
			
		||||
- (IBAction)valueChanged:(id)sender;
 | 
			
		||||
- (IBAction)homePageButton:(id)sender;
 | 
			
		||||
- (IBAction)securityButton:(id)sender;
 | 
			
		||||
- (IBAction)sourceButton:(id)sender;
 | 
			
		||||
- (IBAction)thanksButton:(id)sender;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 
 | 
			
		||||
@@ -142,6 +142,30 @@
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)homePageButton:(id)sender {
 | 
			
		||||
 | 
			
		||||
    [[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender:
 | 
			
		||||
            [NSURL URLWithString:@"http://masterpasswordapp.com"]];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)securityButton:(id)sender {
 | 
			
		||||
 | 
			
		||||
    [[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender:
 | 
			
		||||
            [NSURL URLWithString:@"http://masterpasswordapp.com/security.html"]];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)sourceButton:(id)sender {
 | 
			
		||||
 | 
			
		||||
    [[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender:
 | 
			
		||||
            [NSURL URLWithString:@"https://github.com/Lyndir/MasterPassword/"]];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)thanksButton:(id)sender {
 | 
			
		||||
 | 
			
		||||
    [[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender:
 | 
			
		||||
            [NSURL URLWithString:@"http://thanks.lhunath.com"]];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - Private
 | 
			
		||||
 | 
			
		||||
- (MPPasswordsViewController *)dismissPopup {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  MPPreferencesViewController.h
 | 
			
		||||
//  MasterPassword-iOS
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 04/06/12.
 | 
			
		||||
//  Copyright (c) 2012 Lyndir. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <UIKit/UIKit.h>
 | 
			
		||||
#import "MPTypeViewController.h"
 | 
			
		||||
 | 
			
		||||
@interface MPPreferencesViewControllerOld : UITableViewController<MPTypeDelegate>
 | 
			
		||||
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIScrollView *avatarsView;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIButton *avatarTemplate;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UISwitch *savePasswordSwitch;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UITableViewCell *exportCell;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UITableViewCell *changeMPCell;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *defaultTypeLabel;
 | 
			
		||||
 | 
			
		||||
- (IBAction)didToggleSwitch:(UISwitch *)sender;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,163 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  MPPreferencesViewController.m
 | 
			
		||||
//  MasterPassword-iOS
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 04/06/12.
 | 
			
		||||
//  Copyright (c) 2012 Lyndir. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <QuartzCore/QuartzCore.h>
 | 
			
		||||
 | 
			
		||||
#import "MPPreferencesViewControllerOld.h"
 | 
			
		||||
#import "MPiOSAppDelegate.h"
 | 
			
		||||
#import "MPAppDelegate_Key.h"
 | 
			
		||||
#import "MPAppDelegate_Store.h"
 | 
			
		||||
 | 
			
		||||
@interface MPPreferencesViewControllerOld()
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
@implementation MPPreferencesViewControllerOld
 | 
			
		||||
 | 
			
		||||
- (void)viewDidLoad {
 | 
			
		||||
 | 
			
		||||
    self.avatarTemplate.hidden = YES;
 | 
			
		||||
 | 
			
		||||
    for (NSUInteger a = 0; a < MPAvatarCount; ++a) {
 | 
			
		||||
        UIButton *avatar = [self.avatarTemplate clone];
 | 
			
		||||
        avatar.tag = a;
 | 
			
		||||
        avatar.hidden = NO;
 | 
			
		||||
        avatar.center = CGPointMake(
 | 
			
		||||
                self.avatarTemplate.center.x * (a + 1) + self.avatarTemplate.bounds.size.width / 2 * a,
 | 
			
		||||
                self.avatarTemplate.center.y );
 | 
			
		||||
        [avatar setBackgroundImage:[UIImage imageNamed:PearlString( @"avatar-%ld", (long)a )]
 | 
			
		||||
                          forState:UIControlStateNormal];
 | 
			
		||||
        [avatar setSelectionInSuperviewCandidate:YES isClearable:NO];
 | 
			
		||||
 | 
			
		||||
        avatar.layer.cornerRadius = avatar.bounds.size.height / 2;
 | 
			
		||||
        avatar.layer.shadowColor = [UIColor blackColor].CGColor;
 | 
			
		||||
        avatar.layer.shadowOpacity = 1;
 | 
			
		||||
        avatar.layer.shadowRadius = 5;
 | 
			
		||||
        avatar.backgroundColor = [UIColor clearColor];
 | 
			
		||||
 | 
			
		||||
        [avatar onHighlightOrSelect:^(BOOL highlighted, BOOL selected) {
 | 
			
		||||
            if (highlighted || selected)
 | 
			
		||||
                avatar.backgroundColor = self.avatarTemplate.backgroundColor;
 | 
			
		||||
            else
 | 
			
		||||
                avatar.backgroundColor = [UIColor clearColor];
 | 
			
		||||
        }                   options:0];
 | 
			
		||||
        [avatar onSelect:^(BOOL selected) {
 | 
			
		||||
            if (selected) {
 | 
			
		||||
                [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
 | 
			
		||||
                    [[MPiOSAppDelegate get] activeUserInContext:moc].avatar = (unsigned)avatar.tag;
 | 
			
		||||
                    [moc saveToStore];
 | 
			
		||||
                }];
 | 
			
		||||
            }
 | 
			
		||||
        }        options:0];
 | 
			
		||||
        avatar.selected = (a == [[MPiOSAppDelegate get] activeUserForMainThread].avatar);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [super viewDidLoad];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)viewWillAppear:(BOOL)animated {
 | 
			
		||||
 | 
			
		||||
    inf(@"Preferences will appear");
 | 
			
		||||
    [self.avatarsView autoSizeContent];
 | 
			
		||||
    [self.avatarsView enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
 | 
			
		||||
        if (subview.tag && ((UIControl *)subview).selected) {
 | 
			
		||||
            [self.avatarsView setContentOffset:CGPointMake( subview.center.x - self.avatarsView.bounds.size.width / 2, 0 )
 | 
			
		||||
                                      animated:animated];
 | 
			
		||||
        }
 | 
			
		||||
    }                        recurse:NO];
 | 
			
		||||
 | 
			
		||||
    MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForMainThread];
 | 
			
		||||
    self.savePasswordSwitch.on = activeUser.saveKey;
 | 
			
		||||
    self.defaultTypeLabel.text = [[MPiOSAppDelegate get].key.algorithm shortNameOfType:activeUser.defaultType];
 | 
			
		||||
 | 
			
		||||
    [super viewWillAppear:animated];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL)canBecomeFirstResponder {
 | 
			
		||||
 | 
			
		||||
    return YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
 | 
			
		||||
 | 
			
		||||
    if (motion == UIEventSubtypeMotionShake) {
 | 
			
		||||
        MPCheckpoint( MPCheckpointLogs, @{
 | 
			
		||||
                @"trace" : [MPiOSConfig get].traceMode
 | 
			
		||||
        } );
 | 
			
		||||
        [self performSegueWithIdentifier:@"MP_Logs" sender:self];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL)shouldAutorotate {
 | 
			
		||||
 | 
			
		||||
    return NO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
 | 
			
		||||
 | 
			
		||||
    return UIInterfaceOrientationPortrait;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
 | 
			
		||||
 | 
			
		||||
    if ([[segue identifier] isEqualToString:@"MP_ChooseType"])
 | 
			
		||||
        ((MPTypeViewController *)[segue destinationViewController]).delegate = self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - UITableViewDelegate
 | 
			
		||||
 | 
			
		||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
 | 
			
		||||
    UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
 | 
			
		||||
    if (cell == self.exportCell)
 | 
			
		||||
        [[MPiOSAppDelegate get] showExportForVC:self];
 | 
			
		||||
 | 
			
		||||
    else if (cell == self.changeMPCell) {
 | 
			
		||||
        [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
 | 
			
		||||
            MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
 | 
			
		||||
            [[MPiOSAppDelegate get] changeMasterPasswordFor:activeUser saveInContext:moc didResetBlock:nil];
 | 
			
		||||
        }];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - MPTypeDelegate
 | 
			
		||||
 | 
			
		||||
- (void)didSelectType:(MPElementType)type {
 | 
			
		||||
 | 
			
		||||
    self.defaultTypeLabel.text = [[MPiOSAppDelegate get].key.algorithm shortNameOfType:type];
 | 
			
		||||
 | 
			
		||||
    [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
        MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:context];
 | 
			
		||||
        activeUser.defaultType = type;
 | 
			
		||||
        [context saveToStore];
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (MPElementType)selectedType {
 | 
			
		||||
 | 
			
		||||
    return [[MPiOSAppDelegate get] activeUserForMainThread].defaultType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - IBActions
 | 
			
		||||
 | 
			
		||||
- (IBAction)didToggleSwitch:(UISwitch *)sender {
 | 
			
		||||
 | 
			
		||||
    if (sender == self.savePasswordSwitch)
 | 
			
		||||
        [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
 | 
			
		||||
            MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
 | 
			
		||||
            if ((activeUser.saveKey = sender.on))
 | 
			
		||||
                [[MPiOSAppDelegate get] storeSavedKeyFor:activeUser];
 | 
			
		||||
            else
 | 
			
		||||
                [[MPiOSAppDelegate get] forgetSavedKeyFor:activeUser];
 | 
			
		||||
            [moc saveToStore];
 | 
			
		||||
        }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -1,54 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  MBUnlockViewController.h
 | 
			
		||||
//  MasterPassword
 | 
			
		||||
//
 | 
			
		||||
//  Created by Maarten Billemont on 22/02/12.
 | 
			
		||||
//  Copyright (c) 2012 Lyndir. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <UIKit/UIKit.h>
 | 
			
		||||
#import "LLGitTip.h"
 | 
			
		||||
 | 
			
		||||
@interface MPUnlockViewController : UIViewController<UITextFieldDelegate, UIScrollViewDelegate, UIWebViewDelegate>
 | 
			
		||||
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIImageView *spinner;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *passwordFieldLabel;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UITextField *passwordField;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *passwordView;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIScrollView *avatarsView;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *nameLabel;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *oldNameLabel;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIButton *avatarTemplate;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *createPasswordTipView;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *tip;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *passwordTipView;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *passwordTipLabel;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *wordWall;
 | 
			
		||||
@property(strong, nonatomic) IBOutlet UILongPressGestureRecognizer *targetedUserActionGesture;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *uiContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *shareContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *tipsTipContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet LLGitTip *gitTipButton;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIWebView *newsView;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *emergencyGeneratorContainer;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UITextField *emergencyName;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UITextField *emergencyMasterPassword;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UITextField *emergencySite;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIStepper *emergencyCounterStepper;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UISegmentedControl *emergencyTypeControl;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UILabel *emergencyCounter;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIActivityIndicatorView *emergencyActivity;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIButton *emergencyPassword;
 | 
			
		||||
@property(weak, nonatomic) IBOutlet UIView *emergencyContentTipContainer;
 | 
			
		||||
 | 
			
		||||
- (IBAction)targetedUserAction:(UILongPressGestureRecognizer *)sender;
 | 
			
		||||
- (IBAction)facebook:(id)sender;
 | 
			
		||||
- (IBAction)twitter:(id)sender;
 | 
			
		||||
- (IBAction)google:(id)sender;
 | 
			
		||||
- (IBAction)mail:(id)sender;
 | 
			
		||||
- (IBAction)add:(id)sender;
 | 
			
		||||
- (IBAction)emergencyOpen:(id)sender;
 | 
			
		||||
- (IBAction)emergencyClose:(id)sender;
 | 
			
		||||
- (IBAction)emergencyCopy:(id)sender;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -805,7 +805,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
 | 
			
		||||
            case MPActiveUserStateUserName:
 | 
			
		||||
            case MPActiveUserStateMasterPasswordChoice:
 | 
			
		||||
            case MPActiveUserStateMasterPasswordConfirmation: {
 | 
			
		||||
                self.navigationBarToTopConstraint.priority = UILayoutPriorityDefaultHigh;
 | 
			
		||||
                [self.navigationBarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                self.avatarCollectionView.scrollEnabled = NO;
 | 
			
		||||
                self.entryContainer.alpha = 1;
 | 
			
		||||
                self.footerContainer.alpha = 1;
 | 
			
		||||
@@ -813,14 +813,13 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case MPActiveUserStateMinimized: {
 | 
			
		||||
                self.navigationBarToTopConstraint.priority = 1;
 | 
			
		||||
                [self.navigationBarToTopConstraint layoutWithPriority:1];
 | 
			
		||||
                self.avatarCollectionView.scrollEnabled = NO;
 | 
			
		||||
                self.entryContainer.alpha = 0;
 | 
			
		||||
                self.footerContainer.alpha = 0;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        [self.navigationBarToTopConstraint apply];
 | 
			
		||||
    }                completion:^(BOOL finished) {
 | 
			
		||||
        dbg(@"resume updates");
 | 
			
		||||
        [_afterUpdates setSuspended:NO];
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,8 @@
 | 
			
		||||
    if (!self.initialURL)
 | 
			
		||||
        self.initialURL = [NSURL URLWithString:@"http://masterpasswordapp.com"];
 | 
			
		||||
 | 
			
		||||
    self.webNavigationItem.title = self.initialURL.host;
 | 
			
		||||
 | 
			
		||||
    self.webView.alpha = 0;
 | 
			
		||||
    [self.webView loadRequest:[[NSURLRequest alloc] initWithURL:self.initialURL]];
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -364,27 +364,34 @@
 | 
			
		||||
 | 
			
		||||
- (void)showExportForVC:(UIViewController *)viewController {
 | 
			
		||||
 | 
			
		||||
    [PearlAlert showNotice:
 | 
			
		||||
            @"This will export all your site names.\n\n"
 | 
			
		||||
                    @"You can open the export with a text editor to get an overview of all your sites.\n\n"
 | 
			
		||||
                    @"The file also acts as a personal backup of your site list in case you don't sync with iCloud/iTunes."
 | 
			
		||||
         tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
        [PearlAlert showAlertWithTitle:@"Reveal Passwords?" message:
 | 
			
		||||
                @"Would you like to make all your passwords visible in the export?\n\n"
 | 
			
		||||
                        @"A safe export will only include your stored passwords, in an encrypted manner, "
 | 
			
		||||
                        @"making the result safe from falling in the wrong hands.\n\n"
 | 
			
		||||
                        @"If all your passwords are shown and somebody else finds the export, "
 | 
			
		||||
                        @"they could gain access to all your sites!"
 | 
			
		||||
                             viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                     tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
 | 
			
		||||
            if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 0)
 | 
			
		||||
                // Safe Export
 | 
			
		||||
                [self showExportRevealPasswords:NO forVC:viewController];
 | 
			
		||||
            if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 1)
 | 
			
		||||
                // Show Passwords
 | 
			
		||||
                [self showExportRevealPasswords:YES forVC:viewController];
 | 
			
		||||
        } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Safe Export", @"Show Passwords", nil];
 | 
			
		||||
    } otherTitles:nil];
 | 
			
		||||
    [PearlAlert showAlertWithTitle:@"Exporting Your Sites"
 | 
			
		||||
                           message:@"An export is great for keeping a "
 | 
			
		||||
                                           @"backup list of your accounts.\n\n"
 | 
			
		||||
                                           @"When the file is ready, you will be "
 | 
			
		||||
                                           @"able to mail it to yourself.\n"
 | 
			
		||||
                                           @"You can open it with a text editor or "
 | 
			
		||||
                                           @"with Master Password if you need to "
 | 
			
		||||
                                           @"restore your list of sites."
 | 
			
		||||
                         viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                 tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
        if (buttonIndex != [alert cancelButtonIndex])
 | 
			
		||||
            [PearlAlert showAlertWithTitle:@"Show Passwords?"
 | 
			
		||||
                                   message:@"Would you like to make all your passwords "
 | 
			
		||||
                                                   @"visible in the export file?\n\n"
 | 
			
		||||
                                                   @"A safe export will include all sites "
 | 
			
		||||
                                                   @"but make their passwords invisible.\n"
 | 
			
		||||
                                                   @"It is great as a backup and remains "
 | 
			
		||||
                                                   @"safe when fallen in the wrong hands."
 | 
			
		||||
                                 viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                         tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
 | 
			
		||||
                if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 0)
 | 
			
		||||
                    // Safe Export
 | 
			
		||||
                    [self showExportRevealPasswords:NO forVC:viewController];
 | 
			
		||||
                if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 1)
 | 
			
		||||
                    // Show Passwords
 | 
			
		||||
                    [self showExportRevealPasswords:YES forVC:viewController];
 | 
			
		||||
            } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Safe Export", @"Show Passwords", nil];
 | 
			
		||||
    } cancelTitle:@"Cancel" otherTitles:@"Export Sites", nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)showExportRevealPasswords:(BOOL)revealPasswords forVC:(UIViewController *)viewController {
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -41,7 +41,6 @@
 | 
			
		||||
		93D399BBC0A7EC746CB1B19B /* MPLogsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D391943675426839501BB8 /* MPLogsViewController.h */; };
 | 
			
		||||
		93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */; };
 | 
			
		||||
		93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D8A953779B35403AF6E /* PearlUICollectionView.m */; };
 | 
			
		||||
		93D39B21156EC9A0B4C2BC83 /* MPPreferencesViewControllerOld.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390381D3D3AE241B5D341 /* MPPreferencesViewControllerOld.m */; };
 | 
			
		||||
		93D39B76DD5AB108BA8928E8 /* UIScrollView+PearlAdjustInsets.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */; };
 | 
			
		||||
		93D39B842AB9A5D072810D76 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */; };
 | 
			
		||||
		93D39B8F90F58A5D158DDBA3 /* MPPasswordsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3924EE15017F8A12CB436 /* MPPasswordsViewController.m */; };
 | 
			
		||||
@@ -50,6 +49,7 @@
 | 
			
		||||
		93D39C8AD8EAB747856B3A8C /* LLModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3923B42DA2DA18F287092 /* LLModel.m */; };
 | 
			
		||||
		93D39CB5E2EC1078E898F46A /* MPPasswordLargeCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3937863061C3916AF7AD2 /* MPPasswordLargeCell.m */; };
 | 
			
		||||
		93D39D596A2E376D6F6F5DA1 /* MPCombinedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D393310223DDB35218467A /* MPCombinedViewController.m */; };
 | 
			
		||||
		93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39CC01630D0421205C4C4 /* MPNavigationController.m */; };
 | 
			
		||||
		93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
 | 
			
		||||
		93D39E34FD28D24FE3442C48 /* UITextView+PearlAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3977321EB249981821AB0 /* UITextView+PearlAttributes.m */; };
 | 
			
		||||
		93D39EAA4D064193074D3021 /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A813CA9D7E192261ED2 /* MPFixable.m */; };
 | 
			
		||||
@@ -249,19 +249,10 @@
 | 
			
		||||
		DABD3C091711E2DC00CF925C /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BBA1711E2DC00CF925C /* MPUserEntity.m */; };
 | 
			
		||||
		DABD3C141711E2DC00CF925C /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BD01711E2DC00CF925C /* MasterPassword.xcdatamodeld */; };
 | 
			
		||||
		DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BD91711E2DC00CF925C /* MPiOSAppDelegate.m */; };
 | 
			
		||||
		DABD3C161711E2DC00CF925C /* MPAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BDB1711E2DC00CF925C /* MPAppViewController.m */; };
 | 
			
		||||
		DABD3C171711E2DC00CF925C /* MPAppsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BDD1711E2DC00CF925C /* MPAppsViewController.m */; };
 | 
			
		||||
		DABD3C181711E2DC00CF925C /* MPElementListAllViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BDF1711E2DC00CF925C /* MPElementListAllViewController.m */; };
 | 
			
		||||
		DABD3C191711E2DC00CF925C /* MPElementListCellView.xib in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BE01711E2DC00CF925C /* MPElementListCellView.xib */; };
 | 
			
		||||
		DABD3C1A1711E2DC00CF925C /* MPElementListController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BE21711E2DC00CF925C /* MPElementListController.m */; };
 | 
			
		||||
		DABD3C1B1711E2DC00CF925C /* MPElementListSearchController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BE51711E2DC00CF925C /* MPElementListSearchController.m */; };
 | 
			
		||||
		DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BE71711E2DC00CF925C /* MPGuideViewController.m */; };
 | 
			
		||||
		DABD3C1D1711E2DC00CF925C /* MPMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BE91711E2DC00CF925C /* MPMainViewController.m */; };
 | 
			
		||||
		DABD3C1E1711E2DC00CF925C /* MPPreferencesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BEB1711E2DC00CF925C /* MPPreferencesViewController.m */; };
 | 
			
		||||
		DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BED1711E2DC00CF925C /* MPTypeViewController.m */; };
 | 
			
		||||
		DABD3C201711E2DC00CF925C /* MPUnlockViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BEF1711E2DC00CF925C /* MPUnlockViewController.m */; };
 | 
			
		||||
		DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BF11711E2DC00CF925C /* MPiOSConfig.m */; };
 | 
			
		||||
		DABD3C221711E2DC00CF925C /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BF21711E2DC00CF925C /* MainStoryboard_iPhone.storyboard */; };
 | 
			
		||||
		DABD3C241711E2DC00CF925C /* MasterPassword.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BF81711E2DC00CF925C /* MasterPassword.entitlements */; };
 | 
			
		||||
		DABD3C251711E2DC00CF925C /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BF91711E2DC00CF925C /* Settings.bundle */; };
 | 
			
		||||
		DABD3C261711E2DC00CF925C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BFA1711E2DC00CF925C /* InfoPlist.strings */; };
 | 
			
		||||
@@ -511,7 +502,6 @@
 | 
			
		||||
/* End PBXCopyFilesBuildPhase section */
 | 
			
		||||
 | 
			
		||||
/* Begin PBXFileReference section */
 | 
			
		||||
		93D390381D3D3AE241B5D341 /* MPPreferencesViewControllerOld.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPreferencesViewControllerOld.m; sourceTree = "<group>"; };
 | 
			
		||||
		93D390519405B76CC6A57C4F /* MPCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCell.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; };
 | 
			
		||||
		93D39097C0AAE62C1C321BFC /* MPPasswordTypesCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordTypesCell.m; sourceTree = "<group>"; };
 | 
			
		||||
@@ -540,6 +530,7 @@
 | 
			
		||||
		93D395BA6B2CFF5F49A4D25F /* MPPasswordLargeStoredCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeStoredCell.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D3966B527CA47A0A661CE2 /* MPPasswordLargeDeleteCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeDeleteCell.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = "<group>"; };
 | 
			
		||||
		93D3970502644794E8A027BE /* MPNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPNavigationController.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D3971FE104BB4052484151 /* MPUsersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUsersViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D39730673227EFF6DEFF19 /* MPSetupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSetupViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D3977321EB249981821AB0 /* UITextView+PearlAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITextView+PearlAttributes.m"; sourceTree = "<group>"; };
 | 
			
		||||
@@ -551,7 +542,6 @@
 | 
			
		||||
		93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPWebViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		93D3993422E207BF0B21D089 /* MPPasswordLargeGeneratedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeGeneratedCell.m; sourceTree = "<group>"; };
 | 
			
		||||
		93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCoachmarkViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		93D39961CD6A43648CC0B0DB /* MPPreferencesViewControllerOld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPreferencesViewControllerOld.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D39975CE5AEC99E3F086C7 /* MPPasswordCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordCell.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D3999693660C89A7465F4E /* MPCoachmarkViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCoachmarkViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUsersViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
@@ -574,6 +564,7 @@
 | 
			
		||||
		93D39C44361BE57AF0B3071F /* MPPasswordsSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordsSegue.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D39C86E984EC65DA5ACB1D /* MPAppSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppSettingsViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D39C8E26B06F01566785B7 /* LLToggleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLToggleViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		93D39CC01630D0421205C4C4 /* MPNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNavigationController.m; sourceTree = "<group>"; };
 | 
			
		||||
		93D39CDD434AFD6E1B0DA359 /* MPEmergencyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEmergencyViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D39CE1138FDA4D3D1B847A /* MPPasswordLargeGeneratedCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeGeneratedCell.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D39CF8ADF4542CDC4CD385 /* MPCombinedViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCombinedViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
@@ -1310,31 +1301,14 @@
 | 
			
		||||
		DABD3BD41711E2DC00CF925C /* MasterPassword 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 4.xcdatamodel"; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BD81711E2DC00CF925C /* MPiOSAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPiOSAppDelegate.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BD91711E2DC00CF925C /* MPiOSAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPiOSAppDelegate.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BDA1711E2DC00CF925C /* MPAppViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BDB1711E2DC00CF925C /* MPAppViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BDC1711E2DC00CF925C /* MPAppsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppsViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BDD1711E2DC00CF925C /* MPAppsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppsViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BDE1711E2DC00CF925C /* MPElementListAllViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListAllViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BDF1711E2DC00CF925C /* MPElementListAllViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementListAllViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BE01711E2DC00CF925C /* MPElementListCellView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPElementListCellView.xib; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BE11711E2DC00CF925C /* MPElementListController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListController.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BE21711E2DC00CF925C /* MPElementListController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementListController.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BE31711E2DC00CF925C /* MPElementListDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListDelegate.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BE41711E2DC00CF925C /* MPElementListSearchController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListSearchController.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BE51711E2DC00CF925C /* MPElementListSearchController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementListSearchController.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BE61711E2DC00CF925C /* MPGuideViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPGuideViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BE71711E2DC00CF925C /* MPGuideViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPGuideViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BE81711E2DC00CF925C /* MPMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMainViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BE91711E2DC00CF925C /* MPMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMainViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BEA1711E2DC00CF925C /* MPPreferencesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPreferencesViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BEB1711E2DC00CF925C /* MPPreferencesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPreferencesViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BEC1711E2DC00CF925C /* MPTypeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPTypeViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BED1711E2DC00CF925C /* MPTypeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTypeViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BEE1711E2DC00CF925C /* MPUnlockViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUnlockViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BEF1711E2DC00CF925C /* MPUnlockViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUnlockViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BF01711E2DC00CF925C /* MPiOSConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPiOSConfig.h; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BF11711E2DC00CF925C /* MPiOSConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPiOSConfig.m; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BF21711E2DC00CF925C /* MainStoryboard_iPhone.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MainStoryboard_iPhone.storyboard; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BF31711E2DC00CF925C /* MasterPassword-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MasterPassword-Info.plist"; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BF41711E2DC00CF925C /* MasterPassword-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MasterPassword-Prefix.pch"; sourceTree = "<group>"; };
 | 
			
		||||
		DABD3BF81711E2DC00CF925C /* MasterPassword.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = "<group>"; };
 | 
			
		||||
@@ -2523,35 +2497,16 @@
 | 
			
		||||
				93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */,
 | 
			
		||||
				93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */,
 | 
			
		||||
				93D39CDD434AFD6E1B0DA359 /* MPEmergencyViewController.h */,
 | 
			
		||||
				93D390381D3D3AE241B5D341 /* MPPreferencesViewControllerOld.m */,
 | 
			
		||||
				93D39961CD6A43648CC0B0DB /* MPPreferencesViewControllerOld.h */,
 | 
			
		||||
				DABD3BD81711E2DC00CF925C /* MPiOSAppDelegate.h */,
 | 
			
		||||
				DABD3BD91711E2DC00CF925C /* MPiOSAppDelegate.m */,
 | 
			
		||||
				DABD3BDA1711E2DC00CF925C /* MPAppViewController.h */,
 | 
			
		||||
				DABD3BDB1711E2DC00CF925C /* MPAppViewController.m */,
 | 
			
		||||
				DABD3BDC1711E2DC00CF925C /* MPAppsViewController.h */,
 | 
			
		||||
				DABD3BDD1711E2DC00CF925C /* MPAppsViewController.m */,
 | 
			
		||||
				DABD3BDE1711E2DC00CF925C /* MPElementListAllViewController.h */,
 | 
			
		||||
				DABD3BDF1711E2DC00CF925C /* MPElementListAllViewController.m */,
 | 
			
		||||
				DABD3BE01711E2DC00CF925C /* MPElementListCellView.xib */,
 | 
			
		||||
				DABD3BE11711E2DC00CF925C /* MPElementListController.h */,
 | 
			
		||||
				DABD3BE21711E2DC00CF925C /* MPElementListController.m */,
 | 
			
		||||
				DABD3BE31711E2DC00CF925C /* MPElementListDelegate.h */,
 | 
			
		||||
				DABD3BE41711E2DC00CF925C /* MPElementListSearchController.h */,
 | 
			
		||||
				DABD3BE51711E2DC00CF925C /* MPElementListSearchController.m */,
 | 
			
		||||
				DABD3BE61711E2DC00CF925C /* MPGuideViewController.h */,
 | 
			
		||||
				DABD3BE71711E2DC00CF925C /* MPGuideViewController.m */,
 | 
			
		||||
				DABD3BE81711E2DC00CF925C /* MPMainViewController.h */,
 | 
			
		||||
				DABD3BE91711E2DC00CF925C /* MPMainViewController.m */,
 | 
			
		||||
				DABD3BEA1711E2DC00CF925C /* MPPreferencesViewController.h */,
 | 
			
		||||
				DABD3BEB1711E2DC00CF925C /* MPPreferencesViewController.m */,
 | 
			
		||||
				DABD3BEC1711E2DC00CF925C /* MPTypeViewController.h */,
 | 
			
		||||
				DABD3BED1711E2DC00CF925C /* MPTypeViewController.m */,
 | 
			
		||||
				DABD3BEE1711E2DC00CF925C /* MPUnlockViewController.h */,
 | 
			
		||||
				DABD3BEF1711E2DC00CF925C /* MPUnlockViewController.m */,
 | 
			
		||||
				DABD3BF01711E2DC00CF925C /* MPiOSConfig.h */,
 | 
			
		||||
				DABD3BF11711E2DC00CF925C /* MPiOSConfig.m */,
 | 
			
		||||
				DABD3BF21711E2DC00CF925C /* MainStoryboard_iPhone.storyboard */,
 | 
			
		||||
				DABD3BF31711E2DC00CF925C /* MasterPassword-Info.plist */,
 | 
			
		||||
				DABD3BF41711E2DC00CF925C /* MasterPassword-Prefix.pch */,
 | 
			
		||||
				DABD3BF81711E2DC00CF925C /* MasterPassword.entitlements */,
 | 
			
		||||
@@ -2595,6 +2550,8 @@
 | 
			
		||||
				93D390FD93EFCFECB5193DEF /* MPPasswordsCoachmarkViewController.h */,
 | 
			
		||||
				93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */,
 | 
			
		||||
				93D39F556F2F142740A65E59 /* MPWebViewController.h */,
 | 
			
		||||
				93D39CC01630D0421205C4C4 /* MPNavigationController.m */,
 | 
			
		||||
				93D3970502644794E8A027BE /* MPNavigationController.h */,
 | 
			
		||||
			);
 | 
			
		||||
			path = iOS;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
@@ -3676,9 +3633,7 @@
 | 
			
		||||
				DADEF4121810D2940052CA3E /* love-lyndir.button.green.png in Resources */,
 | 
			
		||||
				DABD3B9D1711E29800CF925C /* social-twitter.png in Resources */,
 | 
			
		||||
				DABD3B9E1711E29800CF925C /* social-twitter@2x.png in Resources */,
 | 
			
		||||
				DABD3C191711E2DC00CF925C /* MPElementListCellView.xib in Resources */,
 | 
			
		||||
				DA854C8418D4CFBF00106317 /* avatar-add.png in Resources */,
 | 
			
		||||
				DABD3C221711E2DC00CF925C /* MainStoryboard_iPhone.storyboard in Resources */,
 | 
			
		||||
				DABD3C241711E2DC00CF925C /* MasterPassword.entitlements in Resources */,
 | 
			
		||||
				DABD3C251711E2DC00CF925C /* Settings.bundle in Resources */,
 | 
			
		||||
				DABD3C261711E2DC00CF925C /* InfoPlist.strings in Resources */,
 | 
			
		||||
@@ -3777,16 +3732,9 @@
 | 
			
		||||
				DABD3C091711E2DC00CF925C /* MPUserEntity.m in Sources */,
 | 
			
		||||
				DABD3C141711E2DC00CF925C /* MasterPassword.xcdatamodeld in Sources */,
 | 
			
		||||
				DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */,
 | 
			
		||||
				DABD3C161711E2DC00CF925C /* MPAppViewController.m in Sources */,
 | 
			
		||||
				DABD3C171711E2DC00CF925C /* MPAppsViewController.m in Sources */,
 | 
			
		||||
				DABD3C181711E2DC00CF925C /* MPElementListAllViewController.m in Sources */,
 | 
			
		||||
				DABD3C1A1711E2DC00CF925C /* MPElementListController.m in Sources */,
 | 
			
		||||
				DABD3C1B1711E2DC00CF925C /* MPElementListSearchController.m in Sources */,
 | 
			
		||||
				DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */,
 | 
			
		||||
				DABD3C1D1711E2DC00CF925C /* MPMainViewController.m in Sources */,
 | 
			
		||||
				DABD3C1E1711E2DC00CF925C /* MPPreferencesViewController.m in Sources */,
 | 
			
		||||
				DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */,
 | 
			
		||||
				DABD3C201711E2DC00CF925C /* MPUnlockViewController.m in Sources */,
 | 
			
		||||
				DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */,
 | 
			
		||||
				DABD3C271711E2DC00CF925C /* main.m in Sources */,
 | 
			
		||||
				93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */,
 | 
			
		||||
@@ -3805,13 +3753,13 @@
 | 
			
		||||
				93D391ED37C9F687FA51EAA1 /* MPEmergencySegue.m in Sources */,
 | 
			
		||||
				93D394B5036C882B33C71872 /* MPPasswordsSegue.m in Sources */,
 | 
			
		||||
				93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */,
 | 
			
		||||
				93D39B21156EC9A0B4C2BC83 /* MPPreferencesViewControllerOld.m in Sources */,
 | 
			
		||||
				93D39BA1EA3CAAC8A220B4A6 /* MPAppSettingsViewController.m in Sources */,
 | 
			
		||||
				93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */,
 | 
			
		||||
				93D391C07818F4C2DC1B6956 /* MPPasswordsCoachmarkViewController.m in Sources */,
 | 
			
		||||
				93D39EAA4D064193074D3021 /* MPFixable.m in Sources */,
 | 
			
		||||
				93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */,
 | 
			
		||||
				93D398BD8B83FEE8BE4EFFFC /* MPPasswordLargeDeleteCell.m in Sources */,
 | 
			
		||||
				93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */,
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -251,7 +251,7 @@
 | 
			
		||||
                                                    <segue destination="Sd5-eW-Cx2" kind="modal" identifier="web" id="gtb-zE-u9H"/>
 | 
			
		||||
                                                </connections>
 | 
			
		||||
                                            </button>
 | 
			
		||||
                                            <view userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="069-Pu-yXe" userLabel="GitTip Tip">
 | 
			
		||||
                                            <view userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="069-Pu-yXe" userLabel="Thanks Tip">
 | 
			
		||||
                                                <rect key="frame" x="42" y="0.0" width="236" height="60"/>
 | 
			
		||||
                                                <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
 | 
			
		||||
                                                <subviews>
 | 
			
		||||
@@ -410,7 +410,7 @@
 | 
			
		||||
        <!--Navigation Controller-->
 | 
			
		||||
        <scene sceneID="bzn-yi-kMJ">
 | 
			
		||||
            <objects>
 | 
			
		||||
                <navigationController definesPresentationContext="YES" navigationBarHidden="YES" id="Q1S-vU-GGO" sceneMemberID="viewController">
 | 
			
		||||
                <navigationController definesPresentationContext="YES" navigationBarHidden="YES" id="Q1S-vU-GGO" customClass="MPNavigationController" sceneMemberID="viewController">
 | 
			
		||||
                    <simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="lightContent"/>
 | 
			
		||||
                    <navigationBar key="navigationBar" contentMode="scaleToFill" id="4yl-zs-iUd">
 | 
			
		||||
                        <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
@@ -504,7 +504,7 @@
 | 
			
		||||
                        <sections>
 | 
			
		||||
                            <tableViewSection id="FEv-Rb-jst">
 | 
			
		||||
                                <cells>
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" rowHeight="97" id="R30-AU-bR6" userLabel="Sign Out">
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" rowHeight="97" id="R30-AU-bR6" userLabel="Sign Out">
 | 
			
		||||
                                        <rect key="frame" x="0.0" y="0.0" width="320" height="97"/>
 | 
			
		||||
                                        <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="R30-AU-bR6" id="f6h-Ff-2Qc">
 | 
			
		||||
@@ -538,7 +538,7 @@
 | 
			
		||||
                                        </tableViewCellContentView>
 | 
			
		||||
                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                    </tableViewCell>
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" rowHeight="216" id="B8R-iE-Ffe" userLabel="Default Password Type">
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" rowHeight="216" id="B8R-iE-Ffe" userLabel="Default Password Type">
 | 
			
		||||
                                        <rect key="frame" x="0.0" y="97" width="320" height="216"/>
 | 
			
		||||
                                        <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="B8R-iE-Ffe" id="8r5-Zc-TRj">
 | 
			
		||||
@@ -604,7 +604,7 @@
 | 
			
		||||
                                        </tableViewCellContentView>
 | 
			
		||||
                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                    </tableViewCell>
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" rowHeight="220" id="Sz1-JP-dw2" userLabel="Avatar">
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" rowHeight="220" id="Sz1-JP-dw2" userLabel="Avatar">
 | 
			
		||||
                                        <rect key="frame" x="0.0" y="313" width="320" height="220"/>
 | 
			
		||||
                                        <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Sz1-JP-dw2" id="R4X-LE-ir9">
 | 
			
		||||
@@ -684,7 +684,7 @@
 | 
			
		||||
                                        </tableViewCellContentView>
 | 
			
		||||
                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                    </tableViewCell>
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" rowHeight="230" id="fRZ-Uh-FR8" userLabel="Save Password">
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" rowHeight="230" id="fRZ-Uh-FR8" userLabel="Save Password">
 | 
			
		||||
                                        <rect key="frame" x="0.0" y="533" width="320" height="230"/>
 | 
			
		||||
                                        <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fRZ-Uh-FR8" id="qCQ-L5-teL">
 | 
			
		||||
@@ -728,7 +728,7 @@
 | 
			
		||||
                                        </tableViewCellContentView>
 | 
			
		||||
                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                    </tableViewCell>
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" rowHeight="97" id="9QG-lM-ymM" userLabel="Feedback">
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" rowHeight="97" id="9QG-lM-ymM" userLabel="Feedback">
 | 
			
		||||
                                        <rect key="frame" x="0.0" y="763" width="320" height="97"/>
 | 
			
		||||
                                        <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="9QG-lM-ymM" id="hK8-XQ-lLz">
 | 
			
		||||
@@ -762,7 +762,7 @@
 | 
			
		||||
                                        </tableViewCellContentView>
 | 
			
		||||
                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                    </tableViewCell>
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" rowHeight="97" id="eth-Dc-JYn" userLabel="Reveal Coachmarks">
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" rowHeight="97" id="eth-Dc-JYn" userLabel="Reveal Coachmarks">
 | 
			
		||||
                                        <rect key="frame" x="0.0" y="860" width="320" height="97"/>
 | 
			
		||||
                                        <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="eth-Dc-JYn" id="8m6-pP-lda">
 | 
			
		||||
@@ -796,7 +796,7 @@
 | 
			
		||||
                                        </tableViewCellContentView>
 | 
			
		||||
                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                    </tableViewCell>
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" rowHeight="110" id="UdB-BV-AHA" userLabel="Check Inconsistencies">
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" rowHeight="110" id="UdB-BV-AHA" userLabel="Check Inconsistencies">
 | 
			
		||||
                                        <rect key="frame" x="0.0" y="957" width="320" height="110"/>
 | 
			
		||||
                                        <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="UdB-BV-AHA" id="V2Y-nu-jhZ">
 | 
			
		||||
@@ -830,7 +830,7 @@
 | 
			
		||||
                                        </tableViewCellContentView>
 | 
			
		||||
                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                    </tableViewCell>
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" rowHeight="125" id="IVT-Rs-nTu" userLabel="Export">
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" rowHeight="125" id="IVT-Rs-nTu" userLabel="Export">
 | 
			
		||||
                                        <rect key="frame" x="0.0" y="1067" width="320" height="125"/>
 | 
			
		||||
                                        <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="IVT-Rs-nTu" id="Q5J-2f-mmz">
 | 
			
		||||
@@ -865,6 +865,86 @@
 | 
			
		||||
                                        </tableViewCellContentView>
 | 
			
		||||
                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                    </tableViewCell>
 | 
			
		||||
                                    <tableViewCell contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" rowHeight="153" id="hmf-Wz-9l2" userLabel="Footer">
 | 
			
		||||
                                        <rect key="frame" x="0.0" y="1192" width="320" height="153"/>
 | 
			
		||||
                                        <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hmf-Wz-9l2" id="AL3-2q-tgO">
 | 
			
		||||
                                            <rect key="frame" x="0.0" y="0.0" width="320" height="152"/>
 | 
			
		||||
                                            <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
                                            <subviews>
 | 
			
		||||
                                                <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" text="© 2012-2014, Maarten Billemont (lhunath)" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sPw-mV-mFF">
 | 
			
		||||
                                                    <rect key="frame" x="20" y="4" width="280" height="12"/>
 | 
			
		||||
                                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
 | 
			
		||||
                                                    <fontDescription key="fontDescription" name="Exo2.0-Thin" family="Exo 2.0" pointSize="10"/>
 | 
			
		||||
                                                    <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                                    <nil key="highlightedColor"/>
 | 
			
		||||
                                                </label>
 | 
			
		||||
                                                <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Rl7-cr-FHf">
 | 
			
		||||
                                                    <rect key="frame" x="20" y="24" width="280" height="26"/>
 | 
			
		||||
                                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
 | 
			
		||||
                                                    <fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="11"/>
 | 
			
		||||
                                                    <state key="normal" title="Home Page">
 | 
			
		||||
                                                        <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                                    </state>
 | 
			
		||||
                                                    <connections>
 | 
			
		||||
                                                        <action selector="homePageButton:" destination="JFc-sj-awD" eventType="touchUpInside" id="ptD-cv-NMr"/>
 | 
			
		||||
                                                    </connections>
 | 
			
		||||
                                                </button>
 | 
			
		||||
                                                <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="epW-Rm-9St">
 | 
			
		||||
                                                    <rect key="frame" x="20" y="58" width="280" height="26"/>
 | 
			
		||||
                                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
 | 
			
		||||
                                                    <fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="11"/>
 | 
			
		||||
                                                    <state key="normal" title="Understanding Master Password's Security">
 | 
			
		||||
                                                        <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                                    </state>
 | 
			
		||||
                                                    <connections>
 | 
			
		||||
                                                        <action selector="securityButton:" destination="JFc-sj-awD" eventType="touchUpInside" id="Efv-cp-Xfh"/>
 | 
			
		||||
                                                    </connections>
 | 
			
		||||
                                                </button>
 | 
			
		||||
                                                <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LTN-ch-h8D">
 | 
			
		||||
                                                    <rect key="frame" x="20" y="92" width="280" height="26"/>
 | 
			
		||||
                                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
 | 
			
		||||
                                                    <fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="11"/>
 | 
			
		||||
                                                    <state key="normal" title="Get the Master Password source code">
 | 
			
		||||
                                                        <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                                    </state>
 | 
			
		||||
                                                    <connections>
 | 
			
		||||
                                                        <action selector="sourceButton:" destination="JFc-sj-awD" eventType="touchUpInside" id="Y3O-di-CZo"/>
 | 
			
		||||
                                                    </connections>
 | 
			
		||||
                                                </button>
 | 
			
		||||
                                                <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Z60-lc-Nka">
 | 
			
		||||
                                                    <rect key="frame" x="20" y="126" width="280" height="26"/>
 | 
			
		||||
                                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
 | 
			
		||||
                                                    <fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="11"/>
 | 
			
		||||
                                                    <state key="normal" title="Send Thanks">
 | 
			
		||||
                                                        <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                                    </state>
 | 
			
		||||
                                                    <connections>
 | 
			
		||||
                                                        <action selector="thanksButton:" destination="JFc-sj-awD" eventType="touchUpInside" id="SqG-hx-mzF"/>
 | 
			
		||||
                                                    </connections>
 | 
			
		||||
                                                </button>
 | 
			
		||||
                                            </subviews>
 | 
			
		||||
                                            <constraints>
 | 
			
		||||
                                                <constraint firstAttribute="trailing" secondItem="LTN-ch-h8D" secondAttribute="trailing" constant="20" symbolic="YES" id="1W6-6Q-Bdv"/>
 | 
			
		||||
                                                <constraint firstItem="LTN-ch-h8D" firstAttribute="top" secondItem="epW-Rm-9St" secondAttribute="bottom" constant="8" symbolic="YES" id="7YP-IL-yTY"/>
 | 
			
		||||
                                                <constraint firstItem="Z60-lc-Nka" firstAttribute="leading" secondItem="AL3-2q-tgO" secondAttribute="leading" constant="20" symbolic="YES" id="Fnk-lP-q0U"/>
 | 
			
		||||
                                                <constraint firstAttribute="bottom" secondItem="Z60-lc-Nka" secondAttribute="bottom" id="Jbk-vs-bo1"/>
 | 
			
		||||
                                                <constraint firstItem="sPw-mV-mFF" firstAttribute="leading" secondItem="AL3-2q-tgO" secondAttribute="leading" constant="20" symbolic="YES" id="Jme-5a-dNH"/>
 | 
			
		||||
                                                <constraint firstItem="LTN-ch-h8D" firstAttribute="leading" secondItem="AL3-2q-tgO" secondAttribute="leading" constant="20" symbolic="YES" id="RpC-WA-bnf"/>
 | 
			
		||||
                                                <constraint firstItem="sPw-mV-mFF" firstAttribute="top" secondItem="AL3-2q-tgO" secondAttribute="top" constant="4" id="X4M-st-0KA"/>
 | 
			
		||||
                                                <constraint firstItem="Z60-lc-Nka" firstAttribute="top" secondItem="LTN-ch-h8D" secondAttribute="bottom" constant="8" symbolic="YES" id="YSW-fw-h4i"/>
 | 
			
		||||
                                                <constraint firstItem="epW-Rm-9St" firstAttribute="top" secondItem="Rl7-cr-FHf" secondAttribute="bottom" constant="8" symbolic="YES" id="b0H-uh-d3G"/>
 | 
			
		||||
                                                <constraint firstItem="Rl7-cr-FHf" firstAttribute="top" secondItem="sPw-mV-mFF" secondAttribute="bottom" constant="8" symbolic="YES" id="gwp-Uq-BEm"/>
 | 
			
		||||
                                                <constraint firstAttribute="trailing" secondItem="Z60-lc-Nka" secondAttribute="trailing" constant="20" symbolic="YES" id="iCv-UX-pPf"/>
 | 
			
		||||
                                                <constraint firstAttribute="trailing" secondItem="Rl7-cr-FHf" secondAttribute="trailing" constant="20" symbolic="YES" id="oej-WB-7Vb"/>
 | 
			
		||||
                                                <constraint firstItem="Rl7-cr-FHf" firstAttribute="leading" secondItem="AL3-2q-tgO" secondAttribute="leading" constant="20" symbolic="YES" id="r2V-pM-d9B"/>
 | 
			
		||||
                                                <constraint firstItem="epW-Rm-9St" firstAttribute="leading" secondItem="AL3-2q-tgO" secondAttribute="leading" constant="20" symbolic="YES" id="rve-aQ-Ggt"/>
 | 
			
		||||
                                                <constraint firstAttribute="trailing" secondItem="epW-Rm-9St" secondAttribute="trailing" constant="20" symbolic="YES" id="sHt-wW-wHU"/>
 | 
			
		||||
                                                <constraint firstAttribute="trailing" secondItem="sPw-mV-mFF" secondAttribute="trailing" constant="20" symbolic="YES" id="xjb-mS-yVZ"/>
 | 
			
		||||
                                            </constraints>
 | 
			
		||||
                                        </tableViewCellContentView>
 | 
			
		||||
                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                    </tableViewCell>
 | 
			
		||||
                                </cells>
 | 
			
		||||
                            </tableViewSection>
 | 
			
		||||
                        </sections>
 | 
			
		||||
@@ -1130,6 +1210,13 @@
 | 
			
		||||
                                                                                <rect key="frame" x="0.0" y="0.0" width="300" height="100"/>
 | 
			
		||||
                                                                                <autoresizingMask key="autoresizingMask"/>
 | 
			
		||||
                                                                                <subviews>
 | 
			
		||||
                                                                                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="3" contentMode="left" text="> age of the universe" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="GrV-gX-eCo" userLabel="Strength">
 | 
			
		||||
                                                                                        <rect key="frame" x="0.0" y="0.0" width="300" height="12"/>
 | 
			
		||||
                                                                                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
 | 
			
		||||
                                                                                        <fontDescription key="fontDescription" type="system" pointSize="10"/>
 | 
			
		||||
                                                                                        <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
 | 
			
		||||
                                                                                        <nil key="highlightedColor"/>
 | 
			
		||||
                                                                                    </label>
 | 
			
		||||
                                                                                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.029999999999999999" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Long Password" lineBreakMode="clip" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qAD-3v-3aq" userLabel="Type">
 | 
			
		||||
                                                                                        <rect key="frame" x="-10" y="19" width="604" height="101"/>
 | 
			
		||||
                                                                                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
 | 
			
		||||
@@ -1251,10 +1338,13 @@
 | 
			
		||||
                                                                                <constraint firstAttribute="trailing" secondItem="q75-Uz-86O" secondAttribute="trailing" constant="8" id="ZsY-wg-aJt"/>
 | 
			
		||||
                                                                                <constraint firstItem="q75-Uz-86O" firstAttribute="leading" secondItem="302-fI-maQ" secondAttribute="leading" constant="8" id="cee-Hz-2IS"/>
 | 
			
		||||
                                                                                <constraint firstAttribute="trailing" secondItem="cOv-2G-EAP" secondAttribute="trailing" id="fNx-v1-XM3"/>
 | 
			
		||||
                                                                                <constraint firstItem="GrV-gX-eCo" firstAttribute="leading" secondItem="302-fI-maQ" secondAttribute="leading" id="hX4-Yf-rzp"/>
 | 
			
		||||
                                                                                <constraint firstItem="cOv-2G-EAP" firstAttribute="leading" secondItem="fQc-Fn-JDq" secondAttribute="trailing" constant="-9" id="hqr-ru-rB7"/>
 | 
			
		||||
                                                                                <constraint firstItem="GrV-gX-eCo" firstAttribute="top" secondItem="302-fI-maQ" secondAttribute="top" id="ptG-Jr-1R8"/>
 | 
			
		||||
                                                                                <constraint firstItem="cOv-2G-EAP" firstAttribute="centerY" secondItem="fQc-Fn-JDq" secondAttribute="centerY" id="rrx-LF-Hk9"/>
 | 
			
		||||
                                                                                <constraint firstItem="fQc-Fn-JDq" firstAttribute="centerY" secondItem="I2J-B6-5rE" secondAttribute="centerY" id="uR7-lg-A9q"/>
 | 
			
		||||
                                                                                <constraint firstItem="qek-2l-YQf" firstAttribute="leading" secondItem="302-fI-maQ" secondAttribute="leading" constant="8" id="wUJ-7N-Z1z"/>
 | 
			
		||||
                                                                                <constraint firstAttribute="trailing" secondItem="GrV-gX-eCo" secondAttribute="trailing" id="yDV-ZB-a8l"/>
 | 
			
		||||
                                                                            </constraints>
 | 
			
		||||
                                                                            <connections>
 | 
			
		||||
                                                                                <outlet property="contentField" destination="q75-Uz-86O" id="nbM-vd-uZi"/>
 | 
			
		||||
@@ -1262,6 +1352,7 @@
 | 
			
		||||
                                                                                <outlet property="counterLabel" destination="I2J-B6-5rE" id="C4b-gE-XHW"/>
 | 
			
		||||
                                                                                <outlet property="loginButton" destination="cOv-2G-EAP" id="WoR-eP-Ztq"/>
 | 
			
		||||
                                                                                <outlet property="nameLabel" destination="qek-2l-YQf" id="CcC-PM-kMx"/>
 | 
			
		||||
                                                                                <outlet property="strengthLabel" destination="GrV-gX-eCo" id="e6J-5c-Dln"/>
 | 
			
		||||
                                                                                <outlet property="typeLabel" destination="qAD-3v-3aq" id="rAM-Kf-5xO"/>
 | 
			
		||||
                                                                                <outlet property="upgradeButton" destination="iLD-rv-uZZ" id="OKi-9X-R6F"/>
 | 
			
		||||
                                                                            </connections>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user