Don't block the MOC lookup.
[IMPROVED] Don't block when MOC is not yet ready, just return nil. [IMPROVED] Outdated tip links to info, icon links to site search. [IMPROVED] Minor improvements to error handling during import.
This commit is contained in:
parent
bc3aa3255e
commit
4cdeab4256
3
.gitignore
vendored
3
.gitignore
vendored
@ -28,3 +28,6 @@ Press/MasterPassword_PressKit/MasterPassword_pressrelease_*.pdf
|
|||||||
# IPA
|
# IPA
|
||||||
/sendipa/*
|
/sendipa/*
|
||||||
!/sendipa/sendipa.conf
|
!/sendipa/sendipa.conf
|
||||||
|
|
||||||
|
# Java
|
||||||
|
MasterPassword/Java/**/target
|
||||||
|
2
External/iCloudStoreManager
vendored
2
External/iCloudStoreManager
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 1614e65222a543a75cdf4e5f757f06e39b5979aa
|
Subproject commit a7b028ff80cd4768be686a9ef2067dfd31989ce0
|
@ -20,9 +20,9 @@ typedef enum {
|
|||||||
|
|
||||||
@interface MPAppDelegate_Shared (Store)<UbiquityStoreManagerDelegate>
|
@interface MPAppDelegate_Shared (Store)<UbiquityStoreManagerDelegate>
|
||||||
|
|
||||||
+ (NSManagedObjectContext *)managedObjectContext;
|
+ (NSManagedObjectContext *)managedObjectContextIfReady;
|
||||||
+ (NSManagedObjectModel *)managedObjectModel;
|
+ (NSManagedObjectModel *)managedObjectModel;
|
||||||
- (NSManagedObjectContext *)managedObjectContext;
|
- (NSManagedObjectContext *)managedObjectContextIfReady;
|
||||||
- (NSManagedObjectModel *)managedObjectModel;
|
- (NSManagedObjectModel *)managedObjectModel;
|
||||||
|
|
||||||
- (UbiquityStoreManager *)storeManager;
|
- (UbiquityStoreManager *)storeManager;
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
|
|
||||||
#pragma mark - Core Data setup
|
#pragma mark - Core Data setup
|
||||||
|
|
||||||
+ (NSManagedObjectContext *)managedObjectContext {
|
+ (NSManagedObjectContext *)managedObjectContextIfReady {
|
||||||
|
|
||||||
return [[self get] managedObjectContext];
|
return [[self get] managedObjectContextIfReady];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSManagedObjectModel *)managedObjectModel {
|
+ (NSManagedObjectModel *)managedObjectModel {
|
||||||
@ -33,7 +33,10 @@
|
|||||||
return managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
return managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSManagedObjectContext *)managedObjectContext {
|
- (NSManagedObjectContext *)managedObjectContextIfReady {
|
||||||
|
|
||||||
|
if (![self storeManager].isReady)
|
||||||
|
return nil;
|
||||||
|
|
||||||
static NSManagedObjectContext *managedObjectContext = nil;
|
static NSManagedObjectContext *managedObjectContext = nil;
|
||||||
if (managedObjectContext)
|
if (managedObjectContext)
|
||||||
@ -41,25 +44,14 @@
|
|||||||
|
|
||||||
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
||||||
[managedObjectContext performBlockAndWait:^{
|
[managedObjectContext performBlockAndWait:^{
|
||||||
managedObjectContext.persistentStoreCoordinator = [self persistentStoreCoordinator];
|
|
||||||
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
|
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
|
||||||
|
managedObjectContext.persistentStoreCoordinator = [self storeManager].persistentStoreCoordinator;
|
||||||
|
managedObjectContext.undoManager = [NSUndoManager new];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
return managedObjectContext;
|
return managedObjectContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
|
|
||||||
|
|
||||||
// Start loading the store.
|
|
||||||
[self storeManager];
|
|
||||||
|
|
||||||
// Wait until the storeManager is ready.
|
|
||||||
while (![self storeManager].isReady)
|
|
||||||
[NSThread sleepForTimeInterval:0.1];
|
|
||||||
|
|
||||||
return [self storeManager].persistentStoreCoordinator;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UbiquityStoreManager *)storeManager {
|
- (UbiquityStoreManager *)storeManager {
|
||||||
|
|
||||||
static UbiquityStoreManager *storeManager = nil;
|
static UbiquityStoreManager *storeManager = nil;
|
||||||
@ -112,10 +104,10 @@
|
|||||||
|
|
||||||
- (void)saveContext {
|
- (void)saveContext {
|
||||||
|
|
||||||
[self.managedObjectContext performBlock:^{
|
[self.managedObjectContextIfReady performBlock:^{
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
if ([self.managedObjectContext hasChanges])
|
if ([self.managedObjectContextIfReady hasChanges])
|
||||||
if (![self.managedObjectContext save:&error])
|
if (![self.managedObjectContextIfReady save:&error])
|
||||||
err(@"While saving context: %@", error);
|
err(@"While saving context: %@", error);
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
@ -124,7 +116,7 @@
|
|||||||
|
|
||||||
- (NSManagedObjectContext *)managedObjectContextForUbiquityStoreManager:(UbiquityStoreManager *)usm {
|
- (NSManagedObjectContext *)managedObjectContextForUbiquityStoreManager:(UbiquityStoreManager *)usm {
|
||||||
|
|
||||||
return self.managedObjectContext;
|
return self.managedObjectContextIfReady;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager log:(NSString *)message {
|
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager log:(NSString *)message {
|
||||||
@ -197,17 +189,15 @@
|
|||||||
inf(@"Importing sites.");
|
inf(@"Importing sites.");
|
||||||
|
|
||||||
static NSRegularExpression *headerPattern, *sitePattern;
|
static NSRegularExpression *headerPattern, *sitePattern;
|
||||||
__autoreleasing __block NSError *error;
|
__block NSError *error = nil;
|
||||||
if (!headerPattern) {
|
if (!headerPattern) {
|
||||||
headerPattern = [[NSRegularExpression alloc]
|
headerPattern = [[NSRegularExpression alloc] initWithPattern:@"^#[[:space:]]*([^:]+): (.*)"
|
||||||
initWithPattern:@"^#[[:space:]]*([^:]+): (.*)"
|
|
||||||
options:0 error:&error];
|
options:0 error:&error];
|
||||||
if (error)
|
if (error)
|
||||||
err(@"Error loading the header pattern: %@", error);
|
err(@"Error loading the header pattern: %@", error);
|
||||||
}
|
}
|
||||||
if (!sitePattern) {
|
if (!sitePattern) {
|
||||||
sitePattern = [[NSRegularExpression alloc]
|
sitePattern = [[NSRegularExpression alloc] initWithPattern:@"^([^[:space:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:digit:]]+)(:[[:digit:]]+)?[[:space:]]+([^\t]+)\t(.*)"
|
||||||
initWithPattern:@"^([^[:space:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:digit:]]+)(:[[:digit:]]+)?[[:space:]]+([^\t]+)\t(.*)"
|
|
||||||
options:0 error:&error];
|
options:0 error:&error];
|
||||||
if (error)
|
if (error)
|
||||||
err(@"Error loading the site pattern: %@", error);
|
err(@"Error loading the site pattern: %@", error);
|
||||||
@ -252,9 +242,20 @@
|
|||||||
|
|
||||||
NSFetchRequest *userFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])];
|
NSFetchRequest *userFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])];
|
||||||
userFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", userName];
|
userFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", userName];
|
||||||
[self.managedObjectContext performBlockAndWait:^{
|
__block NSArray *users = nil;
|
||||||
user = [[self.managedObjectContext executeFetchRequest:userFetchRequest error:&error] lastObject];
|
[self.managedObjectContextIfReady performBlockAndWait:^{
|
||||||
|
users = [self.managedObjectContextIfReady executeFetchRequest:userFetchRequest error:&error];
|
||||||
}];
|
}];
|
||||||
|
if (!users) {
|
||||||
|
err(@"While looking for user: %@, error: %@", userName, error);
|
||||||
|
return MPImportResultInternalError;
|
||||||
|
}
|
||||||
|
if ([users count] > 1) {
|
||||||
|
err(@"While looking for user: %@, found more than one: %u", userName, [users count]);
|
||||||
|
return MPImportResultInternalError;
|
||||||
|
}
|
||||||
|
|
||||||
|
user = [users count]? [users lastObject]: nil;
|
||||||
dbg(@"Found user: %@", [user debugDescription]);
|
dbg(@"Found user: %@", [user debugDescription]);
|
||||||
}
|
}
|
||||||
if ([headerName isEqualToString:@"Key ID"])
|
if ([headerName isEqualToString:@"Key ID"])
|
||||||
@ -298,8 +299,8 @@
|
|||||||
if (user) {
|
if (user) {
|
||||||
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND user == %@", name, user];
|
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND user == %@", name, user];
|
||||||
__block NSArray *existingSites = nil;
|
__block NSArray *existingSites = nil;
|
||||||
[self.managedObjectContext performBlockAndWait:^{
|
[self.managedObjectContextIfReady performBlockAndWait:^{
|
||||||
existingSites = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
|
existingSites = [self.managedObjectContextIfReady executeFetchRequest:fetchRequest error:&error];
|
||||||
}];
|
}];
|
||||||
if (!existingSites) {
|
if (!existingSites) {
|
||||||
err(@"Lookup of existing sites failed for site: %@, user: %@, error: %@", name, user.userID, error);
|
err(@"Lookup of existing sites failed for site: %@, user: %@, error: %@", name, user.userID, error);
|
||||||
@ -323,24 +324,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL success = NO;
|
BOOL success = NO;
|
||||||
[self.managedObjectContext.undoManager beginUndoGrouping];
|
[self.managedObjectContextIfReady.undoManager beginUndoGrouping];
|
||||||
@try {
|
@try {
|
||||||
|
|
||||||
// Delete existing sites.
|
// Delete existing sites.
|
||||||
if (elementsToDelete.count)
|
if (elementsToDelete.count)
|
||||||
[self.managedObjectContext performBlockAndWait:^{
|
[self.managedObjectContextIfReady performBlockAndWait:^{
|
||||||
[elementsToDelete enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
|
[elementsToDelete enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
|
||||||
inf(@"Deleting site: %@, it will be replaced by an imported site.", [obj name]);
|
inf(@"Deleting site: %@, it will be replaced by an imported site.", [obj name]);
|
||||||
dbg(@"Deleted Element: %@", [obj debugDescription]);
|
dbg(@"Deleted Element: %@", [obj debugDescription]);
|
||||||
[self.managedObjectContext deleteObject:obj];
|
[self.managedObjectContextIfReady deleteObject:obj];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Import new sites.
|
// Import new sites.
|
||||||
if (!user) {
|
if (!user) {
|
||||||
[self.managedObjectContext performBlockAndWait:^{
|
[self.managedObjectContextIfReady performBlockAndWait:^{
|
||||||
user = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class])
|
user = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class])
|
||||||
inManagedObjectContext:self.managedObjectContext];
|
inManagedObjectContext:self.managedObjectContextIfReady];
|
||||||
user.name = userName;
|
user.name = userName;
|
||||||
user.keyID = [keyIDHex decodeHex];
|
user.keyID = [keyIDHex decodeHex];
|
||||||
}];
|
}];
|
||||||
@ -355,9 +356,9 @@
|
|||||||
NSString *exportContent = [siteElements objectAtIndex:5];
|
NSString *exportContent = [siteElements objectAtIndex:5];
|
||||||
|
|
||||||
// Create new site.
|
// Create new site.
|
||||||
[self.managedObjectContext performBlockAndWait:^{
|
[self.managedObjectContextIfReady performBlockAndWait:^{
|
||||||
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[key.algorithm classNameOfType:type]
|
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[key.algorithm classNameOfType:type]
|
||||||
inManagedObjectContext:self.managedObjectContext];
|
inManagedObjectContext:self.managedObjectContextIfReady];
|
||||||
element.name = name;
|
element.name = name;
|
||||||
element.user = user;
|
element.user = user;
|
||||||
element.type = type;
|
element.type = type;
|
||||||
@ -385,10 +386,10 @@
|
|||||||
return MPImportResultSuccess;
|
return MPImportResultSuccess;
|
||||||
}
|
}
|
||||||
@finally {
|
@finally {
|
||||||
[self.managedObjectContext.undoManager endUndoGrouping];
|
[self.managedObjectContextIfReady.undoManager endUndoGrouping];
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
[self.managedObjectContext.undoManager undoNestedGroup];
|
[self.managedObjectContextIfReady.undoManager undoNestedGroup];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
- (IBAction)upgradePassword;
|
- (IBAction)upgradePassword;
|
||||||
- (IBAction)action:(UIBarButtonItem *)sender;
|
- (IBAction)action:(UIBarButtonItem *)sender;
|
||||||
- (IBAction)toggleUser;
|
- (IBAction)toggleUser;
|
||||||
|
- (IBAction)searchOutdatedElements;
|
||||||
- (IBAction)closeOutdatedAlert;
|
- (IBAction)closeOutdatedAlert;
|
||||||
- (IBAction)infoOutdatedAlert;
|
- (IBAction)infoOutdatedAlert;
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@
|
|||||||
action:@selector(editUserName:)]];
|
action:@selector(editUserName:)]];
|
||||||
[self.userNameContainer addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(copyUserName:)]];
|
[self.userNameContainer addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(copyUserName:)]];
|
||||||
[self.outdatedAlertBack addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
|
[self.outdatedAlertBack addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
|
||||||
action:@selector(searchOutdatedElements:)]];
|
action:@selector(infoOutdatedAlert)]];
|
||||||
|
|
||||||
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui_background"]];
|
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui_background"]];
|
||||||
|
|
||||||
@ -137,12 +137,13 @@
|
|||||||
[self updateAnimated:animated];
|
[self updateAnimated:animated];
|
||||||
|
|
||||||
if ([MPAppDelegate get].activeUser)
|
if ([MPAppDelegate get].activeUser)
|
||||||
[[MPAppDelegate get].managedObjectContext performBlock:^void() {
|
[[MPAppDelegate get].managedObjectContextIfReady performBlock:^void() {
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
NSFetchRequest *migrationRequest = [NSFetchRequest
|
NSFetchRequest *migrationRequest = [NSFetchRequest
|
||||||
fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
|
fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
|
||||||
migrationRequest.predicate = [NSPredicate predicateWithFormat:@"version_ < %d", MPAlgorithmDefaultVersion];
|
migrationRequest.predicate = [NSPredicate predicateWithFormat:@"version_ < %d", MPAlgorithmDefaultVersion];
|
||||||
NSArray *migrationElements = [[MPAppDelegate get].managedObjectContext executeFetchRequest:migrationRequest error:&error];
|
NSArray *migrationElements = [[MPAppDelegate get].managedObjectContextIfReady 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;
|
return;
|
||||||
@ -652,7 +653,7 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)searchOutdatedElements:(UITapGestureRecognizer *)sender {
|
- (IBAction)searchOutdatedElements {
|
||||||
|
|
||||||
self.searchDisplayController.searchBar.selectedScopeButtonIndex = MPSearchScopeOutdated;
|
self.searchDisplayController.searchBar.selectedScopeButtonIndex = MPSearchScopeOutdated;
|
||||||
self.searchDisplayController.searchBar.searchResultsButtonSelected = YES;
|
self.searchDisplayController.searchBar.searchResultsButtonSelected = YES;
|
||||||
@ -824,16 +825,16 @@
|
|||||||
// Update password type.
|
// Update password type.
|
||||||
if ([self.activeElement.algorithm classOfType:type] != self.activeElement.typeClass)
|
if ([self.activeElement.algorithm classOfType:type] != self.activeElement.typeClass)
|
||||||
// Type requires a different class of element. Recreate the element.
|
// Type requires a different class of element. Recreate the element.
|
||||||
[[MPAppDelegate managedObjectContext] performBlockAndWait:^{
|
[[MPAppDelegate managedObjectContextIfReady] performBlockAndWait:^{
|
||||||
MPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:[self.activeElement.algorithm classNameOfType:type]
|
MPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:[self.activeElement.algorithm classNameOfType:type]
|
||||||
inManagedObjectContext:[MPAppDelegate managedObjectContext]];
|
inManagedObjectContext:[MPAppDelegate managedObjectContextIfReady]];
|
||||||
newElement.name = self.activeElement.name;
|
newElement.name = self.activeElement.name;
|
||||||
newElement.user = self.activeElement.user;
|
newElement.user = self.activeElement.user;
|
||||||
newElement.uses = self.activeElement.uses;
|
newElement.uses = self.activeElement.uses;
|
||||||
newElement.lastUsed = self.activeElement.lastUsed;
|
newElement.lastUsed = self.activeElement.lastUsed;
|
||||||
newElement.version = self.activeElement.version;
|
newElement.version = self.activeElement.version;
|
||||||
|
|
||||||
[[MPAppDelegate managedObjectContext] deleteObject:self.activeElement];
|
[[MPAppDelegate managedObjectContextIfReady] deleteObject:self.activeElement];
|
||||||
self.activeElement = newElement;
|
self.activeElement = newElement;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@ -941,7 +942,7 @@
|
|||||||
|
|
||||||
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
|
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
|
||||||
if ([[[request URL] query] isEqualToString:@"outdated"]) {
|
if ([[[request URL] query] isEqualToString:@"outdated"]) {
|
||||||
[self searchOutdatedElements:nil];
|
[self searchOutdatedElements];
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
|
||||||
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses_" ascending:NO]];
|
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses_" ascending:NO]];
|
||||||
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
|
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
|
||||||
managedObjectContext:[MPAppDelegate managedObjectContext]
|
managedObjectContext:[MPAppDelegate managedObjectContextIfReady]
|
||||||
sectionNameKeyPath:nil cacheName:nil];
|
sectionNameKeyPath:nil cacheName:nil];
|
||||||
self.fetchedResultsController.delegate = self;
|
self.fetchedResultsController.delegate = self;
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
@synthesize wordList = _wordList;
|
@synthesize wordList = _wordList;
|
||||||
|
|
||||||
|
|
||||||
- (void)initAvatarAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user {
|
- (void)initializeAvatarAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user {
|
||||||
|
|
||||||
UIScrollView *alertAvatarScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(12, 30, 260, 150)];
|
UIScrollView *alertAvatarScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(12, 30, 260, 150)];
|
||||||
alertAvatarScrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
|
alertAvatarScrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
|
||||||
@ -88,7 +88,7 @@
|
|||||||
[alertAvatarScrollView setContentOffset:selectedOffset animated:YES];
|
[alertAvatarScrollView setContentOffset:selectedOffset animated:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)initConfirmationAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user {
|
- (void)initializeConfirmationAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user {
|
||||||
|
|
||||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(12, 70, 260, 110)];
|
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(12, 70, 260, 110)];
|
||||||
[alert addSubview:container];
|
[alert addSubview:container];
|
||||||
@ -145,6 +145,15 @@
|
|||||||
[self initializeWordLabel:wordLabel];
|
[self initializeWordLabel:wordLabel];
|
||||||
} recurse:NO];
|
} recurse:NO];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserverForName:PersistentStoreDidChange object:nil queue:nil usingBlock:
|
||||||
|
^(NSNotification *note) {
|
||||||
|
[self updateUsers];
|
||||||
|
}];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserverForName:PersistentStoreDidMergeChanges object:nil queue:nil usingBlock:
|
||||||
|
^(NSNotification *note) {
|
||||||
|
[self updateUsers];
|
||||||
|
}];
|
||||||
|
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +204,7 @@
|
|||||||
|
|
||||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])];
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])];
|
||||||
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO]];
|
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO]];
|
||||||
NSArray *users = [[MPAppDelegate managedObjectContext] executeFetchRequest:fetchRequest error:nil];
|
NSArray *users = [[MPAppDelegate managedObjectContextIfReady] executeFetchRequest:fetchRequest error:nil];
|
||||||
|
|
||||||
// Clean up avatars.
|
// Clean up avatars.
|
||||||
for (UIView *subview in [self.avatarsView subviews])
|
for (UIView *subview in [self.avatarsView subviews])
|
||||||
@ -276,16 +285,16 @@
|
|||||||
- (void)didSelectNewUserAvatar:(UIButton *)newUserAvatar {
|
- (void)didSelectNewUserAvatar:(UIButton *)newUserAvatar {
|
||||||
|
|
||||||
__block MPUserEntity *newUser = nil;
|
__block MPUserEntity *newUser = nil;
|
||||||
[[MPAppDelegate managedObjectContext] performBlockAndWait:^{
|
[[MPAppDelegate managedObjectContextIfReady] performBlockAndWait:^{
|
||||||
newUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class])
|
newUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class])
|
||||||
inManagedObjectContext:[MPAppDelegate managedObjectContext]];
|
inManagedObjectContext:[MPAppDelegate managedObjectContextIfReady]];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[self showNewUserNameAlertFor:newUser completion:^(BOOL finished) {
|
[self showNewUserNameAlertFor:newUser completion:^(BOOL finished) {
|
||||||
newUserAvatar.selected = NO;
|
newUserAvatar.selected = NO;
|
||||||
if (!finished)
|
if (!finished)
|
||||||
[[MPAppDelegate managedObjectContext] performBlock:^{
|
[[MPAppDelegate managedObjectContextIfReady] performBlock:^{
|
||||||
[[MPAppDelegate managedObjectContext] deleteObject:newUser];
|
[[MPAppDelegate managedObjectContextIfReady] deleteObject:newUser];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
@ -318,7 +327,7 @@
|
|||||||
[PearlAlert showAlertWithTitle:@"Choose Your Avatar"
|
[PearlAlert showAlertWithTitle:@"Choose Your Avatar"
|
||||||
message:@"\n\n\n\n\n\n" viewStyle:UIAlertViewStyleDefault
|
message:@"\n\n\n\n\n\n" viewStyle:UIAlertViewStyleDefault
|
||||||
initAlert:^(UIAlertView *_alert, UITextField *_firstField) {
|
initAlert:^(UIAlertView *_alert, UITextField *_firstField) {
|
||||||
[self initAvatarAlert:_alert forUser:newUser];
|
[self initializeAvatarAlert:_alert forUser:newUser];
|
||||||
}
|
}
|
||||||
tappedButtonBlock:^(UIAlertView *_alert, NSInteger _buttonIndex) {
|
tappedButtonBlock:^(UIAlertView *_alert, NSInteger _buttonIndex) {
|
||||||
|
|
||||||
@ -335,7 +344,7 @@
|
|||||||
@"\n\n\n\n\n\n"
|
@"\n\n\n\n\n\n"
|
||||||
viewStyle:UIAlertViewStyleDefault
|
viewStyle:UIAlertViewStyleDefault
|
||||||
initAlert:^void(UIAlertView *__alert, UITextField *__firstField) {
|
initAlert:^void(UIAlertView *__alert, UITextField *__firstField) {
|
||||||
[self initConfirmationAlert:__alert forUser:newUser];
|
[self initializeConfirmationAlert:__alert forUser:newUser];
|
||||||
}
|
}
|
||||||
tappedButtonBlock:^void(UIAlertView *__alert, NSInteger __buttonIndex) {
|
tappedButtonBlock:^void(UIAlertView *__alert, NSInteger __buttonIndex) {
|
||||||
if (__buttonIndex == [__alert cancelButtonIndex]) {
|
if (__buttonIndex == [__alert cancelButtonIndex]) {
|
||||||
@ -720,8 +729,8 @@
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (buttonIndex == [sheet destructiveButtonIndex]) {
|
if (buttonIndex == [sheet destructiveButtonIndex]) {
|
||||||
[[MPAppDelegate get].managedObjectContext performBlockAndWait:^{
|
[[MPAppDelegate get].managedObjectContextIfReady performBlockAndWait:^{
|
||||||
[[MPAppDelegate get].managedObjectContext deleteObject:targetedUser];
|
[[MPAppDelegate get].managedObjectContextIfReady deleteObject:targetedUser];
|
||||||
}];
|
}];
|
||||||
[[MPAppDelegate get] saveContext];
|
[[MPAppDelegate get] saveContext];
|
||||||
[self updateUsers];
|
[self updateUsers];
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="2.0" toolsVersion="2549" systemVersion="12A269" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="KZF-fe-y9n">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="2.0" toolsVersion="2549" systemVersion="12A269" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="KZF-fe-y9n">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment defaultVersion="1296" identifier="iOS"/>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="1498"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="1498"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
@ -564,7 +563,7 @@ Your passwords will be AES-encrypted with your master password.</string>
|
|||||||
<rect key="frame" x="20" y="94" width="280" height="31"/>
|
<rect key="frame" x="20" y="94" width="280" height="31"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Tap and hold to save a user name." textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" id="tj6-Ot-Fuh">
|
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Tap and hold to save a login name." textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" id="tj6-Ot-Fuh">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="280" height="31"/>
|
<rect key="frame" x="0.0" y="0.0" width="280" height="31"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
@ -814,9 +813,9 @@ L4m3P4sSw0rD</string>
|
|||||||
<rect key="frame" x="20" y="60" width="260" height="130"/>
|
<rect key="frame" x="20" y="60" width="260" height="130"/>
|
||||||
<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"/>
|
||||||
<string key="text">Some of your sites have outdated passwords. Tap this alert to see them.
|
<string key="text">Some of your sites have outdated passwords. Tap this alert for more info or to find them.
|
||||||
|
|
||||||
You should upgrade these sites and update their account's passwords as soon as convenient.</string>
|
You should upgrade these sites and update their account's passwords as soon as is convenient.</string>
|
||||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||||
@ -842,7 +841,7 @@ You should upgrade these sites and update their account's passwords as soon as c
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="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"/>
|
||||||
<state key="normal" image="icon_info.png">
|
<state key="normal" image="icon_find.png">
|
||||||
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
</state>
|
</state>
|
||||||
@ -850,7 +849,23 @@ You should upgrade these sites and update their account's passwords as soon as c
|
|||||||
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
</state>
|
</state>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="infoOutdatedAlert" destination="PQa-Xl-A3x" eventType="touchUpInside" id="U2G-GA-wT2"/>
|
<action selector="searchOutdatedElements" destination="PQa-Xl-A3x" eventType="touchUpInside" id="7Wz-49-RQe"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Sfy-hx-kVU">
|
||||||
|
<rect key="frame" x="184" y="81" width="22" height="22"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" hint="" label="Close"/>
|
||||||
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||||
|
<state key="normal" image="icon_find.png">
|
||||||
|
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
|
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</state>
|
||||||
|
<state key="highlighted">
|
||||||
|
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</state>
|
||||||
|
<connections>
|
||||||
|
<action selector="searchOutdatedElements" destination="PQa-Xl-A3x" eventType="touchUpInside" id="4jj-PA-b0I"/>
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
</subviews>
|
</subviews>
|
||||||
@ -1798,7 +1813,7 @@ You could use the word wall for inspiration in finding a memorable master passw
|
|||||||
<image name="icon_action.png" width="32" height="32"/>
|
<image name="icon_action.png" width="32" height="32"/>
|
||||||
<image name="icon_cancel.png" width="32" height="32"/>
|
<image name="icon_cancel.png" width="32" height="32"/>
|
||||||
<image name="icon_edit.png" width="32" height="32"/>
|
<image name="icon_edit.png" width="32" height="32"/>
|
||||||
<image name="icon_info.png" width="32" height="32"/>
|
<image name="icon_find.png" width="32" height="32"/>
|
||||||
<image name="icon_person.png" width="32" height="32"/>
|
<image name="icon_person.png" width="32" height="32"/>
|
||||||
<image name="icon_plus.png" width="32" height="32"/>
|
<image name="icon_plus.png" width="32" height="32"/>
|
||||||
<image name="icon_up.png" width="32" height="32"/>
|
<image name="icon_up.png" width="32" height="32"/>
|
||||||
@ -1833,13 +1848,11 @@ You could use the word wall for inspiration in finding a memorable master passw
|
|||||||
<relationship kind="action" name="closeAlert"/>
|
<relationship kind="action" name="closeAlert"/>
|
||||||
<relationship kind="action" name="closeOutdatedAlert"/>
|
<relationship kind="action" name="closeOutdatedAlert"/>
|
||||||
<relationship kind="action" name="copyContent"/>
|
<relationship kind="action" name="copyContent"/>
|
||||||
<relationship kind="action" name="copyUserName:" candidateClass="UITapGestureRecognizer"/>
|
|
||||||
<relationship kind="action" name="editPassword"/>
|
<relationship kind="action" name="editPassword"/>
|
||||||
<relationship kind="action" name="editUserName:" candidateClass="UILongPressGestureRecognizer"/>
|
<relationship kind="action" name="editUserName:" candidateClass="UILongPressGestureRecognizer"/>
|
||||||
<relationship kind="action" name="incrementPasswordCounter"/>
|
<relationship kind="action" name="incrementPasswordCounter"/>
|
||||||
<relationship kind="action" name="infoOutdatedAlert"/>
|
<relationship kind="action" name="infoOutdatedAlert"/>
|
||||||
<relationship kind="action" name="resetPasswordCounter:" candidateClass="UILongPressGestureRecognizer"/>
|
<relationship kind="action" name="resetPasswordCounter:" candidateClass="UILongPressGestureRecognizer"/>
|
||||||
<relationship kind="action" name="searchOutdatedElements:" candidateClass="UITapGestureRecognizer"/>
|
|
||||||
<relationship kind="action" name="toggleUser"/>
|
<relationship kind="action" name="toggleUser"/>
|
||||||
<relationship kind="action" name="upgradePassword"/>
|
<relationship kind="action" name="upgradePassword"/>
|
||||||
<relationship kind="outlet" name="actionsTipContainer" candidateClass="UIView"/>
|
<relationship kind="outlet" name="actionsTipContainer" candidateClass="UIView"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user