2
0

Style login name, add login generated gear, improve logic for when to show login name.

This commit is contained in:
Maarten Billemont 2017-04-15 10:57:52 -04:00
parent 907d2a8ca6
commit 0a1f215a1a
6 changed files with 296 additions and 287 deletions

@ -1 +1 @@
Subproject commit 6f3efd7abd80019ea1945f3a2cc5a6f4bbb3ad67 Subproject commit eee65e95220fdc1c775dbecdc795d64da1dad047

View File

@ -478,9 +478,11 @@ NSOperationQueue *_mpwQueue = nil;
else else
algorithm = site.algorithm; algorithm = site.algorithm;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ if (!loginGenerated || [loginName length])
resultBlock( loginName || !loginGenerated? loginName: resultBlock( loginName );
[algorithm generateLoginForSiteNamed:name usingKey:siteKey] ); else
PearlNotMainQueue( ^{
resultBlock( [algorithm generateLoginForSiteNamed:name usingKey:siteKey] );
} ); } );
} }
@ -513,9 +515,8 @@ NSOperationQueue *_mpwQueue = nil;
else else
algorithm = site.algorithm; algorithm = site.algorithm;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ PearlNotMainQueue( ^{
NSString *result = [algorithm generatePasswordForSiteNamed:name ofType:type withCounter:counter usingKey:siteKey]; resultBlock( [algorithm generatePasswordForSiteNamed:name ofType:type withCounter:counter usingKey:siteKey] );
resultBlock( result );
} ); } );
break; break;
} }
@ -529,9 +530,8 @@ NSOperationQueue *_mpwQueue = nil;
NSData *encryptedContent = ((MPStoredSiteEntity *)site).contentObject; NSData *encryptedContent = ((MPStoredSiteEntity *)site).contentObject;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ PearlNotMainQueue( ^{
NSString *result = [self decryptContent:encryptedContent usingKey:siteKey]; resultBlock( [self decryptContent:encryptedContent usingKey:siteKey] );
resultBlock( result );
} ); } );
break; break;
} }
@ -543,9 +543,8 @@ NSOperationQueue *_mpwQueue = nil;
NSDictionary *siteQuery = [self queryForDevicePrivateSiteNamed:site.name]; NSDictionary *siteQuery = [self queryForDevicePrivateSiteNamed:site.name];
NSData *encryptedContent = [PearlKeyChain dataOfItemForQuery:siteQuery]; NSData *encryptedContent = [PearlKeyChain dataOfItemForQuery:siteQuery];
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ PearlNotMainQueue( ^{
NSString *result = [self decryptContent:encryptedContent usingKey:siteKey]; resultBlock( [self decryptContent:encryptedContent usingKey:siteKey] );
resultBlock( result );
} ); } );
break; break;
} }
@ -564,9 +563,8 @@ NSOperationQueue *_mpwQueue = nil;
else else
algorithm = site.algorithm; algorithm = site.algorithm;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ PearlNotMainQueue( ^{
NSString *result = [algorithm generateAnswerForSiteNamed:name onQuestion:nil usingKey:siteKey]; resultBlock( [algorithm generateAnswerForSiteNamed:name onQuestion:nil usingKey:siteKey] );
resultBlock( result );
} ); } );
} }
@ -585,9 +583,8 @@ NSOperationQueue *_mpwQueue = nil;
else if ([[MPAppDelegate_Shared get] isFeatureUnlocked:MPProductGenerateAnswers]) else if ([[MPAppDelegate_Shared get] isFeatureUnlocked:MPProductGenerateAnswers])
algorithm = question.site.algorithm; algorithm = question.site.algorithm;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ PearlNotMainQueue( ^{
NSString *result = [algorithm generateAnswerForSiteNamed:name onQuestion:keyword usingKey:siteKey]; resultBlock( [algorithm generateAnswerForSiteNamed:name onQuestion:keyword usingKey:siteKey] );
resultBlock( result );
} ); } );
} }

View File

@ -28,6 +28,7 @@
@property(nonatomic, strong) IBOutlet UITextField *passwordField; @property(nonatomic, strong) IBOutlet UITextField *passwordField;
@property(nonatomic, strong) IBOutlet UIView *loginNameContainer; @property(nonatomic, strong) IBOutlet UIView *loginNameContainer;
@property(nonatomic, strong) IBOutlet UITextField *loginNameField; @property(nonatomic, strong) IBOutlet UITextField *loginNameField;
@property(nonatomic, strong) IBOutlet UILabel *loginNameGenerated;
@property(nonatomic, strong) IBOutlet UILabel *strengthLabel; @property(nonatomic, strong) IBOutlet UILabel *strengthLabel;
@property(nonatomic, strong) IBOutlet UILabel *counterLabel; @property(nonatomic, strong) IBOutlet UILabel *counterLabel;
@property(nonatomic, strong) IBOutlet UIButton *counterButton; @property(nonatomic, strong) IBOutlet UIButton *counterButton;
@ -199,7 +200,7 @@
atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES]; atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
if (textField == self.loginNameField) 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 { - (IBAction)textFieldDidChange:(UITextField *)textField {
@ -224,7 +225,7 @@
if (textField == self.passwordField || textField == self.loginNameField) { if (textField == self.passwordField || textField == self.loginNameField) {
textField.enabled = NO; textField.enabled = NO;
NSString *text = textField.text; NSString *text = [textField.attributedText string]?: textField.text;
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPSiteEntity *site = [self siteInContext:context]; MPSiteEntity *site = [self siteInContext:context];
@ -235,10 +236,8 @@
if ([site.algorithm savePassword:text toSite:site usingKey:[MPiOSAppDelegate get].key]) if ([site.algorithm savePassword:text toSite:site usingKey:[MPiOSAppDelegate get].key])
[PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2]; [PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2];
} }
else if (textField == self.loginNameField && else if (textField == self.loginNameField) {
((site.loginGenerated && ![text length]) || if (![text isEqualToString:[site.algorithm resolveLoginForSite:site usingKey:[MPiOSAppDelegate get].key]]) {
(!site.loginGenerated && ![text isEqualToString:site.loginName]))) {
if (site.loginGenerated || !([site.loginName isEqualToString:text] || (!text && !site.loginName))) {
site.loginGenerated = NO; site.loginGenerated = NO;
site.loginName = text; site.loginName = text;
@ -508,7 +507,6 @@
self.answersButton.gone = ![[MPiOSAppDelegate get] isFeatureUnlocked:MPProductGenerateAnswers]; self.answersButton.gone = ![[MPiOSAppDelegate get] isFeatureUnlocked:MPProductGenerateAnswers];
BOOL settingsMode = self.mode == MPPasswordCellModeSettings; BOOL settingsMode = self.mode == MPPasswordCellModeSettings;
self.loginNameContainer.alpha = settingsMode || mainSite.loginGenerated || [mainSite.loginName length]? 0.7f: 0; 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.modeButton.alpha = self.transientSite? 0: settingsMode? 0.5f: 0.1f;
self.counterLabel.alpha = self.counterButton.alpha = mainSite.type & MPSiteTypeClassGenerated? 0.5f: 0; self.counterLabel.alpha = self.counterButton.alpha = mainSite.type & MPSiteTypeClassGenerated? 0.5f: 0;
self.modeButton.selected = settingsMode; self.modeButton.selected = settingsMode;
@ -520,13 +518,21 @@
[self.passwordField resignFirstResponder]; [self.passwordField resignFirstResponder];
} }
if ([[MPiOSAppDelegate get] isFeatureUnlocked:MPProductGenerateLogins]) 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 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 // Site Name
[self updateSiteName:mainSite]; [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 // Site Password
self.passwordField.secureTextEntry = [[MPiOSConfig get].hidePasswords boolValue]; self.passwordField.secureTextEntry = [[MPiOSConfig get].hidePasswords boolValue];
self.passwordField.attributedPlaceholder = stra( self.passwordField.attributedPlaceholder = stra(
@ -534,12 +540,15 @@
mainSite.type & MPSiteTypeClassGenerated? strl( @"..." ): @"", @{ mainSite.type & MPSiteTypeClassGenerated? strl( @"..." ): @"", @{
NSForegroundColorAttributeName: [UIColor whiteColor] NSForegroundColorAttributeName: [UIColor whiteColor]
} ); } );
// Calculate Fields
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPSiteEntity *site = [self siteInContext:context]; MPSiteEntity *site = [self siteInContext:context];
MPKey *key = [MPiOSAppDelegate get].key; MPKey *key = [MPiOSAppDelegate get].key;
if (!key) if (!key)
return; return;
BOOL loginGenerated = site.loginGenerated;
NSString *password = nil, *loginName = [site resolveLoginUsingKey:key]; NSString *password = nil, *loginName = [site resolveLoginUsingKey:key];
MPSiteType transientType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPSiteTypeGeneratedLong; MPSiteType transientType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPSiteTypeGeneratedLong;
if (self.transientSite && transientType & MPSiteTypeClassGenerated) if (self.transientSite && transientType & MPSiteTypeClassGenerated)
@ -559,13 +568,15 @@
BOOL requiresExplicitMigration = site.requiresExplicitMigration; BOOL requiresExplicitMigration = site.requiresExplicitMigration;
PearlMainQueue( ^{ PearlMainQueue( ^{
self.loginNameField.text = loginName;
self.passwordField.text = password; self.passwordField.text = password;
self.strengthLabel.text = timeToCrackString; 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]) { if (![password length]) {
self.indicatorView.alpha = 1; self.indicatorView.hidden = NO;
[self.indicatorView removeFromSuperview]; [self.indicatorView removeFromSuperview];
[self.modeScrollView addSubview:self.indicatorView]; [self.modeScrollView addSubview:self.indicatorView];
[self.contentView addConstraintsWithVisualFormat:@"V:[indicator][target]" options:NSLayoutFormatAlignAllCenterX [self.contentView addConstraintsWithVisualFormat:@"V:[indicator][target]" options:NSLayoutFormatAlignAllCenterX
@ -575,7 +586,7 @@
}]; }];
} }
else if (requiresExplicitMigration) { else if (requiresExplicitMigration) {
self.indicatorView.alpha = 1; self.indicatorView.hidden = NO;
[self.indicatorView removeFromSuperview]; [self.indicatorView removeFromSuperview];
[self.modeScrollView addSubview:self.indicatorView]; [self.modeScrollView addSubview:self.indicatorView];
[self.contentView addConstraintsWithVisualFormat:@"V:[indicator][target]" options:NSLayoutFormatAlignAllCenterX [self.contentView addConstraintsWithVisualFormat:@"V:[indicator][target]" options:NSLayoutFormatAlignAllCenterX
@ -585,18 +596,10 @@
}]; }];
} }
else 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]; [self.contentView layoutIfNeeded];
}]; }];
} }
@ -616,8 +619,9 @@
range:NSMakeRange( s, [self.fuzzyGroups[f] length] )]; range:NSMakeRange( s, [self.fuzzyGroups[f] length] )];
} }
[attributedSiteName appendAttributedString:stra( if (self.transientSite)
strf( @" - %@", self.transientSite? @"Tap to create": [site.algorithm shortNameOfType:site.type] ), @{} )]; [attributedSiteName appendAttributedString:stra( @" Tap to create", @{} )];
self.siteNameLabel.attributedText = attributedSiteName; self.siteNameLabel.attributedText = attributedSiteName;
} }

View File

@ -89,11 +89,11 @@
if ([selectedSite isKindOfClass:[MPGeneratedSiteEntity class]]) if ([selectedSite isKindOfClass:[MPGeneratedSiteEntity class]])
counter = ((MPGeneratedSiteEntity *)selectedSite).counter; counter = ((MPGeneratedSiteEntity *)selectedSite).counter;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{ PearlNotMainQueue( ^{
NSString *typeContent = [MPAlgorithmDefault generatePasswordForSiteNamed:name ofType:cellType NSString *typeContent = [MPAlgorithmDefault generatePasswordForSiteNamed:name ofType:cellType
withCounter:counter usingKey:[MPiOSAppDelegate get].key]; withCounter:counter usingKey:[MPiOSAppDelegate get].key];
dispatch_async( dispatch_get_main_queue(), ^{ PearlMainQueue( ^{
[(UITextField *)[[tableView cellForRowAtIndexPath:indexPath] viewWithTag:2] setText:typeContent]; [(UITextField *)[[tableView cellForRowAtIndexPath:indexPath] viewWithTag:2] setText:typeContent];
} ); } );
} ); } );

View File

@ -163,15 +163,13 @@
return NO; return NO;
// Arbitrary URL to mpsites data. // Arbitrary URL to mpsites data.
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:
NSError *error; ^(NSData *importedSitesData, NSURLResponse *response, NSError *error) {
NSURLResponse *response;
NSData *importedSitesData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url]
returningResponse:&response error:&error];
if (error) if (error)
err( @"While reading imported sites from %@: %@", url, [error fullDescription] ); err( @"While reading imported sites from %@: %@", url, [error fullDescription] );
if (!importedSitesData) { if (!importedSitesData) {
[PearlAlert showError:strf( @"Master Password couldn't read the import sites.\n\n%@", [error localizedDescription]?: error )]; [PearlAlert showError:strf( @"Master Password couldn't read the import sites.\n\n%@",
[error localizedDescription]?: error )];
return; return;
} }
@ -182,7 +180,7 @@
} }
[self importSites:importedSitesString]; [self importSites:importedSitesString];
} ); }] resume];
return YES; return YES;
} }

File diff suppressed because it is too large Load Diff