2
0

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.
This commit is contained in:
Maarten Billemont 2012-11-01 10:55:11 -04:00
parent 05ab38b998
commit 32f870406c
7 changed files with 88 additions and 46 deletions

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit 4125775291e209a55991743c5c1c18f7fc590e14 Subproject commit 7cbc205dd8353c4b82ee6e8229df500cdaee0b94

View File

@ -6115,7 +6115,7 @@
DAF2369B163B24D5008AF5B5 /* MasterPassword 2.xcdatamodel */, DAF2369B163B24D5008AF5B5 /* MasterPassword 2.xcdatamodel */,
DAF2369C163B24D5008AF5B5 /* MasterPassword 3.xcdatamodel */, DAF2369C163B24D5008AF5B5 /* MasterPassword 3.xcdatamodel */,
); );
currentVersion = DAF2369A163B24D5008AF5B5 /* MasterPassword 1.xcdatamodel */; currentVersion = DAF2369C163B24D5008AF5B5 /* MasterPassword 3.xcdatamodel */;
path = MasterPassword.xcdatamodeld; path = MasterPassword.xcdatamodeld;
sourceTree = "<group>"; sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel; versionGroupType = wrapper.xcdatamodel;

View File

@ -33,7 +33,7 @@ static EventHotKeyID MPShowHotKey = {.signature = 'show', .id = 1};
+ (void)initialize { + (void)initialize {
[MPConfig get]; [MPMacConfig get];
#ifdef DEBUG #ifdef DEBUG
[PearlLogger get].printLevel = PearlLogLevelTrace; [PearlLogger get].printLevel = PearlLogLevelTrace;
@ -71,12 +71,15 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
NSManagedObjectContext *moc = [MPAppDelegate managedObjectContextIfReady]; NSManagedObjectContext *moc = [MPAppDelegate managedObjectContextIfReady];
if (!moc) { if (!moc) {
[self.createUserItem setEnabled:NO]; [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]; [[self.usersItem.submenu addItemWithTitle:@"Loading..." action:NULL keyEquivalent:@""] setEnabled:NO];
return; return;
} }
[self.createUserItem setEnabled:YES]; [self.createUserItem setEnabled:YES];
self.createUserItem.toolTip = nil;
[moc performBlockAndWait:^{ [moc performBlockAndWait:^{
NSArray *users = nil; NSArray *users = nil;
NSError *error = nil; NSError *error = nil;
@ -91,6 +94,9 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
[userItem setTarget:self]; [userItem setTarget:self];
[userItem setRepresentedObject:user]; [userItem setRepresentedObject:user];
[[self.usersItem submenu] addItem:userItem]; [[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); NSAssert1([[item representedObject] isKindOfClass:[MPUserEntity class]], @"Not a user: %@", item.representedObject);
self.activeUser = 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 { - (void)showMenu {
self.rememberPasswordItem.state = [[MPConfig get].rememberLogin boolValue]? NSOnState: NSOffState; self.rememberPasswordItem.state = [[MPConfig get].rememberLogin boolValue]? NSOnState: NSOffState;
self.savePasswordItem.state = [MPAppDelegate get].activeUser.saveKey? 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]; [self.statusItem popUpStatusItemMenu:self.statusMenu];
} }
@ -130,8 +134,13 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
[self.storeManager useiCloudStore:sender.state == NSOffState alertUser:YES]; [self.storeManager useiCloudStore:sender.state == NSOffState alertUser:YES];
if (sender == rememberPasswordItem) if (sender == rememberPasswordItem)
[MPConfig get].rememberLogin = [NSNumber numberWithBool:![[MPConfig get].rememberLogin boolValue]]; [MPConfig get].rememberLogin = [NSNumber numberWithBool:![[MPConfig get].rememberLogin boolValue]];
if (sender == savePasswordItem) if (sender == savePasswordItem) {
[MPAppDelegate get].activeUser.saveKey = ![MPAppDelegate get].activeUser.saveKey; 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 { - (IBAction)newUser:(NSMenuItem *)sender {
@ -150,30 +159,29 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
self.savePasswordItem.state = [MPAppDelegate get].activeUser.saveKey? NSOnState: NSOffState; 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 #pragma mark - NSApplicationDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Setup delegates and listeners. // Setup delegates and listeners.
[MPConfig get].delegate = self; [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. // Initially, use iCloud.
if ([[MPConfig get].firstRun boolValue]) if ([[MPConfig get].firstRun boolValue])
@ -186,6 +194,16 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
self.statusItem.target = self; self.statusItem.target = self;
self.statusItem.action = @selector(showMenu); 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: [[NSNotificationCenter defaultCenter] addObserverForName:PersistentStoreDidChange object:nil queue:nil usingBlock:
^(NSNotification *note) { ^(NSNotification *note) {
[self updateUsers]; [self updateUsers];
@ -217,11 +235,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
- (void)applicationDidBecomeActive:(NSNotification *)notification { - (void)applicationDidBecomeActive:(NSNotification *)notification {
static BOOL firstTime = YES; [self.passwordWindow showWindow:self];
if (firstTime)
firstTime = NO;
else
[self.passwordWindow showWindow:self];
} }
- (void)applicationWillResignActive:(NSNotification *)notification { - (void)applicationWillResignActive:(NSNotification *)notification {
@ -282,7 +296,10 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
[super ubiquityStoreManager:manager didSwitchToiCloud:iCloudEnabled]; [super ubiquityStoreManager:manager didSwitchToiCloud:iCloudEnabled];
self.useICloudItem.state = iCloudEnabled? NSOnState: NSOffState; 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 (![[MPConfig get].iCloudDecided boolValue]) {
if (iCloudEnabled) if (iCloudEnabled)

View File

@ -1,5 +1,5 @@
// //
// MPConfig.h // MPMacConfig.h
// MasterPassword // MasterPassword
// //
// Created by Maarten Billemont on 02/01/12. // Created by Maarten Billemont on 02/01/12.
@ -10,6 +10,8 @@
@interface MPMacConfig : MPConfig @interface MPMacConfig : MPConfig
@property (nonatomic, retain) NSString *usedUserName;
+ (MPMacConfig *)get; + (MPMacConfig *)get;
@end @end

View File

@ -1,5 +1,5 @@
// //
// MPConfig.m // MPMacConfig.m
// MasterPassword // MasterPassword
// //
// Created by Maarten Billemont on 02/01/12. // Created by Maarten Billemont on 02/01/12.
@ -8,6 +8,8 @@
@implementation MPMacConfig @implementation MPMacConfig
@dynamic usedUserName;
- (id)init { - (id)init {
if (!(self = [super init])) if (!(self = [super init]))

View File

@ -17,6 +17,8 @@
@property (nonatomic, strong) NSString *oldSiteName; @property (nonatomic, strong) NSString *oldSiteName;
@property (nonatomic, strong) NSArray /* MPElementEntity */ *siteResults; @property (nonatomic, strong) NSArray /* MPElementEntity */ *siteResults;
@property (nonatomic) BOOL inProgress;
@end @end
@ -25,6 +27,8 @@
@synthesize siteField; @synthesize siteField;
@synthesize contentField; @synthesize contentField;
@synthesize tipField; @synthesize tipField;
@synthesize inProgress = _inProgress;
- (void)windowDidLoad { - (void)windowDidLoad {
@ -33,7 +37,8 @@
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window queue:nil [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window queue:nil
usingBlock:^(NSNotification *note) { usingBlock:^(NSNotification *note) {
[self unlock]; if (!self.inProgress)
[self unlock];
[self.siteField selectText:self]; [self.siteField selectText:self];
}]; }];
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:self.window queue:nil [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:self.window queue:nil
@ -106,8 +111,10 @@
// "Unlock" button. // "Unlock" button.
self.contentContainer.alphaValue = 0; self.contentContainer.alphaValue = 0;
[self.progressView startAnimation:nil]; [self.progressView startAnimation:nil];
self.inProgress = YES;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
BOOL success = [[MPAppDelegate get] signInAsUser:[MPAppDelegate get].activeUser usingMasterPassword:[(NSSecureTextField *)alert.accessoryView stringValue]]; BOOL success = [[MPAppDelegate get] signInAsUser:[MPAppDelegate get].activeUser usingMasterPassword:[(NSSecureTextField *)alert.accessoryView stringValue]];
self.inProgress = NO;
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self.progressView stopAnimation:nil]; [self.progressView stopAnimation:nil];

View File

@ -74,6 +74,7 @@
<array class="NSMutableArray" key="NSMenuItems"> <array class="NSMutableArray" key="NSMenuItems">
<object class="NSMenuItem" id="576787569"> <object class="NSMenuItem" id="576787569">
<reference key="NSMenu" ref="934187555"/> <reference key="NSMenu" ref="934187555"/>
<bool key="NSIsDisabled">YES</bool>
<string key="NSTitle">New User</string> <string key="NSTitle">New User</string>
<string key="NSKeyEquiv"/> <string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int> <int key="NSMnemonicLoc">2147483647</int>
@ -520,6 +521,14 @@
<string key="748.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="748.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="755.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="755.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="756.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="756.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<object class="NSMutableDictionary" key="757.IBAttributePlaceholdersKey">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="576787569"/>
<string key="toolTip">Creating users is not yet supported. Please use the iOS app with iCloud enabled to create users and sites.</string>
</object>
</object>
<string key="757.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="757.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="759.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="759.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
</dictionary> </dictionary>
@ -537,6 +546,7 @@
<dictionary class="NSMutableDictionary" key="actions"> <dictionary class="NSMutableDictionary" key="actions">
<string key="activate:">id</string> <string key="activate:">id</string>
<string key="newUser:">NSMenuItem</string> <string key="newUser:">NSMenuItem</string>
<string key="signOut:">id</string>
<string key="togglePreference:">NSMenuItem</string> <string key="togglePreference:">NSMenuItem</string>
</dictionary> </dictionary>
<dictionary class="NSMutableDictionary" key="actionInfosByName"> <dictionary class="NSMutableDictionary" key="actionInfosByName">
@ -548,14 +558,18 @@
<string key="name">newUser:</string> <string key="name">newUser:</string>
<string key="candidateClassName">NSMenuItem</string> <string key="candidateClassName">NSMenuItem</string>
</object> </object>
<object class="IBActionInfo" key="signOut:">
<string key="name">signOut:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo" key="togglePreference:"> <object class="IBActionInfo" key="togglePreference:">
<string key="name">togglePreference:</string> <string key="name">togglePreference:</string>
<string key="candidateClassName">NSMenuItem</string> <string key="candidateClassName">NSMenuItem</string>
</object> </object>
</dictionary> </dictionary>
<dictionary class="NSMutableDictionary" key="outlets"> <dictionary class="NSMutableDictionary" key="outlets">
<string key="createUserItem">NSMenuItem</string>
<string key="lockItem">NSMenuItem</string> <string key="lockItem">NSMenuItem</string>
<string key="newUserItem">NSMenuItem</string>
<string key="rememberPasswordItem">NSMenuItem</string> <string key="rememberPasswordItem">NSMenuItem</string>
<string key="savePasswordItem">NSMenuItem</string> <string key="savePasswordItem">NSMenuItem</string>
<string key="showItem">NSMenuItem</string> <string key="showItem">NSMenuItem</string>
@ -564,12 +578,12 @@
<string key="usersItem">NSMenuItem</string> <string key="usersItem">NSMenuItem</string>
</dictionary> </dictionary>
<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName"> <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
<object class="IBToOneOutletInfo" key="lockItem"> <object class="IBToOneOutletInfo" key="createUserItem">
<string key="name">lockItem</string> <string key="name">createUserItem</string>
<string key="candidateClassName">NSMenuItem</string> <string key="candidateClassName">NSMenuItem</string>
</object> </object>
<object class="IBToOneOutletInfo" key="newUserItem"> <object class="IBToOneOutletInfo" key="lockItem">
<string key="name">newUserItem</string> <string key="name">lockItem</string>
<string key="candidateClassName">NSMenuItem</string> <string key="candidateClassName">NSMenuItem</string>
</object> </object>
<object class="IBToOneOutletInfo" key="rememberPasswordItem"> <object class="IBToOneOutletInfo" key="rememberPasswordItem">
@ -604,7 +618,7 @@
</object> </object>
<object class="IBPartialClassDescription"> <object class="IBPartialClassDescription">
<string key="className">MPAppDelegate_Shared</string> <string key="className">MPAppDelegate_Shared</string>
<string key="superclassName">NSObject</string> <string key="superclassName">PearlAppDelegate</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier"> <object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string> <string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/MPAppDelegate_Shared.h</string> <string key="minorKey">./Classes/MPAppDelegate_Shared.h</string>