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 {