diff --git a/External/Crashlytics.framework/Versions/A/Crashlytics b/External/Crashlytics.framework/Versions/A/Crashlytics index 6bf7ab8b..c62b9af9 100644 Binary files a/External/Crashlytics.framework/Versions/A/Crashlytics and b/External/Crashlytics.framework/Versions/A/Crashlytics differ diff --git a/External/Crashlytics.framework/Versions/A/Headers/Crashlytics.h b/External/Crashlytics.framework/Versions/A/Headers/Crashlytics.h index 2de40dbd..59addeff 100644 --- a/External/Crashlytics.framework/Versions/A/Headers/Crashlytics.h +++ b/External/Crashlytics.framework/Versions/A/Headers/Crashlytics.h @@ -170,6 +170,16 @@ OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); **/ @property (nonatomic, readonly) NSDate *crashedOnDate; +/** + * Returns the os version that the application crashed on. + **/ +@property (nonatomic, readonly) NSString *OSVersion; + +/** + * Returns the os build version that the application crashed on. + **/ +@property (nonatomic, readonly) NSString *OSBuildVersion; + @end /** diff --git a/External/Crashlytics.framework/Versions/A/Resources/Info.plist b/External/Crashlytics.framework/Versions/A/Resources/Info.plist index c7e9624d..bb5c77b7 100644 --- a/External/Crashlytics.framework/Versions/A/Resources/Info.plist +++ b/External/Crashlytics.framework/Versions/A/Resources/Info.plist @@ -15,13 +15,13 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.8 + 2.0.9 CFBundleSupportedPlatforms iPhoneOS CFBundleVersion - 0200.08.00 + 0200.09.00 DTPlatformName iphoneos MinimumOSVersion diff --git a/External/Pearl b/External/Pearl index 2293e3a4..c2b07f9c 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit 2293e3a48a0e54c09a7ce135c946e4c4ca46bac7 +Subproject commit c2b07f9c648fd6386aca0c982b44769bb36ac4b3 diff --git a/External/UbiquityStoreManager b/External/UbiquityStoreManager index 226619a4..389c8b78 160000 --- a/External/UbiquityStoreManager +++ b/External/UbiquityStoreManager @@ -1 +1 @@ -Subproject commit 226619a45744dd4aefbbdb948d7e44ab3ecad341 +Subproject commit 389c8b78501331af77c363857f381a497cbf0060 diff --git a/MasterPassword/ObjC/MPAppDelegate_Store.m b/MasterPassword/ObjC/MPAppDelegate_Store.m index 6e5fcb7f..657006ae 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Store.m +++ b/MasterPassword/ObjC/MPAppDelegate_Store.m @@ -33,11 +33,6 @@ typedef NS_ENUM(NSInteger, MPMigrationLevelCloudStore) { }; @implementation MPAppDelegate_Shared(Store) -#if TARGET_OS_IPHONE - PearlAssociatedObjectProperty(PearlAlert*, HandleCloudContentAlert, handleCloudContentAlert); -PearlAssociatedObjectProperty(PearlAlert*, FixCloudContentAlert, fixCloudContentAlert); -PearlAssociatedObjectProperty(PearlOverlay*, StoreLoading, storeLoading); -#endif PearlAssociatedObjectProperty(NSManagedObjectContext*, PrivateManagedObjectContext, privateManagedObjectContext); PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, mainManagedObjectContext); @@ -127,7 +122,10 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillTerminateNotification object:[NSApplication sharedApplication] queue:nil usingBlock:^(NSNotification *note) { - [[self mainManagedObjectContext] saveToStore]; + NSManagedObjectContext *moc = self.mainManagedObjectContextIfReady; + [moc performBlockAndWait:^{ + [moc saveToStore]; + }]; }]; #endif @@ -330,15 +328,13 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, - (void)ubiquityStoreManager:(UbiquityStoreManager *)manager willLoadStoreIsCloud:(BOOL)isCloudStore { - self.privateManagedObjectContext = nil; - self.mainManagedObjectContext = nil; + NSManagedObjectContext *moc = self.mainManagedObjectContextIfReady; + [moc performBlockAndWait:^{ + [moc saveToStore]; -#if TARGET_OS_IPHONE - dispatch_async( dispatch_get_main_queue(), ^{ - if (![self.storeLoading isVisible]) - self.storeLoading = [PearlOverlay showOverlayWithTitle:@"Opening Your Data"]; - } ); -#endif + self.privateManagedObjectContext = nil; + self.mainManagedObjectContext = nil; + }]; [self migrateStoreForManager:manager isCloud:isCloudStore]; } @@ -378,12 +374,6 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, self.privateManagedObjectContext = privateManagedObjectContext; self.mainManagedObjectContext = mainManagedObjectContext; - -#if TARGET_OS_IPHONE - [self.handleCloudContentAlert cancelAlertAnimated:YES]; - [self.fixCloudContentAlert cancelAlertAnimated:YES]; - [self.storeLoading cancelOverlay]; -#endif } - (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didEncounterError:(NSError *)error cause:(UbiquityStoreErrorCause)cause @@ -397,46 +387,6 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, } ); } -- (BOOL)ubiquityStoreManager:(UbiquityStoreManager *)manager handleCloudContentCorruptionWithHealthyStore:(BOOL)storeHealthy { - -#if TARGET_OS_IPHONE - if (manager.cloudEnabled && !storeHealthy && !([self.handleCloudContentAlert.alertView isVisible] || [self.fixCloudContentAlert.alertView isVisible])) - dispatch_async( dispatch_get_main_queue(), ^{ - [self showCloudContentAlert]; - } ); -#endif - - return NO; -} - -#if TARGET_OS_IPHONE -- (void)showCloudContentAlert { - - __weak MPAppDelegate_Shared *wSelf = self; - [self.handleCloudContentAlert cancelAlertAnimated:NO]; - self.handleCloudContentAlert = [PearlAlert showActivityWithTitle:@"iCloud Sync Problem" message: - @"Waiting for your other device to auto‑correct the problem..." - initAlert:^(UIAlertView *alert) { - [alert addButtonWithTitle:@"Fix Now"]; - }]; - - self.handleCloudContentAlert.tappedButtonBlock = ^(UIAlertView *alert, NSInteger buttonIndex) { - wSelf.fixCloudContentAlert = [PearlAlert showAlertWithTitle:@"Fix iCloud Now" message: - @"This problem can usually 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." - viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock: - ^(UIAlertView *alert_, NSInteger buttonIndex_) { - if (buttonIndex_ == alert_.cancelButtonIndex) - [wSelf showCloudContentAlert]; - if (buttonIndex_ == [alert_ firstOtherButtonIndex]) - [wSelf.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:YES]; - } - cancelTitle:[PearlStrings get].commonButtonBack otherTitles:@"Fix Anyway", nil]; - }; -} - -#endif - #pragma mark - Utilities - (void)addElementNamed:(NSString *)siteName completion:(void (^)(MPElementEntity *element))completion { diff --git a/MasterPassword/ObjC/MPEntities.m b/MasterPassword/ObjC/MPEntities.m index 9bc32e01..15bc8b23 100644 --- a/MasterPassword/ObjC/MPEntities.m +++ b/MasterPassword/ObjC/MPEntities.m @@ -13,11 +13,12 @@ - (BOOL)saveToStore { - NSError *error; - if (![self save:&error]) { - err(@"While saving: %@", error); - return NO; - } + __block BOOL success = NO; + [self performBlockAndWait:^{ + NSError *error = nil; + if (!(success = [self save:&error])) + err(@"While saving: %@", error); + }]; return !self.parentContext || [self.parentContext saveToStore]; } diff --git a/MasterPassword/ObjC/Mac/MPMacAppDelegate.h b/MasterPassword/ObjC/Mac/MPMacAppDelegate.h index 6dcb8f77..dc8d2255 100644 --- a/MasterPassword/ObjC/Mac/MPMacAppDelegate.h +++ b/MasterPassword/ObjC/Mac/MPMacAppDelegate.h @@ -26,7 +26,6 @@ @property(nonatomic, weak) IBOutlet NSMenuItem *dialogStyleHUD; - (IBAction)showPasswordWindow; -- (IBAction)activate:(id)sender; - (IBAction)togglePreference:(NSMenuItem *)sender; - (IBAction)newUser:(NSMenuItem *)sender; - (IBAction)lock:(id)sender; diff --git a/MasterPassword/ObjC/Mac/MPMacAppDelegate.m b/MasterPassword/ObjC/Mac/MPMacAppDelegate.m index 8458787b..56889e41 100644 --- a/MasterPassword/ObjC/Mac/MPMacAppDelegate.m +++ b/MasterPassword/ObjC/Mac/MPMacAppDelegate.m @@ -119,18 +119,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven [self.statusItem popUpStatusItemMenu:self.statusMenu]; } -- (IBAction)activate:(id)sender { - - if (![self activeUserForThread]) - // No user, can't activate. - return; - - if ([[NSApplication sharedApplication] isActive]) - [self applicationDidBecomeActive:nil]; - else - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; -} - - (IBAction)togglePreference:(NSMenuItem *)sender { if (sender == self.useICloudItem) @@ -227,12 +215,12 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven self.statusItem.target = self; self.statusItem.action = @selector(showMenu); - [[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock: + [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock: ^(NSNotification *note) { [self updateUsers]; }]; [[NSNotificationCenter defaultCenter] - addObserverForName:UbiquityManagedStoreDidImportChangesNotification object:nil queue:nil usingBlock: + addObserverForName:USMStoreDidImportChangesNotification object:nil queue:nil usingBlock: ^(NSNotification *note) { [self updateUsers]; }]; @@ -359,6 +347,14 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven - (IBAction)showPasswordWindow { + // If no user, can't activate. + if (![self activeUserForThread]) + return; + + // Activate the app if not active. + if (![[NSApplication sharedApplication] isActive]) + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; + // Don't show window if we weren't already running (ie. if we haven't been activated before). if (!self.passwordWindow) self.passwordWindow = [[MPPasswordWindowController alloc] initWithWindowNibName:@"MPPasswordWindowController"]; diff --git a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m index 613498ce..fba82d9f 100644 --- a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m +++ b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m @@ -69,7 +69,7 @@ [self.window close]; }]; [[NSNotificationCenter defaultCenter] - addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) { + addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) { [self waitUntilStoreLoaded]; }]; diff --git a/MasterPassword/ObjC/iOS/MPElementListController.m b/MasterPassword/ObjC/iOS/MPElementListController.m index 61333779..aa9a8b5a 100644 --- a/MasterPassword/ObjC/iOS/MPElementListController.m +++ b/MasterPassword/ObjC/iOS/MPElementListController.m @@ -15,7 +15,7 @@ - (void)viewDidLoad { - [[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock: + [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock: ^(NSNotification *note) { [self updateData]; }]; diff --git a/MasterPassword/ObjC/iOS/MPMainViewController.m b/MasterPassword/ObjC/iOS/MPMainViewController.m index a3ddcc23..a08ae4d1 100644 --- a/MasterPassword/ObjC/iOS/MPMainViewController.m +++ b/MasterPassword/ObjC/iOS/MPMainViewController.m @@ -107,7 +107,7 @@ [self.navigationController popToRootViewControllerAnimated:animated]; }]; }]; - [[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock: + [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock: ^(NSNotification *note) { if (!self.activeElementForThread) [self didSelectElement:nil]; diff --git a/MasterPassword/ObjC/iOS/MPUnlockViewController.m b/MasterPassword/ObjC/iOS/MPUnlockViewController.m index 18dde9c6..06509e4d 100644 --- a/MasterPassword/ObjC/iOS/MPUnlockViewController.m +++ b/MasterPassword/ObjC/iOS/MPUnlockViewController.m @@ -164,11 +164,11 @@ [self initializeWordLabel:wordLabel]; } recurse:NO]; - [[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock: + [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock: ^(NSNotification *note) { [self updateUsers]; }]; - [[NSNotificationCenter defaultCenter] addObserverForName:UbiquityManagedStoreDidImportChangesNotification object:nil queue:nil + [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidImportChangesNotification object:nil queue:nil usingBlock:^(NSNotification *note) { [self updateUsers]; }]; diff --git a/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m b/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m index 50fffc09..09477a9d 100644 --- a/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m +++ b/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m @@ -12,6 +12,13 @@ #import "IASKSettingsReader.h" #import "GPPSignIn.h" +@interface MPiOSAppDelegate() + +@property(nonatomic, strong) PearlAlert *handleCloudContentAlert; +@property(nonatomic, strong) PearlAlert *fixCloudContentAlert; +@property(nonatomic, strong) PearlOverlay *storeLoading; +@end + @implementation MPiOSAppDelegate + (void)initialize { @@ -630,6 +637,67 @@ } +#pragma mark - Google+ +- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager willLoadStoreIsCloud:(BOOL)isCloudStore { + + dispatch_async( dispatch_get_main_queue(), ^{ + [self.handleCloudContentAlert cancelAlertAnimated:YES]; + if (![self.storeLoading isVisible]) + self.storeLoading = [PearlOverlay showOverlayWithTitle:@"Opening Your Data"]; + } ); + + [super ubiquityStoreManager:manager willLoadStoreIsCloud:isCloudStore]; +} + +- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didLoadStoreForCoordinator:(NSPersistentStoreCoordinator *)coordinator + isCloud:(BOOL)isCloudStore { + + [super ubiquityStoreManager:manager didLoadStoreForCoordinator:coordinator isCloud:isCloudStore]; + + dispatch_async( dispatch_get_main_queue(), ^{ + [self.handleCloudContentAlert cancelAlertAnimated:YES]; + [self.fixCloudContentAlert cancelAlertAnimated:YES]; + [self.storeLoading cancelOverlayAnimated:YES]; + } ); +} + +- (BOOL)ubiquityStoreManager:(UbiquityStoreManager *)manager handleCloudContentCorruptionWithHealthyStore:(BOOL)storeHealthy { + + if (manager.cloudEnabled && !storeHealthy && !([self.handleCloudContentAlert.alertView isVisible] || [self.fixCloudContentAlert.alertView isVisible])) + dispatch_async( dispatch_get_main_queue(), ^{ + [self.storeLoading cancelOverlayAnimated:YES]; + [self showCloudContentAlert]; + } ); + + return NO; +} + +- (void)showCloudContentAlert { + + __weak MPiOSAppDelegate *wSelf = self; + [self.handleCloudContentAlert cancelAlertAnimated:NO]; + self.handleCloudContentAlert = [PearlAlert showActivityWithTitle:@"iCloud Sync Problem" message: + @"Waiting for your other device to auto‑correct the problem..." + initAlert:^(UIAlertView *alert) { + [alert addButtonWithTitle:@"Fix Now"]; + }]; + + self.handleCloudContentAlert.tappedButtonBlock = ^(UIAlertView *alert, NSInteger buttonIndex) { + wSelf.fixCloudContentAlert = [PearlAlert showAlertWithTitle:@"Fix iCloud Now" message: + @"This problem can usually 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." + viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock: + ^(UIAlertView *alert_, NSInteger buttonIndex_) { + if (buttonIndex_ == alert_.cancelButtonIndex) + [wSelf showCloudContentAlert]; + if (buttonIndex_ == [alert_ firstOtherButtonIndex]) + [wSelf.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:YES]; + } + cancelTitle:[PearlStrings get].commonButtonBack otherTitles:@"Fix Anyway", nil]; + }; +} + + #pragma mark - Google+ - (NSDictionary *)googlePlusInfo {