diff --git a/External/Pearl b/External/Pearl index 047cab4e..b63670d8 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit 047cab4e60a35090eb901e61d9fd76e55afff0ac +Subproject commit b63670d86d557bf37052c2c5ea0af6387731e5bb diff --git a/External/iOS/Reveal.framework/Versions/A/Reveal b/External/iOS/Reveal.framework/Versions/A/Reveal index 4ffdd56e..91b23296 100644 Binary files a/External/iOS/Reveal.framework/Versions/A/Reveal and b/External/iOS/Reveal.framework/Versions/A/Reveal differ diff --git a/MasterPassword/ObjC/iOS/MPAvatarCell.m b/MasterPassword/ObjC/iOS/MPAvatarCell.m index 828570e0..111b7bb8 100644 --- a/MasterPassword/ObjC/iOS/MPAvatarCell.m +++ b/MasterPassword/ObjC/iOS/MPAvatarCell.m @@ -57,11 +57,14 @@ const long MPAvatarAdd = 10000; self.avatarImageView.layer.masksToBounds = NO; self.avatarImageView.backgroundColor = [UIColor clearColor]; - [self observeKeyPath:@"selected" withBlock:^(id from, id to, NSKeyValueChange cause, id _self) { - [_self updateAnimated:self.superview != nil]; + [self observeKeyPath:@"bounds" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *_self) { + _self.contentView.frame = _self.bounds; }]; - [self observeKeyPath:@"highlighted" withBlock:^(id from, id to, NSKeyValueChange cause, id _self) { - [_self updateAnimated:self.superview != nil]; + [self observeKeyPath:@"selected" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *_self) { + [_self updateAnimated:_self.superview != nil]; + }]; + [self observeKeyPath:@"highlighted" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *_self) { + [_self updateAnimated:_self.superview != nil]; }]; CABasicAnimation *toShadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"]; diff --git a/MasterPassword/ObjC/iOS/MPPasswordCell.m b/MasterPassword/ObjC/iOS/MPPasswordCell.m index cd6f4ac1..66665822 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordCell.m +++ b/MasterPassword/ObjC/iOS/MPPasswordCell.m @@ -62,28 +62,36 @@ [self observeKeyPath:@"bounds" withBlock:^(id from, id to, NSKeyValueChange cause, id _self) { if (from && !CGSizeEqualToSize( [from CGRectValue].size, [to CGRectValue].size )) - [self setupLayer]; + [_self setupLayer]; }]; [self.contentButton observeKeyPath:@"highlighted" withBlock:^(id from, id to, NSKeyValueChange cause, UIButton *button) { - button.layer.shadowOpacity = button.selected? 0.7f: button.highlighted? 0.3f: 0; + [UIView animateWithDuration:.2f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ + button.layer.shadowOpacity = button.selected? 0.7f: button.highlighted? 0.3f: 0; + } completion:nil]; }]; [self.contentButton observeKeyPath:@"selected" withBlock:^(id from, id to, NSKeyValueChange cause, UIButton *button) { - button.layer.shadowOpacity = button.selected? 0.7f: button.highlighted? 0.3f: 0; + [UIView animateWithDuration:.2f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ + button.layer.shadowOpacity = button.selected? 0.7f: button.highlighted? 0.3f: 0; + } completion:nil]; }]; [self.loginNameButton observeKeyPath:@"highlighted" withBlock:^(id from, id to, NSKeyValueChange cause, UIButton *button) { - button.backgroundColor = [button.backgroundColor colorWithAlphaComponent: - button.selected || button.highlighted? 0.1f: 0]; - button.layer.shadowOpacity = button.selected? 0.7f: button.highlighted? 0.3f: 0; + [UIView animateWithDuration:.2f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ + button.backgroundColor = [button.backgroundColor colorWithAlphaComponent: + button.selected || button.highlighted? 0.1f: 0]; + button.layer.shadowOpacity = button.selected? 0.7f: button.highlighted? 0.3f: 0; + } completion:nil]; }]; [self.loginNameButton observeKeyPath:@"selected" withBlock:^(id from, id to, NSKeyValueChange cause, UIButton *button) { - button.backgroundColor = [button.backgroundColor colorWithAlphaComponent: - button.selected || button.highlighted? 0.1f: 0]; - button.layer.shadowOpacity = button.selected? 0.7f: button.highlighted? 0.3f: 0; + [UIView animateWithDuration:.2f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ + button.backgroundColor = [button.backgroundColor colorWithAlphaComponent: + button.selected || button.highlighted? 0.1f: 0]; + button.layer.shadowOpacity = button.selected? 0.7f: button.highlighted? 0.3f: 0; + } completion:nil]; }]; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.y"]; @@ -96,6 +104,7 @@ - (void)setupLayer { + self.contentView.frame = self.bounds; self.contentButton.layer.cornerRadius = 4; self.contentButton.layer.shadowOffset = CGSizeZero; self.contentButton.layer.shadowRadius = 5; @@ -128,6 +137,12 @@ [self updateAnimated:NO]; } +- (void)dealloc { + + [self.contentButton removeKeyPathObservers]; + [self.loginNameButton removeKeyPathObservers]; +} + #pragma mark - State - (void)setMode:(MPPasswordCellMode)mode animated:(BOOL)animated { @@ -168,11 +183,9 @@ UICollectionView *collectionView = [UICollectionView findAsSuperviewOf:self]; [collectionView scrollToItemAtIndexPath:[collectionView indexPathForCell:self] atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES]; + if (textField == self.loginNameField) - [MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) { - if (![[self elementInContext:mainContext].loginName length]) - self.loginNameField.text = nil; - }]; + self.loginNameButton.titleLabel.alpha = [self.loginNameField.text length] || self.loginNameField.enabled? 0: 1; } - (IBAction)textFieldDidChange:(UITextField *)textField { @@ -208,9 +221,15 @@ if ([element.algorithm savePassword:text toElement:element usingKey:[MPiOSAppDelegate get].key]) [PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2]; } - else if (textField == self.loginNameField && ![text isEqualToString:element.loginName]) { + else if (textField == self.loginNameField && + ((element.loginGenerated && ![text length]) || + (!element.loginGenerated && ![text isEqualToString:element.loginName]))) { element.loginName = text; - [PearlOverlay showTemporaryOverlayWithTitle:@"Login Updated" dismissAfter:2]; + element.loginGenerated = NO; + if ([text length]) + [PearlOverlay showTemporaryOverlayWithTitle:@"Login Name Saved" dismissAfter:2]; + else + [PearlOverlay showTemporaryOverlayWithTitle:@"Login Name Cleared" dismissAfter:2]; } [context saveToStore]; @@ -408,6 +427,7 @@ if (![self copyLoginOfElement:element saveInContext:context]) { element.loginGenerated = YES; [context saveToStore]; + [PearlOverlay showTemporaryOverlayWithTitle:@"Login Name Generated" dismissAfter:2]; [self updateAnimated:YES]; } @@ -445,24 +465,18 @@ // UI self.upgradeButton.alpha = mainElement.requiresExplicitMigration? 1: 0; - self.loginNameContainer.alpha = self.mode == MPPasswordCellModeSettings || - mainElement.loginGenerated || [mainElement.loginName length]? 0.7f: 0; - self.loginNameField.textColor = [UIColor colorWithHexString:[mainElement.loginName length]? @"6D5E63": @"5E636D"]; - self.modeButton.alpha = self.transientSite? 0: self.mode == MPPasswordCellModePassword? 0.1f: 0.5f; + BOOL settingsMode = self.mode == MPPasswordCellModeSettings; + self.loginNameContainer.alpha = settingsMode || mainElement.loginGenerated || [mainElement.loginName length]? 0.7f: 0; + self.loginNameField.textColor = [UIColor colorWithHexString:mainElement.loginGenerated? @"5E636D": @"6D5E63"]; + self.modeButton.alpha = self.transientSite? 0: settingsMode? 0.5f: 0.1f; self.counterLabel.alpha = self.counterButton.alpha = mainElement.type & MPElementTypeClassGenerated? 0.5f: 0; - self.modeButton.selected = self.mode == MPPasswordCellModeSettings; - self.strengthLabel.gone = self.mode == MPPasswordCellModePassword; + self.modeButton.selected = settingsMode; + self.strengthLabel.gone = !settingsMode; self.modeScrollView.scrollEnabled = !self.transientSite; [self.modeScrollView setContentOffset:CGPointMake( self.mode * self.modeScrollView.frame.size.width, 0 ) animated:animated]; - - // Indicator - switch (self.mode) { - case MPPasswordCellModePassword: - [self.loginNameField resignFirstResponder]; - [self.passwordField resignFirstResponder]; - break; - case MPPasswordCellModeSettings: - break; + if (!settingsMode) { + [self.loginNameField resignFirstResponder]; + [self.passwordField resignFirstResponder]; } // Site Name @@ -484,13 +498,14 @@ password = [MPAlgorithmDefault generatePasswordForSiteNamed:self.transientSite ofType: [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPElementTypeGeneratedLong withCounter:1 usingKey:key]; - else { + else if (element) password = [element resolvePasswordUsingKey:key]; - } + else + return; TimeToCrack timeToCrack; NSString *timeToCrackString = nil; - id algorithm = mainElement.algorithm?: MPAlgorithmDefault; + id algorithm = element.algorithm?: MPAlgorithmDefault; MPAttacker attackHardware = [[MPConfig get].siteAttacker unsignedIntegerValue]; if ([algorithm timeToCrack:&timeToCrack passwordOfType:element.type byAttacker:attackHardware] || [algorithm timeToCrack:&timeToCrack passwordString:password byAttacker:attackHardware]) @@ -500,6 +515,7 @@ self.loginNameField.text = loginName; self.passwordField.text = password; self.strengthLabel.text = timeToCrackString; + self.loginNameButton.titleLabel.alpha = [loginName length] || self.loginNameField.enabled? 0: 1; if ([password length]) self.indicatorView.alpha = 0; @@ -510,7 +526,7 @@ [self.contentView addConstraintsWithVisualFormat:@"V:[indicator][target]" options:NSLayoutFormatAlignAllCenterX metrics:nil views:@{ @"indicator" : self.indicatorView, - @"target" : self.mode == MPPasswordCellModeSettings? self.editButton: self.modeButton + @"target" : settingsMode? self.editButton: self.modeButton }]; } } ); @@ -521,9 +537,6 @@ self.counterLabel.text = strf( @"%lu", (unsigned long)((MPElementGeneratedEntity *)mainElement).counter ); // Site Login Name - self.loginNameField.attributedPlaceholder = stra( self.loginNameField.placeholder, @{ - NSForegroundColorAttributeName : [UIColor whiteColor] - } ); self.loginNameField.enabled = self.passwordField.enabled = // [self.loginNameField isFirstResponder] || [self.passwordField isFirstResponder]; diff --git a/MasterPassword/ObjC/iOS/MPPasswordsViewController.m b/MasterPassword/ObjC/iOS/MPPasswordsViewController.m index 0473d8de..4a7cf778 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordsViewController.m +++ b/MasterPassword/ObjC/iOS/MPPasswordsViewController.m @@ -356,7 +356,7 @@ referenceSizeForHeaderInSection:(NSInteger)section { if (!key || [key isEqualToString:NSStringFromSelector( @selector( dictationSearch ) )]) self.passwordsSearchBar.keyboardType = [[MPiOSConfig get].dictationSearch boolValue]? UIKeyboardTypeDefault: UIKeyboardTypeURL; if (!key || [key isEqualToString:NSStringFromSelector( @selector( hidePasswords ) )]) - [self updatePasswords]; + [self.passwordCollectionView reloadData]; } - (void)updatePasswords { diff --git a/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m b/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m index f5bfff0b..5cba92dc 100644 --- a/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m +++ b/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m @@ -26,7 +26,7 @@ if ([self class] == [MPiOSAppDelegate class]) { [PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo; #ifdef DEBUG - [PearlLogger get].printLevel = PearlLogLevelTrace; + [PearlLogger get].printLevel = PearlLogLevelDebug; //Trace; #else [PearlLogger get].printLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelDebug: PearlLogLevelInfo; #endif diff --git a/MasterPassword/ObjC/iOS/Storyboard.storyboard b/MasterPassword/ObjC/iOS/Storyboard.storyboard index cdf6f31d..0d40266a 100644 --- a/MasterPassword/ObjC/iOS/Storyboard.storyboard +++ b/MasterPassword/ObjC/iOS/Storyboard.storyboard @@ -1,6 +1,7 @@ + @@ -46,6 +47,7 @@ Exo2.0-Regular Exo2.0-Regular Exo2.0-Regular + Exo2.0-Regular Exo2.0-Thin @@ -1060,24 +1062,29 @@ - + - + - - + @@ -1102,7 +1109,7 @@ - + @@ -1137,12 +1144,15 @@ + + + - - + - @@ -1344,7 +1335,6 @@ - @@ -2381,7 +2371,6 @@ See -