2
0

Improvements to login name editing, saving/generating.

This commit is contained in:
Maarten Billemont 2014-09-16 00:34:22 -04:00
parent 88fdc89f27
commit c97546a232
7 changed files with 79 additions and 74 deletions

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit 047cab4e60a35090eb901e61d9fd76e55afff0ac
Subproject commit b63670d86d557bf37052c2c5ea0af6387731e5bb

Binary file not shown.

View File

@ -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"];

View File

@ -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<MPAlgorithm> algorithm = mainElement.algorithm?: MPAlgorithmDefault;
id<MPAlgorithm> 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];

View File

@ -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 {

View File

@ -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

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6245" systemVersion="13E28" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="Q1S-vU-GGO">
<dependencies>
<deployment defaultVersion="1792" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
<capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
@ -46,6 +47,7 @@
<string>Exo2.0-Regular</string>
<string>Exo2.0-Regular</string>
<string>Exo2.0-Regular</string>
<string>Exo2.0-Regular</string>
</mutableArray>
<mutableArray key="Exo2.0-Thin.otf">
<string>Exo2.0-Thin</string>
@ -1060,24 +1062,29 @@
<action selector="doContent:" destination="W2g-yv-V3V" eventType="touchUpInside" id="ukg-D8-8O3"/>
</connections>
</button>
<view alpha="0.69999999999999996" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="w2g-zN-1wZ" userLabel="Login Container">
<view alpha="0.59999999999999998" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="w2g-zN-1wZ" userLabel="Login Container">
<rect key="frame" x="0.0" y="0.0" width="300" height="21"/>
<subviews>
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="q3g-CJ-LbN" userLabel="Separator">
<view alpha="0.80000000000000004" contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="q3g-CJ-LbN" userLabel="Separator">
<rect key="frame" x="-1" y="20" width="300" height="1"/>
<color key="backgroundColor" red="0.14901960784313725" green="0.14901960784313725" blue="0.14901960784313725" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="jyk-dC-QLb"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Iwe-rQ-ma0" userLabel="Copy Login">
<rect key="frame" x="0.0" y="0.0" width="300" height="29"/>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="top" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Iwe-rQ-ma0" userLabel="Copy Login">
<rect key="frame" x="0.0" y="0.0" width="300" height="33"/>
<color key="backgroundColor" red="0.18431372549019609" green="0.15686274509803921" blue="0.15686274509803921" alpha="0.01" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="11"/>
<inset key="titleEdgeInsets" minX="0.0" minY="-4" maxX="0.0" maxY="0.0"/>
<state key="normal" title="Tap to generate username or use pencil to save one">
<color key="titleColor" white="1" alpha="0.35999999999999999" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="doLoginName:" destination="W2g-yv-V3V" eventType="touchUpInside" id="Ex0-re-QrI"/>
</connections>
</button>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Tap to generate username" textAlignment="center" minimumFontSize="9" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="3I9-vf-IZK" userLabel="Login">
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="center" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="3I9-vf-IZK" userLabel="Login">
<rect key="frame" x="8" y="0.0" width="284" height="20"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
@ -1102,7 +1109,7 @@
<constraint firstItem="3I9-vf-IZK" firstAttribute="leading" secondItem="w2g-zN-1wZ" secondAttribute="leading" constant="8" id="cMp-Hs-Hpl"/>
<constraint firstItem="3I9-vf-IZK" firstAttribute="top" secondItem="w2g-zN-1wZ" secondAttribute="top" id="eg4-pX-Itm"/>
<constraint firstAttribute="trailing" secondItem="3I9-vf-IZK" secondAttribute="trailing" constant="8" id="jOw-lP-CuB"/>
<constraint firstAttribute="bottom" secondItem="Iwe-rQ-ma0" secondAttribute="bottom" constant="-8" id="oyp-AJ-Nu6"/>
<constraint firstAttribute="bottom" secondItem="Iwe-rQ-ma0" secondAttribute="bottom" constant="-12" id="oyp-AJ-Nu6"/>
<constraint firstItem="Iwe-rQ-ma0" firstAttribute="top" secondItem="w2g-zN-1wZ" secondAttribute="top" id="q2j-Aa-lEd"/>
</constraints>
</view>
@ -1137,12 +1144,15 @@
<constraint firstAttribute="bottom" secondItem="wfM-xz-roR" secondAttribute="bottom" id="w1O-DM-5gJ"/>
<constraint firstItem="blw-Ou-8I8" firstAttribute="leading" secondItem="2tX-WK-ASq" secondAttribute="leading" id="x6P-h1-nhk"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="ignoreTouches" value="YES"/>
</userDefinedRuntimeAttributes>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tl3-hd-x35" userLabel="Main Container">
<rect key="frame" x="0.0" y="0.0" width="300" height="100"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.5" contentMode="left" text="apple.com - long" lineBreakMode="tailTruncation" minimumFontSize="8" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OwP-sb-Wxl" userLabel="Site Name">
<rect key="frame" x="8" y="76" width="204" height="15.5"/>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.20000000000000001" contentMode="left" text="apple.com - Long" lineBreakMode="tailTruncation" minimumFontSize="8" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OwP-sb-Wxl" userLabel="Site Name">
<rect key="frame" x="8" y="76.5" width="248" height="15.5"/>
<accessibility key="accessibilityConfiguration" label="">
<accessibilityTraits key="traits" none="YES" staticText="YES" summaryElement="YES"/>
</accessibility>
@ -1152,31 +1162,12 @@
<color key="shadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<button hidden="YES" opaque="NO" alpha="0.5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Agd-0J-z5o" userLabel="Field Mode">
<rect key="frame" x="212" y="56" width="44" height="44"/>
<accessibility key="accessibilityConfiguration" hint="Edits the password."/>
<constraints>
<constraint firstAttribute="height" constant="44" id="6Pa-21-Lwi"/>
<constraint firstAttribute="width" constant="44" id="WTe-56-pc7"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="6" minY="6" maxX="6" maxY="6"/>
<state key="normal" image="icon_person.png">
<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="selected" image="icon_key.png"/>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="Agd-0J-z5o" secondAttribute="trailing" constant="44" id="3Pc-mp-S6g"/>
<constraint firstAttribute="trailing" secondItem="OwP-sb-Wxl" secondAttribute="trailing" constant="44" id="2lS-p3-pxY"/>
<constraint firstItem="OwP-sb-Wxl" firstAttribute="leading" secondItem="tl3-hd-x35" secondAttribute="leading" constant="8" id="ec1-f1-mud"/>
<constraint firstAttribute="bottom" secondItem="OwP-sb-Wxl" secondAttribute="bottom" constant="8" id="nV5-ND-sbl"/>
<constraint firstItem="Agd-0J-z5o" firstAttribute="leading" secondItem="OwP-sb-Wxl" secondAttribute="trailing" id="wRj-23-2nN"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="ignoreTouches" value="YES"/>
@ -1344,7 +1335,6 @@
<constraint firstItem="b5f-wN-2xb" firstAttribute="centerY" secondItem="I0v-ou-hDb" secondAttribute="centerY" id="KPv-e0-uR0"/>
<constraint firstItem="LvK-28-fbm" firstAttribute="leading" secondItem="tl3-hd-x35" secondAttribute="trailing" id="NXL-Fd-whf"/>
<constraint firstItem="b5f-wN-2xb" firstAttribute="top" secondItem="tuh-Au-J9k" secondAttribute="bottom" id="SBC-kJ-Gku"/>
<constraint firstItem="b5f-wN-2xb" firstAttribute="centerY" secondItem="Agd-0J-z5o" secondAttribute="centerY" id="W01-oa-2rY"/>
<constraint firstAttribute="bottom" secondItem="LvK-28-fbm" secondAttribute="bottom" id="ZBx-Lf-XHF"/>
<constraint firstItem="b5f-wN-2xb" firstAttribute="centerY" secondItem="vGk-t6-hZn" secondAttribute="centerY" id="fGB-8g-u5b"/>
<constraint firstItem="tl3-hd-x35" firstAttribute="leading" secondItem="bff-RU-OcY" secondAttribute="leading" id="fx5-KQ-LSM"/>
@ -2381,7 +2371,6 @@ See </string>
<image name="icon_cancel.png" width="32" height="32"/>
<image name="icon_edit.png" width="32" height="32"/>
<image name="icon_gears.png" width="32" height="32"/>
<image name="icon_key.png" width="32" height="32"/>
<image name="icon_list-names.png" width="32" height="32"/>
<image name="icon_person.png" width="32" height="32"/>
<image name="icon_plus.png" width="32" height="32"/>