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];
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,7 +973,8 @@
[UIView animateWithDuration:0.2 animations:^{
self.emergencyGeneratorContainer.alpha = 0;
} completion:^(BOOL finished) {
[self emergencyCloseAnimated:NO];
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,24 +731,27 @@
@"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) {
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."
viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:
^(UIAlertView *alert_, NSInteger buttonIndex_) {
if (buttonIndex_ == alert_.cancelButtonIndex)
[wSelf showCloudContentAlert];
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];
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 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)
[wSelf showCloudContentAlert];
if (buttonIndex_ == [alert_ firstOtherButtonIndex])
[wSelf.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:YES];
if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 1)
[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,95 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>Enable this setting to send us carefully anonymized information to help us diagnose and resolve issues you might experience in the future.</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<string>[auto]</string>
<key>Title</key>
<string>Version</string>
<key>Key</key>
<string>unset</string>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<string>[auto]</string>
<key>Title</key>
<string>Build</string>
<key>Key</key>
<string>unset</string>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<string>[auto]</string>
<key>Title</key>
<string>Copyright</string>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
<key>Key</key>
<string>unset</string>
</dict>
<dict>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
<key>Title</key>
<string>Send Diagnostic Info</string>
<key>Key</key>
<string>sendInfo</string>
<key>DefaultValue</key>
<false/>
</dict>
<dict>
<key>FooterText</key>
<string>When enabled, you will not be logged out when switching out of the application. This will help you get to your passwords faster, but when someone finds your device unlocked, they can too.</string>
<key>Title</key>
<string>Master Password</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<false/>
<key>Key</key>
<string>rememberLogin</string>
<key>Title</key>
<string>Stay logged in</string>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
</dict>
<dict>
<key>Type</key>
<string>PSGroupSpecifier</string>
<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>
</dict>
<dict>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
<key>Title</key>
<string>iCloud</string>
<key>Key</key>
<string>USMCloudEnabledKey</string>
<key>DefaultValue</key>
<true/>
</dict>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>Enable this setting to send us carefully anonymized information to help us diagnose and resolve issues you might experience in the future.</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<string>[auto]</string>
<key>Title</key>
<string>Version</string>
<key>Key</key>
<string>unset</string>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<string>[auto]</string>
<key>Title</key>
<string>Build</string>
<key>Key</key>
<string>unset</string>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<string>[auto]</string>
<key>Title</key>
<string>Copyright</string>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
<key>Key</key>
<string>unset</string>
</dict>
<dict>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
<key>Title</key>
<string>Send Diagnostic Info</string>
<key>Key</key>
<string>sendInfo</string>
<key>DefaultValue</key>
<false/>
</dict>
<dict>
<key>FooterText</key>
<string>When enabled, you will not be logged out when switching out of the application. This will help you get to your passwords faster, but when someone finds your device unlocked, they can too.</string>
<key>Title</key>
<string>Master Password</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<false/>
<key>Key</key>
<string>rememberLogin</string>
<key>Title</key>
<string>Stay logged in</string>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
</dict>
<dict>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>Title</key>
<string></string>
<key>FooterText</key>
<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>
<string>PSToggleSwitchSpecifier</string>
<key>Title</key>
<string>iCloud</string>
<key>Key</key>
<string>iCloudEnabled</string>
<key>DefaultValue</key>
<true/>
</dict>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</plist>