2
0

iCloud toggling + internal improvements

[UPDATED]   Change TestFlight preprocessor toggles to
            TESTFLIGHT_SDK_VERSION.
[IMPROVED]  Change logic behind shared MPAppDelegate to inheritance,
            allowing for the common files to implement methods that the
            platform-specific class can override.
[IMPROVED]  Handling and checking of config changes.
[ADDED]     iCloud config toggle, allowing a user to turn on and off
            the iCloud store.
[IMPROVED]  Explanation of iCloud.
This commit is contained in:
Maarten Billemont 2012-05-11 22:45:05 +02:00
parent 6bbd183ac9
commit 82b8de5e23
18 changed files with 160 additions and 100 deletions

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit 489ac3004875581ebd0f46256ad6a45e6172b92a Subproject commit b45e33014850ece1a42afb4ac5363aadd0ea90d6

View File

@ -6,9 +6,9 @@
// Copyright (c) 2011 Lyndir. All rights reserved. // Copyright (c) 2011 Lyndir. All rights reserved.
// //
#import "MPAppDelegate.h" #import "MPAppDelegate_Shared.h"
@interface MPAppDelegate (Key) @interface MPAppDelegate_Shared (Key)
- (void)loadStoredKey; - (void)loadStoredKey;
- (IBAction)signOut:(id)sender; - (IBAction)signOut:(id)sender;

View File

@ -7,10 +7,10 @@
// //
#import "MPConfig.h" #import "MPConfig.h"
#import "MPAppDelegate_Shared.h" #import "MPAppDelegate_Key.h"
#import "MPElementEntity.h" #import "MPElementEntity.h"
@implementation MPAppDelegate (Key) @implementation MPAppDelegate_Shared (Key)
static NSDictionary *keyQuery() { static NSDictionary *keyQuery() {
@ -43,7 +43,7 @@ static NSDictionary *keyHashQuery() {
[PearlKeyChain deleteItemForQuery:keyHashQuery()]; [PearlKeyChain deleteItemForQuery:keyHashQuery()];
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyForgotten object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyForgotten object:self];
#if TARGET_OS_IPHONE #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPTestFlightCheckpointMPForgotten]; [TestFlight passCheckpoint:MPTestFlightCheckpointMPForgotten];
#endif #endif
} }
@ -64,7 +64,7 @@ static NSDictionary *keyHashQuery() {
// Key should not be stored in keychain. Delete it. // Key should not be stored in keychain. Delete it.
if ([PearlKeyChain deleteItemForQuery:keyQuery()] != errSecItemNotFound) if ([PearlKeyChain deleteItemForQuery:keyQuery()] != errSecItemNotFound)
dbg(@"Deleted key from key chain."); dbg(@"Deleted key from key chain.");
#if TARGET_OS_IPHONE #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPTestFlightCheckpointMPUnstored]; [TestFlight passCheckpoint:MPTestFlightCheckpointMPUnstored];
#endif #endif
} }
@ -86,13 +86,13 @@ static NSDictionary *keyHashQuery() {
if (![keyHash isEqual:tryKeyHash]) { if (![keyHash isEqual:tryKeyHash]) {
dbg(@"Key phrase hash mismatch. Expected: %@, answer: %@.", keyHash, tryKeyHash); dbg(@"Key phrase hash mismatch. Expected: %@, answer: %@.", keyHash, tryKeyHash);
#if TARGET_OS_IPHONE #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPTestFlightCheckpointMPMismatch]; [TestFlight passCheckpoint:MPTestFlightCheckpointMPMismatch];
#endif #endif
return NO; return NO;
} }
#if TARGET_OS_IPHONE #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPTestFlightCheckpointMPEntered]; [TestFlight passCheckpoint:MPTestFlightCheckpointMPEntered];
#endif #endif
@ -102,15 +102,17 @@ static NSDictionary *keyHashQuery() {
- (void)updateKey:(NSData *)key { - (void)updateKey:(NSData *)key {
self.key = key; if (self.key != key) {
self.key = key;
if (key) if (key)
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeySet object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeySet object:self];
else else
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyUnset object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyUnset object:self];
}
if (key) { if (self.key) {
self.keyHash = keyHashForKey(key); self.keyHash = keyHashForKey(self.key);
self.keyID = [self.keyHash encodeHex]; self.keyID = [self.keyHash encodeHex];
dbg(@"Updating key ID to: %@.", self.keyID); dbg(@"Updating key ID to: %@.", self.keyID);
@ -125,14 +127,14 @@ static NSDictionary *keyHashQuery() {
dbg(@"Storing key in key chain."); dbg(@"Storing key in key chain.");
[PearlKeyChain addOrUpdateItemForQuery:keyQuery() [PearlKeyChain addOrUpdateItemForQuery:keyQuery()
withAttributes:[NSDictionary dictionaryWithObjectsAndKeys: withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
key, (__bridge id)kSecValueData, self.key, (__bridge id)kSecValueData,
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
kSecAttrAccessibleWhenUnlocked, (__bridge id)kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, (__bridge id)kSecAttrAccessible,
#endif #endif
nil]]; nil]];
} }
#if TARGET_OS_IPHONE #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPTestFlightCheckpointSetKey]; [TestFlight passCheckpoint:MPTestFlightCheckpointSetKey];
#endif #endif
} }

View File

@ -6,22 +6,14 @@
// Copyright (c) 2011 Lyndir. All rights reserved. // Copyright (c) 2011 Lyndir. All rights reserved.
// //
#import "MPAppDelegate.h" @interface MPAppDelegate_Shared : PearlAppDelegate
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
@interface MPAppDelegate () {
}
@property (strong, nonatomic) NSData *key; @property (strong, nonatomic) NSData *key;
@property (strong, nonatomic) NSData *keyHash; @property (strong, nonatomic) NSData *keyHash;
@property (strong, nonatomic) NSString *keyID; @property (strong, nonatomic) NSString *keyID;
@end + (MPAppDelegate_Shared *)get;
@interface MPAppDelegate (Shared)
+ (MPAppDelegate *)get;
- (NSURL *)applicationFilesDirectory; - (NSURL *)applicationFilesDirectory;
@end @end

View File

@ -8,14 +8,18 @@
#import "MPAppDelegate_Shared.h" #import "MPAppDelegate_Shared.h"
@implementation MPAppDelegate (Shared) @implementation MPAppDelegate_Shared
+ (MPAppDelegate *)get { @synthesize key;
@synthesize keyHash;
@synthesize keyID;
+ (MPAppDelegate_Shared *)get {
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
return (MPAppDelegate *)[UIApplication sharedApplication].delegate; return (MPAppDelegate_Shared *)[UIApplication sharedApplication].delegate;
#elif defined (__MAC_OS_X_VERSION_MIN_REQUIRED) #elif defined (__MAC_OS_X_VERSION_MIN_REQUIRED)
return (MPAppDelegate *)[NSApplication sharedApplication].delegate; return (MPAppDelegate_Shared *)[NSApplication sharedApplication].delegate;
#else #else
#error Unsupported OS. #error Unsupported OS.
#endif #endif

View File

@ -18,7 +18,7 @@ typedef enum {
MPImportResultInternalError, MPImportResultInternalError,
} MPImportResult; } MPImportResult;
@interface MPAppDelegate (Store) <UbiquityStoreManagerDelegate> @interface MPAppDelegate_Shared (Store) <UbiquityStoreManagerDelegate>
+ (NSManagedObjectContext *)managedObjectContext; + (NSManagedObjectContext *)managedObjectContext;
+ (NSManagedObjectModel *)managedObjectModel; + (NSManagedObjectModel *)managedObjectModel;

View File

@ -9,7 +9,7 @@
#import "MPAppDelegate_Store.h" #import "MPAppDelegate_Store.h"
#import "MPElementEntity.h" #import "MPElementEntity.h"
@implementation MPAppDelegate (Store) @implementation MPAppDelegate_Shared (Store)
static NSDateFormatter *rfc3339DateFormatter = nil; static NSDateFormatter *rfc3339DateFormatter = nil;
@ -148,13 +148,13 @@ static NSDateFormatter *rfc3339DateFormatter = nil;
} }
} }
trc(@"---"); trc(@"---");
if ([MPAppDelegate get].keyID) { if ([MPAppDelegate_Shared get].keyID) {
trc(@"=== Known sites ==="); trc(@"=== Known sites ===");
NSFetchRequest *fetchRequest = [[self managedObjectModel] NSFetchRequest *fetchRequest = [[self managedObjectModel]
fetchRequestFromTemplateWithName:@"MPElements" fetchRequestFromTemplateWithName:@"MPElements"
substitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys: substitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:
@"", @"query", @"", @"query",
[MPAppDelegate get].keyID, @"keyID", [MPAppDelegate_Shared get].keyID, @"keyID",
nil]]; nil]];
[fetchRequest setSortDescriptors: [fetchRequest setSortDescriptors:
[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses" ascending:NO]]]; [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses" ascending:NO]]];
@ -181,9 +181,19 @@ static NSDateFormatter *rfc3339DateFormatter = nil;
dbg(@"StoreManager: %@", message); dbg(@"StoreManager: %@", message);
} }
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didSwitchToiCloud:(BOOL)didSwitch {
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:didSwitch? MPTestFlightCheckpointCloudEnabled: MPTestFlightCheckpointCloudDisabled];
#endif
inf(@"Using iCloud? %@", didSwitch? @"YES": @"NO");
[MPConfig get].iCloud = [NSNumber numberWithBool:didSwitch];
}
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didEncounterError:(NSError *)error cause:(UbiquityStoreManagerErrorCause)cause context:(id)context { - (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didEncounterError:(NSError *)error cause:(UbiquityStoreManagerErrorCause)cause context:(id)context {
#if TARGET_OS_IPHONE #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:str(@"MPTestFlightCheckpointMPErrorUbiquity_%d", cause)]; [TestFlight passCheckpoint:str(@"MPTestFlightCheckpointMPErrorUbiquity_%d", cause)];
#endif #endif
err(@"StoreManager: cause=%d, context=%@, error=%@", cause, context, error); err(@"StoreManager: cause=%d, context=%@, error=%@", cause, context, error);
@ -195,7 +205,7 @@ static NSDateFormatter *rfc3339DateFormatter = nil;
case UbiquityStoreManagerErrorCauseClearStore: case UbiquityStoreManagerErrorCauseClearStore:
break; break;
case UbiquityStoreManagerErrorCauseOpenLocalStore: { case UbiquityStoreManagerErrorCauseOpenLocalStore: {
#if TARGET_OS_IPHONE #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPTestFlightCheckpointLocalStoreIncompatible]; [TestFlight passCheckpoint:MPTestFlightCheckpointLocalStoreIncompatible];
#endif #endif
wrn(@"Local store could not be opened, resetting it."); wrn(@"Local store could not be opened, resetting it.");
@ -206,7 +216,7 @@ static NSDateFormatter *rfc3339DateFormatter = nil;
return; return;
} }
case UbiquityStoreManagerErrorCauseOpenCloudStore: { case UbiquityStoreManagerErrorCauseOpenCloudStore: {
#if TARGET_OS_IPHONE #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPTestFlightCheckpointCloudStoreIncompatible]; [TestFlight passCheckpoint:MPTestFlightCheckpointCloudStoreIncompatible];
#endif #endif
wrn(@"iCloud store could not be opened, resetting it."); wrn(@"iCloud store could not be opened, resetting it.");
@ -355,7 +365,7 @@ static NSDateFormatter *rfc3339DateFormatter = nil;
} }
[self saveContext]; [self saveContext];
#if TARGET_OS_IPHONE #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPTestFlightCheckpointSitesImported]; [TestFlight passCheckpoint:MPTestFlightCheckpointSitesImported];
#endif #endif
@ -415,7 +425,7 @@ static NSDateFormatter *rfc3339DateFormatter = nil;
[rfc3339DateFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceReferenceDate:lastUsed]], uses, type, [name cStringUsingEncoding:NSUTF8StringEncoding], content? content: @""]; [rfc3339DateFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceReferenceDate:lastUsed]], uses, type, [name cStringUsingEncoding:NSUTF8StringEncoding], content? content: @""];
} }
#if TARGET_OS_IPHONE #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPTestFlightCheckpointSitesExported]; [TestFlight passCheckpoint:MPTestFlightCheckpointSitesExported];
#endif #endif

View File

@ -11,6 +11,9 @@
@property (nonatomic, retain) NSNumber *saveKey; @property (nonatomic, retain) NSNumber *saveKey;
@property (nonatomic, retain) NSNumber *rememberKey; @property (nonatomic, retain) NSNumber *rememberKey;
@property (nonatomic, retain) NSNumber *iCloud;
@property (nonatomic, retain) NSNumber *iCloudDecided;
+ (MPConfig *)get; + (MPConfig *)get;
@end @end

View File

@ -7,10 +7,10 @@
// //
#import "MPConfig.h" #import "MPConfig.h"
#import "MPAppDelegate_Shared.h" #import "MPAppDelegate.h"
@implementation MPConfig @implementation MPConfig
@dynamic saveKey, rememberKey; @dynamic saveKey, rememberKey, iCloud, iCloudDecided;
- (id)init { - (id)init {
@ -20,6 +20,8 @@
[self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys: [self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(saveKey)), [NSNumber numberWithBool:NO], NSStringFromSelector(@selector(saveKey)),
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(rememberKey)), [NSNumber numberWithBool:YES], NSStringFromSelector(@selector(rememberKey)),
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(iCloud)),
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(iCloudDecided)),
nil]]; nil]];
self.delegate = [MPAppDelegate get]; self.delegate = [MPAppDelegate get];

View File

@ -7,7 +7,8 @@
// //
#import "MPElementGeneratedEntity.h" #import "MPElementGeneratedEntity.h"
#import "MPAppDelegate_Shared.h" #import "MPAppDelegate.h"
#import "MPAppDelegate_Key.h"
@implementation MPElementGeneratedEntity @implementation MPElementGeneratedEntity

View File

@ -7,7 +7,8 @@
// //
#import "MPElementStoredEntity.h" #import "MPElementStoredEntity.h"
#import "MPAppDelegate_Shared.h" #import "MPAppDelegate.h"
#import "MPAppDelegate_Key.h"
@interface MPElementStoredEntity () @interface MPElementStoredEntity ()

View File

@ -8,8 +8,11 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h> #import <MessageUI/MessageUI.h>
#import "MPAppDelegate_Shared.h"
@interface MPAppDelegate : PearlAppDelegate <MFMailComposeViewControllerDelegate> @interface MPAppDelegate : MPAppDelegate_Shared <MFMailComposeViewControllerDelegate>
+ (MPAppDelegate *)get;
- (void)showGuide; - (void)showGuide;
- (void)loadKey:(BOOL)animated; - (void)loadKey:(BOOL)animated;

View File

@ -6,7 +6,9 @@
// Copyright (c) 2011 Lyndir. All rights reserved. // Copyright (c) 2011 Lyndir. All rights reserved.
// //
#import "MPAppDelegate_Shared.h" #import "MPAppDelegate.h"
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "MPMainViewController.h" #import "MPMainViewController.h"
#import "IASKSettingsReader.h" #import "IASKSettingsReader.h"
@ -30,10 +32,6 @@
@implementation MPAppDelegate @implementation MPAppDelegate
@synthesize key;
@synthesize keyHash;
@synthesize keyID;
+ (void)initialize { + (void)initialize {
[MPiOSConfig get]; [MPiOSConfig get];
@ -43,6 +41,12 @@
//[NSClassFromString(@"WebView") performSelector:NSSelectorFromString(@"_enableRemoteInspector")]; //[NSClassFromString(@"WebView") performSelector:NSSelectorFromString(@"_enableRemoteInspector")];
#endif #endif
} }
+ (MPAppDelegate *)get {
return (MPAppDelegate *)[super get];
}
- (void)showGuide { - (void)showGuide {
[self.navigationController performSegueWithIdentifier:@"MP_Guide" sender:self]; [self.navigationController performSegueWithIdentifier:@"MP_Guide" sender:self];
@ -229,14 +233,7 @@
[[NSNotificationCenter defaultCenter] addObserverForName:kIASKAppSettingChanged object:nil queue:nil [[NSNotificationCenter defaultCenter] addObserverForName:kIASKAppSettingChanged object:nil queue:nil
usingBlock:^(NSNotification *note) { usingBlock:^(NSNotification *note) {
if ([NSStringFromSelector(@selector(saveKey)) [self checkConfig];
isEqualToString:[note.object description]]) {
[self updateKey:self.key];
[self loadKey:YES];
}
if ([NSStringFromSelector(@selector(forgetKey))
isEqualToString:[note.object description]])
[self loadKey:YES];
}]; }];
#ifdef ADHOC #ifdef ADHOC
@ -324,8 +321,10 @@
if ([[MPiOSConfig get].showQuickStart boolValue]) if ([[MPiOSConfig get].showQuickStart boolValue])
[self showGuide]; [self showGuide];
else else {
[self loadKey:NO]; [self loadKey:NO];
[self checkConfig];
}
[TestFlight passCheckpoint:MPTestFlightCheckpointActivated]; [TestFlight passCheckpoint:MPTestFlightCheckpointActivated];
} }
@ -368,6 +367,18 @@
[TestFlight passCheckpoint:MPTestFlightCheckpointDeactivated]; [TestFlight passCheckpoint:MPTestFlightCheckpointDeactivated];
} }
- (void)checkConfig {
if ([[MPConfig get].saveKey boolValue]) {
if (self.key)
[self updateKey:self.key];
} else
[self loadStoredKey];
if ([[MPConfig get].iCloud boolValue] != [self.storeManager iCloudEnabled])
[self.storeManager useiCloudStore:[[MPConfig get].iCloud boolValue] alertUser:YES];
}
#pragma mark - MFMailComposeViewControllerDelegate #pragma mark - MFMailComposeViewControllerDelegate
- (void)mailComposeController:(MFMailComposeViewController *)controller - (void)mailComposeController:(MFMailComposeViewController *)controller
@ -396,39 +407,54 @@
#pragma mark - UbiquityStoreManagerDelegate #pragma mark - UbiquityStoreManagerDelegate
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didSwitchToiCloud:(BOOL)didSwitch { - (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didSwitchToiCloud:(BOOL)iCloudEnabled {
#if TARGET_OS_IPHONE [super ubiquityStoreManager:manager didSwitchToiCloud:iCloudEnabled];
[TestFlight passCheckpoint:didSwitch? MPTestFlightCheckpointCloudEnabled: MPTestFlightCheckpointCloudDisabled];
#endif
inf(@"Using iCloud? %@", didSwitch? @"YES": @"NO"); if (![[MPConfig get].iCloudDecided boolValue]) {
if (!didSwitch) { if (!iCloudEnabled) {
[PearlAlert showAlertWithTitle:@"iCloud" [PearlAlert showAlertWithTitle:@"iCloud"
message: message:
@"iCloud is now disabled.\n" @"iCloud is now disabled.\n\n"
@"It is highly recommended you enable iCloud. " @"It is highly recommended you enable iCloud."
@"Doing so will let you easily access all your sites from any of your devices. " viewStyle:UIAlertViewStyleDefault tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
@"It will also make it easier to recover from the loss of a device.\n\n" [MPConfig get].iCloudDecided = [NSNumber numberWithBool:YES];
@"iCloud only backs up your site names. If you use stored passwords, "
@"those are always encrypted with your master password. "
@"Apple cannot see any of your private information."
viewStyle:UIAlertViewStyleDefault tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex])
return;
[manager useiCloudStore:YES alertUser:YES]; if (buttonIndex == [alert cancelButtonIndex])
} cancelTitle:@"Leave Off" otherTitles:@"Enable iCloud", nil]; return;
if (buttonIndex == [alert firstOtherButtonIndex] + 0)
[PearlAlert showAlertWithTitle:@"About iCloud"
message:
@"iCloud is Apple's solution for saving your data in \"the cloud\" "
@"and making sure your other iPhones, iPads and Macs are in sync.\n\n"
@"For Master Password, that means your sites are available on all your "
@"Apple devices, and you always have a backup of them in case "
@"you loose one or need to restore.\n\n"
@"Because of the way Master Password works, it doesn't need to send your "
@"site's passwords to Apple. Only their names are saved to make it easier "
@"for you to find the site you need. For some sites you may have set "
@"a user-specified password: these are sent to iCloud after being encrypted "
@"with your master password.\n\n"
@"Apple can never see any of your passwords."
viewStyle:UIAlertViewStyleDefault
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
[self ubiquityStoreManager:manager didSwitchToiCloud:iCloudEnabled];
}
cancelTitle:[PearlStrings get].commonButtonThanks otherTitles:nil];
if (buttonIndex == [alert firstOtherButtonIndex] + 1)
[manager useiCloudStore:YES alertUser:NO];
} cancelTitle:@"Leave iCloud Off" otherTitles:@"Explain?", @"Enable iCloud", nil];
}
} }
} }
#pragma mark - TestFlight #pragma mark - TestFlight
static NSDictionary *testFlightInfo = nil;
- (NSDictionary *)testFlightInfo { - (NSDictionary *)testFlightInfo {
static NSDictionary *testFlightInfo = nil;
if (testFlightInfo == nil) if (testFlightInfo == nil)
testFlightInfo = [[NSDictionary alloc] initWithContentsOfURL: testFlightInfo = [[NSDictionary alloc] initWithContentsOfURL:
[[NSBundle mainBundle] URLForResource:@"TestFlight" withExtension:@"plist"]]; [[NSBundle mainBundle] URLForResource:@"TestFlight" withExtension:@"plist"]];
@ -445,10 +471,9 @@ static NSDictionary *testFlightInfo = nil;
#pragma mark - Crashlytics #pragma mark - Crashlytics
static NSDictionary *crashlyticsInfo = nil;
- (NSDictionary *)crashlyticsInfo { - (NSDictionary *)crashlyticsInfo {
static NSDictionary *crashlyticsInfo = nil;
if (crashlyticsInfo == nil) if (crashlyticsInfo == nil)
crashlyticsInfo = [[NSDictionary alloc] initWithContentsOfURL: crashlyticsInfo = [[NSDictionary alloc] initWithContentsOfURL:
[[NSBundle mainBundle] URLForResource:@"Crashlytics" withExtension:@"plist"]]; [[NSBundle mainBundle] URLForResource:@"Crashlytics" withExtension:@"plist"]];
@ -465,10 +490,9 @@ static NSDictionary *crashlyticsInfo = nil;
#pragma mark - Localytics #pragma mark - Localytics
static NSDictionary *localyticsInfo = nil;
- (NSDictionary *)localyticsInfo { - (NSDictionary *)localyticsInfo {
static NSDictionary *localyticsInfo = nil;
if (localyticsInfo == nil) if (localyticsInfo == nil)
localyticsInfo = [[NSDictionary alloc] initWithContentsOfURL: localyticsInfo = [[NSDictionary alloc] initWithContentsOfURL:
[[NSBundle mainBundle] URLForResource:@"Localytics" withExtension:@"plist"]]; [[NSBundle mainBundle] URLForResource:@"Localytics" withExtension:@"plist"]];

View File

@ -7,7 +7,8 @@
// //
#import "MPGuideViewController.h" #import "MPGuideViewController.h"
#import "MPAppDelegate_Shared.h" #import "MPAppDelegate.h"
@implementation MPGuideViewController @implementation MPGuideViewController
@synthesize scrollView; @synthesize scrollView;

View File

@ -7,7 +7,9 @@
// //
#import "MPMainViewController.h" #import "MPMainViewController.h"
#import "MPAppDelegate_Shared.h" #import "MPAppDelegate.h"
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "MPElementGeneratedEntity.h" #import "MPElementGeneratedEntity.h"
#import "MPElementStoredEntity.h" #import "MPElementStoredEntity.h"
#import "IASKAppSettingsViewController.h" #import "IASKAppSettingsViewController.h"
@ -396,10 +398,11 @@
case 0: case 0:
[self toggleHelpAnimated:YES]; [self toggleHelpAnimated:YES];
break; break;
case 1: case 1: {
[self setHelpChapter:@"faq"]; [self setHelpChapter:@"faq"];
[self setHelpHidden:NO animated:YES]; [self setHelpHidden:NO animated:YES];
break; break;
}
case 2: case 2:
[[MPAppDelegate get] showGuide]; [[MPAppDelegate get] showGuide];
break; break;
@ -426,14 +429,8 @@
break; break;
#ifdef ADHOC #ifdef ADHOC
case 7: case 7:
[[MPAppDelegate get].storeManager useiCloudStore:![MPAppDelegate get].storeManager.iCloudEnabled alertUser:YES];
break;
case 8:
#else #else
case 6: case 6:
[[MPAppDelegate get].storeManager useiCloudStore:![MPAppDelegate get].storeManager.iCloudEnabled alertUser:YES];
break;
case 7:
#endif #endif
#endif #endif
{ {
@ -447,12 +444,12 @@
} cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil } cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil
otherTitles: otherTitles:
[self isHelpVisible]? @"Hide Help": @"Show Help", @"FAQ", @"Tutorial", @"Settings", @"Export", [self isHelpVisible]? @"Hide Help": @"Show Help", @"FAQ", @"Tutorial", @"Settings", @"Export",
#ifdef ADHOC #ifdef ADHOC
@"Feedback", @"Feedback",
#endif #endif
#ifdef DEBUG #ifdef DEBUG
@"Reset iCloud", @"Reset iCloud",
@"Toggle iCloud",
#endif #endif
@"Sign Out", @"Sign Out",
nil]; nil];

View File

@ -7,7 +7,8 @@
// //
#import "MPSearchDelegate.h" #import "MPSearchDelegate.h"
#import "MPAppDelegate_Shared.h" #import "MPAppDelegate.h"
#import "MPAppDelegate_Store.h"
#import "MPElementGeneratedEntity.h" #import "MPElementGeneratedEntity.h"
@interface MPSearchDelegate (Private) @interface MPSearchDelegate (Private)

View File

@ -9,7 +9,8 @@
#import <QuartzCore/QuartzCore.h> #import <QuartzCore/QuartzCore.h>
#import "MPUnlockViewController.h" #import "MPUnlockViewController.h"
#import "MPAppDelegate_Shared.h" #import "MPAppDelegate.h"
#import "MPAppDelegate_Key.h"
typedef enum { typedef enum {
MPLockscreenIdle, MPLockscreenIdle,

View File

@ -78,6 +78,24 @@
<key>Type</key> <key>Type</key>
<string>PSToggleSwitchSpecifier</string> <string>PSToggleSwitchSpecifier</string>
</dict> </dict>
<dict>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>Title</key>
<string></string>
<key>FooterText</key>
<string>Makes your sites available to all your Apple devices. This also works as a way of automatically keeping a back-up of your sites. Apple cannot see any of your passwords.</string>
</dict>
<dict>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
<key>Title</key>
<string>iCloud</string>
<key>Key</key>
<string>iCloud</string>
<key>DefaultValue</key>
<true/>
</dict>
</array> </array>
<key>StringsTable</key> <key>StringsTable</key>
<string>Root</string> <string>Root</string>