Some usability improvements + apptentive fixes.
[IMPROVED]  Make persistence more lazy to avoid UI blocks.
[IMPROVED]  Use "Master Password" as CFBundleDisplayName at runtime.  No
            home-screen length restrictions there.
[FIXED]     Inform Apptentive of significant events.
			
			
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@@ -6,7 +6,7 @@
 | 
			
		||||
	url = git://github.com/futuretap/InAppSettingsKit.git
 | 
			
		||||
[submodule "External/iCloudStoreManager"]
 | 
			
		||||
	path = External/iCloudStoreManager
 | 
			
		||||
	url = git://github.com/alekseyn/iCloudStoreManager.git
 | 
			
		||||
	url = git://github.com/lhunath/iCloudStoreManager.git
 | 
			
		||||
[submodule "External/apptentive"]
 | 
			
		||||
	path = External/apptentive
 | 
			
		||||
	url = git://github.com/apptentive/apptentive-ios.git
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								External/Pearl
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								External/Pearl
									
									
									
									
										vendored
									
									
								
							 Submodule External/Pearl updated: f92b0b1490...046dba1558
									
								
							
							
								
								
									
										2
									
								
								External/iCloudStoreManager
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								External/iCloudStoreManager
									
									
									
									
										vendored
									
									
								
							 Submodule External/iCloudStoreManager updated: 6c19d5aa27...84c718a57d
									
								
							@@ -18,6 +18,13 @@
 | 
			
		||||
		DA0A1D1215690AD40092735D /* tip_arrow_wood.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D0C15690AD40092735D /* tip_arrow_wood.png */; };
 | 
			
		||||
		DA0A1D1515690AF40092735D /* Icon-72@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D1315690AF30092735D /* Icon-72@2x.png */; };
 | 
			
		||||
		DA0A1D1615690AF40092735D /* Icon-Small-50@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D1415690AF40092735D /* Icon-Small-50@2x.png */; };
 | 
			
		||||
		DA30E9CE15722ECA00A68B4C /* NSBundle_PearlMutableInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9CB15722ECA00A68B4C /* NSBundle_PearlMutableInfo.h */; };
 | 
			
		||||
		DA30E9CF15722ECA00A68B4C /* NSBundle_PearlMutableInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CC15722ECA00A68B4C /* NSBundle_PearlMutableInfo.m */; };
 | 
			
		||||
		DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
 | 
			
		||||
		DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */; };
 | 
			
		||||
		DA30E9D415722EF400A68B4C /* Pearl-UIKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9D315722EF400A68B4C /* Pearl-UIKit.m */; };
 | 
			
		||||
		DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9D515723E6900A68B4C /* PearlLazy.h */; };
 | 
			
		||||
		DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9D615723E6900A68B4C /* PearlLazy.m */; };
 | 
			
		||||
		DA4425CC1557BED40052177D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
 | 
			
		||||
		DA4426001557BF260052177D /* UbiquityStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DA4425F11557BF260052177D /* UbiquityStoreManager.h */; };
 | 
			
		||||
		DA4426011557BF260052177D /* UbiquityStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4425F21557BF260052177D /* UbiquityStoreManager.m */; };
 | 
			
		||||
@@ -925,6 +932,13 @@
 | 
			
		||||
		DA0A1D0C15690AD40092735D /* tip_arrow_wood.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = tip_arrow_wood.png; path = Resources/Tooltips/tip_arrow_wood.png; sourceTree = SOURCE_ROOT; };
 | 
			
		||||
		DA0A1D1315690AF30092735D /* Icon-72@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-72@2x.png"; sourceTree = "<group>"; };
 | 
			
		||||
		DA0A1D1415690AF40092735D /* Icon-Small-50@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-50@2x.png"; sourceTree = "<group>"; };
 | 
			
		||||
		DA30E9CB15722ECA00A68B4C /* NSBundle_PearlMutableInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSBundle_PearlMutableInfo.h; sourceTree = "<group>"; };
 | 
			
		||||
		DA30E9CC15722ECA00A68B4C /* NSBundle_PearlMutableInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBundle_PearlMutableInfo.m; sourceTree = "<group>"; };
 | 
			
		||||
		DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; };
 | 
			
		||||
		DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Pearl-Crypto.m"; sourceTree = "<group>"; };
 | 
			
		||||
		DA30E9D315722EF400A68B4C /* Pearl-UIKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Pearl-UIKit.m"; sourceTree = "<group>"; };
 | 
			
		||||
		DA30E9D515723E6900A68B4C /* PearlLazy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLazy.h; sourceTree = "<group>"; };
 | 
			
		||||
		DA30E9D615723E6900A68B4C /* PearlLazy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlLazy.m; sourceTree = "<group>"; };
 | 
			
		||||
		DA4425CB1557BED40052177D /* libiCloudStoreManager.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libiCloudStoreManager.a; sourceTree = BUILT_PRODUCTS_DIR; };
 | 
			
		||||
		DA4425F11557BF260052177D /* UbiquityStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UbiquityStoreManager.h; sourceTree = "<group>"; };
 | 
			
		||||
		DA4425F21557BF260052177D /* UbiquityStoreManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UbiquityStoreManager.m; sourceTree = "<group>"; };
 | 
			
		||||
@@ -2892,6 +2906,8 @@
 | 
			
		||||
		DAFE45D715039823003ABA7C /* Pearl */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				DA30E9CB15722ECA00A68B4C /* NSBundle_PearlMutableInfo.h */,
 | 
			
		||||
				DA30E9CC15722ECA00A68B4C /* NSBundle_PearlMutableInfo.m */,
 | 
			
		||||
				DAFE45D815039823003ABA7C /* NSObject_PearlExport.h */,
 | 
			
		||||
				DAFE45D915039823003ABA7C /* NSObject_PearlExport.m */,
 | 
			
		||||
				DAFE45DA15039823003ABA7C /* NSString_PearlNSArrayFormat.h */,
 | 
			
		||||
@@ -2899,6 +2915,7 @@
 | 
			
		||||
				DAFE45DC15039823003ABA7C /* NSString_PearlSEL.h */,
 | 
			
		||||
				DAFE45DD15039823003ABA7C /* NSString_PearlSEL.m */,
 | 
			
		||||
				DAFE45DE15039823003ABA7C /* Pearl.h */,
 | 
			
		||||
				DA30E9CD15722ECA00A68B4C /* Pearl.m */,
 | 
			
		||||
				DAFE45DF15039823003ABA7C /* PearlAbstractStrings.h */,
 | 
			
		||||
				DAFE45E015039823003ABA7C /* PearlAbstractStrings.m */,
 | 
			
		||||
				DAFE45E315039823003ABA7C /* PearlCodeUtils.h */,
 | 
			
		||||
@@ -2909,6 +2926,8 @@
 | 
			
		||||
				DAFE45E815039823003ABA7C /* PearlDeviceUtils.m */,
 | 
			
		||||
				DAFE45E915039823003ABA7C /* PearlInfoPlist.h */,
 | 
			
		||||
				DAFE45EA15039823003ABA7C /* PearlInfoPlist.m */,
 | 
			
		||||
				DA30E9D515723E6900A68B4C /* PearlLazy.h */,
 | 
			
		||||
				DA30E9D615723E6900A68B4C /* PearlLazy.m */,
 | 
			
		||||
				DAFE45EB15039823003ABA7C /* PearlLogger.h */,
 | 
			
		||||
				DAFE45EC15039823003ABA7C /* PearlLogger.m */,
 | 
			
		||||
				DAFE45ED15039823003ABA7C /* PearlMathUtils.h */,
 | 
			
		||||
@@ -2940,6 +2959,7 @@
 | 
			
		||||
			children = (
 | 
			
		||||
				DA79A9BB1557DB6F00BAA07A /* libscryptenc-ios.a */,
 | 
			
		||||
				DAFE45FD15039823003ABA7C /* Pearl-Crypto.h */,
 | 
			
		||||
				DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */,
 | 
			
		||||
				DAFE45FE15039823003ABA7C /* PearlCryptUtils.h */,
 | 
			
		||||
				DAFE45FF15039823003ABA7C /* PearlCryptUtils.m */,
 | 
			
		||||
				DAFE460015039823003ABA7C /* PearlKeyChain.h */,
 | 
			
		||||
@@ -2959,6 +2979,7 @@
 | 
			
		||||
			children = (
 | 
			
		||||
				DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */,
 | 
			
		||||
				DAFE460915039823003ABA7C /* Pearl-UIKit.h */,
 | 
			
		||||
				DA30E9D315722EF400A68B4C /* Pearl-UIKit.m */,
 | 
			
		||||
				DAFE460A15039823003ABA7C /* PearlAlert.h */,
 | 
			
		||||
				DAFE460B15039823003ABA7C /* PearlAlert.m */,
 | 
			
		||||
				DAFE4A60150399FF003ABA7C /* PearlAppDelegate.m */,
 | 
			
		||||
@@ -3094,6 +3115,8 @@
 | 
			
		||||
				DAFE4A5615039824003ABA7C /* PearlWebViewController.h in Headers */,
 | 
			
		||||
				DAFE4A5815039824003ABA7C /* UIImage_PearlScaling.h in Headers */,
 | 
			
		||||
				DAFE4A63150399FF003ABA7C /* PearlAppDelegate.h in Headers */,
 | 
			
		||||
				DA30E9CE15722ECA00A68B4C /* NSBundle_PearlMutableInfo.h in Headers */,
 | 
			
		||||
				DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */,
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
		};
 | 
			
		||||
@@ -4141,6 +4164,11 @@
 | 
			
		||||
				DAFE4A5715039824003ABA7C /* PearlWebViewController.m in Sources */,
 | 
			
		||||
				DAFE4A5915039824003ABA7C /* UIImage_PearlScaling.m in Sources */,
 | 
			
		||||
				DAFE4A62150399FF003ABA7C /* PearlAppDelegate.m in Sources */,
 | 
			
		||||
				DA30E9CF15722ECA00A68B4C /* NSBundle_PearlMutableInfo.m in Sources */,
 | 
			
		||||
				DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */,
 | 
			
		||||
				DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */,
 | 
			
		||||
				DA30E9D415722EF400A68B4C /* Pearl-UIKit.m in Sources */,
 | 
			
		||||
				DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */,
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -63,14 +63,23 @@
 | 
			
		||||
      shouldUseLaunchSchemeArgsEnv = "YES"
 | 
			
		||||
      savedToolIdentifier = ""
 | 
			
		||||
      useCustomWorkingDirectory = "NO"
 | 
			
		||||
      buildConfiguration = "Production"
 | 
			
		||||
      buildConfiguration = "AppStore"
 | 
			
		||||
      debugDocumentVersioning = "YES">
 | 
			
		||||
      <BuildableProductRunnable>
 | 
			
		||||
         <BuildableReference
 | 
			
		||||
            BuildableIdentifier = "primary"
 | 
			
		||||
            BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
 | 
			
		||||
            BuildableName = "MasterPassword.app"
 | 
			
		||||
            BlueprintName = "MasterPassword"
 | 
			
		||||
            ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
 | 
			
		||||
         </BuildableReference>
 | 
			
		||||
      </BuildableProductRunnable>
 | 
			
		||||
   </ProfileAction>
 | 
			
		||||
   <AnalyzeAction
 | 
			
		||||
      buildConfiguration = "Debug">
 | 
			
		||||
   </AnalyzeAction>
 | 
			
		||||
   <ArchiveAction
 | 
			
		||||
      buildConfiguration = "Production"
 | 
			
		||||
      buildConfiguration = "AppStore"
 | 
			
		||||
      revealArchiveInOrganizer = "YES">
 | 
			
		||||
   </ArchiveAction>
 | 
			
		||||
</Scheme>
 | 
			
		||||
 
 | 
			
		||||
@@ -42,28 +42,37 @@ static NSDateFormatter *rfc3339DateFormatter = nil;
 | 
			
		||||
    if (managedObjectContext)
 | 
			
		||||
        return managedObjectContext;
 | 
			
		||||
    
 | 
			
		||||
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
 | 
			
		||||
    assert(coordinator);
 | 
			
		||||
    return [PearlLazy lazyObjectLoadedFrom:^id{
 | 
			
		||||
        NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
 | 
			
		||||
        assert(coordinator);
 | 
			
		||||
        
 | 
			
		||||
    managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
 | 
			
		||||
    [managedObjectContext performBlockAndWait:^{
 | 
			
		||||
        managedObjectContext.persistentStoreCoordinator = coordinator;
 | 
			
		||||
        managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
 | 
			
		||||
        managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
 | 
			
		||||
        [managedObjectContext performBlockAndWait:^{
 | 
			
		||||
            managedObjectContext.persistentStoreCoordinator = coordinator;
 | 
			
		||||
            managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
 | 
			
		||||
        }];
 | 
			
		||||
        
 | 
			
		||||
        return managedObjectContext;
 | 
			
		||||
    }];
 | 
			
		||||
    
 | 
			
		||||
    return managedObjectContext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
 | 
			
		||||
 | 
			
		||||
    // Wait until the storeManager is ready.
 | 
			
		||||
    for(__block BOOL isReady = [self storeManager].isReady; !isReady;)
 | 
			
		||||
        dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
 | 
			
		||||
            isReady = [self storeManager].isReady;
 | 
			
		||||
        });
 | 
			
		||||
    // Start loading the store.
 | 
			
		||||
    [self storeManager];
 | 
			
		||||
    
 | 
			
		||||
    assert([self storeManager].isReady);
 | 
			
		||||
    return [self storeManager].persistentStoreCoordinator;
 | 
			
		||||
    return [PearlLazy lazyObjectLoadedFrom:^id{
 | 
			
		||||
        // Wait until the storeManager is ready.
 | 
			
		||||
        for(__block BOOL isReady = [self storeManager].isReady; !isReady;) {
 | 
			
		||||
            [NSThread sleepForTimeInterval:0.1];
 | 
			
		||||
            dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
 | 
			
		||||
                isReady = [self storeManager].isReady;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        assert([self storeManager].isReady);
 | 
			
		||||
        return [self storeManager].persistentStoreCoordinator;
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (UbiquityStoreManager *)storeManager {
 | 
			
		||||
 
 | 
			
		||||
@@ -148,6 +148,8 @@
 | 
			
		||||
 | 
			
		||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 | 
			
		||||
    
 | 
			
		||||
    [[[NSBundle mainBundle] mutableLocalizedInfoDictionary] setObject:@"Master Password" forKey:@"CFBundleDisplayName"];
 | 
			
		||||
    
 | 
			
		||||
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
 | 
			
		||||
#ifndef DEBUG
 | 
			
		||||
        @try {
 | 
			
		||||
@@ -212,9 +214,28 @@
 | 
			
		||||
        NSString *apptentiveAPIKey = [self apptentiveAPIKey];
 | 
			
		||||
        if ([apptentiveAPIKey length]) {
 | 
			
		||||
            dbg(@"Initializing Apptentive");
 | 
			
		||||
            
 | 
			
		||||
            ATConnect *connection = [ATConnect sharedConnection];
 | 
			
		||||
            connection.shouldTakeScreenshot = NO;
 | 
			
		||||
            connection.apiKey = apptentiveAPIKey;
 | 
			
		||||
            [connection setApiKey:apptentiveAPIKey];
 | 
			
		||||
            [connection setShouldTakeScreenshot:NO];
 | 
			
		||||
            [connection addAdditionalInfoToFeedback:[PearlInfoPlist get].CFBundleVersion withKey:@"CFBundleVersion"];
 | 
			
		||||
 | 
			
		||||
            ATAppRatingFlow *ratingsFlow = [ATAppRatingFlow sharedRatingFlowWithAppID:[PearlConfig get].iTunesID];
 | 
			
		||||
            [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification object:nil queue:nil
 | 
			
		||||
                                                          usingBlock:^(NSNotification *note) {
 | 
			
		||||
                                                              dispatch_async(dispatch_get_main_queue(), ^{
 | 
			
		||||
                                                                  [ratingsFlow appDidEnterForeground:YES
 | 
			
		||||
                                                                                      viewController:self.navigationController];
 | 
			
		||||
                                                              });
 | 
			
		||||
                                                          }];
 | 
			
		||||
            [[NSNotificationCenter defaultCenter] addObserverForName:MPNotificationKeySet object:nil queue:nil
 | 
			
		||||
                                                          usingBlock:^(NSNotification *note) {
 | 
			
		||||
                                                              dispatch_async(dispatch_get_main_queue(), ^{
 | 
			
		||||
                                                                  [ratingsFlow userDidPerformSignificantEvent:YES
 | 
			
		||||
                                                                                               viewController:self.navigationController];
 | 
			
		||||
                                                              });
 | 
			
		||||
                                                          }];
 | 
			
		||||
            [ratingsFlow appDidLaunch:YES viewController:self.navigationController];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    @catch (NSException *exception) {
 | 
			
		||||
@@ -288,14 +309,6 @@
 | 
			
		||||
     @"https://youtrack.lyndir.com\n"
 | 
			
		||||
                         viewStyle:UIAlertViewStyleDefault tappedButtonBlock:nil
 | 
			
		||||
                       cancelTitle:nil otherTitles:[PearlStrings get].commonButtonOkay, nil];
 | 
			
		||||
#else
 | 
			
		||||
    @try {
 | 
			
		||||
        ATAppRatingFlow *sharedFlow = [ATAppRatingFlow sharedRatingFlowWithAppID:[PearlConfig get].iTunesID];
 | 
			
		||||
        [sharedFlow appDidLaunch:YES viewController:self.navigationController];
 | 
			
		||||
    }
 | 
			
		||||
    @catch (NSException *exception) {
 | 
			
		||||
        err(@"Apptentive: %@", exception);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    
 | 
			
		||||
    [[UIApplication sharedApplication] setStatusBarHidden:NO
 | 
			
		||||
@@ -378,9 +391,6 @@
 | 
			
		||||
    
 | 
			
		||||
    [TestFlight passCheckpoint:MPTestFlightCheckpointActivated];
 | 
			
		||||
    
 | 
			
		||||
    ATAppRatingFlow *sharedFlow = [ATAppRatingFlow sharedRatingFlowWithAppID:[PearlConfig get].iTunesID];
 | 
			
		||||
    [sharedFlow appDidEnterForeground:YES viewController:self.navigationController];
 | 
			
		||||
    
 | 
			
		||||
    [super applicationDidBecomeActive:application];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -541,7 +551,7 @@
 | 
			
		||||
    static NSDictionary *apptentiveInfo = nil;
 | 
			
		||||
    if (apptentiveInfo == nil)
 | 
			
		||||
        apptentiveInfo = [[NSDictionary alloc] initWithContentsOfURL:
 | 
			
		||||
                           [[NSBundle mainBundle] URLForResource:@"Apptentive" withExtension:@"plist"]];
 | 
			
		||||
                          [[NSBundle mainBundle] URLForResource:@"Apptentive" withExtension:@"plist"]];
 | 
			
		||||
    
 | 
			
		||||
    return apptentiveInfo;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -146,8 +146,6 @@
 | 
			
		||||
 | 
			
		||||
- (void)updateAnimated:(BOOL)animated {
 | 
			
		||||
    
 | 
			
		||||
    [[MPAppDelegate get] saveContext];
 | 
			
		||||
    
 | 
			
		||||
    dispatch_async(dispatch_get_main_queue(), ^{
 | 
			
		||||
        if (animated)
 | 
			
		||||
            [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
@@ -352,6 +350,7 @@
 | 
			
		||||
    NSString *oldPassword = [self.activeElement.content description];
 | 
			
		||||
    task();
 | 
			
		||||
    NSString *newPassword = [self.activeElement.content description];
 | 
			
		||||
    [[MPAppDelegate get] saveContext];
 | 
			
		||||
    [self updateAnimated:YES];
 | 
			
		||||
    
 | 
			
		||||
    // Show new and old password.
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@
 | 
			
		||||
@interface MPSearchDelegate (Private)
 | 
			
		||||
 | 
			
		||||
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath;
 | 
			
		||||
- (void)update;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
@@ -38,10 +37,14 @@
 | 
			
		||||
    
 | 
			
		||||
    NSFetchRequest *fetchRequest    = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
 | 
			
		||||
    fetchRequest.sortDescriptors    = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses" ascending:NO]];
 | 
			
		||||
    self.fetchedResultsController   = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
 | 
			
		||||
                                                                          managedObjectContext:[MPAppDelegate managedObjectContext]
 | 
			
		||||
                                                                            sectionNameKeyPath:nil cacheName:nil];
 | 
			
		||||
    self.fetchedResultsController.delegate = self;
 | 
			
		||||
    self.fetchedResultsController   = [PearlLazy lazyObjectLoadedFrom:^id{
 | 
			
		||||
        NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
 | 
			
		||||
                                                                                     managedObjectContext:[MPAppDelegate managedObjectContext]
 | 
			
		||||
                                                                                       sectionNameKeyPath:nil cacheName:nil];
 | 
			
		||||
        controller.delegate = self;
 | 
			
		||||
        
 | 
			
		||||
        return controller;
 | 
			
		||||
    }];
 | 
			
		||||
    
 | 
			
		||||
    self.tipView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 170)];
 | 
			
		||||
    self.tipView.textAlignment = UITextAlignmentCenter;
 | 
			
		||||
@@ -123,12 +126,8 @@
 | 
			
		||||
 | 
			
		||||
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
 | 
			
		||||
    
 | 
			
		||||
    [self update];
 | 
			
		||||
    
 | 
			
		||||
    return NO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)update {
 | 
			
		||||
    if (!controller.active)
 | 
			
		||||
        return NO;
 | 
			
		||||
    
 | 
			
		||||
    assert(self.query);
 | 
			
		||||
    
 | 
			
		||||
@@ -138,7 +137,6 @@
 | 
			
		||||
    NSError *error;
 | 
			
		||||
    if (![self.fetchedResultsController performFetch:&error])
 | 
			
		||||
        err(@"Couldn't fetch elements: %@", error);
 | 
			
		||||
    [self.searchDisplayController.searchResultsTableView reloadData];
 | 
			
		||||
    
 | 
			
		||||
    NSArray *subviews = self.searchDisplayController.searchBar.superview.subviews;
 | 
			
		||||
    NSUInteger overlayIndex = [subviews indexOfObject:self.searchDisplayController.searchBar] + 1;
 | 
			
		||||
@@ -149,6 +147,8 @@
 | 
			
		||||
        [self.tipView removeFromSuperview];
 | 
			
		||||
        [overlay addSubview:self.tipView];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// See MP-14, also crashes easily on internal assertions etc..
 | 
			
		||||
 
 | 
			
		||||
@@ -152,73 +152,69 @@ typedef enum {
 | 
			
		||||
 | 
			
		||||
- (void)textFieldDidEndEditing:(UITextField *)textField {
 | 
			
		||||
    
 | 
			
		||||
    CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
 | 
			
		||||
    rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
 | 
			
		||||
    rotate.fromValue = [NSNumber numberWithFloat:0];
 | 
			
		||||
    rotate.toValue = [NSNumber numberWithFloat:2 * M_PI];
 | 
			
		||||
    rotate.repeatCount = MAXFLOAT;
 | 
			
		||||
    rotate.duration = 3.0;
 | 
			
		||||
    
 | 
			
		||||
    [self.spinner.layer removeAllAnimations];
 | 
			
		||||
    [self.spinner.layer addAnimation:rotate forKey:@"transform"];
 | 
			
		||||
    
 | 
			
		||||
    [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
        self.spinner.alpha = 1.0f;
 | 
			
		||||
    }];
 | 
			
		||||
    
 | 
			
		||||
    [self showMessage:@"Checking password..." state:MPLockscreenProgress];
 | 
			
		||||
    
 | 
			
		||||
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
 | 
			
		||||
        @try {
 | 
			
		||||
            dispatch_async(dispatch_get_main_queue(), ^{
 | 
			
		||||
                CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
 | 
			
		||||
                rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
 | 
			
		||||
                rotate.fromValue = [NSNumber numberWithFloat:0];
 | 
			
		||||
                rotate.toValue = [NSNumber numberWithFloat:2 * M_PI];
 | 
			
		||||
                rotate.repeatCount = MAXFLOAT;
 | 
			
		||||
                rotate.duration = 3.0;
 | 
			
		||||
        BOOL unlocked = [[MPAppDelegate get] tryMasterPassword:textField.text];
 | 
			
		||||
        dispatch_async(dispatch_get_main_queue(), ^{
 | 
			
		||||
            if (unlocked) {
 | 
			
		||||
                [self showMessage:@"Success!" state:MPLockscreenSuccess];
 | 
			
		||||
                
 | 
			
		||||
                [self.spinner.layer removeAllAnimations];
 | 
			
		||||
                [self.spinner.layer addAnimation:rotate forKey:@"transform"];
 | 
			
		||||
                
 | 
			
		||||
                [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
                    self.spinner.alpha = 1.0f;
 | 
			
		||||
                }];
 | 
			
		||||
                
 | 
			
		||||
                [self showMessage:@"Checking password..." state:MPLockscreenProgress];
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            if ([[MPAppDelegate get] tryMasterPassword:textField.text])
 | 
			
		||||
                dispatch_async(dispatch_get_main_queue(), ^{
 | 
			
		||||
                    [self showMessage:@"Success!" state:MPLockscreenSuccess];
 | 
			
		||||
                    
 | 
			
		||||
                    NSFetchRequest *fetchRequest    = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
 | 
			
		||||
                    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"keyID == %@", [MPAppDelegate get].keyID];
 | 
			
		||||
                    fetchRequest.fetchLimit = 1;
 | 
			
		||||
                    BOOL keyIDHasElements = [[[MPAppDelegate managedObjectContext] executeFetchRequest:fetchRequest error:nil] count] > 0;
 | 
			
		||||
                    if (keyIDHasElements)
 | 
			
		||||
                        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (long)(NSEC_PER_SEC * 1.5f)), dispatch_get_main_queue(), ^{
 | 
			
		||||
                            [self dismissModalViewControllerAnimated:YES];
 | 
			
		||||
                        });
 | 
			
		||||
                    else {
 | 
			
		||||
                        [PearlAlert showAlertWithTitle:@"New Master Password"
 | 
			
		||||
                                               message:
 | 
			
		||||
                         @"Please confirm the spelling of this new master password."
 | 
			
		||||
                                             viewStyle:UIAlertViewStyleSecureTextInput
 | 
			
		||||
                                     tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                                         if (buttonIndex == [alert cancelButtonIndex]) {
 | 
			
		||||
                                             [[MPAppDelegate get] updateKey:nil];
 | 
			
		||||
                                             return;
 | 
			
		||||
                                         }
 | 
			
		||||
                                         if (![[alert textFieldAtIndex:0].text isEqualToString:textField.text]) {
 | 
			
		||||
                                             [PearlAlert showAlertWithTitle:@"Incorrect Master Password"
 | 
			
		||||
                                                                    message:
 | 
			
		||||
                                              @"The password you entered doesn't match with the master password you tried to use.  "
 | 
			
		||||
                                              @"You've probably mistyped one of them.\n\n"
 | 
			
		||||
                                              @"Give it another try."
 | 
			
		||||
                                                                  viewStyle:UIAlertViewStyleDefault tappedButtonBlock:nil
 | 
			
		||||
                                                                cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil];
 | 
			
		||||
                                             return;
 | 
			
		||||
                                         }
 | 
			
		||||
                                         [self dismissModalViewControllerAnimated:YES];
 | 
			
		||||
                NSFetchRequest *fetchRequest    = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
 | 
			
		||||
                fetchRequest.predicate = [NSPredicate predicateWithFormat:@"keyID == %@", [MPAppDelegate get].keyID];
 | 
			
		||||
                fetchRequest.fetchLimit = 1;
 | 
			
		||||
                BOOL keyIDHasElements = [[[MPAppDelegate managedObjectContext] executeFetchRequest:fetchRequest error:nil] count] > 0;
 | 
			
		||||
                if (keyIDHasElements)
 | 
			
		||||
                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (long)(NSEC_PER_SEC * 1.5f)), dispatch_get_main_queue(), ^{
 | 
			
		||||
                        [self dismissModalViewControllerAnimated:YES];
 | 
			
		||||
                    });
 | 
			
		||||
                else {
 | 
			
		||||
                    [PearlAlert showAlertWithTitle:@"New Master Password"
 | 
			
		||||
                                           message:
 | 
			
		||||
                     @"Please confirm the spelling of this new master password."
 | 
			
		||||
                                         viewStyle:UIAlertViewStyleSecureTextInput
 | 
			
		||||
                                 tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                                     if (buttonIndex == [alert cancelButtonIndex]) {
 | 
			
		||||
                                         [[MPAppDelegate get] updateKey:nil];
 | 
			
		||||
                                         return;
 | 
			
		||||
                                     }
 | 
			
		||||
                                           cancelTitle:[PearlStrings get].commonButtonCancel
 | 
			
		||||
                                           otherTitles:[PearlStrings get].commonButtonContinue, nil];
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            else
 | 
			
		||||
                dispatch_async(dispatch_get_main_queue(), ^{
 | 
			
		||||
                    [self showMessage:@"Not valid." state:MPLockscreenError];
 | 
			
		||||
                    [UIView animateWithDuration:0.5f animations:^{
 | 
			
		||||
                        self.changeMPView.alpha = 1.0f;
 | 
			
		||||
                    }];
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
        @finally {
 | 
			
		||||
                                     if (![[alert textFieldAtIndex:0].text isEqualToString:textField.text]) {
 | 
			
		||||
                                         [PearlAlert showAlertWithTitle:@"Incorrect Master Password"
 | 
			
		||||
                                                                message:
 | 
			
		||||
                                          @"The password you entered doesn't match with the master password you tried to use.  "
 | 
			
		||||
                                          @"You've probably mistyped one of them.\n\n"
 | 
			
		||||
                                          @"Give it another try."
 | 
			
		||||
                                                              viewStyle:UIAlertViewStyleDefault tappedButtonBlock:nil
 | 
			
		||||
                                                            cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil];
 | 
			
		||||
                                         return;
 | 
			
		||||
                                     }
 | 
			
		||||
                                     [self dismissModalViewControllerAnimated:YES];
 | 
			
		||||
                                 }
 | 
			
		||||
                                       cancelTitle:[PearlStrings get].commonButtonCancel
 | 
			
		||||
                                       otherTitles:[PearlStrings get].commonButtonContinue, nil];
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                [self showMessage:@"Not valid." state:MPLockscreenError];
 | 
			
		||||
                
 | 
			
		||||
                [UIView animateWithDuration:0.5f animations:^{
 | 
			
		||||
                    self.changeMPView.alpha = 1.0f;
 | 
			
		||||
                }];
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            dispatch_async(dispatch_get_main_queue(), ^{
 | 
			
		||||
                [UIView animateWithDuration:0.3f animations:^{
 | 
			
		||||
                    self.spinner.alpha = 0.0f;
 | 
			
		||||
@@ -226,7 +222,7 @@ typedef enum {
 | 
			
		||||
                    [self.spinner.layer removeAllAnimations];
 | 
			
		||||
                }];
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								Site/1/img/SolvingThePasswordProblem.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Site/1/img/SolvingThePasswordProblem.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 376 KiB  | 
		Reference in New Issue
	
	Block a user