From 32f870406cceb244041e651e722a845b6b26031b Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Thu, 1 Nov 2012 10:55:11 -0400 Subject: [PATCH] Mac UI fixes. [FIXED] Behavior of the Mac menu item and appearance of the password window. [ADDED] Disabling menu items while not usable and explaining disabled items with tooltips. --- External/Pearl | 2 +- MasterPassword-Mac.xcodeproj/project.pbxproj | 2 +- MasterPassword/Mac/MPAppDelegate.m | 85 +++++++++++-------- MasterPassword/Mac/MPMacConfig.h | 4 +- MasterPassword/Mac/MPMacConfig.m | 4 +- .../Mac/MPPasswordWindowController.m | 11 ++- MasterPassword/Mac/en.lproj/MainMenu.xib | 26 ++++-- 7 files changed, 88 insertions(+), 46 deletions(-) diff --git a/External/Pearl b/External/Pearl index 41257752..7cbc205d 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit 4125775291e209a55991743c5c1c18f7fc590e14 +Subproject commit 7cbc205dd8353c4b82ee6e8229df500cdaee0b94 diff --git a/MasterPassword-Mac.xcodeproj/project.pbxproj b/MasterPassword-Mac.xcodeproj/project.pbxproj index e1b8f22b..81da1981 100644 --- a/MasterPassword-Mac.xcodeproj/project.pbxproj +++ b/MasterPassword-Mac.xcodeproj/project.pbxproj @@ -6115,7 +6115,7 @@ DAF2369B163B24D5008AF5B5 /* MasterPassword 2.xcdatamodel */, DAF2369C163B24D5008AF5B5 /* MasterPassword 3.xcdatamodel */, ); - currentVersion = DAF2369A163B24D5008AF5B5 /* MasterPassword 1.xcdatamodel */; + currentVersion = DAF2369C163B24D5008AF5B5 /* MasterPassword 3.xcdatamodel */; path = MasterPassword.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/MasterPassword/Mac/MPAppDelegate.m b/MasterPassword/Mac/MPAppDelegate.m index cc7251b3..71a2470e 100644 --- a/MasterPassword/Mac/MPAppDelegate.m +++ b/MasterPassword/Mac/MPAppDelegate.m @@ -33,7 +33,7 @@ static EventHotKeyID MPShowHotKey = {.signature = 'show', .id = 1}; + (void)initialize { - [MPConfig get]; + [MPMacConfig get]; #ifdef DEBUG [PearlLogger get].printLevel = PearlLogLevelTrace; @@ -71,12 +71,15 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven NSManagedObjectContext *moc = [MPAppDelegate managedObjectContextIfReady]; if (!moc) { [self.createUserItem setEnabled:NO]; + self.createUserItem.toolTip = @"Please wait until the app is fully loaded."; [[self.usersItem.submenu addItemWithTitle:@"Loading..." action:NULL keyEquivalent:@""] setEnabled:NO]; return; } [self.createUserItem setEnabled:YES]; + self.createUserItem.toolTip = nil; + [moc performBlockAndWait:^{ NSArray *users = nil; NSError *error = nil; @@ -91,6 +94,9 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven [userItem setTarget:self]; [userItem setRepresentedObject:user]; [[self.usersItem submenu] addItem:userItem]; + + if ([user.name isEqualToString:[MPMacConfig get].usedUserName]) + [self selectUser:userItem]; } }]; } @@ -100,18 +106,16 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven NSAssert1([[item representedObject] isKindOfClass:[MPUserEntity class]], @"Not a user: %@", item.representedObject); self.activeUser = item.representedObject; - - [[[self.usersItem submenu] itemArray] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - [obj setState:NSOffState]; - }]; - item.state = NSOnState; } - (void)showMenu { self.rememberPasswordItem.state = [[MPConfig get].rememberLogin boolValue]? NSOnState: NSOffState; self.savePasswordItem.state = [MPAppDelegate get].activeUser.saveKey? NSOnState: NSOffState; - self.showItem.enabled = ![self.passwordWindow.window isVisible]; + if (!(self.showItem.enabled = ![self.passwordWindow.window isVisible])) + self.showItem.toolTip = @"Master Password is already showing."; + else + self.showItem.toolTip = nil; [self.statusItem popUpStatusItemMenu:self.statusMenu]; } @@ -130,8 +134,13 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven [self.storeManager useiCloudStore:sender.state == NSOffState alertUser:YES]; if (sender == rememberPasswordItem) [MPConfig get].rememberLogin = [NSNumber numberWithBool:![[MPConfig get].rememberLogin boolValue]]; - if (sender == savePasswordItem) - [MPAppDelegate get].activeUser.saveKey = ![MPAppDelegate get].activeUser.saveKey; + if (sender == savePasswordItem) { + if (([MPAppDelegate get].activeUser.saveKey = ![MPAppDelegate get].activeUser.saveKey)) + [[MPAppDelegate get] storeSavedKeyFor:[MPAppDelegate get].activeUser]; + else + [[MPAppDelegate get] forgetSavedKeyFor:[MPAppDelegate get].activeUser]; + [[MPAppDelegate get] saveContext]; + } } - (IBAction)newUser:(NSMenuItem *)sender { @@ -150,30 +159,29 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven self.savePasswordItem.state = [MPAppDelegate get].activeUser.saveKey? NSOnState: NSOffState; } -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - - if ([keyPath isEqualToString:@"key"]) { - if (self.key) - [self.lockItem setEnabled:YES]; - else { - [self.lockItem setEnabled:NO]; - [self.passwordWindow close]; - } - } -} - -- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window { - - return [[self managedObjectContextIfReady] undoManager]; -} - #pragma mark - NSApplicationDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Setup delegates and listeners. [MPConfig get].delegate = self; - [self addObserver:self forKeyPath:@"key" options:0 context:nil]; + [self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) { + if (self.key) { + [self.lockItem setEnabled:YES]; + self.lockItem.toolTip = nil; + + [self.savePasswordItem setEnabled:YES]; + self.savePasswordItem.toolTip = nil; + } else { + [self.lockItem setEnabled:NO]; + self.lockItem.toolTip = @"Master Password is currently locked."; + + [self.savePasswordItem setEnabled:NO]; + self.savePasswordItem.toolTip = @"First unlock by selecting your user and showing the Master Password window."; + + [self.passwordWindow close]; + } + } forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil]; // Initially, use iCloud. if ([[MPConfig get].firstRun boolValue]) @@ -185,7 +193,17 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven self.statusItem.highlightMode = YES; self.statusItem.target = self; self.statusItem.action = @selector(showMenu); - + + [self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) { + [[[self.usersItem submenu] itemArray] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if ([obj representedObject] && [obj representedObject] == self.activeUser) + [obj setState:NSOnState]; + else + [obj setState:NSOffState]; + }]; + + [MPMacConfig get].usedUserName = self.activeUser.name; + } forKeyPath:@"activeUser" options:0 context:nil]; [[NSNotificationCenter defaultCenter] addObserverForName:PersistentStoreDidChange object:nil queue:nil usingBlock: ^(NSNotification *note) { [self updateUsers]; @@ -217,11 +235,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven - (void)applicationDidBecomeActive:(NSNotification *)notification { - static BOOL firstTime = YES; - if (firstTime) - firstTime = NO; - else - [self.passwordWindow showWindow:self]; + [self.passwordWindow showWindow:self]; } - (void)applicationWillResignActive:(NSNotification *)notification { @@ -282,7 +296,10 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven [super ubiquityStoreManager:manager didSwitchToiCloud:iCloudEnabled]; self.useICloudItem.state = iCloudEnabled? NSOnState: NSOffState; - self.useICloudItem.enabled = !iCloudEnabled; + if (!(self.useICloudItem.enabled = !iCloudEnabled)) + self.useICloudItem.toolTip = @"iCloud is required in this version. Future versions will work without iCloud as well."; + else + self.useICloudItem.toolTip = nil; if (![[MPConfig get].iCloudDecided boolValue]) { if (iCloudEnabled) diff --git a/MasterPassword/Mac/MPMacConfig.h b/MasterPassword/Mac/MPMacConfig.h index 52fa15e7..556ae1f4 100644 --- a/MasterPassword/Mac/MPMacConfig.h +++ b/MasterPassword/Mac/MPMacConfig.h @@ -1,5 +1,5 @@ // -// MPConfig.h +// MPMacConfig.h // MasterPassword // // Created by Maarten Billemont on 02/01/12. @@ -10,6 +10,8 @@ @interface MPMacConfig : MPConfig +@property (nonatomic, retain) NSString *usedUserName; + + (MPMacConfig *)get; @end diff --git a/MasterPassword/Mac/MPMacConfig.m b/MasterPassword/Mac/MPMacConfig.m index 59bb878d..708ca2ed 100644 --- a/MasterPassword/Mac/MPMacConfig.m +++ b/MasterPassword/Mac/MPMacConfig.m @@ -1,5 +1,5 @@ // -// MPConfig.m +// MPMacConfig.m // MasterPassword // // Created by Maarten Billemont on 02/01/12. @@ -8,6 +8,8 @@ @implementation MPMacConfig +@dynamic usedUserName; + - (id)init { if (!(self = [super init])) diff --git a/MasterPassword/Mac/MPPasswordWindowController.m b/MasterPassword/Mac/MPPasswordWindowController.m index b49aeab0..8c5ed679 100644 --- a/MasterPassword/Mac/MPPasswordWindowController.m +++ b/MasterPassword/Mac/MPPasswordWindowController.m @@ -17,6 +17,8 @@ @property (nonatomic, strong) NSString *oldSiteName; @property (nonatomic, strong) NSArray /* MPElementEntity */ *siteResults; +@property (nonatomic) BOOL inProgress; + @end @@ -25,6 +27,8 @@ @synthesize siteField; @synthesize contentField; @synthesize tipField; +@synthesize inProgress = _inProgress; + - (void)windowDidLoad { @@ -33,7 +37,8 @@ [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window queue:nil usingBlock:^(NSNotification *note) { - [self unlock]; + if (!self.inProgress) + [self unlock]; [self.siteField selectText:self]; }]; [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:self.window queue:nil @@ -106,9 +111,11 @@ // "Unlock" button. self.contentContainer.alphaValue = 0; [self.progressView startAnimation:nil]; + self.inProgress = YES; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ BOOL success = [[MPAppDelegate get] signInAsUser:[MPAppDelegate get].activeUser usingMasterPassword:[(NSSecureTextField *)alert.accessoryView stringValue]]; - + self.inProgress = NO; + dispatch_async(dispatch_get_main_queue(), ^{ [self.progressView stopAnimation:nil]; diff --git a/MasterPassword/Mac/en.lproj/MainMenu.xib b/MasterPassword/Mac/en.lproj/MainMenu.xib index e9879959..28c3d045 100644 --- a/MasterPassword/Mac/en.lproj/MainMenu.xib +++ b/MasterPassword/Mac/en.lproj/MainMenu.xib @@ -74,6 +74,7 @@ + YES New User 2147483647 @@ -520,6 +521,14 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + ToolTip + + ToolTip + + Creating users is not yet supported. Please use the iOS app with iCloud enabled to create users and sites. + + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -537,6 +546,7 @@ id NSMenuItem + id NSMenuItem @@ -548,14 +558,18 @@ newUser: NSMenuItem + + signOut: + id + togglePreference: NSMenuItem + NSMenuItem NSMenuItem - NSMenuItem NSMenuItem NSMenuItem NSMenuItem @@ -564,12 +578,12 @@ NSMenuItem - - lockItem + + createUserItem NSMenuItem - - newUserItem + + lockItem NSMenuItem @@ -604,7 +618,7 @@ MPAppDelegate_Shared - NSObject + PearlAppDelegate IBProjectSource ./Classes/MPAppDelegate_Shared.h