diff --git a/External/Pearl b/External/Pearl index bde28af7..c5bf46ad 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit bde28af789996972e55a4398b7034088de14d6d8 +Subproject commit c5bf46ad1f7e6f3117a4f48a643e277705c67de3 diff --git a/MasterPassword/ObjC/MPAlgorithmV0.m b/MasterPassword/ObjC/MPAlgorithmV0.m index efa47966..97d9dd39 100644 --- a/MasterPassword/ObjC/MPAlgorithmV0.m +++ b/MasterPassword/ObjC/MPAlgorithmV0.m @@ -239,21 +239,21 @@ switch (type) { case MPElementTypeGeneratedMaximum: - return MPElementTypeStoredDevicePrivate; - case MPElementTypeGeneratedLong: - return MPElementTypeGeneratedMaximum; - case MPElementTypeGeneratedMedium: return MPElementTypeGeneratedLong; - case MPElementTypeGeneratedBasic: + case MPElementTypeGeneratedLong: return MPElementTypeGeneratedMedium; - case MPElementTypeGeneratedShort: + case MPElementTypeGeneratedMedium: return MPElementTypeGeneratedBasic; - case MPElementTypeGeneratedPIN: + case MPElementTypeGeneratedBasic: return MPElementTypeGeneratedShort; - case MPElementTypeStoredPersonal: + case MPElementTypeGeneratedShort: return MPElementTypeGeneratedPIN; - case MPElementTypeStoredDevicePrivate: + case MPElementTypeGeneratedPIN: return MPElementTypeStoredPersonal; + case MPElementTypeStoredPersonal: + return MPElementTypeStoredDevicePrivate; + case MPElementTypeStoredDevicePrivate: + return MPElementTypeGeneratedMaximum; default: return MPElementTypeGeneratedLong; } diff --git a/MasterPassword/ObjC/iOS/MPPasswordCell.m b/MasterPassword/ObjC/iOS/MPPasswordCell.m index f66f6e05..2c739ae1 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordCell.m +++ b/MasterPassword/ObjC/iOS/MPPasswordCell.m @@ -20,10 +20,6 @@ #import "MPiOSAppDelegate.h" #import "MPAppDelegate_Store.h" - -// return [[MPiOSAppDelegate get] changeElement:element saveInContext:context toType:self.type]; - - @interface MPPasswordCell() @property(nonatomic, strong) IBOutlet UILabel *siteNameLabel; @@ -35,8 +31,8 @@ @property(nonatomic, strong) IBOutlet UIButton *counterButton; @property(nonatomic, strong) IBOutlet UIButton *upgradeButton; @property(nonatomic, strong) IBOutlet UIButton *modeButton; -@property(nonatomic, strong) IBOutlet UIButton *passwordEditButton; -@property(nonatomic, strong) IBOutlet UIButton *usernameEditButton; +@property(nonatomic, strong) IBOutlet UIButton *loginModeButton; +@property(nonatomic, strong) IBOutlet UIButton *editButton; @property(nonatomic, strong) IBOutlet UIScrollView *modeScrollView; @property(nonatomic, strong) IBOutlet UIButton *selectionButton; @@ -69,23 +65,22 @@ self.pageControl.transform = CGAffineTransformMakeScale( 0.4f, 0.4f ); [self.selectionButton observeKeyPath:@"highlighted" - withBlock:^(id from, id to, NSKeyValueChange cause, UIButton *button) { + withBlock:^(id from, id to, NSKeyValueChange cause, UIButton *button) { button.layer.shadowOpacity = button.selected? 1: button.highlighted? 0.3f: 0; }]; [self.selectionButton observeKeyPath:@"selected" - withBlock:^(id from, id to, NSKeyValueChange cause, UIButton *button) { + withBlock:^(id from, id to, NSKeyValueChange cause, UIButton *button) { button.layer.shadowOpacity = button.selected? 1: button.highlighted? 0.3f: 0; }]; } -// Unblocks animations for all CALayer properties (eg. shadowOpacity) -- (id)actionForLayer:(CALayer *)layer forKey:(NSString *)event { +- (void)prepareForReuse { - id defaultAction = [super actionForLayer:layer forKey:event]; - if (defaultAction == (id)[NSNull null] && [event isEqualToString:@"position"]) - return defaultAction; + [super prepareForReuse]; - return NSNullToNil( defaultAction ); + _elementOID = nil; + self.loginModeButton.selected = NO; + [self setMode:MPPasswordCellModePassword animated:NO]; } #pragma mark - State @@ -128,7 +123,7 @@ - (void)textFieldDidEndEditing:(UITextField *)textField { - if (textField == self.passwordField) { + if (textField == self.passwordField || textField == self.loginNameField) { NSString *text = textField.text; textField.enabled = NO; @@ -154,16 +149,68 @@ #pragma mark - Actions -- (IBAction)doEditPassword:(UIButton *)sender { +- (IBAction)doLoginMode:(UIButton *)sender { - self.passwordField.enabled = YES; - [self.passwordField becomeFirstResponder]; + self.loginModeButton.selected = !self.loginModeButton.selected; + [self updateAnimated:YES]; } -- (IBAction)doEditLoginName:(UIButton *)sender { +- (IBAction)doDelete:(UIButton *)sender { - self.loginNameField.enabled = YES; - [self.loginNameField becomeFirstResponder]; + MPElementEntity *element = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]; + if (!element) + return; + + [PearlSheet showSheetWithTitle:strf( @"Delete %@?", element.name ) viewStyle:UIActionSheetStyleAutomatic + initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) { + if (buttonIndex == [sheet cancelButtonIndex]) + return; + + [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + [context deleteObject:[self elementInContext:context]]; + [context saveToStore]; + }]; + } cancelTitle:@"Cancel" destructiveTitle:@"Delete Site" otherTitles:nil]; +} + +- (IBAction)doChangeType:(UIButton *)sender { + + [self setMode:MPPasswordCellModePassword animated:YES]; + + [PearlSheet showSheetWithTitle:@"Change Password Type" viewStyle:UIActionSheetStyleAutomatic + initSheet:^(UIActionSheet *sheet) { + MPElementEntity *mainElement = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]; + for (NSNumber *typeNumber in [MPAlgorithmDefault allTypes]) { + MPElementType type = [typeNumber unsignedIntegerValue]; + NSString *typeName = [MPAlgorithmDefault nameOfType:type]; + if (type == mainElement.type) + [sheet addButtonWithTitle:strf( @"● %@", typeName )]; + else + [sheet addButtonWithTitle:typeName]; + } + } tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) { + if (buttonIndex == [sheet cancelButtonIndex]) + return; + + MPElementType type = [[MPAlgorithmDefault allTypes][buttonIndex] unsignedIntegerValue]?: MPElementTypeGeneratedLong; + + [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + MPElementEntity *element = [self elementInContext:context]; + element = [[MPiOSAppDelegate get] changeElement:element saveInContext:context toType:type]; + [self setElement:element animated:YES]; + }]; + } cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:nil]; +} + +- (IBAction)doEdit:(UIButton *)sender { + + if (self.loginModeButton.selected) { + self.loginNameField.enabled = YES; + [self.loginNameField becomeFirstResponder]; + } else if ([self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].type & MPElementTypeClassStored) { + self.passwordField.enabled = YES; + [self.passwordField becomeFirstResponder]; + } } - (IBAction)doMode:(UIButton *)sender { @@ -302,12 +349,15 @@ // UI self.selectionButton.layer.shadowOpacity = self.selectionButton.selected? 1: self.selectionButton.highlighted? 0.3f: 0; self.upgradeButton.alpha = mainElement.requiresExplicitMigration? 1: 0; - self.passwordEditButton.alpha = self.transientSite || mainElement.type & MPElementTypeClassGenerated? 0: 1; + self.passwordField.alpha = self.loginModeButton.selected? 0: 1; + self.loginNameField.alpha = self.loginModeButton.selected? 1: 0; self.modeButton.alpha = self.transientSite? 0: 1; self.counterLabel.alpha = self.counterButton.alpha = mainElement.type & MPElementTypeClassGenerated? 1: 0; self.modeButton.selected = self.mode == MPPasswordCellModeSettings; self.pageControl.currentPage = self.mode == MPPasswordCellModePassword? 0: 1; - [self.modeScrollView setContentOffset:CGPointMake( self.mode * self.modeScrollView.frame.size.width, 0 ) animated:YES]; + self.strengthLabel.alpha = self.mode == MPPasswordCellModePassword? 0: 1; + self.editButton.enabled = self.loginModeButton.selected || mainElement.type & MPElementTypeClassStored; + [self.modeScrollView setContentOffset:CGPointMake( self.mode * self.modeScrollView.frame.size.width, 0 ) animated:animated]; // Site Name self.siteNameLabel.text = strl( @"%@ - %@", self.transientSite?: mainElement.name, @@ -354,37 +404,35 @@ - (void)copyContentOfElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context { // Copy content. - switch (self.mode) { - case MPPasswordCellModePassword: { - inf( @"Copying password for: %@", element.name ); - NSString *password = [element resolveContentUsingKey:[MPAppDelegate_Shared get].key]; - if (![password length]) - return; + if (self.loginModeButton.selected) { + // Login Mode + inf( @"Copying login for: %@", element.name ); + NSString *loginName = element.loginName; + if (![loginName length]) + return; - PearlMainQueue( ^{ - [PearlOverlay showTemporaryOverlayWithTitle:strl( @"Password Copied" ) dismissAfter:2]; - [UIPasteboard generalPasteboard].string = password; - } ); + PearlMainQueue( ^{ + [PearlOverlay showTemporaryOverlayWithTitle:strl( @"Login Name Copied" ) dismissAfter:2]; + [UIPasteboard generalPasteboard].string = loginName; + } ); - [element use]; - [context saveToStore]; - break; - } - case MPPasswordCellModeSettings: { - inf( @"Copying login for: %@", element.name ); - NSString *loginName = element.loginName; - if (![loginName length]) - return; + [element use]; + [context saveToStore]; + } + else { + // Password Mode + inf( @"Copying password for: %@", element.name ); + NSString *password = [element resolveContentUsingKey:[MPAppDelegate_Shared get].key]; + if (![password length]) + return; - PearlMainQueue( ^{ - [PearlOverlay showTemporaryOverlayWithTitle:strl( @"Login Name Copied" ) dismissAfter:2]; - [UIPasteboard generalPasteboard].string = loginName; - } ); + PearlMainQueue( ^{ + [PearlOverlay showTemporaryOverlayWithTitle:strl( @"Password Copied" ) dismissAfter:2]; + [UIPasteboard generalPasteboard].string = password; + } ); - [element use]; - [context saveToStore]; - break; - } + [element use]; + [context saveToStore]; } } diff --git a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj index 672b51c1..399ada2c 100644 --- a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj +++ b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj @@ -81,6 +81,14 @@ DA250A1A195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h in Headers */ = {isa = PBXBuildFile; fileRef = DA250A16195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h */; }; DA25C5F8197AFFB40046CDCF /* icon_tools.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD384C1711E29700CF925C /* icon_tools.png */; }; DA25C5F9197AFFB40046CDCF /* icon_tools@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD384D1711E29700CF925C /* icon_tools@2x.png */; }; + DA25C5FA197CCAE00046CDCF /* icon_delete.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37541711E29500CF925C /* icon_delete.png */; }; + DA25C5FB197CCAE00046CDCF /* icon_delete@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37551711E29500CF925C /* icon_delete@2x.png */; }; + DA25C5FC197CCAF70046CDCF /* icon_list-names.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37A61711E29600CF925C /* icon_list-names.png */; }; + DA25C5FD197CCAF70046CDCF /* icon_list-names@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37A71711E29600CF925C /* icon_list-names@2x.png */; }; + DA25C5FE197DBF200046CDCF /* icon_thumbs-up.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD384A1711E29700CF925C /* icon_thumbs-up.png */; }; + DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD384B1711E29700CF925C /* icon_thumbs-up@2x.png */; }; + DA25C600197DBF260046CDCF /* icon_trash.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38501711E29700CF925C /* icon_trash.png */; }; + DA25C601197DBF260046CDCF /* icon_trash@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38511711E29700CF925C /* icon_trash@2x.png */; }; DA2CA4DD18D28859007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */; }; DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4DA18D28859007798F8 /* NSArray+Pearl.h */; }; DA2CA4DF18D28859007798F8 /* NSTimer+PearlBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4DB18D28859007798F8 /* NSTimer+PearlBlock.m */; }; @@ -3332,6 +3340,7 @@ DABD39371711E29700CF925C /* avatar-0.png in Resources */, DABD39381711E29700CF925C /* avatar-0@2x.png in Resources */, DA250A041956484D00AC23F1 /* image-7.png in Resources */, + DA25C5FC197CCAF70046CDCF /* icon_list-names.png in Resources */, DABD39391711E29700CF925C /* avatar-1.png in Resources */, DA7304E5194E025900E72520 /* tip_basic_black.png in Resources */, DABD393A1711E29700CF925C /* avatar-10.png in Resources */, @@ -3356,6 +3365,7 @@ DA250A091956484D00AC23F1 /* image-4@2x.png in Resources */, DABD39481711E29700CF925C /* avatar-17.png in Resources */, DABD39491711E29700CF925C /* avatar-17@2x.png in Resources */, + DA25C5FD197CCAF70046CDCF /* icon_list-names@2x.png in Resources */, DAC8DF47192831E100BA7D71 /* icon_key.png in Resources */, DA250A071956484D00AC23F1 /* image-5@2x.png in Resources */, DAC8DF48192831E100BA7D71 /* icon_key@2x.png in Resources */, @@ -3370,6 +3380,7 @@ DABD394F1711E29700CF925C /* avatar-3.png in Resources */, DA67460F18DE7F0C00DFE240 /* Exo2.0-ExtraBold.otf in Resources */, DABD39501711E29700CF925C /* avatar-3@2x.png in Resources */, + DA25C600197DBF260046CDCF /* icon_trash.png in Resources */, DABD39511711E29700CF925C /* avatar-4.png in Resources */, DA2509FD1956484D00AC23F1 /* image-10@2x.png in Resources */, DABD39521711E29700CF925C /* avatar-4@2x.png in Resources */, @@ -3377,6 +3388,8 @@ DA73049E194E022700E72520 /* ui_spinner@2x.png in Resources */, DABD39541711E29700CF925C /* avatar-5@2x.png in Resources */, DA250A031956484D00AC23F1 /* image-7@2x.png in Resources */, + DA25C5FA197CCAE00046CDCF /* icon_delete.png in Resources */, + DA25C601197DBF260046CDCF /* icon_trash@2x.png in Resources */, DABD39551711E29700CF925C /* avatar-6.png in Resources */, DABD39561711E29700CF925C /* avatar-6@2x.png in Resources */, DABD39571711E29700CF925C /* avatar-7.png in Resources */, @@ -3392,12 +3405,14 @@ DABD395E1711E29700CF925C /* background@2x.png in Resources */, DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */, DA250A101956484D00AC23F1 /* image-1.png in Resources */, + DA25C5FE197DBF200046CDCF /* icon_thumbs-up.png in Resources */, DABD39871711E29700CF925C /* SourceCodePro-Black.otf in Resources */, DA2509FE1956484D00AC23F1 /* image-10.png in Resources */, DABD39881711E29700CF925C /* SourceCodePro-ExtraLight.otf in Resources */, DABD39A01711E29700CF925C /* icon_action.png in Resources */, DABD39A11711E29700CF925C /* icon_action@2x.png in Resources */, DABD39F21711E29700CF925C /* icon_cancel.png in Resources */, + DA25C5FB197CCAE00046CDCF /* icon_delete@2x.png in Resources */, DA73049F194E022B00E72520 /* ui_textfield.png in Resources */, DABD39F31711E29700CF925C /* icon_cancel@2x.png in Resources */, DA250A0C1956484D00AC23F1 /* image-3.png in Resources */, @@ -3447,6 +3462,7 @@ DABD3FCE1714F45C00CF925C /* identity.png in Resources */, DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */, DA45224B190628B2008F650A /* icon_gear.png in Resources */, + DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */, DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */, DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */, DA250A021956484D00AC23F1 /* image-8.png in Resources */, diff --git a/MasterPassword/ObjC/iOS/Storyboard.storyboard b/MasterPassword/ObjC/iOS/Storyboard.storyboard index b21ebb15..7ac5ec18 100644 --- a/MasterPassword/ObjC/iOS/Storyboard.storyboard +++ b/MasterPassword/ObjC/iOS/Storyboard.storyboard @@ -1027,22 +1027,39 @@ - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + - - + + - - - - - - - - - - - + - - - - - - - + + @@ -1223,7 +1238,7 @@ - - + @@ -1254,6 +1269,7 @@ + @@ -1275,11 +1291,16 @@ + + + + + @@ -1288,8 +1309,12 @@ + + + + @@ -1309,17 +1334,17 @@ - + + - - + @@ -2495,7 +2520,9 @@ See + +