UI improvements to the Mac app.
This commit is contained in:
parent
651a398798
commit
6422084fa0
2
External/Pearl
vendored
2
External/Pearl
vendored
@ -1 +1 @@
|
|||||||
Subproject commit e50cad1411aaafe8083b3863e48b53a1f722c239
|
Subproject commit a3f33c5f0cbafd6910ae55fb313764c18b48ad69
|
@ -26,7 +26,7 @@
|
|||||||
@property(nonatomic, strong) NSWindowController *initialWindow;
|
@property(nonatomic, strong) NSWindowController *initialWindow;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MPMacAppDelegate { NSWindow *_window; }
|
@implementation MPMacAppDelegate
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wfour-char-constants"
|
#pragma clang diagnostic ignored "-Wfour-char-constants"
|
||||||
@ -66,71 +66,157 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
return eventNotHandledErr;
|
return eventNotHandledErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateUsers {
|
#pragma mark - Life
|
||||||
|
|
||||||
[[[self.usersItem submenu] itemArray] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||||
if (idx > 2)
|
|
||||||
[[self.usersItem submenu] removeItem:obj];
|
// Setup delegates and listeners.
|
||||||
|
[MPConfig get].delegate = self;
|
||||||
|
__weak id weakSelf = self;
|
||||||
|
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
||||||
|
dispatch_async( dispatch_get_main_queue(), ^{
|
||||||
|
[weakSelf updateMenuItems];
|
||||||
|
} );
|
||||||
|
} forKeyPath:@"key" options:0 context:nil];
|
||||||
|
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
||||||
|
dispatch_async( dispatch_get_main_queue(), ^{
|
||||||
|
[weakSelf updateMenuItems];
|
||||||
|
} );
|
||||||
|
} forKeyPath:@"activeUser" options:0 context:nil];
|
||||||
|
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
||||||
|
dispatch_async( dispatch_get_main_queue(), ^{
|
||||||
|
[weakSelf updateMenuItems];
|
||||||
|
} );
|
||||||
|
} forKeyPath:@"storeManager.cloudAvailable" options:0 context:nil];
|
||||||
|
|
||||||
|
// Status item.
|
||||||
|
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:[NSOperationQueue mainQueue] usingBlock:
|
||||||
|
^(NSNotification *note) {
|
||||||
|
[self updateUsers];
|
||||||
}];
|
}];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidImportChangesNotification object:nil
|
||||||
|
queue:[NSOperationQueue mainQueue] usingBlock:
|
||||||
|
^(NSNotification *note) {
|
||||||
|
[self updateUsers];
|
||||||
|
}];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserverForName:MPCheckConfigNotification object:nil
|
||||||
|
queue:[NSOperationQueue mainQueue] usingBlock:
|
||||||
|
^(NSNotification *note) {
|
||||||
|
NSString *key = note.object;
|
||||||
|
if (!key || [key isEqualToString:NSStringFromSelector( @selector( rememberLogin ) )])
|
||||||
|
self.rememberPasswordItem.state = [[MPConfig get].rememberLogin boolValue]? NSOnState: NSOffState;
|
||||||
|
if (!key || [key isEqualToString:NSStringFromSelector( @selector( dialogStyleHUD ) )]) {
|
||||||
|
self.dialogStyleRegular.state = ![[MPMacConfig get].dialogStyleHUD boolValue]? NSOnState: NSOffState;
|
||||||
|
self.dialogStyleHUD.state = [[MPMacConfig get].dialogStyleHUD boolValue]? NSOnState: NSOffState;
|
||||||
|
if (![self.passwordWindow.window isVisible])
|
||||||
|
self.passwordWindow = nil;
|
||||||
|
else {
|
||||||
|
[self.passwordWindow close];
|
||||||
|
self.passwordWindow = nil;
|
||||||
|
[self showPasswordWindow:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
[self updateUsers];
|
||||||
|
|
||||||
|
// Global hotkey.
|
||||||
|
EventHotKeyRef hotKeyRef;
|
||||||
|
EventTypeSpec hotKeyEvents[1] = { { .eventClass = kEventClassKeyboard, .eventKind = kEventHotKeyPressed } };
|
||||||
|
OSStatus status = InstallApplicationEventHandler( NewEventHandlerUPP( MPHotKeyHander ), GetEventTypeCount( hotKeyEvents ),
|
||||||
|
hotKeyEvents, (__bridge void *)self, NULL );
|
||||||
|
if (status != noErr)
|
||||||
|
err( @"Error installing application event handler: %i", (int)status );
|
||||||
|
status = RegisterEventHotKey( 35 /* p */, controlKey + cmdKey, MPShowHotKey, GetApplicationEventTarget(), 0, &hotKeyRef );
|
||||||
|
if (status != noErr)
|
||||||
|
err( @"Error registering 'show' hotkey: %i", (int)status );
|
||||||
|
status = RegisterEventHotKey( 35 /* p */, controlKey + optionKey + cmdKey, MPLockHotKey, GetApplicationEventTarget(), 0, &hotKeyRef );
|
||||||
|
if (status != noErr)
|
||||||
|
err( @"Error registering 'lock' hotkey: %i", (int)status );
|
||||||
|
|
||||||
|
// Initial display.
|
||||||
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
|
if ([[MPMacConfig get].firstRun boolValue]) {
|
||||||
|
self.initialWindow = [[NSWindowController alloc] initWithWindowNibName:@"MPInitialWindow" owner:self];
|
||||||
|
[self.initialWindow.window setLevel:NSFloatingWindowLevel];
|
||||||
|
[self.initialWindow showWindow:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillResignActive:(NSNotification *)notification {
|
||||||
|
|
||||||
|
if (![[MPConfig get].rememberLogin boolValue])
|
||||||
|
[self lock:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
|
||||||
|
// Save changes in the application's managed object context before the application terminates.
|
||||||
|
|
||||||
NSManagedObjectContext *context = [MPMacAppDelegate managedObjectContextForMainThreadIfReady];
|
NSManagedObjectContext *context = [MPMacAppDelegate managedObjectContextForMainThreadIfReady];
|
||||||
if (!context) {
|
if (!context)
|
||||||
self.createUserItem.title = @"New User (Not ready)";
|
return NSTerminateNow;
|
||||||
self.createUserItem.enabled = NO;
|
|
||||||
self.createUserItem.toolTip = @"Please wait until the app is fully loaded.";
|
|
||||||
self.deleteUserItem.title = @"Delete User (Not ready)";
|
|
||||||
self.deleteUserItem.enabled = NO;
|
|
||||||
self.deleteUserItem.toolTip = @"Please wait until the app is fully loaded.";
|
|
||||||
[self.usersItem.submenu addItemWithTitle:@"Loading..." action:NULL keyEquivalent:@""].enabled = NO;
|
|
||||||
|
|
||||||
return;
|
if (![context commitEditing])
|
||||||
|
return NSTerminateCancel;
|
||||||
|
|
||||||
|
if (![context hasChanges])
|
||||||
|
return NSTerminateNow;
|
||||||
|
|
||||||
|
[context saveToStore];
|
||||||
|
return NSTerminateNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
MPUserEntity *activeUser = [self activeUserInContext:context];
|
#pragma mark - State
|
||||||
|
|
||||||
self.createUserItem.title = @"New User";
|
- (void)setActiveUser:(MPUserEntity *)activeUser {
|
||||||
self.createUserItem.enabled = YES;
|
|
||||||
self.createUserItem.toolTip = nil;
|
|
||||||
|
|
||||||
self.deleteUserItem.title = activeUser? @"Delete User": @"Delete User (None Selected)";
|
[super setActiveUser:activeUser];
|
||||||
self.deleteUserItem.enabled = activeUser != nil;
|
|
||||||
self.deleteUserItem.toolTip = activeUser? nil: @"First select the user to delete.";
|
|
||||||
|
|
||||||
NSError *error = nil;
|
[MPMacConfig get].usedUserName = activeUser.name;
|
||||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
|
|
||||||
fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO] ];
|
|
||||||
NSArray *users = [context executeFetchRequest:fetchRequest error:&error];
|
|
||||||
if (!users)
|
|
||||||
err( @"Failed to load users: %@", error );
|
|
||||||
|
|
||||||
if (![users count]) {
|
PearlMainQueue( ^{
|
||||||
NSMenuItem *noUsersItem = [self.usersItem.submenu addItemWithTitle:@"No users" action:NULL keyEquivalent:@""];
|
[self updateUsers];
|
||||||
noUsersItem.enabled = NO;
|
} );
|
||||||
noUsersItem.toolTip = @"Use the iOS app to create users and make sure iCloud is enabled in its preferences as well. "
|
|
||||||
@"Then give iCloud some time to sync the new user to your Mac.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.usersItem.state = NSMixedState;
|
- (void)setLoginItemEnabled:(BOOL)enabled {
|
||||||
for (MPUserEntity *user in users) {
|
|
||||||
NSMenuItem *userItem = [[NSMenuItem alloc] initWithTitle:user.name action:@selector( selectUser: ) keyEquivalent:@""];
|
|
||||||
[userItem setTarget:self];
|
|
||||||
[userItem setRepresentedObject:[user objectID]];
|
|
||||||
[[self.usersItem submenu] addItem:userItem];
|
|
||||||
|
|
||||||
if (!activeUser && [user.name isEqualToString:[MPMacConfig get].usedUserName])
|
BOOL loginItemEnabled = [self loginItemEnabled];
|
||||||
[super setActiveUser:activeUser = user];
|
if (loginItemEnabled != enabled) {
|
||||||
|
if (SMLoginItemSetEnabled( (__bridge CFStringRef)LOGIN_HELPER_BUNDLE_ID, (Boolean)enabled ) == true)
|
||||||
if ([activeUser isEqual:user]) {
|
loginItemEnabled = enabled;
|
||||||
userItem.state = NSOnState;
|
|
||||||
self.usersItem.state = NSOffState;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
userItem.state = NSOffState;
|
wrn( @"Failed to set login item." );
|
||||||
}
|
}
|
||||||
|
|
||||||
[self updateMenuItems];
|
self.openAtLoginItem.state = loginItemEnabled? NSOnState: NSOffState;
|
||||||
|
self.openAtLoginButton.state = loginItemEnabled? NSOnState: NSOffState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)loginItemEnabled {
|
||||||
|
|
||||||
|
// The easy and sane method (SMJobCopyDictionary) can pose problems when the app is sandboxed. -_-
|
||||||
|
NSArray *jobs = (__bridge_transfer NSArray *)SMCopyAllJobDictionaries( kSMDomainUserLaunchd );
|
||||||
|
|
||||||
|
for (NSDictionary *job in jobs)
|
||||||
|
if ([LOGIN_HELPER_BUNDLE_ID isEqualToString:[job objectForKey:@"Label"]]) {
|
||||||
|
dbg( @"loginItemEnabled: %@", @([[job objectForKey:@"OnDemand"] boolValue]) );
|
||||||
|
return [[job objectForKey:@"OnDemand"] boolValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg( @"loginItemEnabled: not found" );
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Actions
|
||||||
|
|
||||||
- (void)selectUser:(NSMenuItem *)item {
|
- (void)selectUser:(NSMenuItem *)item {
|
||||||
|
|
||||||
[self signOutAnimated:NO];
|
[self signOutAnimated:NO];
|
||||||
@ -143,13 +229,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
err( @"While looking up selected user: %@", error );
|
err( @"While looking up selected user: %@", error );
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showMenu {
|
|
||||||
|
|
||||||
[self updateMenuItems];
|
|
||||||
|
|
||||||
[self.statusView popUpMenu];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (IBAction)togglePreference:(id)sender {
|
- (IBAction)togglePreference:(id)sender {
|
||||||
|
|
||||||
if (sender == self.enableCloudButton) {
|
if (sender == self.enableCloudButton) {
|
||||||
@ -278,104 +357,99 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
self.initialWindow = nil;
|
self.initialWindow = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)oldValue {
|
- (IBAction)showPasswordWindow:(id)sender {
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:NSStringFromSelector( configKey )];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSApplicationDelegate
|
|
||||||
|
|
||||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
|
||||||
|
|
||||||
// Setup delegates and listeners.
|
|
||||||
[MPConfig get].delegate = self;
|
|
||||||
__weak id weakSelf = self;
|
|
||||||
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
|
||||||
dispatch_async( dispatch_get_main_queue(), ^{
|
|
||||||
[weakSelf updateMenuItems];
|
|
||||||
} );
|
|
||||||
} forKeyPath:@"key" options:0 context:nil];
|
|
||||||
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
|
||||||
dispatch_async( dispatch_get_main_queue(), ^{
|
|
||||||
[weakSelf updateMenuItems];
|
|
||||||
} );
|
|
||||||
} forKeyPath:@"activeUser" options:0 context:nil];
|
|
||||||
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
|
||||||
dispatch_async( dispatch_get_main_queue(), ^{
|
|
||||||
[weakSelf updateMenuItems];
|
|
||||||
} );
|
|
||||||
} forKeyPath:@"storeManager.cloudAvailable" options:0 context:nil];
|
|
||||||
|
|
||||||
// Status item.
|
|
||||||
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:[NSOperationQueue mainQueue] usingBlock:
|
|
||||||
^(NSNotification *note) {
|
|
||||||
[self updateUsers];
|
|
||||||
}];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidImportChangesNotification object:nil
|
|
||||||
queue:[NSOperationQueue mainQueue] usingBlock:
|
|
||||||
^(NSNotification *note) {
|
|
||||||
[self updateUsers];
|
|
||||||
}];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:MPCheckConfigNotification object:nil
|
|
||||||
queue:[NSOperationQueue mainQueue] usingBlock:
|
|
||||||
^(NSNotification *note) {
|
|
||||||
NSString *key = note.object;
|
|
||||||
if (!key || [key isEqualToString:NSStringFromSelector( @selector( rememberLogin ) )])
|
|
||||||
self.rememberPasswordItem.state = [[MPConfig get].rememberLogin boolValue]? NSOnState: NSOffState;
|
|
||||||
if (!key || [key isEqualToString:NSStringFromSelector( @selector( dialogStyleHUD ) )]) {
|
|
||||||
self.dialogStyleRegular.state = ![[MPMacConfig get].dialogStyleHUD boolValue]? NSOnState: NSOffState;
|
|
||||||
self.dialogStyleHUD.state = [[MPMacConfig get].dialogStyleHUD boolValue]? NSOnState: NSOffState;
|
|
||||||
if (![self.passwordWindow.window isVisible])
|
|
||||||
self.passwordWindow = nil;
|
|
||||||
else {
|
|
||||||
[self.passwordWindow close];
|
|
||||||
self.passwordWindow = nil;
|
|
||||||
[self showPasswordWindow:nil];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
[self updateUsers];
|
|
||||||
|
|
||||||
// Global hotkey.
|
|
||||||
EventHotKeyRef hotKeyRef;
|
|
||||||
EventTypeSpec hotKeyEvents[1] = { { .eventClass = kEventClassKeyboard, .eventKind = kEventHotKeyPressed } };
|
|
||||||
OSStatus status = InstallApplicationEventHandler( NewEventHandlerUPP( MPHotKeyHander ), GetEventTypeCount( hotKeyEvents ),
|
|
||||||
hotKeyEvents, (__bridge void *)self, NULL );
|
|
||||||
if (status != noErr)
|
|
||||||
err( @"Error installing application event handler: %i", (int)status );
|
|
||||||
status = RegisterEventHotKey( 35 /* p */, controlKey + cmdKey, MPShowHotKey, GetApplicationEventTarget(), 0, &hotKeyRef );
|
|
||||||
if (status != noErr)
|
|
||||||
err( @"Error registering 'show' hotkey: %i", (int)status );
|
|
||||||
status = RegisterEventHotKey( 35 /* p */, controlKey + optionKey + cmdKey, MPLockHotKey, GetApplicationEventTarget(), 0, &hotKeyRef );
|
|
||||||
if (status != noErr)
|
|
||||||
err( @"Error registering 'lock' hotkey: %i", (int)status );
|
|
||||||
|
|
||||||
// Initial display.
|
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
if ([[MPMacConfig get].firstRun boolValue]) {
|
|
||||||
self.initialWindow = [[NSWindowController alloc] initWithWindowNibName:@"MPInitialWindow" owner:self];
|
// If no user, can't activate.
|
||||||
[self.initialWindow.window setLevel:NSFloatingWindowLevel];
|
if (![self activeUserForMainThread]) {
|
||||||
[self.initialWindow showWindow:self];
|
[[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."]
|
||||||
|
runModal];
|
||||||
|
[self.statusView popUpMenu];
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setActiveUser:(MPUserEntity *)activeUser {
|
// Don't show window if we weren't already running (ie. if we haven't been activated before).
|
||||||
|
if (!self.passwordWindow)
|
||||||
|
self.passwordWindow = [[MPPasswordWindowController alloc] initWithWindowNibName:@"MPPasswordWindowController"];
|
||||||
|
|
||||||
[super setActiveUser:activeUser];
|
[self.passwordWindow showWindow:self];
|
||||||
|
}
|
||||||
|
|
||||||
[MPMacConfig get].usedUserName = activeUser.name;
|
#pragma mark - Private
|
||||||
|
|
||||||
PearlMainQueue( ^{
|
- (void)updateUsers {
|
||||||
[self updateUsers];
|
|
||||||
} );
|
[[[self.usersItem submenu] itemArray] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
|
||||||
|
if (idx > 2)
|
||||||
|
[[self.usersItem submenu] removeItem:obj];
|
||||||
|
}];
|
||||||
|
|
||||||
|
NSManagedObjectContext *context = [MPMacAppDelegate managedObjectContextForMainThreadIfReady];
|
||||||
|
if (!context) {
|
||||||
|
self.createUserItem.title = @"New User (Not ready)";
|
||||||
|
self.createUserItem.enabled = NO;
|
||||||
|
self.createUserItem.toolTip = @"Please wait until the app is fully loaded.";
|
||||||
|
self.deleteUserItem.title = @"Delete User (Not ready)";
|
||||||
|
self.deleteUserItem.enabled = NO;
|
||||||
|
self.deleteUserItem.toolTip = @"Please wait until the app is fully loaded.";
|
||||||
|
[self.usersItem.submenu addItemWithTitle:@"Loading..." action:NULL keyEquivalent:@""].enabled = NO;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPUserEntity *activeUser = [self activeUserInContext:context];
|
||||||
|
|
||||||
|
self.createUserItem.title = @"New User";
|
||||||
|
self.createUserItem.enabled = YES;
|
||||||
|
self.createUserItem.toolTip = nil;
|
||||||
|
|
||||||
|
self.deleteUserItem.title = activeUser? @"Delete User": @"Delete User (None Selected)";
|
||||||
|
self.deleteUserItem.enabled = activeUser != nil;
|
||||||
|
self.deleteUserItem.toolTip = activeUser? nil: @"First select the user to delete.";
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
|
||||||
|
fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO] ];
|
||||||
|
NSArray *users = [context executeFetchRequest:fetchRequest error:&error];
|
||||||
|
if (!users)
|
||||||
|
err( @"Failed to load users: %@", error );
|
||||||
|
|
||||||
|
if (![users count]) {
|
||||||
|
NSMenuItem *noUsersItem = [self.usersItem.submenu addItemWithTitle:@"No users" action:NULL keyEquivalent:@""];
|
||||||
|
noUsersItem.enabled = NO;
|
||||||
|
noUsersItem.toolTip = @"Use the iOS app to create users and make sure iCloud is enabled in its preferences as well. "
|
||||||
|
@"Then give iCloud some time to sync the new user to your Mac.";
|
||||||
|
}
|
||||||
|
|
||||||
|
self.usersItem.state = NSMixedState;
|
||||||
|
for (MPUserEntity *user in users) {
|
||||||
|
NSMenuItem *userItem = [[NSMenuItem alloc] initWithTitle:user.name action:@selector( selectUser: ) keyEquivalent:@""];
|
||||||
|
[userItem setTarget:self];
|
||||||
|
[userItem setRepresentedObject:[user objectID]];
|
||||||
|
[[self.usersItem submenu] addItem:userItem];
|
||||||
|
|
||||||
|
if (!activeUser && [user.name isEqualToString:[MPMacConfig get].usedUserName])
|
||||||
|
[super setActiveUser:activeUser = user];
|
||||||
|
|
||||||
|
if ([activeUser isEqual:user]) {
|
||||||
|
userItem.state = NSOnState;
|
||||||
|
self.usersItem.state = NSOffState;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
userItem.state = NSOffState;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self updateMenuItems];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)showMenu {
|
||||||
|
|
||||||
|
[self updateMenuItems];
|
||||||
|
|
||||||
|
[self.statusView popUpMenu];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateMenuItems {
|
- (void)updateMenuItems {
|
||||||
@ -440,77 +514,11 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)showPasswordWindow:(id)sender {
|
#pragma mark - PearlConfigDelegate
|
||||||
|
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
- (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)oldValue {
|
||||||
|
|
||||||
// If no user, can't activate.
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:NSStringFromSelector( configKey )];
|
||||||
if (![self activeUserForMainThread]) {
|
|
||||||
[[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."]
|
|
||||||
runModal];
|
|
||||||
[self.statusView popUpMenu];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't show window if we weren't already running (ie. if we haven't been activated before).
|
|
||||||
if (!self.passwordWindow)
|
|
||||||
self.passwordWindow = [[MPPasswordWindowController alloc] initWithWindowNibName:@"MPPasswordWindowController"];
|
|
||||||
|
|
||||||
[self.passwordWindow showWindow:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setLoginItemEnabled:(BOOL)enabled {
|
|
||||||
|
|
||||||
BOOL loginItemEnabled = [self loginItemEnabled];
|
|
||||||
if (loginItemEnabled != enabled) {
|
|
||||||
if (SMLoginItemSetEnabled( (__bridge CFStringRef)LOGIN_HELPER_BUNDLE_ID, (Boolean)enabled ) == true)
|
|
||||||
loginItemEnabled = enabled;
|
|
||||||
else
|
|
||||||
wrn( @"Failed to set login item." );
|
|
||||||
}
|
|
||||||
|
|
||||||
self.openAtLoginItem.state = loginItemEnabled? NSOnState: NSOffState;
|
|
||||||
self.openAtLoginButton.state = loginItemEnabled? NSOnState: NSOffState;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)loginItemEnabled {
|
|
||||||
|
|
||||||
// The easy and sane method (SMJobCopyDictionary) can pose problems when the app is sandboxed. -_-
|
|
||||||
NSArray *jobs = (__bridge_transfer NSArray *)SMCopyAllJobDictionaries( kSMDomainUserLaunchd );
|
|
||||||
|
|
||||||
for (NSDictionary *job in jobs)
|
|
||||||
if ([LOGIN_HELPER_BUNDLE_ID isEqualToString:[job objectForKey:@"Label"]]) {
|
|
||||||
dbg( @"loginItemEnabled: %@", @([[job objectForKey:@"OnDemand"] boolValue]) );
|
|
||||||
return [[job objectForKey:@"OnDemand"] boolValue];
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg( @"loginItemEnabled: not found" );
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)applicationWillResignActive:(NSNotification *)notification {
|
|
||||||
|
|
||||||
if (![[MPConfig get].rememberLogin boolValue])
|
|
||||||
[self lock:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
|
|
||||||
// Save changes in the application's managed object context before the application terminates.
|
|
||||||
|
|
||||||
NSManagedObjectContext *context = [MPMacAppDelegate managedObjectContextForMainThreadIfReady];
|
|
||||||
if (!context)
|
|
||||||
return NSTerminateNow;
|
|
||||||
|
|
||||||
if (![context commitEditing])
|
|
||||||
return NSTerminateCancel;
|
|
||||||
|
|
||||||
if (![context hasChanges])
|
|
||||||
return NSTerminateNow;
|
|
||||||
|
|
||||||
[context saveToStore];
|
|
||||||
return NSTerminateNow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#import "MPAppDelegate_Store.h"
|
#import "MPAppDelegate_Store.h"
|
||||||
#import "MPElementModel.h"
|
#import "MPElementModel.h"
|
||||||
#import "MPAppDelegate_Key.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
|
#import "PearlProfiler.h"
|
||||||
|
|
||||||
#define MPAlertIncorrectMP @"MPAlertIncorrectMP"
|
#define MPAlertIncorrectMP @"MPAlertIncorrectMP"
|
||||||
#define MPAlertCreateSite @"MPAlertCreateSite"
|
#define MPAlertCreateSite @"MPAlertCreateSite"
|
||||||
@ -357,12 +358,15 @@
|
|||||||
if ([self.window isOnActiveSpace] && self.window.alphaValue)
|
if ([self.window isOnActiveSpace] && self.window.alphaValue)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
PearlProfiler *profiler = [PearlProfiler new];
|
||||||
CGWindowID windowID = (CGWindowID)[self.window windowNumber];
|
CGWindowID windowID = (CGWindowID)[self.window windowNumber];
|
||||||
CGImageRef capturedImage = CGWindowListCreateImage( CGRectInfinite, kCGWindowListOptionOnScreenBelowWindow, windowID,
|
CGImageRef capturedImage = CGWindowListCreateImage( CGRectInfinite, kCGWindowListOptionOnScreenBelowWindow, windowID,
|
||||||
kCGWindowImageBoundsIgnoreFraming );
|
kCGWindowImageBoundsIgnoreFraming );
|
||||||
|
[profiler finishJob:@"captured window: %d, on screen: %@", windowID, self.window.screen];
|
||||||
NSImage *screenImage = [[NSImage alloc] initWithCGImage:capturedImage size:NSMakeSize(
|
NSImage *screenImage = [[NSImage alloc] initWithCGImage:capturedImage size:NSMakeSize(
|
||||||
CGImageGetWidth( capturedImage ) / self.window.backingScaleFactor,
|
CGImageGetWidth( capturedImage ) / self.window.backingScaleFactor,
|
||||||
CGImageGetHeight( capturedImage ) / self.window.backingScaleFactor )];
|
CGImageGetHeight( capturedImage ) / self.window.backingScaleFactor )];
|
||||||
|
[profiler finishJob:@"image size: %@, bytes: %ld", NSStringFromSize( screenImage.size ), screenImage.TIFFRepresentation.length ];
|
||||||
|
|
||||||
NSImage *smallImage = [[NSImage alloc] initWithSize:NSMakeSize(
|
NSImage *smallImage = [[NSImage alloc] initWithSize:NSMakeSize(
|
||||||
CGImageGetWidth( capturedImage ) / 20,
|
CGImageGetWidth( capturedImage ) / 20,
|
||||||
@ -373,12 +377,16 @@
|
|||||||
operation:NSCompositeSourceOver
|
operation:NSCompositeSourceOver
|
||||||
fraction:1.0];
|
fraction:1.0];
|
||||||
[smallImage unlockFocus];
|
[smallImage unlockFocus];
|
||||||
|
[profiler finishJob:@"small image size: %@, bytes: %ld", NSStringFromSize( screenImage.size ), screenImage.TIFFRepresentation.length];
|
||||||
|
|
||||||
self.blurView.image = smallImage;
|
self.blurView.image = smallImage;
|
||||||
|
[profiler finishJob:@"assigned image"];
|
||||||
|
|
||||||
[self.window setFrame:self.window.screen.frame display:YES];
|
[self.window setFrame:self.window.screen.frame display:YES];
|
||||||
|
[profiler finishJob:@"assigned frame"];
|
||||||
[[NSAnimationContext currentContext] setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
|
[[NSAnimationContext currentContext] setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
|
||||||
[[self.window animator] setAlphaValue:1.0];
|
[[self.window animator] setAlphaValue:1.0];
|
||||||
|
[profiler finishJob:@"animating window"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)fadeOut {
|
- (void)fadeOut {
|
||||||
|
@ -42,25 +42,15 @@
|
|||||||
<real key="inputRadius" value="20"/>
|
<real key="inputRadius" value="20"/>
|
||||||
</configuration>
|
</configuration>
|
||||||
</ciFilter>
|
</ciFilter>
|
||||||
<ciFilter name="CIColorControls">
|
<ciFilter name="CIPhotoEffectProcess">
|
||||||
<configuration>
|
<configuration>
|
||||||
<real key="inputBrightness" value="-0.29999999999999999"/>
|
|
||||||
<real key="inputContrast" value="1"/>
|
|
||||||
<null key="inputImage"/>
|
|
||||||
<real key="inputSaturation" value="0.0"/>
|
|
||||||
</configuration>
|
|
||||||
</ciFilter>
|
|
||||||
<ciFilter name="CIFalseColor">
|
|
||||||
<configuration>
|
|
||||||
<ciColor key="inputColor0" red="0.70196080207824707" green="0.70196080207824707" blue="0.70196080207824707" alpha="1"/>
|
|
||||||
<ciColor key="inputColor1" red="0.0" green="0.25098040699958801" blue="0.50196081399917603" alpha="1"/>
|
|
||||||
<null key="inputImage"/>
|
<null key="inputImage"/>
|
||||||
</configuration>
|
</configuration>
|
||||||
</ciFilter>
|
</ciFilter>
|
||||||
</contentFilters>
|
</contentFilters>
|
||||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="small-screen" id="ArA-2w-I56"/>
|
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="small-screen" id="ArA-2w-I56"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
<secureTextField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="iGR-wo-ual" userLabel="Password Field">
|
<secureTextField hidden="YES" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="iGR-wo-ual" userLabel="Password Field">
|
||||||
<rect key="frame" x="18" y="243" width="612" height="44"/>
|
<rect key="frame" x="18" y="243" width="612" height="44"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<shadow key="shadow">
|
<shadow key="shadow">
|
||||||
@ -113,9 +103,9 @@
|
|||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="pTl-fc-MSY">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="pTl-fc-MSY">
|
||||||
<rect key="frame" x="-2" y="0.0" width="516" height="29"/>
|
<rect key="frame" x="-2" y="0.0" width="516" height="29"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||||
<shadow key="shadow">
|
<shadow key="shadow" blurRadius="1">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="color" white="0.0" alpha="0.80000000000000004" colorSpace="calibratedWhite"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="center" title="apple.com" id="5Ug-eU-C9Y">
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="center" title="apple.com" id="5Ug-eU-C9Y">
|
||||||
<font key="font" size="24" name="HelveticaNeue-Thin"/>
|
<font key="font" size="24" name="HelveticaNeue-Thin"/>
|
||||||
@ -170,9 +160,9 @@
|
|||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OnR-s6-d4P" userLabel="Input Label">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OnR-s6-d4P" userLabel="Input Label">
|
||||||
<rect key="frame" x="213" y="295" width="223" height="20"/>
|
<rect key="frame" x="213" y="295" width="223" height="20"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<shadow key="shadow">
|
<shadow key="shadow" blurRadius="1">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="color" red="0.0" green="0.0" blue="0.0" alpha="0.80000000000000004" colorSpace="calibratedRGB"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Maarten Billemont's password for:" id="1Lb-d0-fQD">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Maarten Billemont's password for:" id="1Lb-d0-fQD">
|
||||||
<font key="font" size="14" name="HelveticaNeue"/>
|
<font key="font" size="14" name="HelveticaNeue"/>
|
||||||
@ -186,9 +176,9 @@
|
|||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="512" id="rW7-Vq-4Xy"/>
|
<constraint firstAttribute="width" constant="512" id="rW7-Vq-4Xy"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<shadow key="shadow">
|
<shadow key="shadow" blurRadius="1">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="color" red="0.0" green="0.0" blue="0.0" alpha="0.80000000000000004" colorSpace="calibratedRGB"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<searchFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" focusRingType="none" alignment="center" placeholderString="Site Name" id="ppl-2c-1E9">
|
<searchFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" focusRingType="none" alignment="center" placeholderString="Site Name" id="ppl-2c-1E9">
|
||||||
<font key="font" size="36" name="HelveticaNeue-Thin"/>
|
<font key="font" size="36" name="HelveticaNeue-Thin"/>
|
||||||
@ -328,6 +318,19 @@
|
|||||||
</configuration>
|
</configuration>
|
||||||
</ciFilter>
|
</ciFilter>
|
||||||
</backgroundFilters>
|
</backgroundFilters>
|
||||||
|
<animations>
|
||||||
|
<caTransition key="subviews">
|
||||||
|
<mutableData key="keyedArchiveRepresentation">
|
||||||
|
YnBsaXN0MDDUAQIDBAUGICFYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKcHCA8Q
|
||||||
|
CRUbVSRudWxs0wkKCwwNDlR0eXBlViRjbGFzc18QEl9fQ0FDb2RpbmdDb250ZW50c4ACgAaAA1RmYWRl
|
||||||
|
0hEKEhRaTlMub2JqZWN0c6ETgASABdIWFxgZWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNBcnJheaIYGlhO
|
||||||
|
U09iamVjdNIWFxwdXENBVHJhbnNpdGlvbqMeHxpcQ0FUcmFuc2l0aW9uW0NBQW5pbWF0aW9uXxAPTlNL
|
||||||
|
ZXllZEFyY2hpdmVy0SIjVHJvb3SAAQAIABEAGgAjAC0AMgA3AD8ARQBMAFEAWABtAG8AcQBzAHgAfQCI
|
||||||
|
AIoAjACOAJMAngCnAK8AsgC7AMAAzQDRAN4A6gD8AP8BBAAAAAAAAAIBAAAAAAAAACQAAAAAAAAAAAAA
|
||||||
|
AAAAAAEGA
|
||||||
|
</mutableData>
|
||||||
|
</caTransition>
|
||||||
|
</animations>
|
||||||
</view>
|
</view>
|
||||||
</window>
|
</window>
|
||||||
<userDefaultsController representsSharedInstance="YES" id="yy2-3W-Ocj"/>
|
<userDefaultsController representsSharedInstance="YES" id="yy2-3W-Ocj"/>
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
93D390C676DF52DA7E459F19 /* MPPasswordWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D9D0061FF1159998F06 /* MPPasswordWindow.m */; };
|
93D390C676DF52DA7E459F19 /* MPPasswordWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D9D0061FF1159998F06 /* MPPasswordWindow.m */; };
|
||||||
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */; };
|
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */; };
|
||||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
|
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
|
||||||
|
93D3970BCF85F7902E611168 /* PearlProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DB3A8ADED08C39A6228 /* PearlProfiler.m */; };
|
||||||
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
|
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
|
||||||
93D39C5789EFA607CF788082 /* MPElementModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */; };
|
93D39C5789EFA607CF788082 /* MPElementModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */; };
|
||||||
93D39C7C2BE7C0E0763B0177 /* MPElementCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D394495528B10D1B61A2C3 /* MPElementCollectionView.m */; };
|
93D39C7C2BE7C0E0763B0177 /* MPElementCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D394495528B10D1B61A2C3 /* MPElementCollectionView.m */; };
|
||||||
|
93D39D304F73B3BBA031522A /* PearlProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D394EEFF5BF555A55AF361 /* PearlProfiler.h */; };
|
||||||
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
|
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
|
||||||
93D39F833DEC1C89B2F795AC /* MPPasswordWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A57A7823DE98A0FF83C /* MPPasswordWindowController.m */; };
|
93D39F833DEC1C89B2F795AC /* MPPasswordWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A57A7823DE98A0FF83C /* MPPasswordWindowController.m */; };
|
||||||
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */; };
|
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */; };
|
||||||
@ -309,12 +311,14 @@
|
|||||||
93D392C3918763B3B72CF366 /* MPPasswordWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordWindowController.h; sourceTree = "<group>"; };
|
93D392C3918763B3B72CF366 /* MPPasswordWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordWindowController.h; sourceTree = "<group>"; };
|
||||||
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
|
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
|
||||||
93D394495528B10D1B61A2C3 /* MPElementCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementCollectionView.m; sourceTree = "<group>"; };
|
93D394495528B10D1B61A2C3 /* MPElementCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementCollectionView.m; sourceTree = "<group>"; };
|
||||||
|
93D394EEFF5BF555A55AF361 /* PearlProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PearlProfiler.h; path = ../../../External/Pearl/Pearl/PearlProfiler.h; sourceTree = "<group>"; };
|
||||||
93D3960D320FF8A072B092E3 /* MPElementCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementCollectionView.h; sourceTree = "<group>"; };
|
93D3960D320FF8A072B092E3 /* MPElementCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementCollectionView.h; sourceTree = "<group>"; };
|
||||||
93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = "<group>"; };
|
93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = "<group>"; };
|
||||||
93D3977484534E99F9BA579D /* MPPasswordWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordWindow.h; sourceTree = "<group>"; };
|
93D3977484534E99F9BA579D /* MPPasswordWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordWindow.h; sourceTree = "<group>"; };
|
||||||
93D39A57A7823DE98A0FF83C /* MPPasswordWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordWindowController.m; sourceTree = "<group>"; };
|
93D39A57A7823DE98A0FF83C /* MPPasswordWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordWindowController.m; sourceTree = "<group>"; };
|
||||||
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = "<group>"; };
|
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = "<group>"; };
|
||||||
93D39D9D0061FF1159998F06 /* MPPasswordWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordWindow.m; sourceTree = "<group>"; };
|
93D39D9D0061FF1159998F06 /* MPPasswordWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordWindow.m; sourceTree = "<group>"; };
|
||||||
|
93D39DB3A8ADED08C39A6228 /* PearlProfiler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PearlProfiler.m; path = ../../../External/Pearl/Pearl/PearlProfiler.m; sourceTree = "<group>"; };
|
||||||
93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementModel.m; sourceTree = "<group>"; };
|
93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementModel.m; sourceTree = "<group>"; };
|
||||||
DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPInitialWindow.xib; sourceTree = "<group>"; };
|
DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPInitialWindow.xib; sourceTree = "<group>"; };
|
||||||
DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "shot-laptop-leaning-iphone.png"; sourceTree = "<group>"; };
|
DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "shot-laptop-leaning-iphone.png"; sourceTree = "<group>"; };
|
||||||
@ -702,6 +706,8 @@
|
|||||||
DACA22121705DDC5002C6C22 /* External */,
|
DACA22121705DDC5002C6C22 /* External */,
|
||||||
DA5BFA47147E415C00F98B1E /* Frameworks */,
|
DA5BFA47147E415C00F98B1E /* Frameworks */,
|
||||||
DA5BFA45147E415C00F98B1E /* Products */,
|
DA5BFA45147E415C00F98B1E /* Products */,
|
||||||
|
93D39DB3A8ADED08C39A6228 /* PearlProfiler.m */,
|
||||||
|
93D394EEFF5BF555A55AF361 /* PearlProfiler.h */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -1343,6 +1349,7 @@
|
|||||||
DAEB93E718AB0FFD000490CC /* crypto.h in Headers */,
|
DAEB93E718AB0FFD000490CC /* crypto.h in Headers */,
|
||||||
DAEB941318AB0FFD000490CC /* ssl2.h in Headers */,
|
DAEB941318AB0FFD000490CC /* ssl2.h in Headers */,
|
||||||
DAEB940D18AB0FFD000490CC /* ripemd.h in Headers */,
|
DAEB940D18AB0FFD000490CC /* ripemd.h in Headers */,
|
||||||
|
93D39D304F73B3BBA031522A /* PearlProfiler.h in Headers */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -1715,6 +1722,7 @@
|
|||||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */,
|
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */,
|
||||||
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */,
|
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */,
|
||||||
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */,
|
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */,
|
||||||
|
93D3970BCF85F7902E611168 /* PearlProfiler.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user