From 195f70db5381e10c0297714e68181e259c1a824c Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Tue, 4 Jun 2013 00:56:19 -0400 Subject: [PATCH] Menu and first-launch improvements. [ADDED] On first start, show the status item by highlighting and opening it. [UPDATED] Using RHStatusItemView for status item so we can highlight it programmatically. [FIXED] Activate app on startup so apps window shows. [ADDED] NSAlert when trying to open password window with no user selected. [UPDATED] Crisper menu icon. --- External/RHStatusItemView | 1 + MasterPassword/ObjC/MPConfig.m | 1 + MasterPassword/ObjC/Mac/MPAppsWindow.xib | 129 +----------------- MasterPassword/ObjC/Mac/MPMacAppDelegate.h | 3 +- MasterPassword/ObjC/Mac/MPMacAppDelegate.m | 31 +++-- .../ObjC/Mac/MPPasswordWindowController.m | 10 +- .../project.pbxproj | 92 +++++++++++++ MasterPassword/Resources/Media/menu-icon.png | Bin 230 -> 1157 bytes .../Resources/Media/menu-icon@2x.png | Bin 351 -> 1461 bytes 9 files changed, 129 insertions(+), 138 deletions(-) create mode 160000 External/RHStatusItemView diff --git a/External/RHStatusItemView b/External/RHStatusItemView new file mode 160000 index 00000000..eb8b21e1 --- /dev/null +++ b/External/RHStatusItemView @@ -0,0 +1 @@ +Subproject commit eb8b21e117bfa5747d67394f06df400ac4c94279 diff --git a/MasterPassword/ObjC/MPConfig.m b/MasterPassword/ObjC/MPConfig.m index 3e0cbd8c..1424d9d2 100644 --- a/MasterPassword/ObjC/MPConfig.m +++ b/MasterPassword/ObjC/MPConfig.m @@ -6,6 +6,7 @@ // Copyright (c) 2012 Lyndir. All rights reserved. // +#import "MPConfig.h" #import "MPAppDelegate_Shared.h" @implementation MPConfig diff --git a/MasterPassword/ObjC/Mac/MPAppsWindow.xib b/MasterPassword/ObjC/Mac/MPAppsWindow.xib index 4b0d19d5..5a9001f8 100644 --- a/MasterPassword/ObjC/Mac/MPAppsWindow.xib +++ b/MasterPassword/ObjC/Mac/MPAppsWindow.xib @@ -763,7 +763,7 @@ com.apple.InterfaceBuilder.CocoaPlugin {{357, 418}, {480, 270}} - + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -831,132 +831,7 @@ 337 - - - - MPAppDelegate_Shared - PearlAppDelegate - - IBProjectSource - ./Classes/MPAppDelegate_Shared.h - - - - MPMacAppDelegate - MPAppDelegate_Shared - - id - id - NSMenuItem - id - id - id - NSMenuItem - - - - iphoneAppStore: - id - - - lock: - id - - - newUser: - NSMenuItem - - - rebuildCloud: - id - - - showPasswordWindow: - id - - - terminate: - id - - - togglePreference: - NSMenuItem - - - - NSButton - NSMenuItem - NSMenuItem - NSMenuItem - NSMenuItem - NSMenuItem - NSMenuItem - NSMenuItem - NSMenu - NSMenuItem - NSMenuItem - - - - appWindowDontShow - NSButton - - - createUserItem - NSMenuItem - - - dialogStyleHUD - NSMenuItem - - - dialogStyleRegular - NSMenuItem - - - lockItem - NSMenuItem - - - rememberPasswordItem - NSMenuItem - - - savePasswordItem - NSMenuItem - - - showItem - NSMenuItem - - - statusMenu - NSMenu - - - useICloudItem - NSMenuItem - - - usersItem - NSMenuItem - - - - IBProjectSource - ./Classes/MPMacAppDelegate.h - - - - NSLayoutConstraint - NSObject - - IBProjectSource - ./Classes/NSLayoutConstraint.h - - - - + 0 IBCocoaFramework YES diff --git a/MasterPassword/ObjC/Mac/MPMacAppDelegate.h b/MasterPassword/ObjC/Mac/MPMacAppDelegate.h index 34bf5e28..4793f2b5 100644 --- a/MasterPassword/ObjC/Mac/MPMacAppDelegate.h +++ b/MasterPassword/ObjC/Mac/MPMacAppDelegate.h @@ -9,10 +9,11 @@ #import #import "MPAppDelegate_Shared.h" #import "MPPasswordWindowController.h" +#import "RHStatusItemView.h" @interface MPMacAppDelegate : MPAppDelegate_Shared -@property(nonatomic, strong) NSStatusItem *statusItem; +@property(nonatomic, strong) RHStatusItemView *statusView; @property(nonatomic, strong) MPPasswordWindowController *passwordWindow; @property(nonatomic, weak) IBOutlet NSMenuItem *lockItem; @property(nonatomic, weak) IBOutlet NSMenuItem *showItem; diff --git a/MasterPassword/ObjC/Mac/MPMacAppDelegate.m b/MasterPassword/ObjC/Mac/MPMacAppDelegate.m index 44507644..402b6ff3 100644 --- a/MasterPassword/ObjC/Mac/MPMacAppDelegate.m +++ b/MasterPassword/ObjC/Mac/MPMacAppDelegate.m @@ -121,7 +121,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven [self updateMenuItems]; - [self.statusItem popUpStatusItemMenu:self.statusMenu]; + [self.statusView popUpMenu]; } - (IBAction)togglePreference:(NSMenuItem *)sender { @@ -195,6 +195,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven - (IBAction)terminate:(id)sender { + NSLog(@"Closing: Terminating"); [self.passwordWindow close]; self.passwordWindow = nil; @@ -205,6 +206,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://itunes.apple.com/app/id510296984"]]; + NSLog(@"Closing: App Store"); [self.appWindowDontShow.window close]; self.appWindowDontShow = nil; } @@ -233,11 +235,12 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven } forKeyPath:@"storeManager.cloudAvailable" options:0 context:nil]; // Status item. - self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength]; - self.statusItem.image = [NSImage imageNamed:@"menu-icon"]; - self.statusItem.highlightMode = YES; - self.statusItem.target = self; - self.statusItem.action = @selector(showMenu); + self.statusView = [[RHStatusItemView alloc] initWithStatusBarItem: + [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength]]; + self.statusView.image = [NSImage imageNamed:@"menu-icon"]; + self.statusView.menu = self.statusMenu; + self.statusView.target = self; + self.statusView.action = @selector(showMenu); [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock: ^(NSNotification *note) { @@ -259,6 +262,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven if (![self.passwordWindow.window isVisible]) self.passwordWindow = nil; else { + NSLog(@"Closing: dialogStyleHUD && passwordWindow.isVisible"); [self.passwordWindow close]; self.passwordWindow = nil; [self showPasswordWindow:nil]; @@ -281,14 +285,20 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven if (status != noErr) err(@"Error registering 'lock' hotkey: %d", status); - // iOS App window - if ([[MPMacConfig get].showAppWindow boolValue]) { + // Initial display. + [NSApp activateIgnoringOtherApps:YES]; + if (YES || [[MPMacConfig get].showAppWindow boolValue]) { [self.appsWindow = [[NSWindowController alloc] initWithWindowNibName:@"MPAppsWindow" owner:self] showWindow:self]; [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:self.appsWindow.window queue:nil usingBlock:^(NSNotification *note) { [MPMacConfig get].showAppWindow = @(self.appWindowDontShow.state == NSOffState); }]; } + [[NSOperationQueue mainQueue] addOperation:[NSBlockOperation blockOperationWithBlock:^{ + if (YES || [[MPMacConfig get].firstRun boolValue]) { + [self showMenu]; + } + }]]; } - (void)setActiveUser:(MPUserEntity *)activeUser { @@ -296,6 +306,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven BOOL reopenPasswordWindow = [self.passwordWindow.window isVisible]; if (![[self activeUserForThread].objectID isEqual:activeUser.objectID]) { + NSLog(@"Closing: activeUser changed: %@ -> %@, reopening: %d", [self activeUserForThread].objectID, activeUser.objectID, reopenPasswordWindow); [self.passwordWindow close]; self.passwordWindow = nil; [super setActiveUser:activeUser]; @@ -375,8 +386,10 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven - (IBAction)showPasswordWindow:(id)sender { // If no user, can't activate. - if (![self activeUserForThread]) + if (YES || ![self activeUserForThread]) { + [[NSAlert alertWithMessageText:@"No User Selected" defaultButton:[PearlStrings get].commonButtonOkay alternateButton:nil otherButton:nil informativeTextWithFormat:@"Begin by selecting or creating your user from the status menu (●●●|) next to the clock.", nil] runModal]; return; + } // Activate the app if not active. if (![[NSApplication sharedApplication] isActive]) diff --git a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m index 7b9be2d1..299347af 100644 --- a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m +++ b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m @@ -30,6 +30,7 @@ - (void)windowDidLoad { + NSLog(@"DidLoad:\n%@", [NSThread callStackSymbols]); if ([[MPMacConfig get].dialogStyleHUD boolValue]) self.window.styleMask = NSHUDWindowMask | NSTitledWindowMask | NSUtilityWindowMask | NSClosableWindowMask; else @@ -55,11 +56,13 @@ } forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil]; [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window queue:nil usingBlock:^(NSNotification *note) { + NSLog(@"DidBecomeKey:\n%@", [NSThread callStackSymbols]); [self checkLoadedAndUnlocked]; [self.siteField selectText:nil]; }]; [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:self.window queue:nil usingBlock:^(NSNotification *note) { + NSLog(@"WillClose:\n%@", [NSThread callStackSymbols]); NSWindow *sheet = [self.window attachedSheet]; if (sheet) [NSApp endSheet:sheet]; @@ -87,8 +90,10 @@ MPUserEntity *activeUser = [MPMacAppDelegate get].activeUserForThread; if (activeUser && !activeUser.saveKey) [self unlock]; - else + else { + NSLog(@"Closing: !inProgress && !key && (!activeUser || activeUser.saveKey)"); [self.window close]; + } } } @@ -160,6 +165,7 @@ - (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { if (contextInfo == MPAlertIncorrectMP) { + NSLog(@"Closing: Incorrect MP, button: %ld", returnCode); [self.window close]; return; } @@ -191,6 +197,7 @@ case NSAlertOtherReturn: { // "Cancel" button. + NSLog(@"Closing: Unlock MP, button: %ld", (long)returnCode); [self.window close]; return; } @@ -288,6 +295,7 @@ - (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector { if (commandSelector == @selector(cancel:)) { // Escape without completion. + NSLog(@"Closing: ESC without completion"); [self.window close]; return YES; } diff --git a/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/project.pbxproj b/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/project.pbxproj index f392f7a1..914dc4c8 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 */; }; + 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 */; }; DAC6326D148680650075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DACA22BB1705DE7D002C6C22 /* UbiquityStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA22B71705DE7D002C6C22 /* UbiquityStoreManager.m */; }; @@ -188,6 +191,18 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + DABC6BFF175D8C85000C15D4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/${PRODUCT_NAME}"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = ""; }; 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = ""; }; @@ -275,6 +290,9 @@ 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; }; 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 = ""; }; + DABC6C14175D8CE1000C15D4 /* RHStatusItemView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RHStatusItemView.m; sourceTree = ""; }; DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; }; DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -407,6 +425,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DABC6C16175D8E3A000C15D4 /* libRHStatusItemView.a in Frameworks */, DA16B33F170661D4000A0EAB /* libUbiquityStoreManager.a in Frameworks */, DA16B341170661DB000A0EAB /* Carbon.framework in Frameworks */, DA16B342170661E0000A0EAB /* Security.framework in Frameworks */, @@ -415,6 +434,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DABC6BFE175D8C85000C15D4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DABC6C02175D8C85000C15D4 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DAC63269148680650075AEA5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -455,6 +482,7 @@ DAC6326C148680650075AEA5 /* libjrswizzle.a */, DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */, DA3EF17915A47744003ABF4E /* Tests.octest */, + DABC6C01175D8C85000C15D4 /* libRHStatusItemView.a */, ); name = Products; sourceTree = ""; @@ -563,6 +591,16 @@ path = Mac; sourceTree = ""; }; + DABC6C0E175D8CE1000C15D4 /* RHStatusItemView */ = { + isa = PBXGroup; + children = ( + DABC6C13175D8CE1000C15D4 /* RHStatusItemView.h */, + DABC6C14175D8CE1000C15D4 /* RHStatusItemView.m */, + ); + name = RHStatusItemView; + path = RHStatusItemView/RHStatusItemView; + sourceTree = ""; + }; DAC77CAF148291A600BCF976 /* Pearl */ = { isa = PBXGroup; children = ( @@ -576,6 +614,7 @@ DACA22121705DDC5002C6C22 /* External */ = { isa = PBXGroup; children = ( + DABC6C0E175D8CE1000C15D4 /* RHStatusItemView */, DACA29751705E2BD002C6C22 /* jrswizzle */, DACA22181705DE28002C6C22 /* Crashlytics.framework */, DAC77CAF148291A600BCF976 /* Pearl */, @@ -928,6 +967,23 @@ productReference = DA5BFA44147E415C00F98B1E /* Master Password.app */; productType = "com.apple.product-type.application"; }; + DABC6C00175D8C85000C15D4 /* RHStatusItemView */ = { + isa = PBXNativeTarget; + buildConfigurationList = DABC6C0A175D8C85000C15D4 /* Build configuration list for PBXNativeTarget "RHStatusItemView" */; + buildPhases = ( + DABC6BFD175D8C85000C15D4 /* Sources */, + DABC6BFE175D8C85000C15D4 /* Frameworks */, + DABC6BFF175D8C85000C15D4 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RHStatusItemView; + productName = RHStatusItemView; + productReference = DABC6C01175D8C85000C15D4 /* libRHStatusItemView.a */; + productType = "com.apple.product-type.library.static"; + }; DAC6326B148680650075AEA5 /* jrswizzle */ = { isa = PBXNativeTarget; buildConfigurationList = DAC63274148680650075AEA5 /* Build configuration list for PBXNativeTarget "jrswizzle" */; @@ -991,6 +1047,7 @@ DAC77CAC148291A600BCF976 /* Pearl */, DAC6326B148680650075AEA5 /* jrswizzle */, DA4425CA1557BED40052177D /* UbiquityStoreManager */, + DABC6C00175D8C85000C15D4 /* RHStatusItemView */, DA3EF17815A47744003ABF4E /* Tests */, ); }; @@ -1164,6 +1221,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DABC6BFD175D8C85000C15D4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DABC6C15175D8CE1000C15D4 /* RHStatusItemView.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DAC63268148680650075AEA5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1646,6 +1711,24 @@ }; name = "AppStore-Mac"; }; + DABC6C0B175D8C85000C15D4 /* Debug-Mac */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = "Debug-Mac"; + }; + DABC6C0C175D8C85000C15D4 /* AdHoc-Mac */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = "AdHoc-Mac"; + }; + DABC6C0D175D8C85000C15D4 /* AppStore-Mac */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = "AppStore-Mac"; + }; DAC63275148680650075AEA5 /* Debug-Mac */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1747,6 +1830,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "AdHoc-Mac"; }; + DABC6C0A175D8C85000C15D4 /* Build configuration list for PBXNativeTarget "RHStatusItemView" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DABC6C0B175D8C85000C15D4 /* Debug-Mac */, + DABC6C0C175D8C85000C15D4 /* AdHoc-Mac */, + DABC6C0D175D8C85000C15D4 /* AppStore-Mac */, + ); + defaultConfigurationIsVisible = 0; + }; DAC63274148680650075AEA5 /* Build configuration list for PBXNativeTarget "jrswizzle" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/MasterPassword/Resources/Media/menu-icon.png b/MasterPassword/Resources/Media/menu-icon.png index 23a5996465c17cd4eba48e6aafb308a9bcfafefc..04b579866c80aff4f1c6460177ee7d823a428078 100644 GIT binary patch literal 1157 zcmeAS@N?(olHy`uVBq!ia0vp^+CVJE!N$PAsJAav708h+ag8Vm&QB{TPb^Aha7@Wh zN>%X8O-xS>N=;0uEIgTN!@$6-k{J?F65;D(m7Jfemk3g$SCLx))Xl(PV_#8_n4Fzj zqL7rDo|$K>^nUk#C56lsTcvPQUjyF)=hTc$kE){7;3~h6MhI|Z8xE1&_n zsU?XD6}dTi#a0!zN?>!XfNYSkzLEl1NlCV?62wsvz5xo(`9-M;rh3M@$p(go3T9?{ zh9;(FW`;TnMh1pP`UXH`rfXh+i#(Mch>H3D2mX;thjEr=FDs+o0^GXscbn}XpVJ5hw7AF^F7L;V>=P7_pOiaoz zEwNPsx)kDt+yc06!V;*iRM zRQ;gT;{4L0WMIUlDTAykuyQU+O)SYT3dzsUfrVl~Mt(_taYlZDf^)E$f`)Hma%LV# zKohLP*VoE3uec;JFFDoI#a0PuhF)f7ij|R*i@Bk>iJP;DqluxRtC6L%rJ<97n}xZh zi>afjiyKU@OMY@`Zfaf$Om7NYuc-k}y`aR9TL84#CABECEH%ZgC_h&L>}jh^+-`Bf zX&zK>3Qo6}xZ>2S4|I$^C~A?S8YToxKOiPN;Q~4Eq@S7xOz%a&g#9Q_+69;?zI(bj zhE&{2`t$$4J+s+?mNSVdDLU<&3tuvDD6A3k33$7^@rJ~DuLg!gnR7$Q^bcoV=r%8vi6*&6UG+!|{Ff5MzCvT)^@J7blr`E{G zNo?n~)<<_e-p()gc%-mRVcM-<_S?Q)+`xO2QJeRJX`q{P*_Ju7dVQ=6-we03FO^A( P0u>CNu6{1-oD!M1p-DO?g8QpKh zh$UTuLN^SGnXsg1kmGDdOM_9zjyje;j?IFVxkI8o3#-jW8{Y$o0SJ5{a8XgLRsaA1 M07*qoM6N<$g1s?Sga7~l diff --git a/MasterPassword/Resources/Media/menu-icon@2x.png b/MasterPassword/Resources/Media/menu-icon@2x.png index 9561860b4ab31889a32f9e8d2de90fcab0eaaf42..a2f8f80a9a6a8fb9524faf4d97b4ec81a059e124 100644 GIT binary patch literal 1461 zcmeAS@N?(olHy`uVBq!ia0vp^VL+_I!N$PA*zuzN7?2}b;u=vBoS#-wo>-L1;Fyx1 zl&avFo0y&&l$w}QS$HzlhJk@uB{L+VB*NFnDmgz_FA=0huOhbqsGEVo#=fE;F*!T6 zL?J0PJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%C zQ%e#RDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^ z3{6bU%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE z%ggo3jrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<-In3$Ab zT4JjNbScCOxdm`z^NOLt1Pn0!io^naLp=kKmtYEgeeo;J&4sHjE(uCSxEHIz#UYgi zsro^w#rdU0$-sz9QwCX8VC7ttnpl!w6q28x0}I7~jQo=P;*9(P1?ONh1r6WC(sS486?E6f0*_Gb3|16ANb(M`J@nS0hVjOG76EHw$x1 z7gI-57dMz*m;B_?+|;}hnBEkiULz+Lb3=2mUK6Z(L5U%^0BEyIYEfocYKmJ?ey#%8 z(^i?d-C~B@EfBpaSlj~jhdEBY`as9%gQ6BGs$oLF^aEnT6E2VgPx`5O!1P`OOxQ+j z)z=vqnAAO8978H@CH?vT-=2A6LuVt4!=xm!6h38T`!(dzLjN$;&by%#m7*V&~a}mRk2R%GAIh<;%9XPgdjj zq{|(Wyf*`n_gR%q*qT1^_Od3Aw>NitJlZ|+)~1Cgsx-=UIdgCBzHw`rhi!eznTEx4 zZ#(8ii?y_e7%f<`T%qI2ItRY5cRh}^2d$oNkYLMNRK>a2^?F8inTceNRoRt|Ti6*G zZS_hYgnp|vd$@?2>^}S4S4_n delta 332 zcmV-S0ki(K3*Q2e9De}+?@v$w00AaRL_t(&-tF4G4T3-z#&IMjBqkOXR5mWa29~t6 z*4Fg&uHgdg;RbBL2#jzZ2_}YcA9_dO>%Vvs3ZCNqg`7;Q=z)z3dju9(V1We|SYUw#7Fdr#Hh(&2or_MTv-j-f)B9tu zh}97R`!>WpwWD`8^md`0pNE~!2k z>f|-8gJZG}dqvr+8>_>SmLn~&zyb>_u)qQfEU>^X!FIr|^Y7LGZ2UX8-1qJcSpJU% emH-Q^_&fm{MPWRbH9ltm0000