From c31df49599b09e37349aff0898321f5f083eb4e3 Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Wed, 17 Apr 2013 22:00:15 -0400 Subject: [PATCH] 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. --- External/Pearl | 2 +- MasterPassword/ObjC/MPAppDelegate_Key.m | 9 +- MasterPassword/ObjC/MPAppDelegate_Shared.h | 3 +- MasterPassword/ObjC/MPAppDelegate_Shared.m | 4 +- MasterPassword/ObjC/MPAppDelegate_Store.m | 8 +- MasterPassword/ObjC/iOS/MPAppDelegate.m | 12 +- .../ObjC/iOS/MPElementListAllViewController.m | 3 +- .../ObjC/iOS/MPElementListController.m | 2 +- .../ObjC/iOS/MPElementListSearchController.m | 2 +- .../ObjC/iOS/MPGuideViewController.m | 6 + .../ObjC/iOS/MPMainViewController.m | 406 +++++++++--------- .../ObjC/iOS/MPPreferencesViewController.m | 17 +- .../ObjC/iOS/MPUnlockViewController.m | 64 ++- .../ObjC/iOS/MainStoryboard_iPhone.storyboard | 186 ++++---- .../project.pbxproj | 8 + 15 files changed, 372 insertions(+), 360 deletions(-) diff --git a/External/Pearl b/External/Pearl index 0d306934..737b1980 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit 0d30693440fd520715f22789d33d5551b3b681c4 +Subproject commit 737b198043a3acb3a262a38a8b14e265801ce682 diff --git a/MasterPassword/ObjC/MPAppDelegate_Key.m b/MasterPassword/ObjC/MPAppDelegate_Key.m index 3d59b7b2..5a0594a0 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Key.m +++ b/MasterPassword/ObjC/MPAppDelegate_Key.m @@ -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 } diff --git a/MasterPassword/ObjC/MPAppDelegate_Shared.h b/MasterPassword/ObjC/MPAppDelegate_Shared.h index 53efe70b..5001fc2e 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Shared.h +++ b/MasterPassword/ObjC/MPAppDelegate_Shared.h @@ -15,11 +15,12 @@ @interface MPAppDelegate_Shared : NSObject #endif -@property (strong, nonatomic) MPUserEntity *activeUser; @property (strong, nonatomic) MPKey *key; + (instancetype)get; +- (MPUserEntity *)activeUserForThread; - (MPUserEntity *)activeUserInContext:(NSManagedObjectContext *)moc; +- (void)setActiveUser:(MPUserEntity *)activeUser; @end diff --git a/MasterPassword/ObjC/MPAppDelegate_Shared.m b/MasterPassword/ObjC/MPAppDelegate_Shared.m index b4f502e5..8a3fd5d1 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Shared.m +++ b/MasterPassword/ObjC/MPAppDelegate_Shared.m @@ -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; } diff --git a/MasterPassword/ObjC/MPAppDelegate_Store.m b/MasterPassword/ObjC/MPAppDelegate_Store.m index b341df16..a77ae4f8 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Store.m +++ b/MasterPassword/ObjC/MPAppDelegate_Store.m @@ -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 auto‑correct 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. diff --git a/MasterPassword/ObjC/iOS/MPAppDelegate.m b/MasterPassword/ObjC/iOS/MPAppDelegate.m index bcb93102..85d9131d 100644 --- a/MasterPassword/ObjC/iOS/MPAppDelegate.m +++ b/MasterPassword/ObjC/iOS/MPAppDelegate.m @@ -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 " @@ -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]; } diff --git a/MasterPassword/ObjC/iOS/MPElementListAllViewController.m b/MasterPassword/ObjC/iOS/MPElementListAllViewController.m index ea313a25..2f5f9e9a 100644 --- a/MasterPassword/ObjC/iOS/MPElementListAllViewController.m +++ b/MasterPassword/ObjC/iOS/MPElementListAllViewController.m @@ -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); }]; } diff --git a/MasterPassword/ObjC/iOS/MPElementListController.m b/MasterPassword/ObjC/iOS/MPElementListController.m index f4111c84..89767a5d 100644 --- a/MasterPassword/ObjC/iOS/MPElementListController.m +++ b/MasterPassword/ObjC/iOS/MPElementListController.m @@ -104,7 +104,7 @@ - (void)updateData { - MPUserEntity *activeUser = [MPAppDelegate get].activeUser; + MPUserEntity *activeUser = [[MPAppDelegate get] activeUserForThread]; if (!activeUser) return; diff --git a/MasterPassword/ObjC/iOS/MPElementListSearchController.m b/MasterPassword/ObjC/iOS/MPElementListSearchController.m index 95512178..5f9e94c7 100644 --- a/MasterPassword/ObjC/iOS/MPElementListSearchController.m +++ b/MasterPassword/ObjC/iOS/MPElementListSearchController.m @@ -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 { diff --git a/MasterPassword/ObjC/iOS/MPGuideViewController.m b/MasterPassword/ObjC/iOS/MPGuideViewController.m index 9350f41e..0ecd431e 100644 --- a/MasterPassword/ObjC/iOS/MPGuideViewController.m +++ b/MasterPassword/ObjC/iOS/MPGuideViewController.m @@ -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; } diff --git a/MasterPassword/ObjC/iOS/MPMainViewController.m b/MasterPassword/ObjC/iOS/MPMainViewController.m index 11bfb20c..721ffa9b 100644 --- a/MasterPassword/ObjC/iOS/MPMainViewController.m +++ b/MasterPassword/ObjC/iOS/MPMainViewController.m @@ -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; }]; } diff --git a/MasterPassword/ObjC/iOS/MPPreferencesViewController.m b/MasterPassword/ObjC/iOS/MPPreferencesViewController.m index acb1901f..7d95f142 100644 --- a/MasterPassword/ObjC/iOS/MPPreferencesViewController.m +++ b/MasterPassword/ObjC/iOS/MPPreferencesViewController.m @@ -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 diff --git a/MasterPassword/ObjC/iOS/MPUnlockViewController.m b/MasterPassword/ObjC/iOS/MPUnlockViewController.m index 243d966f..d2dcb2f3 100644 --- a/MasterPassword/ObjC/iOS/MPUnlockViewController.m +++ b/MasterPassword/ObjC/iOS/MPUnlockViewController.m @@ -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"]] @@ -316,39 +316,37 @@ - (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 diff --git a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard b/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard index 14e9bab1..56844a4a 100644 --- a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard +++ b/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard @@ -9,7 +9,7 @@ - + @@ -481,11 +481,11 @@ Your passwords will be AES-encrypted with your master password. - + - + @@ -662,9 +662,10 @@ Your passwords will be AES-encrypted with your master password. + - + @@ -706,7 +707,7 @@ Your passwords will be AES-encrypted with your master password. - + - + - + - + - + - + - - + - - +