From 8805a411ba4e22a7f09f0c9804e32a95b09ee232 Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Mon, 19 May 2014 14:37:05 -0400 Subject: [PATCH] Show all when empty and fix UI updates. [FIXED] Updating UI when changing entity model. [UPDATED] Show all recent sites when query is empty. --- External/Pearl | 2 +- MasterPassword/ObjC/Mac/MPElementModel.h | 18 ++-- MasterPassword/ObjC/Mac/MPElementModel.m | 93 +++++++++++-------- .../ObjC/Mac/MPPasswordWindowController.m | 12 ++- .../ObjC/Mac/MPPasswordWindowController.xib | 30 ++++-- .../project.pbxproj | 26 +++++- 6 files changed, 114 insertions(+), 67 deletions(-) diff --git a/External/Pearl b/External/Pearl index e0be1305..a7233e2a 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit e0be1305f742b225818f4f7bf37b489c0b0b703e +Subproject commit a7233e2a01f95ae87b9586df883e8177a3e5c299 diff --git a/MasterPassword/ObjC/Mac/MPElementModel.h b/MasterPassword/ObjC/Mac/MPElementModel.h index 6c3e4c9e..09d2f982 100644 --- a/MasterPassword/ObjC/Mac/MPElementModel.h +++ b/MasterPassword/ObjC/Mac/MPElementModel.h @@ -20,16 +20,16 @@ @class MPElementEntity; @interface MPElementModel : NSObject -@property (nonatomic, readonly) NSString *site; -@property (nonatomic, readonly) MPElementType type; -@property (nonatomic, readonly) NSString *typeName; -@property (nonatomic, readonly) NSString *content; -@property (nonatomic, readonly) NSString *loginName; -@property (nonatomic, readonly) NSNumber *uses; +@property (nonatomic) NSString *site; +@property (nonatomic) MPElementType type; +@property (nonatomic) NSString *typeName; +@property (nonatomic) NSString *content; +@property (nonatomic) NSString *loginName; +@property (nonatomic) NSNumber *uses; @property (nonatomic) NSUInteger counter; -@property (nonatomic, readonly) NSDate *lastUsed; -@property (nonatomic, readonly) id algorithm; -@property (nonatomic, readonly) NSArray *types; +@property (nonatomic) NSDate *lastUsed; +@property (nonatomic) id algorithm; +@property (nonatomic) NSArray *typeNames; @property (nonatomic) NSUInteger typeIndex; - (id)initWithEntity:(MPElementEntity *)entity; diff --git a/MasterPassword/ObjC/Mac/MPElementModel.m b/MasterPassword/ObjC/Mac/MPElementModel.m index 0efb40dc..9d05ef2d 100644 --- a/MasterPassword/ObjC/Mac/MPElementModel.m +++ b/MasterPassword/ObjC/Mac/MPElementModel.m @@ -1,12 +1,12 @@ /** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ +* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) +* +* See the enclosed file LICENSE for license information (LGPLv3). If you did +* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt +* +* @author Maarten Billemont +* @license http://www.gnu.org/licenses/lgpl-3.0.txt +*/ // // MPElementModel.h @@ -23,16 +23,10 @@ #import "MPAppDelegate_Store.h" #import "MPMacAppDelegate.h" -@interface MPElementModel() - -@property(nonatomic, strong) NSManagedObjectID *entityOID; -@property(nonatomic, readwrite) NSString *content; -@property(nonatomic, readwrite) MPElementType type; -@property(nonatomic, readwrite) NSString *typeName; -@end - @implementation MPElementModel { + NSManagedObjectID *_entityOID; NSMutableDictionary *_typesByName; + BOOL _initialized; } - (id)initWithEntity:(MPElementEntity *)entity { @@ -40,27 +34,40 @@ if (!(self = [super init])) return nil; - _site = entity.name; - _lastUsed = entity.lastUsed; - _loginName = entity.loginName; - _type = entity.type; - _typeName = entity.typeName; - _uses = entity.uses_; - _counter = [entity isKindOfClass:[MPElementGeneratedEntity class]]? [(MPElementGeneratedEntity *)entity counter]: 0; - _content = [entity.algorithm resolveContentForElement:entity usingKey:[MPAppDelegate_Shared get].key]; - _algorithm = entity.algorithm; + [self setEntity:entity]; + _initialized = YES; + + return self; +} + +- (void)setEntity:(MPElementEntity *)entity { + + if ([_entityOID isEqual:entity.objectID]) + return; _entityOID = entity.objectID; + self.algorithm = entity.algorithm; + self.site = entity.name; + self.lastUsed = entity.lastUsed; + self.loginName = entity.loginName; + self.type = entity.type; + self.typeName = entity.typeName; + self.uses = entity.uses_; + self.counter = [entity isKindOfClass:[MPElementGeneratedEntity class]]? [(MPElementGeneratedEntity *)entity counter]: 0; + // Find all password types and the index of the current type amongst them. _typesByName = [NSMutableDictionary dictionary]; - MPElementType type = _type; + MPElementType type = self.type; do { - [_typesByName setObject:@(type) forKey:[_algorithm shortNameOfType:type]]; - } while (_type != (type = [_algorithm nextType:type])); - _types = [_typesByName keysSortedByValueUsingSelector:@selector(compare:)]; - _typeIndex = [[[_typesByName allValues] sortedArrayUsingSelector:@selector(compare:)] indexOfObject:@(_type)]; + [_typesByName setObject:@(type) forKey:[self.algorithm shortNameOfType:type]]; + } while (self.type != (type = [self.algorithm nextType:type])); + self.typeNames = [_typesByName keysSortedByValueUsingSelector:@selector( compare: )]; + self.typeIndex = [[[_typesByName allValues] sortedArrayUsingSelector:@selector( compare: )] indexOfObject:@(self.type)]; - return self; + [entity.algorithm resolveContentForElement:entity usingKey:[MPAppDelegate_Shared get].key + result:^(NSString *result) { + PearlMainQueue( ^{ self.content = result; } ); + }]; } - (MPElementEntity *)entityInContext:(NSManagedObjectContext *)moc { @@ -71,7 +78,7 @@ NSError *error; MPElementEntity *entity = (MPElementEntity *)[moc existingObjectWithID:_entityOID error:&error]; if (!entity) - err(@"Couldn't retrieve active element: %@", error); + err( @"Couldn't retrieve active element: %@", error ); return entity; } @@ -82,13 +89,20 @@ return; _counter = counter; + if (!_initialized) + // This wasn't a change to the entity. + return; + [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { MPElementEntity *entity = [self entityInContext:context]; if ([entity isKindOfClass:[MPElementGeneratedEntity class]]) { ((MPElementGeneratedEntity *)entity).counter = counter; [context saveToStore]; - self.content = [entity.algorithm resolveContentForElement:entity usingKey:[MPAppDelegate_Shared get].key]; + [entity.algorithm resolveContentForElement:entity usingKey:[MPAppDelegate_Shared get].key + result:^(NSString *result) { + PearlMainQueue( ^{ self.content = result; } ); + }]; } }]; } @@ -99,14 +113,13 @@ return; _typeIndex = typeIndex; - [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - MPElementEntity *entity = [self entityInContext:context]; - entity.type_ = _typesByName[_types[typeIndex]]; - [context saveToStore]; + if (!_initialized) + // This wasn't a change to the entity. + return; - self.type = entity.type; - self.typeName = entity.typeName; - self.content = [entity.algorithm resolveContentForElement:entity usingKey:[MPAppDelegate_Shared get].key]; + [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + [self setEntity:[[MPAppDelegate_Shared get] changeElement:[self entityInContext:context] saveInContext:context + toType:[_typesByName[self.typeNames[typeIndex]] unsignedIntegerValue]]]; }]; } diff --git a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m index 15cebd38..7b038757 100644 --- a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m +++ b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m @@ -55,6 +55,7 @@ // }]; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self ensureLoadedAndUnlockedOrCloseIfLoggedOut:YES]; + [self updateElements]; }]; } forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil]; [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window @@ -62,7 +63,8 @@ ^(NSNotification *note) { [self ensureLoadedAndUnlockedOrCloseIfLoggedOut:NO]; [self.siteField selectText:nil]; - }]; + [self updateElements]; + }]; [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:self.window queue:[NSOperationQueue mainQueue] usingBlock: ^(NSNotification *note) { @@ -334,17 +336,17 @@ - (void)updateElements { - NSString *query = [self.siteField.currentEditor string]; - if (![query length] || ![MPMacAppDelegate get].key) { + if (![MPMacAppDelegate get].key) { self.elements = nil; return; } + NSString *query = [self.siteField.currentEditor string]; [MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) { NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )]; fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"lastUsed" ascending:NO]]; - fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(name BEGINSWITH[cd] %@) AND user == %@", - query, [[MPMacAppDelegate get] activeUserInContext:context]]; + fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(%@ == '' OR name BEGINSWITH[cd] %@) AND user == %@", + query, query, [[MPMacAppDelegate get] activeUserInContext:context]]; NSError *error = nil; NSArray *siteResults = [context executeFetchRequest:fetchRequest error:&error]; diff --git a/MasterPassword/ObjC/Mac/MPPasswordWindowController.xib b/MasterPassword/ObjC/Mac/MPPasswordWindowController.xib index b0f4524b..193e2a08 100644 --- a/MasterPassword/ObjC/Mac/MPPasswordWindowController.xib +++ b/MasterPassword/ObjC/Mac/MPPasswordWindowController.xib @@ -1,8 +1,8 @@ - + - + @@ -19,7 +19,7 @@ - + @@ -168,7 +168,11 @@ - + + + + + @@ -184,7 +188,11 @@ - + + + + + @@ -200,7 +208,11 @@ - + + + + + @@ -241,8 +253,8 @@ - - + + @@ -365,4 +377,4 @@ - \ No newline at end of file + diff --git a/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/project.pbxproj b/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/project.pbxproj index 4c2d0df4..aaa3a35c 100644 --- a/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/project.pbxproj +++ b/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/project.pbxproj @@ -68,6 +68,9 @@ DA5E5D0C1724A667003798D8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CC61724A667003798D8 /* main.m */; }; DA5E5D0D1724A667003798D8 /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CC71724A667003798D8 /* MasterPassword.xcdatamodeld */; }; DA5E5D551724F9C8003798D8 /* MasterPassword.iconset in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5D541724F9C8003798D8 /* MasterPassword.iconset */; }; + DA8ED895192906920099B726 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8ED891192906920099B726 /* PearlTween.m */; }; + DA8ED896192906920099B726 /* PearlTween.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8ED892192906920099B726 /* PearlTween.h */; }; + DA8ED897192906920099B726 /* map-macro.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8ED894192906920099B726 /* map-macro.h */; }; DABC6C02175D8C85000C15D4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DABC6C15175D8CE1000C15D4 /* RHStatusItemView.m in Sources */ = {isa = PBXBuildFile; fileRef = DABC6C14175D8CE1000C15D4 /* RHStatusItemView.m */; }; DABC6C16175D8E3A000C15D4 /* libRHStatusItemView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DABC6C01175D8C85000C15D4 /* libRHStatusItemView.a */; }; @@ -395,6 +398,9 @@ DA6701B716406A4100B61001 /* Accounts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; }; DA6701DD16406B7300B61001 /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; }; DA672D2E14F92C6B004A189C /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + DA8ED891192906920099B726 /* PearlTween.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlTween.m; sourceTree = ""; }; + DA8ED892192906920099B726 /* PearlTween.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlTween.h; sourceTree = ""; }; + DA8ED894192906920099B726 /* map-macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "map-macro.h"; sourceTree = ""; }; DABB981515100B4000B05417 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; DABC6C01175D8C85000C15D4 /* libRHStatusItemView.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRHStatusItemView.a; sourceTree = BUILT_PRODUCTS_DIR; }; DABC6C13175D8CE1000C15D4 /* RHStatusItemView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RHStatusItemView.h; sourceTree = ""; }; @@ -790,6 +796,14 @@ path = Mac; sourceTree = ""; }; + DA8ED893192906920099B726 /* include */ = { + isa = PBXGroup; + children = ( + DA8ED894192906920099B726 /* map-macro.h */, + ); + path = include; + sourceTree = ""; + }; DABC6C0E175D8CE1000C15D4 /* RHStatusItemView */ = { isa = PBXGroup; children = ( @@ -1071,6 +1085,9 @@ DAFE45D715039823003ABA7C /* Pearl */ = { isa = PBXGroup; children = ( + DA8ED891192906920099B726 /* PearlTween.m */, + DA8ED892192906920099B726 /* PearlTween.h */, + DA8ED893192906920099B726 /* include */, DA3B8450190FC86F00246EEA /* NSManagedObject+Pearl.m */, DA3B8451190FC86F00246EEA /* NSManagedObject+Pearl.h */, DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */, @@ -1199,6 +1216,7 @@ DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */, DAEB93F518AB0FFD000490CC /* evp.h in Headers */, DAEB941918AB0FFD000490CC /* ts.h in Headers */, + DA8ED897192906920099B726 /* map-macro.h in Headers */, DAEB93F818AB0FFD000490CC /* krb5_asn.h in Headers */, DAFE4A1915039824003ABA7C /* Pearl.h in Headers */, DAEB93F318AB0FFD000490CC /* engine.h in Headers */, @@ -1211,6 +1229,7 @@ DAEB940418AB0FFD000490CC /* ossl_typ.h in Headers */, DAEB93DC18AB0FFD000490CC /* asn1t.h in Headers */, DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */, + DA8ED896192906920099B726 /* PearlTween.h in Headers */, DAEB93E518AB0FFD000490CC /* conf.h in Headers */, DAFE4A2415039824003ABA7C /* PearlInfoPlist.h in Headers */, DAEB940618AB0FFD000490CC /* pem2.h in Headers */, @@ -1668,6 +1687,7 @@ DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */, DAFE4A3915039824003ABA7C /* PearlRSAKey.m in Sources */, DAFE4A3B15039824003ABA7C /* PearlSCrypt.m in Sources */, + DA8ED895192906920099B726 /* PearlTween.m in Sources */, DA30E9CF15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m in Sources */, DA2CA4F118D323D3007798F8 /* NSTimer+PearlBlock.m in Sources */, DA3B8452190FC86F00246EEA /* NSManagedObject+Pearl.m in Sources */, @@ -2006,7 +2026,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements; - CODE_SIGN_IDENTITY = "Mac Developer: Maarten Billemont (DWGU95U4ZD)"; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2014,6 +2033,7 @@ ); GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch"; INFOPLIST_FILE = "MasterPassword-Info.plist"; + PROVISIONING_PROFILE = "77750158-06A9-41B0-B992-532E2033463E"; SKIP_INSTALL = NO; WRAPPER_NAME = "Master Password.${WRAPPER_EXTENSION}"; }; @@ -2025,7 +2045,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements; - CODE_SIGN_IDENTITY = "Developer ID Application: Maarten Billemont (HL3Q45LX9N)"; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2033,6 +2052,7 @@ ); GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch"; INFOPLIST_FILE = "MasterPassword-Info.plist"; + PROVISIONING_PROFILE = "51A082ED-2873-4B5E-9C73-A74A85EC0CBA"; SKIP_INSTALL = NO; WRAPPER_NAME = "Master Password.${WRAPPER_EXTENSION}"; }; @@ -2123,7 +2143,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements; - CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application: Maarten Billemont (HL3Q45LX9N)"; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2131,6 +2150,7 @@ ); GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch"; INFOPLIST_FILE = "MasterPassword-Info.plist"; + PROVISIONING_PROFILE = "170D83FD-18FE-4A05-B13C-8D16876480C6"; SKIP_INSTALL = NO; WRAPPER_NAME = "Master Password.${WRAPPER_EXTENSION}"; };