2
0

Log VC, iCloud toggling, iOS 7 fixes.

[UPDATED]   Show users and sites in cloud stores of log VC.
[ADDED]     Ability to turn off iCloud if corruption happens.
[ADDED]     When switching iCloud on/off, provide user the option to migrate his current sites.
[ADDED]     Ability to get to settings & logs from unlock VC.
This commit is contained in:
Maarten Billemont 2013-09-05 23:52:12 -04:00
parent ab360066e5
commit 0921796136
12 changed files with 387 additions and 237 deletions

@ -1 +1 @@
Subproject commit 3ad873577684c1e98c11cc081200e9d0402ad3b7
Subproject commit fcc72db0d54cd181f27b71e81901fc66958d71bf

@ -1 +1 @@
Subproject commit 77327f4adc7ca9dbca1a1f3e632d1e95c9ce7e56
Subproject commit ebc094f4c160f8aa3ebbe3f760fbf734b58bc5e6

View File

@ -63,9 +63,9 @@
return;
switchCloudStoreProgress = [PearlAlert showActivityWithTitle:@"Enumerating Stores"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{
[self switchCloudStore];
});
} );
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil];
}
} cancelTitle:[PearlStrings get].commonButtonCancel
@ -75,39 +75,88 @@
- (void)switchCloudStore {
NSError *error = nil;
NSURL *cloudStoreDirectory = [[MPiOSAppDelegate get].storeManager URLForCloudStoreDirectory];
NSURL *cloudContentDirectory = [[MPiOSAppDelegate get].storeManager URLForCloudContentDirectory];
NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:cloudContentDirectory includingPropertiesForKeys:nil
options:NSDirectoryEnumerationSkipsHiddenFiles error:&error];
if (!contents)
err(@"While enumerating cloud contents: %@", error);
NSMutableArray *contentNames = [NSMutableArray arrayWithCapacity:[contents count]];
BOOL directory = NO;
BOOL directory;
NSMutableDictionary *stores = [NSMutableDictionary dictionaryWithCapacity:[contents count]];
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *storePSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSFetchRequest *usersFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
NSFetchRequest *sitesFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
for (NSURL *content in contents)
if ([[NSFileManager defaultManager] fileExistsAtPath:content.path isDirectory:&directory] && directory)
[contentNames addObject:[content lastPathComponent]];
if ([[NSFileManager defaultManager] fileExistsAtPath:content.path isDirectory:&directory] && directory) {
NSString *contentString = [content lastPathComponent];
NSUInteger lastDash = [contentString rangeOfString:@"-" options:NSBackwardsSearch].location;
NSString *storeDescription = lastDash == NSNotFound? contentString: [contentString substringFromIndex:lastDash + 1];
NSPersistentStore *store = nil;
@try {
NSURL *storeURL = [[cloudStoreDirectory
URLByAppendingPathComponent:[content lastPathComponent] isDirectory:NO]
URLByAppendingPathExtension:@"sqlite"];
if (!(store = [storePSC addPersistentStoreWithType:NSSQLiteStoreType configuration:nil
URL:storeURL options:@{
NSPersistentStoreUbiquitousContentNameKey : [[MPiOSAppDelegate get].storeManager valueForKey:@"contentName"],
NSPersistentStoreUbiquitousContentURLKey : content,
NSMigratePersistentStoresAutomaticallyOption : @YES,
NSInferMappingModelAutomaticallyOption : @YES,
NSPersistentStoreFileProtectionKey : NSFileProtectionComplete
} error:&error])) {
wrn(@"Couldn't describe store opening %@: %@", [content lastPathComponent], error);
continue;
}
NSUInteger userCount, siteCount;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
moc.persistentStoreCoordinator = storePSC;
if ((userCount = [moc countForFetchRequest:usersFetchRequest error:&error]) == NSNotFound) {
wrn(@"Couldn't describe store userCount %@: %@", [content lastPathComponent], error);
continue;
}
if ((siteCount = [moc countForFetchRequest:sitesFetchRequest error:&error]) == NSNotFound) {
wrn(@"Couldn't describe store siteCount %@: %@", [content lastPathComponent], error);
continue;
}
storeDescription = PearlString( @"%@: %dU, %dS", storeDescription, userCount, siteCount );
}
@catch (NSException *exception) {
wrn(@"Couldn't describe store %@: exception %@", [content lastPathComponent], exception);
}
@finally {
if (store) if (![storePSC removePersistentStore:store error:&error])
wrn(@"Couldn't remove store %@: %@", [content lastPathComponent], error);
[stores setObject:storeDescription forKey:[content lastPathComponent]];
}
}
NSString *storeUUID = [[MPiOSAppDelegate get].storeManager valueForKey:@"storeUUID_ThreadSafe"];
dispatch_async(dispatch_get_main_queue(), ^{
NSUInteger lastDash = [storeUUID rangeOfString:@"-" options:NSBackwardsSearch].location;
NSString *title = PearlString( @"Current: %@", lastDash == NSNotFound? storeUUID: [storeUUID substringFromIndex:lastDash + 1] );
dispatch_async( dispatch_get_main_queue(), ^{
[switchCloudStoreProgress cancelAlertAnimated:YES];
[PearlSheet showSheetWithTitle:storeUUID
viewStyle:UIActionSheetStyleAutomatic
NSArray *storeUUIDs = [stores allKeys];
[PearlSheet showSheetWithTitle:title viewStyle:UIActionSheetStyleAutomatic
initSheet:^(UIActionSheet *sheet) {
for (NSString *contentName in contentNames) {
[sheet addButtonWithTitle:contentName];
}
for (NSString *contentName in storeUUIDs)
[sheet addButtonWithTitle:[stores objectForKey:contentName]];
}
tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
if (buttonIndex == sheet.cancelButtonIndex)
return;
[[MPiOSAppDelegate get].storeManager setValue:[contentNames objectAtIndex:(unsigned)buttonIndex] forKey:@"storeUUID"];
[[MPiOSAppDelegate get].storeManager setValue:[storeUUIDs objectAtIndex:(unsigned)buttonIndex]
forKey:@"storeUUID"];
[[MPiOSAppDelegate get].storeManager reloadStore];
[[MPiOSAppDelegate get] signOutAnimated:YES];
}
cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil otherTitles:nil];
});
} );
}
- (IBAction)toggleLevelControl:(UISegmentedControl *)sender {

View File

@ -42,7 +42,7 @@
if (self.cloudSwitch) {
[MPiOSConfig get].iCloudDecided = @YES;
[MPiOSAppDelegate get].storeManager.cloudEnabled = self.cloudSwitch.on;
[MPiOSConfig get].iCloudEnabled = @(self.cloudSwitch.on);
}
if (self.rememberLoginSwitch)
[MPiOSConfig get].rememberLogin = @(self.rememberLoginSwitch.on);

View File

@ -37,15 +37,14 @@
@property(weak, nonatomic) IBOutlet UIButton *emergencyPassword;
@property(weak, nonatomic) IBOutlet UIView *emergencyContentTipContainer;
@property(nonatomic, strong) UIColor *avatarShadowColor;
- (IBAction)targetedUserAction:(UILongPressGestureRecognizer *)sender;
- (IBAction)facebook:(UIButton *)sender;
- (IBAction)twitter:(UIButton *)sender;
- (IBAction)google:(UIButton *)sender;
- (IBAction)mail:(UIButton *)sender;
- (IBAction)add:(UIButton *)sender;
- (IBAction)emergencyClose:(UIButton *)sender;
- (IBAction)emergencyCopy:(UIButton *)sender;
- (IBAction)facebook:(id)sender;
- (IBAction)twitter:(id)sender;
- (IBAction)google:(id)sender;
- (IBAction)mail:(id)sender;
- (IBAction)add:(id)sender;
- (IBAction)emergencyOpen:(id)sender;
- (IBAction)emergencyClose:(id)sender;
- (IBAction)emergencyCopy:(id)sender;
@end

View File

@ -243,12 +243,17 @@
inf(@"Lock screen will disappear");
[self emergencyCloseAnimated:animated];
[self.marqueeTipTimer invalidate];
[super viewWillDisappear:animated];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"MP_Settings"])
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
- (BOOL)prefersStatusBarHidden {
return YES;
@ -266,29 +271,8 @@
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake) {
MPCheckpoint( MPCheckpointEmergencyGenerator, nil );
[[self.view findFirstResponderInHierarchy] resignFirstResponder];
self.emergencyGeneratorContainer.alpha = 0;
self.emergencyGeneratorContainer.hidden = NO;
self.emergencyGeneratorContainer.frame = CGRectSetX( self.emergencyGeneratorContainer.frame,
self.emergencyGeneratorContainer.frame.origin.x - 100 );
[UIView animateWithDuration:0.3 animations:^{
self.emergencyGeneratorContainer.frame = CGRectSetX( self.emergencyGeneratorContainer.frame,
self.emergencyGeneratorContainer.frame.origin.x + 150 );
self.emergencyGeneratorContainer.alpha = 1;
} completion:^(BOOL finished) {
if (!finished)
return;
[self.emergencyName becomeFirstResponder];
[UIView animateWithDuration:0.2 animations:^{
self.emergencyGeneratorContainer.frame = CGRectSetX( self.emergencyGeneratorContainer.frame,
self.emergencyGeneratorContainer.frame.origin.x - 50 );
}];
}];
}
if (motion == UIEventSubtypeMotionShake)
[self emergencyOpenAnimated:YES];
}
- (void)marqueeTip {
@ -518,7 +502,6 @@
self.nameLabel.center = CGPointMake( 160, 94 );
self.nameLabel.backgroundColor = [UIColor blackColor];
self.oldNameLabel.center = self.nameLabel.center;
self.avatarShadowColor = [UIColor whiteColor];
}
else if (!selectedUser && self.passwordView.alpha == 1) {
// User was just deselected.
@ -529,7 +512,6 @@
self.nameLabel.center = CGPointMake( 160, 296 );
self.nameLabel.backgroundColor = [UIColor clearColor];
self.oldNameLabel.center = self.nameLabel.center;
self.avatarShadowColor = [UIColor lightGrayColor];
}
// Lay out the word wall.
@ -913,12 +895,20 @@
}];
}
- (IBAction)emergencyClose:(UIButton *)sender {
- (IBAction)emergencyOpen:(id)sender {
if ([sender isKindOfClass:[UIGestureRecognizer class]] && ((UIGestureRecognizer *)sender).state != UIGestureRecognizerStateBegan)
return;
[self emergencyOpenAnimated:YES];
}
- (IBAction)emergencyClose:(id)sender {
[self emergencyCloseAnimated:YES];
}
- (IBAction)emergencyCopy:(UIButton *)sender {
- (IBAction)emergencyCopy:(id)sender {
inf(@"Copying emergency password for: %@", self.emergencyName.text);
[UIPasteboard generalPasteboard].string = [self.emergencyPassword titleForState:UIControlStateNormal];
@ -943,6 +933,38 @@
} );
}
- (void)emergencyOpenAnimated:(BOOL)animated {
[[self.emergencyGeneratorContainer findFirstResponderInHierarchy] resignFirstResponder];
if (animated) {
self.emergencyGeneratorContainer.alpha = 0;
self.emergencyGeneratorContainer.hidden = NO;
self.emergencyGeneratorContainer.frame = CGRectSetX( self.emergencyGeneratorContainer.frame,
self.emergencyGeneratorContainer.frame.origin.x - 100 );
[UIView animateWithDuration:0.2 animations:^{
self.emergencyGeneratorContainer.frame = CGRectSetX( self.emergencyGeneratorContainer.frame,
self.emergencyGeneratorContainer.frame.origin.x + 150 );
self.emergencyGeneratorContainer.alpha = 1;
} completion:^(BOOL finished) {
if (finished) {
[self emergencyOpenAnimated:NO];
[UIView animateWithDuration:0.2 animations:^{
self.emergencyGeneratorContainer.frame = CGRectSetX( self.emergencyGeneratorContainer.frame,
self.emergencyGeneratorContainer.frame.origin.x - 50 );
}];
}
}];
return;
}
MPCheckpoint( MPCheckpointEmergencyGenerator, nil );
self.emergencyGeneratorContainer.hidden = NO;
self.emergencyGeneratorContainer.alpha = 1;
[self.emergencyName becomeFirstResponder];
}
- (void)emergencyCloseAnimated:(BOOL)animated {
[[self.emergencyGeneratorContainer findFirstResponderInHierarchy] resignFirstResponder];
@ -951,6 +973,7 @@
[UIView animateWithDuration:0.2 animations:^{
self.emergencyGeneratorContainer.alpha = 0;
} completion:^(BOOL finished) {
if (finished)
[self emergencyCloseAnimated:NO];
}];
return;
@ -1043,7 +1066,7 @@
destructiveTitle:@"Delete User" otherTitles:@"Reset Password", nil];
}
- (IBAction)facebook:(UIButton *)sender {
- (IBAction)facebook:(id)sender {
if (![SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
[PearlAlert showAlertWithTitle:@"Facebook Not Enabled" message:@"To send tweets, configure Facebook from Settings."
@ -1058,7 +1081,7 @@
[self presentViewController:vc animated:YES completion:nil];
}
- (IBAction)twitter:(UIButton *)sender {
- (IBAction)twitter:(id)sender {
if (![SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) {
[PearlAlert showAlertWithTitle:@"Twitter Not Enabled" message:@"To send tweets, configure Twitter from Settings."
@ -1073,19 +1096,19 @@
[self presentViewController:vc animated:YES completion:nil];
}
- (IBAction)google:(UIButton *)sender {
- (IBAction)google:(id)sender {
id<GPPShareBuilder> shareDialog = [[GPPShare sharedInstance] shareDialog];
[[[shareDialog setURLToShare:[NSURL URLWithString:@"http://masterpasswordapp.com"]]
setPrefillText:@"I've started doing passwords properly thanks to Master Password."] open];
}
- (IBAction)mail:(UIButton *)sender {
- (IBAction)mail:(id)sender {
[[MPiOSAppDelegate get] showFeedbackWithLogs:NO forVC:self];
}
- (IBAction)add:(UIButton *)sender {
- (IBAction)add:(id)sender {
[PearlSheet showSheetWithTitle:@"Follow Master Password" viewStyle:UIActionSheetStyleBlackTranslucent
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {

View File

@ -182,67 +182,12 @@
@try {
[[NSNotificationCenter defaultCenter] addObserverForName:MPCheckConfigNotification object:nil queue:nil usingBlock:
^(NSNotification *note) {
if ([[MPiOSConfig get].sendInfo boolValue]) {
if ([PearlLogger get].printLevel > PearlLogLevelInfo)
[PearlLogger get].printLevel = PearlLogLevelInfo;
#ifdef CRASHLYTICS
[[Crashlytics sharedInstance] setBoolValue:[[MPConfig get].rememberLogin boolValue] forKey:@"rememberLogin"];
[[Crashlytics sharedInstance] setBoolValue:[self storeManager].cloudEnabled forKey:@"iCloud"];
[[Crashlytics sharedInstance] setBoolValue:[[MPConfig get].iCloudDecided boolValue] forKey:@"iCloudDecided"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].sendInfo boolValue] forKey:@"sendInfo"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].helpHidden boolValue] forKey:@"helpHidden"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].showSetup boolValue] forKey:@"showQuickStart"];
[[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].firstRun boolValue] forKey:@"firstRun"];
[[Crashlytics sharedInstance] setIntValue:[[PearlConfig get].launchCount intValue] forKey:@"launchCount"];
[[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].askForReviews boolValue] forKey:@"askForReviews"];
[[Crashlytics sharedInstance]
setIntValue:[[PearlConfig get].reviewAfterLaunches intValue] forKey:@"reviewAfterLaunches"];
[[Crashlytics sharedInstance] setObjectValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"];
#endif
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [MPConfig get].rememberLogin )
forKey:@"rememberLogin"];
[TestFlight addCustomEnvironmentInformation:PearlStringB( [self storeManager].cloudEnabled )
forKey:@"iCloud"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [MPConfig get].iCloudDecided )
forKey:@"iCloudDecided"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [MPiOSConfig get].sendInfo )
forKey:@"sendInfo"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [MPiOSConfig get].helpHidden )
forKey:@"helpHidden"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [MPiOSConfig get].showSetup )
forKey:@"showQuickStart"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [PearlConfig get].firstRun )
forKey:@"firstRun"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [PearlConfig get].launchCount )
forKey:@"launchCount"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [PearlConfig get].askForReviews )
forKey:@"askForReviews"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [PearlConfig get].reviewAfterLaunches )
forKey:@"reviewAfterLaunches"];
[TestFlight addCustomEnvironmentInformation:[PearlConfig get].reviewedVersion
forKey:@"reviewedVersion"];
#endif
MPCheckpoint( MPCheckpointConfig, @{
@"rememberLogin" : @([[MPConfig get].rememberLogin boolValue]),
@"iCloud" : @([self storeManager].cloudEnabled),
@"iCloudDecided" : @([[MPConfig get].iCloudDecided boolValue]),
@"sendInfo" : @([[MPiOSConfig get].sendInfo boolValue]),
@"helpHidden" : @([[MPiOSConfig get].helpHidden boolValue]),
@"showQuickStart" : @([[MPiOSConfig get].showSetup boolValue]),
@"firstRun" : @([[PearlConfig get].firstRun boolValue]),
@"launchCount" : NilToNSNull([PearlConfig get].launchCount),
@"askForReviews" : @([[PearlConfig get].askForReviews boolValue]),
@"reviewAfterLaunches" : NilToNSNull([PearlConfig get].reviewAfterLaunches),
@"reviewedVersion" : NilToNSNull([PearlConfig get].reviewedVersion)
} );
}
[self checkConfig];
}];
[[NSNotificationCenter defaultCenter]
addObserverForName:kIASKAppSettingChanged object:nil queue:nil usingBlock:^(NSNotification *note) {
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:note userInfo:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification
object:note userInfo:nil];
}];
#ifdef ADHOC
@ -447,7 +392,8 @@
- (void)applicationDidBecomeActive:(UIApplication *)application {
inf(@"Re-activated");
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:application userInfo:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification
object:application userInfo:nil];
#ifdef LOCALYTICS
[[LocalyticsSession sharedLocalyticsSession] resume];
@ -635,17 +581,108 @@
otherTitles:[PearlStrings get].commonButtonContinue, nil];
}
#pragma mark - PearlConfigDelegate
- (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)value {
if (configKey == @selector(traceMode)) {
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
inf(@"Trace is now: %@", [[MPiOSConfig get].traceMode boolValue]? @"ON": @"OFF");
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification
object:NSStringFromSelector( configKey ) userInfo:nil];
}
- (void)checkConfig {
// iCloud enabled / disabled
if ([[MPiOSConfig get].iCloudEnabled boolValue] != self.storeManager.cloudEnabled) {
if ([[MPiOSConfig get].iCloudEnabled boolValue])
[self.storeManager setCloudEnabledAndOverwriteCloudWithLocalIfConfirmed:^(void (^setConfirmationAnswer)(BOOL answer)) {
[PearlAlert showAlertWithTitle:@"Keep Sites?"
message:@"You can either revert to your old iCloud sites or overwrite them with your current sites."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex])
setConfirmationAnswer( NO );
if (buttonIndex == [alert firstOtherButtonIndex])
setConfirmationAnswer( YES );
}
cancelTitle:@"Revert" otherTitles:@"Replace iCloud", nil];
}];
else
[self.storeManager setCloudDisabledAndOverwriteLocalWithCloudIfConfirmed:^(void (^setConfirmationAnswer)(BOOL answer)) {
[PearlAlert showAlertWithTitle:@"Keep iCloud Sites?"
message:@"You can either revert to your old sites or overwrite them with your current iCloud sites."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex])
setConfirmationAnswer( NO );
if (buttonIndex == [alert firstOtherButtonIndex])
setConfirmationAnswer( YES );
}
cancelTitle:@"Revert" otherTitles:@"Copy iCloud", nil];
}];
}
[[NSNotificationCenter defaultCenter]
postNotificationName:MPCheckConfigNotification object:NSStringFromSelector( configKey ) userInfo:nil];
// Trace mode
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
// Send info
if ([[MPiOSConfig get].sendInfo boolValue]) {
if ([PearlLogger get].printLevel > PearlLogLevelInfo)
[PearlLogger get].printLevel = PearlLogLevelInfo;
#ifdef CRASHLYTICS
[[Crashlytics sharedInstance] setBoolValue:[[MPConfig get].rememberLogin boolValue] forKey:@"rememberLogin"];
[[Crashlytics sharedInstance] setBoolValue:[self storeManager].cloudEnabled forKey:@"iCloud"];
[[Crashlytics sharedInstance] setBoolValue:[[MPConfig get].iCloudDecided boolValue] forKey:@"iCloudDecided"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].sendInfo boolValue] forKey:@"sendInfo"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].helpHidden boolValue] forKey:@"helpHidden"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].showSetup boolValue] forKey:@"showQuickStart"];
[[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].firstRun boolValue] forKey:@"firstRun"];
[[Crashlytics sharedInstance] setIntValue:[[PearlConfig get].launchCount intValue] forKey:@"launchCount"];
[[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].askForReviews boolValue] forKey:@"askForReviews"];
[[Crashlytics sharedInstance]
setIntValue:[[PearlConfig get].reviewAfterLaunches intValue] forKey:@"reviewAfterLaunches"];
[[Crashlytics sharedInstance] setObjectValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"];
#endif
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [MPConfig get].rememberLogin )
forKey:@"rememberLogin"];
[TestFlight addCustomEnvironmentInformation:PearlStringB( [self storeManager].cloudEnabled )
forKey:@"iCloud"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [MPConfig get].iCloudDecided )
forKey:@"iCloudDecided"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [MPiOSConfig get].sendInfo )
forKey:@"sendInfo"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [MPiOSConfig get].helpHidden )
forKey:@"helpHidden"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [MPiOSConfig get].showSetup )
forKey:@"showQuickStart"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [PearlConfig get].firstRun )
forKey:@"firstRun"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [PearlConfig get].launchCount )
forKey:@"launchCount"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [PearlConfig get].askForReviews )
forKey:@"askForReviews"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB( [PearlConfig get].reviewAfterLaunches )
forKey:@"reviewAfterLaunches"];
[TestFlight addCustomEnvironmentInformation:[PearlConfig get].reviewedVersion
forKey:@"reviewedVersion"];
#endif
MPCheckpoint( MPCheckpointConfig, @{
@"rememberLogin" : @([[MPConfig get].rememberLogin boolValue]),
@"iCloud" : @([self storeManager].cloudEnabled),
@"iCloudDecided" : @([[MPConfig get].iCloudDecided boolValue]),
@"sendInfo" : @([[MPiOSConfig get].sendInfo boolValue]),
@"helpHidden" : @([[MPiOSConfig get].helpHidden boolValue]),
@"showQuickStart" : @([[MPiOSConfig get].showSetup boolValue]),
@"firstRun" : @([[PearlConfig get].firstRun boolValue]),
@"launchCount" : NilToNSNull([PearlConfig get].launchCount),
@"askForReviews" : @([[PearlConfig get].askForReviews boolValue]),
@"reviewAfterLaunches" : NilToNSNull([PearlConfig get].reviewAfterLaunches),
@"reviewedVersion" : NilToNSNull([PearlConfig get].reviewedVersion)
} );
}
}
@ -665,6 +702,7 @@
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didLoadStoreForCoordinator:(NSPersistentStoreCoordinator *)coordinator
isCloud:(BOOL)isCloudStore {
[MPiOSConfig get].iCloudEnabled = @(isCloudStore);
[super ubiquityStoreManager:manager didLoadStoreForCoordinator:coordinator isCloud:isCloudStore];
dispatch_async( dispatch_get_main_queue(), ^{
@ -693,13 +731,15 @@
@"Waiting for your other device to autocorrect the problem..."
initAlert:^(UIAlertView *alert) {
[alert addButtonWithTitle:@"Fix Now"];
[alert addButtonWithTitle:@"Turn Off"];
}];
self.handleCloudContentAlert.tappedButtonBlock = ^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert firstOtherButtonIndex])
wSelf.fixCloudContentAlert = [PearlAlert showAlertWithTitle:@"Fix iCloud Now" message:
@"This problem can be autocorrected by opening the app on another device where you recently made changes.\n"
@"You can correct the problem from this device anyway, but recent changes made on another device might get lost.\n\n"
@"You can also turn iCloud off and go back to your local sites."
@"You can fix the problem from this device anyway, but recent changes from another device might get lost.\n\n"
@"You can also turn iCloud off for now."
viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:
^(UIAlertView *alert_, NSInteger buttonIndex_) {
if (buttonIndex_ == alert_.cancelButtonIndex)
@ -707,10 +747,11 @@
if (buttonIndex_ == [alert_ firstOtherButtonIndex])
[wSelf.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:YES];
if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 1)
wSelf.storeManager.cloudEnabled = NO;
}
cancelTitle:[PearlStrings get].commonButtonBack otherTitles:@"Fix Anyway",
@"Turn Off", nil];
[MPiOSConfig get].iCloudEnabled = NO;
} cancelTitle:[PearlStrings get].commonButtonBack
otherTitles:@"Fix Anyway", @"Turn Off", nil];
if (buttonIndex == [alert firstOtherButtonIndex] + 1)
[MPiOSConfig get].iCloudEnabled = NO;
};
}

View File

@ -17,5 +17,6 @@
@property(nonatomic, retain) NSNumber *typeTipShown;
@property(nonatomic, retain) NSNumber *loginNameTipShown;
@property(nonatomic, retain) NSNumber *traceMode;
@property(nonatomic, retain) NSNumber *iCloudEnabled;
@end

View File

@ -8,7 +8,7 @@
@implementation MPiOSConfig
@dynamic helpHidden, siteInfoHidden, showSetup, actionsTipShown, typeTipShown, loginNameTipShown, traceMode;
@dynamic helpHidden, siteInfoHidden, showSetup, actionsTipShown, typeTipShown, loginNameTipShown, traceMode, iCloudEnabled;
- (id)init {
@ -23,7 +23,8 @@
NSStringFromSelector( @selector(actionsTipShown) ) : @(!self.firstRun),
NSStringFromSelector( @selector(typeTipShown) ) : @(!self.firstRun),
NSStringFromSelector( @selector(loginNameTipShown) ) : @NO,
NSStringFromSelector( @selector(traceMode) ) : @NO
NSStringFromSelector( @selector(traceMode) ) : @NO,
NSStringFromSelector( @selector(iCloudEnabled) ) : @YES
}];
return self;

View File

@ -1499,6 +1499,7 @@ You can use the words in the background for inspiration in finding a memorable m
<button opaque="NO" alpha="0.10000000000000001" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="vM2-8p-qn7" userLabel="mail">
<rect key="frame" x="276" y="0.0" width="44" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<gestureRecognizers/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<state key="normal" title="✉">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
@ -1509,6 +1510,7 @@ You can use the words in the background for inspiration in finding a memorable m
</state>
<connections>
<action selector="mail:" destination="Nbn-Rv-sP1" eventType="touchUpInside" id="f6b-uF-NNs"/>
<outletCollection property="gestureRecognizers" destination="6ew-le-Bbs" appends="YES" id="rBb-Ur-1Cc"/>
</connections>
</button>
<button opaque="NO" alpha="0.10000000000000001" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="2dq-bb-mPl" userLabel="add">
@ -1538,7 +1540,7 @@ You can use the words in the background for inspiration in finding a memorable m
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view hidden="YES" alpha="0.30000000000000016" contentMode="scaleToFill" id="KNa-Xb-RuE" userLabel="View - Emergency Generator">
<view alpha="0.30000000000000016" contentMode="scaleToFill" id="KNa-Xb-RuE" userLabel="View - Emergency Generator">
<rect key="frame" x="-100" y="0.0" width="520" height="504"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
@ -1645,6 +1647,22 @@ You can use the words in the background for inspiration in finding a memorable m
<action selector="emergencyClose:" destination="Nbn-Rv-sP1" eventType="touchUpInside" id="U2r-pg-UGB"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Rxb-jY-TFS">
<rect key="frame" x="15" y="1" width="44" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" hint="" label="Close"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="icon_gears.png">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<segue destination="Vrp-Gl-7qn" kind="push" identifier="MP_Settings" id="hxY-aA-ngI"/>
</connections>
</button>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" hidesWhenStopped="YES" style="whiteLarge" id="3Ax-91-gVM">
<rect key="frame" x="141" y="324" width="37" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
@ -1731,6 +1749,11 @@ You can use the words in the background for inspiration in finding a memorable m
<action selector="targetedUserAction:" destination="Nbn-Rv-sP1" id="mgC-0X-heO"/>
</connections>
</pongPressGestureRecognizer>
<pongPressGestureRecognizer allowableMovement="10" minimumPressDuration="0.5" id="6ew-le-Bbs">
<connections>
<action selector="emergencyOpen:" destination="Nbn-Rv-sP1" id="w9I-iB-DcU"/>
</connections>
</pongPressGestureRecognizer>
</objects>
<point key="canvasLocation" x="455" y="145"/>
</scene>
@ -2287,7 +2310,13 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<outlet property="delegate" destination="Vrp-Gl-7qn" id="Kcg-1V-uAD"/>
</connections>
</tableView>
<navigationItem key="navigationItem" id="ZbK-tt-Abw"/>
<navigationItem key="navigationItem" id="ZbK-tt-Abw">
<barButtonItem key="rightBarButtonItem" title="Logs" id="G5c-pK-nH0">
<connections>
<segue destination="Tx0-mM-kHk" kind="push" id="5Im-dm-qfS"/>
</connections>
</barButtonItem>
</navigationItem>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="lBn-RG-JE2" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
@ -2883,6 +2912,7 @@ However, it means that anyone who finds your device unlocked can do the same.</s
<image name="icon_cancel.png" width="32" height="32"/>
<image name="icon_edit.png" width="32" height="32"/>
<image name="icon_find.png" width="32" height="32"/>
<image name="icon_gears.png" width="32" height="32"/>
<image name="icon_person.png" width="32" height="32"/>
<image name="icon_play.png" width="32" height="32"/>
<image name="icon_plus.png" width="32" height="32"/>
@ -2918,6 +2948,8 @@ However, it means that anyone who finds your device unlocked can do the same.</s
</simulatedMetricsContainer>
<inferredMetricsTieBreakers>
<segue reference="swi-5o-hfK"/>
<segue reference="9Bs-cD-ddF"/>
<segue reference="hxY-aA-ngI"/>
<segue reference="rWT-Kr-cAs"/>
<segue reference="KIl-ZW-M7G"/>
</inferredMetricsTieBreakers>
</document>

View File

@ -72,6 +72,8 @@
DA6701E016406BB400B61001 /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA6701DF16406BB400B61001 /* AdSupport.framework */; settings = {ATTRIBUTES = (Required, ); }; };
DA672D2F14F92C6B004A189C /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DA672D2E14F92C6B004A189C /* libz.dylib */; };
DA672D3014F9413D004A189C /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
DA69540617D975D900BF294E /* icon_gears.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37841711E29500CF925C /* icon_gears.png */; };
DA69540717D975D900BF294E /* icon_gears@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37851711E29500CF925C /* icon_gears@2x.png */; };
DA829E52159847E0002417D3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DA829E6215984832002417D3 /* libFontReplacer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA829E51159847E0002417D3 /* libFontReplacer.a */; };
DA95D5F214DF0B2C008D1B94 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */; };
@ -3121,6 +3123,7 @@
DABD39041711E29700CF925C /* ui_panel_display@2x.png in Resources */,
DABD391D1711E29700CF925C /* ui_spinner.png in Resources */,
DABD391E1711E29700CF925C /* ui_spinner@2x.png in Resources */,
DA69540617D975D900BF294E /* icon_gears.png in Resources */,
DABD39271711E29700CF925C /* ui_textfield.png in Resources */,
DABD39281711E29700CF925C /* ui_textfield@2x.png in Resources */,
DABD39291711E29700CF925C /* ui_toolbar_container.png in Resources */,
@ -3190,6 +3193,7 @@
DABD3ABD1711E29800CF925C /* icon_play@2x.png in Resources */,
DABD3ABE1711E29800CF925C /* icon_plus.png in Resources */,
DABD3ABF1711E29800CF925C /* icon_plus@2x.png in Resources */,
DA69540717D975D900BF294E /* icon_gears@2x.png in Resources */,
DABD3B1C1711E29800CF925C /* icon_up.png in Resources */,
DABD3B1D1711E29800CF925C /* icon_up@2x.png in Resources */,
DABD3B3C1711E29800CF925C /* tip_alert_black.png in Resources */,

View File

@ -1,7 +1,7 @@
<?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>
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
@ -76,7 +76,7 @@
<key>Title</key>
<string></string>
<key>FooterText</key>
<string>Synchronizes your sites with your other Apple devices. It's also a good way of keeping automatic backups.</string>
<string>Synchronizes your sites with your other Apple devices. It&apos;s also a good way of keeping automatic backups.</string>
</dict>
<dict>
<key>Type</key>
@ -84,12 +84,12 @@
<key>Title</key>
<string>iCloud</string>
<key>Key</key>
<string>USMCloudEnabledKey</string>
<string>iCloudEnabled</string>
<key>DefaultValue</key>
<true/>
</dict>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</dict>
</plist>