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 */; };
|
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 */; };
|
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 */; };
|
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 */; };
|
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 */; };
|
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 */; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
DAA3B53A14CCCEE700F35AF6 /* icon_addressbook@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_addressbook@2x.png"; sourceTree = "<group>"; };
|
||||||
@ -1805,6 +1808,7 @@
|
|||||||
DA5BFA50147E415C00F98B1E /* MasterPassword */ = {
|
DA5BFA50147E415C00F98B1E /* MasterPassword */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
DA8E8E4714DDA62D0044257E /* MasterPassword.entitlements */,
|
||||||
DA7C28A214AF02A000491972 /* Models */,
|
DA7C28A214AF02A000491972 /* Models */,
|
||||||
DA7C28A314AF02B100491972 /* Data */,
|
DA7C28A314AF02B100491972 /* Data */,
|
||||||
DA5BFA59147E415C00F98B1E /* OPAppDelegate.h */,
|
DA5BFA59147E415C00F98B1E /* OPAppDelegate.h */,
|
||||||
@ -1834,6 +1838,7 @@
|
|||||||
DA5BFA51147E415C00F98B1E /* Supporting Files */ = {
|
DA5BFA51147E415C00F98B1E /* Supporting Files */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
DA8E8E4514DD7C1D0044257E /* logo-bare.png */,
|
||||||
DA6556F714D730B700841C99 /* Guide */,
|
DA6556F714D730B700841C99 /* Guide */,
|
||||||
DAA3B80414CDBBC600F35AF6 /* jquery-1.6.1.min.js */,
|
DAA3B80414CDBBC600F35AF6 /* jquery-1.6.1.min.js */,
|
||||||
DA84811E14CB50C100A2FA22 /* Tooltips */,
|
DA84811E14CB50C100A2FA22 /* Tooltips */,
|
||||||
@ -2992,6 +2997,7 @@
|
|||||||
DA65571214D760BD00841C99 /* guide_page_6@2x.png in Resources */,
|
DA65571214D760BD00841C99 /* guide_page_6@2x.png in Resources */,
|
||||||
DA41A40B14DB3BF100638533 /* guide_page_0.png in Resources */,
|
DA41A40B14DB3BF100638533 /* guide_page_0.png in Resources */,
|
||||||
DA41A40C14DB3BF100638533 /* guide_page_0@2x.png in Resources */,
|
DA41A40C14DB3BF100638533 /* guide_page_0@2x.png in Resources */,
|
||||||
|
DA8E8E4614DD7C1D0044257E /* logo-bare.png in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -3182,6 +3188,7 @@
|
|||||||
DA5BFA6E147E415C00F98B1E /* Debug */ = {
|
DA5BFA6E147E415C00F98B1E /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
CODE_SIGN_ENTITLEMENTS = MasterPassword/MasterPassword.entitlements;
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "MasterPassword/MasterPassword-Prefix.pch";
|
GCC_PREFIX_HEADER = "MasterPassword/MasterPassword-Prefix.pch";
|
||||||
INFOPLIST_FILE = "MasterPassword/MasterPassword-Info.plist";
|
INFOPLIST_FILE = "MasterPassword/MasterPassword-Info.plist";
|
||||||
@ -3194,6 +3201,7 @@
|
|||||||
DA5BFA6F147E415C00F98B1E /* Release */ = {
|
DA5BFA6F147E415C00F98B1E /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
CODE_SIGN_ENTITLEMENTS = MasterPassword/MasterPassword.entitlements;
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "MasterPassword/MasterPassword-Prefix.pch";
|
GCC_PREFIX_HEADER = "MasterPassword/MasterPassword-Prefix.pch";
|
||||||
INFOPLIST_FILE = "MasterPassword/MasterPassword-Info.plist";
|
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"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||||
<rect key="contentStretch" x="0.050000000000000003" y="0.10000000000000001" width="0.89999999999999991" height="0.79999999999999982"/>
|
<rect key="contentStretch" x="0.050000000000000003" y="0.10000000000000001" width="0.89999999999999991" height="0.79999999999999982"/>
|
||||||
</imageView>
|
</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"/>
|
<rect key="frame" x="11" y="20" width="298" height="86"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||||
<rect key="contentStretch" x="0.050000000000000003" y="0.10000000000000001" width="0.89999999999999991" height="0.79999999999999982"/>
|
<rect key="contentStretch" x="0.050000000000000003" y="0.10000000000000001" width="0.89999999999999991" height="0.79999999999999982"/>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>en</string>
|
<string>en</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>${PRODUCT_NAME}</string>
|
<string>Passwords</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>${EXECUTABLE_NAME}</string>
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
<key>CFBundleIconFiles</key>
|
<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 {
|
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||||
|
|
||||||
if ([[OPConfig get].showQuickstart boolValue])
|
if ([[OPConfig get].showQuickStart boolValue])
|
||||||
[self showGuide];
|
[self showGuide];
|
||||||
else
|
else
|
||||||
[self loadKeyPhrase];
|
[self loadKeyPhrase];
|
||||||
@ -244,13 +244,14 @@
|
|||||||
|
|
||||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||||
|
|
||||||
|
[self saveContext];
|
||||||
|
|
||||||
if (![[OPConfig get].rememberKeyPhrase boolValue])
|
if (![[OPConfig get].rememberKeyPhrase boolValue])
|
||||||
self.keyPhrase = nil;
|
self.keyPhrase = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationWillTerminate:(UIApplication *)application
|
- (void)applicationWillTerminate:(UIApplication *)application {
|
||||||
{
|
|
||||||
// Saves changes in the application's managed object context before the application terminates.
|
|
||||||
[self saveContext];
|
[self saveContext];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,18 +270,13 @@
|
|||||||
return [(OPAppDelegate *)[UIApplication sharedApplication].delegate managedObjectModel];
|
return [(OPAppDelegate *)[UIApplication sharedApplication].delegate managedObjectModel];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)saveContext
|
- (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.
|
[self.managedObjectContext performBlock:^{
|
||||||
*/
|
NSError *error = nil;
|
||||||
err(@"Unresolved error %@, %@", error, [error userInfo]);
|
if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error])
|
||||||
abort();
|
err(@"Unresolved error %@", error);
|
||||||
}
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setKeyPhrase:(NSString *)keyPhrase {
|
- (void)setKeyPhrase:(NSString *)keyPhrase {
|
||||||
@ -312,17 +308,30 @@
|
|||||||
*/
|
*/
|
||||||
- (NSManagedObjectContext *)managedObjectContext
|
- (NSManagedObjectContext *)managedObjectContext
|
||||||
{
|
{
|
||||||
if (__managedObjectContext != nil)
|
if (__managedObjectContext)
|
||||||
{
|
|
||||||
return __managedObjectContext;
|
return __managedObjectContext;
|
||||||
}
|
|
||||||
|
|
||||||
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
|
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
|
||||||
if (coordinator != nil)
|
if (coordinator) {
|
||||||
{
|
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
|
||||||
__managedObjectContext = [[NSManagedObjectContext alloc] init];
|
__managedObjectContext.persistentStoreCoordinator = coordinator;
|
||||||
[__managedObjectContext setPersistentStoreCoordinator: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;
|
return __managedObjectContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,14 +341,11 @@
|
|||||||
*/
|
*/
|
||||||
- (NSManagedObjectModel *)managedObjectModel
|
- (NSManagedObjectModel *)managedObjectModel
|
||||||
{
|
{
|
||||||
if (__managedObjectModel != nil)
|
if (__managedObjectModel)
|
||||||
{
|
|
||||||
return __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
|
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
|
||||||
{
|
{
|
||||||
if (__persistentStoreCoordinator != nil)
|
if (__persistentStoreCoordinator)
|
||||||
{
|
|
||||||
return __persistentStoreCoordinator;
|
return __persistentStoreCoordinator;
|
||||||
}
|
|
||||||
|
|
||||||
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MasterPassword.sqlite"];
|
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MasterPassword.sqlite"];
|
||||||
|
|
||||||
NSError *error = nil;
|
|
||||||
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
|
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
|
||||||
|
[__persistentStoreCoordinator lock];
|
||||||
|
NSError *error = nil;
|
||||||
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL
|
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL
|
||||||
options:[NSDictionary dictionaryWithObjectsAndKeys:
|
options:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
(id)kCFBooleanTrue, NSMigratePersistentStoresAutomaticallyOption,
|
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
|
||||||
(id)kCFBooleanTrue, NSInferMappingModelAutomaticallyOption,
|
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
|
||||||
|
@"MasterPassword.store", NSPersistentStoreUbiquitousContentNameKey,
|
||||||
|
[[[NSFileManager defaultManager]
|
||||||
|
URLForUbiquityContainerIdentifier:nil]
|
||||||
|
URLByAppendingPathComponent:@"store"
|
||||||
|
isDirectory:YES], NSPersistentStoreUbiquitousContentURLKey,
|
||||||
nil]
|
nil]
|
||||||
error:&error])
|
error:&error])
|
||||||
{
|
{
|
||||||
@ -395,6 +405,7 @@
|
|||||||
@throw [NSException exceptionWithName:error.domain reason:error.localizedDescription
|
@throw [NSException exceptionWithName:error.domain reason:error.localizedDescription
|
||||||
userInfo:[NSDictionary dictionaryWithObject:error forKey:@"cause"]];
|
userInfo:[NSDictionary dictionaryWithObject:error forKey:@"cause"]];
|
||||||
}
|
}
|
||||||
|
[__persistentStoreCoordinator unlock];
|
||||||
|
|
||||||
return __persistentStoreCoordinator;
|
return __persistentStoreCoordinator;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
@property (nonatomic, retain) NSNumber *rememberKeyPhrase;
|
@property (nonatomic, retain) NSNumber *rememberKeyPhrase;
|
||||||
@property (nonatomic, retain) NSNumber *forgetKeyPhrase;
|
@property (nonatomic, retain) NSNumber *forgetKeyPhrase;
|
||||||
@property (nonatomic, retain) NSNumber *helpHidden;
|
@property (nonatomic, retain) NSNumber *helpHidden;
|
||||||
@property (nonatomic, retain) NSNumber *showQuickstart;
|
@property (nonatomic, retain) NSNumber *showQuickStart;
|
||||||
|
|
||||||
+ (OPConfig *)get;
|
+ (OPConfig *)get;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
@implementation OPConfig
|
@implementation OPConfig
|
||||||
|
|
||||||
@dynamic dataStoreError, storeKeyPhrase, rememberKeyPhrase, forgetKeyPhrase, helpHidden, showQuickstart;
|
@dynamic dataStoreError, storeKeyPhrase, rememberKeyPhrase, forgetKeyPhrase, helpHidden, showQuickStart;
|
||||||
|
|
||||||
|
|
||||||
- (id)init {
|
- (id)init {
|
||||||
@ -24,7 +24,7 @@
|
|||||||
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(rememberKeyPhrase)),
|
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(rememberKeyPhrase)),
|
||||||
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(forgetKeyPhrase)),
|
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(forgetKeyPhrase)),
|
||||||
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(helpHidden)),
|
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(helpHidden)),
|
||||||
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(showQuickstart)),
|
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(showQuickStart)),
|
||||||
nil]];
|
nil]];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
@property (nonatomic) int16_t type;
|
@property (nonatomic) int16_t type;
|
||||||
@property (nonatomic) int16_t uses;
|
@property (nonatomic) int16_t uses;
|
||||||
@property (nonatomic) NSTimeInterval lastUsed;
|
@property (nonatomic) NSTimeInterval lastUsed;
|
||||||
|
@property (nonatomic, readonly) id content;
|
||||||
|
|
||||||
- (void)use;
|
- (void)use;
|
||||||
- (id)content;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
[super viewWillDisappear:animated];
|
[super viewWillDisappear:animated];
|
||||||
|
|
||||||
[OPConfig get].showQuickstart = [NSNumber numberWithBool:NO];
|
[OPConfig get].showQuickStart = [NSNumber numberWithBool:NO];
|
||||||
[[OPAppDelegate get] loadKeyPhrase];
|
[[OPAppDelegate get] loadKeyPhrase];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,25 +75,29 @@
|
|||||||
[self updateAnimated:NO];
|
[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 {
|
- (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.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]
|
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue]
|
||||||
usingBlock:^(NSNotification *note) {
|
usingBlock:^(NSNotification *note) {
|
||||||
if (![OPAppDelegate get].keyPhrase) {
|
if (![OPAppDelegate get].keyPhrase) {
|
||||||
@ -216,10 +220,12 @@
|
|||||||
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
|
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
|
||||||
|
|
||||||
self.alertTitle.text = title;
|
self.alertTitle.text = title;
|
||||||
|
NSRange scrollRange = NSMakeRange(self.alertBody.text.length, message.length);
|
||||||
if ([self.alertBody.text length])
|
if ([self.alertBody.text length])
|
||||||
self.alertBody.text = [NSString stringWithFormat:@"%@\n\n---\n\n%@", self.alertBody.text, message];
|
self.alertBody.text = [NSString stringWithFormat:@"%@\n\n---\n\n%@", self.alertBody.text, message];
|
||||||
else
|
else
|
||||||
self.alertBody.text = message;
|
self.alertBody.text = message;
|
||||||
|
[self.alertBody scrollRangeToVisible:scrollRange];
|
||||||
|
|
||||||
[UIView animateWithDuration:0.2f animations:^{
|
[UIView animateWithDuration:0.2f animations:^{
|
||||||
self.alertContainer.alpha = 1;
|
self.alertContainer.alpha = 1;
|
||||||
@ -310,18 +316,19 @@
|
|||||||
|
|
||||||
[self updateElement:^{
|
[self updateElement:^{
|
||||||
// Update password type.
|
// 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.
|
// Type requires a different class of element. Recreate the element.
|
||||||
OPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:ClassNameFromOPElementType(type)
|
[[OPAppDelegate managedObjectContext] performBlockAndWait:^{
|
||||||
inManagedObjectContext:[OPAppDelegate managedObjectContext]];
|
OPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:ClassNameFromOPElementType(type)
|
||||||
newElement.name = self.activeElement.name;
|
inManagedObjectContext:[OPAppDelegate managedObjectContext]];
|
||||||
newElement.mpHashHex = self.activeElement.mpHashHex;
|
newElement.name = self.activeElement.name;
|
||||||
newElement.uses = self.activeElement.uses;
|
newElement.mpHashHex = self.activeElement.mpHashHex;
|
||||||
newElement.lastUsed = self.activeElement.lastUsed;
|
newElement.uses = self.activeElement.uses;
|
||||||
|
newElement.lastUsed = self.activeElement.lastUsed;
|
||||||
|
|
||||||
[[OPAppDelegate managedObjectContext] deleteObject:self.activeElement];
|
[[OPAppDelegate managedObjectContext] deleteObject:self.activeElement];
|
||||||
self.activeElement = newElement;
|
self.activeElement = newElement;
|
||||||
}
|
}];
|
||||||
|
|
||||||
self.activeElement.type = type;
|
self.activeElement.type = type;
|
||||||
|
|
||||||
|
@ -42,16 +42,18 @@
|
|||||||
|
|
||||||
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView {
|
- (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.backgroundColor = [UIColor blackColor];
|
||||||
tableView.rowHeight = 34.0f;
|
tableView.rowHeight = 34.0f;
|
||||||
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
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 {
|
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
|
||||||
|
|
||||||
[self update];
|
[self update];
|
||||||
@ -89,7 +91,8 @@
|
|||||||
[self.searchDisplayController.searchResultsTableView beginUpdates];
|
[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;
|
UITableView *tableView = self.searchDisplayController.searchResultsTableView;
|
||||||
switch(type) {
|
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;
|
UITableView *tableView = self.searchDisplayController.searchResultsTableView;
|
||||||
switch(type) {
|
switch(type) {
|
||||||
@ -191,21 +195,33 @@
|
|||||||
|
|
||||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
OPElementEntity *element;
|
|
||||||
if (indexPath.section < [[self.fetchedResultsController sections] count])
|
if (indexPath.section < [[self.fetchedResultsController sections] count])
|
||||||
element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
[self.delegate didSelectElement:[self.fetchedResultsController objectAtIndexPath:indexPath]];
|
||||||
|
|
||||||
else {
|
else {
|
||||||
// "New" section.
|
// "New" section.
|
||||||
element = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([OPElementGeneratedEntity class])
|
NSString *siteName = self.searchDisplayController.searchBar.text;
|
||||||
inManagedObjectContext:[OPAppDelegate managedObjectContext]];
|
[AlertViewController showAlertWithTitle:@"New Site"
|
||||||
assert([element isKindOfClass:ClassFromOPElementType(element.type)]);
|
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;
|
||||||
|
|
||||||
element.name = self.searchDisplayController.searchBar.text;
|
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
||||||
element.mpHashHex = [OPAppDelegate get].keyPhraseHashHex;
|
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 {
|
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||||
@ -232,11 +248,11 @@
|
|||||||
// "New" section.
|
// "New" section.
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (editingStyle == UITableViewCellEditingStyleDelete) {
|
if (editingStyle == UITableViewCellEditingStyleDelete)
|
||||||
OPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
[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>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#define OPPersistentStoreDidChangeNotification @"OPPersistentStoreDidChange"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OPElementContentTypePassword,
|
OPElementContentTypePassword,
|
||||||
OPElementContentTypeNote,
|
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 {
|
h2 {
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
}
|
}
|
||||||
|
h3 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
i {
|
i {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
@ -33,6 +36,17 @@
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
font-weight: bold;
|
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>
|
</style>
|
||||||
<script src="jquery-1.6.1.min.js" type="text/javascript"></script>
|
<script src="jquery-1.6.1.min.js" type="text/javascript"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -43,8 +57,11 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1 onclick="setClass('OPElementStoredEntity')">Master Password</h1>
|
<header>
|
||||||
<h2 onclick="setClass('OPElementGeneratedEntity')">by Lyndir</h2>
|
<h1>Master Password</h1>
|
||||||
|
<h2>by <a href="http://www.lyndir.com">Lyndir</a></h2>
|
||||||
|
<h3>© 2011</h3>
|
||||||
|
</header>
|
||||||
|
|
||||||
<h2 id="1">— 1 —</h2>
|
<h2 id="1">— 1 —</h2>
|
||||||
<p>
|
<p>
|
||||||
|
BIN
MasterPassword/Resources/logo-bare.png
Normal file
After Width: | Height: | Size: 12 KiB |
@ -106,9 +106,9 @@
|
|||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
<string>PSToggleSwitchSpecifier</string>
|
<string>PSToggleSwitchSpecifier</string>
|
||||||
<key>Title</key>
|
<key>Title</key>
|
||||||
<string>Show Quickstart</string>
|
<string>Show Quick Start</string>
|
||||||
<key>Key</key>
|
<key>Key</key>
|
||||||
<string>showQuickstart</string>
|
<string>showQuickStart</string>
|
||||||
<key>DefaultValue</key>
|
<key>DefaultValue</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
|