2
0

activeUser refactor, tool tip hiding and dismiss when logout.

[UPDATED]   Made activeUser access follow same pattern as activeElement which makes it more clear what the thread model is like.
[FIXED]     Save after update of all elements.
[UPDATED]   Tool tips hidden in IB now; makes it less cluttered.
[FIXED]     Dismissing view controllers when logging out.
This commit is contained in:
Maarten Billemont 2013-04-17 22:00:15 -04:00
parent ee93412dd1
commit c31df49599
15 changed files with 372 additions and 360 deletions

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit 0d30693440fd520715f22789d33d5551b3b681c4
Subproject commit 737b198043a3acb3a262a38a8b14e265801ce682

View File

@ -73,11 +73,8 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
if (self.key)
self.key = nil;
if (self.activeUser) {
self.activeUser = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:MPSignedOutNotification object:self userInfo:
@{@"animated": @(animated)}];
}
self.activeUser = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:MPSignedOutNotification object:self userInfo:@{@"animated": @(animated)}];
}
- (BOOL)signInAsUser:(MPUserEntity *)user usingMasterPassword:(NSString *)password {
@ -235,7 +232,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
[moc saveToStore];
#ifdef PEARL_UIKIT
[activityAlert cancelAlert];
[activityAlert cancelAlertAnimated:YES];
#endif
}

View File

@ -15,11 +15,12 @@
@interface MPAppDelegate_Shared : NSObject <PearlConfigDelegate>
#endif
@property (strong, nonatomic) MPUserEntity *activeUser;
@property (strong, nonatomic) MPKey *key;
+ (instancetype)get;
- (MPUserEntity *)activeUserForThread;
- (MPUserEntity *)activeUserInContext:(NSManagedObjectContext *)moc;
- (void)setActiveUser:(MPUserEntity *)activeUser;
@end

View File

@ -24,7 +24,7 @@
#endif
}
- (MPUserEntity *)activeUser {
- (MPUserEntity *)activeUserForThread {
if (!_activeUserOID)
return nil;
@ -36,7 +36,7 @@
NSError *error;
MPUserEntity *activeUser = (MPUserEntity *)[moc existingObjectWithID:_activeUserOID error:&error];
if (!activeUser)
err(@"Failed to retrieve active user: %@", error);
err(@"Failed to retrieve active user: %@", error);
return activeUser;
}

View File

@ -356,8 +356,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
self.privateManagedObjectContext = privateManagedObjectContext;
self.mainManagedObjectContext = mainManagedObjectContext;
[self.handleCloudContentAlert cancelAlert];
[self.fixCloudContentAlert cancelAlert];
[self.handleCloudContentAlert cancelAlertAnimated:YES];
[self.fixCloudContentAlert cancelAlertAnimated:YES];
[self.storeLoading cancelOverlay];
}
@ -391,7 +391,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
- (void)showCloudContentAlert {
__weak MPAppDelegate_Shared *wSelf = self;
[self.handleCloudContentAlert cancelAlert];
[self.handleCloudContentAlert cancelAlertAnimated:NO];
self.handleCloudContentAlert = [PearlAlert showActivityWithTitle:@"iCloud Sync Problem" message:
@"Waiting for your other device to autocorrect the problem..."
initAlert:^(UIAlertView *alert) {
@ -634,7 +634,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
- (NSString *)exportSitesShowingPasswords:(BOOL)showPasswords {
MPUserEntity *activeUser = self.activeUser;
MPUserEntity *activeUser = [self activeUserForThread];
inf(@"Exporting sites, %@, for: %@", showPasswords? @"showing passwords": @"omitting passwords", activeUser.userID);
// Header.

View File

@ -362,7 +362,7 @@
break;
}
[activityAlert cancelAlert];
[activityAlert cancelAlertAnimated:YES];
});
return YES;
@ -489,7 +489,7 @@
- (void)openFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController {
NSString *userName = [MPAppDelegate get].activeUser.name;
NSString *userName = [[MPAppDelegate get] activeUserForThread].name;
PearlLogLevel logLevel = [[MPiOSConfig get].sendInfo boolValue]? PearlLogLevelDebug: PearlLogLevelInfo;
[[[PearlEMail alloc] initForEMailTo:@"Master Password Development <masterpassword@lyndir.com>"
@ -555,12 +555,12 @@
NSString *message;
if (showPasswords)
message = PearlString(@"Export of Master Password sites with passwords included.\n"
message = PearlString(@"Export of Master Password sites with passwords included.\n\n"
@"REMINDER: Make sure nobody else sees this file! Passwords are visible!\n\n\n"
@"--\n"
@"%@\n"
@"Master Password %@, build %@",
self.activeUser.name,
[self activeUserForThread].name,
[PearlInfoPlist get].CFBundleShortVersionString,
[PearlInfoPlist get].CFBundleVersion);
else
@ -568,7 +568,7 @@
@"--\n"
@"%@\n"
@"Master Password %@, build %@",
self.activeUser.name,
[self activeUserForThread].name,
[PearlInfoPlist get].CFBundleShortVersionString,
[PearlInfoPlist get].CFBundleVersion);
@ -578,7 +578,7 @@
[PearlEMail sendEMailTo:nil subject:@"Master Password Export" body:message
attachments:[[PearlEMailAttachment alloc] initWithContent:[exportedSites dataUsingEncoding:NSUTF8StringEncoding]
mimeType:@"text/plain" fileName:
PearlString(@"%@ (%@).mpsites", self.activeUser.name, [exportDateFormatter stringFromDate:[NSDate date]])],
PearlString(@"%@ (%@).mpsites", [self activeUserForThread].name, [exportDateFormatter stringFromDate:[NSDate date]])],
nil];
}

View File

@ -77,7 +77,7 @@
[self performUpgradeAllWithCompletion:^(BOOL success, NSDictionary *changes) {
dispatch_async( dispatch_get_main_queue(), ^{
[self showUpgradeChanges:changes];
[activity cancelAlert];
[activity cancelAlertAnimated:YES];
} );
}];
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil];
@ -110,6 +110,7 @@
} forKey:element.name];
}
[moc saveToStore];
completion(YES, elementChanges);
}];
}

View File

@ -104,7 +104,7 @@
- (void)updateData {
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
MPUserEntity *activeUser = [[MPAppDelegate get] activeUserForThread];
if (!activeUser)
return;

View File

@ -196,7 +196,7 @@
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
cell.textLabel.text = query;
cell.detailTextLabel.text = PearlString(@"New site: %@",
[MPAlgorithmDefault shortNameOfType:[[MPAppDelegate get].activeUser defaultType]]);
[MPAlgorithmDefault shortNameOfType:[[[MPAppDelegate get] activeUserForThread] defaultType]]);
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

View File

@ -33,6 +33,12 @@
[super viewDidLoad];
self.siteNameTip.hidden = NO;
self.contentTip.hidden = NO;
self.usernameTip.hidden = NO;
self.typeTip.hidden = NO;
self.toolTip.hidden = NO;
self.tickCount = 30;
}

View File

@ -84,19 +84,29 @@
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPElementUpdatedNotification object:nil queue:nil usingBlock:
^void(NSNotification *note) {
[self activeElementDo:^(MPElementEntity *activeElement) {
if (activeElement.type & MPElementTypeClassStored && ![[activeElement.content description] length])
[self showToolTip:@"Tap to set a password." withIcon:self.toolTipEditIcon];
if (activeElement.requiresExplicitMigration)
[self showToolTip:@"Password outdated. Tap to upgrade it." withIcon:nil];
}];
MPElementEntity *activeElement = [self activeElementForThread];
if (activeElement.type & MPElementTypeClassStored && ![[activeElement.content description] length])
[self showToolTip:@"Tap to set a password." withIcon:self.toolTipEditIcon];
if (activeElement.requiresExplicitMigration)
[self showToolTip:@"Password outdated. Tap to upgrade it." withIcon:nil];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil queue:nil usingBlock:
^(NSNotification *note) {
BOOL animated = [[note.userInfo objectForKey:@"animated"] boolValue];
_activeElementOID = nil;
self.suppressOutdatedAlert = NO;
[self updateAnimated:NO];
[self.navigationController popToRootViewControllerAnimated:[[note.userInfo objectForKey:@"animated"] boolValue]];
[[PearlSheet activeSheets] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[obj cancelSheetAnimated:NO];
}];
if (![self.navigationController presentedViewController])
[self.navigationController popToRootViewControllerAnimated:animated];
else
[self.navigationController dismissViewControllerAnimated:animated completion:^{
[self.navigationController popToRootViewControllerAnimated:animated];
}];
}];
[super viewDidLoad];
@ -104,18 +114,19 @@
- (void)viewWillAppear:(BOOL)animated {
[self activeElementDo:^(MPElementEntity *activeElement) {
if (activeElement.user != [MPAppDelegate get].activeUser)
_activeElementOID = nil;
}];
MPElementEntity *activeElement = [self activeElementForThread];
if (activeElement.user != [[MPAppDelegate get] activeUserForThread])
_activeElementOID = nil;
self.searchDisplayController.searchBar.text = nil;
self.alertContainer.alpha = 0;
self.outdatedAlertContainer.alpha = 0;
self.searchTipContainer.alpha = 0;
self.actionsTipContainer.alpha = 0;
self.typeTipContainer.alpha = 0;
self.toolTipContainer.alpha = 0;
self.alertContainer.hidden = NO;
self.outdatedAlertContainer.hidden = NO;
self.searchTipContainer.hidden = NO;
self.actionsTipContainer.hidden = NO;
self.typeTipContainer.hidden = NO;
self.toolTipContainer.hidden = NO;
self.contentTipContainer.hidden = NO;
self.loginNameTipContainer.hidden = NO;
[self updateAnimated:NO];
@ -132,7 +143,7 @@
// Needed for when we appear after a modal VC dismisses:
// We can't present until the other modal VC has been fully dismissed and presenting in -viewWillAppear: will fail.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
MPUserEntity *activeUser = [[MPAppDelegate get] activeUserForThread];
if ([MPAlgorithmDefault migrateUser:activeUser] && !self.suppressOutdatedAlert)
[UIView animateWithDuration:0.3f animations:^{
self.outdatedAlertContainer.alpha = 1;
@ -182,59 +193,58 @@
return;
}
[self activeElementDo:^(MPElementEntity *activeElement) {
[self setHelpChapter:activeElement? @"2": @"1"];
[self updateHelpHiddenAnimated:NO];
MPElementEntity *activeElement = [self activeElementForThread];
[self setHelpChapter:activeElement? @"2": @"1"];
[self updateHelpHiddenAnimated:NO];
self.passwordCounter.alpha = 0;
self.passwordIncrementer.alpha = 0;
self.passwordEdit.alpha = 0;
self.passwordUpgrade.alpha = 0;
self.passwordUser.alpha = 0;
self.displayContainer.alpha = 0;
self.passwordCounter.alpha = 0;
self.passwordIncrementer.alpha = 0;
self.passwordEdit.alpha = 0;
self.passwordUpgrade.alpha = 0;
self.passwordUser.alpha = 0;
self.displayContainer.alpha = 0;
if (activeElement) {
self.passwordUser.alpha = 0.5f;
self.displayContainer.alpha = 1.0f;
}
if (activeElement) {
self.passwordUser.alpha = 0.5f;
self.displayContainer.alpha = 1.0f;
}
if (activeElement.requiresExplicitMigration)
self.passwordUpgrade.alpha = 0.5f;
if (activeElement.requiresExplicitMigration)
self.passwordUpgrade.alpha = 0.5f;
else {
if (activeElement.type & MPElementTypeClassGenerated) {
self.passwordCounter.alpha = 0.5f;
self.passwordIncrementer.alpha = 0.5f;
} else
if (activeElement.type & MPElementTypeClassStored)
self.passwordEdit.alpha = 0.5f;
}
else {
if (activeElement.type & MPElementTypeClassGenerated) {
self.passwordCounter.alpha = 0.5f;
self.passwordIncrementer.alpha = 0.5f;
} else
if (activeElement.type & MPElementTypeClassStored)
self.passwordEdit.alpha = 0.5f;
}
self.siteName.text = activeElement.name;
self.siteName.text = activeElement.name;
self.typeButton.alpha = activeElement? 1: 0;
[self.typeButton setTitle:activeElement.typeName
forState:UIControlStateNormal];
self.typeButton.alpha = activeElement? 1: 0;
[self.typeButton setTitle:activeElement.typeName
forState:UIControlStateNormal];
if ([activeElement isKindOfClass:[MPElementGeneratedEntity class]])
self.passwordCounter.text = PearlString(@"%u", ((MPElementGeneratedEntity *)activeElement).counter);
if ([activeElement isKindOfClass:[MPElementGeneratedEntity class]])
self.passwordCounter.text = PearlString(@"%u", ((MPElementGeneratedEntity *)activeElement).counter);
self.contentField.enabled = NO;
self.contentField.text = @"";
if (activeElement.name && ![activeElement isDeleted])
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSString *description = [activeElement.content description];
self.contentField.enabled = NO;
self.contentField.text = @"";
if (activeElement.name && ![activeElement isDeleted])
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSString *description = [activeElement.content description];
dispatch_async(dispatch_get_main_queue(), ^{
self.contentField.text = description;
});
dispatch_async(dispatch_get_main_queue(), ^{
self.contentField.text = description;
});
});
self.loginNameField.enabled = NO;
self.loginNameField.text = activeElement.loginName;
self.siteInfoHidden = !activeElement || ([[MPiOSConfig get].siteInfoHidden boolValue] && (activeElement.loginName == nil));
[self updateUserHiddenAnimated:NO];
}];
self.loginNameField.enabled = NO;
self.loginNameField.text = activeElement.loginName;
self.siteInfoHidden = !activeElement || ([[MPiOSConfig get].siteInfoHidden boolValue] && (activeElement.loginName == nil));
[self updateUserHiddenAnimated:NO];
}
- (void)toggleHelpAnimated:(BOOL)animated {
@ -344,12 +354,11 @@
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self activeElementDo:^(MPElementEntity *activeElement) {
NSString *error = [self.helpView stringByEvaluatingJavaScriptFromString:
PearlString(@"setClass('%@');", activeElement.typeClassName)];
if (error.length)
MPElementEntity *activeElement = [self activeElementForThread];
NSString *error = [self.helpView stringByEvaluatingJavaScriptFromString:
PearlString(@"setClass('%@');", activeElement.typeClassName)];
if (error.length)
err(@"helpView.setClass: %@", error);
}];
}
- (void)showContentTip:(NSString *)message withIcon:(UIImageView *)icon {
@ -451,43 +460,41 @@
- (IBAction)copyContent {
[self activeElementDo:^(MPElementEntity *activeElement) {
id content = activeElement.content;
if (!content)
// Nothing to copy.
return;
MPElementEntity *activeElement = [self activeElementForThread];
id content = activeElement.content;
if (!content)
// Nothing to copy.
return;
inf(@"Copying password for: %@", activeElement.name);
[UIPasteboard generalPasteboard].string = [content description];
inf(@"Copying password for: %@", activeElement.name);
[UIPasteboard generalPasteboard].string = [content description];
[self showContentTip:@"Copied!" withIcon:nil];
[self showContentTip:@"Copied!" withIcon:nil];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointCopyToPasteboard];
[TestFlight passCheckpoint:MPCheckpointCopyToPasteboard];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCopyToPasteboard attributes:@{@"type" : activeElement.typeName,
@"version" : @(activeElement.version)}];
}];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCopyToPasteboard attributes:@{@"type" : activeElement.typeName,
@"version" : @(activeElement.version)}];
}
- (IBAction)copyLoginName:(UITapGestureRecognizer *)sender {
[self activeElementDo:^(MPElementEntity *activeElement) {
if (!activeElement.loginName)
return;
MPElementEntity *activeElement = [self activeElementForThread];
if (!activeElement.loginName)
return;
inf(@"Copying user name for: %@", activeElement.name);
[UIPasteboard generalPasteboard].string = activeElement.loginName;
inf(@"Copying user name for: %@", activeElement.name);
[UIPasteboard generalPasteboard].string = activeElement.loginName;
[self showLoginNameTip:@"Copied!"];
[self showLoginNameTip:@"Copied!"];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointCopyLoginNameToPasteboard];
[TestFlight passCheckpoint:MPCheckpointCopyLoginNameToPasteboard];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCopyLoginNameToPasteboard
attributes:@{@"type" : activeElement.typeName,
@"version" : @(activeElement.version)}];
}];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCopyLoginNameToPasteboard
attributes:@{@"type" : activeElement.typeName,
@"version" : @(activeElement.version)}];
}
- (IBAction)incrementPasswordCounter {
@ -522,34 +529,30 @@
if (sender.state != UIGestureRecognizerStateBegan)
// Only fire when the gesture was first detected.
return;
__block BOOL abort = NO;
[self activeElementDo:^(MPElementEntity *activeElement) {
if (![activeElement isKindOfClass:[MPElementGeneratedEntity class]]) {
// Not of a type that supports a password counter.
err(@"Cannot reset password counter: Element is not generated: %@", activeElement.name);
abort = YES;
} else
if (((MPElementGeneratedEntity *)activeElement).counter == 1)
// Counter has initial value, no point resetting.
abort = YES;
}];
if (abort)
MPElementEntity *activeElement = [self activeElementForThread];
if (![activeElement isKindOfClass:[MPElementGeneratedEntity class]]) {
// Not of a type that supports a password counter.
err(@"Cannot reset password counter: Element is not generated: %@", activeElement.name);
return;
} else
if (((MPElementGeneratedEntity *)activeElement).counter == 1)
// Counter has initial value, no point resetting.
return;
[self changeActiveElementWithWarning:
@"You are resetting the site's password counter.\n\n"
@"If you continue, the site's password will change back to its original value. "
@"You will then need to update your account's password back to this original value."
do:^BOOL(MPElementEntity *activeElement){
inf(@"Resetting password counter for: %@", activeElement.name);
((MPElementGeneratedEntity *)activeElement).counter = 1;
do:^BOOL(MPElementEntity *activeElement_){
inf(@"Resetting password counter for: %@", activeElement_.name);
((MPElementGeneratedEntity *)activeElement_).counter = 1;
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointResetPasswordCounter];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointResetPasswordCounter
attributes:@{@"type": activeElement.typeName,
@"version": @(activeElement.version)}];
attributes:@{@"type": activeElement_.typeName,
@"version": @(activeElement_.version)}];
return YES;
}];
}
@ -560,19 +563,18 @@
// Only fire when the gesture was first detected.
return;
[self activeElementDo:^(MPElementEntity *activeElement) {
if (!activeElement)
return;
MPElementEntity *activeElement = [self activeElementForThread];
if (!activeElement)
return;
self.loginNameField.enabled = YES;
[self.loginNameField becomeFirstResponder];
self.loginNameField.enabled = YES;
[self.loginNameField becomeFirstResponder];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointEditLoginName];
[TestFlight passCheckpoint:MPCheckpointEditLoginName];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointEditLoginName attributes:@{@"type" : activeElement.typeName,
@"version" : @(activeElement.version)}];
}];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointEditLoginName attributes:@{@"type" : activeElement.typeName,
@"version" : @(activeElement.version)}];
}
- (void)changeActiveElementWithWarning:(NSString *)warning do:(BOOL (^)(MPElementEntity *activeElement))task; {
@ -588,101 +590,92 @@
- (void)changeActiveElementWithoutWarningDo:(BOOL (^)(MPElementEntity *activeElement))task; {
// Update element, keeping track of the old password.
[self activeElementDo:^(MPElementEntity *activeElement) {
// Perform the task.
NSString *oldPassword = [activeElement.content description];
if (!task( activeElement ))
return;
NSString *newPassword = [activeElement.content description];
MPElementEntity *activeElement = [self activeElementForThread];
NSString *oldPassword = [activeElement.content description];
if (!task( activeElement ))
return;
NSString *newPassword = [activeElement.content description];
// Save.
[activeElement.managedObjectContext saveToStore];
// Save.
[activeElement.managedObjectContext saveToStore];
// Update the UI.
dispatch_async( dispatch_get_main_queue(), ^{
[self updateAnimated:YES];
// Update the UI.
dispatch_async( dispatch_get_main_queue(), ^{
[self updateAnimated:YES];
// Show new and old password.
if ([oldPassword length] && ![oldPassword isEqualToString:newPassword])
[self showAlertWithTitle:@"Password Changed!"
message:PearlString( @"The password for %@ has changed.\n\n"
@"IMPORTANT:\n"
@"Don't forget to update the site with your new password! "
@"Your old password was:\n"
@"%@", activeElement.name, oldPassword )];
} );
}];
// Show new and old password.
if ([oldPassword length] && ![oldPassword isEqualToString:newPassword])
[self showAlertWithTitle:@"Password Changed!"
message:PearlString( @"The password for %@ has changed.\n\n"
@"IMPORTANT:\n"
@"Don't forget to update the site with your new password! "
@"Your old password was:\n"
@"%@", activeElement.name, oldPassword )];
} );
}
- (void)activeElementDo:(void (^)(MPElementEntity *activeElement))task {
- (MPElementEntity *)activeElementForThread {
if (!_activeElementOID) {
task(nil);
return;
}
if (!_activeElementOID)
return nil;
NSManagedObjectContext *moc = [MPAppDelegate managedObjectContextForThreadIfReady];
if (!moc) {
task(nil);
return;
}
if (!moc)
return nil;
NSError *error;
MPElementEntity *activeElement = (MPElementEntity *)[moc existingObjectWithID:_activeElementOID error:&error];
if (!activeElement)
err(@"Couldn't retrieve active element: %@", error);
task(activeElement);
return activeElement;
}
- (IBAction)editPassword {
[self activeElementDo:^(MPElementEntity *activeElement) {
if (!(activeElement.type & MPElementTypeClassStored)) {
// Not of a type that supports editing the content.
err(@"Cannot edit content: Element is not stored: %@", activeElement.name);
return;
}
MPElementEntity *activeElement = [self activeElementForThread];
if (!(activeElement.type & MPElementTypeClassStored)) {
// Not of a type that supports editing the content.
err(@"Cannot edit content: Element is not stored: %@", activeElement.name);
return;
}
self.contentField.enabled = YES;
[self.contentField becomeFirstResponder];
self.contentField.enabled = YES;
[self.contentField becomeFirstResponder];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointEditPassword];
[TestFlight passCheckpoint:MPCheckpointEditPassword];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointEditPassword attributes:@{@"type" : activeElement.typeName,
@"version" : @(activeElement.version)}];
}];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointEditPassword attributes:@{@"type" : activeElement.typeName,
@"version" : @(activeElement.version)}];
}
- (IBAction)upgradePassword {
__block NSString *warning = nil;
[self activeElementDo:^(MPElementEntity *activeElement) {
warning = activeElement.type & MPElementTypeClassGenerated?
MPElementEntity *activeElement = [self activeElementForThread];
if (!activeElement)
return;
NSString *warning = activeElement.type & MPElementTypeClassGenerated?
@"You are upgrading the site.\n\n"
@"This upgrade improves the site's compatibility with the latest version of Master Password.\n\n"
@"Your password will change and you will need to update your site's account."
:
@"You are upgrading the site.\n\n"
@"This upgrade improves the site's compatibility with the latest version of Master Password.";
}];
if (!warning)
return;
[self changeActiveElementWithWarning:warning do:
^BOOL(MPElementEntity *activeElement) {
inf(@"Explicitly migrating element: %@", activeElement);
[activeElement migrateExplicitly:YES];
^BOOL(MPElementEntity *activeElement_) {
inf(@"Explicitly migrating element: %@", activeElement_);
[activeElement_ migrateExplicitly:YES];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointExplicitMigration];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointExplicitMigration attributes:@{
@"type" : activeElement.typeName,
@"version" : @(activeElement.version)
@"type" : activeElement_.typeName,
@"version" : @(activeElement_.version)
}];
return YES;
}];
@ -783,12 +776,7 @@
- (MPElementEntity *)selectedElement {
__block MPElementEntity *selectedElement;
[self activeElementDo:^(MPElementEntity *activeElement) {
selectedElement = activeElement;
}];
return selectedElement;
return [self activeElementForThread];
}
- (void)didSelectType:(MPElementType)type {
@ -839,36 +827,34 @@
return YES;
}];
[self activeElementDo:^(MPElementEntity *activeElement) {
inf(@"Selected: %@", activeElement.name);
dbg(@"Element:\n%@", [activeElement debugDescription]);
MPElementEntity *activeElement = [self activeElementForThread];
inf(@"Selected: %@", activeElement.name);
if (![[MPiOSConfig get].typeTipShown boolValue])
[UIView animateWithDuration:0.5f animations:^{
self.typeTipContainer.alpha = 1;
} completion:^(BOOL finished) {
if (finished) {
[MPiOSConfig get].typeTipShown = PearlBool(YES);
if (![[MPiOSConfig get].typeTipShown boolValue])
[UIView animateWithDuration:0.5f animations:^{
self.typeTipContainer.alpha = 1;
} completion:^(BOOL finished) {
if (finished) {
[MPiOSConfig get].typeTipShown = PearlBool(YES);
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.2f animations:^{
self.typeTipContainer.alpha = 0;
}];
});
}
}];
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.2f animations:^{
self.typeTipContainer.alpha = 0;
}];
});
}
}];
[self.searchDisplayController setActive:NO animated:YES];
self.searchDisplayController.searchBar.text = activeElement.name;
[self.searchDisplayController setActive:NO animated:YES];
self.searchDisplayController.searchBar.text = activeElement.name;
[[NSNotificationCenter defaultCenter] postNotificationName:MPElementUpdatedNotification object:activeElement.objectID];
[[NSNotificationCenter defaultCenter] postNotificationName:MPElementUpdatedNotification object:activeElement.objectID];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:PearlString(MPCheckpointUseType @"_%@", activeElement.typeShortName)];
[TestFlight passCheckpoint:PearlString(MPCheckpointUseType @"_%@", activeElement.typeShortName)];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointUseType attributes:@{@"type" : activeElement.typeName,
@"version" : @(activeElement.version)}];
}];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointUseType attributes:@{@"type" : activeElement.typeName,
@"version" : @(activeElement.version)}];
[self updateAnimated:YES];
}
@ -886,21 +872,17 @@
if (textField == self.contentField) {
self.contentField.enabled = NO;
__block BOOL abort = NO;
[self activeElementDo:^(MPElementEntity *activeElement) {
if (![activeElement isKindOfClass:[MPElementStoredEntity class]]) {
// Not of a type whose content can be edited.
err(@"Cannot update element content: Element is not stored: %@", activeElement.name);
abort = YES;
} else if ([((MPElementStoredEntity *)activeElement).content isEqual:self.contentField.text])
// Content hasn't changed.
abort = YES;
}];
if (abort)
MPElementEntity *activeElement = [self activeElementForThread];
if (![activeElement isKindOfClass:[MPElementStoredEntity class]]) {
// Not of a type whose content can be edited.
err(@"Cannot update element content: Element is not stored: %@", activeElement.name);
return;
} else if ([((MPElementStoredEntity *)activeElement).content isEqual:self.contentField.text])
// Content hasn't changed.
return;
[self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement) {
((MPElementStoredEntity *)activeElement).content = self.contentField.text;
[self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement_) {
((MPElementStoredEntity *)activeElement_).content = self.contentField.text;
return YES;
}];
}

View File

@ -47,12 +47,12 @@
} options:0];
[avatar onSelect:^(BOOL selected) {
if (selected) {
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
MPUserEntity *activeUser = [[MPAppDelegate get] activeUserForThread];
activeUser.avatar = (unsigned)avatar.tag;
[activeUser.managedObjectContext saveToStore];
}
} options:0];
avatar.selected = (a == [MPAppDelegate get].activeUser.avatar);
avatar.selected = (a == [[MPAppDelegate get] activeUserForThread].avatar);
}
[super viewDidLoad];
@ -68,8 +68,9 @@
}
} recurse:NO];
self.savePasswordSwitch.on = [MPAppDelegate get].activeUser.saveKey;
self.defaultTypeLabel.text = [[MPAppDelegate get].key.algorithm shortNameOfType:[MPAppDelegate get].activeUser.defaultType];
MPUserEntity *activeUser = [[MPAppDelegate get] activeUserForThread];
self.savePasswordSwitch.on = activeUser.saveKey;
self.defaultTypeLabel.text = [[MPAppDelegate get].key.algorithm shortNameOfType:activeUser.defaultType];
[super viewWillAppear:animated];
}
@ -113,7 +114,7 @@
else
if (cell == self.changeMPCell) {
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
MPUserEntity *activeUser = [[MPAppDelegate get] activeUserForThread];
[[MPAppDelegate get] changeMasterPasswordFor:activeUser inContext:activeUser.managedObjectContext didResetBlock:nil];
}
@ -132,7 +133,7 @@
- (void)didSelectType:(MPElementType)type {
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
MPUserEntity *activeUser = [[MPAppDelegate get] activeUserForThread];
activeUser.defaultType = type;
[activeUser.managedObjectContext saveToStore];
@ -141,14 +142,14 @@
- (MPElementType)selectedType {
return [MPAppDelegate get].activeUser.defaultType;
return [[MPAppDelegate get] activeUserForThread].defaultType;
}
#pragma mark - IBActions
- (IBAction)didToggleSwitch:(UISwitch *)sender {
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
MPUserEntity *activeUser = [[MPAppDelegate get] activeUserForThread];
if ((activeUser.saveKey = sender.on))
[[MPAppDelegate get] storeSavedKeyFor:activeUser];
else

View File

@ -120,8 +120,8 @@
self.nameLabel.layer.cornerRadius = 5;
self.avatarTemplate.hidden = YES;
self.spinner.alpha = 0;
self.passwordTipView.alpha = 0;
self.createPasswordTipView.alpha = 0;
self.passwordTipView.hidden = NO;
self.createPasswordTipView.hidden = NO;
NSMutableArray *wordListLines = [NSMutableArray arrayWithCapacity:27413];
[[[NSString alloc] initWithData:[NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"dictionary" withExtension:@"lst"]]
@ -317,38 +317,36 @@
- (void)showNewUserNameAlertFor:(MPUserEntity *)newUser inContext:(NSManagedObjectContext *)moc
completion:(void (^)(BOOL finished))completion {
PEARL_MAIN_THREAD_START
[PearlAlert showAlertWithTitle:@"Enter Your Name"
message:nil viewStyle:UIAlertViewStylePlainTextInput
initAlert:^(UIAlertView *alert, UITextField *firstField) {
firstField.autocapitalizationType = UITextAutocapitalizationTypeWords;
firstField.keyboardType = UIKeyboardTypeAlphabet;
firstField.text = newUser.name;
firstField.placeholder = @"eg. Robert Lee Mitchell";
firstField.enablesReturnKeyAutomatically = YES;
}
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex]) {
completion(NO);
return;
[PearlAlert showAlertWithTitle:@"Enter Your Name"
message:nil viewStyle:UIAlertViewStylePlainTextInput
initAlert:^(UIAlertView *alert, UITextField *firstField) {
firstField.autocapitalizationType = UITextAutocapitalizationTypeWords;
firstField.keyboardType = UIKeyboardTypeAlphabet;
firstField.text = newUser.name;
firstField.placeholder = @"eg. Robert Lee Mitchell";
firstField.enablesReturnKeyAutomatically = YES;
}
NSString *name = [alert textFieldAtIndex:0].text;
if (!name.length) {
[PearlAlert showAlertWithTitle:@"Name Is Required" message:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
[self showNewUserNameAlertFor:newUser inContext:moc completion:completion];
} cancelTitle:@"Try Again" otherTitles:nil];
return;
}
// Save
[moc performBlockAndWait:^{
newUser.name = name;
}];
[self showNewUserAvatarAlertFor:newUser inContext:moc completion:completion];
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex]) {
completion(NO);
return;
}
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonSave, nil];
PEARL_MAIN_THREAD_END
NSString *name = [alert textFieldAtIndex:0].text;
if (!name.length) {
[PearlAlert showAlertWithTitle:@"Name Is Required" message:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
[self showNewUserNameAlertFor:newUser inContext:moc completion:completion];
} cancelTitle:@"Try Again" otherTitles:nil];
return;
}
// Save
[moc performBlockAndWait:^{
newUser.name = name;
}];
[self showNewUserAvatarAlertFor:newUser inContext:moc completion:completion];
}
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonSave, nil];
}
- (void)showNewUserAvatarAlertFor:(MPUserEntity *)newUser inContext:(NSManagedObjectContext *)moc

View File

@ -9,7 +9,7 @@
<objects>
<tableViewController id="NKe-nv-566" customClass="MPTypeViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="btl-G4-V0S">
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
<rect key="frame" x="0.0" y="64" width="320" height="416"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/>
<view key="tableFooterView" contentMode="scaleToFill" id="aNa-wb-cYK">
@ -481,11 +481,11 @@ Your passwords will be AES-encrypted with your master password.</string>
<objects>
<viewController id="PQa-Xl-A3x" customClass="MPMainViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ep0-Hn-5TR">
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
<rect key="frame" x="0.0" y="64" width="320" height="416"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" image="background.png" id="0hY-LL-ITu">
<rect key="frame" x="0.0" y="44" width="320" height="460"/>
<rect key="frame" x="0.0" y="44" width="320" height="372"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<view contentMode="scaleToFill" id="Juh-jm-UDr" userLabel="View - Content">
@ -662,9 +662,10 @@ Your passwords will be AES-encrypted with your master password.</string>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view contentMode="scaleToFill" id="61G-By-qLB" userLabel="View - Help">
<rect key="frame" x="0.0" y="334" width="320" height="170"/>
<rect key="frame" x="0.0" y="246" width="320" height="170"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="top" image="Square-bottom.png" id="lbm-A0-3PK">
@ -706,7 +707,7 @@ Your passwords will be AES-encrypted with your master password.</string>
<color key="tintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL"/>
</searchBar>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="foz-tW-xGw" userLabel="View - Action Tip">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="foz-tW-xGw" userLabel="View - Action Tip">
<rect key="frame" x="10" y="0.0" width="300" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
@ -729,7 +730,7 @@ Your passwords will be AES-encrypted with your master password.</string>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="zOR-Du-qRL" userLabel="View - Search Tip">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="zOR-Du-qRL" userLabel="View - Search Tip">
<rect key="frame" x="10" y="15" width="300" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
@ -748,9 +749,9 @@ Your passwords will be AES-encrypted with your master password.</string>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="UM8-56-kAO" userLabel="View - Tool Tip">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="UM8-56-kAO" userLabel="View - Tool Tip">
<rect key="frame" x="10" y="15" width="266" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black_bottom_right.png" id="LqX-rO-rep">
<rect key="frame" x="0.0" y="0.0" width="266" height="60"/>
@ -771,7 +772,7 @@ Your passwords will be AES-encrypted with your master password.</string>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="g55-0m-WjS" userLabel="View - Type Tip">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="g55-0m-WjS" userLabel="View - Type Tip">
<rect key="frame" x="10" y="228" width="300" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
@ -790,7 +791,7 @@ Your passwords will be AES-encrypted with your master password.</string>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="v2m-Gf-pEV" userLabel="View - Content Tip">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="v2m-Gf-pEV" userLabel="View - Content Tip">
<rect key="frame" x="55" y="50" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
@ -808,7 +809,7 @@ Your passwords will be AES-encrypted with your master password.</string>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="b9W-aA-93r" userLabel="View - User Name Tip">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="b9W-aA-93r" userLabel="View - User Name Tip">
<rect key="frame" x="55" y="110" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
@ -826,8 +827,8 @@ Your passwords will be AES-encrypted with your master password.</string>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view alpha="0.0" contentMode="scaleToFill" id="6wk-NU-VQG" userLabel="View - Outdated Alert">
<rect key="frame" x="10" y="318" width="300" height="180"/>
<view hidden="YES" alpha="0.0" contentMode="scaleToFill" id="6wk-NU-VQG" userLabel="View - Outdated Alert">
<rect key="frame" x="10" y="230" width="300" height="180"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews>
<imageView contentMode="scaleToFill" image="tip_alert_black.png" id="f30-i7-VBv">
@ -904,8 +905,8 @@ These sites should be upgraded and their account's passwords updated as soon as
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view alpha="0.0" contentMode="scaleToFill" id="yRY-qt-gz8" userLabel="View - Alert">
<rect key="frame" x="10" y="318" width="300" height="180"/>
<view hidden="YES" alpha="0.0" contentMode="scaleToFill" id="yRY-qt-gz8" userLabel="View - Alert">
<rect key="frame" x="10" y="230" width="300" height="180"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_alert_black.png" id="TUv-Tl-xTc">
@ -1084,15 +1085,15 @@ L4m3P4sSw0rD</string>
<objects>
<viewController storyboardIdentifier="MPUnlockViewController" wantsFullScreenLayout="YES" modalTransitionStyle="flipHorizontal" id="Nbn-Rv-sP1" customClass="MPUnlockViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="GeE-5J-ZZO">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="QWe-Gw-rD3">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<view contentMode="scaleToFill" id="PHH-XC-9QQ">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_spinner.png" id="27q-lX-0vy">
@ -1251,7 +1252,7 @@ L4m3P4sSw0rD</string>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.5" contentMode="left" text="Tap and hold to delete or reset user." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="DBJ-Qi-ZcF">
<rect key="frame" x="20" y="548" width="280" height="20"/>
<rect key="frame" x="20" y="460" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="12"/>
<color key="textColor" cocoaTouchSystemColor="lightTextColor"/>
@ -1260,7 +1261,7 @@ L4m3P4sSw0rD</string>
</label>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" indicatorStyle="white" delaysContentTouches="NO" id="Blg-F1-9NA">
<rect key="frame" x="0.0" y="16" width="320" height="340"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="top" showsTouchWhenHighlighted="YES" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="Ten-ig-gog">
<rect key="frame" x="105" y="30" width="110" height="110"/>
@ -1283,7 +1284,7 @@ L4m3P4sSw0rD</string>
</scrollView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="left" text="Maarten Billemont" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumFontSize="10" id="8s0-nT-Aoq">
<rect key="frame" x="90" y="377" width="140" height="15"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" name="Futura-CondensedExtraBold" family="Futura" pointSize="13"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@ -1291,15 +1292,15 @@ L4m3P4sSw0rD</string>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Maarten Billemont" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumFontSize="10" id="0NM-NI-7UR">
<rect key="frame" x="90" y="174" width="140" height="15"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" name="Futura-CondensedExtraBold" family="Futura" pointSize="13"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="xWL-xQ-KjX">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="xWL-xQ-KjX" userLabel="View - Create Password Tip">
<rect key="frame" x="20" y="60" width="280" height="100"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" id="Xrk-S4-ZN5">
<rect key="frame" x="0.0" y="0.0" width="280" height="100"/>
@ -1321,7 +1322,7 @@ You could use the word wall for inspiration in finding a memorable master passw
</view>
<view contentMode="scaleToFill" id="7cc-yu-i0m">
<rect key="frame" x="20" y="168" width="280" height="88"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Enter your master password:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="RhX-bA-EhC">
<rect key="frame" x="10" y="0.0" width="260" height="20"/>
@ -1345,7 +1346,7 @@ You could use the word wall for inspiration in finding a memorable master passw
<outlet property="delegate" destination="Nbn-Rv-sP1" id="Y0T-cI-gF1"/>
</connections>
</textField>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="NvG-0R-eTZ">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="NvG-0R-eTZ" userLabel="View - Password Tip">
<rect key="frame" x="35" y="0.0" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
@ -1443,7 +1444,7 @@ You could use the word wall for inspiration in finding a memorable master passw
</connections>
</button>
<webView opaque="NO" contentMode="scaleToFill" id="rGU-aZ-XVm">
<rect key="frame" x="0.0" y="499" width="320" height="44"/>
<rect key="frame" x="0.0" y="411" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<dataDetectorType key="dataDetectorTypes"/>
@ -1491,14 +1492,19 @@ You could use the word wall for inspiration in finding a memorable master passw
</objects>
<point key="canvasLocation" x="455" y="145"/>
</scene>
<!--Navigation Controller-->
<!--Pearl Navigation Controller-->
<scene sceneID="wrY-9D-LEc">
<objects>
<navigationController definesPresentationContext="YES" id="uu3-4d-bYN" sceneMemberID="viewController">
<navigationController definesPresentationContext="YES" id="uu3-4d-bYN" customClass="PearlNavigationController" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="T2Q-L6-b8f">
<autoresizingMask key="autoresizingMask"/>
<color key="tintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
</navigationBar>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="supportedInterfaceOrientations">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<segue destination="Q4b-t4-pwH" kind="relationship" relationship="rootViewController" id="5mm-gX-15G"/>
</connections>
@ -1512,11 +1518,11 @@ You could use the word wall for inspiration in finding a memorable master passw
<objects>
<viewController id="Q4b-t4-pwH" customClass="MPSetupViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="FnB-rI-puV">
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
<rect key="frame" x="0.0" y="64" width="320" height="416"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="RjU-5e-mti">
<rect key="frame" x="0.0" y="-64" width="320" height="568"/>
<rect key="frame" x="0.0" y="-64" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="top" image="cloud.png" id="Ahr-aa-V1N">
@ -1570,7 +1576,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<objects>
<tableViewController id="idA-Pj-1U9" customClass="MPElementListAllViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="48" sectionHeaderHeight="22" sectionFooterHeight="22" id="N83-sj-4tl">
<rect key="frame" x="0.0" y="20" width="320" height="548"/>
<rect key="frame" x="0.0" y="20" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<navigationBar key="tableHeaderView" contentMode="scaleToFill" id="l0p-Tu-L9k">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
@ -1608,33 +1614,40 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<scene sceneID="3cC-Qq-rgU">
<objects>
<viewController wantsFullScreenLayout="YES" id="2Th-Tb-22a" customClass="MPAppsViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="DHZ-5g-6vT">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<view key="view" contentMode="scaleToFill" id="AhE-Ed-ajP">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="book.png" id="wjL-OU-K7k">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="page-gorillas.png" id="QQT-37-azo">
<rect key="frame" x="0.0" y="81" width="305" height="400"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="drq-47-KK9">
<rect key="frame" x="85" y="536" width="150" height="32"/>
<view contentMode="scaleToFill" id="DHZ-5g-6vT">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal">
<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>
<action selector="exit" destination="2Th-Tb-22a" eventType="touchUpInside" id="6Ra-GC-jSG"/>
</connections>
</button>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="book.png" id="wjL-OU-K7k">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="page-gorillas.png" id="QQT-37-azo">
<rect key="frame" x="0.0" y="38" width="305" height="400"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="drq-47-KK9">
<rect key="frame" x="85" y="448" width="150" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal">
<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>
<action selector="exit" destination="2Th-Tb-22a" eventType="touchUpInside" id="6Ra-GC-jSG"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
</view>
</subviews>
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
</view>
@ -1647,10 +1660,10 @@ If you set a custom password, it will be encrypted before it is saved to the clo
</objects>
<point key="canvasLocation" x="-85" y="-495"/>
</scene>
<!--Navigation Controller-->
<!--Pearl Navigation Controller-->
<scene sceneID="8r0-wA-Zre">
<objects>
<navigationController id="KZF-fe-y9n" sceneMemberID="viewController">
<navigationController id="KZF-fe-y9n" customClass="PearlNavigationController" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="sif-x3-Fol">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
@ -1658,6 +1671,9 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<color key="tintColor" red="0.37254901960784315" green="0.39215686274509803" blue="0.42745098039215684" alpha="1" colorSpace="calibratedRGB"/>
</navigationBar>
<nil name="viewControllers"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="forwardInterfaceRotation" value="YES"/>
</userDefinedRuntimeAttributes>
<connections>
<segue destination="uu3-4d-bYN" kind="modal" identifier="MP_Setup" id="qw3-O5-NEa"/>
<segue destination="Nbn-Rv-sP1" kind="relationship" relationship="rootViewController" id="Gzv-dM-6bM"/>
@ -1673,7 +1689,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<objects>
<tableViewController id="oLN-6u-GLb" customClass="MPPreferencesViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="oSh-Ap-kLt">
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
<rect key="frame" x="0.0" y="64" width="320" height="416"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/>
<view key="tableFooterView" contentMode="scaleToFill" id="63M-7L-M7o">
@ -1797,7 +1813,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
</label>
<switch opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" id="ilG-0h-SOb">
<rect key="frame" x="221" y="8" width="79" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
<color key="onTintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
<connections>
<action selector="didToggleSwitch:" destination="oLN-6u-GLb" eventType="valueChanged" id="e5q-mf-XK7"/>
@ -1838,7 +1854,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Long" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="vKJ-1b-NeO">
<rect key="frame" x="200" y="11" width="100" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<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"/>
@ -2060,11 +2076,11 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<objects>
<viewController id="ZgN-2j-05b" customClass="MPSetupViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="QIH-dS-sqD">
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
<rect key="frame" x="0.0" y="64" width="320" height="416"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="FTf-06-1Pg">
<rect key="frame" x="0.0" y="-64" width="320" height="568"/>
<rect key="frame" x="0.0" y="-64" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Getting Started" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="FkR-cP-Y7K">
@ -2075,7 +2091,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<nil key="highlightedColor"/>
</label>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" usesAttributedText="YES" id="hwP-ds-GDh">
<rect key="frame" x="20" y="137" width="280" height="367"/>
<rect key="frame" x="20" y="137" width="280" height="279"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<attributedString key="attributedText">
@ -2187,11 +2203,11 @@ You can make passwords for anything, like email addresses, sites or real-world t
<objects>
<viewController id="myN-X7-9Tg" customClass="MPGuideViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="vkG-Oi-PHo">
<rect key="frame" x="0.0" y="20" width="320" height="548"/>
<rect key="frame" x="0.0" y="20" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" image="background.png" id="C2i-R4-36i">
<rect key="frame" x="0.0" y="44" width="320" height="504"/>
<rect key="frame" x="0.0" y="44" width="320" height="416"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<view clipsSubviews="YES" contentMode="scaleToFill" id="vSk-nT-Vwf" userLabel="View - Display">
@ -2331,7 +2347,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</scopeButtonTitles>
</searchBar>
<view alpha="0.60000000000000009" contentMode="scaleToFill" id="Ahl-o0-lMv">
<rect key="frame" x="0.0" y="0.0" width="320" height="548"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="3wI-lo-tWc">
@ -2351,7 +2367,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="UHf-cp-97W">
<rect key="frame" x="33" y="502" width="44" height="44"/>
<rect key="frame" x="33" y="414" width="44" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<accessibility key="accessibilityConfiguration" hint="" label="Close"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
@ -2367,7 +2383,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="jDS-Vh-ETL">
<rect key="frame" x="124" y="234" width="72" height="80"/>
<rect key="frame" x="124" y="190" width="72" height="80"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" hint="" label="Close"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
@ -2383,7 +2399,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="nXW-Eq-JOa">
<rect key="frame" x="243" y="502" width="44" height="44"/>
<rect key="frame" x="243" y="414" width="44" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<accessibility key="accessibilityConfiguration" hint="" label="Close"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
@ -2399,16 +2415,16 @@ You can make passwords for anything, like email addresses, sites or real-world t
</connections>
</button>
<progressView opaque="NO" contentMode="scaleToFill" id="nf7-oM-7dh">
<rect key="frame" x="85" y="519" width="150" height="9"/>
<rect key="frame" x="85" y="431" width="150" height="9"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="progressTintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
</progressView>
</subviews>
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
</view>
<view userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="nDU-uf-V0X" userLabel="View - Tool Tip">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="nDU-uf-V0X" userLabel="View - Tool Tip">
<rect key="frame" x="10" y="59" width="266" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black_bottom_right.png" id="Tmk-FU-w4D">
<rect key="frame" x="0.0" y="0.0" width="266" height="60"/>
@ -2425,7 +2441,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="cUZ-lb-h7x" userLabel="View - Search Tip">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="cUZ-lb-h7x" userLabel="View - Site Name Tip">
<rect key="frame" x="10" y="55" width="300" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
@ -2444,7 +2460,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="X0C-Qf-SMn" userLabel="View - Content Tip">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="X0C-Qf-SMn" userLabel="View - Content Tip">
<rect key="frame" x="55" y="110" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
@ -2462,7 +2478,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="w3j-Qm-9gD" userLabel="View - User Name Tip">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="w3j-Qm-9gD" userLabel="View - User Name Tip">
<rect key="frame" x="55" y="166" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
@ -2480,7 +2496,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="Pub-jz-pkR" userLabel="View - Type Tip">
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="Pub-jz-pkR" userLabel="View - Type Tip">
<rect key="frame" x="10" y="272" width="300" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
@ -2539,11 +2555,11 @@ You can make passwords for anything, like email addresses, sites or real-world t
<objects>
<viewController id="kSj-yX-DmT" customClass="MPSetupViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="sT4-Jb-e5D">
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
<rect key="frame" x="0.0" y="64" width="320" height="416"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="Eqt-R0-LTj">
<rect key="frame" x="0.0" y="-64" width="320" height="568"/>
<rect key="frame" x="0.0" y="-64" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="top" image="unlocked.png" id="4ah-P0-2DG">
@ -2764,7 +2780,6 @@ However, it means that anyone who finds your device unlocked can do the same.</s
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPSetupViewController.h"/>
<relationships>
<relationship kind="action" name="close:" candidateClass="UIBarButtonItem"/>
<relationship kind="action" name="showGuide:" candidateClass="UIBarButtonItem"/>
<relationship kind="outlet" name="cloudSwitch" candidateClass="UISwitch"/>
<relationship kind="outlet" name="rememberLoginSwitch" candidateClass="UISwitch"/>
</relationships>
@ -2802,14 +2817,17 @@ However, it means that anyone who finds your device unlocked can do the same.</s
<relationship kind="outlet" name="wordWall" candidateClass="UIView"/>
</relationships>
</class>
<class className="PearlNavigationController" superclassName="UINavigationController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/PearlNavigationController.h"/>
</class>
</classes>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<nil key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4"/>
<simulatedScreenMetrics key="destination"/>
</simulatedMetricsContainer>
<inferredMetricsTieBreakers>
<segue reference="KIl-ZW-M7G"/>
<segue reference="jgo-j3-gbW"/>
<segue reference="swi-5o-hfK"/>
<segue reference="9Bs-cD-ddF"/>
</inferredMetricsTieBreakers>
</document>

View File

@ -12,7 +12,9 @@
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */; };
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */; };
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3956915634581E737B38C /* PearlNavigationController.m */; };
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3942A356B639724157982 /* PearlOverlay.h */; };
93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; };
93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; };
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
@ -1017,8 +1019,10 @@
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>"; };
93D3956915634581E737B38C /* PearlNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlNavigationController.m; sourceTree = "<group>"; };
93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = "<group>"; };
93D39730673227EFF6DEFF19 /* MPSetupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSetupViewController.h; sourceTree = "<group>"; };
93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlNavigationController.h; sourceTree = "<group>"; };
93D39A28369954D147E239BA /* MPSetupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSetupViewController.m; sourceTree = "<group>"; };
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = "<group>"; };
93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlEMail.h; sourceTree = "<group>"; };
@ -3506,6 +3510,8 @@
DAFE4A1215039824003ABA7C /* UIImage+PearlScaling.m */,
93D390FADEB325D8D54A957D /* PearlOverlay.m */,
93D3942A356B639724157982 /* PearlOverlay.h */,
93D3956915634581E737B38C /* PearlNavigationController.m */,
93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */,
);
path = "Pearl-UIKit";
sourceTree = "<group>";
@ -3630,6 +3636,7 @@
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */,
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */,
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */,
93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -4842,6 +4849,7 @@
93D39262A8A97DB748213309 /* PearlEMail.m in Sources */,
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */,
93D3922A53E41A54832E90D9 /* PearlOverlay.m in Sources */,
93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};