diff --git a/Default.png b/Default.png index 89acac3e..af1b56ab 100644 Binary files a/Default.png and b/Default.png differ diff --git a/MasterPassword.sketch/Data b/MasterPassword.sketch/Data index 4b1d13b3..13b830aa 100644 Binary files a/MasterPassword.sketch/Data and b/MasterPassword.sketch/Data differ diff --git a/MasterPassword.sketch/QuickLook/Preview.pdf b/MasterPassword.sketch/QuickLook/Preview.pdf index e4589f06..206948bb 100644 Binary files a/MasterPassword.sketch/QuickLook/Preview.pdf and b/MasterPassword.sketch/QuickLook/Preview.pdf differ diff --git a/MasterPassword.xcodeproj/project.pbxproj b/MasterPassword.xcodeproj/project.pbxproj index d64830d3..ca18fdb6 100644 --- a/MasterPassword.xcodeproj/project.pbxproj +++ b/MasterPassword.xcodeproj/project.pbxproj @@ -203,6 +203,7 @@ DA84819414CB521E00A2FA22 /* tip_location_mercury.png in Resources */ = {isa = PBXBuildFile; fileRef = DA84817614CB521E00A2FA22 /* tip_location_mercury.png */; }; DA84819514CB521E00A2FA22 /* tip_location_teal.png in Resources */ = {isa = PBXBuildFile; fileRef = DA84817714CB521E00A2FA22 /* tip_location_teal.png */; }; DA84819614CB521E00A2FA22 /* tip_location_wood.png in Resources */ = {isa = PBXBuildFile; fileRef = DA84817814CB521E00A2FA22 /* tip_location_wood.png */; }; + DA8E8E4614DD7C1D0044257E /* logo-bare.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8E8E4514DD7C1D0044257E /* logo-bare.png */; }; DAA3B68E14CCCEE700F35AF6 /* icon_addressbook-person@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA3B53814CCCEE700F35AF6 /* icon_addressbook-person@2x.png */; }; DAA3B68F14CCCEE700F35AF6 /* icon_addressbook.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA3B53914CCCEE700F35AF6 /* icon_addressbook.png */; }; DAA3B69014CCCEE700F35AF6 /* icon_addressbook@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA3B53A14CCCEE700F35AF6 /* icon_addressbook@2x.png */; }; @@ -904,6 +905,8 @@ DA84817614CB521E00A2FA22 /* tip_location_mercury.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tip_location_mercury.png; sourceTree = ""; }; DA84817714CB521E00A2FA22 /* tip_location_teal.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tip_location_teal.png; sourceTree = ""; }; DA84817814CB521E00A2FA22 /* tip_location_wood.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tip_location_wood.png; sourceTree = ""; }; + DA8E8E4514DD7C1D0044257E /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "logo-bare.png"; path = "Resources/logo-bare.png"; sourceTree = ""; }; + DA8E8E4714DDA62D0044257E /* MasterPassword.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = ""; }; DAA3B53814CCCEE700F35AF6 /* icon_addressbook-person@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_addressbook-person@2x.png"; sourceTree = ""; }; DAA3B53914CCCEE700F35AF6 /* icon_addressbook.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_addressbook.png; sourceTree = ""; }; DAA3B53A14CCCEE700F35AF6 /* icon_addressbook@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_addressbook@2x.png"; sourceTree = ""; }; @@ -1805,6 +1808,7 @@ DA5BFA50147E415C00F98B1E /* MasterPassword */ = { isa = PBXGroup; children = ( + DA8E8E4714DDA62D0044257E /* MasterPassword.entitlements */, DA7C28A214AF02A000491972 /* Models */, DA7C28A314AF02B100491972 /* Data */, DA5BFA59147E415C00F98B1E /* OPAppDelegate.h */, @@ -1834,6 +1838,7 @@ DA5BFA51147E415C00F98B1E /* Supporting Files */ = { isa = PBXGroup; children = ( + DA8E8E4514DD7C1D0044257E /* logo-bare.png */, DA6556F714D730B700841C99 /* Guide */, DAA3B80414CDBBC600F35AF6 /* jquery-1.6.1.min.js */, DA84811E14CB50C100A2FA22 /* Tooltips */, @@ -2992,6 +2997,7 @@ DA65571214D760BD00841C99 /* guide_page_6@2x.png in Resources */, DA41A40B14DB3BF100638533 /* guide_page_0.png in Resources */, DA41A40C14DB3BF100638533 /* guide_page_0@2x.png in Resources */, + DA8E8E4614DD7C1D0044257E /* logo-bare.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3182,6 +3188,7 @@ DA5BFA6E147E415C00F98B1E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_ENTITLEMENTS = MasterPassword/MasterPassword.entitlements; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "MasterPassword/MasterPassword-Prefix.pch"; INFOPLIST_FILE = "MasterPassword/MasterPassword-Info.plist"; @@ -3194,6 +3201,7 @@ DA5BFA6F147E415C00F98B1E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_ENTITLEMENTS = MasterPassword/MasterPassword.entitlements; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "MasterPassword/MasterPassword-Prefix.pch"; INFOPLIST_FILE = "MasterPassword/MasterPassword-Info.plist"; diff --git a/MasterPassword/MainStoryboard_iPhone.storyboard b/MasterPassword/MainStoryboard_iPhone.storyboard index 327df89b..d38e0936 100644 --- a/MasterPassword/MainStoryboard_iPhone.storyboard +++ b/MasterPassword/MainStoryboard_iPhone.storyboard @@ -349,7 +349,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo - + diff --git a/MasterPassword/MasterPassword-Info.plist b/MasterPassword/MasterPassword-Info.plist index a379c999..31f6c4d3 100644 --- a/MasterPassword/MasterPassword-Info.plist +++ b/MasterPassword/MasterPassword-Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - ${PRODUCT_NAME} + Passwords CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFiles diff --git a/MasterPassword/MasterPassword.entitlements b/MasterPassword/MasterPassword.entitlements new file mode 100644 index 00000000..5757dc2a --- /dev/null +++ b/MasterPassword/MasterPassword.entitlements @@ -0,0 +1,16 @@ + + + + + com.apple.developer.ubiquity-container-identifiers + + $(TeamIdentifierPrefix)com.lyndir.lhunath.MasterPassword + + com.apple.developer.ubiquity-kvstore-identifier + $(TeamIdentifierPrefix)com.lyndir.lhunath.MasterPassword + keychain-access-groups + + $(AppIdentifierPrefix)com.lyndir.lhunath.MasterPassword + + + diff --git a/MasterPassword/OPAppDelegate.m b/MasterPassword/OPAppDelegate.m index c3507bb3..dd165756 100644 --- a/MasterPassword/OPAppDelegate.m +++ b/MasterPassword/OPAppDelegate.m @@ -121,7 +121,7 @@ } - (void)applicationDidBecomeActive:(UIApplication *)application { - if ([[OPConfig get].showQuickstart boolValue]) + if ([[OPConfig get].showQuickStart boolValue]) [self showGuide]; else [self loadKeyPhrase]; @@ -244,13 +244,14 @@ - (void)applicationWillResignActive:(UIApplication *)application { + [self saveContext]; + if (![[OPConfig get].rememberKeyPhrase boolValue]) self.keyPhrase = nil; } -- (void)applicationWillTerminate:(UIApplication *)application -{ - // Saves changes in the application's managed object context before the application terminates. +- (void)applicationWillTerminate:(UIApplication *)application { + [self saveContext]; } @@ -269,18 +270,13 @@ return [(OPAppDelegate *)[UIApplication sharedApplication].delegate managedObjectModel]; } -- (void)saveContext -{ - NSError *error = nil; - if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error]) { - /* - Replace this implementation with code to handle the error appropriately. - - abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. - */ - err(@"Unresolved error %@, %@", error, [error userInfo]); - abort(); - } +- (void)saveContext { + + [self.managedObjectContext performBlock:^{ + NSError *error = nil; + if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error]) + err(@"Unresolved error %@", error); + }]; } - (void)setKeyPhrase:(NSString *)keyPhrase { @@ -312,17 +308,30 @@ */ - (NSManagedObjectContext *)managedObjectContext { - if (__managedObjectContext != nil) - { + if (__managedObjectContext) return __managedObjectContext; - } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; - if (coordinator != nil) - { - __managedObjectContext = [[NSManagedObjectContext alloc] init]; - [__managedObjectContext setPersistentStoreCoordinator:coordinator]; + if (coordinator) { + __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; + __managedObjectContext.persistentStoreCoordinator = coordinator; + + [[NSNotificationCenter defaultCenter] addObserverForName:NSPersistentStoreDidImportUbiquitousContentChangesNotification + object:coordinator + queue:nil + usingBlock:^(NSNotification *note) { + dbg(@"Ubiquitous content change: %@", note); + + [__managedObjectContext performBlock:^{ + [__managedObjectContext mergeChangesFromContextDidSaveNotification:note]; + + [[NSNotificationCenter defaultCenter] postNotification: + [NSNotification notificationWithName:OPPersistentStoreDidChangeNotification + object:self userInfo:[note userInfo]]]; + }]; + }]; } + return __managedObjectContext; } @@ -332,14 +341,11 @@ */ - (NSManagedObjectModel *)managedObjectModel { - if (__managedObjectModel != nil) - { + if (__managedObjectModel) return __managedObjectModel; - } + NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MasterPassword" withExtension:@"momd"]; - __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; - - return __managedObjectModel; + return __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; } /** @@ -348,19 +354,23 @@ */ - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { - if (__persistentStoreCoordinator != nil) - { + if (__persistentStoreCoordinator) return __persistentStoreCoordinator; - } NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MasterPassword.sqlite"]; - NSError *error = nil; __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; + [__persistentStoreCoordinator lock]; + NSError *error = nil; if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:[NSDictionary dictionaryWithObjectsAndKeys: - (id)kCFBooleanTrue, NSMigratePersistentStoresAutomaticallyOption, - (id)kCFBooleanTrue, NSInferMappingModelAutomaticallyOption, + [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, + [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, + @"MasterPassword.store", NSPersistentStoreUbiquitousContentNameKey, + [[[NSFileManager defaultManager] + URLForUbiquityContainerIdentifier:nil] + URLByAppendingPathComponent:@"store" + isDirectory:YES], NSPersistentStoreUbiquitousContentURLKey, nil] error:&error]) { @@ -395,7 +405,8 @@ @throw [NSException exceptionWithName:error.domain reason:error.localizedDescription userInfo:[NSDictionary dictionaryWithObject:error forKey:@"cause"]]; } - + [__persistentStoreCoordinator unlock]; + return __persistentStoreCoordinator; } diff --git a/MasterPassword/OPConfig.h b/MasterPassword/OPConfig.h index 25e82ac9..a721d075 100644 --- a/MasterPassword/OPConfig.h +++ b/MasterPassword/OPConfig.h @@ -13,7 +13,7 @@ @property (nonatomic, retain) NSNumber *rememberKeyPhrase; @property (nonatomic, retain) NSNumber *forgetKeyPhrase; @property (nonatomic, retain) NSNumber *helpHidden; -@property (nonatomic, retain) NSNumber *showQuickstart; +@property (nonatomic, retain) NSNumber *showQuickStart; + (OPConfig *)get; diff --git a/MasterPassword/OPConfig.m b/MasterPassword/OPConfig.m index f8c0323c..d812083c 100644 --- a/MasterPassword/OPConfig.m +++ b/MasterPassword/OPConfig.m @@ -10,7 +10,7 @@ @implementation OPConfig -@dynamic dataStoreError, storeKeyPhrase, rememberKeyPhrase, forgetKeyPhrase, helpHidden, showQuickstart; +@dynamic dataStoreError, storeKeyPhrase, rememberKeyPhrase, forgetKeyPhrase, helpHidden, showQuickStart; - (id)init { @@ -24,7 +24,7 @@ [NSNumber numberWithBool:YES], NSStringFromSelector(@selector(rememberKeyPhrase)), [NSNumber numberWithBool:NO], NSStringFromSelector(@selector(forgetKeyPhrase)), [NSNumber numberWithBool:NO], NSStringFromSelector(@selector(helpHidden)), - [NSNumber numberWithBool:YES], NSStringFromSelector(@selector(showQuickstart)), + [NSNumber numberWithBool:YES], NSStringFromSelector(@selector(showQuickStart)), nil]]; return self; diff --git a/MasterPassword/OPElementEntity.h b/MasterPassword/OPElementEntity.h index ba6f3f3a..0a84458b 100644 --- a/MasterPassword/OPElementEntity.h +++ b/MasterPassword/OPElementEntity.h @@ -17,8 +17,8 @@ @property (nonatomic) int16_t type; @property (nonatomic) int16_t uses; @property (nonatomic) NSTimeInterval lastUsed; +@property (nonatomic, readonly) id content; - (void)use; -- (id)content; @end diff --git a/MasterPassword/OPGuideViewController.m b/MasterPassword/OPGuideViewController.m index 03760f4e..36690d8e 100644 --- a/MasterPassword/OPGuideViewController.m +++ b/MasterPassword/OPGuideViewController.m @@ -28,7 +28,7 @@ [super viewWillDisappear:animated]; - [OPConfig get].showQuickstart = [NSNumber numberWithBool:NO]; + [OPConfig get].showQuickStart = [NSNumber numberWithBool:NO]; [[OPAppDelegate get] loadKeyPhrase]; } diff --git a/MasterPassword/OPMainViewController.m b/MasterPassword/OPMainViewController.m index 29ff104a..fb3ddaa4 100644 --- a/MasterPassword/OPMainViewController.m +++ b/MasterPassword/OPMainViewController.m @@ -75,25 +75,29 @@ [self updateAnimated:NO]; } -- (void)viewWillDisappear:(BOOL)animated { +- (void)viewDidAppear:(BOOL)animated { - [super viewWillDisappear:animated]; + [super viewDidAppear:animated]; - self.searchTipContainer.hidden = YES; + // Put the search tip on the window so it's above the nav bar. + if (![self.searchTipContainer.superview isEqual:self.navigationController.navigationBar.superview]) { + CGRect frameInWindow = [self.searchTipContainer.window convertRect:self.searchTipContainer.frame + fromView:self.searchTipContainer.superview]; + [self.searchTipContainer removeFromSuperview]; + [self.navigationController.navigationBar.superview addSubview:self.searchTipContainer]; + self.searchTipContainer.frame = [self.searchTipContainer.window convertRect:frameInWindow + toView:self.searchTipContainer.superview]; + } } - (void)viewDidLoad { - // Put the search tip on the window so it's above the nav bar. - CGRect newFrame = [self.navigationController.navigationBar convertRect:self.searchTipContainer.frame - fromView:self.searchTipContainer.superview]; - [self.searchTipContainer removeFromSuperview]; - [self.navigationController.navigationBar addSubview:self.searchTipContainer]; - self.searchTipContainer.frame = newFrame; - self.searchTipContainer.hidden = YES; - - // Because IB's edit button doesn't auto-toggle self.editable like editButtonItem does. self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui_background"]]; + //self.navigationItem.titleView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"logo-bare.png"]]; + self.navigationItem.titleView.frame = CGRectMake(0, 0, 50, 50); + self.navigationItem.titleView.center = self.navigationController.navigationBar.center; + self.navigationItem.titleView.contentMode = UIViewContentModeScaleAspectFit; + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { if (![OPAppDelegate get].keyPhrase) { @@ -216,10 +220,12 @@ - (void)showAlertWithTitle:(NSString *)title message:(NSString *)message { self.alertTitle.text = title; + NSRange scrollRange = NSMakeRange(self.alertBody.text.length, message.length); if ([self.alertBody.text length]) self.alertBody.text = [NSString stringWithFormat:@"%@\n\n---\n\n%@", self.alertBody.text, message]; else self.alertBody.text = message; + [self.alertBody scrollRangeToVisible:scrollRange]; [UIView animateWithDuration:0.2f animations:^{ self.alertContainer.alpha = 1; @@ -310,18 +316,19 @@ [self updateElement:^{ // Update password type. - if (ClassFromOPElementType(type) != ClassFromOPElementType(self.activeElement.type)) { + if (ClassFromOPElementType(type) != ClassFromOPElementType(self.activeElement.type)) // Type requires a different class of element. Recreate the element. - OPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:ClassNameFromOPElementType(type) - inManagedObjectContext:[OPAppDelegate managedObjectContext]]; - newElement.name = self.activeElement.name; - newElement.mpHashHex = self.activeElement.mpHashHex; - newElement.uses = self.activeElement.uses; - newElement.lastUsed = self.activeElement.lastUsed; - - [[OPAppDelegate managedObjectContext] deleteObject:self.activeElement]; - self.activeElement = newElement; - } + [[OPAppDelegate managedObjectContext] performBlockAndWait:^{ + OPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:ClassNameFromOPElementType(type) + inManagedObjectContext:[OPAppDelegate managedObjectContext]]; + newElement.name = self.activeElement.name; + newElement.mpHashHex = self.activeElement.mpHashHex; + newElement.uses = self.activeElement.uses; + newElement.lastUsed = self.activeElement.lastUsed; + + [[OPAppDelegate managedObjectContext] deleteObject:self.activeElement]; + self.activeElement = newElement; + }]; self.activeElement.type = type; diff --git a/MasterPassword/OPSearchDelegate.m b/MasterPassword/OPSearchDelegate.m index 1607de3f..c899ddab 100644 --- a/MasterPassword/OPSearchDelegate.m +++ b/MasterPassword/OPSearchDelegate.m @@ -42,16 +42,18 @@ - (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView { + [[NSNotificationCenter defaultCenter] addObserverForName:OPPersistentStoreDidChangeNotification + object:nil queue:nil usingBlock:^(NSNotification *note) { + NSError *error; + if (![self.fetchedResultsController performFetch:&error]) + err(@"Couldn't fetch elements: %@", error); + }]; + tableView.backgroundColor = [UIColor blackColor]; tableView.rowHeight = 34.0f; tableView.separatorStyle = UITableViewCellSeparatorStyleNone; } -- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView { - - [tableView setEditing:self.searchDisplayController.searchContentsController.editing animated:NO]; -} - - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { [self update]; @@ -89,7 +91,8 @@ [self.searchDisplayController.searchResultsTableView beginUpdates]; } -- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { +- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject + atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { UITableView *tableView = self.searchDisplayController.searchResultsTableView; switch(type) { @@ -118,7 +121,8 @@ } -- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { +- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo + atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { UITableView *tableView = self.searchDisplayController.searchResultsTableView; switch(type) { @@ -191,21 +195,33 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - OPElementEntity *element; if (indexPath.section < [[self.fetchedResultsController sections] count]) - element = [self.fetchedResultsController objectAtIndexPath:indexPath]; + [self.delegate didSelectElement:[self.fetchedResultsController objectAtIndexPath:indexPath]]; else { // "New" section. - element = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([OPElementGeneratedEntity class]) - inManagedObjectContext:[OPAppDelegate managedObjectContext]]; - assert([element isKindOfClass:ClassFromOPElementType(element.type)]); - - element.name = self.searchDisplayController.searchBar.text; - element.mpHashHex = [OPAppDelegate get].keyPhraseHashHex; + NSString *siteName = self.searchDisplayController.searchBar.text; + [AlertViewController showAlertWithTitle:@"New Site" + message:l(@"Do you want to create a new site named:\n%@", siteName) + viewStyle:UIAlertViewStyleDefault + tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { + if (buttonIndex == [alert cancelButtonIndex]) + return; + + [self.fetchedResultsController.managedObjectContext performBlock:^{ + OPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([OPElementGeneratedEntity class]) + inManagedObjectContext:self.fetchedResultsController.managedObjectContext]; + assert([element isKindOfClass:ClassFromOPElementType(element.type)]); + + element.name = siteName; + element.mpHashHex = [OPAppDelegate get].keyPhraseHashHex; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate didSelectElement:element]; + }); + }]; + } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil]; } - - [self.delegate didSelectElement:element]; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { @@ -232,11 +248,11 @@ // "New" section. return; - if (editingStyle == UITableViewCellEditingStyleDelete) { - OPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath]; - - [[OPAppDelegate managedObjectContext] deleteObject:element]; - } + if (editingStyle == UITableViewCellEditingStyleDelete) + [self.fetchedResultsController.managedObjectContext performBlock:^{ + OPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath]; + [self.fetchedResultsController.managedObjectContext deleteObject:element]; + }]; } diff --git a/MasterPassword/OPTypes.h b/MasterPassword/OPTypes.h index 544b238e..26847c56 100644 --- a/MasterPassword/OPTypes.h +++ b/MasterPassword/OPTypes.h @@ -8,6 +8,8 @@ #import +#define OPPersistentStoreDidChangeNotification @"OPPersistentStoreDidChange" + typedef enum { OPElementContentTypePassword, OPElementContentTypeNote, diff --git a/MasterPassword/Resources/Guide/guide_page_0.png b/MasterPassword/Resources/Guide/guide_page_0.png index 2d9c8205..dc7e810b 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_0.png and b/MasterPassword/Resources/Guide/guide_page_0.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_0@2x.png b/MasterPassword/Resources/Guide/guide_page_0@2x.png index c56aba6b..0988c1df 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_0@2x.png and b/MasterPassword/Resources/Guide/guide_page_0@2x.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_1.png b/MasterPassword/Resources/Guide/guide_page_1.png index af306dd4..40e7aada 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_1.png and b/MasterPassword/Resources/Guide/guide_page_1.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_1@2x.png b/MasterPassword/Resources/Guide/guide_page_1@2x.png index 5c8299fc..bef0747c 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_1@2x.png and b/MasterPassword/Resources/Guide/guide_page_1@2x.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_2.png b/MasterPassword/Resources/Guide/guide_page_2.png index 4746bd9d..b979797d 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_2.png and b/MasterPassword/Resources/Guide/guide_page_2.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_2@2x.png b/MasterPassword/Resources/Guide/guide_page_2@2x.png index 818f0da3..cc09ca4e 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_2@2x.png and b/MasterPassword/Resources/Guide/guide_page_2@2x.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_3.png b/MasterPassword/Resources/Guide/guide_page_3.png index 760a6ded..39e55d20 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_3.png and b/MasterPassword/Resources/Guide/guide_page_3.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_3@2x.png b/MasterPassword/Resources/Guide/guide_page_3@2x.png index 6ab4c84a..58ed10ef 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_3@2x.png and b/MasterPassword/Resources/Guide/guide_page_3@2x.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_4.png b/MasterPassword/Resources/Guide/guide_page_4.png index da139718..30aec2af 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_4.png and b/MasterPassword/Resources/Guide/guide_page_4.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_4@2x.png b/MasterPassword/Resources/Guide/guide_page_4@2x.png index 61f433a2..979b7f15 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_4@2x.png and b/MasterPassword/Resources/Guide/guide_page_4@2x.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_5.png b/MasterPassword/Resources/Guide/guide_page_5.png index daa0cfe2..8912c4d5 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_5.png and b/MasterPassword/Resources/Guide/guide_page_5.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_5@2x.png b/MasterPassword/Resources/Guide/guide_page_5@2x.png index f2812b07..af0a6c3a 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_5@2x.png and b/MasterPassword/Resources/Guide/guide_page_5@2x.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_6.png b/MasterPassword/Resources/Guide/guide_page_6.png index a61b593e..3089211f 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_6.png and b/MasterPassword/Resources/Guide/guide_page_6.png differ diff --git a/MasterPassword/Resources/Guide/guide_page_6@2x.png b/MasterPassword/Resources/Guide/guide_page_6@2x.png index 140dfcf4..8d4150a7 100644 Binary files a/MasterPassword/Resources/Guide/guide_page_6@2x.png and b/MasterPassword/Resources/Guide/guide_page_6@2x.png differ diff --git a/MasterPassword/Resources/fifo b/MasterPassword/Resources/fifo deleted file mode 100644 index e69de29b..00000000 diff --git a/MasterPassword/Resources/help.html b/MasterPassword/Resources/help.html index cbffddcb..a3d0e6fe 100644 --- a/MasterPassword/Resources/help.html +++ b/MasterPassword/Resources/help.html @@ -17,6 +17,9 @@ h2 { font-size: inherit; } + h3 { + font-size: 12px; + } i { font-weight: bold; } @@ -33,6 +36,17 @@ color: inherit; font-weight: bold; } + header { + height: 8em; + padding: 3em 0 0; + } + header h1, header h2 { + margin: 0; + padding: 0.5ex; + } + header h3 { + padding-top: 2em; + } -

Master Password

-

by Lyndir

+
+

Master Password

+

by Lyndir

+

© 2011

+

— 1 —

diff --git a/MasterPassword/Resources/logo-bare.png b/MasterPassword/Resources/logo-bare.png new file mode 100644 index 00000000..ac0c3254 Binary files /dev/null and b/MasterPassword/Resources/logo-bare.png differ diff --git a/MasterPassword/Settings.bundle/Root.plist b/MasterPassword/Settings.bundle/Root.plist index ed38b984..fe1efded 100644 --- a/MasterPassword/Settings.bundle/Root.plist +++ b/MasterPassword/Settings.bundle/Root.plist @@ -106,9 +106,9 @@ Type PSToggleSwitchSpecifier Title - Show Quickstart + Show Quick Start Key - showQuickstart + showQuickStart DefaultValue