iCloud sync of store.
[FIXED] Guide toggle not working well. [IMPROVED] Core Data on a separate thread. [IMPROVED] Guide.
BIN
Default.png
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 130 KiB |
@ -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 = "<group>"; };
|
||||
DA84817714CB521E00A2FA22 /* tip_location_teal.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tip_location_teal.png; sourceTree = "<group>"; };
|
||||
DA84817814CB521E00A2FA22 /* tip_location_wood.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tip_location_wood.png; sourceTree = "<group>"; };
|
||||
DA8E8E4514DD7C1D0044257E /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "logo-bare.png"; path = "Resources/logo-bare.png"; sourceTree = "<group>"; };
|
||||
DA8E8E4714DDA62D0044257E /* MasterPassword.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = "<group>"; };
|
||||
DAA3B53814CCCEE700F35AF6 /* icon_addressbook-person@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_addressbook-person@2x.png"; sourceTree = "<group>"; };
|
||||
DAA3B53914CCCEE700F35AF6 /* icon_addressbook.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_addressbook.png; sourceTree = "<group>"; };
|
||||
DAA3B53A14CCCEE700F35AF6 /* icon_addressbook@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_addressbook@2x.png"; sourceTree = "<group>"; };
|
||||
@ -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";
|
||||
|
@ -349,7 +349,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<rect key="contentStretch" x="0.050000000000000003" y="0.10000000000000001" width="0.89999999999999991" height="0.79999999999999982"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" alpha="0.80000001192092896" contentMode="scaleToFill" image="ui_panel_display.png" id="cw7-HD-Wht">
|
||||
<imageView userInteractionEnabled="NO" alpha="0.80000000000000004" contentMode="scaleToFill" image="ui_panel_display.png" id="cw7-HD-Wht">
|
||||
<rect key="frame" x="11" y="20" width="298" height="86"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<rect key="contentStretch" x="0.050000000000000003" y="0.10000000000000001" width="0.89999999999999991" height="0.79999999999999982"/>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<string>Passwords</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFiles</key>
|
||||
|
16
MasterPassword/MasterPassword.entitlements
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.ubiquity-container-identifiers</key>
|
||||
<array>
|
||||
<string>$(TeamIdentifierPrefix)com.lyndir.lhunath.MasterPassword</string>
|
||||
</array>
|
||||
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
|
||||
<string>$(TeamIdentifierPrefix)com.lyndir.lhunath.MasterPassword</string>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)com.lyndir.lhunath.MasterPassword</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
@ -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.
|
||||
- (void)saveContext {
|
||||
|
||||
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();
|
||||
}
|
||||
[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;
|
||||
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MasterPassword" withExtension:@"momd"];
|
||||
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,6 +405,7 @@
|
||||
@throw [NSException exceptionWithName:error.domain reason:error.localizedDescription
|
||||
userInfo:[NSDictionary dictionaryWithObject:error forKey:@"cause"]];
|
||||
}
|
||||
[__persistentStoreCoordinator unlock];
|
||||
|
||||
return __persistentStoreCoordinator;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
[OPConfig get].showQuickstart = [NSNumber numberWithBool:NO];
|
||||
[OPConfig get].showQuickStart = [NSNumber numberWithBool:NO];
|
||||
[[OPAppDelegate get] loadKeyPhrase];
|
||||
}
|
||||
|
||||
|
@ -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,8 +316,9 @@
|
||||
|
||||
[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.
|
||||
[[OPAppDelegate managedObjectContext] performBlockAndWait:^{
|
||||
OPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:ClassNameFromOPElementType(type)
|
||||
inManagedObjectContext:[OPAppDelegate managedObjectContext]];
|
||||
newElement.name = self.activeElement.name;
|
||||
@ -321,7 +328,7 @@
|
||||
|
||||
[[OPAppDelegate managedObjectContext] deleteObject:self.activeElement];
|
||||
self.activeElement = newElement;
|
||||
}
|
||||
}];
|
||||
|
||||
self.activeElement.type = type;
|
||||
|
||||
|
@ -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 <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
|
||||
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)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]];
|
||||
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 = self.searchDisplayController.searchBar.text;
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||
@ -232,11 +248,11 @@
|
||||
// "New" section.
|
||||
return;
|
||||
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete) {
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete)
|
||||
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
||||
OPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
||||
|
||||
[[OPAppDelegate managedObjectContext] deleteObject:element];
|
||||
}
|
||||
[self.fetchedResultsController.managedObjectContext deleteObject:element];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#define OPPersistentStoreDidChangeNotification @"OPPersistentStoreDidChange"
|
||||
|
||||
typedef enum {
|
||||
OPElementContentTypePassword,
|
||||
OPElementContentTypeNote,
|
||||
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 247 KiB After Width: | Height: | Size: 218 KiB |
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 331 KiB After Width: | Height: | Size: 314 KiB |
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 110 KiB |
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 285 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 267 KiB |
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 138 KiB |
Before Width: | Height: | Size: 412 KiB After Width: | Height: | Size: 405 KiB |
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 354 KiB After Width: | Height: | Size: 328 KiB |
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 369 KiB After Width: | Height: | Size: 240 KiB |
@ -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;
|
||||
}
|
||||
</style>
|
||||
<script src="jquery-1.6.1.min.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
@ -43,8 +57,11 @@
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 onclick="setClass('OPElementStoredEntity')">Master Password</h1>
|
||||
<h2 onclick="setClass('OPElementGeneratedEntity')">by Lyndir</h2>
|
||||
<header>
|
||||
<h1>Master Password</h1>
|
||||
<h2>by <a href="http://www.lyndir.com">Lyndir</a></h2>
|
||||
<h3>© 2011</h3>
|
||||
</header>
|
||||
|
||||
<h2 id="1">— 1 —</h2>
|
||||
<p>
|
||||
|
BIN
MasterPassword/Resources/logo-bare.png
Normal file
After Width: | Height: | Size: 12 KiB |
@ -106,9 +106,9 @@
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>Title</key>
|
||||
<string>Show Quickstart</string>
|
||||
<string>Show Quick Start</string>
|
||||
<key>Key</key>
|
||||
<string>showQuickstart</string>
|
||||
<string>showQuickStart</string>
|
||||
<key>DefaultValue</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|