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:
parent
ab360066e5
commit
0921796136
2
External/InAppSettingsKit
vendored
2
External/InAppSettingsKit
vendored
@ -1 +1 @@
|
||||
Subproject commit 3ad873577684c1e98c11cc081200e9d0402ad3b7
|
||||
Subproject commit fcc72db0d54cd181f27b71e81901fc66958d71bf
|
2
External/UbiquityStoreManager
vendored
2
External/UbiquityStoreManager
vendored
@ -1 +1 @@
|
||||
Subproject commit 77327f4adc7ca9dbca1a1f3e632d1e95c9ce7e56
|
||||
Subproject commit ebc094f4c160f8aa3ebbe3f760fbf734b58bc5e6
|
@ -75,34 +75,83 @@
|
||||
- (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"];
|
||||
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];
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
[[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];
|
||||
}];
|
||||
}
|
||||
|
||||
// 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 auto‑correct 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 auto‑corrected 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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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>
|
@ -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 */,
|
||||
|
@ -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's also a good way of keeping automatic backups.</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
@ -84,7 +84,7 @@
|
||||
<key>Title</key>
|
||||
<string>iCloud</string>
|
||||
<key>Key</key>
|
||||
<string>USMCloudEnabledKey</string>
|
||||
<string>iCloudEnabled</string>
|
||||
<key>DefaultValue</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
Loading…
Reference in New Issue
Block a user