diff --git a/platform-darwin/External/Pearl b/platform-darwin/External/Pearl index 6f3efd7a..eee65e95 160000 --- a/platform-darwin/External/Pearl +++ b/platform-darwin/External/Pearl @@ -1 +1 @@ -Subproject commit 6f3efd7abd80019ea1945f3a2cc5a6f4bbb3ad67 +Subproject commit eee65e95220fdc1c775dbecdc795d64da1dad047 diff --git a/platform-darwin/Source/MPAlgorithmV0.m b/platform-darwin/Source/MPAlgorithmV0.m index a839d9fb..423a9760 100644 --- a/platform-darwin/Source/MPAlgorithmV0.m +++ b/platform-darwin/Source/MPAlgorithmV0.m @@ -478,10 +478,12 @@ NSOperationQueue *_mpwQueue = nil; else algorithm = site.algorithm; - dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ - resultBlock( loginName || !loginGenerated? loginName: - [algorithm generateLoginForSiteNamed:name usingKey:siteKey] ); - } ); + if (!loginGenerated || [loginName length]) + resultBlock( loginName ); + else + PearlNotMainQueue( ^{ + resultBlock( [algorithm generateLoginForSiteNamed:name usingKey:siteKey] ); + } ); } - (void)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock { @@ -513,9 +515,8 @@ NSOperationQueue *_mpwQueue = nil; else algorithm = site.algorithm; - dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ - NSString *result = [algorithm generatePasswordForSiteNamed:name ofType:type withCounter:counter usingKey:siteKey]; - resultBlock( result ); + PearlNotMainQueue( ^{ + resultBlock( [algorithm generatePasswordForSiteNamed:name ofType:type withCounter:counter usingKey:siteKey] ); } ); break; } @@ -529,9 +530,8 @@ NSOperationQueue *_mpwQueue = nil; NSData *encryptedContent = ((MPStoredSiteEntity *)site).contentObject; - dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ - NSString *result = [self decryptContent:encryptedContent usingKey:siteKey]; - resultBlock( result ); + PearlNotMainQueue( ^{ + resultBlock( [self decryptContent:encryptedContent usingKey:siteKey] ); } ); break; } @@ -543,9 +543,8 @@ NSOperationQueue *_mpwQueue = nil; NSDictionary *siteQuery = [self queryForDevicePrivateSiteNamed:site.name]; NSData *encryptedContent = [PearlKeyChain dataOfItemForQuery:siteQuery]; - dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ - NSString *result = [self decryptContent:encryptedContent usingKey:siteKey]; - resultBlock( result ); + PearlNotMainQueue( ^{ + resultBlock( [self decryptContent:encryptedContent usingKey:siteKey] ); } ); break; } @@ -564,9 +563,8 @@ NSOperationQueue *_mpwQueue = nil; else algorithm = site.algorithm; - dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ - NSString *result = [algorithm generateAnswerForSiteNamed:name onQuestion:nil usingKey:siteKey]; - resultBlock( result ); + PearlNotMainQueue( ^{ + resultBlock( [algorithm generateAnswerForSiteNamed:name onQuestion:nil usingKey:siteKey] ); } ); } @@ -585,9 +583,8 @@ NSOperationQueue *_mpwQueue = nil; else if ([[MPAppDelegate_Shared get] isFeatureUnlocked:MPProductGenerateAnswers]) algorithm = question.site.algorithm; - dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ - NSString *result = [algorithm generateAnswerForSiteNamed:name onQuestion:keyword usingKey:siteKey]; - resultBlock( result ); + PearlNotMainQueue( ^{ + resultBlock( [algorithm generateAnswerForSiteNamed:name onQuestion:keyword usingKey:siteKey] ); } ); } diff --git a/platform-darwin/Source/iOS/MPPasswordCell.m b/platform-darwin/Source/iOS/MPPasswordCell.m index c8fab60f..5bc30595 100644 --- a/platform-darwin/Source/iOS/MPPasswordCell.m +++ b/platform-darwin/Source/iOS/MPPasswordCell.m @@ -28,6 +28,7 @@ @property(nonatomic, strong) IBOutlet UITextField *passwordField; @property(nonatomic, strong) IBOutlet UIView *loginNameContainer; @property(nonatomic, strong) IBOutlet UITextField *loginNameField; +@property(nonatomic, strong) IBOutlet UILabel *loginNameGenerated; @property(nonatomic, strong) IBOutlet UILabel *strengthLabel; @property(nonatomic, strong) IBOutlet UILabel *counterLabel; @property(nonatomic, strong) IBOutlet UIButton *counterButton; @@ -199,7 +200,7 @@ atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES]; if (textField == self.loginNameField) - self.loginNameButton.titleLabel.alpha = [self.loginNameField.text length] || self.loginNameField.enabled? 0: 1; + self.loginNameButton.hidden = [self.loginNameField.attributedText length] || self.loginNameField.enabled; } - (IBAction)textFieldDidChange:(UITextField *)textField { @@ -224,7 +225,7 @@ if (textField == self.passwordField || textField == self.loginNameField) { textField.enabled = NO; - NSString *text = textField.text; + NSString *text = [textField.attributedText string]?: textField.text; [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { MPSiteEntity *site = [self siteInContext:context]; @@ -235,10 +236,8 @@ if ([site.algorithm savePassword:text toSite:site usingKey:[MPiOSAppDelegate get].key]) [PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2]; } - else if (textField == self.loginNameField && - ((site.loginGenerated && ![text length]) || - (!site.loginGenerated && ![text isEqualToString:site.loginName]))) { - if (site.loginGenerated || !([site.loginName isEqualToString:text] || (!text && !site.loginName))) { + else if (textField == self.loginNameField) { + if (![text isEqualToString:[site.algorithm resolveLoginForSite:site usingKey:[MPiOSAppDelegate get].key]]) { site.loginGenerated = NO; site.loginName = text; @@ -508,7 +507,6 @@ self.answersButton.gone = ![[MPiOSAppDelegate get] isFeatureUnlocked:MPProductGenerateAnswers]; BOOL settingsMode = self.mode == MPPasswordCellModeSettings; self.loginNameContainer.alpha = settingsMode || mainSite.loginGenerated || [mainSite.loginName length]? 0.7f: 0; - self.loginNameField.textColor = [UIColor colorWithHexString:mainSite.loginGenerated? @"5E636D": @"6D5E63"]; self.modeButton.alpha = self.transientSite? 0: settingsMode? 0.5f: 0.1f; self.counterLabel.alpha = self.counterButton.alpha = mainSite.type & MPSiteTypeClassGenerated? 0.5f: 0; self.modeButton.selected = settingsMode; @@ -520,13 +518,21 @@ [self.passwordField resignFirstResponder]; } if ([[MPiOSAppDelegate get] isFeatureUnlocked:MPProductGenerateLogins]) - [self.loginNameButton setTitle:@"Tap to generate username or use pencil to save one" forState:UIControlStateNormal]; + [self.loginNameButton setTitle:@"Tap here to ⚙ generate username or the pencil to type one" forState:UIControlStateNormal]; else - [self.loginNameButton setTitle:@"Tap the pencil to save a username" forState:UIControlStateNormal]; + [self.loginNameButton setTitle:@"Tap the pencil to type a username" forState:UIControlStateNormal]; // Site Name [self updateSiteName:mainSite]; + // Site Counter + if ([mainSite isKindOfClass:[MPGeneratedSiteEntity class]]) + self.counterLabel.text = strf( @"%lu", (unsigned long)((MPGeneratedSiteEntity *)mainSite).counter ); + + // Site Login Name + self.loginNameField.enabled = self.passwordField.enabled = // + [self.loginNameField isFirstResponder] || [self.passwordField isFirstResponder]; + // Site Password self.passwordField.secureTextEntry = [[MPiOSConfig get].hidePasswords boolValue]; self.passwordField.attributedPlaceholder = stra( @@ -534,12 +540,15 @@ mainSite.type & MPSiteTypeClassGenerated? strl( @"..." ): @"", @{ NSForegroundColorAttributeName: [UIColor whiteColor] } ); + + // Calculate Fields [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { MPSiteEntity *site = [self siteInContext:context]; MPKey *key = [MPiOSAppDelegate get].key; if (!key) return; + BOOL loginGenerated = site.loginGenerated; NSString *password = nil, *loginName = [site resolveLoginUsingKey:key]; MPSiteType transientType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPSiteTypeGeneratedLong; if (self.transientSite && transientType & MPSiteTypeClassGenerated) @@ -559,13 +568,15 @@ BOOL requiresExplicitMigration = site.requiresExplicitMigration; PearlMainQueue( ^{ - self.loginNameField.text = loginName; self.passwordField.text = password; self.strengthLabel.text = timeToCrackString; - self.loginNameButton.titleLabel.alpha = [loginName length] || self.loginNameField.enabled? 0: 1; + self.loginNameGenerated.hidden = !loginGenerated; + self.loginNameField.attributedText = + strarm( stra( loginName?: @"", self.siteNameLabel.textAttributes ), NSParagraphStyleAttributeName, nil ); + self.loginNameButton.hidden = [loginName length] || self.loginNameField.enabled; if (![password length]) { - self.indicatorView.alpha = 1; + self.indicatorView.hidden = NO; [self.indicatorView removeFromSuperview]; [self.modeScrollView addSubview:self.indicatorView]; [self.contentView addConstraintsWithVisualFormat:@"V:[indicator][target]" options:NSLayoutFormatAlignAllCenterX @@ -575,7 +586,7 @@ }]; } else if (requiresExplicitMigration) { - self.indicatorView.alpha = 1; + self.indicatorView.hidden = NO; [self.indicatorView removeFromSuperview]; [self.modeScrollView addSubview:self.indicatorView]; [self.contentView addConstraintsWithVisualFormat:@"V:[indicator][target]" options:NSLayoutFormatAlignAllCenterX @@ -585,18 +596,10 @@ }]; } else - self.indicatorView.alpha = 0; + self.indicatorView.hidden = YES; } ); }]; - // Site Counter - if ([mainSite isKindOfClass:[MPGeneratedSiteEntity class]]) - self.counterLabel.text = strf( @"%lu", (unsigned long)((MPGeneratedSiteEntity *)mainSite).counter ); - - // Site Login Name - self.loginNameField.enabled = self.passwordField.enabled = // - [self.loginNameField isFirstResponder] || [self.passwordField isFirstResponder]; - [self.contentView layoutIfNeeded]; }]; } @@ -616,8 +619,9 @@ range:NSMakeRange( s, [self.fuzzyGroups[f] length] )]; } - [attributedSiteName appendAttributedString:stra( - strf( @" - %@", self.transientSite? @"Tap to create": [site.algorithm shortNameOfType:site.type] ), @{} )]; + if (self.transientSite) + [attributedSiteName appendAttributedString:stra( @" – Tap to create", @{} )]; + self.siteNameLabel.attributedText = attributedSiteName; } diff --git a/platform-darwin/Source/iOS/MPTypeViewController.m b/platform-darwin/Source/iOS/MPTypeViewController.m index e8410bcd..017600ce 100644 --- a/platform-darwin/Source/iOS/MPTypeViewController.m +++ b/platform-darwin/Source/iOS/MPTypeViewController.m @@ -89,11 +89,11 @@ if ([selectedSite isKindOfClass:[MPGeneratedSiteEntity class]]) counter = ((MPGeneratedSiteEntity *)selectedSite).counter; - dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{ + PearlNotMainQueue( ^{ NSString *typeContent = [MPAlgorithmDefault generatePasswordForSiteNamed:name ofType:cellType withCounter:counter usingKey:[MPiOSAppDelegate get].key]; - dispatch_async( dispatch_get_main_queue(), ^{ + PearlMainQueue( ^{ [(UITextField *)[[tableView cellForRowAtIndexPath:indexPath] viewWithTag:2] setText:typeContent]; } ); } ); diff --git a/platform-darwin/Source/iOS/MPiOSAppDelegate.m b/platform-darwin/Source/iOS/MPiOSAppDelegate.m index 92df73fc..ffd80baa 100644 --- a/platform-darwin/Source/iOS/MPiOSAppDelegate.m +++ b/platform-darwin/Source/iOS/MPiOSAppDelegate.m @@ -163,26 +163,24 @@ return NO; // Arbitrary URL to mpsites data. - dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ - NSError *error; - NSURLResponse *response; - NSData *importedSitesData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] - returningResponse:&response error:&error]; - if (error) - err( @"While reading imported sites from %@: %@", url, [error fullDescription] ); - if (!importedSitesData) { - [PearlAlert showError:strf( @"Master Password couldn't read the import sites.\n\n%@", [error localizedDescription]?: error )]; - return; - } + [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler: + ^(NSData *importedSitesData, NSURLResponse *response, NSError *error) { + if (error) + err( @"While reading imported sites from %@: %@", url, [error fullDescription] ); + if (!importedSitesData) { + [PearlAlert showError:strf( @"Master Password couldn't read the import sites.\n\n%@", + [error localizedDescription]?: error )]; + return; + } - NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding]; - if (!importedSitesString) { - [PearlAlert showError:@"Master Password couldn't understand the import file."]; - return; - } + NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding]; + if (!importedSitesString) { + [PearlAlert showError:@"Master Password couldn't understand the import file."]; + return; + } - [self importSites:importedSitesString]; - } ); + [self importSites:importedSitesString]; + }] resume]; return YES; } diff --git a/platform-darwin/Source/iOS/Storyboard.storyboard b/platform-darwin/Source/iOS/Storyboard.storyboard index 5ada040b..83d19308 100644 --- a/platform-darwin/Source/iOS/Storyboard.storyboard +++ b/platform-darwin/Source/iOS/Storyboard.storyboard @@ -1,6 +1,6 @@ - + @@ -46,27 +46,27 @@ - + - + - + - + @@ -76,7 +76,7 @@ - + @@ -157,11 +157,11 @@ - + - + @@ -170,7 +170,7 @@ - + - + - + @@ -218,7 +218,7 @@ - + @@ -276,10 +276,10 @@ - + - + @@ -328,7 +328,7 @@ - + @@ -353,7 +353,7 @@ - + @@ -462,18 +462,18 @@ - + - + - + @@ -534,7 +534,7 @@ - + @@ -556,11 +556,11 @@ - + - + @@ -607,7 +607,7 @@ - + @@ -616,20 +616,20 @@ - + - + - + - + - + - + - + @@ -714,7 +714,7 @@ - + @@ -742,26 +742,26 @@ - + - + - + @@ -783,7 +783,7 @@ + - + @@ -1191,10 +1198,12 @@ + + @@ -1236,15 +1245,15 @@ - @@ -1507,6 +1516,7 @@ + @@ -1531,12 +1541,12 @@ - + - + @@ -1988,7 +1998,7 @@ eg. apple.com, rmitchell@twitter.com - + @@ -1996,10 +2006,10 @@ eg. apple.com, rmitchell@twitter.com - + - + @@ -2027,11 +2037,11 @@ eg. apple.com, rmitchell@twitter.com - + - + @@ -2043,10 +2053,10 @@ eg. apple.com, rmitchell@twitter.com - + - + @@ -2056,7 +2066,7 @@ eg. apple.com, rmitchell@twitter.com - + @@ -2085,13 +2095,13 @@ eg. apple.com, rmitchell@twitter.com