2
0

Emergency generator, avatar change, improvements.

[ADDED]     Ability to change avatar while creating new user.
[FIXED]     Transition oddness.
[IMPROVED]  Remove passwordsVC while not needed.
[ADDED]     Emergency generator.
This commit is contained in:
Maarten Billemont 2014-04-12 14:43:41 -04:00
parent bd37f1d6a7
commit b2624c7572
23 changed files with 910 additions and 155 deletions

2
External/LoveLyndir vendored

@ -1 +1 @@
Subproject commit 0b858644cb58c357e055b41c2747ad9d45fa9ce3
Subproject commit ceed9e20009f2cf3679445e2c60b0f206aaef383

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit d462ada876939cab875e08736b1efc7af065848d
Subproject commit 8d3d345c4cc4c2630167d173767a856988c9d460

@ -1 +1 @@
Subproject commit ef9aa1c29ed6e1729be4d6a3dd65e2c8a289bf4c
Subproject commit c02affe877a6de49bbe4055b8dceed52613f4e12

View File

@ -408,11 +408,9 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
}
MPElementType type = activeUser.defaultType;
NSString *typeEntityClassName = [MPAlgorithmDefault classNameOfType:type];
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityClassName
inManagedObjectContext:context];
NSString *typeEntityName = [MPAlgorithmDefault classNameOfType:type];
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
element.name = siteName;
element.user = activeUser;
element.type = type;
@ -440,9 +438,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
else {
// Type requires a different class of element. Recreate the element.
MPElementEntity *newElement
= [NSEntityDescription insertNewObjectForEntityForName:[element.algorithm classNameOfType:type]
inManagedObjectContext:context];
NSString *typeEntityName = [element.algorithm classNameOfType:type];
MPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
newElement.type = type;
newElement.name = element.name;
newElement.user = element.user;
@ -648,8 +645,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
// Make sure there is a user.
if (!user) {
user = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass( [MPUserEntity class] )
inManagedObjectContext:context];
user = [MPUserEntity insertNewObjectInContext:context];
user.name = importUserName;
user.keyID = importKeyID;
dbg(@"Created User: %@", [user debugDescription]);
@ -665,9 +661,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
NSString *exportContent = siteElements[5];
// Create new site.
MPElementEntity
*element = [NSEntityDescription insertNewObjectForEntityForName:[MPAlgorithmForVersion( version ) classNameOfType:type]
inManagedObjectContext:context];
NSString *typeEntityName = [MPAlgorithmForVersion( version ) classNameOfType:type];
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
element.name = name;
element.user = user;
element.type = type;

View File

@ -103,9 +103,9 @@ const long MPAvatarAdd = 10000;
- (void)setAvatar:(long)avatar {
_avatar = avatar;
_avatar = avatar == MPAvatarAdd? MPAvatarAdd: (avatar + MPAvatarCount) % MPAvatarCount;
if (avatar == MPAvatarAdd) {
if (_avatar == MPAvatarAdd) {
self.avatarImageView.image = [UIImage imageNamed:@"avatar-add"];
self.name = strl( @"New User" );
_newUser = YES;

View File

@ -28,6 +28,4 @@ typedef NS_ENUM(NSUInteger, MPCombinedMode) {
@property(assign, nonatomic) MPCombinedMode mode;
- (IBAction)doSignOut:(UIBarButtonItem *)sender;
@end

View File

@ -17,21 +17,22 @@
//
#import "MPCombinedViewController.h"
#import "MPiOSAppDelegate.h"
#import "MPAppDelegate_Store.h"
#import "MPAppDelegate_Key.h"
#import "MPUsersViewController.h"
#import "MPPasswordsViewController.h"
#import "MPEmergencySegue.h"
#import "MPEmergencyViewController.h"
#import "MPPasswordsSegue.h"
@interface MPCombinedViewController()
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *passwordsTopConstraint;
@property(nonatomic, strong) MPUsersViewController *usersVC;
@property(nonatomic, strong) MPPasswordsViewController *passwordsVC;
@property(nonatomic, weak) MPUsersViewController *usersVC;
@property(nonatomic, weak) MPEmergencyViewController *emergencyVC;
@end
@implementation MPCombinedViewController {
NSArray *_notificationObservers;
MPPasswordsViewController *_passwordsVC;
}
- (void)viewDidLoad {
@ -66,8 +67,16 @@
if ([segue.identifier isEqualToString:@"users"])
self.usersVC = segue.destinationViewController;
if ([segue.identifier isEqualToString:@"passwords"])
self.passwordsVC = segue.destinationViewController;
if ([segue.identifier isEqualToString:@"passwords"]) {
NSAssert([segue isKindOfClass:[MPPasswordsSegue class]], @"passwords segue should be MPPasswordsSegue: %@", segue);
NSAssert([sender isKindOfClass:[NSDictionary class]], @"sender should be dictionary: %@", sender);
NSAssert([[sender objectForKey:@"animated"] isKindOfClass:[NSNumber class]], @"sender should contain 'animated': %@", sender);
[(MPPasswordsSegue *)segue setAnimated:[sender[@"animated"] boolValue]];
UIViewController *destinationVC = segue.destinationViewController;
_passwordsVC = [destinationVC isKindOfClass:[MPPasswordsViewController class]]? (MPPasswordsViewController *)destinationVC: nil;
}
if ([segue.identifier isEqualToString:@"emergency"])
self.emergencyVC = segue.destinationViewController;
}
- (UIStatusBarStyle)preferredStatusBarStyle {
@ -75,6 +84,29 @@
return UIStatusBarStyleLightContent;
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake && !self.emergencyVC)
[self performSegueWithIdentifier:@"emergency" sender:self];
}
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController
fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier {
if ([identifier isEqualToString:@"emergency"]) {
MPEmergencySegue *segue = [[MPEmergencySegue alloc] initWithIdentifier:identifier
source:fromViewController destination:toViewController];
segue.unwind = YES;
dbg_return(segue);
}
dbg_return((id)nil);
}
#pragma mark - Properties
@ -85,30 +117,30 @@
- (void)setMode:(MPCombinedMode)mode animated:(BOOL)animated {
if (_mode == mode && animated)
return;
_mode = mode;
[self becomeFirstResponder];
switch (self.mode) {
case MPCombinedModeUserSelection: {
[self.usersVC setActive:YES animated:animated];
[self.passwordsVC setActive:NO animated:animated];
// MPUsersViewController *usersVC = [self.storyboard instantiateViewControllerWithIdentifier:@"MPUsersViewController"];
// [self setViewControllers:@[ usersVC ] direction:UIPageViewControllerNavigationDirectionReverse
// animated:animated completion:nil];
break;
}
case MPCombinedModePasswordSelection: {
[self.usersVC setActive:NO animated:animated];
[self.passwordsVC setActive:YES animated:animated];
// MPPasswordsViewController *passwordsVC = [self.storyboard instantiateViewControllerWithIdentifier:@"MPPasswordsViewController"];
// [self setViewControllers:@[ passwordsVC ] direction:UIPageViewControllerNavigationDirectionForward
// animated:animated completion:nil];
break;
switch (self.mode) {
case MPCombinedModeUserSelection: {
[self.usersVC setActive:YES animated:animated];
if (_passwordsVC) {
MPPasswordsSegue *segue = [[MPPasswordsSegue alloc] initWithIdentifier:@"passwords" source:_passwordsVC destination:self];
[self prepareForSegue:segue sender:@{ @"animated" : @(animated) }];
[segue perform];
}
break;
}
case MPCombinedModePasswordSelection: {
[self.usersVC setActive:NO animated:animated];
[self performSegueWithIdentifier:@"passwords" sender:@{ @"animated" : @(animated) }];
break;
}
}
[self.passwordsTopConstraint apply];
[self.passwordsTopConstraint apply];
}
#pragma mark - Private
@ -144,12 +176,4 @@
_notificationObservers = nil;
}
#pragma mark - Actions
- (IBAction)doSignOut:(UIBarButtonItem *)sender {
[[MPiOSAppDelegate get] signOutAnimated:YES];
}
@end

View File

@ -0,0 +1,24 @@
/**
* 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
*/
//
// MPEmergencySegue.h
// MPEmergencySegue
//
// Created by lhunath on 2014-04-09.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MPEmergencySegue : UIStoryboardSegue
@property(nonatomic) BOOL unwind;
@end

View File

@ -0,0 +1,57 @@
/**
* 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
*/
//
// MPEmergencySegue.h
// MPEmergencySegue
//
// Created by lhunath on 2014-04-09.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import "MPEmergencySegue.h"
@implementation MPEmergencySegue {
}
- (void)perform {
UIViewController *sourceViewController = self.sourceViewController;
UIViewController *destinationViewController = self.destinationViewController;
if (!self.unwind) {
// Winding
[sourceViewController addChildViewController:destinationViewController];
[sourceViewController.view addSubview:destinationViewController.view];
CGRectSetY(destinationViewController.view.bounds, sourceViewController.view.frame.size.height);
[UIView transitionWithView:sourceViewController.view duration:0.3f options:UIViewAnimationOptionAllowAnimatedContent
animations:^{
CGRectSetY(destinationViewController.view.bounds, 0);
} completion:^(BOOL finished) {
if (finished)
[destinationViewController didMoveToParentViewController:sourceViewController];
}];
}
else {
// Unwinding
[sourceViewController willMoveToParentViewController:nil];
[UIView transitionWithView:sourceViewController.parentViewController.view duration:0.3f options:UIViewAnimationOptionAllowAnimatedContent
animations:^{
CGRectSetY(sourceViewController.view.bounds, sourceViewController.parentViewController.view.frame.size.height);
} completion:^(BOOL finished) {
if (finished) {
[sourceViewController.view removeFromSuperview];
[sourceViewController removeFromParentViewController];
}
}];
}
}
@end

View File

@ -0,0 +1,37 @@
/**
* 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
*/
//
// MPCombinedViewController.h
// MPCombinedViewController
//
// Created by lhunath on 2014-03-08.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import "LLGitTip.h"
@interface MPEmergencyViewController : UIViewController <UITextFieldDelegate>
@property(weak, nonatomic) IBOutlet UIView *emergencyGeneratorDialog;
@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)emergencyCopy:(id)sender;
@end

View File

@ -0,0 +1,75 @@
/**
* 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
*/
//
// MPCombinedViewController.h
// MPCombinedViewController
//
// Created by lhunath on 2014-03-08.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import "MPEmergencyViewController.h"
#import "MPEntities.h"
#import "MPAvatarCell.h"
#import "MPiOSAppDelegate.h"
#import "MPAppDelegate_Store.h"
#import "MPAppDelegate_Key.h"
#import "MPEmergencySegue.h"
@implementation MPEmergencyViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor clearColor];
self.emergencyGeneratorDialog.layer.cornerRadius = 5;
}
- (BOOL)canPerformUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender {
return [self respondsToSelector:action];
}
#pragma mark - Actions
- (IBAction)unwindToCombined:(UIStoryboardSegue *)sender {
dbg(@"unwindToCombined:%@", sender);
}
#pragma mark - UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField {
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
// This isn't really in UITextFieldDelegate. We fake it from UITextFieldTextDidChangeNotification.
- (void)textFieldEditingChanged:(UITextField *)textField {
}
#pragma mark - Actions
- (IBAction)emergencyClose:(id)sender {
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)emergencyCopy:(id)sender {
}
@end

View File

@ -0,0 +1,25 @@
/**
* 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
*/
//
// MPPasswordsSegue.h
// MPPasswordsSegue
//
// Created by lhunath on 2014-04-12.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MPPasswordsSegue : UIStoryboardSegue
@property (nonatomic, assign) BOOL animated;
@end

View File

@ -0,0 +1,63 @@
/**
* 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
*/
//
// MPPasswordsSegue.h
// MPPasswordsSegue
//
// Created by lhunath on 2014-04-12.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import "MPPasswordsSegue.h"
#import "MPPasswordsViewController.h"
@implementation MPPasswordsSegue {
}
- (id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination {
if (!(self = [super initWithIdentifier:identifier source:source destination:destination]))
return nil;
self.animated = YES;
return self;
}
- (void)perform {
if ([self.destinationViewController isKindOfClass:[MPPasswordsViewController class]]) {
__weak MPPasswordsViewController *passwordsVC = self.destinationViewController;
[self.sourceViewController addChildViewController:passwordsVC];
[[passwordsVC.parentViewController view] addSubview:passwordsVC.view];
passwordsVC.active = NO;
[passwordsVC setActive:YES animated:self.animated completion:^(BOOL finished) {
if (!finished)
return;
[passwordsVC didMoveToParentViewController:passwordsVC.parentViewController];
}];
} else if ([self.sourceViewController isKindOfClass:[MPPasswordsViewController class]]) {
__weak MPPasswordsViewController *passwordsVC = self.sourceViewController;
[passwordsVC willMoveToParentViewController:nil];
[passwordsVC setActive:NO animated:self.animated completion:^(BOOL finished) {
if (!finished)
return;
[passwordsVC.view removeFromSuperview];
[passwordsVC removeFromParentViewController];
}];
}
}
@end

View File

@ -31,6 +31,8 @@
@property(assign, nonatomic) BOOL active;
@property(nonatomic, copy) NSString *originalQuery;
- (void)setActive:(BOOL)active animated:(BOOL)animated;
- (void)setActive:(BOOL)active animated:(BOOL)animated completion:(void (^)(BOOL finished))completion;
- (IBAction)action:(id)sender;
@end

View File

@ -20,7 +20,6 @@
#import "MPiOSAppDelegate.h"
#import "MPAppDelegate_Store.h"
#import "MPPasswordLargeCell.h"
#import "UIScrollView+PearlAdjustInsets.h"
#import "MPPasswordTypesCell.h"
#import "MPPasswordSmallCell.h"
#import "UIColor+Expanded.h"
@ -62,6 +61,7 @@
[self registerObservers];
[self observeStore];
[self updatePasswords];
}
- (void)viewWillDisappear:(BOOL)animated {
@ -94,7 +94,7 @@
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
if (collectionView == self.passwordCollectionView)
dbg_return_tr([self.fetchedResultsController.sections count], @);
return [self.fetchedResultsController.sections count];
Throw(@"Unexpected collection view: %@", collectionView);
}
@ -102,8 +102,9 @@
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
if (collectionView == self.passwordCollectionView)
dbg_return_tr(!self.query.length? 0: ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[section]).numberOfObjects +
(_exactMatch? 0: 1), @, @(section));
return ![MPiOSAppDelegate get].activeUserOID? 0:
((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[section]).numberOfObjects +
(!_exactMatch && [[self query] length]? 1: 0);
Throw(@"Unexpected collection view: %@", collectionView);
}
@ -121,11 +122,11 @@
cell = [MPPasswordSmallCell dequeueCellForElement:element fromCollectionView:collectionView atIndexPath:indexPath];
}
else
// New Site.
// New Site.
cell = [MPPasswordTypesCell dequeueCellForTransientSite:self.query fromCollectionView:collectionView atIndexPath:indexPath];
[UIView setAnimationsEnabled:YES];
dbg_return(cell, indexPath);
return cell;
}
Throw(@"Unexpected collection view: %@", collectionView);
@ -220,9 +221,11 @@
if (!updatesForType)
_fetchedUpdates[@(type)] = updatesForType = [NSMutableArray new];
[updatesForType addObject:@{ @"object" : NilToNSNull(anObject),
@"indexPath" : NilToNSNull(indexPath),
@"newIndexPath" : NilToNSNull(newIndexPath) }];
[updatesForType addObject:@{
@"object" : NilToNSNull(anObject),
@"indexPath" : NilToNSNull(indexPath),
@"newIndexPath" : NilToNSNull(newIndexPath)
}];
switch (type) {
case NSFetchedResultsChangeInsert:
dbg(@"didChangeObject: insert: %@", [updatesForType lastObject]);
@ -248,8 +251,10 @@
if (!updatesForType)
_fetchedUpdates[@(type << 3)] = updatesForType = [NSMutableArray new];
[updatesForType addObject:@{ @"sectionInfo" : NilToNSNull(sectionInfo),
@"index" : @(sectionIndex) }];
[updatesForType addObject:@{
@"sectionInfo" : NilToNSNull(sectionInfo),
@"index" : @(sectionIndex)
}];
switch (type) {
case NSFetchedResultsChangeInsert:
dbg(@"didChangeSection: insert: %@", [updatesForType lastObject]);
@ -458,7 +463,7 @@
NSString *query = self.query;
NSManagedObjectID *activeUserOID = [MPiOSAppDelegate get].activeUserOID;
if (!activeUserOID || ![query length]) {
if (!activeUserOID) {
self.passwordsSearchBar.text = nil;
PearlMainQueue( ^{ [self.passwordCollectionView reloadData]; } );
return;
@ -466,8 +471,10 @@
[self.fetchedResultsController.managedObjectContext performBlock:^{
NSError *error = nil;
self.fetchedResultsController.fetchRequest.predicate = [NSPredicate predicateWithFormat:
@"user == %@ AND name BEGINSWITH[cd] %@", activeUserOID, query];
self.fetchedResultsController.fetchRequest.predicate =
[query length]?
[NSPredicate predicateWithFormat:@"user == %@ AND name BEGINSWITH[cd] %@", activeUserOID, query]:
[NSPredicate predicateWithFormat:@"user == %@", activeUserOID];
if (![self.fetchedResultsController performFetch:&error])
err(@"Couldn't fetch elements: %@", error);
@ -536,14 +543,14 @@
- (void)setActive:(BOOL)active {
[self setActive:active animated:YES];
[self setActive:active animated:NO completion:nil];
}
- (void)setActive:(BOOL)active animated:(BOOL)animated {
- (void)setActive:(BOOL)active animated:(BOOL)animated completion:(void (^)(BOOL finished))completion {
_active = active;
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
[UIView animateWithDuration:animated? 0.4f: 0 animations:^{
self.navigationBarToPasswordsConstraint.priority = active? UILayoutPriorityDefaultHigh: 1;
self.navigationBarToTopConstraint.priority = active? 1: UILayoutPriorityDefaultHigh;
self.passwordsToBottomConstraint.priority = active? 1: UILayoutPriorityDefaultHigh;
@ -551,9 +558,51 @@
[self.navigationBarToPasswordsConstraint apply];
[self.navigationBarToTopConstraint apply];
[self.passwordsToBottomConstraint apply];
}];
} completion:completion];
}
#pragma mark - Actions
- (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: Guide");
[[MPiOSAppDelegate get] showGuide];
break;
}
case 1: {
inf(@"Action: Preferences");
[self performSegueWithIdentifier:@"MP_UserProfile" sender:self];
break;
}
case 2: {
inf(@"Action: Other Apps");
[self performSegueWithIdentifier:@"MP_OtherApps" sender:self];
break;
}
case 3: {
inf(@"Action: Feedback via Mail");
[[MPiOSAppDelegate get] showFeedbackWithLogs:YES forVC:self];
break;
}
default: {
wrn(@"Unsupported action: %ld", (long)(buttonIndex - [sheet firstOtherButtonIndex]));
break;
}
}
}
cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil otherTitles:
@"Overview",
@"User Profile",
@"Other Apps",
@"Feedback",
nil];
}
@end

View File

@ -416,8 +416,7 @@
- (void)didSelectNewUserAvatar:(UIButton *)newUserAvatar {
if (![MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity *newUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass( [MPUserEntity class] )
inManagedObjectContext:context];
MPUserEntity *newUser = [MPUserEntity insertNewObjectInContext:context];
[self showNewUserNameAlertFor:newUser saveInContext:context completion:^(BOOL finished) {
newUserAvatar.selected = NO;

View File

@ -27,14 +27,19 @@
@property(weak, nonatomic) IBOutlet LLGitTip *gitTipButton;
@property(weak, nonatomic) IBOutlet UITextField *entryField;
@property(weak, nonatomic) IBOutlet UILabel *entryLabel;
@property(weak, nonatomic) IBOutlet UILabel *entryTip;
@property(weak, nonatomic) IBOutlet UIView *entryTipContainer;
@property(weak, nonatomic) IBOutlet UIView *entryContainer;
@property(weak, nonatomic) IBOutlet UIView *footerContainer;
@property(weak, nonatomic) IBOutlet UIActivityIndicatorView *storeLoadingActivity;
@property(weak, nonatomic) IBOutlet UICollectionView *avatarCollectionView;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *avatarCollectionCenterConstraint;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *navigationBarToTopConstraint;
@property (strong, nonatomic) IBOutlet UIButton *nextAvatarButton;
@property (strong, nonatomic) IBOutlet UIButton *previousAvatarButton;
@property(assign, nonatomic) BOOL active;
- (void)setActive:(BOOL)active animated:(BOOL)animated;
- (IBAction)changeAvatar:(UIButton *)sender;
@end

View File

@ -98,17 +98,6 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
[self.marqueeTipTimer invalidate];
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
// if (motion == UIEventSubtypeMotionShake)
// [self emergencyOpenAnimated:YES];
}
#pragma mark - UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField {
@ -138,7 +127,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
if (!signedIn) {
// Sign in failed.
// TODO: warn user
[self showEntryTip:strl( @"Incorrect password! Typo?" )];
return;
}
}];
@ -149,7 +138,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
NSString *userName = self.entryField.text;
if (![userName length]) {
// No name entered.
// TODO: warn user
[self showEntryTip:strl( @"First, enter your name" )];
return NO;
}
@ -161,7 +150,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
NSString *masterPassword = self.entryField.text;
if (![masterPassword length]) {
// No password entered.
// TODO: warn user
[self showEntryTip:strl( @"Pick a master password" )];
return NO;
}
@ -172,43 +161,43 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
NSString *masterPassword = self.entryField.text;
if (![masterPassword length]) {
// No password entered.
// TODO: warn user
[self showEntryTip:strl( @"Confirm your master password" )];
return NO;
}
if (![masterPassword isEqualToString:_masterPasswordChoice]) {
// Master password confirmation failed.
// TODO: warn user
[self showEntryTip:strl( @"Looks like a typo! Try again." )];
self.activeUserState = MPActiveUserStateMasterPasswordChoice;
return NO;
}
[self.entryField endEditing:YES];
[self selectedAvatar].spinnerActive = YES;
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPAvatarCell *avatarCell = [self selectedAvatar];
avatarCell.spinnerActive = YES;
if (![MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
BOOL isNew = NO;
MPUserEntity *user = [self selectedUserInContext:context isNew:&isNew];
MPUserEntity *user = [self userForAvatar:avatarCell inContext:context isNew:&isNew];
if (isNew) {
user = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass( [MPUserEntity class] )
inManagedObjectContext:context];
MPAvatarCell *avatarCell = [self selectedAvatar];
user = [MPUserEntity insertNewObjectInContext:context];
user.avatar = avatarCell.avatar;
user.name = avatarCell.name;
}
BOOL signedIn = [[MPiOSAppDelegate get] signInAsUser:user saveInContext:context usingMasterPassword:masterPassword];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
PearlMainQueue( ^{
self.entryField.text = @"";
[self selectedAvatar].spinnerActive = NO;
if (!signedIn) {
// Sign in failed, shouldn't happen for a new user.
// TODO: warn user
[self showEntryTip:strl( @"Couldn't create new user." )];
self.activeUserState = MPActiveUserStateNone;
return;
}
}];
}];
} );
}])
avatarCell.spinnerActive = NO;
break;
}
@ -274,8 +263,8 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
if (collectionView == self.avatarCollectionView) {
MPAvatarCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[MPAvatarCell reuseIdentifier] forIndexPath:indexPath];
[cell addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(didLongPress:)]];
[self updateVisibilityForAvatar:cell atIndexPath:indexPath animated:NO];
[self updateModeForAvatar:cell atIndexPath:indexPath animated:NO];
[self updateVisibilityForAvatar:cell atIndexPath:indexPath animated:NO];
BOOL isNew = NO;
MPUserEntity *user = [self userForIndexPath:indexPath inContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]
@ -399,6 +388,21 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
#pragma mark - Private
- (void)showEntryTip:(NSString *)message {
self.entryTip.text = message;
[UIView animateWithDuration:0.3f animations:^{
self.entryTipContainer.alpha = 1;
} completion:^(BOOL finished) {
if (finished)
PearlMainQueueAfter( 4, ^{
[UIView animateWithDuration:0.3f animations:^{
self.entryTipContainer.alpha = 0;
}];
} );
}];
}
- (void)firedMarqueeTimer:(NSTimer *)timer {
[UIView animateWithDuration:0.5 animations:^{
@ -464,17 +468,8 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
- (void)updateAvatarAtIndexPath:(NSIndexPath *)indexPath {
MPAvatarCell *cell = (MPAvatarCell *)[self.avatarCollectionView cellForItemAtIndexPath:indexPath];
[self updateVisibilityForAvatar:cell atIndexPath:indexPath animated:NO];
[self updateModeForAvatar:cell atIndexPath:indexPath animated:NO];
}
- (void)updateVisibilityForAvatar:(MPAvatarCell *)cell atIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated {
CGFloat current = [self.avatarCollectionView layoutAttributesForItemAtIndexPath:indexPath].center.x -
self.avatarCollectionView.contentOffset.x;
CGFloat max = self.avatarCollectionView.bounds.size.width;
[cell setVisibility:MAX(0, MIN( 1, 1 - ABS( current / (max / 2) - 1 ) )) animated:animated];
[self updateVisibilityForAvatar:cell atIndexPath:indexPath animated:NO];
}
- (void)updateModeForAvatar:(MPAvatarCell *)avatarCell atIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated {
@ -505,6 +500,21 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
}
}
- (void)updateVisibilityForAvatar:(MPAvatarCell *)cell atIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated {
CGFloat current = [self.avatarCollectionView layoutAttributesForItemAtIndexPath:indexPath].center.x -
self.avatarCollectionView.contentOffset.x;
CGFloat max = self.avatarCollectionView.bounds.size.width;
CGFloat visibility = MAX(0, MIN( 1, 1 - ABS( current / (max / 2) - 1 ) ));
[cell setVisibility:visibility animated:animated];
if (cell.newUser) {
self.previousAvatarButton.alpha = cell.mode == MPAvatarModeRaisedAndActive? visibility * 0.7f: 0;
self.nextAvatarButton.alpha = cell.mode == MPAvatarModeRaisedAndActive? visibility * 0.7f: 0;
}
}
- (void)afterUpdatesMainQueue:(void (^)(void))block {
[_afterUpdates addOperationWithBlock:^{
@ -560,6 +570,14 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
Weakify(self);
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
[UIView animateWithDuration:0.3f animations:^{
self.avatarCollectionView.alpha = mainContext? 1: 0;
}];
if (mainContext && self.storeLoadingActivity.isAnimating)
[self.storeLoadingActivity stopAnimating];
if (!mainContext && !self.storeLoadingActivity.isAnimating)
[self.storeLoadingActivity startAnimating];
if (!_mocObserver && mainContext)
_mocObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:mainContext
@ -618,7 +636,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
- (void)setActive:(BOOL)active {
[self setActive:active animated:YES];
[self setActive:active animated:NO];
}
- (void)setActive:(BOOL)active animated:(BOOL)animated {
@ -674,7 +692,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
[_afterUpdates setSuspended:YES];
dbg(@"suspend updates");
__block BOOL requestFirstResponder = NO;
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
[UIView animateWithDuration:animated? 0.4f: 0 animations:^{
MPAvatarCell *selectedAvatar = [self selectedAvatar];
// Set avatar modes.
@ -682,6 +700,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:0];
MPAvatarCell *avatarCell = (MPAvatarCell *)[self.avatarCollectionView cellForItemAtIndexPath:indexPath];
[self updateModeForAvatar:avatarCell atIndexPath:indexPath animated:animated];
[self updateVisibilityForAvatar:avatarCell atIndexPath:indexPath animated:animated];
if (selectedAvatar && avatarCell == selectedAvatar)
[self.avatarCollectionView scrollToItemAtIndexPath:indexPath
@ -698,6 +717,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
self.entryLabel.text = strl( @"Enter your master password:" );
self.entryField.text = nil;
self.entryField.secureTextEntry = YES;
self.entryField.autocapitalizationType = UITextAutocapitalizationTypeNone;
break;
}
case MPActiveUserStateUserName: {
@ -705,6 +725,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
self.entryLabel.text = strl( @"Enter your full name:" );
self.entryField.text = nil;
self.entryField.secureTextEntry = NO;
self.entryField.autocapitalizationType = UITextAutocapitalizationTypeWords;
break;
}
case MPActiveUserStateMasterPasswordChoice: {
@ -712,6 +733,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
self.entryLabel.text = strl( @"Choose your master password:" );
self.entryField.text = nil;
self.entryField.secureTextEntry = YES;
self.entryField.autocapitalizationType = UITextAutocapitalizationTypeNone;
break;
}
case MPActiveUserStateMasterPasswordConfirmation: {
@ -720,6 +742,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
self.entryLabel.text = strl( @"Confirm your master password:" );
self.entryField.text = nil;
self.entryField.secureTextEntry = YES;
self.entryField.autocapitalizationType = UITextAutocapitalizationTypeNone;
break;
}
case MPActiveUserStateMinimized:
@ -731,7 +754,6 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
switch (activeUserState) {
case MPActiveUserStateNone: {
self.navigationBarToTopConstraint.priority = UILayoutPriorityDefaultHigh;
self.avatarCollectionCenterConstraint.priority = UILayoutPriorityDefaultHigh;
self.avatarCollectionView.scrollEnabled = YES;
self.entryContainer.alpha = 0;
self.footerContainer.alpha = 1;
@ -742,7 +764,6 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
case MPActiveUserStateMasterPasswordChoice:
case MPActiveUserStateMasterPasswordConfirmation: {
self.navigationBarToTopConstraint.priority = UILayoutPriorityDefaultHigh;
self.avatarCollectionCenterConstraint.priority = UILayoutPriorityDefaultLow;
self.avatarCollectionView.scrollEnabled = NO;
self.entryContainer.alpha = 1;
self.footerContainer.alpha = 1;
@ -751,7 +772,6 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
}
case MPActiveUserStateMinimized: {
self.navigationBarToTopConstraint.priority = 1;
self.avatarCollectionCenterConstraint.priority = UILayoutPriorityDefaultLow;
self.avatarCollectionView.scrollEnabled = NO;
self.entryContainer.alpha = 0;
self.footerContainer.alpha = 0;
@ -759,25 +779,29 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
}
}
[self.navigationBarToTopConstraint apply];
[self.avatarCollectionCenterConstraint apply];
// Toggle the keyboard.
} completion:^(BOOL finished) {
dbg(@"resume updates");
[_afterUpdates setSuspended:NO];
}];
UIResponder *oldFirstResponder = [UIResponder findFirstResponder];
if (requestFirstResponder)
[self.entryField becomeFirstResponder];
else
[self.entryField resignFirstResponder];
UIResponder *newFirstResponder = [UIResponder findFirstResponder];
if (newFirstResponder != oldFirstResponder)
dbg(@"first responder: %@ -> %@", oldFirstResponder, newFirstResponder);
}
#pragma mark - Actions
- (IBAction)doSignOut:(UIBarButtonItem *)sender {
- (IBAction)changeAvatar:(UIButton *)sender {
[[MPiOSAppDelegate get] signOutAnimated:YES];
if (sender == self.previousAvatarButton)
--[self selectedAvatar].avatar;
if (sender == self.nextAvatarButton)
++[self selectedAvatar].avatar;
}
@end

View File

@ -10,25 +10,28 @@
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "IASKSettingsReader.h"
#import "JRSwizzle.h"
@interface MPiOSAppDelegate()
@property(nonatomic, weak) PearlAlert *handleCloudDisabledAlert;
@property(nonatomic, weak) PearlAlert *handleCloudContentAlert;
@property(nonatomic, weak) PearlAlert *fixCloudContentAlert;
@property(nonatomic, weak) PearlOverlay *storeLoading;
@property(nonatomic, weak) PearlOverlay *storeLoadingOverlay;
@end
@implementation MPiOSAppDelegate
+ (void)initialize {
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
if ([self class] == [MPiOSAppDelegate class]) {
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
#ifdef DEBUG
[PearlLogger get].printLevel = PearlLogLevelDebug;
[PearlLogger get].printLevel = PearlLogLevelDebug;
#else
[PearlLogger get].printLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelDebug: PearlLogLevelInfo;
[PearlLogger get].printLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelDebug: PearlLogLevelInfo;
#endif
}
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
@ -731,8 +734,8 @@
dispatch_async( dispatch_get_main_queue(), ^{
[self.handleCloudContentAlert cancelAlertAnimated:YES];
if (![self.storeLoading isVisible])
self.storeLoading = [PearlOverlay showProgressOverlayWithTitle:@"Loading Sites"];
if (!self.storeLoadingOverlay)
self.storeLoadingOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Loading Sites"];
} );
[super ubiquityStoreManager:manager willLoadStoreIsCloud:isCloudStore];
@ -746,21 +749,21 @@
[self.handleCloudContentAlert cancelAlertAnimated:YES];
[self.fixCloudContentAlert cancelAlertAnimated:YES];
[self.storeLoading cancelOverlayAnimated:YES];
[self.storeLoadingOverlay cancelOverlayAnimated:YES];
[self.handleCloudDisabledAlert cancelAlertAnimated:YES];
}
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager failedLoadingStoreWithCause:(UbiquityStoreErrorCause)cause context:(id)context
wasCloud:(BOOL)wasCloudStore {
[self.storeLoading cancelOverlayAnimated:YES];
[self.storeLoadingOverlay cancelOverlayAnimated:YES];
[self.handleCloudDisabledAlert cancelAlertAnimated:YES];
}
- (BOOL)ubiquityStoreManager:(UbiquityStoreManager *)manager handleCloudContentCorruptionWithHealthyStore:(BOOL)storeHealthy {
if (manager.cloudEnabled && !storeHealthy && !([self.handleCloudContentAlert.alertView isVisible] || [self.fixCloudContentAlert.alertView isVisible])) {
[self.storeLoading cancelOverlayAnimated:YES];
if (manager.cloudEnabled && !storeHealthy && !(self.handleCloudContentAlert || self.fixCloudContentAlert)) {
[self.storeLoadingOverlay cancelOverlayAnimated:YES];
[self.handleCloudDisabledAlert cancelAlertAnimated:YES];
[self showCloudContentAlert];
};
@ -770,17 +773,19 @@
- (BOOL)ubiquityStoreManagerHandleCloudDisabled:(UbiquityStoreManager *)manager {
if (![self.handleCloudDisabledAlert isVisible])
if (!self.handleCloudDisabledAlert)
self.handleCloudDisabledAlert = [PearlAlert showAlertWithTitle:@"iCloud Login" message:
@"You haven't added an iCloud account to your device yet.\n"
@"To add one, tap 'Wait For Me', go into Apple's Settings and add an iCloud account."
@"To add one, go into Apple's Settings -> iCloud."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == alert.firstOtherButtonIndex)
if (buttonIndex == alert.firstOtherButtonIndex) {
[MPiOSConfig get].iCloudEnabled = @NO;
return;
}
[self.storeManager reloadStore];
} cancelTitle:@"Wait For Me" otherTitles:@"Disable iCloud", nil];
} cancelTitle:@"Try Again" otherTitles:@"Disable iCloud", nil];
return YES;
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="5053" systemVersion="13C64" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="KZF-fe-y9n">
<dependencies>
<deployment defaultVersion="1536" identifier="iOS"/>
<deployment defaultVersion="1792" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3733"/>
</dependencies>
<scenes>

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
93D391ED37C9F687FA51EAA1 /* MPEmergencySegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3937712BF1B67623E5764 /* MPEmergencySegue.m */; };
93D3922A53E41A54832E90D9 /* PearlOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390FADEB325D8D54A957D /* PearlOverlay.m */; };
93D39233C3EDD9A947ABA52D /* LLButtonView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39BF6BCBDFFE844E7D34C /* LLButtonView.m */; };
93D39262A8A97DB748213309 /* PearlEMail.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D393BB973253D4BAAC84AA /* PearlEMail.m */; };
@ -14,7 +15,9 @@
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */; };
93D39392DEDA376F93C6C718 /* MPCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39BAA71DE51B4D8A1286C /* MPCell.m */; };
93D393BA1B8402D08DB40231 /* MPPasswordElementCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39342E5F115EFCC90E976 /* MPPasswordElementCell.m */; };
93D394B5036C882B33C71872 /* MPPasswordsSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E7A12CC352B2825AA66 /* MPPasswordsSegue.m */; };
93D394F6D3F6E2553AA0D684 /* MPPasswordLargeStoredCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3947F6BB69CA9A9124A5D /* MPPasswordLargeStoredCell.m */; };
93D39536EB550E811CCD04BC /* UIResponder+PearlFirstResponder.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */; };
93D3954E96236384AFA00453 /* UIScrollView+PearlAdjustInsets.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390FB3110DCCE68E600DC /* UIScrollView+PearlAdjustInsets.m */; };
93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */; };
93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B381350802A194BF332 /* MPAvatarCell.m */; };
@ -23,6 +26,8 @@
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3942A356B639724157982 /* PearlOverlay.h */; };
93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */; };
93D3980046016EFD05B35BC5 /* PearlUICollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */; };
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */; };
93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */; };
93D399278165FD6D950F0025 /* MPPasswordTypesCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39097C0AAE62C1C321BFC /* MPPasswordTypesCell.m */; };
93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; };
93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; };
@ -35,9 +40,11 @@
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
93D39C8AD8EAB747856B3A8C /* LLModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3923B42DA2DA18F287092 /* LLModel.m */; };
93D39CB5E2EC1078E898F46A /* MPPasswordLargeCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3937863061C3916AF7AD2 /* MPPasswordLargeCell.m */; };
93D39CB738EB39994D1B691C /* NSManagedObject+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D395268D000379F218BCA1 /* NSManagedObject+Pearl.h */; };
93D39D596A2E376D6F6F5DA1 /* MPCombinedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D393310223DDB35218467A /* MPCombinedViewController.m */; };
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
93D39EDD960C381D64E4DCDD /* MPPasswordSmallCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3952CC60991B97D69F26A /* MPPasswordSmallCell.m */; };
93D39F18B48FB351E727DD2B /* NSManagedObject+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D398EBF99FF0C245FD561E /* NSManagedObject+Pearl.m */; };
93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A28369954D147E239BA /* MPSetupViewController.m */; };
93D39FA97F4C3F69A75D5A03 /* MPPasswordLargeGeneratedCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3993422E207BF0B21D089 /* MPPasswordLargeGeneratedCell.m */; };
DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */; };
@ -524,12 +531,15 @@
93D3932D6C25F2C2D929F8A1 /* MPPasswordElementCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordElementCell.h; sourceTree = "<group>"; };
93D393310223DDB35218467A /* MPCombinedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCombinedViewController.m; sourceTree = "<group>"; };
93D39342E5F115EFCC90E976 /* MPPasswordElementCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordElementCell.m; sourceTree = "<group>"; };
93D3937712BF1B67623E5764 /* MPEmergencySegue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEmergencySegue.m; sourceTree = "<group>"; };
93D3937863061C3916AF7AD2 /* MPPasswordLargeCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeCell.m; sourceTree = "<group>"; };
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; };
93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = "<group>"; };
93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIResponder+PearlFirstResponder.h"; sourceTree = "<group>"; };
93D3947F6BB69CA9A9124A5D /* MPPasswordLargeStoredCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeStoredCell.m; sourceTree = "<group>"; };
93D395268D000379F218BCA1 /* NSManagedObject+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSManagedObject+Pearl.h"; sourceTree = "<group>"; };
93D3952CC60991B97D69F26A /* MPPasswordSmallCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordSmallCell.m; sourceTree = "<group>"; };
93D3956915634581E737B38C /* PearlNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlNavigationController.m; sourceTree = "<group>"; };
93D395BA6B2CFF5F49A4D25F /* MPPasswordLargeStoredCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeStoredCell.h; sourceTree = "<group>"; };
@ -541,18 +551,24 @@
93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlNavigationController.h; sourceTree = "<group>"; };
93D39888EE06F06264CC963B /* MPPasswordSmallCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordSmallCell.h; sourceTree = "<group>"; };
93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; };
93D398EBF99FF0C245FD561E /* NSManagedObject+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObject+Pearl.m"; sourceTree = "<group>"; };
93D3993422E207BF0B21D089 /* MPPasswordLargeGeneratedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeGeneratedCell.m; sourceTree = "<group>"; };
93D39975CE5AEC99E3F086C7 /* MPPasswordCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordCell.h; sourceTree = "<group>"; };
93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUsersViewController.m; sourceTree = "<group>"; };
93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIResponder+PearlFirstResponder.m"; sourceTree = "<group>"; };
93D39A28369954D147E239BA /* MPSetupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSetupViewController.m; sourceTree = "<group>"; };
93D39A3CC4D8330831FC8CB4 /* LLToggleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLToggleViewController.h; sourceTree = "<group>"; };
93D39A41340CF778E00D0E6D /* MPEmergencySegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEmergencySegue.h; sourceTree = "<group>"; };
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = "<group>"; };
93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEmergencyViewController.m; sourceTree = "<group>"; };
93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUICollectionView.h; sourceTree = "<group>"; };
93D39B381350802A194BF332 /* MPAvatarCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAvatarCell.m; sourceTree = "<group>"; };
93D39BA6C5CB452973918B7D /* LLButtonView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLButtonView.h; sourceTree = "<group>"; };
93D39BAA71DE51B4D8A1286C /* MPCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCell.m; sourceTree = "<group>"; };
93D39BF6BCBDFFE844E7D34C /* LLButtonView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLButtonView.m; sourceTree = "<group>"; };
93D39C44361BE57AF0B3071F /* MPPasswordsSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordsSegue.h; sourceTree = "<group>"; };
93D39C8E26B06F01566785B7 /* LLToggleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLToggleViewController.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>"; };
93D39D8A953779B35403AF6E /* PearlUICollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUICollectionView.m; sourceTree = "<group>"; };
@ -560,6 +576,7 @@
93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+PearlAdjustInsets.h"; sourceTree = "<group>"; };
93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordCell.m; sourceTree = "<group>"; };
93D39E02F69CACAB61C056F8 /* MPPasswordLargeCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeCell.h; sourceTree = "<group>"; };
93D39E7A12CC352B2825AA66 /* MPPasswordsSegue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordsSegue.m; sourceTree = "<group>"; };
93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlEMail.h; sourceTree = "<group>"; };
93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; };
DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
@ -1701,6 +1718,8 @@
DA5BFA45147E415C00F98B1E /* Products */,
93D39975CE5AEC99E3F086C7 /* MPPasswordCell.h */,
93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */,
93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */,
93D39CDD434AFD6E1B0DA359 /* MPEmergencyViewController.h */,
);
sourceTree = "<group>";
};
@ -2573,6 +2592,10 @@
93D39888EE06F06264CC963B /* MPPasswordSmallCell.h */,
93D39342E5F115EFCC90E976 /* MPPasswordElementCell.m */,
93D3932D6C25F2C2D929F8A1 /* MPPasswordElementCell.h */,
93D3937712BF1B67623E5764 /* MPEmergencySegue.m */,
93D39A41340CF778E00D0E6D /* MPEmergencySegue.h */,
93D39E7A12CC352B2825AA66 /* MPPasswordsSegue.m */,
93D39C44361BE57AF0B3071F /* MPPasswordsSegue.h */,
);
path = iOS;
sourceTree = "<group>";
@ -3108,6 +3131,10 @@
93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */,
93D39D8A953779B35403AF6E /* PearlUICollectionView.m */,
93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */,
93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */,
93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */,
93D398EBF99FF0C245FD561E /* NSManagedObject+Pearl.m */,
93D395268D000379F218BCA1 /* NSManagedObject+Pearl.h */,
);
path = "Pearl-UIKit";
sourceTree = "<group>";
@ -3292,6 +3319,8 @@
DAEB934218AA537D000490CC /* bn.h in Headers */,
93D39B76DD5AB108BA8928E8 /* UIScrollView+PearlAdjustInsets.h in Headers */,
93D3980046016EFD05B35BC5 /* PearlUICollectionView.h in Headers */,
93D39536EB550E811CCD04BC /* UIResponder+PearlFirstResponder.h in Headers */,
93D39CB738EB39994D1B691C /* NSManagedObject+Pearl.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -3875,6 +3904,9 @@
93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */,
93D39EDD960C381D64E4DCDD /* MPPasswordSmallCell.m in Sources */,
93D393BA1B8402D08DB40231 /* MPPasswordElementCell.m in Sources */,
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */,
93D391ED37C9F687FA51EAA1 /* MPEmergencySegue.m in Sources */,
93D394B5036C882B33C71872 /* MPPasswordsSegue.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -3955,6 +3987,8 @@
DA2CA4DF18D28859007798F8 /* NSTimer+PearlBlock.m in Sources */,
93D3954E96236384AFA00453 /* UIScrollView+PearlAdjustInsets.m in Sources */,
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */,
93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */,
93D39F18B48FB351E727DD2B /* NSManagedObject+Pearl.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -57,6 +57,12 @@
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "-com.apple.coredata.ubiquity.logLevel 3"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>

View File

@ -23,6 +23,10 @@
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="VDd-oM-ZOO" userLabel="Store Activity">
<rect key="frame" x="142" y="266" width="37" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</activityIndicatorView>
<navigationBar contentMode="scaleToFill" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="790-G2-I8g">
<rect key="frame" x="0.0" y="20" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
@ -31,7 +35,7 @@
<navigationItem id="WjE-Yw-JEC"/>
</items>
</navigationBar>
<collectionView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" minimumZoomScale="0.0" maximumZoomScale="0.0" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="L6J-pd-gcp" userLabel="Avatar Collection">
<collectionView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" alpha="0.0" contentMode="scaleToFill" minimumZoomScale="0.0" maximumZoomScale="0.0" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="L6J-pd-gcp" userLabel="Avatar Collection">
<rect key="frame" x="0.0" y="20" width="320" height="548"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
@ -45,6 +49,9 @@
<collectionViewCell opaque="NO" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPAvatarCell" id="Zab-uQ-uk9" customClass="MPAvatarCell">
<rect key="frame" x="80" y="-10" width="160" height="568"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<userGuides>
<userLayoutGuide location="209" affinity="minY"/>
</userGuides>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="160" height="568"/>
<autoresizingMask key="autoresizingMask"/>
@ -123,6 +130,36 @@
<outlet property="delegate" destination="S8q-YF-Kt9" id="det-Eh-phM"/>
</connections>
</collectionView>
<button opaque="NO" alpha="0.69999999999999996" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9u7-pu-Wtv" userLabel="Previous Avatar">
<rect key="frame" x="0.0" y="191.5" width="44" height="53"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<constraints>
<constraint firstAttribute="width" constant="44" id="Ay6-Jg-c3T"/>
</constraints>
<fontDescription key="fontDescription" name="SourceCodePro-ExtraLight" family="Source Code Pro" pointSize="32"/>
<state key="normal">
<string key="title">〈
❬</string>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="changeAvatar:" destination="S8q-YF-Kt9" eventType="touchUpInside" id="lNu-mK-3zD"/>
</connections>
</button>
<button opaque="NO" alpha="0.69999999999999996" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fUK-gJ-NRE" userLabel="Next Avatar">
<rect key="frame" x="276" y="191.5" width="44" height="53"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<constraints>
<constraint firstAttribute="width" constant="44" id="oAm-YX-Fx5"/>
</constraints>
<fontDescription key="fontDescription" name="SourceCodePro-ExtraLight" family="Source Code Pro" pointSize="32"/>
<state key="normal" title="〉">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="changeAvatar:" destination="S8q-YF-Kt9" eventType="touchUpInside" id="kL5-zV-zbb"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qp1-nX-o4i" userLabel="Entry" customClass="PearlUIView">
<rect key="frame" x="20" y="280" width="280" height="63"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
@ -149,9 +186,38 @@
<outlet property="delegate" destination="S8q-YF-Kt9" id="5u3-XN-LOe"/>
</connections>
</textField>
<view userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fdS-zb-K9I" userLabel="Entry Tip">
<rect key="frame" x="35" y="-16" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" translatesAutoresizingMaskIntoConstraints="NO" id="g2g-5i-er4">
<rect key="frame" x="0.0" y="0.0" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.15000000000000002" y="0.14999999999999999" width="0.69999999999999973" height="0.44999999999999996"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Incorrect Password" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" preferredMaxLayoutWidth="170" translatesAutoresizingMaskIntoConstraints="NO" id="ZI7-qg-7OW">
<rect key="frame" x="20" y="12" width="170" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="g2g-5i-er4" firstAttribute="leading" secondItem="fdS-zb-K9I" secondAttribute="leading" id="5ZK-p5-ihF"/>
<constraint firstAttribute="trailing" secondItem="g2g-5i-er4" secondAttribute="trailing" id="8hg-ky-ZAt"/>
<constraint firstItem="ZI7-qg-7OW" firstAttribute="leading" secondItem="fdS-zb-K9I" secondAttribute="leading" constant="20" id="Mh3-5h-v8I"/>
<constraint firstItem="g2g-5i-er4" firstAttribute="top" secondItem="fdS-zb-K9I" secondAttribute="top" id="gg2-xC-JDl"/>
<constraint firstItem="ZI7-qg-7OW" firstAttribute="centerY" secondItem="fdS-zb-K9I" secondAttribute="top" constant="20" id="ipO-Or-BYy"/>
<constraint firstAttribute="trailing" secondItem="ZI7-qg-7OW" secondAttribute="trailing" constant="20" id="wEs-fc-uQi"/>
<constraint firstAttribute="bottom" secondItem="g2g-5i-er4" secondAttribute="bottom" id="ycz-7a-HTB"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="z3Z-AB-fG2" firstAttribute="centerX" secondItem="fdS-zb-K9I" secondAttribute="centerX" id="66w-7r-2i8"/>
<constraint firstItem="z3Z-AB-fG2" firstAttribute="bottom" secondItem="UfK-na-vOU" secondAttribute="bottom" constant="-4" id="753-1g-2UH"/>
<constraint firstItem="5fe-rt-zFa" firstAttribute="leading" secondItem="qp1-nX-o4i" secondAttribute="leading" constant="20" symbolic="YES" id="B5U-63-4Dk"/>
<constraint firstItem="z3Z-AB-fG2" firstAttribute="top" secondItem="UfK-na-vOU" secondAttribute="top" constant="4" id="DSx-ER-FLa"/>
@ -160,6 +226,7 @@
<constraint firstAttribute="trailing" secondItem="5fe-rt-zFa" secondAttribute="trailing" constant="20" symbolic="YES" id="TZY-ev-UUs"/>
<constraint firstItem="z3Z-AB-fG2" firstAttribute="leading" secondItem="UfK-na-vOU" secondAttribute="leading" constant="10" id="XRN-Nd-Dqu"/>
<constraint firstItem="5fe-rt-zFa" firstAttribute="top" secondItem="qp1-nX-o4i" secondAttribute="top" id="caW-jx-6Ui"/>
<constraint firstItem="z3Z-AB-fG2" firstAttribute="centerY" secondItem="fdS-zb-K9I" secondAttribute="bottom" id="dnr-bx-I4g"/>
<constraint firstAttribute="bottom" secondItem="UfK-na-vOU" secondAttribute="bottom" id="iN7-BO-Qwf"/>
<constraint firstAttribute="trailing" secondItem="UfK-na-vOU" secondAttribute="trailing" id="k3M-Oh-kM1"/>
<constraint firstItem="z3Z-AB-fG2" firstAttribute="trailing" secondItem="UfK-na-vOU" secondAttribute="trailing" constant="-10" id="nEd-y0-Fzk"/>
@ -233,18 +300,24 @@
</view>
</subviews>
<constraints>
<constraint firstAttribute="centerX" secondItem="VDd-oM-ZOO" secondAttribute="centerX" id="0j9-vM-WFA"/>
<constraint firstAttribute="trailing" secondItem="790-G2-I8g" secondAttribute="trailing" id="2Wb-fS-TFg"/>
<constraint firstAttribute="bottom" secondItem="qp1-nX-o4i" secondAttribute="bottom" constant="225" id="4aN-54-XmH"/>
<constraint firstAttribute="trailing" secondItem="L6J-pd-gcp" secondAttribute="trailing" id="9fV-8e-y3E"/>
<constraint firstItem="L6J-pd-gcp" firstAttribute="leading" secondItem="rWM-08-aab" secondAttribute="leading" id="BcO-0y-Nih"/>
<constraint firstItem="qp1-nX-o4i" firstAttribute="leading" secondItem="rWM-08-aab" secondAttribute="leading" constant="20" symbolic="YES" id="DY1-Ad-Mbi"/>
<constraint firstItem="qp1-nX-o4i" firstAttribute="top" secondItem="fUK-gJ-NRE" secondAttribute="centerY" constant="62" id="KaV-34-aBy"/>
<constraint firstAttribute="bottom" secondItem="XEP-O3-ayG" secondAttribute="bottom" id="PpW-Of-YOc"/>
<constraint firstAttribute="trailing" secondItem="fUK-gJ-NRE" secondAttribute="trailing" id="TBr-pS-kEK"/>
<constraint firstItem="790-G2-I8g" firstAttribute="leading" secondItem="rWM-08-aab" secondAttribute="leading" id="YWp-yC-ar7"/>
<constraint firstAttribute="trailing" secondItem="qp1-nX-o4i" secondAttribute="trailing" constant="20" symbolic="YES" id="cOq-BS-Xmo"/>
<constraint firstAttribute="top" secondItem="790-G2-I8g" secondAttribute="bottom" priority="1" id="dTp-TY-5bb"/>
<constraint firstAttribute="centerY" secondItem="VDd-oM-ZOO" secondAttribute="centerY" id="dxP-im-1dM"/>
<constraint firstItem="qp1-nX-o4i" firstAttribute="top" secondItem="9u7-pu-Wtv" secondAttribute="centerY" constant="62" id="go1-rO-rVJ"/>
<constraint firstAttribute="bottom" secondItem="L6J-pd-gcp" secondAttribute="bottom" id="jNR-Gp-sIv"/>
<constraint firstItem="XEP-O3-ayG" firstAttribute="leading" secondItem="rWM-08-aab" secondAttribute="leading" id="pAt-0Y-LYv"/>
<constraint firstAttribute="trailing" secondItem="XEP-O3-ayG" secondAttribute="trailing" id="raD-hD-OYt"/>
<constraint firstItem="9u7-pu-Wtv" firstAttribute="leading" secondItem="rWM-08-aab" secondAttribute="leading" id="sez-BC-G3I"/>
</constraints>
</view>
</subviews>
@ -264,13 +337,18 @@
<outlet property="entryContainer" destination="qp1-nX-o4i" id="tSJ-e8-W8b"/>
<outlet property="entryField" destination="z3Z-AB-fG2" id="iAO-Gd-flO"/>
<outlet property="entryLabel" destination="5fe-rt-zFa" id="Nn1-nQ-oy3"/>
<outlet property="entryTip" destination="ZI7-qg-7OW" id="dZj-rZ-efd"/>
<outlet property="entryTipContainer" destination="fdS-zb-K9I" id="sJc-4z-usV"/>
<outlet property="footerContainer" destination="XEP-O3-ayG" id="9cI-p9-av3"/>
<outlet property="gitTipButton" destination="vHz-dw-oPb" id="3tG-8S-u13"/>
<outlet property="gitTipTip" destination="069-Pu-yXe" id="wWf-2X-Ryw"/>
<outlet property="hintLabel" destination="N9g-Kk-yjc" id="Tve-2r-t0Q"/>
<outlet property="navigationBar" destination="790-G2-I8g" id="XTa-zJ-6Kv"/>
<outlet property="navigationBarToTopConstraint" destination="dTp-TY-5bb" id="Ulm-4Q-eW9"/>
<outlet property="nextAvatarButton" destination="fUK-gJ-NRE" id="5qo-lK-rSa"/>
<outlet property="previousAvatarButton" destination="9u7-pu-Wtv" id="Hgv-lN-S1n"/>
<outlet property="searchDisplayController" destination="h98-GT-FoS" id="VvS-JO-rqq"/>
<outlet property="storeLoadingActivity" destination="VDd-oM-ZOO" id="MJ7-2f-e8n"/>
<outlet property="userSelectionContainer" destination="rWM-08-aab" id="Yme-hX-8P0"/>
</connections>
</viewController>
@ -309,7 +387,7 @@
<viewControllerLayoutGuide type="top" id="zOG-3W-l4v"/>
<viewControllerLayoutGuide type="bottom" id="lXD-AZ-Umi"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="fkJ-D0-yue">
<view key="view" contentMode="scaleToFill" id="fkJ-D0-yue" userLabel="Root">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
@ -324,37 +402,23 @@
<segue destination="S8q-YF-Kt9" kind="embed" identifier="users" id="9AR-TX-BkY"/>
</connections>
</containerView>
<containerView clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cs4-pY-dDU" userLabel="Passwords" customClass="PearlUIView">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="ignoreTouches" value="YES"/>
</userDefinedRuntimeAttributes>
<connections>
<segue destination="nkY-z6-8jd" kind="embed" identifier="passwords" id="zVW-2z-RMJ"/>
</connections>
</containerView>
</subviews>
<constraints>
<constraint firstItem="lXD-AZ-Umi" firstAttribute="top" secondItem="Lkg-xn-bce" secondAttribute="bottom" id="4xV-YK-k7B"/>
<constraint firstItem="Lkg-xn-bce" firstAttribute="top" secondItem="fkJ-D0-yue" secondAttribute="top" id="EIy-Cd-0vW"/>
<constraint firstItem="jDK-5y-QRP" firstAttribute="top" secondItem="fkJ-D0-yue" secondAttribute="top" id="ILt-pX-rHm"/>
<constraint firstAttribute="trailing" secondItem="cs4-pY-dDU" secondAttribute="trailing" id="Ika-kA-pLW"/>
<constraint firstAttribute="trailing" secondItem="jDK-5y-QRP" secondAttribute="trailing" id="L2M-Eb-kwd"/>
<constraint firstAttribute="trailing" secondItem="Lkg-xn-bce" secondAttribute="trailing" id="ROW-fK-z92"/>
<constraint firstItem="lXD-AZ-Umi" firstAttribute="top" secondItem="jDK-5y-QRP" secondAttribute="bottom" id="TUm-Qo-P4W"/>
<constraint firstItem="Lkg-xn-bce" firstAttribute="leading" secondItem="fkJ-D0-yue" secondAttribute="leading" id="UH5-Kk-taJ"/>
<constraint firstItem="jDK-5y-QRP" firstAttribute="leading" secondItem="fkJ-D0-yue" secondAttribute="leading" id="jPw-0w-Fbo"/>
<constraint firstItem="lXD-AZ-Umi" firstAttribute="top" secondItem="cs4-pY-dDU" secondAttribute="bottom" id="jv3-3p-9nK"/>
<constraint firstItem="cs4-pY-dDU" firstAttribute="top" secondItem="fkJ-D0-yue" secondAttribute="top" id="vqr-Ej-iQn"/>
<constraint firstItem="cs4-pY-dDU" firstAttribute="leading" secondItem="fkJ-D0-yue" secondAttribute="leading" id="whE-iL-jHl"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="MPa-zX-Kaq"/>
<connections>
<outlet property="passwordsTopConstraint" destination="vqr-Ej-iQn" id="HZg-lk-4e1"/>
<outlet property="passwordsView" destination="cs4-pY-dDU" id="dGJ-iD-pDb"/>
<outlet property="usersView" destination="jDK-5y-QRP" id="RJ0-04-DDS"/>
<segue destination="osn-5H-SWW" kind="custom" identifier="emergency" customClass="MPEmergencySegue" id="gtX-Cx-AA2"/>
<segue destination="nkY-z6-8jd" kind="custom" identifier="passwords" customClass="MPPasswordsSegue" id="Ozp-YT-Utx"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="F33-Fe-Tb6" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -383,7 +447,11 @@
<color key="barTintColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/>
<items>
<navigationItem id="JCx-F3-LfN">
<barButtonItem key="rightBarButtonItem" systemItem="action" id="NHA-Vf-agZ"/>
<barButtonItem key="rightBarButtonItem" systemItem="action" id="NHA-Vf-agZ">
<connections>
<action selector="action:" destination="nkY-z6-8jd" id="bgD-pW-lMz"/>
</connections>
</barButtonItem>
</navigationItem>
</items>
<userDefinedRuntimeAttributes>
@ -395,7 +463,7 @@
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<searchBar contentMode="redraw" barStyle="black" searchBarStyle="minimal" placeholder="eg. apple.com" showsBookmarkButton="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oAG-Ea-TOI">
<searchBar contentMode="redraw" barStyle="black" searchBarStyle="minimal" placeholder="eg. apple.com" translatesAutoresizingMaskIntoConstraints="NO" id="oAG-Ea-TOI">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL"/>
@ -844,12 +912,277 @@
</objects>
<point key="canvasLocation" x="1350" y="1200"/>
</scene>
<!--Emergency View Controller-->
<scene sceneID="c0a-VZ-JJf">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" modalTransitionStyle="flipHorizontal" id="osn-5H-SWW" customClass="MPEmergencyViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="cmU-lf-Fxd"/>
<viewControllerLayoutGuide type="bottom" id="IV3-lc-Fnf"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="7jl-cw-kaJ" userLabel="Root">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GiS-3g-cDj" userLabel="Emergency Generator Root">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1lc-e7-Qme" userLabel="Emergency Generator">
<rect key="frame" x="8" y="28" width="304" height="374"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Emergency Generator" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="4Lh-s0-Dbt">
<rect key="frame" x="20" y="20" width="264" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Bold" family="Gill Sans" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Generate your password without logging in. Great for if you're borrowing a friend's device or are having trouble logging in." lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" preferredMaxLayoutWidth="264" translatesAutoresizingMaskIntoConstraints="NO" id="vHS-3A-Tae">
<rect key="frame" x="20" y="49" width="264" height="49"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="GillSans-LightItalic" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Your Name" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="XAC-Da-lpf">
<rect key="frame" x="20" y="106" width="264" height="30"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="words" keyboardAppearance="alert" returnKeyType="next" enablesReturnKeyAutomatically="YES"/>
<connections>
<outlet property="delegate" destination="osn-5H-SWW" id="VQI-Lq-GWG"/>
</connections>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Your Master Password" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="J46-0E-no3">
<rect key="frame" x="20" y="144" width="264" height="30"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardAppearance="alert" returnKeyType="next" enablesReturnKeyAutomatically="YES" secureTextEntry="YES"/>
<connections>
<outlet property="delegate" destination="osn-5H-SWW" id="bpf-YA-5XP"/>
</connections>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Site Name" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="56H-xR-09J">
<rect key="frame" x="20" y="182" width="264" height="30"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL" keyboardAppearance="alert" returnKeyType="done" enablesReturnKeyAutomatically="YES"/>
<connections>
<outlet property="delegate" destination="osn-5H-SWW" id="QgA-TS-5KG"/>
</connections>
</textField>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bar" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="e4b-Iv-Pk9">
<rect key="frame" x="20" y="220" width="264" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<segments>
<segment title="Max"/>
<segment title="Long"/>
<segment title="Med"/>
<segment title="Basic"/>
<segment title="Short"/>
<segment title="PIN"/>
</segments>
<color key="tintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
</segmentedControl>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Counter" lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" preferredMaxLayoutWidth="64" translatesAutoresizingMaskIntoConstraints="NO" id="cAo-K2-E23">
<rect key="frame" x="20" y="259" width="64" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<stepper opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" maximumValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="ZPT-EI-yuv">
<rect key="frame" x="190" y="256" width="94" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
</stepper>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="1" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="3Cd-XH-Wau">
<rect key="frame" x="172" y="259" width="10" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bON-0a-K0M">
<rect key="frame" x="260" y="0.0" width="44" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" hint="" label="Close"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="ETb-fm-wAa"/>
<constraint firstAttribute="width" constant="44" id="Fu5-NW-dMz"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="icon_cancel.png">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<segue destination="p6o-h3-NRH" kind="unwind" identifier="emergency" unwindAction="unwindToCombined:" id="VI2-VR-bQc"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="J2u-kc-30c">
<rect key="frame" x="0.0" y="0.0" width="44" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" hint="" label="Close"/>
<constraints>
<constraint firstAttribute="width" constant="44" id="9eE-Ya-Lbf"/>
<constraint firstAttribute="height" constant="44" id="gtp-ee-onG"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="icon_gears.png">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
</button>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" hidesWhenStopped="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="4sN-hm-xio">
<rect key="frame" x="133" y="317" width="37" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
</activityIndicatorView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="W8a-1e-Qpz">
<rect key="frame" x="0.0" y="325" width="304" height="49"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="AmericanTypewriter-Bold" family="American Typewriter" pointSize="30"/>
<size key="titleShadowOffset" width="0.0" height="1"/>
<state key="normal" title="Kucy9-RimuTich">
<color key="titleColor" red="0.47450980390000003" green="0.86666666670000003" blue="0.98431372549999996" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="emergencyCopy:" destination="osn-5H-SWW" eventType="touchUpInside" id="JvH-n0-6k8"/>
</connections>
</button>
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="beo-cJ-jIn" userLabel="View - Content Tip">
<rect key="frame" x="47" y="289" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" translatesAutoresizingMaskIntoConstraints="NO" id="nyL-cO-aPa">
<rect key="frame" x="0.0" y="0.0" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Copied!" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="rtA-NK-3HP">
<rect key="frame" x="20" y="11" width="170" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="nyL-cO-aPa" firstAttribute="top" secondItem="beo-cJ-jIn" secondAttribute="top" id="136-Ys-inF"/>
<constraint firstAttribute="trailing" secondItem="nyL-cO-aPa" secondAttribute="trailing" id="JtV-gp-6VI"/>
<constraint firstAttribute="width" constant="210" id="M21-jn-WPV"/>
<constraint firstItem="nyL-cO-aPa" firstAttribute="leading" secondItem="beo-cJ-jIn" secondAttribute="leading" id="VVd-4X-WHl"/>
<constraint firstItem="rtA-NK-3HP" firstAttribute="leading" secondItem="beo-cJ-jIn" secondAttribute="leading" constant="20" symbolic="YES" id="bqM-mO-fYt"/>
<constraint firstAttribute="bottom" secondItem="nyL-cO-aPa" secondAttribute="bottom" id="foJ-bR-Tun"/>
<constraint firstAttribute="trailing" secondItem="rtA-NK-3HP" secondAttribute="trailing" constant="20" symbolic="YES" id="nWa-6t-02o"/>
<constraint firstAttribute="centerY" secondItem="rtA-NK-3HP" secondAttribute="centerY" constant="10.5" id="zCJ-Ju-uEc"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
<constraints>
<constraint firstItem="J46-0E-no3" firstAttribute="top" secondItem="XAC-Da-lpf" secondAttribute="bottom" constant="8" symbolic="YES" id="0sm-dC-Ype"/>
<constraint firstItem="W8a-1e-Qpz" firstAttribute="top" secondItem="ZPT-EI-yuv" secondAttribute="bottom" constant="40" id="2N2-cs-FPH"/>
<constraint firstAttribute="trailing" secondItem="56H-xR-09J" secondAttribute="trailing" constant="20" symbolic="YES" id="38q-U5-ROK"/>
<constraint firstAttribute="bottom" secondItem="4sN-hm-xio" secondAttribute="bottom" constant="20" symbolic="YES" id="5Eu-eF-yJE"/>
<constraint firstItem="XAC-Da-lpf" firstAttribute="top" secondItem="vHS-3A-Tae" secondAttribute="bottom" constant="8" symbolic="YES" id="6DM-0p-7ZN"/>
<constraint firstAttribute="trailing" secondItem="bON-0a-K0M" secondAttribute="trailing" id="A9o-KP-Gco"/>
<constraint firstAttribute="trailing" secondItem="XAC-Da-lpf" secondAttribute="trailing" constant="20" symbolic="YES" id="AM8-r9-7JZ"/>
<constraint firstAttribute="trailing" secondItem="4Lh-s0-Dbt" secondAttribute="trailing" constant="20" symbolic="YES" id="AiF-cY-b3S"/>
<constraint firstItem="e4b-Iv-Pk9" firstAttribute="top" secondItem="56H-xR-09J" secondAttribute="bottom" constant="8" symbolic="YES" id="F9w-eU-2yK"/>
<constraint firstItem="3Cd-XH-Wau" firstAttribute="centerY" secondItem="ZPT-EI-yuv" secondAttribute="centerY" constant="-1" id="FL4-EX-TPE"/>
<constraint firstItem="56H-xR-09J" firstAttribute="top" secondItem="J46-0E-no3" secondAttribute="bottom" constant="8" symbolic="YES" id="Hse-8i-9M7"/>
<constraint firstItem="vHS-3A-Tae" firstAttribute="top" secondItem="4Lh-s0-Dbt" secondAttribute="bottom" constant="8" symbolic="YES" id="KSY-FU-zZo"/>
<constraint firstItem="56H-xR-09J" firstAttribute="leading" secondItem="1lc-e7-Qme" secondAttribute="leading" constant="20" symbolic="YES" id="Mau-H7-qGk"/>
<constraint firstItem="J2u-kc-30c" firstAttribute="top" secondItem="1lc-e7-Qme" secondAttribute="top" id="P6z-yO-yf1"/>
<constraint firstAttribute="bottom" secondItem="W8a-1e-Qpz" secondAttribute="bottom" id="UHK-Oa-dVz"/>
<constraint firstAttribute="trailing" secondItem="W8a-1e-Qpz" secondAttribute="trailing" id="Wto-bi-7cK"/>
<constraint firstItem="beo-cJ-jIn" firstAttribute="centerX" secondItem="W8a-1e-Qpz" secondAttribute="centerX" id="XKG-YV-Ywc"/>
<constraint firstAttribute="trailing" secondItem="ZPT-EI-yuv" secondAttribute="trailing" constant="20" symbolic="YES" id="Y6S-XB-LZw"/>
<constraint firstItem="cAo-K2-E23" firstAttribute="leading" secondItem="1lc-e7-Qme" secondAttribute="leading" constant="20" symbolic="YES" id="ana-bH-tXF"/>
<constraint firstItem="cAo-K2-E23" firstAttribute="centerY" secondItem="3Cd-XH-Wau" secondAttribute="centerY" id="bNn-uS-xFD"/>
<constraint firstItem="J2u-kc-30c" firstAttribute="leading" secondItem="1lc-e7-Qme" secondAttribute="leading" id="dAy-CG-bok"/>
<constraint firstAttribute="trailing" secondItem="e4b-Iv-Pk9" secondAttribute="trailing" constant="20" symbolic="YES" id="eJc-ik-sKE"/>
<constraint firstAttribute="trailing" secondItem="vHS-3A-Tae" secondAttribute="trailing" constant="20" symbolic="YES" id="f5B-0z-RcZ"/>
<constraint firstItem="e4b-Iv-Pk9" firstAttribute="leading" secondItem="1lc-e7-Qme" secondAttribute="leading" constant="20" symbolic="YES" id="gO9-M2-f6V"/>
<constraint firstItem="4Lh-s0-Dbt" firstAttribute="top" secondItem="1lc-e7-Qme" secondAttribute="top" constant="20" symbolic="YES" id="hIW-2I-3FE"/>
<constraint firstItem="bON-0a-K0M" firstAttribute="top" secondItem="1lc-e7-Qme" secondAttribute="top" id="ikF-Ua-E4r"/>
<constraint firstItem="W8a-1e-Qpz" firstAttribute="leading" secondItem="1lc-e7-Qme" secondAttribute="leading" id="mMd-GF-btJ"/>
<constraint firstAttribute="trailing" secondItem="J46-0E-no3" secondAttribute="trailing" constant="20" symbolic="YES" id="n1Q-ie-qM5"/>
<constraint firstItem="4Lh-s0-Dbt" firstAttribute="leading" secondItem="1lc-e7-Qme" secondAttribute="leading" constant="20" symbolic="YES" id="oS6-8x-NDj"/>
<constraint firstItem="ZPT-EI-yuv" firstAttribute="leading" secondItem="3Cd-XH-Wau" secondAttribute="trailing" constant="8" symbolic="YES" id="rX1-52-d9v"/>
<constraint firstItem="vHS-3A-Tae" firstAttribute="leading" secondItem="1lc-e7-Qme" secondAttribute="leading" constant="20" symbolic="YES" id="tHF-hR-QxL"/>
<constraint firstItem="J46-0E-no3" firstAttribute="leading" secondItem="1lc-e7-Qme" secondAttribute="leading" constant="20" symbolic="YES" id="tbN-R3-voN"/>
<constraint firstItem="beo-cJ-jIn" firstAttribute="bottom" secondItem="W8a-1e-Qpz" secondAttribute="centerY" id="xiJ-7N-2e0"/>
<constraint firstItem="XAC-Da-lpf" firstAttribute="leading" secondItem="1lc-e7-Qme" secondAttribute="leading" constant="20" symbolic="YES" id="yrb-LB-Pha"/>
<constraint firstItem="ZPT-EI-yuv" firstAttribute="top" secondItem="e4b-Iv-Pk9" secondAttribute="bottom" constant="8" symbolic="YES" id="yul-EL-xCT"/>
<constraint firstAttribute="centerX" secondItem="4sN-hm-xio" secondAttribute="centerX" constant="0.5" id="zQh-Ka-9zH"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="1lc-e7-Qme" firstAttribute="leading" secondItem="GiS-3g-cDj" secondAttribute="leading" constant="8" id="3xS-Ou-InS"/>
<constraint firstAttribute="trailing" secondItem="1lc-e7-Qme" secondAttribute="trailing" constant="8" id="KWW-Vx-P8J"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="GiS-3g-cDj" secondAttribute="trailing" id="TjK-B6-KoI"/>
<constraint firstItem="GiS-3g-cDj" firstAttribute="top" secondItem="7jl-cw-kaJ" secondAttribute="top" id="Zzd-AD-1X5"/>
<constraint firstItem="GiS-3g-cDj" firstAttribute="leading" secondItem="7jl-cw-kaJ" secondAttribute="leading" id="bk6-yS-CW5"/>
<constraint firstItem="1lc-e7-Qme" firstAttribute="top" secondItem="cmU-lf-Fxd" secondAttribute="bottom" constant="8" id="mhg-9h-rmE"/>
<constraint firstItem="IV3-lc-Fnf" firstAttribute="top" secondItem="GiS-3g-cDj" secondAttribute="bottom" id="t22-RN-Hm0"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="Iif-Vk-z5j">
<barButtonItem key="backBarButtonItem" title="Log Out" id="cKa-vZ-q96"/>
</navigationItem>
<connections>
<outlet property="emergencyActivity" destination="4sN-hm-xio" id="OR9-Pj-ygm"/>
<outlet property="emergencyContentTipContainer" destination="beo-cJ-jIn" id="BdT-0M-8qC"/>
<outlet property="emergencyCounter" destination="3Cd-XH-Wau" id="wv7-jZ-6tX"/>
<outlet property="emergencyCounterStepper" destination="ZPT-EI-yuv" id="w5c-hO-T51"/>
<outlet property="emergencyGeneratorContainer" destination="GiS-3g-cDj" id="01o-PU-SNZ"/>
<outlet property="emergencyGeneratorDialog" destination="1lc-e7-Qme" id="JYt-mv-XV2"/>
<outlet property="emergencyMasterPassword" destination="J46-0E-no3" id="DfH-4n-cop"/>
<outlet property="emergencyName" destination="XAC-Da-lpf" id="XCk-0H-IcI"/>
<outlet property="emergencyPassword" destination="W8a-1e-Qpz" id="Xfx-nM-1LX"/>
<outlet property="emergencySite" destination="56H-xR-09J" id="8no-IN-nsH"/>
<outlet property="emergencyTypeControl" destination="e4b-Iv-Pk9" id="S69-yO-7bv"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="2GS-rH-ANj" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="p6o-h3-NRH" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="1350" y="-264"/>
</scene>
</scenes>
<resources>
<image name="avatar-0.png" width="110" height="110"/>
<image name="background.png" width="568" height="568"/>
<image name="gittip.png" width="89" height="18"/>
<image name="icon_cancel.png" width="32" height="32"/>
<image name="icon_edit.png" width="32" height="32"/>
<image name="icon_gears.png" width="32" height="32"/>
<image name="icon_person.png" width="32" height="32"/>
<image name="icon_plus.png" width="32" height="32"/>
<image name="icon_up.png" width="32" height="32"/>