Core Data context fixes and migration fixes.
[FIXED] More careful Core Data threading and context usage. [FIXED] iOS bug when migrating, now using USM's copy migration. [ADDED] Better handling of store changes while in Main VC and Element List VCs.
This commit is contained in:
parent
07e44a46ae
commit
d27a0fdbad
2
External/UbiquityStoreManager
vendored
2
External/UbiquityStoreManager
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 25a30fadcb80e337a664127c6c86c4fc46e96e5f
|
Subproject commit 9a4d52c382ae01f81cc9d94982b58222b3240f73
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
@interface MPAppDelegate_Shared(Key)
|
@interface MPAppDelegate_Shared(Key)
|
||||||
|
|
||||||
- (BOOL)signInAsUser:(MPUserEntity *)user usingMasterPassword:(NSString *)password;
|
- (BOOL)signInAsUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc usingMasterPassword:(NSString *)password;
|
||||||
- (void)signOutAnimated:(BOOL)animated;
|
- (void)signOutAnimated:(BOOL)animated;
|
||||||
|
|
||||||
- (void)storeSavedKeyFor:(MPUserEntity *)user;
|
- (void)storeSavedKeyFor:(MPUserEntity *)user;
|
||||||
|
@ -77,18 +77,20 @@ 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 usingMasterPassword:(NSString *)password {
|
- (BOOL)signInAsUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc usingMasterPassword:(NSString *)password {
|
||||||
|
|
||||||
|
if (password)
|
||||||
|
NSAssert(![NSThread isMainThread], @"Computing key may not happen from the main thread.");
|
||||||
|
|
||||||
assert(!password || ![NSThread isMainThread]); // If we need to computing a key, this operation shouldn't be on the main thread.
|
|
||||||
MPKey *tryKey = nil;
|
MPKey *tryKey = nil;
|
||||||
|
|
||||||
// Method 1: When the user has no keyID set, set a new key from the given master password.
|
// Method 1: When the user has no keyID set, set a new key from the given master password.
|
||||||
if (!user.keyID) {
|
if (!user.keyID) {
|
||||||
if ([password length]) if ((tryKey = [MPAlgorithmDefault keyForPassword:password ofUserNamed:user.name])) {
|
if ([password length] && (tryKey = [MPAlgorithmDefault keyForPassword:password ofUserNamed:user.name])) {
|
||||||
user.keyID = tryKey.keyID;
|
user.keyID = tryKey.keyID;
|
||||||
|
|
||||||
// Migrate existing elements.
|
// Migrate existing elements.
|
||||||
[self migrateElementsForUser:user inContext:user.managedObjectContext toKey:tryKey];
|
[self migrateElementsForUser:user inContext:moc toKey:tryKey];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +155,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
user.lastUsed = [NSDate date];
|
user.lastUsed = [NSDate date];
|
||||||
[user.managedObjectContext saveToStore];
|
[moc saveToStore];
|
||||||
self.activeUser = user;
|
self.activeUser = user;
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPSignedInNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPSignedInNotification object:self];
|
||||||
|
@ -26,19 +26,7 @@
|
|||||||
|
|
||||||
- (MPUserEntity *)activeUserForThread {
|
- (MPUserEntity *)activeUserForThread {
|
||||||
|
|
||||||
if (!_activeUserOID)
|
return [self activeUserInContext:[MPAppDelegate_Shared managedObjectContextForThreadIfReady]];
|
||||||
return nil;
|
|
||||||
|
|
||||||
NSManagedObjectContext *moc = [MPAppDelegate_Shared managedObjectContextForThreadIfReady];
|
|
||||||
if (!moc)
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
NSError *error;
|
|
||||||
MPUserEntity *activeUser = (MPUserEntity *)[moc existingObjectWithID:_activeUserOID error:&error];
|
|
||||||
if (!activeUser)
|
|
||||||
err(@"Failed to retrieve active user: %@", error);
|
|
||||||
|
|
||||||
return activeUser;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (MPUserEntity *)activeUserInContext:(NSManagedObjectContext *)moc {
|
- (MPUserEntity *)activeUserInContext:(NSManagedObjectContext *)moc {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
@implementation MPAppDelegate_Shared(Store)
|
@implementation MPAppDelegate_Shared(Store)
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
PearlAssociatedObjectProperty(PearlAlert*, HandleCloudContentAlert, handleCloudContentAlert);
|
PearlAssociatedObjectProperty(PearlAlert*, HandleCloudContentAlert, handleCloudContentAlert);
|
||||||
PearlAssociatedObjectProperty(PearlAlert*, FixCloudContentAlert, fixCloudContentAlert);
|
PearlAssociatedObjectProperty(PearlAlert*, FixCloudContentAlert, fixCloudContentAlert);
|
||||||
PearlAssociatedObjectProperty(PearlOverlay*, StoreLoading, storeLoading);
|
PearlAssociatedObjectProperty(PearlOverlay*, StoreLoading, storeLoading);
|
||||||
#endif
|
#endif
|
||||||
@ -157,8 +157,6 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
NSMigratePersistentStoresAutomaticallyOption : @YES,
|
NSMigratePersistentStoresAutomaticallyOption : @YES,
|
||||||
NSInferMappingModelAutomaticallyOption : @YES
|
NSInferMappingModelAutomaticallyOption : @YES
|
||||||
};
|
};
|
||||||
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
|
|
||||||
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
|
|
||||||
|
|
||||||
// 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:[manager URLForLocalStoreDirectory].path
|
||||||
@ -168,31 +166,13 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the old local store.
|
if (![manager copyMigrateStore:oldLocalStoreURL withOptions:oldLocalStoreOptions
|
||||||
NSPersistentStore *oldStore = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:oldLocalStoreURL
|
toStore:newLocalStoreURL withOptions:newLocalStoreOptions
|
||||||
options:oldLocalStoreOptions error:&error];
|
error:nil cause:nil context:nil]) {
|
||||||
if (!oldStore) {
|
|
||||||
err(@"While opening old store for migration %@: %@", oldLocalStoreURL.path, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Migrate to the new local store.
|
|
||||||
if (![psc migratePersistentStore:oldStore toURL:newLocalStoreURL options:newLocalStoreOptions withType:NSSQLiteStoreType
|
|
||||||
error:&error]) {
|
|
||||||
err(@"While migrating local store from %@ -> %@: %@", oldLocalStoreURL, newLocalStoreURL, error);
|
|
||||||
manager.localStoreURL = oldLocalStoreURL;
|
manager.localStoreURL = oldLocalStoreURL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean-up.
|
|
||||||
for (NSPersistentStore *store in psc.persistentStores)
|
|
||||||
if (![psc removePersistentStore:store error:&error]) {
|
|
||||||
err(@"While removing the migrated store from the store context: %@", error);
|
|
||||||
}
|
|
||||||
if (![[NSFileManager defaultManager] removeItemAtURL:oldLocalStoreURL error:&error]) {
|
|
||||||
err(@"While deleting the old local store: %@", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
inf(@"Successfully migrated old to new local store.");
|
inf(@"Successfully migrated old to new local store.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,32 +240,10 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
|
if (![manager copyMigrateStore:oldCloudStoreURL withOptions:oldCloudStoreOptions
|
||||||
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
|
toStore:newCloudStoreURL withOptions:newCloudStoreOptions
|
||||||
|
error:nil cause:nil context:nil])
|
||||||
// Open the old cloud store.
|
|
||||||
NSPersistentStore *oldStore = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:oldCloudStoreURL
|
|
||||||
options:oldCloudStoreOptions error:&error];
|
|
||||||
if (!oldStore) {
|
|
||||||
err(@"While opening old store for migration %@: %@", oldCloudStoreURL.path, error);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// Migrate to the new cloud store.
|
|
||||||
if (![psc migratePersistentStore:oldStore toURL:newCloudStoreURL options:newCloudStoreOptions withType:NSSQLiteStoreType
|
|
||||||
error:&error]) {
|
|
||||||
err(@"While migrating cloud store from %@ -> %@: %@", oldCloudStoreURL.path, newCloudStoreURL.path, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean-up.
|
|
||||||
for (NSPersistentStore *store in psc.persistentStores)
|
|
||||||
if (![psc removePersistentStore:store error:&error]) {
|
|
||||||
err(@"While removing the migrated store from the store context: %@", error);
|
|
||||||
}
|
|
||||||
if (![[NSFileManager defaultManager] removeItemAtURL:oldCloudStoreURL error:&error]) {
|
|
||||||
err(@"While deleting the old cloud store: %@", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"LocalUUIDKey"];
|
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"LocalUUIDKey"];
|
||||||
inf(@"Successfully migrated old to new cloud store.");
|
inf(@"Successfully migrated old to new cloud store.");
|
||||||
@ -322,7 +280,6 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
|
|
||||||
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager willLoadStoreIsCloud:(BOOL)isCloudStore {
|
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager willLoadStoreIsCloud:(BOOL)isCloudStore {
|
||||||
|
|
||||||
// FIXME
|
|
||||||
self.privateManagedObjectContext = nil;
|
self.privateManagedObjectContext = nil;
|
||||||
self.mainManagedObjectContext = nil;
|
self.mainManagedObjectContext = nil;
|
||||||
|
|
||||||
@ -413,6 +370,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
cancelTitle:[PearlStrings get].commonButtonBack otherTitles:@"Fix Anyway", nil];
|
cancelTitle:[PearlStrings get].commonButtonBack otherTitles:@"Fix Anyway", nil];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#pragma mark - Import / Export
|
#pragma mark - Import / Export
|
||||||
|
@ -13,6 +13,16 @@
|
|||||||
NSDateFormatter *_dateFormatter;
|
NSDateFormatter *_dateFormatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock:
|
||||||
|
^(NSNotification *note) {
|
||||||
|
[self updateData];
|
||||||
|
}];
|
||||||
|
|
||||||
|
[super viewDidLoad];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)addElementNamed:(NSString *)siteName completion:(void (^)(BOOL success))completion {
|
- (void)addElementNamed:(NSString *)siteName completion:(void (^)(BOOL success))completion {
|
||||||
|
|
||||||
if (![siteName length]) {
|
if (![siteName length]) {
|
||||||
@ -105,8 +115,12 @@
|
|||||||
- (void)updateData {
|
- (void)updateData {
|
||||||
|
|
||||||
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForThread];
|
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForThread];
|
||||||
if (!activeUser)
|
if (!activeUser) {
|
||||||
|
_fetchedResultsControllerByLastUsed = nil;
|
||||||
|
_fetchedResultsControllerByUses = nil;
|
||||||
|
[self.tableView reloadData];
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Build predicate.
|
// Build predicate.
|
||||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user == %@", activeUser];
|
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user == %@", activeUser];
|
||||||
|
@ -63,11 +63,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
|
|
||||||
|
|
||||||
[self.delegate didSelectElement:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
|
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
|
||||||
|
|
||||||
controller.searchBar.text = @"";
|
controller.searchBar.text = @"";
|
||||||
|
@ -77,10 +77,10 @@
|
|||||||
self.alertBody.text = nil;
|
self.alertBody.text = nil;
|
||||||
self.toolTipEditIcon.hidden = YES;
|
self.toolTipEditIcon.hidden = YES;
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:self queue:nil usingBlock:
|
||||||
addObserverForName:UIApplicationDidEnterBackgroundNotification object:self queue:nil usingBlock:^(NSNotification *note) {
|
^(NSNotification *note) {
|
||||||
self.suppressOutdatedAlert = NO;
|
self.suppressOutdatedAlert = NO;
|
||||||
}];
|
}];
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:MPElementUpdatedNotification object:nil queue:nil usingBlock:
|
[[NSNotificationCenter defaultCenter] addObserverForName:MPElementUpdatedNotification object:nil queue:nil usingBlock:
|
||||||
^void(NSNotification *note) {
|
^void(NSNotification *note) {
|
||||||
MPElementEntity *activeElement = [self activeElementForThread];
|
MPElementEntity *activeElement = [self activeElementForThread];
|
||||||
@ -107,6 +107,11 @@
|
|||||||
[self.navigationController popToRootViewControllerAnimated:animated];
|
[self.navigationController popToRootViewControllerAnimated:animated];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock:
|
||||||
|
^(NSNotification *note) {
|
||||||
|
if (!self.activeElementForThread)
|
||||||
|
[self didSelectElement:nil];
|
||||||
|
}];
|
||||||
|
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
}
|
}
|
||||||
@ -584,37 +589,43 @@
|
|||||||
|
|
||||||
- (void)changeActiveElementWithoutWarningDo:(BOOL (^)(MPElementEntity *activeElement))task; {
|
- (void)changeActiveElementWithoutWarningDo:(BOOL (^)(MPElementEntity *activeElement))task; {
|
||||||
|
|
||||||
MPElementEntity *activeElement = [self activeElementForThread];
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
NSString *oldPassword = [activeElement.content description];
|
MPElementEntity *activeElement = [self activeElementInContext:context];
|
||||||
if (!task( activeElement ))
|
if (!activeElement)
|
||||||
return;
|
return;
|
||||||
NSString *newPassword = [activeElement.content description];
|
|
||||||
|
|
||||||
// Save.
|
NSString *oldPassword = [activeElement.content description];
|
||||||
[activeElement.managedObjectContext saveToStore];
|
if (!task( activeElement ))
|
||||||
|
return;
|
||||||
|
NSString *newPassword = [activeElement.content description];
|
||||||
|
|
||||||
// Update the UI.
|
// Save.
|
||||||
dispatch_async( dispatch_get_main_queue(), ^{
|
[context saveToStore];
|
||||||
[self updateAnimated:YES];
|
|
||||||
|
|
||||||
// Show new and old password.
|
// Update the UI.
|
||||||
if ([oldPassword length] && ![oldPassword isEqualToString:newPassword])
|
dispatch_async( dispatch_get_main_queue(), ^{
|
||||||
[self showAlertWithTitle:@"Password Changed!"
|
[self updateAnimated:YES];
|
||||||
message:PearlString( @"The password for %@ has changed.\n\n"
|
|
||||||
@"IMPORTANT:\n"
|
// Show new and old password.
|
||||||
@"Don't forget to update the site with your new password! "
|
if ([oldPassword length] && ![oldPassword isEqualToString:newPassword])
|
||||||
@"Your old password was:\n"
|
[self showAlertWithTitle:@"Password Changed!"
|
||||||
@"%@", activeElement.name, oldPassword )];
|
message:PearlString( @"The password for %@ has changed.\n\n"
|
||||||
} );
|
@"IMPORTANT:\n"
|
||||||
|
@"Don't forget to update the site with your new password! "
|
||||||
|
@"Your old password was:\n"
|
||||||
|
@"%@", activeElement.name, oldPassword )];
|
||||||
|
} );
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (MPElementEntity *)activeElementForThread {
|
- (MPElementEntity *)activeElementForThread {
|
||||||
|
|
||||||
if (!_activeElementOID)
|
return [self activeElementInContext:[MPiOSAppDelegate managedObjectContextForThreadIfReady]];
|
||||||
return nil;
|
}
|
||||||
|
|
||||||
NSManagedObjectContext *moc = [MPiOSAppDelegate managedObjectContextForThreadIfReady];
|
- (MPElementEntity *)activeElementInContext:(NSManagedObjectContext *)moc {
|
||||||
if (!moc)
|
|
||||||
|
if (!_activeElementOID)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
NSError *error;
|
NSError *error;
|
||||||
@ -801,47 +812,45 @@
|
|||||||
|
|
||||||
- (void)didSelectElement:(MPElementEntity *)element {
|
- (void)didSelectElement:(MPElementEntity *)element {
|
||||||
|
|
||||||
if (!element)
|
inf(@"Selected: %@", element.name);
|
||||||
return;
|
|
||||||
|
|
||||||
_activeElementOID = element.objectID;
|
_activeElementOID = element.objectID;
|
||||||
[self closeAlert];
|
[self closeAlert];
|
||||||
[self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement) {
|
|
||||||
if ([activeElement use] == 1)
|
|
||||||
[self showAlertWithTitle:@"New Site" message:
|
|
||||||
PearlString( @"You've just created a password for %@.\n\n"
|
|
||||||
@"IMPORTANT:\n"
|
|
||||||
@"Go to %@ and set or change the password for your account to the password above.\n"
|
|
||||||
@"Do this right away: if you forget, you may have trouble remembering which password to use to log into the site later on.",
|
|
||||||
activeElement.name, activeElement.name )];
|
|
||||||
return YES;
|
|
||||||
}];
|
|
||||||
|
|
||||||
MPElementEntity *activeElement = [self activeElementForThread];
|
if (element) {
|
||||||
inf(@"Selected: %@", activeElement.name);
|
[self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement) {
|
||||||
|
if ([activeElement use] == 1)
|
||||||
if (![[MPiOSConfig get].typeTipShown boolValue])
|
[self showAlertWithTitle:@"New Site" message:
|
||||||
[UIView animateWithDuration:0.5f animations:^{
|
PearlString( @"You've just created a password for %@.\n\n"
|
||||||
self.typeTipContainer.alpha = 1;
|
@"IMPORTANT:\n"
|
||||||
} completion:^(BOOL finished) {
|
@"Go to %@ and set or change the password for your account to the password above.\n"
|
||||||
if (finished) {
|
@"Do this right away: if you forget, you may have trouble remembering which password to use to log into the site later on.",
|
||||||
[MPiOSConfig get].typeTipShown = PearlBool(YES);
|
activeElement.name, activeElement.name )];
|
||||||
|
return YES;
|
||||||
dispatch_after(
|
|
||||||
dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ), dispatch_get_main_queue(), ^{
|
|
||||||
[UIView animateWithDuration:0.2f animations:^{
|
|
||||||
self.typeTipContainer.alpha = 0;
|
|
||||||
}];
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
if (![[MPiOSConfig get].typeTipShown boolValue])
|
||||||
|
[UIView animateWithDuration:0.5f animations:^{
|
||||||
|
self.typeTipContainer.alpha = 1;
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
if (finished) {
|
||||||
|
[MPiOSConfig get].typeTipShown = PearlBool(YES);
|
||||||
|
|
||||||
|
dispatch_after(
|
||||||
|
dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ), dispatch_get_main_queue(), ^{
|
||||||
|
[UIView animateWithDuration:0.2f animations:^{
|
||||||
|
self.typeTipContainer.alpha = 0;
|
||||||
|
}];
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
[self.searchDisplayController setActive:NO animated:YES];
|
[self.searchDisplayController setActive:NO animated:YES];
|
||||||
self.searchDisplayController.searchBar.text = activeElement.name;
|
self.searchDisplayController.searchBar.text = element.name;
|
||||||
|
|
||||||
MPCheckpoint( MPCheckpointUseType, @{
|
MPCheckpoint( MPCheckpointUseType, @{
|
||||||
@"type" : activeElement.typeName,
|
@"type" : element.typeName,
|
||||||
@"version" : @(activeElement.version)
|
@"version" : @(element.version)
|
||||||
} );
|
} );
|
||||||
|
|
||||||
[self updateAnimated:YES];
|
[self updateAnimated:YES];
|
||||||
|
@ -14,8 +14,6 @@
|
|||||||
#import "MPAppDelegate_Key.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
#import "MPAppDelegate_Store.h"
|
#import "MPAppDelegate_Store.h"
|
||||||
|
|
||||||
#import "GPPSignIn.h"
|
|
||||||
|
|
||||||
@interface MPUnlockViewController()
|
@interface MPUnlockViewController()
|
||||||
|
|
||||||
@property(strong, nonatomic) NSMutableDictionary *avatarToUserOID;
|
@property(strong, nonatomic) NSMutableDictionary *avatarToUserOID;
|
||||||
@ -163,26 +161,26 @@
|
|||||||
[self initializeWordLabel:wordLabel];
|
[self initializeWordLabel:wordLabel];
|
||||||
} recurse:NO];
|
} recurse:NO];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock:
|
||||||
addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
|
^(NSNotification *note) {
|
||||||
[self updateUsers];
|
[self updateUsers];
|
||||||
}];
|
}];
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidImportChangesNotification object:nil queue:nil
|
||||||
addObserverForName:UbiquityManagedStoreDidImportChangesNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
|
usingBlock:^(NSNotification *note) {
|
||||||
[self updateUsers];
|
[self updateUsers];
|
||||||
}];
|
}];
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:nil usingBlock:
|
||||||
addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
|
^(NSNotification *note) {
|
||||||
[self emergencyCloseAnimated:NO];
|
[self emergencyCloseAnimated:NO];
|
||||||
self.uiContainer.alpha = 0;
|
self.uiContainer.alpha = 0;
|
||||||
}];
|
}];
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:nil usingBlock:
|
||||||
addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
|
^(NSNotification *note) {
|
||||||
[self updateLayoutAnimated:NO allowScroll:NO completion:nil];
|
[self updateLayoutAnimated:NO allowScroll:NO completion:nil];
|
||||||
[UIView animateWithDuration:1 animations:^{
|
[UIView animateWithDuration:1 animations:^{
|
||||||
self.uiContainer.alpha = 1;
|
self.uiContainer.alpha = 1;
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[self updateLayoutAnimated:NO allowScroll:YES completion:nil];
|
[self updateLayoutAnimated:NO allowScroll:YES completion:nil];
|
||||||
|
|
||||||
@ -356,16 +354,16 @@
|
|||||||
|
|
||||||
- (void)didToggleUserSelection {
|
- (void)didToggleUserSelection {
|
||||||
|
|
||||||
MPUserEntity *selectedUser = self.selectedUser;
|
MPUserEntity *selectedUser = [self selectedUserForThread];
|
||||||
if (!selectedUser)
|
if (!selectedUser)
|
||||||
[self.passwordField resignFirstResponder];
|
[self.passwordField resignFirstResponder];
|
||||||
else if ([[MPiOSAppDelegate get] signInAsUser:selectedUser usingMasterPassword:nil]) {
|
else if ([[MPiOSAppDelegate get] signInAsUser:selectedUser inContext:selectedUser.managedObjectContext usingMasterPassword:nil]) {
|
||||||
[self performSegueWithIdentifier:@"MP_Unlock" sender:self];
|
[self performSegueWithIdentifier:@"MP_Unlock" sender:self];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self updateLayoutAnimated:YES allowScroll:YES completion:^(BOOL finished) {
|
[self updateLayoutAnimated:YES allowScroll:YES completion:^(BOOL finished) {
|
||||||
if (self.selectedUser)
|
if ([self selectedUserForThread])
|
||||||
[self.passwordField becomeFirstResponder];
|
[self.passwordField becomeFirstResponder];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
@ -479,7 +477,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lay out password entry and user selection views.
|
// Lay out password entry and user selection views.
|
||||||
if (self.selectedUser && !self.passwordView.alpha) {
|
MPUserEntity *selectedUser = [self selectedUserForThread];
|
||||||
|
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.center = CGPointMake( 160, 180 );
|
||||||
@ -489,7 +488,7 @@
|
|||||||
self.oldNameLabel.center = self.nameLabel.center;
|
self.oldNameLabel.center = self.nameLabel.center;
|
||||||
self.avatarShadowColor = [UIColor whiteColor];
|
self.avatarShadowColor = [UIColor whiteColor];
|
||||||
}
|
}
|
||||||
else if (!self.selectedUser && self.passwordView.alpha == 1) {
|
else if (!selectedUser && self.passwordView.alpha == 1) {
|
||||||
// User was just deselected.
|
// User was just deselected.
|
||||||
self.passwordField.text = nil;
|
self.passwordField.text = nil;
|
||||||
self.passwordView.alpha = 0;
|
self.passwordView.alpha = 0;
|
||||||
@ -502,7 +501,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lay out the word wall.
|
// Lay out the word wall.
|
||||||
if (!self.selectedUser || self.selectedUser.keyID) {
|
if (!selectedUser || selectedUser.keyID) {
|
||||||
self.passwordFieldLabel.text = @"Enter your master password:";
|
self.passwordFieldLabel.text = @"Enter your master password:";
|
||||||
|
|
||||||
self.wordWall.alpha = 0;
|
self.wordWall.alpha = 0;
|
||||||
@ -530,8 +529,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lay out user targeting.
|
// Lay out user targeting.
|
||||||
MPUserEntity *targetedUser = self.selectedUser;
|
UIButton *selectedAvatar = [self avatarForUser:selectedUser];
|
||||||
UIButton *selectedAvatar = [self avatarForUser:self.selectedUser];
|
MPUserEntity *targetedUser = selectedUser;
|
||||||
UIButton *targetedAvatar = selectedAvatar;
|
UIButton *targetedAvatar = selectedAvatar;
|
||||||
if (!targetedAvatar) {
|
if (!targetedAvatar) {
|
||||||
targetedAvatar = [self findTargetedAvatar];
|
targetedAvatar = [self findTargetedAvatar];
|
||||||
@ -547,7 +546,7 @@
|
|||||||
BOOL isTargeted = avatar == targetedAvatar;
|
BOOL isTargeted = avatar == targetedAvatar;
|
||||||
|
|
||||||
avatar.userInteractionEnabled = isTargeted;
|
avatar.userInteractionEnabled = isTargeted;
|
||||||
avatar.alpha = isTargeted? 1: self.selectedUser? 0.1: 0.4;
|
avatar.alpha = isTargeted? 1: [self selectedUserForThread]? 0.1: 0.4;
|
||||||
|
|
||||||
[self updateAvatarShadowColor:avatar isTargeted:isTargeted];
|
[self updateAvatarShadowColor:avatar isTargeted:isTargeted];
|
||||||
} recurse:NO];
|
} recurse:NO];
|
||||||
@ -612,14 +611,15 @@
|
|||||||
|
|
||||||
- (void)tryMasterPassword {
|
- (void)tryMasterPassword {
|
||||||
|
|
||||||
if (!self.selectedUser)
|
if (![self selectedUserForThread])
|
||||||
// No user selected, can't try sign-in.
|
// No user selected, can't try sign-in.
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[self setSpinnerActive:YES];
|
[self setSpinnerActive:YES];
|
||||||
|
|
||||||
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
||||||
BOOL unlocked = [[MPiOSAppDelegate get] signInAsUser:self.selectedUser usingMasterPassword:self.passwordField.text];
|
BOOL unlocked = [[MPiOSAppDelegate get] signInAsUser:[self selectedUserInContext:moc] inContext:moc
|
||||||
|
usingMasterPassword:self.passwordField.text];
|
||||||
|
|
||||||
dispatch_async( dispatch_get_main_queue(), ^{
|
dispatch_async( dispatch_get_main_queue(), ^{
|
||||||
if (unlocked)
|
if (unlocked)
|
||||||
@ -632,7 +632,7 @@
|
|||||||
[self setSpinnerActive:NO];
|
[self setSpinnerActive:NO];
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
} );
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIButton *)findTargetedAvatar {
|
- (UIButton *)findTargetedAvatar {
|
||||||
@ -697,9 +697,9 @@
|
|||||||
self.spinner.alpha = active? 1: 0;
|
self.spinner.alpha = active? 1: 0;
|
||||||
|
|
||||||
if (active)
|
if (active)
|
||||||
[self avatarForUser:self.selectedUser].backgroundColor = [UIColor clearColor];
|
[self avatarForUser:[self selectedUserForThread]].backgroundColor = [UIColor clearColor];
|
||||||
else
|
else
|
||||||
[self avatarForUser:self.selectedUser].backgroundColor = self.avatarTemplate.backgroundColor;
|
[self avatarForUser:[self selectedUserForThread]].backgroundColor = self.avatarTemplate.backgroundColor;
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -779,7 +779,7 @@
|
|||||||
else if (textField == self.passwordField) {
|
else if (textField == self.passwordField) {
|
||||||
[self setSpinnerActive:YES];
|
[self setSpinnerActive:YES];
|
||||||
|
|
||||||
if (self.selectedUser.keyID)
|
if ([self selectedUserForThread].keyID)
|
||||||
[self tryMasterPassword];
|
[self tryMasterPassword];
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -980,7 +980,7 @@
|
|||||||
if (sender.state != UIGestureRecognizerStateBegan)
|
if (sender.state != UIGestureRecognizerStateBegan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (self.selectedUser)
|
if ([self selectedUserForThread])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MPUserEntity *targetedUser = [self userForAvatar:[self findTargetedAvatar]];
|
MPUserEntity *targetedUser = [self userForAvatar:[self findTargetedAvatar]];
|
||||||
@ -1118,15 +1118,16 @@
|
|||||||
|
|
||||||
#pragma mark - Core Data
|
#pragma mark - Core Data
|
||||||
|
|
||||||
- (MPUserEntity *)selectedUser {
|
- (MPUserEntity *)selectedUserForThread {
|
||||||
|
|
||||||
|
return [self selectedUserInContext:[MPiOSAppDelegate managedObjectContextForThreadIfReady]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPUserEntity *)selectedUserInContext:(NSManagedObjectContext *)moc {
|
||||||
|
|
||||||
if (!_selectedUserOID)
|
if (!_selectedUserOID)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
NSManagedObjectContext *moc = [MPiOSAppDelegate managedObjectContextForThreadIfReady];
|
|
||||||
if (!moc)
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
NSError *error;
|
NSError *error;
|
||||||
MPUserEntity *selectedUser = (MPUserEntity *)[moc existingObjectWithID:_selectedUserOID error:&error];
|
MPUserEntity *selectedUser = (MPUserEntity *)[moc existingObjectWithID:_selectedUserOID error:&error];
|
||||||
if (!selectedUser)
|
if (!selectedUser)
|
||||||
|
Loading…
Reference in New Issue
Block a user