Collection-view for elements and swipe to modify.
[ADDED] NSCollectionView for navigating between elements. [ADDED] Mac: Functional buttons for changing type, loginName and counter.
This commit is contained in:
parent
c48bed5ebd
commit
775a6fd4ea
@ -37,6 +37,8 @@
|
|||||||
- (NSString *)shortNameOfType:(MPElementType)type;
|
- (NSString *)shortNameOfType:(MPElementType)type;
|
||||||
- (NSString *)classNameOfType:(MPElementType)type;
|
- (NSString *)classNameOfType:(MPElementType)type;
|
||||||
- (Class)classOfType:(MPElementType)type;
|
- (Class)classOfType:(MPElementType)type;
|
||||||
|
- (MPElementType)nextType:(MPElementType)type;
|
||||||
|
- (MPElementType)previousType:(MPElementType)type;
|
||||||
|
|
||||||
- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key;
|
- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key;
|
||||||
- (NSString *)storedContentForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key;
|
- (NSString *)storedContentForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key;
|
||||||
|
@ -127,7 +127,7 @@
|
|||||||
return @"Device Private Password";
|
return @"Device Private Password";
|
||||||
}
|
}
|
||||||
|
|
||||||
Throw(@"Type not supported: %d", type);
|
Throw(@"Type not supported: %lu", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)shortNameOfType:(MPElementType)type {
|
- (NSString *)shortNameOfType:(MPElementType)type {
|
||||||
@ -161,7 +161,7 @@
|
|||||||
return @"Device";
|
return @"Device";
|
||||||
}
|
}
|
||||||
|
|
||||||
Throw(@"Type not supported: %d", type);
|
Throw(@"Type not supported: %lu", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)classNameOfType:(MPElementType)type {
|
- (NSString *)classNameOfType:(MPElementType)type {
|
||||||
@ -200,7 +200,43 @@
|
|||||||
return [MPElementStoredEntity class];
|
return [MPElementStoredEntity class];
|
||||||
}
|
}
|
||||||
|
|
||||||
Throw(@"Type not supported: %d", type);
|
Throw(@"Type not supported: %lu", type);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementType)nextType:(MPElementType)type {
|
||||||
|
|
||||||
|
if (!type)
|
||||||
|
Throw(@"No type given.");
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case MPElementTypeGeneratedMaximum:
|
||||||
|
return MPElementTypeStoredDevicePrivate;
|
||||||
|
case MPElementTypeGeneratedLong:
|
||||||
|
return MPElementTypeGeneratedMaximum;
|
||||||
|
case MPElementTypeGeneratedMedium:
|
||||||
|
return MPElementTypeGeneratedLong;
|
||||||
|
case MPElementTypeGeneratedBasic:
|
||||||
|
return MPElementTypeGeneratedMedium;
|
||||||
|
case MPElementTypeGeneratedShort:
|
||||||
|
return MPElementTypeGeneratedBasic;
|
||||||
|
case MPElementTypeGeneratedPIN:
|
||||||
|
return MPElementTypeGeneratedShort;
|
||||||
|
case MPElementTypeStoredPersonal:
|
||||||
|
return MPElementTypeGeneratedPIN;
|
||||||
|
case MPElementTypeStoredDevicePrivate:
|
||||||
|
return MPElementTypeStoredPersonal;
|
||||||
|
}
|
||||||
|
|
||||||
|
Throw(@"Type not supported: %lu", type);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementType)previousType:(MPElementType)type {
|
||||||
|
|
||||||
|
MPElementType previousType = type, nextType = type;
|
||||||
|
while ((nextType = [self nextType:nextType]) != type)
|
||||||
|
previousType = nextType;
|
||||||
|
|
||||||
|
return previousType;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key {
|
- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key {
|
||||||
@ -264,13 +300,13 @@
|
|||||||
case MPElementTypeGeneratedBasic:
|
case MPElementTypeGeneratedBasic:
|
||||||
case MPElementTypeGeneratedShort:
|
case MPElementTypeGeneratedShort:
|
||||||
case MPElementTypeGeneratedPIN: {
|
case MPElementTypeGeneratedPIN: {
|
||||||
NSAssert(NO, @"Cannot save content to element with generated type %d.", element.type);
|
NSAssert(NO, @"Cannot save content to element with generated type %lu.", element.type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MPElementTypeStoredPersonal: {
|
case MPElementTypeStoredPersonal: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
||||||
|
|
||||||
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
|
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
|
||||||
encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
||||||
@ -279,7 +315,7 @@
|
|||||||
}
|
}
|
||||||
case MPElementTypeStoredDevicePrivate: {
|
case MPElementTypeStoredDevicePrivate: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
||||||
|
|
||||||
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
|
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
|
||||||
encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
||||||
@ -324,7 +360,7 @@
|
|||||||
case MPElementTypeGeneratedShort:
|
case MPElementTypeGeneratedShort:
|
||||||
case MPElementTypeGeneratedPIN: {
|
case MPElementTypeGeneratedPIN: {
|
||||||
NSAssert([element isKindOfClass:[MPElementGeneratedEntity class]],
|
NSAssert([element isKindOfClass:[MPElementGeneratedEntity class]],
|
||||||
@"Element with generated type %d is not an MPElementGeneratedEntity, but a %@.", element.type, [element class]);
|
@"Element with generated type %lu is not an MPElementGeneratedEntity, but a %@.", element.type, [element class]);
|
||||||
|
|
||||||
NSString *name = element.name;
|
NSString *name = element.name;
|
||||||
MPElementType type = element.type;
|
MPElementType type = element.type;
|
||||||
@ -346,7 +382,7 @@
|
|||||||
|
|
||||||
case MPElementTypeStoredPersonal: {
|
case MPElementTypeStoredPersonal: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
||||||
|
|
||||||
NSData *encryptedContent = ((MPElementStoredEntity *)element).contentObject;
|
NSData *encryptedContent = ((MPElementStoredEntity *)element).contentObject;
|
||||||
|
|
||||||
@ -358,7 +394,7 @@
|
|||||||
}
|
}
|
||||||
case MPElementTypeStoredDevicePrivate: {
|
case MPElementTypeStoredDevicePrivate: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
||||||
|
|
||||||
NSDictionary *elementQuery = [self queryForDevicePrivateElementNamed:element.name];
|
NSDictionary *elementQuery = [self queryForDevicePrivateElementNamed:element.name];
|
||||||
NSData *encryptedContent = [PearlKeyChain dataOfItemForQuery:elementQuery];
|
NSData *encryptedContent = [PearlKeyChain dataOfItemForQuery:elementQuery];
|
||||||
@ -387,7 +423,7 @@
|
|||||||
|
|
||||||
case MPElementTypeStoredPersonal: {
|
case MPElementTypeStoredPersonal: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
||||||
if ([importKey.keyID isEqualToData:elementKey.keyID])
|
if ([importKey.keyID isEqualToData:elementKey.keyID])
|
||||||
((MPElementStoredEntity *)element).contentObject = [protectedContent decodeBase64];
|
((MPElementStoredEntity *)element).contentObject = [protectedContent decodeBase64];
|
||||||
|
|
||||||
@ -445,7 +481,7 @@
|
|||||||
|
|
||||||
case MPElementTypeStoredPersonal: {
|
case MPElementTypeStoredPersonal: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
||||||
result = [((MPElementStoredEntity *)element).contentObject encodeBase64];
|
result = [((MPElementStoredEntity *)element).contentObject encodeBase64];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -409,6 +409,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
newElement.loginName = element.loginName;
|
newElement.loginName = element.loginName;
|
||||||
|
|
||||||
[context deleteObject:element];
|
[context deleteObject:element];
|
||||||
|
// TODO: Dodgy... we're not saving consistently here.
|
||||||
|
// Either we should save regardless and change the method signature to saveInContext: or not save at all.
|
||||||
[context saveToStore];
|
[context saveToStore];
|
||||||
|
|
||||||
NSError *error;
|
NSError *error;
|
||||||
@ -699,7 +701,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
|
|
||||||
[export appendFormat:@"%@ %8ld %8s %20s\t%@\n",
|
[export appendFormat:@"%@ %8ld %8s %20s\t%@\n",
|
||||||
[[NSDateFormatter rfc3339DateFormatter] stringFromDate:lastUsed], (long)uses,
|
[[NSDateFormatter rfc3339DateFormatter] stringFromDate:lastUsed], (long)uses,
|
||||||
[PearlString( @"%u:%lu", type, (unsigned long)version ) UTF8String], [name UTF8String], content
|
[PearlString( @"%lu:%lu", type, (unsigned long)version ) UTF8String], [name UTF8String], content
|
||||||
? content: @""];
|
? content: @""];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +53,8 @@
|
|||||||
aType = [self.user defaultType];
|
aType = [self.user defaultType];
|
||||||
if (!aType || aType == (MPElementType)NSNotFound)
|
if (!aType || aType == (MPElementType)NSNotFound)
|
||||||
aType = MPElementTypeGeneratedLong;
|
aType = MPElementTypeGeneratedLong;
|
||||||
|
if (![self isKindOfClass:[self.algorithm classOfType:aType]])
|
||||||
|
Throw(@"This object's class does not support the type: %lu", aType);
|
||||||
|
|
||||||
self.type_ = @(aType);
|
self.type_ = @(aType);
|
||||||
}
|
}
|
||||||
@ -125,7 +127,7 @@
|
|||||||
|
|
||||||
- (NSString *)debugDescription {
|
- (NSString *)debugDescription {
|
||||||
|
|
||||||
return PearlString( @"{%@: name=%@, user=%@, type=%d, uses=%ld, lastUsed=%@, version=%ld, loginName=%@, requiresExplicitMigration=%d}",
|
return PearlString( @"{%@: name=%@, user=%@, type=%lu, uses=%ld, lastUsed=%@, version=%ld, loginName=%@, requiresExplicitMigration=%d}",
|
||||||
NSStringFromClass( [self class] ), self.name, self.user.name, self.type, (long)self.uses, self.lastUsed, (long)self.version,
|
NSStringFromClass( [self class] ), self.name, self.user.name, self.type, (long)self.uses, self.lastUsed, (long)self.version,
|
||||||
self.loginName, self.requiresExplicitMigration );
|
self.loginName, self.requiresExplicitMigration );
|
||||||
}
|
}
|
||||||
|
@ -8,27 +8,27 @@
|
|||||||
|
|
||||||
#import "MPKey.h"
|
#import "MPKey.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef NS_ENUM(NSUInteger, MPElementContentType) {
|
||||||
MPElementContentTypePassword,
|
MPElementContentTypePassword,
|
||||||
MPElementContentTypeNote,
|
MPElementContentTypeNote,
|
||||||
MPElementContentTypePicture,
|
MPElementContentTypePicture,
|
||||||
} MPElementContentType;
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef NS_ENUM(NSUInteger, MPElementTypeClass) {
|
||||||
/** Generate the password. */
|
/** Generate the password. */
|
||||||
MPElementTypeClassGenerated = 1 << 4,
|
MPElementTypeClassGenerated = 1 << 4,
|
||||||
/** Store the password. */
|
/** Store the password. */
|
||||||
MPElementTypeClassStored = 1 << 5,
|
MPElementTypeClassStored = 1 << 5,
|
||||||
} MPElementTypeClass;
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef NS_ENUM(NSUInteger, MPElementFeature) {
|
||||||
/** Export the key-protected content data. */
|
/** Export the key-protected content data. */
|
||||||
MPElementFeatureExportContent = 1 << 10,
|
MPElementFeatureExportContent = 1 << 10,
|
||||||
/** Never export content. */
|
/** Never export content. */
|
||||||
MPElementFeatureDevicePrivate = 1 << 11,
|
MPElementFeatureDevicePrivate = 1 << 11,
|
||||||
} MPElementFeature;
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef NS_ENUM(NSUInteger, MPElementType) {
|
||||||
MPElementTypeGeneratedMaximum = 0x0 | MPElementTypeClassGenerated | 0x0,
|
MPElementTypeGeneratedMaximum = 0x0 | MPElementTypeClassGenerated | 0x0,
|
||||||
MPElementTypeGeneratedLong = 0x1 | MPElementTypeClassGenerated | 0x0,
|
MPElementTypeGeneratedLong = 0x1 | MPElementTypeClassGenerated | 0x0,
|
||||||
MPElementTypeGeneratedMedium = 0x2 | MPElementTypeClassGenerated | 0x0,
|
MPElementTypeGeneratedMedium = 0x2 | MPElementTypeClassGenerated | 0x0,
|
||||||
@ -38,7 +38,7 @@ typedef enum {
|
|||||||
|
|
||||||
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
|
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
|
||||||
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
|
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
|
||||||
} MPElementType;
|
};
|
||||||
|
|
||||||
#define MPErrorDomain @"MPErrorDomain"
|
#define MPErrorDomain @"MPErrorDomain"
|
||||||
|
|
||||||
|
@ -17,9 +17,17 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
@class MPElementModel;
|
||||||
|
|
||||||
@interface MPElementCollectionView : NSCollectionViewItem
|
@interface MPElementCollectionView : NSCollectionViewItem
|
||||||
|
|
||||||
@property(nonatomic, weak) IBOutlet NSTextField *siteField;
|
@property (nonatomic) MPElementModel *representedObject;
|
||||||
@property(nonatomic, weak) IBOutlet NSTextField *contentField;
|
@property (nonatomic) NSString *typeTitle;
|
||||||
|
@property (nonatomic) NSString *loginNameTitle;
|
||||||
|
@property (nonatomic) NSString *counterTitle;
|
||||||
|
|
||||||
|
- (IBAction)toggleType:(id)sender;
|
||||||
|
- (IBAction)setLoginName:(id)sender;
|
||||||
|
- (IBAction)incrementCounter:(id)sender;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -17,7 +17,237 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPElementCollectionView.h"
|
#import "MPElementCollectionView.h"
|
||||||
|
#import "MPElementModel.h"
|
||||||
|
#import "MPMacAppDelegate.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
|
||||||
|
#define MPAlertChangeType @"MPAlertChangeType"
|
||||||
|
#define MPAlertChangeLogin @"MPAlertChangeLogin"
|
||||||
|
#define MPAlertChangeCounter @"MPAlertChangeCounter"
|
||||||
|
#define MPAlertChangeContent @"MPAlertChangeContent"
|
||||||
|
|
||||||
@implementation MPElementCollectionView {
|
@implementation MPElementCollectionView {
|
||||||
|
id _representedObjectObserver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@dynamic representedObject;
|
||||||
|
|
||||||
|
- (id)initWithCoder:(NSCoder *)coder {
|
||||||
|
|
||||||
|
if (!(self = [super initWithCoder:coder]))
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
__weak MPElementCollectionView *wSelf = self;
|
||||||
|
_representedObjectObserver = [self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
||||||
|
dispatch_async( dispatch_get_main_queue(), ^{
|
||||||
|
dbg(@"updating login name of %@ to: %@", wSelf.representedObject.site, wSelf.representedObject.loginName);
|
||||||
|
wSelf.typeTitle = PearlString( @"Type:\n%@", wSelf.representedObject.typeName );
|
||||||
|
wSelf.loginNameTitle = PearlString( @"Login Name:\n%@", wSelf.representedObject.loginName );
|
||||||
|
|
||||||
|
if (wSelf.representedObject.type & MPElementTypeClassGenerated)
|
||||||
|
wSelf.counterTitle = PearlString( @"Number:\n%@", wSelf.representedObject.counter );
|
||||||
|
else if (wSelf.representedObject.type & MPElementTypeClassStored)
|
||||||
|
wSelf.counterTitle = PearlString( @"Update Password" );
|
||||||
|
} );
|
||||||
|
} forKeyPath:@"representedObject" options:0 context:nil];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
|
||||||
|
if (_representedObjectObserver)
|
||||||
|
[self removeObserver:_representedObjectObserver forKeyPath:@"representedObject"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)toggleType:(id)sender {
|
||||||
|
|
||||||
|
id<MPAlgorithm> algorithm = self.representedObject.algorithm;
|
||||||
|
NSString *previousType = [algorithm nameOfType:[algorithm previousType:self.representedObject.type]];
|
||||||
|
NSString *nextType = [algorithm nameOfType:[algorithm nextType:self.representedObject.type]];
|
||||||
|
|
||||||
|
[[NSAlert alertWithMessageText:@"Change Password Type"
|
||||||
|
defaultButton:nextType alternateButton:@"Cancel" otherButton:previousType
|
||||||
|
informativeTextWithFormat:@"Changing the password type for this site will cause the password to change.\n"
|
||||||
|
@"You will need to update your account with the new password.\n\n"
|
||||||
|
@"Changing back to the old type will restore your current password."]
|
||||||
|
beginSheetModalForWindow:self.view.window modalDelegate:self
|
||||||
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertChangeType];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)setLoginName:(id)sender {
|
||||||
|
|
||||||
|
NSAlert *alert = [NSAlert alertWithMessageText:@"Update Login Name"
|
||||||
|
defaultButton:@"Update" alternateButton:@"Cancel" otherButton:nil
|
||||||
|
informativeTextWithFormat:@"Enter the login name for %@:", self.representedObject.site];
|
||||||
|
NSTextField *passwordField = [[NSTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
||||||
|
[alert setAccessoryView:passwordField];
|
||||||
|
[alert layout];
|
||||||
|
[passwordField becomeFirstResponder];
|
||||||
|
[alert beginSheetModalForWindow:self.view.window modalDelegate:self
|
||||||
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertChangeLogin];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)incrementCounter:(id)sender {
|
||||||
|
|
||||||
|
if (self.representedObject.type & MPElementTypeClassGenerated) {
|
||||||
|
[[NSAlert alertWithMessageText:@"Change Password Number"
|
||||||
|
defaultButton:@"New Password" alternateButton:@"Cancel" otherButton:@"Initial Password"
|
||||||
|
informativeTextWithFormat:@"Increasing the password number gives you a new password for the site.\n"
|
||||||
|
@"You will need to update your account with the new password.\n\n"
|
||||||
|
@"Changing back to the initial password will reset the password number to 1."]
|
||||||
|
beginSheetModalForWindow:self.view.window modalDelegate:self
|
||||||
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertChangeCounter];
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (self.representedObject.type & MPElementTypeClassStored) {
|
||||||
|
NSAlert *alert = [NSAlert alertWithMessageText:@"Update Password"
|
||||||
|
defaultButton:@"Update" alternateButton:@"Cancel" otherButton:nil
|
||||||
|
informativeTextWithFormat:@"Enter the new password for %@:", self.representedObject.site];
|
||||||
|
NSSecureTextField *passwordField = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
||||||
|
[alert setAccessoryView:passwordField];
|
||||||
|
[alert layout];
|
||||||
|
[passwordField becomeFirstResponder];
|
||||||
|
[alert beginSheetModalForWindow:self.view.window modalDelegate:self
|
||||||
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertChangeContent];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
|
||||||
|
|
||||||
|
if (contextInfo == MPAlertChangeType) {
|
||||||
|
switch (returnCode) {
|
||||||
|
case NSAlertDefaultReturn: {
|
||||||
|
// "Next type" button.
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||||
|
element = [[MPMacAppDelegate get] changeElement:element inContext:context
|
||||||
|
toType:[element.algorithm nextType:element.type]];
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertAlternateReturn: {
|
||||||
|
// "Cancel" button.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertOtherReturn: {
|
||||||
|
// "Previous type" button.
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||||
|
element = [[MPMacAppDelegate get] changeElement:element inContext:context
|
||||||
|
toType:[element.algorithm previousType:element.type]];
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (contextInfo == MPAlertChangeLogin) {
|
||||||
|
switch (returnCode) {
|
||||||
|
case NSAlertDefaultReturn: {
|
||||||
|
// "Update" button.
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||||
|
element.loginName = [(NSTextField *)alert.accessoryView stringValue];
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertAlternateReturn: {
|
||||||
|
// "Cancel" button.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (contextInfo == MPAlertChangeCounter) {
|
||||||
|
switch (returnCode) {
|
||||||
|
case NSAlertDefaultReturn: {
|
||||||
|
// "New Password" button.
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||||
|
if ([element isKindOfClass:[MPElementGeneratedEntity class]]) {
|
||||||
|
MPElementGeneratedEntity *generatedElement = (MPElementGeneratedEntity *)element;
|
||||||
|
++generatedElement.counter;
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertAlternateReturn: {
|
||||||
|
// "Cancel" button.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertOtherReturn: {
|
||||||
|
// "Initial Password" button.
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||||
|
if ([element isKindOfClass:[MPElementGeneratedEntity class]]) {
|
||||||
|
MPElementGeneratedEntity *generatedElement = (MPElementGeneratedEntity *)element;
|
||||||
|
generatedElement.counter = 1;
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (contextInfo == MPAlertChangeContent) {
|
||||||
|
switch (returnCode) {
|
||||||
|
case NSAlertDefaultReturn: {
|
||||||
|
// "Update" button.
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||||
|
[element.algorithm saveContent:[(NSSecureTextField *)alert.accessoryView stringValue]
|
||||||
|
toElement:element usingKey:[MPMacAppDelegate get].key];
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertAlternateReturn: {
|
||||||
|
// "Cancel" button.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -21,11 +21,14 @@
|
|||||||
|
|
||||||
@interface MPElementModel : NSObject
|
@interface MPElementModel : NSObject
|
||||||
@property (nonatomic) NSString *site;
|
@property (nonatomic) NSString *site;
|
||||||
@property (nonatomic) NSString *type;
|
@property (nonatomic) MPElementType type;
|
||||||
|
@property (nonatomic) NSString *typeName;
|
||||||
@property (nonatomic) NSString *content;
|
@property (nonatomic) NSString *content;
|
||||||
@property (nonatomic) NSString *loginName;
|
@property (nonatomic) NSString *loginName;
|
||||||
@property (nonatomic) NSNumber *uses;
|
@property (nonatomic) NSNumber *uses;
|
||||||
|
@property (nonatomic) NSNumber *counter;
|
||||||
@property (nonatomic) NSDate *lastUsed;
|
@property (nonatomic) NSDate *lastUsed;
|
||||||
|
@property (nonatomic, strong) id<MPAlgorithm> algorithm;
|
||||||
|
|
||||||
- (MPElementEntity *)entityForMainThread;
|
- (MPElementEntity *)entityForMainThread;
|
||||||
- (MPElementEntity *)entityInContext:(NSManagedObjectContext *)moc;
|
- (MPElementEntity *)entityInContext:(NSManagedObjectContext *)moc;
|
||||||
|
@ -39,9 +39,12 @@
|
|||||||
self.site = entity.name;
|
self.site = entity.name;
|
||||||
self.lastUsed = entity.lastUsed;
|
self.lastUsed = entity.lastUsed;
|
||||||
self.loginName = entity.loginName;
|
self.loginName = entity.loginName;
|
||||||
self.type = entity.typeName;
|
self.type = entity.type;
|
||||||
|
self.typeName = entity.typeName;
|
||||||
self.uses = entity.uses_;
|
self.uses = entity.uses_;
|
||||||
|
self.counter = @([entity isKindOfClass:[MPElementGeneratedEntity class]]? [(MPElementGeneratedEntity *)entity counter]: 0);
|
||||||
self.content = [entity.algorithm resolveContentForElement:entity usingKey:[MPAppDelegate_Shared get].key];
|
self.content = [entity.algorithm resolveContentForElement:entity usingKey:[MPAppDelegate_Shared get].key];
|
||||||
|
self.algorithm = entity.algorithm;
|
||||||
self.entityOID = entity.objectID;
|
self.entityOID = entity.objectID;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="4514" systemVersion="13B3116" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="4514" systemVersion="13B3116" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment defaultVersion="1080" identifier="macosx"/>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="4514"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="4514"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
@ -16,7 +15,7 @@
|
|||||||
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" wantsToBeColor="NO" animationBehavior="default" id="1">
|
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" wantsToBeColor="NO" animationBehavior="default" id="1">
|
||||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||||
<rect key="contentRect" x="196" y="240" width="833" height="540"/>
|
<rect key="contentRect" x="196" y="240" width="833" height="540"/>
|
||||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
|
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="900"/>
|
||||||
<view key="contentView" id="2" userLabel="Container">
|
<view key="contentView" id="2" userLabel="Container">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="833" height="540"/>
|
<rect key="frame" x="0.0" y="0.0" width="833" height="540"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
@ -7,12 +7,13 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
@class MPElementModel;
|
||||||
|
|
||||||
@interface MPPasswordWindowController : NSWindowController<NSTextFieldDelegate>
|
@interface MPPasswordWindowController : NSWindowController<NSTextFieldDelegate, NSCollectionViewDelegate>
|
||||||
|
|
||||||
@property(nonatomic, strong) NSMutableArray *elements;
|
@property(nonatomic, strong) NSMutableArray *elements;
|
||||||
|
@property(nonatomic, strong) NSIndexSet *elementSelectionIndexes;
|
||||||
@property(nonatomic, weak) IBOutlet NSTextField *siteField;
|
@property(nonatomic, weak) IBOutlet NSTextField *siteField;
|
||||||
@property(nonatomic, weak) IBOutlet NSTextField *tipField;
|
|
||||||
@property(nonatomic, weak) IBOutlet NSView *contentContainer;
|
@property(nonatomic, weak) IBOutlet NSView *contentContainer;
|
||||||
@property(nonatomic, weak) IBOutlet NSTextField *userLabel;
|
@property(nonatomic, weak) IBOutlet NSTextField *userLabel;
|
||||||
@property(nonatomic, weak) IBOutlet NSCollectionView *siteCollectionView;
|
@property(nonatomic, weak) IBOutlet NSCollectionView *siteCollectionView;
|
||||||
|
@ -42,8 +42,6 @@
|
|||||||
self.backgroundQueue = [NSOperationQueue new];
|
self.backgroundQueue = [NSOperationQueue new];
|
||||||
self.backgroundQueue.maxConcurrentOperationCount = 1;
|
self.backgroundQueue.maxConcurrentOperationCount = 1;
|
||||||
|
|
||||||
[self.tipField setStringValue:@""];
|
|
||||||
|
|
||||||
[self.userLabel setStringValue:PearlString( @"%@'s password for:", [[MPMacAppDelegate get] activeUserForMainThread].name )];
|
[self.userLabel setStringValue:PearlString( @"%@'s password for:", [[MPMacAppDelegate get] activeUserForMainThread].name )];
|
||||||
[[MPMacAppDelegate get] addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
[[MPMacAppDelegate get] addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
||||||
// [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
// [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
||||||
@ -160,7 +158,6 @@
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
[self.siteField setStringValue:@""];
|
[self.siteField setStringValue:@""];
|
||||||
[self.tipField setStringValue:@""];
|
|
||||||
|
|
||||||
NSAlert *alert = [NSAlert alertWithMessageText:@"Master Password is locked."
|
NSAlert *alert = [NSAlert alertWithMessageText:@"Master Password is locked."
|
||||||
defaultButton:@"Unlock" alternateButton:@"Change" otherButton:@"Cancel"
|
defaultButton:@"Unlock" alternateButton:@"Change" otherButton:@"Cancel"
|
||||||
@ -265,12 +262,49 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSCollectionViewDelegate
|
||||||
|
|
||||||
|
- (void)setElementSelectionIndexes:(NSIndexSet *)elementSelectionIndexes {
|
||||||
|
|
||||||
|
// First reset bounds.
|
||||||
|
PearlMainThread(^{
|
||||||
|
NSUInteger selectedIndex = self.elementSelectionIndexes.firstIndex;
|
||||||
|
if (selectedIndex != NSNotFound && selectedIndex < self.elements.count)
|
||||||
|
[[self selectedView].animator setBoundsOrigin:NSZeroPoint];
|
||||||
|
} );
|
||||||
|
|
||||||
|
_elementSelectionIndexes = elementSelectionIndexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSTextFieldDelegate
|
||||||
|
|
||||||
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector {
|
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector {
|
||||||
|
|
||||||
if (commandSelector == @selector(cancel:)) { // Escape without completion.
|
if (commandSelector == @selector(cancel:)) { // Escape without completion.
|
||||||
[self close];
|
[self close];
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
if (self.elements.count) {
|
||||||
|
if (commandSelector == @selector(moveUp:)) {
|
||||||
|
self.elementSelectionIndexes =
|
||||||
|
[NSIndexSet indexSetWithIndex:(self.elementSelectionIndexes.firstIndex - 1 + self.elements.count) % self.elements.count];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if (commandSelector == @selector(moveDown:)) {
|
||||||
|
self.elementSelectionIndexes =
|
||||||
|
[NSIndexSet indexSetWithIndex:(self.elementSelectionIndexes.firstIndex + 1) % self.elements.count];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if (commandSelector == @selector(moveLeft:)) {
|
||||||
|
[[self selectedView].animator setBoundsOrigin:NSZeroPoint];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if (commandSelector == @selector(moveRight:)) {
|
||||||
|
NSBox *selectedView = [self selectedView];
|
||||||
|
[selectedView.animator setBoundsOrigin:NSMakePoint( selectedView.bounds.size.width / 2, 0 )];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
// if ((self.siteFieldPreventCompletion = [NSStringFromSelector( commandSelector ) hasPrefix:@"delete"])) { // Backspace any time.
|
// if ((self.siteFieldPreventCompletion = [NSStringFromSelector( commandSelector ) hasPrefix:@"delete"])) { // Backspace any time.
|
||||||
// _activeElementOID = nil;
|
// _activeElementOID = nil;
|
||||||
// [self trySiteWithAction:NO];
|
// [self trySiteWithAction:NO];
|
||||||
@ -278,7 +312,7 @@
|
|||||||
// }
|
// }
|
||||||
if (commandSelector == @selector(insertNewline:)) { // Return without completion.
|
if (commandSelector == @selector(insertNewline:)) { // Return without completion.
|
||||||
[self useSite];
|
[self useSite];
|
||||||
return YES;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NO;
|
return NO;
|
||||||
@ -305,6 +339,8 @@
|
|||||||
[self updateElements];
|
[self updateElements];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
- (void)updateElements {
|
- (void)updateElements {
|
||||||
NSString *query = [self.siteField.currentEditor string];
|
NSString *query = [self.siteField.currentEditor string];
|
||||||
if (![query length] || ![MPMacAppDelegate get].key) {
|
if (![query length] || ![MPMacAppDelegate get].key) {
|
||||||
@ -327,17 +363,32 @@
|
|||||||
for (MPElementEntity *element in siteResults)
|
for (MPElementEntity *element in siteResults)
|
||||||
[newElements addObject:[[MPElementModel alloc] initWithEntity:element]];
|
[newElements addObject:[[MPElementModel alloc] initWithEntity:element]];
|
||||||
self.elements = newElements;
|
self.elements = newElements;
|
||||||
|
if (!self.selectedElement && [newElements count])
|
||||||
|
self.elementSelectionIndexes = [NSIndexSet indexSetWithIndex:0];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (MPElementModel *)selectedElement {
|
- (NSBox *)selectedView {
|
||||||
|
|
||||||
NSIndexSet *selectedIndexes = self.siteCollectionView.selectionIndexes;
|
NSUInteger selectedIndex = self.elementSelectionIndexes.firstIndex;
|
||||||
if (!selectedIndexes.count)
|
if (selectedIndex == NSNotFound || selectedIndex >= self.elements.count)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
return (MPElementModel *)self.elements[selectedIndexes.firstIndex];
|
return (NSBox *)[self.siteCollectionView itemAtIndex:selectedIndex].view;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementModel *)selectedElement {
|
||||||
|
|
||||||
|
if (!self.elementSelectionIndexes.count)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return (MPElementModel *)self.elements[self.elementSelectionIndexes.firstIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSelectedElement:(MPElementModel *)element {
|
||||||
|
|
||||||
|
self.elementSelectionIndexes = [NSIndexSet indexSetWithIndex:[self.elements indexOfObject:element]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)useSite {
|
- (void)useSite {
|
||||||
@ -346,60 +397,22 @@
|
|||||||
if (selectedElement) {
|
if (selectedElement) {
|
||||||
// Performing action while content is available. Copy it.
|
// Performing action while content is available. Copy it.
|
||||||
[self copyContent:selectedElement.content];
|
[self copyContent:selectedElement.content];
|
||||||
|
NSBox *selectedView = [self selectedView];
|
||||||
self.tipField.alphaValue = 1;
|
dispatch_async( dispatch_get_main_queue(), ^{
|
||||||
self.tipField.stringValue = @"Copied! Hit ⎋ (ESC) to close window.";
|
[selectedView.animator setFillColor:[NSColor controlHighlightColor]];
|
||||||
dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ), dispatch_get_main_queue(),
|
dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)(0.3f * NSEC_PER_SEC) ), dispatch_get_main_queue(), ^{
|
||||||
^{
|
dispatch_async( dispatch_get_main_queue(), ^{
|
||||||
[NSAnimationContext beginGrouping];
|
[selectedView.animator setFillColor:[NSColor selectedControlColor]];
|
||||||
[[NSAnimationContext currentContext] setDuration:0.2f];
|
} );
|
||||||
[self.tipField.animator setAlphaValue:0];
|
} );
|
||||||
[NSAnimationContext endGrouping];
|
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
NSString *siteName = [self.siteField stringValue];
|
NSString *siteName = [self.siteField stringValue];
|
||||||
if ([siteName length]) {
|
if ([siteName length])
|
||||||
// Performing action without content but a site name is written.
|
// Performing action without content but a site name is written.
|
||||||
[self createNewSite:siteName];
|
[self createNewSite:siteName];
|
||||||
[self.tipField setStringValue:@""];
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
|
||||||
// MPElementEntity *activeElement = [self activeElementInContext:context];
|
|
||||||
// NSString *typeName = [activeElement typeShortName];
|
|
||||||
// [activeElement.algorithm resolveContentForElement:activeElement usingKey:[MPAppDelegate_Shared get].key result:
|
|
||||||
// ^(NSString *result) {
|
|
||||||
// BOOL actionHandled = NO;
|
|
||||||
// if (doAction) {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
|
||||||
// [self setContent:result];
|
|
||||||
// if (actionHandled)
|
|
||||||
// [self.tipField setStringValue:@""];
|
|
||||||
// else if (![result length]) {
|
|
||||||
// if ([siteName length])
|
|
||||||
// [self.tipField setStringValue:@"Hit ⌤ (ENTER) to create a new site."];
|
|
||||||
// else
|
|
||||||
// [self.tipField setStringValue:@""];
|
|
||||||
// }
|
|
||||||
// else if (!doAction)
|
|
||||||
// [self.tipField setStringValue:@"Hit ⌤ (ENTER) to copy the password."];
|
|
||||||
// else {
|
|
||||||
// [self.tipField setStringValue:@"Copied! Hit ⎋ (ESC) to close window."];
|
|
||||||
// dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ), dispatch_get_main_queue(),
|
|
||||||
// ^{
|
|
||||||
// [NSAnimationContext beginGrouping];
|
|
||||||
// [[NSAnimationContext currentContext] setDuration:0.2f];
|
|
||||||
// [self.tipField.animator setAlphaValue:0];
|
|
||||||
// [NSAnimationContext endGrouping];
|
|
||||||
// } );
|
|
||||||
// }
|
|
||||||
// }];
|
|
||||||
// }];
|
|
||||||
// }];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)copyContent:(NSString *)content {
|
- (void)copyContent:(NSString *)content {
|
||||||
@ -427,6 +440,8 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - KVO
|
||||||
|
|
||||||
- (void)insertObject:(MPElementModel *)model inElementsAtIndex:(NSUInteger)index {
|
- (void)insertObject:(MPElementModel *)model inElementsAtIndex:(NSUInteger)index {
|
||||||
|
|
||||||
[self.elements insertObject:model atIndex:index];
|
[self.elements insertObject:model atIndex:index];
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<outlet property="contentContainer" destination="143" id="214"/>
|
<outlet property="contentContainer" destination="143" id="214"/>
|
||||||
<outlet property="siteCollectionView" destination="pr9-BO-vQV" id="Bnh-WQ-RaO"/>
|
<outlet property="siteCollectionView" destination="pr9-BO-vQV" id="Bnh-WQ-RaO"/>
|
||||||
<outlet property="siteField" destination="182" id="224"/>
|
<outlet property="siteField" destination="182" id="224"/>
|
||||||
<outlet property="tipField" destination="183" id="226"/>
|
|
||||||
<outlet property="userLabel" destination="216" id="223"/>
|
<outlet property="userLabel" destination="216" id="223"/>
|
||||||
<outlet property="window" destination="22" id="40"/>
|
<outlet property="window" destination="22" id="40"/>
|
||||||
</connections>
|
</connections>
|
||||||
@ -19,20 +18,20 @@
|
|||||||
<customObject id="-3" userLabel="Application"/>
|
<customObject id="-3" userLabel="Application"/>
|
||||||
<window title="Master Password" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="22" customClass="NSPanel">
|
<window title="Master Password" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="22" customClass="NSPanel">
|
||||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES" texturedBackground="YES"/>
|
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES" texturedBackground="YES"/>
|
||||||
<rect key="contentRect" x="600" y="530" width="480" height="373"/>
|
<rect key="contentRect" x="600" y="530" width="480" height="320"/>
|
||||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
|
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
|
||||||
<value key="minSize" type="size" width="480" height="199"/>
|
<value key="minSize" type="size" width="480" height="320"/>
|
||||||
<value key="maxSize" type="size" width="480" height="200"/>
|
<value key="maxSize" type="size" width="480" height="320"/>
|
||||||
<view key="contentView" wantsLayer="YES" id="23">
|
<view key="contentView" wantsLayer="YES" id="23">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="480" height="373"/>
|
<rect key="frame" x="0.0" y="0.0" width="480" height="320"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="143">
|
<customView translatesAutoresizingMaskIntoConstraints="NO" id="143">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="480" height="373"/>
|
<rect key="frame" x="0.0" y="0.0" width="480" height="320"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="182">
|
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="182">
|
||||||
<rect key="frame" x="140" y="306" width="200" height="22"/>
|
<rect key="frame" x="140" y="253" width="200" height="22"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="200" id="258"/>
|
<constraint firstAttribute="width" constant="200" id="258"/>
|
||||||
@ -46,21 +45,8 @@
|
|||||||
<outlet property="delegate" destination="-2" id="188"/>
|
<outlet property="delegate" destination="-2" id="188"/>
|
||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="183">
|
|
||||||
<rect key="frame" x="18" y="20" width="444" height="17"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
|
||||||
<shadow key="shadow" blurRadius="1">
|
|
||||||
<size key="offset" width="0.0" height="1"/>
|
|
||||||
<color key="color" white="0.0" alpha="0.90000000000000002" colorSpace="calibratedWhite"/>
|
|
||||||
</shadow>
|
|
||||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="center" title="Hit enter to copy the password." usesSingleLineMode="YES" id="184">
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
</textFieldCell>
|
|
||||||
</textField>
|
|
||||||
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="216">
|
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="216">
|
||||||
<rect key="frame" x="130" y="336" width="221" height="17"/>
|
<rect key="frame" x="130" y="283" width="221" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<shadow key="shadow" blurRadius="1">
|
<shadow key="shadow" blurRadius="1">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
@ -72,20 +58,21 @@
|
|||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<scrollView autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tjI-mV-s8H">
|
<scrollView autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" hasVerticalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tjI-mV-s8H">
|
||||||
<rect key="frame" x="0.0" y="45" width="480" height="253"/>
|
<rect key="frame" x="0.0" y="0.0" width="480" height="245"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<clipView key="contentView" id="mfh-QT-ClZ">
|
<clipView key="contentView" id="mfh-QT-ClZ">
|
||||||
<rect key="frame" x="1" y="1" width="478" height="251"/>
|
<rect key="frame" x="1" y="1" width="478" height="243"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<collectionView selectable="YES" maxNumberOfColumns="1" id="pr9-BO-vQV">
|
<collectionView selectable="YES" maxNumberOfColumns="1" id="pr9-BO-vQV">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="478" height="251"/>
|
<rect key="frame" x="0.0" y="0.0" width="478" height="243"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="secondaryBackgroundColor" name="controlAlternatingRowColor" catalog="System" colorSpace="catalog"/>
|
<color key="secondaryBackgroundColor" name="controlAlternatingRowColor" catalog="System" colorSpace="catalog"/>
|
||||||
<connections>
|
<connections>
|
||||||
<binding destination="jTN-Q9-Ajn" name="content" keyPath="arrangedObjects" id="dtF-fs-Fpe"/>
|
<binding destination="jTN-Q9-Ajn" name="content" keyPath="arrangedObjects" id="dtF-fs-Fpe"/>
|
||||||
|
<binding destination="-2" name="selectionIndexes" keyPath="elementSelectionIndexes" previousBinding="dtF-fs-Fpe" id="UFy-9F-18H"/>
|
||||||
<outlet property="itemPrototype" destination="QBZ-sO-HQn" id="QAi-HN-YUc"/>
|
<outlet property="itemPrototype" destination="QBZ-sO-HQn" id="QAi-HN-YUc"/>
|
||||||
</connections>
|
</connections>
|
||||||
</collectionView>
|
</collectionView>
|
||||||
@ -96,18 +83,15 @@
|
|||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="vs6-1G-hvM">
|
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="vs6-1G-hvM">
|
||||||
<rect key="frame" x="234" y="1" width="15" height="143"/>
|
<rect key="frame" x="-100" y="-100" width="15" height="143"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
</scrollView>
|
</scrollView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="183" firstAttribute="leading" secondItem="143" secondAttribute="leading" constant="20" symbolic="YES" id="200"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="183" secondAttribute="trailing" constant="20" symbolic="YES" id="201"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="183" secondAttribute="bottom" constant="20" symbolic="YES" id="209"/>
|
|
||||||
<constraint firstItem="216" firstAttribute="top" secondItem="143" secondAttribute="top" constant="20" symbolic="YES" id="218"/>
|
<constraint firstItem="216" firstAttribute="top" secondItem="143" secondAttribute="top" constant="20" symbolic="YES" id="218"/>
|
||||||
<constraint firstItem="182" firstAttribute="top" secondItem="216" secondAttribute="bottom" constant="8" symbolic="YES" id="221"/>
|
<constraint firstItem="182" firstAttribute="top" secondItem="216" secondAttribute="bottom" constant="8" symbolic="YES" id="221"/>
|
||||||
<constraint firstItem="183" firstAttribute="top" secondItem="tjI-mV-s8H" secondAttribute="bottom" constant="8" symbolic="YES" id="9Vk-0h-GEZ"/>
|
<constraint firstAttribute="bottom" secondItem="tjI-mV-s8H" secondAttribute="bottom" id="6y8-tJ-1sX"/>
|
||||||
<constraint firstAttribute="centerX" secondItem="182" secondAttribute="centerX" id="W6t-BO-Njn"/>
|
<constraint firstAttribute="centerX" secondItem="182" secondAttribute="centerX" id="W6t-BO-Njn"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="tjI-mV-s8H" secondAttribute="trailing" id="aKe-a9-Br8"/>
|
<constraint firstAttribute="trailing" secondItem="tjI-mV-s8H" secondAttribute="trailing" id="aKe-a9-Br8"/>
|
||||||
<constraint firstItem="tjI-mV-s8H" firstAttribute="leading" secondItem="143" secondAttribute="leading" id="d8F-JD-EhR"/>
|
<constraint firstItem="tjI-mV-s8H" firstAttribute="leading" secondItem="143" secondAttribute="leading" id="d8F-JD-EhR"/>
|
||||||
@ -127,98 +111,175 @@
|
|||||||
<outlet property="delegate" destination="-2" id="39"/>
|
<outlet property="delegate" destination="-2" id="39"/>
|
||||||
</connections>
|
</connections>
|
||||||
</window>
|
</window>
|
||||||
<collectionViewItem id="QBZ-sO-HQn">
|
<collectionViewItem id="QBZ-sO-HQn" customClass="MPElementCollectionView">
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="view" destination="qT3-mQ-aNP" id="0Bp-d3-Fhc"/>
|
<outlet property="view" destination="bhu-Ky-PQq" id="jZh-jC-6bL"/>
|
||||||
</connections>
|
</connections>
|
||||||
</collectionViewItem>
|
</collectionViewItem>
|
||||||
<view wantsLayer="YES" id="qT3-mQ-aNP">
|
<arrayController objectClassName="MPElementModel" id="jTN-Q9-Ajn">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="480" height="63"/>
|
<connections>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<binding destination="-2" name="contentArray" keyPath="self.elements" id="8Uz-14-YG0"/>
|
||||||
|
</connections>
|
||||||
|
</arrayController>
|
||||||
|
<box autoresizesSubviews="NO" wantsLayer="YES" boxType="custom" borderType="none" titlePosition="noTitle" id="bhu-Ky-PQq">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="960" height="61"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<view key="contentView">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="960" height="61"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="xwJ-Pu-glP">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="xwJ-Pu-glP">
|
||||||
<rect key="frame" x="6" y="38" width="70" height="17"/>
|
<rect key="frame" x="6" y="36" width="70" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<shadow key="shadow" blurRadius="1">
|
||||||
|
<size key="offset" width="0.0" height="1"/>
|
||||||
|
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
|
||||||
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="apple.com" id="ymH-M0-M5d">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="apple.com" id="ymH-M0-M5d">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
<connections>
|
<connections>
|
||||||
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.site" id="qtG-zK-Kqm"/>
|
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.site" id="4as-ow-WbD"/>
|
||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Cn5-nt-e6X">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Cn5-nt-e6X">
|
||||||
<rect key="frame" x="343" y="38" width="131" height="17"/>
|
<rect key="frame" x="342" y="36" width="131" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<shadow key="shadow" blurRadius="1">
|
||||||
|
<size key="offset" width="0.0" height="1"/>
|
||||||
|
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
|
||||||
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="lhunath@lyndir.com" id="Px4-pS-kwG">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="lhunath@lyndir.com" id="Px4-pS-kwG">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
<connections>
|
<connections>
|
||||||
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.loginName" id="IBW-j2-pi0"/>
|
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.loginName" id="kuR-ui-n33"/>
|
||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="a1n-Sf-Mw6">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="a1n-Sf-Mw6">
|
||||||
<rect key="frame" x="6" y="8" width="207" height="35"/>
|
<rect key="frame" x="6" y="8" width="207" height="35"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<constraints>
|
<shadow key="shadow" blurRadius="1">
|
||||||
<constraint firstAttribute="height" constant="35" id="mdi-n9-noL"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
</constraints>
|
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
|
||||||
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="RutuTutnTeni4," id="7jb-Fa-xX3">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="RutuTutnTeni4," id="7jb-Fa-xX3">
|
||||||
<font key="font" size="24" name="Menlo-Regular"/>
|
<font key="font" size="24" name="Menlo-Regular"/>
|
||||||
<color key="textColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
<connections>
|
<connections>
|
||||||
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.content" id="MRG-PR-8IO"/>
|
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.content" id="19u-Zx-3vP"/>
|
||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mp4-r1-7Xg">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mp4-r1-7Xg">
|
||||||
<rect key="frame" x="267" y="8" width="207" height="35"/>
|
<rect key="frame" x="440" y="8" width="33" height="35"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<constraints>
|
<shadow key="shadow" blurRadius="1">
|
||||||
<constraint firstAttribute="height" constant="35" id="dU6-nc-x6h"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
</constraints>
|
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
|
||||||
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="12" id="Vb9-nO-cWY">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="12" id="Vb9-nO-cWY">
|
||||||
<font key="font" size="24" name="Menlo-Regular"/>
|
<font key="font" size="24" name="Menlo-Regular"/>
|
||||||
<color key="textColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
<connections>
|
<connections>
|
||||||
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.uses" id="QEe-6y-lip"/>
|
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.uses" id="7gd-qw-W5L"/>
|
||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
</subviews>
|
<box autoresizesSubviews="NO" horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="tsT-Xh-Nxb">
|
||||||
|
<rect key="frame" x="477" y="0.0" width="5" height="61"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||||
|
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||||
|
<font key="titleFont" metaFont="system"/>
|
||||||
|
</box>
|
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="oC2-zu-Voi">
|
||||||
|
<rect key="frame" x="480" y="-1" width="160" height="63"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="a1n-Sf-Mw6" firstAttribute="leading" secondItem="qT3-mQ-aNP" secondAttribute="leading" constant="8" id="08s-TV-lf5"/>
|
<constraint firstAttribute="height" constant="61" id="228-Aw-hiL"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="Cn5-nt-e6X" secondAttribute="trailing" constant="8" id="21i-fq-NLo"/>
|
|
||||||
<constraint firstItem="xwJ-Pu-glP" firstAttribute="leading" secondItem="qT3-mQ-aNP" secondAttribute="leading" constant="8" id="Gwd-ln-Nsx"/>
|
|
||||||
<constraint firstItem="mp4-r1-7Xg" firstAttribute="top" secondItem="Cn5-nt-e6X" secondAttribute="bottom" constant="-5" id="MB5-53-Khp"/>
|
|
||||||
<constraint firstItem="a1n-Sf-Mw6" firstAttribute="top" secondItem="xwJ-Pu-glP" secondAttribute="bottom" constant="-5" id="hVN-ux-Os9"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="mp4-r1-7Xg" secondAttribute="trailing" constant="8" id="hv0-qD-0tP"/>
|
|
||||||
<constraint firstItem="Cn5-nt-e6X" firstAttribute="top" secondItem="qT3-mQ-aNP" secondAttribute="top" constant="8" id="lfU-7M-U8M"/>
|
|
||||||
<constraint firstItem="xwJ-Pu-glP" firstAttribute="top" secondItem="qT3-mQ-aNP" secondAttribute="top" constant="8" id="nbr-g3-Zgg"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="a1n-Sf-Mw6" secondAttribute="bottom" constant="8" id="vfQ-H0-s3U"/>
|
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="5ZG-4S-zov">
|
||||||
<arrayController objectClassName="MPElementModel" id="jTN-Q9-Ajn">
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<declaredKeys>
|
<string key="title">Type:
|
||||||
<string>site</string>
|
Long Password</string>
|
||||||
<string>type</string>
|
<font key="font" metaFont="system"/>
|
||||||
<string>content</string>
|
</buttonCell>
|
||||||
<string>loginName</string>
|
|
||||||
<string>uses</string>
|
|
||||||
<string>lastUsed</string>
|
|
||||||
</declaredKeys>
|
|
||||||
<connections>
|
<connections>
|
||||||
<binding destination="-2" name="contentArray" keyPath="self.elements" id="8Uz-14-YG0"/>
|
<action selector="toggleType:" target="QBZ-sO-HQn" id="pdJ-Uz-fac"/>
|
||||||
|
<binding destination="QBZ-sO-HQn" name="title" keyPath="typeTitle" id="Ric-aa-82E"/>
|
||||||
</connections>
|
</connections>
|
||||||
</arrayController>
|
</button>
|
||||||
<view id="J0B-yE-vAw">
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="sEM-ko-UxJ">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
|
<rect key="frame" x="640" y="-1" width="160" height="63"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" imagePosition="overlaps" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ymB-jq-V5d">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<string key="title">Login Name:
|
||||||
|
lhunath@lyndir.com</string>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="setLoginName:" target="QBZ-sO-HQn" id="xMV-pi-ofl"/>
|
||||||
|
<binding destination="QBZ-sO-HQn" name="title" keyPath="loginNameTitle" id="4Bw-5R-OCr"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="SA7-eS-Kal" userLabel="Square - Number: 1">
|
||||||
|
<rect key="frame" x="800" y="-1" width="160" height="63"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" imagePosition="overlaps" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="7b3-Hz-grn">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<string key="title">Number:
|
||||||
|
1</string>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="incrementCounter:" target="QBZ-sO-HQn" id="dZP-Rc-LHA"/>
|
||||||
|
<binding destination="QBZ-sO-HQn" name="title" keyPath="counterTitle" id="cGQ-ec-Yyy"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
</view>
|
</view>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="centerY" secondItem="SA7-eS-Kal" secondAttribute="centerY" id="72p-MU-EeL"/>
|
||||||
|
<constraint firstItem="SA7-eS-Kal" firstAttribute="height" secondItem="oC2-zu-Voi" secondAttribute="height" id="8ev-ss-Omh"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="SA7-eS-Kal" secondAttribute="trailing" id="BDj-TF-YFN"/>
|
||||||
|
<constraint firstAttribute="centerY" secondItem="sEM-ko-UxJ" secondAttribute="centerY" id="F2A-cH-miL"/>
|
||||||
|
<constraint firstItem="Cn5-nt-e6X" firstAttribute="top" secondItem="bhu-Ky-PQq" secondAttribute="top" constant="8" id="FWS-tY-KkM"/>
|
||||||
|
<constraint firstItem="SA7-eS-Kal" firstAttribute="width" secondItem="sEM-ko-UxJ" secondAttribute="width" id="HKZ-ha-UXa"/>
|
||||||
|
<constraint firstItem="tsT-Xh-Nxb" firstAttribute="leading" secondItem="Cn5-nt-e6X" secondAttribute="trailing" constant="8" id="LjD-10-tVU"/>
|
||||||
|
<constraint firstItem="SA7-eS-Kal" firstAttribute="leading" secondItem="sEM-ko-UxJ" secondAttribute="trailing" id="Maf-za-cvg"/>
|
||||||
|
<constraint firstItem="oC2-zu-Voi" firstAttribute="leading" secondItem="tsT-Xh-Nxb" secondAttribute="trailing" id="NJd-Us-uj8"/>
|
||||||
|
<constraint firstItem="tsT-Xh-Nxb" firstAttribute="top" secondItem="bhu-Ky-PQq" secondAttribute="top" id="ODH-Nx-QdY"/>
|
||||||
|
<constraint firstAttribute="centerY" secondItem="oC2-zu-Voi" secondAttribute="centerY" id="ODK-IE-HEh"/>
|
||||||
|
<constraint firstItem="xwJ-Pu-glP" firstAttribute="leading" secondItem="bhu-Ky-PQq" secondAttribute="leading" constant="8" id="QAM-jm-t0y"/>
|
||||||
|
<constraint firstAttribute="centerY" secondItem="tsT-Xh-Nxb" secondAttribute="centerY" id="Rpi-lc-dZ1"/>
|
||||||
|
<constraint firstItem="tsT-Xh-Nxb" firstAttribute="leading" secondItem="mp4-r1-7Xg" secondAttribute="trailing" constant="8" id="Xfc-Jq-2Rb"/>
|
||||||
|
<constraint firstItem="SA7-eS-Kal" firstAttribute="width" secondItem="oC2-zu-Voi" secondAttribute="width" id="akL-8k-gbu"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="tsT-Xh-Nxb" secondAttribute="bottom" id="ds1-7i-B7I"/>
|
||||||
|
<constraint firstItem="a1n-Sf-Mw6" firstAttribute="leading" secondItem="bhu-Ky-PQq" secondAttribute="leading" constant="8" id="e3g-2s-yee"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="mp4-r1-7Xg" secondAttribute="bottom" constant="8" id="jCW-5H-6pT"/>
|
||||||
|
<constraint firstAttribute="centerX" secondItem="tsT-Xh-Nxb" secondAttribute="centerX" id="kx6-g0-jUW"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="a1n-Sf-Mw6" secondAttribute="bottom" constant="8" id="mWW-rt-kl2"/>
|
||||||
|
<constraint firstItem="SA7-eS-Kal" firstAttribute="height" secondItem="sEM-ko-UxJ" secondAttribute="height" id="mpf-ND-lSa"/>
|
||||||
|
<constraint firstItem="sEM-ko-UxJ" firstAttribute="leading" secondItem="oC2-zu-Voi" secondAttribute="trailing" id="tmV-ZM-J1I"/>
|
||||||
|
<constraint firstItem="xwJ-Pu-glP" firstAttribute="top" secondItem="bhu-Ky-PQq" secondAttribute="top" constant="8" id="z8k-ot-NjU"/>
|
||||||
|
</constraints>
|
||||||
|
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||||
|
<color key="fillColor" name="selectedControlColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<connections>
|
||||||
|
<binding destination="QBZ-sO-HQn" name="transparent" keyPath="selected" id="Tpz-Rp-lA7">
|
||||||
|
<dictionary key="options">
|
||||||
|
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||||
|
</dictionary>
|
||||||
|
</binding>
|
||||||
|
</connections>
|
||||||
|
</box>
|
||||||
</objects>
|
</objects>
|
||||||
</document>
|
</document>
|
@ -13,7 +13,6 @@
|
|||||||
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 */; };
|
||||||
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 */; };
|
||||||
DA0933CA1747A56A00DE1CEF /* MPInitialWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */; };
|
|
||||||
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 */; };
|
||||||
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CF1747B91B00DE1CEF /* appstore.png */; };
|
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CF1747B91B00DE1CEF /* appstore.png */; };
|
||||||
DA16B33F170661D4000A0EAB /* libUbiquityStoreManager.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */; };
|
DA16B33F170661D4000A0EAB /* libUbiquityStoreManager.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */; };
|
||||||
@ -204,6 +203,7 @@
|
|||||||
DAEB942718AB0FFD000490CC /* sha256.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D618AB0FFD000490CC /* sha256.h */; };
|
DAEB942718AB0FFD000490CC /* sha256.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D618AB0FFD000490CC /* sha256.h */; };
|
||||||
DAEB942818AB0FFD000490CC /* sysendian.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D718AB0FFD000490CC /* sysendian.h */; };
|
DAEB942818AB0FFD000490CC /* sysendian.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D718AB0FFD000490CC /* sysendian.h */; };
|
||||||
DAEB942918AB0FFD000490CC /* warn.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D818AB0FFD000490CC /* warn.h */; };
|
DAEB942918AB0FFD000490CC /* warn.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D818AB0FFD000490CC /* warn.h */; };
|
||||||
|
DAEB942E18B47FB3000490CC /* MPInitialWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */; };
|
||||||
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45D815039823003ABA7C /* NSObject+PearlExport.h */; };
|
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45D815039823003ABA7C /* NSObject+PearlExport.h */; };
|
||||||
DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */; };
|
DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */; };
|
||||||
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */; };
|
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */; };
|
||||||
@ -1452,6 +1452,7 @@
|
|||||||
DACA27231705DF81002C6C22 /* avatar-15@2x.png in Resources */,
|
DACA27231705DF81002C6C22 /* avatar-15@2x.png in Resources */,
|
||||||
DACA27241705DF81002C6C22 /* avatar-5@2x.png in Resources */,
|
DACA27241705DF81002C6C22 /* avatar-5@2x.png in Resources */,
|
||||||
DACA27251705DF81002C6C22 /* avatar-6.png in Resources */,
|
DACA27251705DF81002C6C22 /* avatar-6.png in Resources */,
|
||||||
|
DAEB942E18B47FB3000490CC /* MPInitialWindow.xib in Resources */,
|
||||||
DACA27261705DF81002C6C22 /* avatar-6@2x.png in Resources */,
|
DACA27261705DF81002C6C22 /* avatar-6@2x.png in Resources */,
|
||||||
DACA27271705DF81002C6C22 /* avatar-16@2x.png in Resources */,
|
DACA27271705DF81002C6C22 /* avatar-16@2x.png in Resources */,
|
||||||
DACA27281705DF81002C6C22 /* avatar-10.png in Resources */,
|
DACA27281705DF81002C6C22 /* avatar-10.png in Resources */,
|
||||||
@ -1486,7 +1487,6 @@
|
|||||||
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */,
|
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */,
|
||||||
DA5E5D0B1724A667003798D8 /* MainMenu.xib in Resources */,
|
DA5E5D0B1724A667003798D8 /* MainMenu.xib in Resources */,
|
||||||
DA5E5D551724F9C8003798D8 /* MasterPassword.iconset in Resources */,
|
DA5E5D551724F9C8003798D8 /* MasterPassword.iconset in Resources */,
|
||||||
DA0933CA1747A56A00DE1CEF /* MPInitialWindow.xib in Resources */,
|
|
||||||
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */,
|
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */,
|
||||||
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */,
|
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */,
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user