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.
 | 
			
		||||
         
 | 
			
		||||
         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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,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;
 | 
			
		||||
        
 | 
			
		||||
 
 | 
			
		||||
@@ -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]];
 | 
			
		||||
        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];
 | 
			
		||||
        }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||