2
0

Compare commits

..

26 Commits

Author SHA1 Message Date
Maarten Billemont
e3963a72ad Press bump. 2013-05-11 20:05:07 -04:00
Maarten Billemont
cefe8d144d Import fix, password type change fix, fancier generator appearance.
[FIXED]     Import of ubiquity changes was using wrong delegate method and MOC.
[FIXED]     Password type change broken when password type causes a class change.
[IMPROVED]  Fancier animation of emergency generator appearance.
2013-05-11 19:43:41 -04:00
Maarten Billemont
076cfb1257 MOC saving improvements, Mac app activation, loading overlay, USM update.
[MOVED]     iOS code from MPAppDelegate_Shared to MPiOSAppDelegate.
[FIXED]     Perform MOC saving in MOC perform blocks.
[FIXED]     Mac: Activate app when showing password window and not active.
[FIXED]     Hide overlay while corruption dialog is up.
[FIXED]     Hide corruption dialog when reloading store.
2013-05-11 08:55:09 -04:00
Maarten Billemont
71e3f44c8c Improved migration, file-based StoreUUID, Mac fixes.
[ADDED]     Migration to file-based StoreUUID.
[IMPROVED]  Cleaner, more modular, migration code.
[FIXED]     Don't hook activation to show password window: too annoying when focus shifts.
[FIXED]     Don't set the active user when just importing ubiquity changes, it causes a log-out.
[ADDED]     Mac: Ability to rebuild iCloud.
[REMOVED]   Mac: wasRunning logic to avoid password window appearance on first activation.
[FIXED]     Mac: Retrieve siteName from main thread.
2013-05-10 11:13:55 -04:00
Maarten Billemont
c36f34346d Output info level logs when sendInfo is enabled to aid in debugging. 2013-05-07 16:16:33 -04:00
Maarten Billemont
cd6b83ffe8 iPhone 5 alignment issue in unlock VC.
[FIXED]     Deselect new user avatar if MOC is unavailable when tapping it.
[FIXED]     Position of avatars & spinner on iPhone 5.
[IMPROVED]  Issue button in review dialog.
2013-05-07 13:25:05 -04:00
Maarten Billemont
d110fd18c1 Started checkpoint and executable name revert.
[ADDED]     "Started" checkpoint that logs some platform environment properties.
[REVERTED]  Executable/app name back to just MasterPassword.
2013-05-07 11:22:01 -04:00
Maarten Billemont
e45b9985c2 Mac: New sites.
[MOVED]     Creation of new elements moved to shared code.
[FIXED]     When switching user, unset active key.
[FIXED]     Synchronize content calculation to avoid race issues while typing.
[ADDED]     Ability to create new sites.
[FIXED]     Unset active element when hitting backspace or escape.
2013-05-07 00:48:48 -04:00
Maarten Billemont
8f4eb6df84 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-05-03 23:50:57 -04:00
Maarten Billemont
809bd60169 Info.plist fixes.
[FIXED]     Add extensions to Icon as well to CFBundleIconFiles because Xcode doesn't seem to listen to the Apple docs.
[FIXED]     Removed newsstand metadata: this is not a newsstand app.
2013-05-03 11:29:38 -04:00
Maarten Billemont
802c5949da More compatible way of specifying icon files.
[FIXED]     Add extensions to Icon as well to CFBundleIconFiles because Xcode doesn't seem to listen to the Apple docs.
2013-05-03 10:15:27 -04:00
Maarten Billemont
407c5528ee Fix sign comparison of enum. 2013-05-02 22:03:53 -04:00
Maarten Billemont
fed3a2bc10 Fix sign comparison of enum. 2013-05-02 22:03:53 -04:00
Maarten Billemont
7329353c6c Work-around for a weird Core Data bug. 2013-05-02 22:01:18 -04:00
Maarten Billemont
a7c861d1b0 Work-around for a weird Core Data bug. 2013-05-02 22:01:18 -04:00
Maarten Billemont
9af8ab3360 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-05-02 20:41:46 -04:00
Maarten Billemont
ddb5328019 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-05-02 20:41:46 -04:00
Maarten Billemont
96d97d95e1 New user on Mac.
[ADDED]     Mac: Support for creating a new user.
2013-05-02 20:40:12 -04:00
Maarten Billemont
ab15694d9a Safer migration, boolean description fix.
[ADDED]     Safer store migration: don't delete the old store, allowing the client to downgrade.
[ADDED]     Log checkpoints and send to TestFlight too.
[FIXED]     Describe booleans as YES/NO, not 1/0.
2013-05-02 11:19:34 -04:00
Maarten Billemont
81312e3ff4 Safer migration, boolean description fix.
[ADDED]     Safer store migration: don't delete the old store, allowing the client to downgrade.
[ADDED]     Log checkpoints and send to TestFlight too.
[FIXED]     Describe booleans as YES/NO, not 1/0.
2013-05-02 11:19:34 -04:00
Maarten Billemont
5e1e88bdeb Fancier password dialog.
[ADDED]     Mac: Shadows on labels so they're easier to read in regular mode.
[ADDED]     Mac: Some "subtle" bling on the password.
2013-04-30 21:10:52 -04:00
Maarten Billemont
9882bf408c Content generation fix.
[UPDATED]   For safer MOC usage API.
[FIXED]     Actually set the active element so that content is generated.
2013-04-30 20:49:42 -04:00
Maarten Billemont
40f34f3d77 Avoid using object.managedObjectContext - when no strong reference exists to the MOC, it may yield nil.
[FIXED]     Unexpected nil MOCs.
2013-04-30 01:49:53 -04:00
Maarten Billemont
0ee1e176ed Don't use temporary objectIDs for state.
[FIXED]     Make sure we have permanent ObjectIDs before storing them in state.
[FIXED]     MP-14
2013-04-30 00:32:30 -04:00
Maarten Billemont
c73f89e4a1 App versioning update.
[UPDATED]   App versioning: version is now: decimal short commit hash, short version is now tag+commit number.
2013-04-29 21:24:45 -04:00
Maarten Billemont
fe9a1cdbc4 Log Inspector and trace mode.
[ADDED]     Log Inspector, shake on preference screen to open log.
[ADDED]     Trace Mode: Log at trace level.
[FIXED]     Log messages weren't being recorded for inclusion in feedback.
2013-04-29 21:15:14 -04:00
43 changed files with 1367 additions and 574 deletions

View File

@@ -170,6 +170,16 @@ OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
**/ **/
@property (nonatomic, readonly) NSDate *crashedOnDate; @property (nonatomic, readonly) NSDate *crashedOnDate;
/**
* Returns the os version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSVersion;
/**
* Returns the os build version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSBuildVersion;
@end @end
/** /**

View File

@@ -15,13 +15,13 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>2.0.8</string> <string>2.0.9</string>
<key>CFBundleSupportedPlatforms</key> <key>CFBundleSupportedPlatforms</key>
<array> <array>
<string>iPhoneOS</string> <string>iPhoneOS</string>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0200.08.00</string> <string>0200.09.00</string>
<key>DTPlatformName</key> <key>DTPlatformName</key>
<string>iphoneos</string> <string>iphoneos</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>

2
External/Pearl vendored

View File

@@ -25,7 +25,7 @@
@required @required
- (NSUInteger)version; - (NSUInteger)version;
- (BOOL)migrateUser:(MPUserEntity *)user; - (BOOL)migrateUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc;
- (BOOL)migrateElement:(MPElementEntity *)element explicit:(BOOL)explicit; - (BOOL)migrateElement:(MPElementEntity *)element explicit:(BOOL)explicit;
- (MPKey *)keyForPassword:(NSString *)password ofUserNamed:(NSString *)userName; - (MPKey *)keyForPassword:(NSString *)password ofUserNamed:(NSString *)userName;

View File

@@ -31,12 +31,12 @@
return 0; return 0;
} }
- (BOOL)migrateUser:(MPUserEntity *)user { - (BOOL)migrateUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc {
NSError *error = nil; NSError *error = nil;
NSFetchRequest *migrationRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )]; NSFetchRequest *migrationRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
migrationRequest.predicate = [NSPredicate predicateWithFormat:@"version_ < %d AND user == %@", self.version, user]; migrationRequest.predicate = [NSPredicate predicateWithFormat:@"version_ < %d AND user == %@", self.version, user];
NSArray *migrationElements = [user.managedObjectContext executeFetchRequest:migrationRequest error:&error]; NSArray *migrationElements = [moc executeFetchRequest:migrationRequest error:&error];
if (!migrationElements) { if (!migrationElements) {
err(@"While looking for elements to migrate: %@", error); err(@"While looking for elements to migrate: %@", error);
return NO; return NO;

View File

@@ -10,7 +10,7 @@
@interface MPAppDelegate_Shared(Key) @interface MPAppDelegate_Shared(Key)
- (BOOL)signInAsUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc usingMasterPassword:(NSString *)password; - (BOOL)signInAsUser:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc usingMasterPassword:(NSString *)password;
- (void)signOutAnimated:(BOOL)animated; - (void)signOutAnimated:(BOOL)animated;
- (void)storeSavedKeyFor:(MPUserEntity *)user; - (void)storeSavedKeyFor:(MPUserEntity *)user;

View File

@@ -77,7 +77,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
[[NSNotificationCenter defaultCenter] postNotificationName:MPSignedOutNotification object:self userInfo:@{ @"animated" : @(animated) }]; [[NSNotificationCenter defaultCenter] postNotificationName:MPSignedOutNotification object:self userInfo:@{ @"animated" : @(animated) }];
} }
- (BOOL)signInAsUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc usingMasterPassword:(NSString *)password { - (BOOL)signInAsUser:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc usingMasterPassword:(NSString *)password {
if (password) if (password)
NSAssert(![NSThread isMainThread], @"Computing key may not happen from the main thread."); NSAssert(![NSThread isMainThread], @"Computing key may not happen from the main thread.");

View File

@@ -44,6 +44,10 @@
- (void)setActiveUser:(MPUserEntity *)activeUser { - (void)setActiveUser:(MPUserEntity *)activeUser {
NSError *error;
if (activeUser.objectID.isTemporaryID && ![activeUser.managedObjectContext obtainPermanentIDsForObjects:@[ activeUser ] error:&error])
err(@"Failed to obtain a permanent object ID after setting active user: %@", error);
_activeUserOID = activeUser.objectID; _activeUserOID = activeUser.objectID;
} }

View File

@@ -25,6 +25,8 @@ typedef enum {
+ (BOOL)managedObjectContextPerformBlockAndWait:(void (^)(NSManagedObjectContext *))mocBlock; + (BOOL)managedObjectContextPerformBlockAndWait:(void (^)(NSManagedObjectContext *))mocBlock;
- (UbiquityStoreManager *)storeManager; - (UbiquityStoreManager *)storeManager;
- (void)addElementNamed:(NSString *)siteName completion:(void (^)(MPElementEntity *element))completion;
- (MPImportResult)importSites:(NSString *)importedSitesString - (MPImportResult)importSites:(NSString *)importedSitesString
askImportPassword:(NSString *(^)(NSString *userName))importPassword askImportPassword:(NSString *(^)(NSString *userName))importPassword
askUserPassword:(NSString *(^)(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))userPassword; askUserPassword:(NSString *(^)(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))userPassword;

View File

@@ -15,12 +15,24 @@
#define STORE_OPTIONS #define STORE_OPTIONS
#endif #endif
#define MPCloudContainerIdentifier @"HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.shared"
#define MPMigrationLevelLocalStoreKey @"MPMigrationLevelLocalStoreKey"
#define MPMigrationLevelCloudStoreKey @"MPMigrationLevelCloudStoreKey"
typedef NS_ENUM(NSInteger, MPMigrationLevelLocalStore) {
MPMigrationLevelLocalStoreV1,
MPMigrationLevelLocalStoreV2,
MPMigrationLevelLocalStoreCurrent = MPMigrationLevelLocalStoreV2,
};
typedef NS_ENUM(NSInteger, MPMigrationLevelCloudStore) {
MPMigrationLevelCloudStoreV1,
MPMigrationLevelCloudStoreV2,
MPMigrationLevelCloudStoreV3,
MPMigrationLevelCloudStoreCurrent = MPMigrationLevelCloudStoreV3,
};
@implementation MPAppDelegate_Shared(Store) @implementation MPAppDelegate_Shared(Store)
#if TARGET_OS_IPHONE
PearlAssociatedObjectProperty(PearlAlert*, HandleCloudContentAlert, handleCloudContentAlert);
PearlAssociatedObjectProperty(PearlAlert*, FixCloudContentAlert, fixCloudContentAlert);
PearlAssociatedObjectProperty(PearlOverlay*, StoreLoading, storeLoading);
#endif
PearlAssociatedObjectProperty(NSManagedObjectContext*, PrivateManagedObjectContext, privateManagedObjectContext); PearlAssociatedObjectProperty(NSManagedObjectContext*, PrivateManagedObjectContext, privateManagedObjectContext);
PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, mainManagedObjectContext); PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, mainManagedObjectContext);
@@ -91,7 +103,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
return storeManager; return storeManager;
storeManager = [[UbiquityStoreManager alloc] initStoreNamed:nil withManagedObjectModel:nil localStoreURL:nil storeManager = [[UbiquityStoreManager alloc] initStoreNamed:nil withManagedObjectModel:nil localStoreURL:nil
containerIdentifier:@"HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.shared" containerIdentifier:MPCloudContainerIdentifier
additionalStoreOptions:@{ STORE_OPTIONS } additionalStoreOptions:@{ STORE_OPTIONS }
delegate:self]; delegate:self];
@@ -99,18 +111,21 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification
object:[UIApplication sharedApplication] queue:nil object:[UIApplication sharedApplication] queue:nil
usingBlock:^(NSNotification *note) { usingBlock:^(NSNotification *note) {
[self saveContexts]; [[self mainManagedObjectContext] saveToStore];
}]; }];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification
object:[UIApplication sharedApplication] queue:nil object:[UIApplication sharedApplication] queue:nil
usingBlock:^(NSNotification *note) { usingBlock:^(NSNotification *note) {
[self saveContexts]; [[self mainManagedObjectContext] saveToStore];
}]; }];
#else #else
[[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillTerminateNotification [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillTerminateNotification
object:[NSApplication sharedApplication] queue:nil object:[NSApplication sharedApplication] queue:nil
usingBlock:^(NSNotification *note) { usingBlock:^(NSNotification *note) {
[self saveContexts]; NSManagedObjectContext *moc = self.mainManagedObjectContextIfReady;
[moc performBlockAndWait:^{
[moc saveToStore];
}];
}]; }];
#endif #endif
@@ -119,33 +134,113 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
- (void)migrateStoreForManager:(UbiquityStoreManager *)manager isCloud:(BOOL)isCloudStore { - (void)migrateStoreForManager:(UbiquityStoreManager *)manager isCloud:(BOOL)isCloudStore {
[self migrateLocalStoreForManager:manager]; [self migrateLocalStore];
if (isCloudStore) if (isCloudStore)
[self migrateCloudStoreForManager:manager]; [self migrateCloudStore];
} }
- (void)migrateLocalStoreForManager:(UbiquityStoreManager *)manager { - (void)migrateLocalStore {
MPMigrationLevelLocalStore migrationLevel = (signed)[[NSUserDefaults standardUserDefaults] integerForKey:MPMigrationLevelLocalStoreKey];
if (migrationLevel >= MPMigrationLevelLocalStoreCurrent)
// Local store up-to-date.
return;
inf(@"Local store migration level: %d (current %d)", (signed)migrationLevel, (signed)MPMigrationLevelLocalStoreCurrent);
if (migrationLevel <= MPMigrationLevelLocalStoreV1)
[self migrateV1LocalStore];
[[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelLocalStoreCurrent forKey:MPMigrationLevelLocalStoreKey];
inf(@"Successfully migrated old to new local store.");
}
- (void)migrateCloudStore {
MPMigrationLevelCloudStore migrationLevel = (signed)[[NSUserDefaults standardUserDefaults] integerForKey:MPMigrationLevelCloudStoreKey];
if (migrationLevel >= MPMigrationLevelCloudStoreCurrent)
// Cloud store up-to-date.
return;
inf(@"Cloud store migration level: %d (current %d)", (signed)migrationLevel, (signed)MPMigrationLevelCloudStoreCurrent);
if (migrationLevel <= MPMigrationLevelCloudStoreV1)
[self migrateV1CloudStore];
else if (migrationLevel <= MPMigrationLevelCloudStoreV2)
[self migrateV2CloudStore];
[[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey];
}
- (void)migrateV1CloudStore {
// Migrate cloud enabled preference.
NSNumber *oldCloudEnabled = [[NSUserDefaults standardUserDefaults] objectForKey:@"iCloudEnabledKey"];
if ([oldCloudEnabled boolValue])
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:USMCloudEnabledKey];
// Migrate cloud store.
NSString *uuid = [[NSUserDefaults standardUserDefaults] stringForKey:@"LocalUUIDKey"];
if (!uuid) {
inf(@"No V1 cloud store to migrate.");
return;
}
inf(@"Migrating V1 cloud store: %@ -> %@", uuid, [self.storeManager valueForKey:@"storeUUID"]);
NSURL *cloudContainerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:MPCloudContainerIdentifier];
NSURL *oldCloudContentURL = [[cloudContainerURL
URLByAppendingPathComponent:@"Data" isDirectory:YES]
URLByAppendingPathComponent:uuid isDirectory:YES];
NSURL *oldCloudStoreURL = [[[cloudContainerURL
URLByAppendingPathComponent:@"Database.nosync" isDirectory:YES]
URLByAppendingPathComponent:uuid isDirectory:NO] URLByAppendingPathExtension:@"sqlite"];
[self migrateFromCloudStore:oldCloudStoreURL cloudContent:oldCloudContentURL contentName:uuid];
}
- (void)migrateV2CloudStore {
// Migrate cloud store.
NSString *uuid = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:@"USMStoreUUIDKey"];
if (!uuid) {
inf(@"No V2 cloud store to migrate.");
return;
}
inf(@"Migrating V2 cloud store: %@ -> %@", uuid, [self.storeManager valueForKey:@"storeUUID"]);
NSURL *cloudContainerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:MPCloudContainerIdentifier];
NSURL *oldCloudContentURL = [[cloudContainerURL
URLByAppendingPathComponent:@"CloudLogs" isDirectory:YES]
URLByAppendingPathComponent:uuid isDirectory:YES];
NSURL *oldCloudStoreURL = [[[cloudContainerURL
URLByAppendingPathComponent:@"CloudStore.nosync" isDirectory:YES]
URLByAppendingPathComponent:uuid isDirectory:NO] URLByAppendingPathExtension:@"sqlite"];
[self migrateFromCloudStore:oldCloudStoreURL cloudContent:oldCloudContentURL contentName:uuid];
}
- (void)migrateV1LocalStore {
NSURL *applicationFilesDirectory = [[[NSFileManager defaultManager] NSURL *applicationFilesDirectory = [[[NSFileManager defaultManager]
URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *oldLocalStoreURL = [[applicationFilesDirectory NSURL *oldLocalStoreURL = [[applicationFilesDirectory
URLByAppendingPathComponent:@"MasterPassword" isDirectory:NO] URLByAppendingPathExtension:@"sqlite"]; URLByAppendingPathComponent:@"MasterPassword" isDirectory:NO] URLByAppendingPathExtension:@"sqlite"];
NSURL *newLocalStoreURL = [manager URLForLocalStore];
if ([newLocalStoreURL isEqual:oldLocalStoreURL]) {
// Old store migration failed earlier and we set the old URL as the manager's local store.
return;
}
if (![[NSFileManager defaultManager] fileExistsAtPath:oldLocalStoreURL.path isDirectory:NO]) { if (![[NSFileManager defaultManager] fileExistsAtPath:oldLocalStoreURL.path isDirectory:NO]) {
// No local store to migrate. inf(@"No V1 local store to migrate.");
return; return;
} }
if ([[NSFileManager defaultManager] fileExistsAtPath:newLocalStoreURL.path isDirectory:NO]) {
wrn(@"Can't migrate old local store: A new local store already exists."); inf(@"Migrating V1 local store");
[self migrateFromLocalStore:oldLocalStoreURL];
}
- (void)migrateFromLocalStore:(NSURL *)oldLocalStoreURL {
NSURL *newLocalStoreURL = [self.storeManager URLForLocalStore];
if ([[NSFileManager defaultManager] fileExistsAtPath:newLocalStoreURL.path isDirectory:NO]) {
wrn(@"Can't migrate local store: A new local store already exists.");
return; return;
} }
inf(@"Migrating local store...");
NSError *error = nil; NSError *error = nil;
NSDictionary *oldLocalStoreOptions = @{ NSDictionary *oldLocalStoreOptions = @{
STORE_OPTIONS STORE_OPTIONS
@@ -159,69 +254,38 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
}; };
// Create the directory to hold the new local store. // Create the directory to hold the new local store.
if (![[NSFileManager defaultManager] createDirectoryAtPath:[manager URLForLocalStoreDirectory].path if (![[NSFileManager defaultManager] createDirectoryAtPath:[self.storeManager URLForLocalStoreDirectory].path
withIntermediateDirectories:YES attributes:nil error:&error]) { withIntermediateDirectories:YES attributes:nil error:&error])
err(@"While creating directory for new local store: %@", error); err(@"While creating directory for new local store: %@", error);
manager.localStoreURL = oldLocalStoreURL;
return;
}
if (![manager copyMigrateStore:oldLocalStoreURL withOptions:oldLocalStoreOptions if (![self.storeManager copyMigrateStore:oldLocalStoreURL withOptions:oldLocalStoreOptions
toStore:newLocalStoreURL withOptions:newLocalStoreOptions toStore:newLocalStoreURL withOptions:newLocalStoreOptions
error:nil cause:nil context:nil]) { error:nil cause:nil context:nil])
manager.localStoreURL = oldLocalStoreURL; return;
inf(@"Successfully migrated to new local store.");
}
- (void)migrateFromCloudStore:(NSURL *)oldCloudStoreURL cloudContent:(NSURL *)oldCloudContentURL contentName:(NSString *)contentName {
if (![self.storeManager cloudSafeForSeeding]) {
inf(@"Can't migrate cloud store: A new cloud store already exists.");
return; return;
} }
inf(@"Successfully migrated old to new local store."); NSURL *newCloudStoreURL = [self.storeManager URLForCloudStore];
} NSURL *newCloudContentURL = [self.storeManager URLForCloudContent];
- (void)migrateCloudStoreForManager:(UbiquityStoreManager *)manager {
// Migrate cloud enabled preference.
NSNumber *oldCloudEnabled = [[NSUserDefaults standardUserDefaults] objectForKey:@"iCloudEnabledKey"];
if ([oldCloudEnabled boolValue]) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:USMCloudEnabledKey];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"iCloudEnabledKey"];
}
// Migrate cloud store.
NSString *uuid = [[NSUserDefaults standardUserDefaults] stringForKey:@"LocalUUIDKey"];
if (!uuid)
// No old cloud store to migrate.
return;
if (![manager cloudSafeForSeeding]) {
wrn(@"Can't migrate old cloud store: A new cloud store already exists.");
return;
}
NSURL *cloudContainerURL = [[NSFileManager defaultManager]
URLForUbiquityContainerIdentifier:@"HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.shared"];
NSURL *newCloudStoreURL = [manager URLForCloudStore];
NSURL *newCloudContentURL = [manager URLForCloudContent];
NSURL *oldCloudContentURL = [[cloudContainerURL URLByAppendingPathComponent:@"Data" isDirectory:YES]
URLByAppendingPathComponent:uuid isDirectory:YES];
NSURL *oldCloudStoreDirectoryURL = [cloudContainerURL URLByAppendingPathComponent:@"Database.nosync" isDirectory:YES];
NSURL *oldCloudStoreURL = [[oldCloudStoreDirectoryURL URLByAppendingPathComponent:uuid isDirectory:NO]
URLByAppendingPathExtension:@"sqlite"];
inf(@"Migrating cloud store: %@ -> %@", uuid, [manager valueForKey:@"storeUUID"]);
NSError *error = nil; NSError *error = nil;
NSDictionary *oldCloudStoreOptions = @{ NSDictionary *oldCloudStoreOptions = @{
STORE_OPTIONS STORE_OPTIONS
// This is here in an attempt to have iCloud recreate the old store file from NSPersistentStoreUbiquitousContentNameKey : contentName,
// the baseline and transaction logs from the iCloud account.
// In my tests however only the baseline was used to recreate the store which then ended up being empty.
NSPersistentStoreUbiquitousContentNameKey : uuid,
NSPersistentStoreUbiquitousContentURLKey : oldCloudContentURL, NSPersistentStoreUbiquitousContentURLKey : oldCloudContentURL,
// So instead, we'll just open up the old store as read-only, if it exists.
NSReadOnlyPersistentStoreOption : @YES,
NSInferMappingModelAutomaticallyOption : @YES NSInferMappingModelAutomaticallyOption : @YES
}; };
NSDictionary *newCloudStoreOptions = @{ NSDictionary *newCloudStoreOptions = @{
STORE_OPTIONS STORE_OPTIONS
NSPersistentStoreUbiquitousContentNameKey : [manager valueForKey:@"contentName"], NSPersistentStoreUbiquitousContentNameKey : [self.storeManager valueForKey:@"contentName"],
NSPersistentStoreUbiquitousContentURLKey : newCloudContentURL, NSPersistentStoreUbiquitousContentURLKey : newCloudContentURL,
NSMigratePersistentStoresAutomaticallyOption : @YES, NSMigratePersistentStoresAutomaticallyOption : @YES,
NSInferMappingModelAutomaticallyOption : @YES NSInferMappingModelAutomaticallyOption : @YES
@@ -229,48 +293,32 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
// Create the directory to hold the new cloud store. // Create the directory to hold the new cloud store.
// This is only necessary if we want to try to rebuild the old store. See comment above about how that failed. // This is only necessary if we want to try to rebuild the old store. See comment above about how that failed.
if (![[NSFileManager defaultManager] createDirectoryAtPath:oldCloudStoreDirectoryURL.path if (![[NSFileManager defaultManager] createDirectoryAtPath:[oldCloudStoreURL URLByDeletingLastPathComponent].path
withIntermediateDirectories:YES attributes:nil error:&error]) { withIntermediateDirectories:YES attributes:nil error:&error])
err(@"While creating directory for old cloud store: %@", error); err(@"While creating directory for old cloud store: %@", error);
return; if (![[NSFileManager defaultManager] createDirectoryAtPath:oldCloudContentURL.path
} withIntermediateDirectories:YES attributes:nil error:&error])
if (![[NSFileManager defaultManager] createDirectoryAtPath:[manager URLForCloudStoreDirectory].path err(@"While creating directory for old cloud content: %@", error);
withIntermediateDirectories:YES attributes:nil error:&error]) { if (![[NSFileManager defaultManager] createDirectoryAtPath:[self.storeManager URLForCloudStoreDirectory].path
withIntermediateDirectories:YES attributes:nil error:&error])
err(@"While creating directory for new cloud store: %@", error); err(@"While creating directory for new cloud store: %@", error);
return; if (![[NSFileManager defaultManager] createDirectoryAtPath:[self.storeManager URLForCloudContent].path
} withIntermediateDirectories:YES attributes:nil error:&error])
err(@"While creating directory for new cloud content: %@", error);
if (![manager copyMigrateStore:oldCloudStoreURL withOptions:oldCloudStoreOptions if (![self.storeManager copyMigrateStore:oldCloudStoreURL withOptions:oldCloudStoreOptions
toStore:newCloudStoreURL withOptions:newCloudStoreOptions toStore:newCloudStoreURL withOptions:newCloudStoreOptions
error:nil cause:nil context:nil]) error:nil cause:nil context:nil])
return; return;
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"LocalUUIDKey"]; inf(@"Successfully migrated to new cloud store.");
inf(@"Successfully migrated old to new cloud store.");
}
- (void)saveContexts {
NSManagedObjectContext *mainManagedObjectContext = self.mainManagedObjectContext;
[mainManagedObjectContext performBlockAndWait:^{
NSError *error = nil;
if (![mainManagedObjectContext save:&error])
err(@"While saving main context: %@", error);
}];
NSManagedObjectContext *privateManagedObjectContext = [self privateManagedObjectContextIfReady];
[privateManagedObjectContext performBlockAndWait:^{
NSError *error = nil;
if (![privateManagedObjectContext save:&error])
err(@"While saving private context: %@", error);
}];
} }
#pragma mark - UbiquityStoreManagerDelegate #pragma mark - UbiquityStoreManagerDelegate
- (NSManagedObjectContext *)managedObjectContextForUbiquityStoreManager:(UbiquityStoreManager *)usm { - (NSManagedObjectContext *)managedObjectContextForUbiquityChangesInManager:(UbiquityStoreManager *)manager {
return [self privateManagedObjectContextIfReady]; return [self mainManagedObjectContextIfReady];
} }
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager log:(NSString *)message { - (void)ubiquityStoreManager:(UbiquityStoreManager *)manager log:(NSString *)message {
@@ -280,15 +328,13 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager willLoadStoreIsCloud:(BOOL)isCloudStore { - (void)ubiquityStoreManager:(UbiquityStoreManager *)manager willLoadStoreIsCloud:(BOOL)isCloudStore {
NSManagedObjectContext *moc = [self mainManagedObjectContextIfReady];
[moc performBlockAndWait:^{
[moc saveToStore];
self.privateManagedObjectContext = nil; self.privateManagedObjectContext = nil;
self.mainManagedObjectContext = nil; self.mainManagedObjectContext = nil;
}];
#if TARGET_OS_IPHONE
dispatch_async( dispatch_get_main_queue(), ^{
if (![self.storeLoading isVisible])
self.storeLoading = [PearlOverlay showOverlayWithTitle:@"Opening Your Data"];
} );
#endif
[self migrateStoreForManager:manager isCloud:isCloudStore]; [self migrateStoreForManager:manager isCloud:isCloudStore];
} }
@@ -307,6 +353,20 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
[privateManagedObjectContext performBlockAndWait:^{ [privateManagedObjectContext performBlockAndWait:^{
privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy; privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
privateManagedObjectContext.persistentStoreCoordinator = coordinator; privateManagedObjectContext.persistentStoreCoordinator = coordinator;
// dbg(@"===");
// NSError *error;
// for (NSEntityDescription *entityDescription in [coordinator.managedObjectModel entities]) {
// dbg(@"Entities: %@", entityDescription.name);
// NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:entityDescription.name];
// NSArray *entities = [privateManagedObjectContext executeFetchRequest:request error:&error];
// if (!entities)
// err(@" - Error: %@", error);
// else
// for (id entity in entities)
// dbg(@" - %@", [entity debugDescription]);
// }
// dbg(@"===");
}]; }];
NSManagedObjectContext *mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; NSManagedObjectContext *mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
@@ -314,12 +374,6 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
self.privateManagedObjectContext = privateManagedObjectContext; self.privateManagedObjectContext = privateManagedObjectContext;
self.mainManagedObjectContext = mainManagedObjectContext; self.mainManagedObjectContext = mainManagedObjectContext;
#if TARGET_OS_IPHONE
[self.handleCloudContentAlert cancelAlertAnimated:YES];
[self.fixCloudContentAlert cancelAlertAnimated:YES];
[self.storeLoading cancelOverlay];
#endif
} }
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didEncounterError:(NSError *)error cause:(UbiquityStoreErrorCause)cause - (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didEncounterError:(NSError *)error cause:(UbiquityStoreErrorCause)cause
@@ -333,47 +387,44 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
} ); } );
} }
- (BOOL)ubiquityStoreManager:(UbiquityStoreManager *)manager handleCloudContentCorruptionWithHealthyStore:(BOOL)storeHealthy { #pragma mark - Utilities
#if TARGET_OS_IPHONE - (void)addElementNamed:(NSString *)siteName completion:(void (^)(MPElementEntity *element))completion {
if (manager.cloudEnabled && !storeHealthy && !([self.handleCloudContentAlert.alertView isVisible] || [self.fixCloudContentAlert.alertView isVisible]))
if (![siteName length]) {
completion( nil );
return;
}
[MPAppDelegate_Shared managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
MPUserEntity *activeUser = [self activeUserInContext:moc];
assert(activeUser);
MPElementType type = activeUser.defaultType;
if (!type)
type = activeUser.defaultType = MPElementTypeGeneratedLong;
NSString *typeEntityClassName = [MPAlgorithmDefault classNameOfType:type];
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityClassName
inManagedObjectContext:moc];
element.name = siteName;
element.user = activeUser;
element.type = type;
element.lastUsed = [NSDate date];
element.version = MPAlgorithmDefaultVersion;
[moc saveToStore];
NSError *error = nil;
if (element.objectID.isTemporaryID && ![moc obtainPermanentIDsForObjects:@[ element ] error:&error])
err(@"Failed to obtain a permanent object ID after creating new element: %@", error);
NSManagedObjectID *elementOID = [element objectID];
dispatch_async( dispatch_get_main_queue(), ^{ dispatch_async( dispatch_get_main_queue(), ^{
[self showCloudContentAlert]; completion( (MPElementEntity *)[[MPAppDelegate_Shared managedObjectContextForThreadIfReady] objectRegisteredForID:elementOID] );
} ); } );
#endif
return NO;
}
#if TARGET_OS_IPHONE
- (void)showCloudContentAlert {
__weak MPAppDelegate_Shared *wSelf = self;
[self.handleCloudContentAlert cancelAlertAnimated:NO];
self.handleCloudContentAlert = [PearlAlert showActivityWithTitle:@"iCloud Sync Problem" message:
@"Waiting for your other device to autocorrect the problem..."
initAlert:^(UIAlertView *alert) {
[alert addButtonWithTitle:@"Fix Now"];
}]; }];
self.handleCloudContentAlert.tappedButtonBlock = ^(UIAlertView *alert, NSInteger buttonIndex) {
wSelf.fixCloudContentAlert = [PearlAlert showAlertWithTitle:@"Fix iCloud Now" message:
@"This problem can usually be autocorrected by opening the app on another device where you recently made changes.\n"
@"You can correct the problem from this device anyway, but recent changes made on another device might get lost."
viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:
^(UIAlertView *alert_, NSInteger buttonIndex_) {
if (buttonIndex_ == alert_.cancelButtonIndex)
[wSelf showCloudContentAlert];
if (buttonIndex_ == [alert_ firstOtherButtonIndex])
[wSelf.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:YES];
} }
cancelTitle:[PearlStrings get].commonButtonBack otherTitles:@"Fix Anyway", nil];
};
}
#endif
#pragma mark - Import / Export
- (MPImportResult)importSites:(NSString *)importedSitesString - (MPImportResult)importSites:(NSString *)importedSitesString
askImportPassword:(NSString *(^)(NSString *userName))importPassword askImportPassword:(NSString *(^)(NSString *userName))importPassword
@@ -493,6 +544,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
NSString *uses = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:2]]; NSString *uses = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:2]];
NSString *type = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:3]]; NSString *type = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:3]];
NSString *version = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:4]]; NSString *version = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:4]];
if ([version length])
version = [version substringFromIndex:1]; // Strip the leading colon.
NSString *name = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:5]]; NSString *name = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:5]];
NSString *exportContent = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:6]]; NSString *exportContent = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:6]];
@@ -509,6 +562,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
[elementsToDelete addObjectsFromArray:existingSites]; [elementsToDelete addObjectsFromArray:existingSites];
[importedSiteElements addObject:@[ lastUsed, uses, type, version, name, exportContent ]]; [importedSiteElements addObject:@[ lastUsed, uses, type, version, name, exportContent ]];
dbg(@"Will import site: lastUsed=%@, uses=%@, type=%@, version=%@, name=%@, exportContent=%@",
lastUsed, uses, type, version, name, exportContent);
} }
} }

View File

@@ -13,11 +13,12 @@
- (BOOL)saveToStore { - (BOOL)saveToStore {
NSError *error; __block BOOL success = NO;
if (![self save:&error]) { [self performBlockAndWait:^{
NSError *error = nil;
if (!(success = [self save:&error]))
err(@"While saving: %@", error); err(@"While saving: %@", error);
return NO; }];
}
return !self.parentContext || [self.parentContext saveToStore]; return !self.parentContext || [self.parentContext saveToStore];
} }

View File

@@ -68,6 +68,8 @@ typedef enum {
#define MPCheckpointApps @"MPCheckpointApps" #define MPCheckpointApps @"MPCheckpointApps"
#define MPCheckpointApp @"MPCheckpointApp" #define MPCheckpointApp @"MPCheckpointApp"
#define MPCheckpointEmergencyGenerator @"MPCheckpointEmergencyGenerator" #define MPCheckpointEmergencyGenerator @"MPCheckpointEmergencyGenerator"
#define MPCheckpointLogs @"MPCheckpointLogs"
#define MPCheckpointStarted @"MPCheckpointStarted"
#define MPSignedInNotification @"MPSignedInNotification" #define MPSignedInNotification @"MPSignedInNotification"
#define MPSignedOutNotification @"MPSignedOutNotification" #define MPSignedOutNotification @"MPSignedOutNotification"
@@ -77,7 +79,11 @@ typedef enum {
static void MPCheckpoint(NSString *checkpoint, NSDictionary *attributes) { static void MPCheckpoint(NSString *checkpoint, NSDictionary *attributes) {
inf(@"%@: %@", checkpoint, attributes);
#ifdef LOCALYTICS #ifdef LOCALYTICS
[[LocalyticsSession sharedLocalyticsSession] tagEvent:checkpoint attributes:attributes]; [[LocalyticsSession sharedLocalyticsSession] tagEvent:checkpoint attributes:attributes];
#endif #endif
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:checkpoint];
#endif
} }

View File

@@ -25,9 +25,10 @@
@property(nonatomic, weak) IBOutlet NSMenuItem *dialogStyleRegular; @property(nonatomic, weak) IBOutlet NSMenuItem *dialogStyleRegular;
@property(nonatomic, weak) IBOutlet NSMenuItem *dialogStyleHUD; @property(nonatomic, weak) IBOutlet NSMenuItem *dialogStyleHUD;
- (IBAction)activate:(id)sender; - (IBAction)showPasswordWindow;
- (IBAction)togglePreference:(NSMenuItem *)sender; - (IBAction)togglePreference:(NSMenuItem *)sender;
- (IBAction)newUser:(NSMenuItem *)sender; - (IBAction)newUser:(NSMenuItem *)sender;
- (IBAction)lock:(id)sender; - (IBAction)lock:(id)sender;
- (IBAction)rebuildCloud:(id)sender;
@end @end

View File

@@ -11,12 +11,6 @@
#import "MPAppDelegate_Store.h" #import "MPAppDelegate_Store.h"
#import <Carbon/Carbon.h> #import <Carbon/Carbon.h>
@interface MPMacAppDelegate()
@property(nonatomic) BOOL wasRunning;
@end
@implementation MPMacAppDelegate @implementation MPMacAppDelegate
#pragma clang diagnostic push #pragma clang diagnostic push
@@ -46,7 +40,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
// Check which hotkey this was. // Check which hotkey this was.
if (hotKeyID.signature == MPShowHotKey.signature && hotKeyID.id == MPShowHotKey.id) { if (hotKeyID.signature == MPShowHotKey.signature && hotKeyID.id == MPShowHotKey.id) {
[((__bridge MPMacAppDelegate *)userData) activate:nil]; [((__bridge MPMacAppDelegate *)userData) showPasswordWindow];
return noErr; return noErr;
} }
if (hotKeyID.signature == MPLockHotKey.signature && hotKeyID.id == MPLockHotKey.id) { if (hotKeyID.signature == MPLockHotKey.signature && hotKeyID.id == MPLockHotKey.id) {
@@ -92,19 +86,24 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
@"Then give iCloud some time to sync the new user to your Mac."; @"Then give iCloud some time to sync the new user to your Mac.";
} }
MPUserEntity *activeUser = self.activeUserForThread;
for (MPUserEntity *user in users) { for (MPUserEntity *user in users) {
NSMenuItem *userItem = [[NSMenuItem alloc] initWithTitle:user.name action:@selector(selectUser:) keyEquivalent:@""]; NSMenuItem *userItem = [[NSMenuItem alloc] initWithTitle:user.name action:@selector(selectUser:) keyEquivalent:@""];
[userItem setTarget:self]; [userItem setTarget:self];
[userItem setRepresentedObject:[user objectID]]; [userItem setRepresentedObject:[user objectID]];
[[self.usersItem submenu] addItem:userItem]; [[self.usersItem submenu] addItem:userItem];
if ([user.name isEqualToString:[MPMacConfig get].usedUserName]) if (!activeUser && [user.name isEqualToString:[MPMacConfig get].usedUserName])
[self selectUser:userItem]; [self selectUser:userItem];
} }
[self updateMenuItems];
} }
- (void)selectUser:(NSMenuItem *)item { - (void)selectUser:(NSMenuItem *)item {
[self signOutAnimated:NO];
NSError *error = nil; NSError *error = nil;
NSManagedObjectContext *moc = [MPMacAppDelegate managedObjectContextForThreadIfReady]; NSManagedObjectContext *moc = [MPMacAppDelegate managedObjectContextForThreadIfReady];
self.activeUser = (MPUserEntity *)[moc existingObjectWithID:[item representedObject] error:&error]; self.activeUser = (MPUserEntity *)[moc existingObjectWithID:[item representedObject] error:&error];
@@ -120,18 +119,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
[self.statusItem popUpStatusItemMenu:self.statusMenu]; [self.statusItem popUpStatusItemMenu:self.statusMenu];
} }
- (IBAction)activate:(id)sender {
if (![self activeUserForThread])
// No user, can't activate.
return;
if ([[NSApplication sharedApplication] isActive])
[self applicationDidBecomeActive:nil];
else
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
}
- (IBAction)togglePreference:(NSMenuItem *)sender { - (IBAction)togglePreference:(NSMenuItem *)sender {
if (sender == self.useICloudItem) if (sender == self.useICloudItem)
@@ -139,12 +126,13 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
if (sender == self.rememberPasswordItem) if (sender == self.rememberPasswordItem)
[MPConfig get].rememberLogin = [NSNumber numberWithBool:![[MPConfig get].rememberLogin boolValue]]; [MPConfig get].rememberLogin = [NSNumber numberWithBool:![[MPConfig get].rememberLogin boolValue]];
if (sender == self.savePasswordItem) { if (sender == self.savePasswordItem) {
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserForThread]; NSManagedObjectContext *moc = [MPMacAppDelegate managedObjectContextForThreadIfReady];
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:moc];
if ((activeUser.saveKey = !activeUser.saveKey)) if ((activeUser.saveKey = !activeUser.saveKey))
[[MPMacAppDelegate get] storeSavedKeyFor:activeUser]; [[MPMacAppDelegate get] storeSavedKeyFor:activeUser];
else else
[[MPMacAppDelegate get] forgetSavedKeyFor:activeUser]; [[MPMacAppDelegate get] forgetSavedKeyFor:activeUser];
[activeUser.managedObjectContext saveToStore]; [moc saveToStore];
} }
if (sender == self.dialogStyleRegular) if (sender == self.dialogStyleRegular)
[MPMacConfig get].dialogStyleHUD = @NO; [MPMacConfig get].dialogStyleHUD = @NO;
@@ -153,6 +141,35 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
} }
- (IBAction)newUser:(NSMenuItem *)sender { - (IBAction)newUser:(NSMenuItem *)sender {
NSAlert *alert = [NSAlert alertWithMessageText:@"New User"
defaultButton:@"Create User" alternateButton:nil otherButton:@"Cancel"
informativeTextWithFormat:@"To begin, enter your full name.\n\n"
@"IMPORTANT: Enter your name correctly, including the right capitalization, "
@"as you would on an official document."];
NSTextField *nameField = [[NSTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
[alert setAccessoryView:nameField];
[alert layout];
[nameField becomeFirstResponder];
if ([alert runModal] != NSAlertDefaultReturn)
return;
NSString *name = [(NSSecureTextField *)alert.accessoryView stringValue];
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
MPUserEntity *newUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass( [MPUserEntity class] )
inManagedObjectContext:moc];
newUser.name = name;
[moc saveToStore];
NSError *error = nil;
if (![moc obtainPermanentIDsForObjects:@[ newUser ] error:&error])
err(@"Failed to obtain permanent object ID for new user: %@", error);
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self updateUsers];
[self setActiveUser:newUser];
[self showPasswordWindow];
}];
}];
} }
- (IBAction)lock:(id)sender { - (IBAction)lock:(id)sender {
@@ -160,6 +177,16 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
self.key = nil; self.key = nil;
} }
- (IBAction)rebuildCloud:(id)sender {
if ([[NSAlert alertWithMessageText:@"iCloud Truth Sync" defaultButton:@"Continue"
alternateButton:nil otherButton:@"Cancel"
informativeTextWithFormat:@"This action will force all your iCloud enabled devices to revert to this device's version of the truth."
@"\n\nThis is only necessary if you notice that your devices aren't syncing properly anymore. "
"Any data on other devices not available from here will be lost."] runModal] == NSAlertDefaultReturn)
[self.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:NO];
}
- (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)oldValue { - (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)oldValue {
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
@@ -188,12 +215,12 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
self.statusItem.target = self; self.statusItem.target = self;
self.statusItem.action = @selector(showMenu); self.statusItem.action = @selector(showMenu);
[[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock: [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock:
^(NSNotification *note) { ^(NSNotification *note) {
[self updateUsers]; [self updateUsers];
}]; }];
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
addObserverForName:UbiquityManagedStoreDidImportChangesNotification object:nil queue:nil usingBlock: addObserverForName:USMStoreDidImportChangesNotification object:nil queue:nil usingBlock:
^(NSNotification *note) { ^(NSNotification *note) {
[self updateUsers]; [self updateUsers];
}]; }];
@@ -315,21 +342,25 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
- (void)applicationDidBecomeActive:(NSNotification *)notification { - (void)applicationDidBecomeActive:(NSNotification *)notification {
[self showPasswordWindow]; // [self showPasswordWindow];
} }
- (void)showPasswordWindow { - (IBAction)showPasswordWindow {
// If no user, can't activate.
if (![self activeUserForThread])
return;
// Activate the app if not active.
if (![[NSApplication sharedApplication] isActive])
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
// Don't show window if we weren't already running (ie. if we haven't been activated before). // Don't show window if we weren't already running (ie. if we haven't been activated before).
if (!self.wasRunning)
self.wasRunning = YES;
else {
if (!self.passwordWindow) if (!self.passwordWindow)
self.passwordWindow = [[MPPasswordWindowController alloc] initWithWindowNibName:@"MPPasswordWindowController"]; self.passwordWindow = [[MPPasswordWindowController alloc] initWithWindowNibName:@"MPPasswordWindowController"];
[self.passwordWindow showWindow:self]; [self.passwordWindow showWindow:self];
} }
}
- (void)applicationWillResignActive:(NSNotification *)notification { - (void)applicationWillResignActive:(NSNotification *)notification {

View File

@@ -13,12 +13,14 @@
#define MPAlertUnlockMP @"MPAlertUnlockMP" #define MPAlertUnlockMP @"MPAlertUnlockMP"
#define MPAlertIncorrectMP @"MPAlertIncorrectMP" #define MPAlertIncorrectMP @"MPAlertIncorrectMP"
#define MPAlertCreateSite @"MPAlertCreateSite"
@interface MPPasswordWindowController() @interface MPPasswordWindowController()
@property(nonatomic) BOOL inProgress; @property(nonatomic) BOOL inProgress;
@property(nonatomic) BOOL siteFieldPreventCompletion; @property(nonatomic) BOOL siteFieldPreventCompletion;
@property(nonatomic, strong) NSOperationQueue *backgroundQueue;
@end @end
@implementation MPPasswordWindowController { @implementation MPPasswordWindowController {
@@ -32,6 +34,9 @@
else else
self.window.styleMask = NSTexturedBackgroundWindowMask | NSResizableWindowMask | NSTitledWindowMask | NSClosableWindowMask; self.window.styleMask = NSTexturedBackgroundWindowMask | NSResizableWindowMask | NSTitledWindowMask | NSClosableWindowMask;
self.backgroundQueue = [NSOperationQueue new];
self.backgroundQueue.maxConcurrentOperationCount = 1;
[self setContent:@""]; [self setContent:@""];
[self.tipField setStringValue:@""]; [self.tipField setStringValue:@""];
@@ -48,6 +53,8 @@
// } forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil]; // } forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil];
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
addObserverForName:NSWindowDidBecomeKeyNotification object:self.window queue:nil usingBlock:^(NSNotification *note) { addObserverForName:NSWindowDidBecomeKeyNotification object:self.window queue:nil usingBlock:^(NSNotification *note) {
if (![MPMacAppDelegate managedObjectContextForThreadIfReady])
[self waitUntilStoreLoaded];
if (!self.inProgress) if (!self.inProgress)
[self unlock]; [self unlock];
[self.siteField selectText:self]; [self.siteField selectText:self];
@@ -58,28 +65,37 @@
}]; }];
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
addObserverForName:MPSignedOutNotification object:nil queue:nil usingBlock:^(NSNotification *note) { addObserverForName:MPSignedOutNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
_activeElementOID = nil;
[self.window close]; [self.window close];
}]; }];
[[NSNotificationCenter defaultCenter]
addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
[self waitUntilStoreLoaded];
}];
[super windowDidLoad]; [super windowDidLoad];
} }
- (void)waitUntilStoreLoaded {
}
- (void)unlock { - (void)unlock {
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserForThread]; NSManagedObjectContext *moc = [MPMacAppDelegate managedObjectContextForThreadIfReady];
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:moc];
if (!activeUser) if (!activeUser)
// No user to sign in with. // No user to sign in with.
return; return;
if ([MPMacAppDelegate get].key) if ([MPMacAppDelegate get].key)
// Already logged in. // Already logged in.
return; return;
if ([[MPMacAppDelegate get] signInAsUser:activeUser usingMasterPassword:nil]) if ([[MPMacAppDelegate get] signInAsUser:activeUser saveInContext:moc usingMasterPassword:nil])
// Load the key from the keychain. // Load the key from the keychain.
return; return;
if (![MPMacAppDelegate get].key) if (![MPMacAppDelegate get].key)
// Ask the user to set the key through his master password. // Ask the user to set the key through his master password.
dispatch_async( dispatch_get_main_queue(), ^{ [[NSOperationQueue mainQueue] addOperationWithBlock:^{
if ([MPMacAppDelegate get].key) if ([MPMacAppDelegate get].key)
return; return;
@@ -97,7 +113,7 @@
[passwordField becomeFirstResponder]; [passwordField becomeFirstResponder];
[alert beginSheetModalForWindow:self.window modalDelegate:self [alert beginSheetModalForWindow:self.window modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertUnlockMP]; didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertUnlockMP];
} ); }];
} }
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { - (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
@@ -107,11 +123,11 @@
return; return;
} }
if (contextInfo == MPAlertUnlockMP) { if (contextInfo == MPAlertUnlockMP) {
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserForThread]; NSManagedObjectContext *moc = [MPMacAppDelegate managedObjectContextForThreadIfReady];
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:moc];
switch (returnCode) { switch (returnCode) {
case NSAlertAlternateReturn: case NSAlertAlternateReturn: {
// "Change" button. // "Change" button.
{
NSInteger returnCode_ = [[NSAlert NSInteger returnCode_ = [[NSAlert
alertWithMessageText:@"Changing Master Password" defaultButton:nil alertWithMessageText:@"Changing Master Password" defaultButton:nil
alternateButton:[PearlStrings get].commonButtonCancel otherButton:nil informativeTextWithFormat: alternateButton:[PearlStrings get].commonButtonCancel otherButton:nil informativeTextWithFormat:
@@ -126,39 +142,48 @@
activeUser.keyID = nil; activeUser.keyID = nil;
[[MPMacAppDelegate get] forgetSavedKeyFor:activeUser]; [[MPMacAppDelegate get] forgetSavedKeyFor:activeUser];
[[MPMacAppDelegate get] signOutAnimated:YES]; [[MPMacAppDelegate get] signOutAnimated:YES];
} [moc saveToStore];
} }
break; break;
}
case NSAlertOtherReturn: case NSAlertOtherReturn: {
// "Cancel" button. // "Cancel" button.
[self.window close]; [self.window close];
return; return;
}
case NSAlertDefaultReturn: { case NSAlertDefaultReturn: {
// "Unlock" button. // "Unlock" button.
self.contentContainer.alphaValue = 0; self.contentContainer.alphaValue = 0;
[self.progressView startAnimation:nil]; [self.progressView startAnimation:nil];
self.inProgress = YES; self.inProgress = YES;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0 ), ^{
BOOL success = [[MPMacAppDelegate get] signInAsUser:activeUser NSString *password = [(NSSecureTextField *)alert.accessoryView stringValue];
usingMasterPassword:[(NSSecureTextField *)alert.accessoryView stringValue]]; [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc_) {
NSError *error = nil;
MPUserEntity *activeUser_ = (MPUserEntity *)[moc_ existingObjectWithID:activeUser.objectID error:&error];
if (!activeUser_)
err(@"Failed to retrieve active use while logging in: %@", error);
BOOL success = [[MPMacAppDelegate get] signInAsUser:activeUser saveInContext:moc_
usingMasterPassword:password];
self.inProgress = NO; self.inProgress = NO;
dispatch_async( dispatch_get_main_queue(), ^{ [[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self.progressView stopAnimation:nil]; [self.progressView stopAnimation:nil];
if (success) if (success)
self.contentContainer.alphaValue = 1; self.contentContainer.alphaValue = 1;
else { else {
[[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{ [[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{
NSLocalizedDescriptionKey : PearlString( @"Incorrect master password for user %@", NSLocalizedDescriptionKey : PearlString( @"Incorrect master password for user %@", activeUser.name )
activeUser.name )
}]] beginSheetModalForWindow:self.window modalDelegate:self }]] beginSheetModalForWindow:self.window modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertIncorrectMP]; didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertIncorrectMP];
} }
} ); }];
} ); }];
break;
} }
default: default:
@@ -167,12 +192,27 @@
return; return;
} }
if (contextInfo == MPAlertCreateSite) {
switch (returnCode) {
case NSAlertDefaultReturn: {
[[MPMacAppDelegate get] addElementNamed:[self.siteField stringValue] completion:^(MPElementEntity *element) {
if (element) {
_activeElementOID = element.objectID;
[self trySiteWithAction:NO];
}
}];
break;
}
default:
break;
}
}
} }
- (NSArray *)control:(NSControl *)control textView:(NSTextView *)textView completions:(NSArray *)words - (NSArray *)control:(NSControl *)control textView:(NSTextView *)textView completions:(NSArray *)words
forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index { forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index {
NSString *query = [[control stringValue] substringWithRange:charRange]; NSString *query = [[textView string] substringWithRange:charRange];
if (![query length] || ![MPMacAppDelegate get].key) if (![query length] || ![MPMacAppDelegate get].key)
return nil; return nil;
@@ -185,20 +225,22 @@
NSError *error = nil; NSError *error = nil;
NSArray *siteResults = [context executeFetchRequest:fetchRequest error:&error]; NSArray *siteResults = [context executeFetchRequest:fetchRequest error:&error];
if (error) if (!siteResults)
err(@"While fetching elements for completion: %@", error); err(@"While fetching elements for completion: %@", error);
else if ([siteResults count]) {
if (siteResults) { _activeElementOID = ((NSManagedObject *)[siteResults objectAtIndex:0]).objectID;
for (MPElementEntity *element in siteResults) for (MPElementEntity *element in siteResults)
[mutableResults addObject:element.name]; [mutableResults addObject:element.name];
//[mutableResults addObject:query]; // For when the app should be able to create new sites. //[mutableResults addObject:query]; // For when the app should be able to create new sites.
} }
else
_activeElementOID = nil;
}]; }];
if ([mutableResults count] == 1) { if ([mutableResults count] < 2) {
//[textView setString:[(MPElementEntity *)[siteResults objectAtIndex:0] name]]; //[textView setString:[(MPElementEntity *)[siteResults objectAtIndex:0] name]];
//[textView setSelectedRange:NSMakeRange( [query length], [[textView string] length] - [query length] )]; //[textView setSelectedRange:NSMakeRange( [query length], [[textView string] length] - [query length] )];
[self trySiteAndCopyContent:NO]; [self trySiteWithAction:NO];
} }
return mutableResults; return mutableResults;
@@ -206,29 +248,29 @@
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector { - (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector {
if (commandSelector == @selector(cancel:)) { if (commandSelector == @selector(cancel:)) { // Escape without completion.
[self.window close]; [self.window close];
return YES; return YES;
} }
if ((self.siteFieldPreventCompletion = [NSStringFromSelector( commandSelector ) hasPrefix:@"delete"])) if ((self.siteFieldPreventCompletion = [NSStringFromSelector( commandSelector ) hasPrefix:@"delete"])) { // Backspace any time.
_activeElementOID = nil;
[self trySiteWithAction:NO];
return NO; return NO;
if (commandSelector == @selector(insertNewline:)) { }
[self trySiteAndCopyContent:YES]; if (commandSelector == @selector(insertNewline:)) { // Return without completion.
[self trySiteWithAction:YES];
return YES; return YES;
} }
return NO; return NO;
} }
- (void)copyContents {
}
- (void)controlTextDidEndEditing:(NSNotification *)note { - (void)controlTextDidEndEditing:(NSNotification *)note {
if (note.object != self.siteField) if (note.object != self.siteField)
return; return;
[self trySiteAndCopyContent:NO]; [self trySiteWithAction:NO];
} }
- (void)controlTextDidChange:(NSNotification *)note { - (void)controlTextDidChange:(NSNotification *)note {
@@ -237,12 +279,18 @@
return; return;
// Update the site content as the site name changes. // Update the site content as the site name changes.
BOOL enterPressed = [[NSApp currentEvent] type] == NSKeyDown && if ([[NSApp currentEvent] type] == NSKeyDown &&
[[[NSApp currentEvent] charactersIgnoringModifiers] isEqualToString:@"\r"]; [[[NSApp currentEvent] charactersIgnoringModifiers] isEqualToString:@"\r"]) { // Return while completing.
[self trySiteAndCopyContent:enterPressed]; [self trySiteWithAction:YES];
if (enterPressed)
return; return;
}
if ([[NSApp currentEvent] type] == NSKeyDown &&
[[[NSApp currentEvent] charactersIgnoringModifiers] characterAtIndex:0] == 0x1b) { // Escape while completing.
_activeElementOID = nil;
[self trySiteWithAction:NO];
return;
}
if (self.siteFieldPreventCompletion) { if (self.siteFieldPreventCompletion) {
self.siteFieldPreventCompletion = NO; self.siteFieldPreventCompletion = NO;
@@ -256,11 +304,12 @@
- (MPElementEntity *)activeElementForThread { - (MPElementEntity *)activeElementForThread {
if (!_activeElementOID) return [self activeElementInContext:[MPMacAppDelegate managedObjectContextForThreadIfReady]];
return nil; }
NSManagedObjectContext *moc = [MPMacAppDelegate managedObjectContextForThreadIfReady]; - (MPElementEntity *)activeElementInContext:(NSManagedObjectContext *)moc {
if (!moc)
if (!_activeElementOID)
return nil; return nil;
NSError *error; NSError *error;
@@ -281,66 +330,75 @@
}]]; }]];
} }
- (void)trySiteAndCopyContent:(BOOL)copyContent { - (void)trySiteWithAction:(BOOL)doAction {
[self setContent:@""]; NSString *siteName = [self.siteField stringValue];
[self.tipField setStringValue:@"Generating..."]; [self.backgroundQueue addOperationWithBlock:^{
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{
NSString *content = [[self activeElementForThread].content description]; NSString *content = [[self activeElementForThread].content description];
if (!content) if (!content)
content = @""; content = @"";
if (copyContent) {
[[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; dbg(@"name: %@, action: %d", siteName, doAction);
if (![[NSPasteboard generalPasteboard] setString:content forType:NSPasteboardTypeString]) { if (doAction) {
wrn(@"Couldn't copy password to pasteboard."); if ([content length]) {
// Performing action while content is available. Copy it.
[self copyContent:content];
}
else if ([siteName length]) {
// Performing action without content but a site name is written.
[self createNewSite:siteName];
return; return;
} }
MPElementEntity *activeElement = [self activeElementForThread];
[activeElement use];
[activeElement.managedObjectContext saveToStore];
} }
dispatch_async( dispatch_get_main_queue(), ^{ [[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self setContent:content]; [self setContent:content];
self.tipField.alphaValue = 1; self.tipField.alphaValue = 1;
if (!copyContent) if ([content length] == 0) {
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."]; [self.tipField setStringValue:@"Hit ⌤ (ENTER) to copy the password."];
else { else {
[self.tipField setStringValue:@"Copied! Hit ⎋ (ESC) to close window."]; [self.tipField setStringValue:@"Copied! Hit ⎋ (ESC) to close window."];
dispatch_time_t popTime = dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ); dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ), dispatch_get_main_queue(), ^{
dispatch_after( popTime, dispatch_get_main_queue(), ^{
[NSAnimationContext beginGrouping]; [NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0.2f]; [[NSAnimationContext currentContext] setDuration:0.2f];
[self.tipField.animator setAlphaValue:0]; [self.tipField.animator setAlphaValue:0];
[NSAnimationContext endGrouping]; [NSAnimationContext endGrouping];
} ); } );
} }
} );
} );
// For when the app should be able to create new sites.
/*
else
[[MPMacAppDelegate get].managedObjectContext performBlock:^{
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPElementGeneratedEntity class])
inManagedObjectContext:[MPMacAppDelegate get].managedObjectContext];
assert([element isKindOfClass:ClassFromMPElementType(element.type)]);
assert([MPMacAppDelegate get].keyID);
element.name = siteName;
element.keyID = [MPMacAppDelegate get].keyID;
NSString *description = [element.content description];
[element use];
dispatch_async(dispatch_get_main_queue(), ^{
[self setContent:description];
});
}]; }];
*/ }];
}
- (void)copyContent:(NSString *)content {
[[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
if (![[NSPasteboard generalPasteboard] setString:content forType:NSPasteboardTypeString]) {
wrn(@"Couldn't copy password to pasteboard.");
return;
}
NSManagedObjectContext *moc = [MPMacAppDelegate managedObjectContextForThreadIfReady];
MPElementEntity *activeElement = [self activeElementInContext:moc];
[activeElement use];
[moc saveToStore];
}
- (void)createNewSite:(NSString *)siteName {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSAlert *alert = [NSAlert alertWithMessageText:@"Create site?"
defaultButton:@"Create" alternateButton:nil otherButton:@"Cancel"
informativeTextWithFormat:@"Do you want to create a new site named:\n\n%@", siteName];
[alert beginSheetModalForWindow:self.window modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertCreateSite];
}];
} }
@end @end

View File

@@ -63,6 +63,14 @@
<reference key="NSSuperview" ref="1072816887"/> <reference key="NSSuperview" ref="1072816887"/>
<reference key="NSWindow"/> <reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="402376051"/> <reference key="NSNextKeyView" ref="402376051"/>
<object class="NSShadow" key="NSViewShadow">
<double key="NSShadowVert">1</double>
<double key="NSShadowBlurRadius">1</double>
<object class="NSColor" key="NSShadowColor" id="546806116">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MCAwLjYAA</bytes>
</object>
</object>
<string key="NSReuseIdentifierKey">_NS:1535</string> <string key="NSReuseIdentifierKey">_NS:1535</string>
<bool key="NSEnabled">YES</bool> <bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="406294418"> <object class="NSTextFieldCell" key="NSCell" id="406294418">
@@ -99,6 +107,14 @@
<reference key="NSSuperview" ref="1072816887"/> <reference key="NSSuperview" ref="1072816887"/>
<reference key="NSWindow"/> <reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="104294954"/> <reference key="NSNextKeyView" ref="104294954"/>
<object class="NSShadow" key="NSViewShadow">
<double key="NSShadowVert">1</double>
<double key="NSShadowBlurRadius">1</double>
<object class="NSColor" key="NSShadowColor" id="227321360">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MCAwLjYAA</bytes>
</object>
</object>
<string key="NSReuseIdentifierKey">_NS:1505</string> <string key="NSReuseIdentifierKey">_NS:1505</string>
<bool key="NSEnabled">YES</bool> <bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="249851874"> <object class="NSTextFieldCell" key="NSCell" id="249851874">
@@ -173,7 +189,6 @@
<reference key="NSWindow"/> <reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="49669222"/> <reference key="NSNextKeyView" ref="49669222"/>
<object class="NSShadow" key="NSViewShadow"> <object class="NSShadow" key="NSViewShadow">
<double key="NSShadowHoriz">1</double>
<double key="NSShadowVert">1</double> <double key="NSShadowVert">1</double>
<double key="NSShadowBlurRadius">1</double> <double key="NSShadowBlurRadius">1</double>
<object class="NSColor" key="NSShadowColor" id="444840817"> <object class="NSColor" key="NSShadowColor" id="444840817">
@@ -181,6 +196,17 @@
<bytes key="NSWhite">MCAwLjYAA</bytes> <bytes key="NSWhite">MCAwLjYAA</bytes>
</object> </object>
</object> </object>
<array key="NSViewContentFilters">
<object class="CIGaussianBlur">
<real value="0.40000000000000002" key="CI_inputRadius"/>
<bool key="CIEnabled">YES</bool>
</object>
<object class="CIBloom">
<real value="10" key="CI_inputRadius"/>
<real value="0.5" key="CI_inputIntensity"/>
<bool key="CIEnabled">YES</bool>
</object>
</array>
<string key="NSReuseIdentifierKey">_NS:9</string> <string key="NSReuseIdentifierKey">_NS:9</string>
<string key="NSAntiCompressionPriority">{250, 750}</string> <string key="NSAntiCompressionPriority">{250, 750}</string>
<bool key="NSEnabled">YES</bool> <bool key="NSEnabled">YES</bool>
@@ -218,6 +244,7 @@
<string key="NSFrame">{{224, 84}, {32, 32}}</string> <string key="NSFrame">{{224, 84}, {32, 32}}</string>
<reference key="NSSuperview" ref="258451033"/> <reference key="NSSuperview" ref="258451033"/>
<reference key="NSWindow"/> <reference key="NSWindow"/>
<reference key="NSNextKeyView"/>
<string key="NSReuseIdentifierKey">_NS:945</string> <string key="NSReuseIdentifierKey">_NS:945</string>
<int key="NSpiFlags">28682</int> <int key="NSpiFlags">28682</int>
<double key="NSMaxValue">100</double> <double key="NSMaxValue">100</double>
@@ -833,7 +860,7 @@
<real value="1" key="181.IBViewIntegration.shadowBlurRadius"/> <real value="1" key="181.IBViewIntegration.shadowBlurRadius"/>
<reference key="181.IBViewIntegration.shadowColor" ref="444840817"/> <reference key="181.IBViewIntegration.shadowColor" ref="444840817"/>
<real value="1" key="181.IBViewIntegration.shadowOffsetHeight"/> <real value="1" key="181.IBViewIntegration.shadowOffsetHeight"/>
<real value="1" key="181.IBViewIntegration.shadowOffsetWidth"/> <real value="0.0" key="181.IBViewIntegration.shadowOffsetWidth"/>
<array class="NSMutableArray" key="182.IBNSViewMetadataConstraints"> <array class="NSMutableArray" key="182.IBNSViewMetadataConstraints">
<reference ref="102475933"/> <reference ref="102475933"/>
</array> </array>
@@ -845,6 +872,10 @@
<real value="0.0" key="182.IBViewIntegration.shadowOffsetWidth"/> <real value="0.0" key="182.IBViewIntegration.shadowOffsetWidth"/>
<boolean value="NO" key="183.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/> <boolean value="NO" key="183.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
<string key="183.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="183.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<real value="1" key="183.IBViewIntegration.shadowBlurRadius"/>
<reference key="183.IBViewIntegration.shadowColor" ref="227321360"/>
<real value="1" key="183.IBViewIntegration.shadowOffsetHeight"/>
<real value="0.0" key="183.IBViewIntegration.shadowOffsetWidth"/>
<string key="184.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="184.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="185.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="185.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="186.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="186.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
@@ -859,6 +890,10 @@
<string key="210.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="210.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="NO" key="216.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/> <boolean value="NO" key="216.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
<string key="216.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="216.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<real value="1" key="216.IBViewIntegration.shadowBlurRadius"/>
<reference key="216.IBViewIntegration.shadowColor" ref="546806116"/>
<real value="1" key="216.IBViewIntegration.shadowOffsetHeight"/>
<real value="0.0" key="216.IBViewIntegration.shadowOffsetWidth"/>
<string key="217.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="217.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="218.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="218.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="219.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="219.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>

View File

@@ -13,7 +13,7 @@
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>MasterPassword</string> <string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>

View File

@@ -27,6 +27,8 @@
DA3EF17B15A47744003ABF4E /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA3EF17A15A47744003ABF4E /* SenTestingKit.framework */; }; DA3EF17B15A47744003ABF4E /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA3EF17A15A47744003ABF4E /* SenTestingKit.framework */; };
DA3EF17D15A47744003ABF4E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DA3EF17D15A47744003ABF4E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DA4425CC1557BED40052177D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DA4425CC1557BED40052177D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DA4C45F4173B57B700745CC5 /* NSURL+UbiquityStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DA4C45F2173B57B700745CC5 /* NSURL+UbiquityStoreManager.h */; };
DA4C45F5173B57B700745CC5 /* NSURL+UbiquityStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4C45F3173B57B700745CC5 /* NSURL+UbiquityStoreManager.m */; };
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; }; DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
DA5E5C8817248AA1003798D8 /* crypto_aesctr.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C7B17248AA1003798D8 /* crypto_aesctr.h */; }; DA5E5C8817248AA1003798D8 /* crypto_aesctr.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C7B17248AA1003798D8 /* crypto_aesctr.h */; };
DA5E5C8917248AA1003798D8 /* crypto_scrypt.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C7C17248AA1003798D8 /* crypto_scrypt.h */; }; DA5E5C8917248AA1003798D8 /* crypto_scrypt.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C7C17248AA1003798D8 /* crypto_scrypt.h */; };
@@ -201,7 +203,9 @@
DA3EF17915A47744003ABF4E /* Tests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; DA3EF17915A47744003ABF4E /* Tests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.octest; sourceTree = BUILT_PRODUCTS_DIR; };
DA3EF17A15A47744003ABF4E /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; DA3EF17A15A47744003ABF4E /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libUbiquityStoreManager.a; sourceTree = BUILT_PRODUCTS_DIR; }; DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libUbiquityStoreManager.a; sourceTree = BUILT_PRODUCTS_DIR; };
DA5BFA44147E415C00F98B1E /* MasterPassword-Mac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MasterPassword-Mac.app"; sourceTree = BUILT_PRODUCTS_DIR; }; DA4C45F2173B57B700745CC5 /* NSURL+UbiquityStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+UbiquityStoreManager.h"; sourceTree = "<group>"; };
DA4C45F3173B57B700745CC5 /* NSURL+UbiquityStoreManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+UbiquityStoreManager.m"; sourceTree = "<group>"; };
DA5BFA44147E415C00F98B1E /* MasterPassword.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MasterPassword.app; sourceTree = BUILT_PRODUCTS_DIR; };
DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
DA5BFA4E147E415C00F98B1E /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; DA5BFA4E147E415C00F98B1E /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
@@ -440,7 +444,7 @@
DA5BFA45147E415C00F98B1E /* Products */ = { DA5BFA45147E415C00F98B1E /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DA5BFA44147E415C00F98B1E /* MasterPassword-Mac.app */, DA5BFA44147E415C00F98B1E /* MasterPassword.app */,
DAC77CAD148291A600BCF976 /* libPearl.a */, DAC77CAD148291A600BCF976 /* libPearl.a */,
DAC6326C148680650075AEA5 /* libjrswizzle.a */, DAC6326C148680650075AEA5 /* libjrswizzle.a */,
DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */, DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */,
@@ -577,6 +581,8 @@
DACA22B61705DE7D002C6C22 /* UbiquityStoreManager */ = { DACA22B61705DE7D002C6C22 /* UbiquityStoreManager */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DA4C45F2173B57B700745CC5 /* NSURL+UbiquityStoreManager.h */,
DA4C45F3173B57B700745CC5 /* NSURL+UbiquityStoreManager.m */,
DACA22BA1705DE7D002C6C22 /* UbiquityStoreManager.h */, DACA22BA1705DE7D002C6C22 /* UbiquityStoreManager.h */,
DACA22B71705DE7D002C6C22 /* UbiquityStoreManager.m */, DACA22B71705DE7D002C6C22 /* UbiquityStoreManager.m */,
DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */, DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */,
@@ -800,6 +806,7 @@
files = ( files = (
DACA22BC1705DE7D002C6C22 /* NSError+UbiquityStoreManager.h in Headers */, DACA22BC1705DE7D002C6C22 /* NSError+UbiquityStoreManager.h in Headers */,
DACA22BE1705DE7D002C6C22 /* UbiquityStoreManager.h in Headers */, DACA22BE1705DE7D002C6C22 /* UbiquityStoreManager.h in Headers */,
DA4C45F4173B57B700745CC5 /* NSURL+UbiquityStoreManager.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -893,9 +900,9 @@
productReference = DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */; productReference = DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */;
productType = "com.apple.product-type.library.static"; productType = "com.apple.product-type.library.static";
}; };
DA5BFA43147E415C00F98B1E /* MasterPassword-Mac */ = { DA5BFA43147E415C00F98B1E /* MasterPassword */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword-Mac" */; buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword" */;
buildPhases = ( buildPhases = (
DA5BFA40147E415C00F98B1E /* Sources */, DA5BFA40147E415C00F98B1E /* Sources */,
DA5BFA41147E415C00F98B1E /* Frameworks */, DA5BFA41147E415C00F98B1E /* Frameworks */,
@@ -907,9 +914,9 @@
); );
dependencies = ( dependencies = (
); );
name = "MasterPassword-Mac"; name = MasterPassword;
productName = MasterPassword; productName = MasterPassword;
productReference = DA5BFA44147E415C00F98B1E /* MasterPassword-Mac.app */; productReference = DA5BFA44147E415C00F98B1E /* MasterPassword.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
}; };
DAC6326B148680650075AEA5 /* jrswizzle */ = { DAC6326B148680650075AEA5 /* jrswizzle */ = {
@@ -971,7 +978,7 @@
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
targets = ( targets = (
DA5BFA43147E415C00F98B1E /* MasterPassword-Mac */, DA5BFA43147E415C00F98B1E /* MasterPassword */,
DAC77CAC148291A600BCF976 /* Pearl */, DAC77CAC148291A600BCF976 /* Pearl */,
DAC6326B148680650075AEA5 /* jrswizzle */, DAC6326B148680650075AEA5 /* jrswizzle */,
DA4425CA1557BED40052177D /* UbiquityStoreManager */, DA4425CA1557BED40052177D /* UbiquityStoreManager */,
@@ -1116,6 +1123,7 @@
files = ( files = (
DACA22BB1705DE7D002C6C22 /* UbiquityStoreManager.m in Sources */, DACA22BB1705DE7D002C6C22 /* UbiquityStoreManager.m in Sources */,
DACA22BD1705DE7D002C6C22 /* NSError+UbiquityStoreManager.m in Sources */, DACA22BD1705DE7D002C6C22 /* NSError+UbiquityStoreManager.m in Sources */,
DA4C45F5173B57B700745CC5 /* NSURL+UbiquityStoreManager.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -1190,7 +1198,7 @@
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
DA3EF19E15A47AEB003ABF4E /* PBXTargetDependency */ = { DA3EF19E15A47AEB003ABF4E /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
target = DA5BFA43147E415C00F98B1E /* MasterPassword-Mac */; target = DA5BFA43147E415C00F98B1E /* MasterPassword */;
targetProxy = DA3EF19D15A47AEB003ABF4E /* PBXContainerItemProxy */; targetProxy = DA3EF19D15A47AEB003ABF4E /* PBXContainerItemProxy */;
}; };
DAC63286148681200075AEA5 /* PBXTargetDependency */ = { DAC63286148681200075AEA5 /* PBXTargetDependency */ = {
@@ -1717,7 +1725,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = "AdHoc-Mac"; defaultConfigurationName = "AdHoc-Mac";
}; };
DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword-Mac" */ = { DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
DA5BFA6E147E415C00F98B1E /* Debug-Mac */, DA5BFA6E147E415C00F98B1E /* Debug-Mac */,

View File

@@ -15,8 +15,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-Mac.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-Mac" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj"> ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
@@ -43,8 +43,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-Mac.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-Mac" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj"> ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
@@ -61,8 +61,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-Mac.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-Mac" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj"> ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>

View File

@@ -15,8 +15,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-Mac.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-Mac" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj"> ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
@@ -43,11 +43,18 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-Mac.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-Mac" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj"> ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
<EnvironmentVariables>
<EnvironmentVariable
key = "CA_DEBUG_TRANSACTIONS"
value = "1"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions> <AdditionalOptions>
</AdditionalOptions> </AdditionalOptions>
</LaunchAction> </LaunchAction>
@@ -61,8 +68,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-Mac.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-Mac" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj"> ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>

View File

@@ -201,6 +201,41 @@
</array> </array>
</object> </object>
</object> </object>
<object class="NSMenuItem" id="939693094">
<reference key="NSMenu" ref="800575174"/>
<string key="NSTitle">Advanced</string>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="269450960"/>
<reference key="NSMixedImage" ref="977440657"/>
<string key="NSAction">submenuAction:</string>
<object class="NSMenu" key="NSSubmenu" id="534220172">
<string key="NSTitle">Advanced</string>
<array class="NSMutableArray" key="NSMenuItems">
<object class="NSMenuItem" id="842321178">
<reference key="NSMenu" ref="534220172"/>
<string key="NSTitle">iCloud Truth Sync</string>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="269450960"/>
<reference key="NSMixedImage" ref="977440657"/>
</object>
<object class="NSMenuItem" id="946018575">
<reference key="NSMenu" ref="534220172"/>
<bool key="NSIsDisabled">YES</bool>
<string key="NSTitle">Force this device's version of the truth upon all others.</string>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="269450960"/>
<reference key="NSMixedImage" ref="977440657"/>
<object class="NSAttributedString" key="NSAttributedTitle">
<string key="NSString">Force this device's version of the truth upon all others.</string>
<reference key="NSAttributes" ref="583461090"/>
</object>
</object>
</array>
</object>
</object>
</array> </array>
<bool key="NSNoAutoenable">YES</bool> <bool key="NSNoAutoenable">YES</bool>
</object> </object>
@@ -288,14 +323,6 @@
</object> </object>
<int key="connectionID">731</int> <int key="connectionID">731</int>
</object> </object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">activate:</string>
<reference key="source" ref="976324537"/>
<reference key="destination" ref="846612332"/>
</object>
<int key="connectionID">736</int>
</object>
<object class="IBConnectionRecord"> <object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection"> <object class="IBOutletConnection" key="connection">
<string key="label">useICloudItem</string> <string key="label">useICloudItem</string>
@@ -408,6 +435,22 @@
</object> </object>
<int key="connectionID">774</int> <int key="connectionID">774</int>
</object> </object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">rebuildCloud:</string>
<reference key="source" ref="976324537"/>
<reference key="destination" ref="842321178"/>
</object>
<int key="connectionID">780</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">showPasswordWindow</string>
<reference key="source" ref="976324537"/>
<reference key="destination" ref="846612332"/>
</object>
<int key="connectionID">781</int>
</object>
</array> </array>
<object class="IBMutableOrderedSet" key="objectRecords"> <object class="IBMutableOrderedSet" key="objectRecords">
<array key="orderedObjects"> <array key="orderedObjects">
@@ -503,6 +546,7 @@
<reference ref="110488020"/> <reference ref="110488020"/>
<reference ref="123831322"/> <reference ref="123831322"/>
<reference ref="123543264"/> <reference ref="123543264"/>
<reference ref="939693094"/>
</array> </array>
<reference key="parent" ref="851296005"/> <reference key="parent" ref="851296005"/>
</object> </object>
@@ -590,6 +634,33 @@
<reference key="object" ref="117792016"/> <reference key="object" ref="117792016"/>
<reference key="parent" ref="293904698"/> <reference key="parent" ref="293904698"/>
</object> </object>
<object class="IBObjectRecord">
<int key="objectID">776</int>
<reference key="object" ref="939693094"/>
<array class="NSMutableArray" key="children">
<reference ref="534220172"/>
</array>
<reference key="parent" ref="800575174"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">777</int>
<reference key="object" ref="534220172"/>
<array class="NSMutableArray" key="children">
<reference ref="842321178"/>
<reference ref="946018575"/>
</array>
<reference key="parent" ref="939693094"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">778</int>
<reference key="object" ref="842321178"/>
<reference key="parent" ref="534220172"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">779</int>
<reference key="object" ref="946018575"/>
<reference key="parent" ref="534220172"/>
</object>
</array> </array>
</object> </object>
<dictionary class="NSMutableDictionary" key="flattenedProperties"> <dictionary class="NSMutableDictionary" key="flattenedProperties">
@@ -628,14 +699,158 @@
<string key="766.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="766.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="767.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="767.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="768.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="768.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="776.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="777.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="778.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="779.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
</dictionary> </dictionary>
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/> <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
<nil key="activeLocalization"/> <nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/> <dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/> <nil key="sourceID"/>
<int key="maxID">774</int> <int key="maxID">781</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
<object class="IBPartialClassDescription">
<string key="className">MPAppDelegate_Shared</string>
<string key="superclassName">PearlAppDelegate</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/MPAppDelegate_Shared.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">MPMacAppDelegate</string>
<string key="superclassName">MPAppDelegate_Shared</string>
<dictionary class="NSMutableDictionary" key="actions">
<string key="activate:">id</string>
<string key="lock:">id</string>
<string key="newUser:">NSMenuItem</string>
<string key="rebuildCloud:">id</string>
<string key="togglePreference:">NSMenuItem</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="actionInfosByName">
<object class="IBActionInfo" key="activate:">
<string key="name">activate:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo" key="lock:">
<string key="name">lock:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo" key="newUser:">
<string key="name">newUser:</string>
<string key="candidateClassName">NSMenuItem</string>
</object>
<object class="IBActionInfo" key="rebuildCloud:">
<string key="name">rebuildCloud:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo" key="togglePreference:">
<string key="name">togglePreference:</string>
<string key="candidateClassName">NSMenuItem</string>
</object>
</dictionary>
<dictionary class="NSMutableDictionary" key="outlets">
<string key="createUserItem">NSMenuItem</string>
<string key="dialogStyleHUD">NSMenuItem</string>
<string key="dialogStyleRegular">NSMenuItem</string>
<string key="lockItem">NSMenuItem</string>
<string key="rememberPasswordItem">NSMenuItem</string>
<string key="savePasswordItem">NSMenuItem</string>
<string key="showItem">NSMenuItem</string>
<string key="statusMenu">NSMenu</string>
<string key="useICloudItem">NSMenuItem</string>
<string key="usersItem">NSMenuItem</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
<object class="IBToOneOutletInfo" key="createUserItem">
<string key="name">createUserItem</string>
<string key="candidateClassName">NSMenuItem</string>
</object>
<object class="IBToOneOutletInfo" key="dialogStyleHUD">
<string key="name">dialogStyleHUD</string>
<string key="candidateClassName">NSMenuItem</string>
</object>
<object class="IBToOneOutletInfo" key="dialogStyleRegular">
<string key="name">dialogStyleRegular</string>
<string key="candidateClassName">NSMenuItem</string>
</object>
<object class="IBToOneOutletInfo" key="lockItem">
<string key="name">lockItem</string>
<string key="candidateClassName">NSMenuItem</string>
</object>
<object class="IBToOneOutletInfo" key="rememberPasswordItem">
<string key="name">rememberPasswordItem</string>
<string key="candidateClassName">NSMenuItem</string>
</object>
<object class="IBToOneOutletInfo" key="savePasswordItem">
<string key="name">savePasswordItem</string>
<string key="candidateClassName">NSMenuItem</string>
</object>
<object class="IBToOneOutletInfo" key="showItem">
<string key="name">showItem</string>
<string key="candidateClassName">NSMenuItem</string>
</object>
<object class="IBToOneOutletInfo" key="statusMenu">
<string key="name">statusMenu</string>
<string key="candidateClassName">NSMenu</string>
</object>
<object class="IBToOneOutletInfo" key="useICloudItem">
<string key="name">useICloudItem</string>
<string key="candidateClassName">NSMenuItem</string>
</object>
<object class="IBToOneOutletInfo" key="usersItem">
<string key="name">usersItem</string>
<string key="candidateClassName">NSMenuItem</string>
</object>
</dictionary>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/MPMacAppDelegate.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">PearlAppDelegate</string>
<string key="superclassName">UIResponder</string>
<dictionary class="NSMutableDictionary" key="outlets">
<string key="navigationController">UINavigationController</string>
<string key="window">UIWindow</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
<object class="IBToOneOutletInfo" key="navigationController">
<string key="name">navigationController</string>
<string key="candidateClassName">UINavigationController</string>
</object>
<object class="IBToOneOutletInfo" key="window">
<string key="name">window</string>
<string key="candidateClassName">UIWindow</string>
</object>
</dictionary>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/PearlAppDelegate.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">UINavigationController</string>
<string key="superclassName">UIViewController</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/UINavigationController.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">UIWindow</string>
<string key="superclassName">UIView</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/UIWindow.h</string>
</object>
</object>
</array>
</object> </object>
<object class="IBClassDescriber" key="IBDocument.Classes"/>
<int key="IBDocument.localizationMode">0</int> <int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string> <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies"> <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">

View File

@@ -55,9 +55,11 @@
return; return;
__weak MPElementListAllViewController *wSelf = self; __weak MPElementListAllViewController *wSelf = self;
[self addElementNamed:[alert textFieldAtIndex:0].text completion:^(BOOL success) { [[MPiOSAppDelegate get] addElementNamed:[alert textFieldAtIndex:0].text completion:^(MPElementEntity *element) {
if (success) if (element) {
[wSelf.delegate didSelectElement:element];
[wSelf close:nil]; [wSelf close:nil];
}
}]; }];
} }
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonOkay, nil]; cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonOkay, nil];

View File

@@ -15,7 +15,6 @@
@property(readonly) NSDateFormatter *dateFormatter; @property(readonly) NSDateFormatter *dateFormatter;
- (void)updateData; - (void)updateData;
- (void)addElementNamed:(NSString *)siteName completion:(void (^)(BOOL success))completion;
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atTableIndexPath:(NSIndexPath *)indexPath; - (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atTableIndexPath:(NSIndexPath *)indexPath;
- (void)customTableViewUpdates; - (void)customTableViewUpdates;

View File

@@ -15,7 +15,7 @@
- (void)viewDidLoad { - (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock: [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock:
^(NSNotification *note) { ^(NSNotification *note) {
[self updateData]; [self updateData];
}]; }];
@@ -23,44 +23,6 @@
[super viewDidLoad]; [super viewDidLoad];
} }
- (void)addElementNamed:(NSString *)siteName completion:(void (^)(BOOL success))completion {
if (![siteName length]) {
if (completion)
completion( false );
return;
}
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
assert(activeUser);
MPElementType type = activeUser.defaultType;
if (!type)
type = activeUser.defaultType = MPElementTypeGeneratedLong;
NSString *typeEntityClassName = [MPAlgorithmDefault classNameOfType:type];
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityClassName
inManagedObjectContext:moc];
element.name = siteName;
element.user = activeUser;
element.type = type;
element.lastUsed = [NSDate date];
element.version = MPAlgorithmDefaultVersion;
[moc saveToStore];
NSManagedObjectID *elementOID = [element objectID];
dispatch_async( dispatch_get_main_queue(), ^{
MPElementEntity *element_ = (MPElementEntity *)[[MPiOSAppDelegate managedObjectContextForThreadIfReady]
objectRegisteredForID:elementOID];
[self.delegate didSelectElement:element_];
if (completion)
completion( true );
} );
}];
}
- (NSFetchedResultsController *)fetchedResultsControllerByLastUsed { - (NSFetchedResultsController *)fetchedResultsControllerByLastUsed {
if (!_fetchedResultsControllerByLastUsed) { if (!_fetchedResultsControllerByLastUsed) {
@@ -145,9 +107,9 @@
NSError *error; NSError *error;
self.fetchedResultsControllerByLastUsed.fetchRequest.predicate = predicate; self.fetchedResultsControllerByLastUsed.fetchRequest.predicate = predicate;
self.fetchedResultsControllerByUses.fetchRequest.predicate = predicate; self.fetchedResultsControllerByUses.fetchRequest.predicate = predicate;
if (![self.fetchedResultsControllerByLastUsed performFetch:&error]) if (self.fetchedResultsControllerByLastUsed && ![self.fetchedResultsControllerByLastUsed performFetch:&error])
err(@"Couldn't fetch elements: %@", error); err(@"Couldn't fetch elements: %@", error);
if (![self.fetchedResultsControllerByUses performFetch:&error]) if (self.fetchedResultsControllerByUses && ![self.fetchedResultsControllerByUses performFetch:&error])
err(@"Couldn't fetch elements: %@", error); err(@"Couldn't fetch elements: %@", error);
[self.tableView reloadData]; [self.tableView reloadData];
@@ -157,50 +119,46 @@
} }
// See MP-14, also crashes easily on internal assertions etc.. // See MP-14, also crashes easily on internal assertions etc..
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { //- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
//
dbg(@"%@", NSStringFromSelector( _cmd )); // [self.tableView beginUpdates];
[self.tableView beginUpdates]; //}
} //
//- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject // atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { //
// switch (type) {
switch (type) { //
// case NSFetchedResultsChangeInsert:
case NSFetchedResultsChangeInsert: // [self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ]
dbg(@"%@ -- NSFetchedResultsChangeInsert:%@", NSStringFromSelector( _cmd ), anObject); // withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ] // break;
withRowAnimation:UITableViewRowAnimationAutomatic]; //
break; // case NSFetchedResultsChangeDelete:
// [self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
case NSFetchedResultsChangeDelete: // withRowAnimation:UITableViewRowAnimationAutomatic];
dbg(@"%@ -- NSFetchedResultsChangeDelete:%@", NSStringFromSelector( _cmd ), anObject); // break;
[self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ] //
withRowAnimation:UITableViewRowAnimationAutomatic]; // case NSFetchedResultsChangeUpdate:
break; // [self.tableView reloadRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
// withRowAnimation:UITableViewRowAnimationAutomatic];
case NSFetchedResultsChangeUpdate: // break;
dbg(@"%@ -- NSFetchedResultsChangeUpdate:%@", NSStringFromSelector( _cmd ), anObject); //
[self.tableView reloadRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ] // case NSFetchedResultsChangeMove:
withRowAnimation:UITableViewRowAnimationAutomatic]; // [self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
break; // withRowAnimation:UITableViewRowAnimationAutomatic];
// [self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ]
case NSFetchedResultsChangeMove: // withRowAnimation:UITableViewRowAnimationAutomatic];
dbg(@"%@ -- NSFetchedResultsChangeMove:%@", NSStringFromSelector( _cmd ), anObject); // break;
[self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ] // }
withRowAnimation:UITableViewRowAnimationAutomatic]; //}
[self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
dbg(@"%@ on %@", NSStringFromSelector( _cmd ), [NSThread currentThread].name); // [self customTableViewUpdates];
[self customTableViewUpdates]; // [self.tableView endUpdates];
[self.tableView endUpdates];
[self.tableView reloadData];
} }
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
@@ -296,12 +254,18 @@
forRowAtIndexPath:(NSIndexPath *)indexPath { forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) { if (editingStyle == UITableViewCellEditingStyleDelete) {
MPElementEntity *element = [self elementForTableIndexPath:indexPath]; NSManagedObjectID *elementOID = [self elementForTableIndexPath:indexPath].objectID;
[element.managedObjectContext performBlockAndWait:^{ [MPiOSAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
NSError *error = nil;
MPElementEntity *element = (MPElementEntity *)[context existingObjectWithID:elementOID error:&error];
if (!element) {
err(@"Failed to retrieve element to delete: %@", error);
return;
}
inf(@"Deleting element: %@", element.name); inf(@"Deleting element: %@", element.name);
[element.managedObjectContext deleteObject:element]; [context deleteObject:element];
[element.managedObjectContext saveToStore]; [context saveToStore];
MPCheckpoint( MPCheckpointDeleteElement, @{ MPCheckpoint( MPCheckpointDeleteElement, @{
@"type" : element.typeName, @"type" : element.typeName,

View File

@@ -9,6 +9,7 @@
#import "MPElementListSearchController.h" #import "MPElementListSearchController.h"
#import "MPMainViewController.h" #import "MPMainViewController.h"
#import "MPiOSAppDelegate.h" #import "MPiOSAppDelegate.h"
#import "MPAppDelegate_Store.h"
@interface MPElementListSearchController() @interface MPElementListSearchController()
@@ -216,7 +217,11 @@
if (buttonIndex == [alert cancelButtonIndex]) if (buttonIndex == [alert cancelButtonIndex])
return; return;
[self addElementNamed:siteName completion:nil]; __weak MPElementListController *wSelf = self;
[[MPiOSAppDelegate get] addElementNamed:siteName completion:^(MPElementEntity *element) {
if (element)
[wSelf.delegate didSelectElement:element];
}];
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil]; } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil];
} }

View File

@@ -0,0 +1,29 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPLogsViewController.h
// MPLogsViewController
//
// Created by lhunath on 2013-04-29.
// Copyright, lhunath (Maarten Billemont) 2013. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface MPLogsViewController : UIViewController
@property (weak, nonatomic) IBOutlet UITextView *logView;
@property (weak, nonatomic) IBOutlet UISegmentedControl *levelControl;
- (IBAction)toggleLevelControl:(UISegmentedControl *)sender;
- (IBAction)close:(UIBarButtonItem *)sender;
- (IBAction)refresh:(UIBarButtonItem *)sender;
- (IBAction)mail:(UIBarButtonItem *)sender;
@end

View File

@@ -0,0 +1,87 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPLogsViewController.h
// MPLogsViewController
//
// Created by lhunath on 2013-04-29.
// Copyright, lhunath (Maarten Billemont) 2013. All rights reserved.
//
#import "MPLogsViewController.h"
#import "MPiOSAppDelegate.h"
@implementation MPLogsViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserverForName:NSUserDefaultsDidChangeNotification object:nil queue:nil usingBlock:
^(NSNotification *note) {
self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0;
}];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self refresh:nil];
self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0;
}
- (IBAction)toggleLevelControl:(UISegmentedControl *)sender {
BOOL traceEnabled = (BOOL)self.levelControl.selectedSegmentIndex;
if (traceEnabled) {
[PearlAlert showAlertWithTitle:@"Enable Trace Mode?" message:
@"Trace mode will log the internal operation of the application.\n"
@"Unless you're looking for the cause of a problem, you should leave this off to save memory."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex])
return;
[MPiOSConfig get].traceMode = @YES;
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Enable Trace", nil];
}
else
[MPiOSConfig get].traceMode = @NO;
}
- (IBAction)close:(UIBarButtonItem *)sender {
[self.navigationController popViewControllerAnimated:YES];
}
- (IBAction)refresh:(UIBarButtonItem *)sender {
self.logView.text = [[PearlLogger get] formatMessagesWithLevel:PearlLogLevelTrace];
}
- (IBAction)mail:(UIBarButtonItem *)sender {
if ([[MPiOSConfig get].traceMode boolValue]) {
[PearlAlert showAlertWithTitle:@"Hiding Trace Messages" message:
@"Trace-level log messages will not be mailed. "
@"These messages contain sensitive and personal information."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
[[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self];
} cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil];
}
else
[[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self];
}
@end

View File

@@ -107,7 +107,7 @@
[self.navigationController popToRootViewControllerAnimated:animated]; [self.navigationController popToRootViewControllerAnimated:animated];
}]; }];
}]; }];
[[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock: [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock:
^(NSNotification *note) { ^(NSNotification *note) {
if (!self.activeElementForThread) if (!self.activeElementForThread)
[self didSelectElement:nil]; [self didSelectElement:nil];
@@ -146,15 +146,15 @@
// Needed for when we appear after a modal VC dismisses: // Needed for when we appear after a modal VC dismisses:
// We can't present until the other modal VC has been fully dismissed and presenting in -viewWillAppear: will fail. // We can't present until the other modal VC has been fully dismissed and presenting in -viewWillAppear: will fail.
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{ [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForThread]; MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
if ([MPAlgorithmDefault migrateUser:activeUser] && !self.suppressOutdatedAlert) if ([MPAlgorithmDefault migrateUser:activeUser inContext:moc] && !self.suppressOutdatedAlert)
[UIView animateWithDuration:0.3f animations:^{ [UIView animateWithDuration:0.3f animations:^{
self.outdatedAlertContainer.alpha = 1; self.outdatedAlertContainer.alpha = 1;
self.suppressOutdatedAlert = YES; self.suppressOutdatedAlert = YES;
}]; }];
[activeUser.managedObjectContext saveToStore]; [moc saveToStore];
} ); }];
if (![[MPiOSConfig get].actionsTipShown boolValue]) if (![[MPiOSConfig get].actionsTipShown boolValue])
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{ [UIView animateWithDuration:animated? 0.3f: 0 animations:^{
@@ -506,7 +506,7 @@
@"If you continue, a new password will be generated for this site. " @"If you continue, a new password will be generated for this site. "
@"You will then need to update your account's old password to this newly generated password.\n\n" @"You will then need to update your account's old password to this newly generated password.\n\n"
@"You can reset the counter by holding down on this button." @"You can reset the counter by holding down on this button."
do:^BOOL(MPElementEntity *activeElement) { do:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) {
if (![activeElement isKindOfClass:[MPElementGeneratedEntity class]]) { if (![activeElement isKindOfClass:[MPElementGeneratedEntity class]]) {
// Not of a type that supports a password counter. // Not of a type that supports a password counter.
err(@"Cannot increment password counter: Element is not generated: %@", activeElement.name); err(@"Cannot increment password counter: Element is not generated: %@", activeElement.name);
@@ -545,7 +545,7 @@
@"You are resetting the site's password counter.\n\n" @"You are resetting the site's password counter.\n\n"
@"If you continue, the site's password will change back to its original value. " @"If you continue, the site's password will change back to its original value. "
@"You will then need to update your account's password back to this original value." @"You will then need to update your account's password back to this original value."
do:^BOOL(MPElementEntity *activeElement_) { do:^BOOL(MPElementEntity *activeElement_, NSManagedObjectContext *context) {
inf(@"Resetting password counter for: %@", activeElement_.name); inf(@"Resetting password counter for: %@", activeElement_.name);
((MPElementGeneratedEntity *)activeElement_).counter = 1; ((MPElementGeneratedEntity *)activeElement_).counter = 1;
@@ -576,7 +576,8 @@
} ); } );
} }
- (void)changeActiveElementWithWarning:(NSString *)warning do:(BOOL (^)(MPElementEntity *activeElement))task; { - (void)changeActiveElementWithWarning:(NSString *)warning
do:(BOOL (^)(MPElementEntity *activeElement, NSManagedObjectContext *context))task {
[PearlAlert showAlertWithTitle:@"Password Change" message:warning viewStyle:UIAlertViewStyleDefault [PearlAlert showAlertWithTitle:@"Password Change" message:warning viewStyle:UIAlertViewStyleDefault
initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
@@ -587,7 +588,7 @@
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil]; } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil];
} }
- (void)changeActiveElementWithoutWarningDo:(BOOL (^)(MPElementEntity *activeElement))task; { - (void)changeActiveElementWithoutWarningDo:(BOOL (^)(MPElementEntity *, NSManagedObjectContext *context))task {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *activeElement = [self activeElementInContext:context]; MPElementEntity *activeElement = [self activeElementInContext:context];
@@ -595,8 +596,10 @@
return; return;
NSString *oldPassword = [activeElement.content description]; NSString *oldPassword = [activeElement.content description];
if (!task( activeElement )) if (!task( activeElement, context ))
return; return;
activeElement = [self activeElementInContext:context];
NSString *newPassword = [activeElement.content description]; NSString *newPassword = [activeElement.content description];
// Save. // Save.
@@ -669,7 +672,7 @@
@"This upgrade improves the site's compatibility with the latest version of Master Password."; @"This upgrade improves the site's compatibility with the latest version of Master Password.";
[self changeActiveElementWithWarning:warning do: [self changeActiveElementWithWarning:warning do:
^BOOL(MPElementEntity *activeElement_) { ^BOOL(MPElementEntity *activeElement_, NSManagedObjectContext *context) {
inf(@"Explicitly migrating element: %@", activeElement_); inf(@"Explicitly migrating element: %@", activeElement_);
[activeElement_ migrateExplicitly:YES]; [activeElement_ migrateExplicitly:YES];
@@ -785,12 +788,16 @@
@"You are about to change the type of this password.\n\n" @"You are about to change the type of this password.\n\n"
@"If you continue, the password for this site will change. " @"If you continue, the password for this site will change. "
@"You will need to update your account's old password to the new one." @"You will need to update your account's old password to the new one."
do:^BOOL(MPElementEntity *activeElement) { do:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) {
if ([activeElement.algorithm classOfType:type] != activeElement.typeClass) { if ([activeElement.algorithm classOfType:type] == activeElement.typeClass)
activeElement.type = type;
else {
// Type requires a different class of element. Recreate the element. // Type requires a different class of element. Recreate the element.
MPElementEntity *newElement MPElementEntity *newElement
= [NSEntityDescription insertNewObjectForEntityForName:[activeElement.algorithm classNameOfType:type] = [NSEntityDescription insertNewObjectForEntityForName:[activeElement.algorithm classNameOfType:type]
inManagedObjectContext:activeElement.managedObjectContext]; inManagedObjectContext:context];
newElement.type = type;
newElement.name = activeElement.name; newElement.name = activeElement.name;
newElement.user = activeElement.user; newElement.user = activeElement.user;
newElement.uses = activeElement.uses; newElement.uses = activeElement.uses;
@@ -798,11 +805,16 @@
newElement.version = activeElement.version; newElement.version = activeElement.version;
newElement.loginName = activeElement.loginName; newElement.loginName = activeElement.loginName;
[activeElement.managedObjectContext deleteObject:activeElement]; [context deleteObject:activeElement];
[context saveToStore];
NSError *error;
if (![context obtainPermanentIDsForObjects:@[ newElement ] error:&error])
err(@"Failed to obtain a permanent object ID after changing object type: %@", error);
_activeElementOID = newElement.objectID; _activeElementOID = newElement.objectID;
activeElement = newElement; activeElement = newElement;
} }
activeElement.type = type;
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
postNotificationName:MPElementUpdatedNotification object:activeElement.objectID]; postNotificationName:MPElementUpdatedNotification object:activeElement.objectID];
@@ -817,7 +829,7 @@
[self closeAlert]; [self closeAlert];
if (element) { if (element) {
[self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement) { [self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) {
if ([activeElement use] == 1) if ([activeElement use] == 1)
[self showAlertWithTitle:@"New Site" message: [self showAlertWithTitle:@"New Site" message:
PearlString( @"You've just created a password for %@.\n\n" PearlString( @"You've just created a password for %@.\n\n"
@@ -843,15 +855,15 @@
} ); } );
} }
}]; }];
}
[self.searchDisplayController setActive:NO animated:YES];
self.searchDisplayController.searchBar.text = element.name;
MPCheckpoint( MPCheckpointUseType, @{ MPCheckpoint( MPCheckpointUseType, @{
@"type" : element.typeName, @"type" : element.typeName,
@"version" : @(element.version) @"version" : @(element.version)
} ); } );
}
[self.searchDisplayController setActive:NO animated:YES];
self.searchDisplayController.searchBar.text = element.name;
[self updateAnimated:YES]; [self updateAnimated:YES];
} }
@@ -880,7 +892,7 @@
// Content hasn't changed. // Content hasn't changed.
return; return;
[self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement_) { [self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement_, NSManagedObjectContext *context) {
((MPElementStoredEntity *)activeElement_).content = self.contentField.text; ((MPElementStoredEntity *)activeElement_).content = self.contentField.text;
return YES; return YES;
}]; }];
@@ -893,7 +905,7 @@
[MPiOSConfig get].loginNameTipShown = @YES; [MPiOSConfig get].loginNameTipShown = @YES;
} }
[self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement) { [self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) {
if ([self.loginNameField.text length]) if ([self.loginNameField.text length])
activeElement.loginName = self.loginNameField.text; activeElement.loginName = self.loginNameField.text;
else else

View File

@@ -47,9 +47,13 @@
} options:0]; } options:0];
[avatar onSelect:^(BOOL selected) { [avatar onSelect:^(BOOL selected) {
if (selected) { if (selected) {
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForThread]; NSManagedObjectContext *moc = [MPiOSAppDelegate managedObjectContextForThreadIfReady];
if (!moc)
return;
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
activeUser.avatar = (unsigned)avatar.tag; activeUser.avatar = (unsigned)avatar.tag;
[activeUser.managedObjectContext saveToStore]; [moc saveToStore];
} }
} options:0]; } options:0];
avatar.selected = (a == [[MPiOSAppDelegate get] activeUserForThread].avatar); avatar.selected = (a == [[MPiOSAppDelegate get] activeUserForThread].avatar);
@@ -89,6 +93,21 @@
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
} }
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake) {
MPCheckpoint( MPCheckpointLogs, @{
@"trace": [MPiOSConfig get].traceMode
} );
[self performSegueWithIdentifier:@"MP_Logs" sender:self];
}
}
- (BOOL)shouldAutorotate { - (BOOL)shouldAutorotate {
return NO; return NO;
@@ -114,8 +133,12 @@
[[MPiOSAppDelegate get] export]; [[MPiOSAppDelegate get] export];
else if (cell == self.changeMPCell) { else if (cell == self.changeMPCell) {
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForThread]; NSManagedObjectContext *moc = [MPiOSAppDelegate managedObjectContextForThreadIfReady];
[[MPiOSAppDelegate get] changeMasterPasswordFor:activeUser inContext:activeUser.managedObjectContext didResetBlock:nil]; if (!moc)
return;
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
[[MPiOSAppDelegate get] changeMasterPasswordFor:activeUser saveInContext:moc didResetBlock:nil];
} }
[tableView deselectRowAtIndexPath:indexPath animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES];
@@ -125,9 +148,13 @@
- (void)didSelectType:(MPElementType)type { - (void)didSelectType:(MPElementType)type {
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForThread]; NSManagedObjectContext *moc = [MPiOSAppDelegate managedObjectContextForThreadIfReady];
if (!moc)
return;
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
activeUser.defaultType = type; activeUser.defaultType = type;
[activeUser.managedObjectContext saveToStore]; [moc saveToStore];
self.defaultTypeLabel.text = [[MPiOSAppDelegate get].key.algorithm shortNameOfType:activeUser.defaultType]; self.defaultTypeLabel.text = [[MPiOSAppDelegate get].key.algorithm shortNameOfType:activeUser.defaultType];
} }
@@ -141,12 +168,16 @@
- (IBAction)didToggleSwitch:(UISwitch *)sender { - (IBAction)didToggleSwitch:(UISwitch *)sender {
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForThread]; NSManagedObjectContext *moc = [MPiOSAppDelegate managedObjectContextForThreadIfReady];
if (!moc)
return;
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
if ((activeUser.saveKey = sender.on)) if ((activeUser.saveKey = sender.on))
[[MPiOSAppDelegate get] storeSavedKeyFor:activeUser]; [[MPiOSAppDelegate get] storeSavedKeyFor:activeUser];
else else
[[MPiOSAppDelegate get] forgetSavedKeyFor:activeUser]; [[MPiOSAppDelegate get] forgetSavedKeyFor:activeUser];
[activeUser.managedObjectContext saveToStore]; [moc saveToStore];
} }
@end @end

View File

@@ -77,7 +77,9 @@
[(UITextField *)[cell viewWithTag:2] setText:@"..."]; [(UITextField *)[cell viewWithTag:2] setText:@"..."];
NSString *name = selectedElement.name; NSString *name = selectedElement.name;
NSUInteger counter = ((MPElementGeneratedEntity *)selectedElement).counter; NSUInteger counter = 0;
if ([selectedElement isKindOfClass:[MPElementGeneratedEntity class]])
counter = ((MPElementGeneratedEntity *)selectedElement).counter;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{ dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{
NSString *typeContent = [MPAlgorithmDefault generateContentNamed:name ofType:cellType NSString *typeContent = [MPAlgorithmDefault generateContentNamed:name ofType:cellType

View File

@@ -8,12 +8,14 @@
#import <QuartzCore/QuartzCore.h> #import <QuartzCore/QuartzCore.h>
#import <Social/Social.h> #import <Social/Social.h>
#import <CoreGraphics/CoreGraphics.h>
#import "MPUnlockViewController.h" #import "MPUnlockViewController.h"
#import "MPiOSAppDelegate.h" #import "MPiOSAppDelegate.h"
#import "MPAppDelegate_Key.h" #import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h" #import "MPAppDelegate_Store.h"
@interface MPUnlockViewController() @interface MPUnlockViewController()
@property(strong, nonatomic) NSMutableDictionary *avatarToUserOID; @property(strong, nonatomic) NSMutableDictionary *avatarToUserOID;
@@ -28,6 +30,7 @@
@property(nonatomic, strong) NSArray *marqueeTipTexts; @property(nonatomic, strong) NSArray *marqueeTipTexts;
@end @end
@implementation MPUnlockViewController { @implementation MPUnlockViewController {
NSManagedObjectID *_selectedUserOID; NSManagedObjectID *_selectedUserOID;
} }
@@ -116,7 +119,8 @@
- (void)viewDidLoad { - (void)viewDidLoad {
[self.newsView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.masterpasswordapp.com/news.html"]]]; NSString *newsURL = PearlString( @"http://www.masterpasswordapp.com/news.html?version=%@", [[PearlInfoPlist get] CFBundleVersion] );
[self.newsView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:newsURL]]];
self.avatarToUserOID = [NSMutableDictionary dictionaryWithCapacity:3]; self.avatarToUserOID = [NSMutableDictionary dictionaryWithCapacity:3];
@@ -161,11 +165,11 @@
[self initializeWordLabel:wordLabel]; [self initializeWordLabel:wordLabel];
} recurse:NO]; } recurse:NO];
[[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock: [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock:
^(NSNotification *note) { ^(NSNotification *note) {
[self updateUsers]; [self updateUsers];
}]; }];
[[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidImportChangesNotification object:nil queue:nil [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidImportChangesNotification object:nil queue:nil
usingBlock:^(NSNotification *note) { usingBlock:^(NSNotification *note) {
[self updateUsers]; [self updateUsers];
}]; }];
@@ -206,6 +210,8 @@
- (void)viewDidAppear:(BOOL)animated { - (void)viewDidAppear:(BOOL)animated {
[self becomeFirstResponder];
if (!animated && !self.navigationController.presentedViewController) if (!animated && !self.navigationController.presentedViewController)
[[self findTargetedAvatar] setSelected:YES]; [[self findTargetedAvatar] setSelected:YES];
else else
@@ -251,10 +257,21 @@
self.emergencyGeneratorContainer.alpha = 0; self.emergencyGeneratorContainer.alpha = 0;
self.emergencyGeneratorContainer.hidden = NO; self.emergencyGeneratorContainer.hidden = NO;
[UIView animateWithDuration:0.5 animations:^{ self.emergencyGeneratorContainer.frame = CGRectSetX( self.emergencyGeneratorContainer.frame,
self.emergencyGeneratorContainer.frame.origin.x - 100 );
[UIView animateWithDuration:0.3 animations:^{
self.emergencyGeneratorContainer.frame = CGRectSetX( self.emergencyGeneratorContainer.frame,
self.emergencyGeneratorContainer.frame.origin.x + 150 );
self.emergencyGeneratorContainer.alpha = 1; self.emergencyGeneratorContainer.alpha = 1;
} completion:^(BOOL finished) { } completion:^(BOOL finished) {
if (!finished)
return;
[self.emergencyName becomeFirstResponder]; [self.emergencyName becomeFirstResponder];
[UIView animateWithDuration:0.2 animations:^{
self.emergencyGeneratorContainer.frame = CGRectSetX( self.emergencyGeneratorContainer.frame,
self.emergencyGeneratorContainer.frame.origin.x - 50 );
}];
}]; }];
} }
} }
@@ -344,20 +361,19 @@
[self.avatarToUserOID setObject:NilToNSNull([user objectID]) forKey:[NSValue valueWithNonretainedObject:avatar]]; [self.avatarToUserOID setObject:NilToNSNull([user objectID]) forKey:[NSValue valueWithNonretainedObject:avatar]];
if ([_selectedUserOID isEqual:[user objectID]]) { if ([_selectedUserOID isEqual:[user objectID]])
self.selectedUser = user;
avatar.selected = YES; avatar.selected = YES;
}
return avatar; return avatar;
} }
- (void)didToggleUserSelection { - (void)didToggleUserSelection {
MPUserEntity *selectedUser = [self selectedUserForThread]; NSManagedObjectContext *moc = [MPiOSAppDelegate managedObjectContextForThreadIfReady];
MPUserEntity *selectedUser = [self selectedUserInContext:moc];
if (!selectedUser) if (!selectedUser)
[self.passwordField resignFirstResponder]; [self.passwordField resignFirstResponder];
else if ([[MPiOSAppDelegate get] signInAsUser:selectedUser inContext:selectedUser.managedObjectContext usingMasterPassword:nil]) { else if ([[MPiOSAppDelegate get] signInAsUser:selectedUser saveInContext:moc usingMasterPassword:nil]) {
[self performSegueWithIdentifier:@"MP_Unlock" sender:self]; [self performSegueWithIdentifier:@"MP_Unlock" sender:self];
return; return;
} }
@@ -370,15 +386,17 @@
- (void)didSelectNewUserAvatar:(UIButton *)newUserAvatar { - (void)didSelectNewUserAvatar:(UIButton *)newUserAvatar {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) { if (![MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
MPUserEntity *newUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass( [MPUserEntity class] ) MPUserEntity
*newUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass( [MPUserEntity class] )
inManagedObjectContext:moc]; inManagedObjectContext:moc];
[self showNewUserNameAlertFor:newUser inContext:moc completion:^(BOOL finished) { [self showNewUserNameAlertFor:newUser inContext:moc completion:^(BOOL finished) {
newUserAvatar.selected = NO; newUserAvatar.selected = NO;
self.selectedUser = newUser; self.selectedUser = newUser;
}]; }];
}]; }])
newUserAvatar.selected = NO;
} }
- (void)showNewUserNameAlertFor:(MPUserEntity *)newUser inContext:(NSManagedObjectContext *)moc - (void)showNewUserNameAlertFor:(MPUserEntity *)newUser inContext:(NSManagedObjectContext *)moc
@@ -449,7 +467,12 @@
} }
// Confirm // Confirm
[moc performBlockAndWait:^{
[moc saveToStore]; [moc saveToStore];
NSError *error = nil;
if (![moc obtainPermanentIDsForObjects:@[ newUser ] error:&error])
err(@"Failed to obtain permanent object ID for new user: %@", error);
}];
completion( YES ); completion( YES );
[self updateUsers]; [self updateUsers];
@@ -481,7 +504,7 @@
if (selectedUser && !self.passwordView.alpha) { if (selectedUser && !self.passwordView.alpha) {
// User was just selected. // User was just selected.
self.passwordView.alpha = 1; self.passwordView.alpha = 1;
self.avatarsView.center = CGPointMake( 160, 180 ); self.avatarsView.frame = CGRectSetY( self.avatarsView.frame, 16 );
self.avatarsView.scrollEnabled = NO; self.avatarsView.scrollEnabled = NO;
self.nameLabel.center = CGPointMake( 160, 94 ); self.nameLabel.center = CGPointMake( 160, 94 );
self.nameLabel.backgroundColor = [UIColor blackColor]; self.nameLabel.backgroundColor = [UIColor blackColor];
@@ -492,7 +515,7 @@
// User was just deselected. // User was just deselected.
self.passwordField.text = nil; self.passwordField.text = nil;
self.passwordView.alpha = 0; self.passwordView.alpha = 0;
self.avatarsView.center = CGPointMake( 160, 310 ); self.avatarsView.frame = CGRectSetY( self.avatarsView.frame, 140 );
self.avatarsView.scrollEnabled = YES; self.avatarsView.scrollEnabled = YES;
self.nameLabel.center = CGPointMake( 160, 296 ); self.nameLabel.center = CGPointMake( 160, 296 );
self.nameLabel.backgroundColor = [UIColor clearColor]; self.nameLabel.backgroundColor = [UIColor clearColor];
@@ -534,7 +557,7 @@
UIButton *targetedAvatar = selectedAvatar; UIButton *targetedAvatar = selectedAvatar;
if (!targetedAvatar) { if (!targetedAvatar) {
targetedAvatar = [self findTargetedAvatar]; targetedAvatar = [self findTargetedAvatar];
targetedUser = [self userForAvatar:targetedAvatar]; targetedUser = [self userForAvatar:targetedAvatar inContext:[MPiOSAppDelegate managedObjectContextForThreadIfReady]];
} }
[self.avatarsView enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) { [self.avatarsView enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
@@ -552,7 +575,8 @@
} recurse:NO]; } recurse:NO];
if (allowScroll) { if (allowScroll) {
CGPoint targetContentOffset = CGPointMake( MAX(0, targetedAvatar.center.x - self.avatarsView.bounds.size.width / 2), CGPoint targetContentOffset = CGPointMake(
MAX(0, targetedAvatar.center.x - self.avatarsView.bounds.size.width / 2),
self.avatarsView.contentOffset.y ); self.avatarsView.contentOffset.y );
if (!CGPointEqualToPoint( self.avatarsView.contentOffset, targetContentOffset )) if (!CGPointEqualToPoint( self.avatarsView.contentOffset, targetContentOffset ))
[self.avatarsView setContentOffset:targetContentOffset animated:animated]; [self.avatarsView setContentOffset:targetContentOffset animated:animated];
@@ -618,7 +642,7 @@
[self setSpinnerActive:YES]; [self setSpinnerActive:YES];
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) { [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
BOOL unlocked = [[MPiOSAppDelegate get] signInAsUser:[self selectedUserInContext:moc] inContext:moc BOOL unlocked = [[MPiOSAppDelegate get] signInAsUser:[self selectedUserInContext:moc] saveInContext:moc
usingMasterPassword:self.passwordField.text]; usingMasterPassword:self.passwordField.text];
dispatch_async( dispatch_get_main_queue(), ^{ dispatch_async( dispatch_get_main_queue(), ^{
@@ -655,11 +679,7 @@
return avatar; return avatar;
} }
- (MPUserEntity *)userForAvatar:(UIButton *)avatar { - (MPUserEntity *)userForAvatar:(UIButton *)avatar inContext:(NSManagedObjectContext *)moc {
NSManagedObjectContext *moc = [MPiOSAppDelegate managedObjectContextForThreadIfReady];
if (!moc)
return nil;
NSManagedObjectID *userOID = NSNullToNil([self.avatarToUserOID objectForKey:[NSValue valueWithNonretainedObject:avatar]]); NSManagedObjectID *userOID = NSNullToNil([self.avatarToUserOID objectForKey:[NSValue valueWithNonretainedObject:avatar]]);
if (!userOID) if (!userOID)
@@ -919,7 +939,7 @@
[[self.emergencyGeneratorContainer findFirstResponderInHierarchy] resignFirstResponder]; [[self.emergencyGeneratorContainer findFirstResponderInHierarchy] resignFirstResponder];
if (animated) { if (animated) {
[UIView animateWithDuration:0.5 animations:^{ [UIView animateWithDuration:0.2 animations:^{
self.emergencyGeneratorContainer.alpha = 0; self.emergencyGeneratorContainer.alpha = 0;
} completion:^(BOOL finished) { } completion:^(BOOL finished) {
[self emergencyCloseAnimated:NO]; [self emergencyCloseAnimated:NO];
@@ -983,11 +1003,11 @@
if ([self selectedUserForThread]) if ([self selectedUserForThread])
return; return;
MPUserEntity *targetedUser = [self userForAvatar:[self findTargetedAvatar]]; NSManagedObjectContext *moc = [MPiOSAppDelegate managedObjectContextForThreadIfReady];
MPUserEntity *targetedUser = [self userForAvatar:[self findTargetedAvatar] inContext:moc];
if (!targetedUser) if (!targetedUser)
return; return;
NSManagedObjectContext *moc = targetedUser.managedObjectContext;
[PearlSheet showSheetWithTitle:targetedUser.name [PearlSheet showSheetWithTitle:targetedUser.name
viewStyle:UIActionSheetStyleBlackTranslucent viewStyle:UIActionSheetStyleBlackTranslucent
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) { initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
@@ -1007,7 +1027,7 @@
} }
if (buttonIndex == [sheet firstOtherButtonIndex]) if (buttonIndex == [sheet firstOtherButtonIndex])
[[MPiOSAppDelegate get] changeMasterPasswordFor:targetedUser inContext:moc didResetBlock:^{ [[MPiOSAppDelegate get] changeMasterPasswordFor:targetedUser saveInContext:moc didResetBlock:^{
dispatch_async( dispatch_get_main_queue(), ^{ dispatch_async( dispatch_get_main_queue(), ^{
[[self avatarForUser:targetedUser] setSelected:YES]; [[self avatarForUser:targetedUser] setSelected:YES];
} ); } );
@@ -1138,6 +1158,11 @@
- (void)setSelectedUser:(MPUserEntity *)selectedUser { - (void)setSelectedUser:(MPUserEntity *)selectedUser {
NSError *error = nil;
if (selectedUser.objectID.isTemporaryID &&
![selectedUser.managedObjectContext obtainPermanentIDsForObjects:@[ selectedUser ] error:&error])
err(@"Failed to obtain a permanent object ID after setting selected user: %@", error);
_selectedUserOID = selectedUser.objectID; _selectedUserOID = selectedUser.objectID;
} }

View File

@@ -17,8 +17,9 @@
- (void)showGuide; - (void)showGuide;
- (void)showSetup; - (void)showSetup;
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController; - (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController;
- (void)openFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController;
- (void)export; - (void)export;
- (void)changeMasterPasswordFor:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc didResetBlock:(void (^)(void))didReset; - (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void (^)(void))didReset;
@end @end

View File

@@ -12,15 +12,25 @@
#import "IASKSettingsReader.h" #import "IASKSettingsReader.h"
#import "GPPSignIn.h" #import "GPPSignIn.h"
@interface MPiOSAppDelegate()
@property(nonatomic, strong) PearlAlert *handleCloudContentAlert;
@property(nonatomic, strong) PearlAlert *fixCloudContentAlert;
@property(nonatomic, strong) PearlOverlay *storeLoading;
@end
@implementation MPiOSAppDelegate @implementation MPiOSAppDelegate
+ (void)initialize { + (void)initialize {
[MPiOSConfig get]; [MPiOSConfig get];
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
#ifdef DEBUG #ifdef DEBUG
[PearlLogger get].printLevel = PearlLogLevelDebug; [PearlLogger get].printLevel = PearlLogLevelDebug;
//[NSClassFromString(@"WebView") performSelector:NSSelectorFromString(@"_enableRemoteInspector")]; //[NSClassFromString(@"WebView") performSelector:NSSelectorFromString(@"_enableRemoteInspector")];
#else
if ([[MPiOSConfig get].sendInfo boolValue])
[PearlLogger get].printLevel = PearlLogLevelInfo;
#endif #endif
} }
@@ -202,23 +212,28 @@
[[Crashlytics sharedInstance] setObjectValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"]; [[Crashlytics sharedInstance] setObjectValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"];
#ifdef TESTFLIGHT_SDK_VERSION #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight addCustomEnvironmentInformation:[@([[MPConfig get].rememberLogin boolValue]) description] [TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPConfig get].rememberLogin)
forKey:@"rememberLogin"]; forKey:@"rememberLogin"];
[TestFlight addCustomEnvironmentInformation:[@([self storeManager].cloudEnabled) description] forKey:@"iCloud"]; [TestFlight addCustomEnvironmentInformation:PearlStringB([self storeManager].cloudEnabled)
[TestFlight addCustomEnvironmentInformation:[@([[MPConfig get].iCloudDecided boolValue]) description] forKey:@"iCloud"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPConfig get].iCloudDecided)
forKey:@"iCloudDecided"]; forKey:@"iCloudDecided"];
[TestFlight addCustomEnvironmentInformation:[@([[MPiOSConfig get].sendInfo boolValue]) description] forKey:@"sendInfo"]; [TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPiOSConfig get].sendInfo)
[TestFlight addCustomEnvironmentInformation:[@([[MPiOSConfig get].helpHidden boolValue]) description] forKey:@"sendInfo"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPiOSConfig get].helpHidden)
forKey:@"helpHidden"]; forKey:@"helpHidden"];
[TestFlight addCustomEnvironmentInformation:[@([[MPiOSConfig get].showSetup boolValue]) description] [TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPiOSConfig get].showSetup)
forKey:@"showQuickStart"]; forKey:@"showQuickStart"];
[TestFlight addCustomEnvironmentInformation:[@([[PearlConfig get].firstRun boolValue]) description] forKey:@"firstRun"]; [TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].firstRun)
[TestFlight addCustomEnvironmentInformation:[[PearlConfig get].launchCount description] forKey:@"launchCount"]; forKey:@"firstRun"];
[TestFlight addCustomEnvironmentInformation:[@([[PearlConfig get].askForReviews boolValue]) description] [TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].launchCount)
forKey:@"launchCount"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].askForReviews)
forKey:@"askForReviews"]; forKey:@"askForReviews"];
[TestFlight addCustomEnvironmentInformation:[[PearlConfig get].reviewAfterLaunches description] [TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].reviewAfterLaunches)
forKey:@"reviewAfterLaunches"]; forKey:@"reviewAfterLaunches"];
[TestFlight addCustomEnvironmentInformation:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"]; [TestFlight addCustomEnvironmentInformation:[PearlConfig get].reviewedVersion
forKey:@"reviewedVersion"];
#endif #endif
MPCheckpoint( MPCheckpointConfig, @{ MPCheckpoint( MPCheckpointConfig, @{
@"rememberLogin" : @([[MPConfig get].rememberLogin boolValue]), @"rememberLogin" : @([[MPConfig get].rememberLogin boolValue]),
@@ -228,9 +243,9 @@
@"helpHidden" : @([[MPiOSConfig get].helpHidden boolValue]), @"helpHidden" : @([[MPiOSConfig get].helpHidden boolValue]),
@"showQuickStart" : @([[MPiOSConfig get].showSetup boolValue]), @"showQuickStart" : @([[MPiOSConfig get].showSetup boolValue]),
@"firstRun" : @([[PearlConfig get].firstRun boolValue]), @"firstRun" : @([[PearlConfig get].firstRun boolValue]),
@"launchCount" : NilToNSNull([[PearlConfig get].launchCount description]), @"launchCount" : NilToNSNull([PearlConfig get].launchCount),
@"askForReviews" : @([[PearlConfig get].askForReviews boolValue]), @"askForReviews" : @([[PearlConfig get].askForReviews boolValue]),
@"reviewAfterLaunches" : NilToNSNull([[PearlConfig get].reviewAfterLaunches description]), @"reviewAfterLaunches" : NilToNSNull([PearlConfig get].reviewAfterLaunches),
@"reviewedVersion" : NilToNSNull([PearlConfig get].reviewedVersion) @"reviewedVersion" : NilToNSNull([PearlConfig get].reviewedVersion)
} ); } );
} }
@@ -261,6 +276,18 @@
[[MPiOSAppDelegate get] showSetup]; [[MPiOSAppDelegate get] showSetup];
} ); } );
MPCheckpoint(MPCheckpointStarted, @{
@"simulator" : PearlStringB([PearlDeviceUtils isSimulator]),
@"encrypted" : PearlStringB([PearlDeviceUtils isAppEncrypted]),
@"jailbroken" : PearlStringB([PearlDeviceUtils isJailbroken]),
@"platform" : [PearlDeviceUtils platform],
#ifdef APPSTORE
@"legal" : PearlStringB([PearlDeviceUtils isAppEncrypted]),
#else
@"legal" : @"YES",
#endif
});
return YES; return YES;
} }
@@ -434,11 +461,6 @@
MPCheckpoint( MPCheckpointShowSetup, nil ); MPCheckpoint( MPCheckpointShowSetup, nil );
} }
- (void)showFeedback {
[self showFeedbackWithLogs:NO forVC:nil];
}
- (void)showReview { - (void)showReview {
MPCheckpoint( MPCheckpointReview, nil ); MPCheckpoint( MPCheckpointReview, nil );
@@ -475,7 +497,9 @@
- (void)openFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController { - (void)openFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController {
NSString *userName = [[MPiOSAppDelegate get] activeUserForThread].name; NSString *userName = [[MPiOSAppDelegate get] activeUserForThread].name;
PearlLogLevel logLevel = [[MPiOSConfig get].sendInfo boolValue]? PearlLogLevelDebug: PearlLogLevelInfo; PearlLogLevel logLevel = PearlLogLevelInfo;
if (logs && ([[MPiOSConfig get].sendInfo boolValue] || [[MPiOSConfig get].traceMode boolValue]))
logLevel = PearlLogLevelDebug;
[[[PearlEMail alloc] initForEMailTo:@"Master Password Development <masterpassword@lyndir.com>" [[[PearlEMail alloc] initForEMailTo:@"Master Password Development <masterpassword@lyndir.com>"
subject:PearlString( @"Feedback for Master Password [%@]", subject:PearlString( @"Feedback for Master Password [%@]",
@@ -570,7 +594,7 @@
nil]; nil];
} }
- (void)changeMasterPasswordFor:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc didResetBlock:(void (^)(void))didReset { - (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void (^)(void))didReset {
[PearlAlert showAlertWithTitle:@"Changing Master Password" [PearlAlert showAlertWithTitle:@"Changing Master Password"
message: message:
@@ -603,11 +627,77 @@
- (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)value { - (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)value {
if (configKey == @selector(traceMode)) {
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
inf(@"Trace is now: %@", [[MPiOSConfig get].traceMode boolValue]? @"ON": @"OFF");
}
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
postNotificationName:MPCheckConfigNotification object:NSStringFromSelector( configKey ) userInfo:nil]; postNotificationName:MPCheckConfigNotification object:NSStringFromSelector( configKey ) userInfo:nil];
} }
#pragma mark - Google+
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager willLoadStoreIsCloud:(BOOL)isCloudStore {
dispatch_async( dispatch_get_main_queue(), ^{
[self.handleCloudContentAlert cancelAlertAnimated:YES];
if (![self.storeLoading isVisible])
self.storeLoading = [PearlOverlay showOverlayWithTitle:@"Opening Your Data"];
} );
[super ubiquityStoreManager:manager willLoadStoreIsCloud:isCloudStore];
}
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didLoadStoreForCoordinator:(NSPersistentStoreCoordinator *)coordinator
isCloud:(BOOL)isCloudStore {
[super ubiquityStoreManager:manager didLoadStoreForCoordinator:coordinator isCloud:isCloudStore];
dispatch_async( dispatch_get_main_queue(), ^{
[self.handleCloudContentAlert cancelAlertAnimated:YES];
[self.fixCloudContentAlert cancelAlertAnimated:YES];
[self.storeLoading cancelOverlayAnimated:YES];
} );
}
- (BOOL)ubiquityStoreManager:(UbiquityStoreManager *)manager handleCloudContentCorruptionWithHealthyStore:(BOOL)storeHealthy {
if (manager.cloudEnabled && !storeHealthy && !([self.handleCloudContentAlert.alertView isVisible] || [self.fixCloudContentAlert.alertView isVisible]))
dispatch_async( dispatch_get_main_queue(), ^{
[self.storeLoading cancelOverlayAnimated:YES];
[self showCloudContentAlert];
} );
return NO;
}
- (void)showCloudContentAlert {
__weak MPiOSAppDelegate *wSelf = self;
[self.handleCloudContentAlert cancelAlertAnimated:NO];
self.handleCloudContentAlert = [PearlAlert showActivityWithTitle:@"iCloud Sync Problem" message:
@"Waiting for your other device to autocorrect the problem..."
initAlert:^(UIAlertView *alert) {
[alert addButtonWithTitle:@"Fix Now"];
}];
self.handleCloudContentAlert.tappedButtonBlock = ^(UIAlertView *alert, NSInteger buttonIndex) {
wSelf.fixCloudContentAlert = [PearlAlert showAlertWithTitle:@"Fix iCloud Now" message:
@"This problem can usually be autocorrected by opening the app on another device where you recently made changes.\n"
@"You can correct the problem from this device anyway, but recent changes made on another device might get lost."
viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:
^(UIAlertView *alert_, NSInteger buttonIndex_) {
if (buttonIndex_ == alert_.cancelButtonIndex)
[wSelf showCloudContentAlert];
if (buttonIndex_ == [alert_ firstOtherButtonIndex])
[wSelf.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:YES];
}
cancelTitle:[PearlStrings get].commonButtonBack otherTitles:@"Fix Anyway", nil];
};
}
#pragma mark - Google+ #pragma mark - Google+
- (NSDictionary *)googlePlusInfo { - (NSDictionary *)googlePlusInfo {

View File

@@ -16,5 +16,6 @@
@property(nonatomic, retain) NSNumber *actionsTipShown; @property(nonatomic, retain) NSNumber *actionsTipShown;
@property(nonatomic, retain) NSNumber *typeTipShown; @property(nonatomic, retain) NSNumber *typeTipShown;
@property(nonatomic, retain) NSNumber *loginNameTipShown; @property(nonatomic, retain) NSNumber *loginNameTipShown;
@property(nonatomic, retain) NSNumber *traceMode;
@end @end

View File

@@ -8,7 +8,7 @@
@implementation MPiOSConfig @implementation MPiOSConfig
@dynamic sendInfo, helpHidden, siteInfoHidden, showSetup, actionsTipShown, typeTipShown, loginNameTipShown; @dynamic helpHidden, siteInfoHidden, showSetup, actionsTipShown, typeTipShown, loginNameTipShown, traceMode;
- (id)init { - (id)init {
@@ -20,9 +20,10 @@
NSStringFromSelector( @selector(siteInfoHidden) ) : @YES, NSStringFromSelector( @selector(siteInfoHidden) ) : @YES,
NSStringFromSelector( @selector(showSetup) ) : @YES, NSStringFromSelector( @selector(showSetup) ) : @YES,
NSStringFromSelector( @selector(iTunesID) ) : @"510296984", NSStringFromSelector( @selector(iTunesID) ) : @"510296984",
NSStringFromSelector( @selector(actionsTipShown) ) : PearlBoolNot(self.firstRun), NSStringFromSelector( @selector(actionsTipShown) ) : @(!self.firstRun),
NSStringFromSelector( @selector(typeTipShown) ) : PearlBoolNot(self.firstRun), NSStringFromSelector( @selector(typeTipShown) ) : @(!self.firstRun),
NSStringFromSelector( @selector(loginNameTipShown) ) : PearlBool(NO) NSStringFromSelector( @selector(loginNameTipShown) ) : @NO,
NSStringFromSelector( @selector(traceMode) ) : @NO
}]; }];
return self; return self;

View File

@@ -9,7 +9,7 @@
<objects> <objects>
<tableViewController id="NKe-nv-566" customClass="MPTypeViewController" sceneMemberID="viewController"> <tableViewController id="NKe-nv-566" customClass="MPTypeViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="btl-G4-V0S"> <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="btl-G4-V0S">
<rect key="frame" x="0.0" y="64" width="320" height="416"/> <rect key="frame" x="0.0" y="64" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/> <color key="backgroundColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/>
<view key="tableFooterView" contentMode="scaleToFill" id="aNa-wb-cYK"> <view key="tableFooterView" contentMode="scaleToFill" id="aNa-wb-cYK">
@@ -476,16 +476,109 @@ Your passwords will be AES-encrypted with your master password.</string>
</objects> </objects>
<point key="canvasLocation" x="1537" y="145"/> <point key="canvasLocation" x="1537" y="145"/>
</scene> </scene>
<!--Logs View Controller - Log Inspector-->
<scene sceneID="AKo-Ze-vcJ">
<objects>
<viewController id="Tx0-mM-kHk" customClass="MPLogsViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="3oc-v8-YGP">
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="mtJ-9r-6yT">
<rect key="frame" x="0.0" y="0.0" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" id="ojc-Tn-DM1">
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<string key="text">119-20:51:52 MPiOSAppDelegate.m:36 | INFO : Initializing TestFlight
119-20:51:52 MPiOSAppDelegate.m:70 | INFO : Initializing Google+
119-20:51:52 MPiOSAppDelegate.m:80 | INFO : Initializing Crashlytics
119-20:51:52 MPiOSAppDelegate.m:109 | INFO : Initializing Localytics
119-20:51:53 PearlAppDelegate.m:71 | INFO : Master Password (MasterPassword) 1.4 (1.4.0) (GIT: 1.4-0-g8a4eecd-dirty)
119-20:51:53 MPiOSAppDelegate.m:257 | INFO : Started up with device identifier: A8C51CDA-6F60-4F0C-BFC9-68A08F2F2DD7
119-20:51:59 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] (Re)loading store...
119-20:51:59 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Will load cloud store: 0B3CA2DF-5796-44DF-B5E0-121EC3846464 (definite).
119-20:51:59 PearlConfig.m:193 | INFO : Lock screen will appear
119-20:51:59 MPiOSAppDelegate.m:412 | INFO : Re-activated
119-20:51:59 PearlConfig.m:180 | DEBUG : MPiOSConfig.launchCount = [70 ->] 71
119-20:52:02 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Clearing stores...
119-20:52:03 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Loading store without seeding.
119-20:52:09 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Cloud enabled and successfully loaded cloud store.
119-20:52:09 MPAppDelegate_Store.m:299 | INFO : Using iCloud? 1
119-20:52:12 MPAppDelegate_Key.m:28 | INFO : Found key in keychain for: b55911588b178466be1d6392597e899b8de46f9a
119-20:52:12 MPAppDelegate_Key.m:132 | INFO : Logged in: b55911588b178466be1d6392597e899b8de46f9a
119-20:52:13 MPUnlockViewController.m:229 | INFO : Lock screen will disappear
119-20:52:13 MPMainViewController.m:142 | INFO : Main will appear
119-20:52:16 MPMainViewController.m:734 | INFO : Action: Preferences
119-20:52:17 MPMainViewController.m:187 | INFO : Main will disappear.
</string>
<color key="textColor" cocoaTouchSystemColor="lightTextColor"/>
<fontDescription key="fontDescription" name="AmericanTypewriter" family="American Typewriter" pointSize="9"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
<toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="QPO-l8-Opz">
<rect key="frame" x="0.0" y="460" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<items>
<barButtonItem systemItem="compose" id="Yvq-If-VqG">
<connections>
<action selector="mail:" destination="Tx0-mM-kHk" id="Efg-Nz-tf2"/>
</connections>
</barButtonItem>
<barButtonItem systemItem="refresh" id="fzf-tt-Vc3">
<connections>
<action selector="refresh:" destination="Tx0-mM-kHk" id="Xur-Ed-PN7"/>
</connections>
</barButtonItem>
<barButtonItem systemItem="flexibleSpace" id="GcH-O1-v3J"/>
<barButtonItem style="plain" id="yi1-I8-uzn">
<segmentedControl key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bar" selectedSegmentIndex="0" id="lzO-Kl-IPf">
<rect key="frame" x="191" y="8" width="123" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<segments>
<segment title="Normal"/>
<segment title="Debug"/>
</segments>
<color key="tintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
<connections>
<action selector="toggleLevelControl:" destination="Tx0-mM-kHk" eventType="valueChanged" id="Snn-NE-BnD"/>
</connections>
</segmentedControl>
<color key="tintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
</barButtonItem>
</items>
</toolbar>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
<navigationItem key="navigationItem" title="Log Inspector" id="RrC-3Q-nBN">
<barButtonItem key="rightBarButtonItem" systemItem="done" id="RYe-xc-zYv">
<connections>
<action selector="close:" destination="Tx0-mM-kHk" id="KrS-tQ-IOf"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="levelControl" destination="lzO-Kl-IPf" id="B7k-yM-dR0"/>
<outlet property="logView" destination="ojc-Tn-DM1" id="mOS-LG-HHA"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="2Jl-Qq-bOz" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2078" y="145"/>
</scene>
<!--Main View Controller - Master Password--> <!--Main View Controller - Master Password-->
<scene sceneID="U26-Zf-euQ"> <scene sceneID="U26-Zf-euQ">
<objects> <objects>
<viewController id="PQa-Xl-A3x" customClass="MPMainViewController" sceneMemberID="viewController"> <viewController id="PQa-Xl-A3x" customClass="MPMainViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ep0-Hn-5TR"> <view key="view" contentMode="scaleToFill" id="Ep0-Hn-5TR">
<rect key="frame" x="0.0" y="64" width="320" height="416"/> <rect key="frame" x="0.0" y="64" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" image="background.png" id="0hY-LL-ITu"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" image="background.png" id="0hY-LL-ITu">
<rect key="frame" x="0.0" y="44" width="320" height="372"/> <rect key="frame" x="0.0" y="44" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView> </imageView>
<view contentMode="scaleToFill" id="Juh-jm-UDr" userLabel="View - Content"> <view contentMode="scaleToFill" id="Juh-jm-UDr" userLabel="View - Content">
@@ -665,7 +758,7 @@ Your passwords will be AES-encrypted with your master password.</string>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view> </view>
<view contentMode="scaleToFill" id="61G-By-qLB" userLabel="View - Help"> <view contentMode="scaleToFill" id="61G-By-qLB" userLabel="View - Help">
<rect key="frame" x="0.0" y="246" width="320" height="170"/> <rect key="frame" x="0.0" y="334" width="320" height="170"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="top" image="Square-bottom.png" id="lbm-A0-3PK"> <imageView userInteractionEnabled="NO" contentMode="top" image="Square-bottom.png" id="lbm-A0-3PK">
@@ -828,7 +921,7 @@ Your passwords will be AES-encrypted with your master password.</string>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view> </view>
<view hidden="YES" alpha="0.0" contentMode="scaleToFill" id="6wk-NU-VQG" userLabel="View - Outdated Alert"> <view hidden="YES" alpha="0.0" contentMode="scaleToFill" id="6wk-NU-VQG" userLabel="View - Outdated Alert">
<rect key="frame" x="10" y="230" width="300" height="180"/> <rect key="frame" x="10" y="318" width="300" height="180"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews> <subviews>
<imageView contentMode="scaleToFill" image="tip_alert_black.png" id="f30-i7-VBv"> <imageView contentMode="scaleToFill" image="tip_alert_black.png" id="f30-i7-VBv">
@@ -906,7 +999,7 @@ These sites should be upgraded and their account's passwords updated as soon as
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view> </view>
<view hidden="YES" alpha="0.0" contentMode="scaleToFill" id="yRY-qt-gz8" userLabel="View - Alert"> <view hidden="YES" alpha="0.0" contentMode="scaleToFill" id="yRY-qt-gz8" userLabel="View - Alert">
<rect key="frame" x="10" y="230" width="300" height="180"/> <rect key="frame" x="10" y="318" width="300" height="180"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_alert_black.png" id="TUv-Tl-xTc"> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_alert_black.png" id="TUv-Tl-xTc">
@@ -1085,20 +1178,20 @@ L4m3P4sSw0rD</string>
<objects> <objects>
<viewController storyboardIdentifier="MPUnlockViewController" wantsFullScreenLayout="YES" modalTransitionStyle="flipHorizontal" id="Nbn-Rv-sP1" customClass="MPUnlockViewController" sceneMemberID="viewController"> <viewController storyboardIdentifier="MPUnlockViewController" wantsFullScreenLayout="YES" modalTransitionStyle="flipHorizontal" id="Nbn-Rv-sP1" customClass="MPUnlockViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="GeE-5J-ZZO"> <view key="view" contentMode="scaleToFill" id="GeE-5J-ZZO">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/> <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="QWe-Gw-rD3"> <imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="QWe-Gw-rD3">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/> <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView> </imageView>
<view contentMode="scaleToFill" id="PHH-XC-9QQ" userLabel="View - UI Container"> <view contentMode="scaleToFill" id="PHH-XC-9QQ" userLabel="View - UI Container">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/> <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_spinner.png" id="27q-lX-0vy"> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_spinner.png" id="27q-lX-0vy">
<rect key="frame" x="105" y="40" width="110" height="110"/> <rect key="frame" x="105" y="46" width="110" height="110"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView> </imageView>
<view contentMode="scaleToFill" id="JTj-nh-BWs" userLabel="Word Wall"> <view contentMode="scaleToFill" id="JTj-nh-BWs" userLabel="Word Wall">
<rect key="frame" x="0.0" y="0.0" width="960" height="200"/> <rect key="frame" x="0.0" y="0.0" width="960" height="200"/>
@@ -1252,7 +1345,7 @@ L4m3P4sSw0rD</string>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view> </view>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.5" contentMode="left" text="Tap and hold to delete or reset user." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="DBJ-Qi-ZcF"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.5" contentMode="left" text="Tap and hold to delete or reset user." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="DBJ-Qi-ZcF">
<rect key="frame" x="20" y="460" width="280" height="20"/> <rect key="frame" x="20" y="548" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="12"/> <fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="12"/>
<color key="textColor" cocoaTouchSystemColor="lightTextColor"/> <color key="textColor" cocoaTouchSystemColor="lightTextColor"/>
@@ -1444,7 +1537,7 @@ You could use the word wall for inspiration in finding a memorable master passw
</connections> </connections>
</button> </button>
<webView opaque="NO" contentMode="scaleToFill" id="rGU-aZ-XVm"> <webView opaque="NO" contentMode="scaleToFill" id="rGU-aZ-XVm">
<rect key="frame" x="0.0" y="411" width="320" height="44"/> <rect key="frame" x="0.0" y="499" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<dataDetectorType key="dataDetectorTypes"/> <dataDetectorType key="dataDetectorTypes"/>
@@ -1456,15 +1549,15 @@ You could use the word wall for inspiration in finding a memorable master passw
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view> </view>
<view hidden="YES" alpha="0.30000000000000016" contentMode="scaleToFill" id="KNa-Xb-RuE" userLabel="View - Emergency Generator"> <view hidden="YES" alpha="0.30000000000000016" contentMode="scaleToFill" id="KNa-Xb-RuE" userLabel="View - Emergency Generator">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/> <rect key="frame" x="-100" y="0.0" width="520" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<view contentMode="scaleToFill" id="vdf-Kn-Sle"> <view contentMode="scaleToFill" id="vdf-Kn-Sle">
<rect key="frame" x="0.0" y="20" width="320" height="346"/> <rect key="frame" x="100" y="20" width="320" height="434"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_panel_display.png" id="jLf-TI-anP"> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_panel_display.png" id="jLf-TI-anP">
<rect key="frame" x="11" y="0.0" width="298" height="346"/> <rect key="frame" x="11" y="0.0" width="298" height="434"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.050000000000000003" y="0.10000000000000001" width="0.89999999999999991" height="0.79999999999999982"/> <rect key="contentStretch" x="0.050000000000000003" y="0.10000000000000001" width="0.89999999999999991" height="0.79999999999999982"/>
</imageView> </imageView>
@@ -1563,11 +1656,11 @@ You could use the word wall for inspiration in finding a memorable master passw
</connections> </connections>
</button> </button>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" hidesWhenStopped="YES" style="whiteLarge" id="3Ax-91-gVM"> <activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" hidesWhenStopped="YES" style="whiteLarge" id="3Ax-91-gVM">
<rect key="frame" x="141.5" y="300" width="37" height="37"/> <rect key="frame" x="141" y="388" width="37" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
</activityIndicatorView> </activityIndicatorView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="r9J-C9-Bt1"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="r9J-C9-Bt1">
<rect key="frame" x="20" y="292" width="280" height="54"/> <rect key="frame" x="20" y="380" width="280" height="54"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="AmericanTypewriter-Bold" family="American Typewriter" pointSize="30"/> <fontDescription key="fontDescription" name="AmericanTypewriter-Bold" family="American Typewriter" pointSize="30"/>
<size key="titleShadowOffset" width="0.0" height="1"/> <size key="titleShadowOffset" width="0.0" height="1"/>
@@ -1583,7 +1676,7 @@ You could use the word wall for inspiration in finding a memorable master passw
</connections> </connections>
</button> </button>
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="sD9-hR-UAI" userLabel="View - Content Tip"> <view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="sD9-hR-UAI" userLabel="View - Content Tip">
<rect key="frame" x="55" y="266" width="210" height="60"/> <rect key="frame" x="55" y="354" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" id="Lua-xm-WX6"> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" id="Lua-xm-WX6">
@@ -1679,11 +1772,11 @@ You could use the word wall for inspiration in finding a memorable master passw
<objects> <objects>
<viewController id="Q4b-t4-pwH" customClass="MPSetupViewController" sceneMemberID="viewController"> <viewController id="Q4b-t4-pwH" customClass="MPSetupViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="FnB-rI-puV"> <view key="view" contentMode="scaleToFill" id="FnB-rI-puV">
<rect key="frame" x="0.0" y="64" width="320" height="416"/> <rect key="frame" x="0.0" y="64" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="RjU-5e-mti"> <imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="RjU-5e-mti">
<rect key="frame" x="0.0" y="-64" width="320" height="480"/> <rect key="frame" x="0.0" y="-64" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView> </imageView>
<imageView userInteractionEnabled="NO" contentMode="top" image="cloud.png" id="Ahr-aa-V1N"> <imageView userInteractionEnabled="NO" contentMode="top" image="cloud.png" id="Ahr-aa-V1N">
@@ -1737,7 +1830,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<objects> <objects>
<tableViewController id="idA-Pj-1U9" customClass="MPElementListAllViewController" sceneMemberID="viewController"> <tableViewController id="idA-Pj-1U9" customClass="MPElementListAllViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="48" sectionHeaderHeight="22" sectionFooterHeight="22" id="N83-sj-4tl"> <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="48" sectionHeaderHeight="22" sectionFooterHeight="22" id="N83-sj-4tl">
<rect key="frame" x="0.0" y="20" width="320" height="460"/> <rect key="frame" x="0.0" y="20" width="320" height="548"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<navigationBar key="tableHeaderView" contentMode="scaleToFill" id="l0p-Tu-L9k"> <navigationBar key="tableHeaderView" contentMode="scaleToFill" id="l0p-Tu-L9k">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/> <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
@@ -1776,11 +1869,11 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<objects> <objects>
<viewController wantsFullScreenLayout="YES" id="2Th-Tb-22a" customClass="MPAppsViewController" sceneMemberID="viewController"> <viewController wantsFullScreenLayout="YES" id="2Th-Tb-22a" customClass="MPAppsViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="AhE-Ed-ajP"> <view key="view" contentMode="scaleToFill" id="AhE-Ed-ajP">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/> <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<view contentMode="scaleToFill" id="DHZ-5g-6vT"> <view contentMode="scaleToFill" id="DHZ-5g-6vT">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/> <rect key="frame" x="0.0" y="44" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="book.png" id="wjL-OU-K7k"> <imageView userInteractionEnabled="NO" contentMode="center" image="book.png" id="wjL-OU-K7k">
@@ -1850,7 +1943,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<objects> <objects>
<tableViewController id="oLN-6u-GLb" customClass="MPPreferencesViewController" sceneMemberID="viewController"> <tableViewController id="oLN-6u-GLb" customClass="MPPreferencesViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="oSh-Ap-kLt"> <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="oSh-Ap-kLt">
<rect key="frame" x="0.0" y="64" width="320" height="416"/> <rect key="frame" x="0.0" y="64" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/> <color key="backgroundColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/>
<view key="tableFooterView" contentMode="scaleToFill" id="63M-7L-M7o"> <view key="tableFooterView" contentMode="scaleToFill" id="63M-7L-M7o">
@@ -2172,6 +2265,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<outlet property="defaultTypeLabel" destination="vKJ-1b-NeO" id="4vz-2l-xXk"/> <outlet property="defaultTypeLabel" destination="vKJ-1b-NeO" id="4vz-2l-xXk"/>
<outlet property="exportCell" destination="X2m-92-Qzh" id="zjs-9C-uKX"/> <outlet property="exportCell" destination="X2m-92-Qzh" id="zjs-9C-uKX"/>
<outlet property="savePasswordSwitch" destination="ilG-0h-SOb" id="iZD-gQ-pve"/> <outlet property="savePasswordSwitch" destination="ilG-0h-SOb" id="iZD-gQ-pve"/>
<segue destination="Tx0-mM-kHk" kind="push" identifier="MP_Logs" id="rWT-Kr-cAs"/>
</connections> </connections>
</tableViewController> </tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="CEl-jQ-l9k" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="CEl-jQ-l9k" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -2183,7 +2277,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<objects> <objects>
<tableViewController id="Vrp-Gl-7qn" customClass="IASKAppSettingsViewController" sceneMemberID="viewController"> <tableViewController id="Vrp-Gl-7qn" customClass="IASKAppSettingsViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="singleLineEtched" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="NCp-ii-ux0"> <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="singleLineEtched" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="NCp-ii-ux0">
<rect key="frame" x="0.0" y="64" width="320" height="416"/> <rect key="frame" x="0.0" y="64" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/> <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes> <prototypes>
@@ -2267,11 +2361,11 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<objects> <objects>
<viewController id="ZgN-2j-05b" customClass="MPSetupViewController" sceneMemberID="viewController"> <viewController id="ZgN-2j-05b" customClass="MPSetupViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="QIH-dS-sqD"> <view key="view" contentMode="scaleToFill" id="QIH-dS-sqD">
<rect key="frame" x="0.0" y="64" width="320" height="416"/> <rect key="frame" x="0.0" y="64" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="FTf-06-1Pg"> <imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="FTf-06-1Pg">
<rect key="frame" x="0.0" y="-64" width="320" height="480"/> <rect key="frame" x="0.0" y="-64" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView> </imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Getting Started" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="FkR-cP-Y7K"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Getting Started" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="FkR-cP-Y7K">
@@ -2282,7 +2376,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" usesAttributedText="YES" id="hwP-ds-GDh"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" usesAttributedText="YES" id="hwP-ds-GDh">
<rect key="frame" x="20" y="137" width="280" height="279"/> <rect key="frame" x="20" y="137" width="280" height="367"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<attributedString key="attributedText"> <attributedString key="attributedText">
@@ -2394,11 +2488,11 @@ You can make passwords for anything, like email addresses, sites or real-world t
<objects> <objects>
<viewController id="myN-X7-9Tg" customClass="MPGuideViewController" sceneMemberID="viewController"> <viewController id="myN-X7-9Tg" customClass="MPGuideViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="vkG-Oi-PHo"> <view key="view" contentMode="scaleToFill" id="vkG-Oi-PHo">
<rect key="frame" x="0.0" y="20" width="320" height="460"/> <rect key="frame" x="0.0" y="20" width="320" height="548"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" image="background.png" id="C2i-R4-36i"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" image="background.png" id="C2i-R4-36i">
<rect key="frame" x="0.0" y="44" width="320" height="416"/> <rect key="frame" x="0.0" y="44" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView> </imageView>
<view clipsSubviews="YES" contentMode="scaleToFill" id="vSk-nT-Vwf" userLabel="View - Display"> <view clipsSubviews="YES" contentMode="scaleToFill" id="vSk-nT-Vwf" userLabel="View - Display">
@@ -2538,7 +2632,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</scopeButtonTitles> </scopeButtonTitles>
</searchBar> </searchBar>
<view alpha="0.60000000000000009" contentMode="scaleToFill" id="Ahl-o0-lMv"> <view alpha="0.60000000000000009" contentMode="scaleToFill" id="Ahl-o0-lMv">
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/> <rect key="frame" x="0.0" y="0.0" width="320" height="548"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="3wI-lo-tWc"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="3wI-lo-tWc">
@@ -2558,7 +2652,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</connections> </connections>
</button> </button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="UHf-cp-97W"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="UHf-cp-97W">
<rect key="frame" x="33" y="414" width="44" height="44"/> <rect key="frame" x="33" y="502" width="44" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<accessibility key="accessibilityConfiguration" hint="" label="Close"/> <accessibility key="accessibilityConfiguration" hint="" label="Close"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
@@ -2574,7 +2668,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</connections> </connections>
</button> </button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="jDS-Vh-ETL"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="jDS-Vh-ETL">
<rect key="frame" x="124" y="190" width="72" height="80"/> <rect key="frame" x="124" y="234" width="72" height="80"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" hint="" label="Close"/> <accessibility key="accessibilityConfiguration" hint="" label="Close"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
@@ -2590,7 +2684,7 @@ You can make passwords for anything, like email addresses, sites or real-world t
</connections> </connections>
</button> </button>
<progressView opaque="NO" contentMode="scaleToFill" id="nf7-oM-7dh"> <progressView opaque="NO" contentMode="scaleToFill" id="nf7-oM-7dh">
<rect key="frame" x="85" y="431" width="150" height="9"/> <rect key="frame" x="85" y="519" width="150" height="9"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="progressTintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/> <color key="progressTintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
</progressView> </progressView>
@@ -2729,11 +2823,11 @@ You can make passwords for anything, like email addresses, sites or real-world t
<objects> <objects>
<viewController id="kSj-yX-DmT" customClass="MPSetupViewController" sceneMemberID="viewController"> <viewController id="kSj-yX-DmT" customClass="MPSetupViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="sT4-Jb-e5D"> <view key="view" contentMode="scaleToFill" id="sT4-Jb-e5D">
<rect key="frame" x="0.0" y="64" width="320" height="416"/> <rect key="frame" x="0.0" y="64" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="Eqt-R0-LTj"> <imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="Eqt-R0-LTj">
<rect key="frame" x="0.0" y="-64" width="320" height="480"/> <rect key="frame" x="0.0" y="-64" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView> </imageView>
<imageView userInteractionEnabled="NO" contentMode="top" image="unlocked.png" id="4ah-P0-2DG"> <imageView userInteractionEnabled="NO" contentMode="top" image="unlocked.png" id="4ah-P0-2DG">
@@ -2869,7 +2963,6 @@ However, it means that anyone who finds your device unlocked can do the same.</s
<relationships> <relationships>
<relationship kind="action" name="close"/> <relationship kind="action" name="close"/>
<relationship kind="action" name="play"/> <relationship kind="action" name="play"/>
<relationship kind="action" name="toggleVolume"/>
<relationship kind="outlet" name="content" candidateClass="UIView"/> <relationship kind="outlet" name="content" candidateClass="UIView"/>
<relationship kind="outlet" name="contentButton" candidateClass="UIButton"/> <relationship kind="outlet" name="contentButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="contentText" candidateClass="UITextField"/> <relationship kind="outlet" name="contentText" candidateClass="UITextField"/>
@@ -2885,7 +2978,17 @@ However, it means that anyone who finds your device unlocked can do the same.</s
<relationship kind="outlet" name="typeTip" candidateClass="UIView"/> <relationship kind="outlet" name="typeTip" candidateClass="UIView"/>
<relationship kind="outlet" name="usernameButton" candidateClass="UIButton"/> <relationship kind="outlet" name="usernameButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="usernameTip" candidateClass="UIView"/> <relationship kind="outlet" name="usernameTip" candidateClass="UIView"/>
<relationship kind="outlet" name="volumeButton" candidateClass="UIButton"/> </relationships>
</class>
<class className="MPLogsViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPLogsViewController.h"/>
<relationships>
<relationship kind="action" name="close:" candidateClass="UIBarButtonItem"/>
<relationship kind="action" name="mail:" candidateClass="UIBarButtonItem"/>
<relationship kind="action" name="refresh:" candidateClass="UIBarButtonItem"/>
<relationship kind="action" name="toggleLevelControl:" candidateClass="UISegmentedControl"/>
<relationship kind="outlet" name="levelControl" candidateClass="UISegmentedControl"/>
<relationship kind="outlet" name="logView" candidateClass="UITextView"/>
</relationships> </relationships>
</class> </class>
<class className="MPMainViewController" superclassName="UIViewController"> <class className="MPMainViewController" superclassName="UIViewController">
@@ -3014,7 +3117,7 @@ However, it means that anyone who finds your device unlocked can do the same.</s
<simulatedMetricsContainer key="defaultSimulatedMetrics"> <simulatedMetricsContainer key="defaultSimulatedMetrics">
<nil key="statusBar"/> <nil key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/> <simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination"/> <simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer> </simulatedMetricsContainer>
<inferredMetricsTieBreakers> <inferredMetricsTieBreakers>
<segue reference="jgo-j3-gbW"/> <segue reference="jgo-j3-gbW"/>

View File

@@ -39,28 +39,19 @@
<string>Icon-72</string> <string>Icon-72</string>
<string>Icon-Small</string> <string>Icon-Small</string>
<string>Icon-Small-50</string> <string>Icon-Small-50</string>
<string>Icon.png</string>
<string>Icon@2x.png</string>
</array> </array>
<key>UIPrerenderedIcon</key> <key>UIPrerenderedIcon</key>
<true/> <true/>
</dict> </dict>
<key>UINewsstandIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string></string>
</array>
<key>UINewsstandBindingEdge</key>
<string>UINewsstandBindingEdgeLeft</string>
<key>UINewsstandBindingType</key>
<string>UINewsstandBindingTypeMagazine</string>
</dict>
</dict> </dict>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>com.lyndir.lhunath.MasterPassword</string> <string>com.lyndir.lhunath.MasterPassword</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>MasterPassword</string> <string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>

View File

@@ -16,10 +16,14 @@
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3942A356B639724157982 /* PearlOverlay.h */; }; 93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3942A356B639724157982 /* PearlOverlay.h */; };
93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; }; 93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; };
93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; }; 93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; };
93D399A3008C590EE104F856 /* NSURL+UbiquityStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3970B24FC0B53D989F7E3 /* NSURL+UbiquityStoreManager.m */; };
93D399BBC0A7EC746CB1B19B /* MPLogsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D391943675426839501BB8 /* MPLogsViewController.h */; };
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 */; };
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 */; };
93D39EC9C559D2922B048CFE /* NSURL+UbiquityStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3957F61D8AFE3B6580C32 /* NSURL+UbiquityStoreManager.h */; };
93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A28369954D147E239BA /* MPSetupViewController.m */; }; 93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A28369954D147E239BA /* MPSetupViewController.m */; };
DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */; }; DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */; };
DA095E75172F4CD8001C948B /* MPLogsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3979190DACEBD1F6AE9F4 /* MPLogsViewController.m */; };
DA30E9CE15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9CB15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h */; }; DA30E9CE15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9CB15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h */; };
DA30E9CF15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CC15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m */; }; DA30E9CF15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CC15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m */; };
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; }; DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
@@ -968,13 +972,17 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; }; 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; };
93D390FADEB325D8D54A957D /* PearlOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlOverlay.m; sourceTree = "<group>"; }; 93D390FADEB325D8D54A957D /* PearlOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlOverlay.m; sourceTree = "<group>"; };
93D391943675426839501BB8 /* MPLogsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLogsViewController.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>"; };
93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; }; 93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; };
93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; }; 93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = "<group>"; }; 93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = "<group>"; };
93D3956915634581E737B38C /* PearlNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlNavigationController.m; sourceTree = "<group>"; }; 93D3956915634581E737B38C /* PearlNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlNavigationController.m; sourceTree = "<group>"; };
93D3957F61D8AFE3B6580C32 /* NSURL+UbiquityStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+UbiquityStoreManager.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>"; };
93D3970B24FC0B53D989F7E3 /* NSURL+UbiquityStoreManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+UbiquityStoreManager.m"; sourceTree = "<group>"; };
93D39730673227EFF6DEFF19 /* MPSetupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSetupViewController.h; sourceTree = "<group>"; }; 93D39730673227EFF6DEFF19 /* MPSetupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSetupViewController.h; sourceTree = "<group>"; };
93D3979190DACEBD1F6AE9F4 /* MPLogsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPLogsViewController.m; sourceTree = "<group>"; };
93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlNavigationController.h; sourceTree = "<group>"; }; 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlNavigationController.h; sourceTree = "<group>"; };
93D39A28369954D147E239BA /* MPSetupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSetupViewController.m; sourceTree = "<group>"; }; 93D39A28369954D147E239BA /* MPSetupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSetupViewController.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>"; };
@@ -997,7 +1005,7 @@
DA5A09DE171A70E4005284AB /* play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play@2x.png"; sourceTree = "<group>"; }; DA5A09DE171A70E4005284AB /* play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play@2x.png"; sourceTree = "<group>"; };
DA5A09E8171BB0F7005284AB /* unlocked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unlocked.png; sourceTree = "<group>"; }; DA5A09E8171BB0F7005284AB /* unlocked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unlocked.png; sourceTree = "<group>"; };
DA5A09E9171BB0F7005284AB /* unlocked@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "unlocked@2x.png"; sourceTree = "<group>"; }; DA5A09E9171BB0F7005284AB /* unlocked@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "unlocked@2x.png"; sourceTree = "<group>"; };
DA5BFA44147E415C00F98B1E /* MasterPassword-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MasterPassword-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; DA5BFA44147E415C00F98B1E /* MasterPassword.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MasterPassword.app; sourceTree = BUILT_PRODUCTS_DIR; };
DA5BFA48147E415C00F98B1E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; DA5BFA48147E415C00F98B1E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
@@ -2131,7 +2139,7 @@
DA5BFA45147E415C00F98B1E /* Products */ = { DA5BFA45147E415C00F98B1E /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DA5BFA44147E415C00F98B1E /* MasterPassword-iOS.app */, DA5BFA44147E415C00F98B1E /* MasterPassword.app */,
DAC77CAD148291A600BCF976 /* libPearl.a */, DAC77CAD148291A600BCF976 /* libPearl.a */,
DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */, DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */,
DAC6326C148680650075AEA5 /* libjrswizzle.a */, DAC6326C148680650075AEA5 /* libjrswizzle.a */,
@@ -3007,6 +3015,8 @@
DABD3BFC1711E2DC00CF925C /* main.m */, DABD3BFC1711E2DC00CF925C /* main.m */,
93D39A28369954D147E239BA /* MPSetupViewController.m */, 93D39A28369954D147E239BA /* MPSetupViewController.m */,
93D39730673227EFF6DEFF19 /* MPSetupViewController.h */, 93D39730673227EFF6DEFF19 /* MPSetupViewController.h */,
93D3979190DACEBD1F6AE9F4 /* MPLogsViewController.m */,
93D391943675426839501BB8 /* MPLogsViewController.h */,
); );
path = iOS; path = iOS;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -3066,6 +3076,8 @@
DACA22B71705DE7D002C6C22 /* UbiquityStoreManager.m */, DACA22B71705DE7D002C6C22 /* UbiquityStoreManager.m */,
DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */, DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */,
DACA22B91705DE7D002C6C22 /* NSError+UbiquityStoreManager.m */, DACA22B91705DE7D002C6C22 /* NSError+UbiquityStoreManager.m */,
93D3970B24FC0B53D989F7E3 /* NSURL+UbiquityStoreManager.m */,
93D3957F61D8AFE3B6580C32 /* NSURL+UbiquityStoreManager.h */,
); );
name = UbiquityStoreManager; name = UbiquityStoreManager;
path = UbiquityStoreManager/UbiquityStoreManager; path = UbiquityStoreManager/UbiquityStoreManager;
@@ -3523,6 +3535,8 @@
files = ( files = (
DACA22BC1705DE7D002C6C22 /* NSError+UbiquityStoreManager.h in Headers */, DACA22BC1705DE7D002C6C22 /* NSError+UbiquityStoreManager.h in Headers */,
DACA22BE1705DE7D002C6C22 /* UbiquityStoreManager.h in Headers */, DACA22BE1705DE7D002C6C22 /* UbiquityStoreManager.h in Headers */,
93D399BBC0A7EC746CB1B19B /* MPLogsViewController.h in Headers */,
93D39EC9C559D2922B048CFE /* NSURL+UbiquityStoreManager.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -3685,9 +3699,9 @@
productReference = DA497B9715E8C90E00B52167 /* libGoogle+.a */; productReference = DA497B9715E8C90E00B52167 /* libGoogle+.a */;
productType = "com.apple.product-type.library.static"; productType = "com.apple.product-type.library.static";
}; };
DA5BFA43147E415C00F98B1E /* MasterPassword-iOS */ = { DA5BFA43147E415C00F98B1E /* MasterPassword */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword-iOS" */; buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword" */;
buildPhases = ( buildPhases = (
DA5BFA40147E415C00F98B1E /* Sources */, DA5BFA40147E415C00F98B1E /* Sources */,
DA5BFA41147E415C00F98B1E /* Frameworks */, DA5BFA41147E415C00F98B1E /* Frameworks */,
@@ -3699,9 +3713,9 @@
); );
dependencies = ( dependencies = (
); );
name = "MasterPassword-iOS"; name = MasterPassword;
productName = MasterPassword; productName = MasterPassword;
productReference = DA5BFA44147E415C00F98B1E /* MasterPassword-iOS.app */; productReference = DA5BFA44147E415C00F98B1E /* MasterPassword.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
}; };
DA829E50159847E0002417D3 /* FontReplacer */ = { DA829E50159847E0002417D3 /* FontReplacer */ = {
@@ -3912,7 +3926,7 @@
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
targets = ( targets = (
DA5BFA43147E415C00F98B1E /* MasterPassword-iOS */, DA5BFA43147E415C00F98B1E /* MasterPassword */,
DAC77CAC148291A600BCF976 /* Pearl */, DAC77CAC148291A600BCF976 /* Pearl */,
DAC6325C1486805C0075AEA5 /* uicolor-utilities */, DAC6325C1486805C0075AEA5 /* uicolor-utilities */,
DAC6326B148680650075AEA5 /* jrswizzle */, DAC6326B148680650075AEA5 /* jrswizzle */,
@@ -4655,7 +4669,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = "/bin/bash -e"; shellPath = "/bin/bash -e";
shellScript = "PATH+=:/usr/libexec\n\naddPlistWithKey() {\n local key=$1 type=$2 value=$3 plist=${4:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Delete :'$key'\" \"$plist\" 2>/dev/null || true\n PlistBuddy -c \"Add :'$key' '$type' '$value'\" \"$plist\"\n}\nsetPlistWithKey() {\n local key=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Set :'$key' '$value'\" \"$plist\"\n}\ngetPlistWithKey() {\n local key=$1 plist=${2:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Print :'$key'\" \"$plist\"\n}\nsetSettingWithTitle() {\n local i title=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Settings.bundle/Root.plist\"}\n \n for (( i=0; 1; ++i )); do\n PlistBuddy -c \"Print :PreferenceSpecifiers:$i\" \"$plist\" &>/dev/null || break\n echo \"Checking preference specifier $i\"\n \n [[ $(PlistBuddy -c \"Print :PreferenceSpecifiers:$i:Title\" \"$plist\" 2>/dev/null) = $title ]] || continue\n \n echo \"Correct title, setting value.\"\n PlistBuddy -c \"Set :PreferenceSpecifiers:$i:DefaultValue $value\" \"$plist\"\n break\n done\n}\n\ndescription=$(git describe --always --dirty --long)\nbuild=${description%-g*} build=${build//-/.}\ntag=${description%%-*}\n\naddPlistWithKey GITDescription string \"$description\"\nsetPlistWithKey CFBundleVersion \"$build\"\nsetPlistWithKey CFBundleShortVersionString \"$tag\"\n\nsetSettingWithTitle \"Build\" \"$build\"\nsetSettingWithTitle \"Version\" \"$tag\"\nsetSettingWithTitle \"Copyright\" \"$(getPlistWithKey NSHumanReadableCopyright)\"\n"; shellScript = "PATH+=:/usr/libexec\n\naddPlistWithKey() {\n local key=$1 type=$2 value=$3 plist=${4:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Delete :'$key'\" \"$plist\" 2>/dev/null || true\n PlistBuddy -c \"Add :'$key' '$type' '$value'\" \"$plist\"\n}\nsetPlistWithKey() {\n local key=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Set :'$key' '$value'\" \"$plist\"\n}\ngetPlistWithKey() {\n local key=$1 plist=${2:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Print :'$key'\" \"$plist\"\n}\nsetSettingWithTitle() {\n local i title=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Settings.bundle/Root.plist\"}\n \n for (( i=0; 1; ++i )); do\n PlistBuddy -c \"Print :PreferenceSpecifiers:$i\" \"$plist\" &>/dev/null || break\n echo \"Checking preference specifier $i\"\n \n [[ $(PlistBuddy -c \"Print :PreferenceSpecifiers:$i:Title\" \"$plist\" 2>/dev/null) = $title ]] || continue\n \n echo \"Correct title, setting value.\"\n PlistBuddy -c \"Set :PreferenceSpecifiers:$i:DefaultValue $value\" \"$plist\"\n break\n done\n}\n\ndescription=$(git describe --always --dirty --long)\ncommit=${description##*-g} commit=$((0x$commit))\nversion=${description%-g*} version=${version//-/.}\n\naddPlistWithKey GITDescription string \"$description\"\nsetPlistWithKey CFBundleVersion \"$commit\"\nsetPlistWithKey CFBundleShortVersionString \"$version\"\n\nsetSettingWithTitle \"Build\" \"$commit\"\nsetSettingWithTitle \"Version\" \"$version\"\nsetSettingWithTitle \"Copyright\" \"$(getPlistWithKey NSHumanReadableCopyright)\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
DAD3125D155288AA00A3F9ED /* Run Script: Crashlytics */ = { DAD3125D155288AA00A3F9ED /* Run Script: Crashlytics */ = {
@@ -4689,6 +4703,7 @@
files = ( files = (
DACA22BB1705DE7D002C6C22 /* UbiquityStoreManager.m in Sources */, DACA22BB1705DE7D002C6C22 /* UbiquityStoreManager.m in Sources */,
DACA22BD1705DE7D002C6C22 /* NSError+UbiquityStoreManager.m in Sources */, DACA22BD1705DE7D002C6C22 /* NSError+UbiquityStoreManager.m in Sources */,
93D399A3008C590EE104F856 /* NSURL+UbiquityStoreManager.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -4771,6 +4786,7 @@
DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */, DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */,
DABD3C271711E2DC00CF925C /* main.m in Sources */, DABD3C271711E2DC00CF925C /* main.m in Sources */,
93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */, 93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */,
DA095E75172F4CD8001C948B /* MPLogsViewController.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -4890,7 +4906,7 @@
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
DA3EF19E15A47AEB003ABF4E /* PBXTargetDependency */ = { DA3EF19E15A47AEB003ABF4E /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
target = DA5BFA43147E415C00F98B1E /* MasterPassword-iOS */; target = DA5BFA43147E415C00F98B1E /* MasterPassword */;
targetProxy = DA3EF19D15A47AEB003ABF4E /* PBXContainerItemProxy */; targetProxy = DA3EF19D15A47AEB003ABF4E /* PBXContainerItemProxy */;
}; };
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
@@ -5084,7 +5100,7 @@
GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
@@ -5154,7 +5170,7 @@
GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
@@ -5279,7 +5295,7 @@
GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
@@ -5563,7 +5579,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = "AdHoc-iOS"; defaultConfigurationName = "AdHoc-iOS";
}; };
DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword-iOS" */ = { DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
DA5BFA6E147E415C00F98B1E /* Debug-iOS */, DA5BFA6E147E415C00F98B1E /* Debug-iOS */,
@@ -5631,6 +5647,7 @@
DAFC5661172C573B00CB5CC5 /* AppStore-iOS */, DAFC5661172C573B00CB5CC5 /* AppStore-iOS */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = "AdHoc-iOS";
}; };
/* End XCConfigurationList section */ /* End XCConfigurationList section */

View File

@@ -15,8 +15,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-iOS.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-iOS" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj"> ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
@@ -43,8 +43,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-iOS.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-iOS" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj"> ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
@@ -61,8 +61,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-iOS.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-iOS" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj"> ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>

View File

@@ -15,8 +15,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-iOS.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-iOS" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj"> ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
@@ -33,8 +33,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-iOS.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-iOS" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj"> ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
@@ -52,8 +52,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-iOS.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-iOS" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj"> ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
@@ -70,8 +70,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E" BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword-iOS.app" BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword-iOS" BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj"> ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>

2
Press

Submodule Press updated: 59d660c6de...88f1de4ef2