diff --git a/External/Pearl b/External/Pearl index d8c2fa37..99c73fd3 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit d8c2fa3755d1f440cd5eaa980adffef08a805b25 +Subproject commit 99c73fd3b37b4d2621548f5ae366c163231a346d diff --git a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m index 0197707f..0ee06814 100644 --- a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m +++ b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m @@ -46,7 +46,7 @@ informativeTextWithFormat:@"Certain sites require explicit migration to get updated to the latest version of the " @"Master Password algorithm. For these sites, a migration button will appear. Migrating these sites will cause " @"their passwords to change. You'll need to update your profile for that site with the new password."]; - [activeUser saveContext]; + [moc saveToStore]; }]; } forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil]; [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window queue:nil diff --git a/MasterPassword/ObjC/iOS/MPAppDelegate.m b/MasterPassword/ObjC/iOS/MPAppDelegate.m index 316a11ba..bcb93102 100644 --- a/MasterPassword/ObjC/iOS/MPAppDelegate.m +++ b/MasterPassword/ObjC/iOS/MPAppDelegate.m @@ -260,8 +260,10 @@ inf(@"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier]); - if ([[MPiOSConfig get].showSetup boolValue]) - [[MPAppDelegate get] showSetup]; + dispatch_async(dispatch_get_main_queue(), ^{ + if ([[MPiOSConfig get].showSetup boolValue]) + [[MPAppDelegate get] showSetup]; + }); return YES; } @@ -592,21 +594,21 @@ if (buttonIndex == [alert cancelButtonIndex]) return; - [moc performBlock:^{ + [moc performBlockAndWait:^{ inf(@"Unsetting master password for: %@.", user.userID); user.keyID = nil; [self forgetSavedKeyFor:user]; [moc saveToStore]; + }]; - [self signOutAnimated:YES]; - if (didReset) - didReset(); + [self signOutAnimated:YES]; + if (didReset) + didReset(); #ifdef TESTFLIGHT_SDK_VERSION - [TestFlight passCheckpoint:MPCheckpointChangeMP]; + [TestFlight passCheckpoint:MPCheckpointChangeMP]; #endif - [[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointChangeMP attributes:nil]; - }]; + [[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointChangeMP attributes:nil]; } cancelTitle:[PearlStrings get].commonButtonAbort otherTitles:[PearlStrings get].commonButtonContinue, nil]; diff --git a/MasterPassword/ObjC/iOS/MPElementListController.m b/MasterPassword/ObjC/iOS/MPElementListController.m index b27c90a5..c34c8648 100644 --- a/MasterPassword/ObjC/iOS/MPElementListController.m +++ b/MasterPassword/ObjC/iOS/MPElementListController.m @@ -250,20 +250,23 @@ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { - if (editingStyle == UITableViewCellEditingStyleDelete) - [self.fetchedResultsController.managedObjectContext performBlock:^{ + if (editingStyle == UITableViewCellEditingStyleDelete) { + NSManagedObjectContext *moc = self.fetchedResultsController.managedObjectContext; + [moc performBlock:^{ MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath]; inf(@"Deleting element: %@", element.name); - [self.fetchedResultsController.managedObjectContext deleteObject:element]; + [moc deleteObject:element]; #ifdef TESTFLIGHT_SDK_VERSION [TestFlight passCheckpoint:MPCheckpointDeleteElement]; #endif [[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointDeleteElement attributes:@{ - @"type" : element.typeName, - @"version" : @(element.version)}]; + @"type" : element.typeName, + @"version" : @(element.version) + }]; }]; + } } @end diff --git a/MasterPassword/ObjC/iOS/MPGuideViewController.h b/MasterPassword/ObjC/iOS/MPGuideViewController.h index 9669ca5e..aeba3517 100644 --- a/MasterPassword/ObjC/iOS/MPGuideViewController.h +++ b/MasterPassword/ObjC/iOS/MPGuideViewController.h @@ -10,6 +10,25 @@ @interface MPGuideViewController : UIViewController +@property (weak, nonatomic) IBOutlet UIView *siteNameTip; +@property (weak, nonatomic) IBOutlet UIView *contentTip; +@property (weak, nonatomic) IBOutlet UILabel *contentTipText; +@property (weak, nonatomic) IBOutlet UIButton *usernameButton; +@property (weak, nonatomic) IBOutlet UIView *usernameTip; +@property (weak, nonatomic) IBOutlet UIButton *typeButton; +@property (weak, nonatomic) IBOutlet UIView *typeTip; +@property (weak, nonatomic) IBOutlet UIButton *toolButton; +@property (weak, nonatomic) IBOutlet UIView *toolTip; +@property (weak, nonatomic) IBOutlet UIProgressView *progress; +@property (weak, nonatomic) IBOutlet UIView *content; +@property (weak, nonatomic) IBOutlet UIButton *contentButton; +@property (weak, nonatomic) IBOutlet UITextField *contentText; +@property (weak, nonatomic) IBOutlet UIButton *volumeButton; +@property (weak, nonatomic) IBOutlet UIButton *largePlayButton; +@property (weak, nonatomic) IBOutlet UIButton *smallPlayButton; + +- (IBAction)play; - (IBAction)close; +- (IBAction)toggleVolume; @end diff --git a/MasterPassword/ObjC/iOS/MPGuideViewController.m b/MasterPassword/ObjC/iOS/MPGuideViewController.m index 119ab18e..9350f41e 100644 --- a/MasterPassword/ObjC/iOS/MPGuideViewController.m +++ b/MasterPassword/ObjC/iOS/MPGuideViewController.m @@ -8,23 +8,55 @@ #import "MPGuideViewController.h" +@interface MPGuideViewController() + +@property(nonatomic, strong) NSTimer *timer; +@property(nonatomic) int tickCount; +@property(nonatomic) int currentTick; +@property(nonatomic) int lastTick; +@property(nonatomic) BOOL muted; +@end @implementation MPGuideViewController - (BOOL)shouldAutorotate { - + return NO; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { - + return UIInterfaceOrientationPortrait; } +- (void)viewDidLoad { + + [super viewDidLoad]; + + self.tickCount = 30; +} + - (void)viewWillAppear:(BOOL)animated { inf(@"Guide will appear."); [super viewWillAppear:animated]; + + if (self.navigationController) { + // Via setup + [self.navigationController setNavigationBarHidden:YES animated:animated]; + self.smallPlayButton.hidden = YES; + self.siteNameTip.alpha = 0; + self.content.alpha = 0; + self.content.frame = CGRectSetHeight( self.content.frame, 180 ); + self.contentTip.alpha = 0; + self.usernameTip.alpha = 0; + self.typeTip.alpha = 0; + self.toolTip.alpha = 0; + } + else { + // Via segue + self.largePlayButton.hidden = YES; + } } - (void)viewDidAppear:(BOOL)animated { @@ -37,12 +69,139 @@ - (void)viewWillDisappear:(BOOL)animated { inf(@"Guide will disappear."); + [self.navigationController setNavigationBarHidden:NO animated:animated]; [super viewWillDisappear:animated]; } +- (IBAction)play { + + if (self.timer) { + // Pause + [self.timer invalidate]; + self.timer = nil; + + self.smallPlayButton.hidden = NO; + [self.smallPlayButton setImage:[UIImage imageNamed:@"icon_play"] forState:UIControlStateNormal]; + } + + else { + // Play + self.smallPlayButton.hidden = NO; + self.largePlayButton.hidden = YES; + [self.smallPlayButton setImage:[UIImage imageNamed:@"icon_pause"] forState:UIControlStateNormal]; + + self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(tick:) + userInfo:nil repeats:YES]; + } +} + - (IBAction)close { [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; } +- (IBAction)toggleVolume { + + if ((self.muted = !self.muted)) + [self.volumeButton setImage:[UIImage imageNamed:@"icon_volume-mute"] forState:UIControlStateNormal]; + else + [self.volumeButton setImage:[UIImage imageNamed:@"icon_volume-high"] forState:UIControlStateNormal]; +} + +- (void)tick:(NSTimer *)timer { + + self.lastTick = self.currentTick; + ++self.currentTick; + [self.progress setProgress:(float)self.currentTick / self.tickCount animated:YES]; + + if (self.currentTick < 5) { + [UIView animateWithDuration:0.5 animations:^{ + self.siteNameTip.alpha = 1; + self.content.alpha = 0; + self.content.frame = CGRectSetHeight( self.content.frame, 180 ); + self.contentTip.alpha = 0; + self.usernameTip.alpha = 0; + self.typeTip.alpha = 0; + self.toolTip.alpha = 0; + }]; + } + else if (self.currentTick < 10) { + [UIView animateWithDuration:0.5 animations:^{ + self.siteNameTip.alpha = 0; + self.content.alpha = 1; + self.contentTip.alpha = 1; + self.usernameTip.alpha = 0; + self.typeTip.alpha = 0; + self.toolTip.alpha = 0; + }]; + } + else if (self.currentTick < 15) { + [UIView animateWithDuration:0.5 animations:^{ + self.siteNameTip.alpha = 0; + self.content.alpha = 1; + self.contentTip.alpha = 1; + self.contentButton.highlighted = YES; + self.contentTipText.text = @"Tap to copy"; + self.usernameTip.alpha = 0; + self.typeTip.alpha = 0; + self.toolButton.highlighted = NO; + self.toolTip.alpha = 0; + }]; + } + else if (self.currentTick < 20) { + [UIView animateWithDuration:0.5 animations:^{ + self.siteNameTip.alpha = 0; + self.content.alpha = 1; + self.content.frame = CGRectSetHeight( self.content.frame, 231 ); + self.contentTip.alpha = 0; + self.contentButton.highlighted = NO; + self.contentTipText.text = @"Use this password"; + self.usernameButton.highlighted = YES; + self.usernameTip.alpha = 1; + self.typeTip.alpha = 0; + self.toolTip.alpha = 0; + }]; + } + else if (self.currentTick < 25) { + [UIView animateWithDuration:0.5 animations:^{ + self.siteNameTip.alpha = 0; + self.content.alpha = 1; + self.contentTip.alpha = 0; + self.usernameButton.highlighted = NO; + self.usernameTip.alpha = 0; + self.typeTip.alpha = 1; + self.typeButton.highlighted = YES; + self.toolTip.alpha = 0; + }]; + } + else if (self.currentTick < 30) { + [UIView animateWithDuration:0.5 animations:^{ + self.siteNameTip.alpha = 0; + self.content.alpha = 1; + self.contentTip.alpha = 0; + self.usernameTip.alpha = 0; + self.typeTip.alpha = 0; + self.typeButton.highlighted = NO; + self.toolButton.highlighted = YES; + self.toolTip.alpha = 1; + self.contentText.text = @"XupuMajf4'Hafh"; + }]; + } + else if (self.currentTick <= self.tickCount) { + [self.timer invalidate]; + self.timer = nil; + self.currentTick = 0; + [UIView animateWithDuration:0.5 animations:^{ + [self.smallPlayButton setImage:[UIImage imageNamed:@"icon_play"] forState:UIControlStateNormal]; + self.siteNameTip.alpha = 1; + self.content.alpha = 1; + self.contentTip.alpha = 1; + self.usernameTip.alpha = 1; + self.typeTip.alpha = 1; + self.toolButton.highlighted = NO; + self.toolTip.alpha = 0; + }]; + } +} + @end diff --git a/MasterPassword/ObjC/iOS/MPMainViewController.m b/MasterPassword/ObjC/iOS/MPMainViewController.m index da800ee2..aa9949a5 100644 --- a/MasterPassword/ObjC/iOS/MPMainViewController.m +++ b/MasterPassword/ObjC/iOS/MPMainViewController.m @@ -590,34 +590,28 @@ // Update element, keeping track of the old password. [self activeElementDo:^(MPElementEntity *activeElement) { - NSManagedObjectContext *moc = activeElement.managedObjectContext; - [moc performBlock:^{ + // Perform the task. + NSString *oldPassword = [activeElement.content description]; + if (!task( activeElement )) + return; + NSString *newPassword = [activeElement.content description]; - // Perform the task. - NSString *oldPassword = [activeElement.content description]; - if (!task(activeElement)) - return; - NSString *newPassword = [activeElement.content description]; + // Save. + [activeElement.managedObjectContext saveToStore]; - // Save. - NSError *error; - if (![moc save:&error]) - err(@"While saving changes to: %@, error: %@", activeElement.name, error); + // Update the UI. + dispatch_async( dispatch_get_main_queue(), ^{ + [self updateAnimated:YES]; - // Update the UI. - dispatch_async(dispatch_get_main_queue(), ^{ - [self updateAnimated:YES]; - - // Show new and old password. - if ([oldPassword length] && ![oldPassword isEqualToString:newPassword]) - [self showAlertWithTitle:@"Password Changed!" - message:PearlString(@"The password for %@ has changed.\n\n" - @"IMPORTANT:\n" - @"Don't forget to update the site with your new password! " - @"Your old password was:\n" - @"%@", activeElement.name, oldPassword)]; - }); - }]; + // Show new and old password. + if ([oldPassword length] && ![oldPassword isEqualToString:newPassword]) + [self showAlertWithTitle:@"Password Changed!" + message:PearlString( @"The password for %@ has changed.\n\n" + @"IMPORTANT:\n" + @"Don't forget to update the site with your new password! " + @"Your old password was:\n" + @"%@", activeElement.name, oldPassword )]; + } ); }]; } diff --git a/MasterPassword/ObjC/iOS/MPSetupViewController.h b/MasterPassword/ObjC/iOS/MPSetupViewController.h index 7c8bd08e..19160c17 100644 --- a/MasterPassword/ObjC/iOS/MPSetupViewController.h +++ b/MasterPassword/ObjC/iOS/MPSetupViewController.h @@ -19,6 +19,9 @@ #import @interface MPSetupViewController : UIViewController + +@property (weak, nonatomic) IBOutlet UISwitch *cloudSwitch; + - (IBAction)close:(UIBarButtonItem *)sender; -- (IBAction)showGuide:(UIBarButtonItem *)sender; + @end diff --git a/MasterPassword/ObjC/iOS/MPSetupViewController.m b/MasterPassword/ObjC/iOS/MPSetupViewController.m index edc09c4b..2c85fc34 100644 --- a/MasterPassword/ObjC/iOS/MPSetupViewController.m +++ b/MasterPassword/ObjC/iOS/MPSetupViewController.m @@ -18,9 +18,30 @@ #import "MPSetupViewController.h" #import "MPAppDelegate.h" +#import "MPAppDelegate_Store.h" @implementation MPSetupViewController +- (void)viewDidAppear:(BOOL)animated { + + [[LocalyticsSession sharedLocalyticsSession] tagScreen:@"Setup"]; + + [super viewDidAppear:animated]; + + if (self.cloudSwitch && [[MPiOSConfig get].iCloudDecided boolValue]) + self.cloudSwitch.on = [MPAppDelegate get].storeManager.cloudEnabled; +} + +- (void)viewWillDisappear:(BOOL)animated { + + [super viewWillDisappear:animated]; + + if (self.cloudSwitch) { + [MPiOSConfig get].iCloudDecided = @YES; + [MPAppDelegate get].storeManager.cloudEnabled = self.cloudSwitch.on; + } +} + - (IBAction)close:(UIBarButtonItem *)sender { [MPiOSConfig get].showSetup = @NO; diff --git a/MasterPassword/ObjC/iOS/MPTypeViewController.m b/MasterPassword/ObjC/iOS/MPTypeViewController.m index 216673b1..85c44d46 100644 --- a/MasterPassword/ObjC/iOS/MPTypeViewController.m +++ b/MasterPassword/ObjC/iOS/MPTypeViewController.m @@ -94,8 +94,8 @@ cellElement.user = selectedElement_.user; cellElement.loginName = selectedElement_.loginName; cellElement.version = MPAlgorithmDefaultVersion; - NSString *typeContent = [cellElement.algorithm generateContentForElement:cellElement usingKey:[MPAppDelegate get].key]; + NSString *typeContent = [cellElement.algorithm generateContentForElement:cellElement usingKey:[MPAppDelegate get].key]; dispatch_async(dispatch_get_main_queue(), ^{ [(UITextField *) [[tableView cellForRowAtIndexPath:indexPath] viewWithTag:2] setText:typeContent]; }); diff --git a/MasterPassword/ObjC/iOS/MPUnlockViewController.m b/MasterPassword/ObjC/iOS/MPUnlockViewController.m index 4f2f5297..e6325c6b 100644 --- a/MasterPassword/ObjC/iOS/MPUnlockViewController.m +++ b/MasterPassword/ObjC/iOS/MPUnlockViewController.m @@ -319,7 +319,7 @@ - (void)showNewUserNameAlertFor:(MPUserEntity *)newUser inContext:(NSManagedObjectContext *)moc completion:(void (^)(BOOL finished))completion { - dispatch_async(dispatch_get_main_queue(), ^{ + PEARL_MAIN_THREAD_START [PearlAlert showAlertWithTitle:@"Enter Your Name" message:nil viewStyle:UIAlertViewStylePlainTextInput initAlert:^(UIAlertView *alert, UITextField *firstField) { @@ -334,24 +334,23 @@ completion(NO); return; } - if (![alert textFieldAtIndex:0].text.length) { + NSString *name = [alert textFieldAtIndex:0].text; + if (!name.length) { [PearlAlert showAlertWithTitle:@"Name Is Required" message:nil viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { - [moc performBlock:^{ - [self showNewUserNameAlertFor:newUser inContext:moc completion:completion]; - }]; + [self showNewUserNameAlertFor:newUser inContext:moc completion:completion]; } cancelTitle:@"Try Again" otherTitles:nil]; return; } // Save - [moc performBlock:^{ - newUser.name = [alert textFieldAtIndex:0].text; - [self showNewUserAvatarAlertFor:newUser inContext:moc completion:completion]; + [moc performBlockAndWait:^{ + newUser.name = name; }]; + [self showNewUserAvatarAlertFor:newUser inContext:moc completion:completion]; } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonSave, nil]; - }); + PEARL_MAIN_THREAD_END } - (void)showNewUserAvatarAlertFor:(MPUserEntity *)newUser inContext:(NSManagedObjectContext *)moc @@ -365,9 +364,7 @@ tappedButtonBlock:^(UIAlertView *_alert, NSInteger _buttonIndex) { // Okay - [moc performBlock:^{ - [self showNewUserConfirmationAlertFor:newUser inContext:moc completion:completion]; - }]; + [self showNewUserConfirmationAlertFor:newUser inContext:moc completion:completion]; } cancelTitle:nil otherTitles:[PearlStrings get].commonButtonOkay, nil]; } @@ -384,9 +381,7 @@ } tappedButtonBlock:^void(UIAlertView *__alert, NSInteger __buttonIndex) { if (__buttonIndex == [__alert cancelButtonIndex]) { - [moc performBlock:^{ - [self showNewUserNameAlertFor:newUser inContext:moc completion:completion]; - }]; + [self showNewUserNameAlertFor:newUser inContext:moc completion:completion]; return; } @@ -808,12 +803,10 @@ } if (buttonIndex == [sheet firstOtherButtonIndex]) - [moc performBlock:^{ - [[MPAppDelegate get] changeMasterPasswordFor:targetedUser inContext:moc didResetBlock:^{ - dispatch_async(dispatch_get_main_queue(), ^{ - [[self avatarForUser:targetedUser] setSelected:YES]; - }); - }]; + [[MPAppDelegate get] changeMasterPasswordFor:targetedUser inContext:moc didResetBlock:^{ + dispatch_async(dispatch_get_main_queue(), ^{ + [[self avatarForUser:targetedUser] setSelected:YES]; + }); }]; } cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:@"Delete User" otherTitles:@"Reset Password", nil]; diff --git a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard b/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard index e4afda33..f8fee226 100644 --- a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard +++ b/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard @@ -1536,7 +1536,7 @@ You could use the word wall for inspiration in finding a memorable master passw - + Enabling iCloud will keep all your iPhones, iPads and Macs nicely in-sync. Any site you add on this device will automatically appear on all your others as well. @@ -1548,7 +1548,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo - + @@ -1561,6 +1561,9 @@ If you set a custom password, it will be encrypted before it is saved to the clo + + + @@ -1669,7 +1672,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo - + @@ -2084,7 +2087,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo - + @@ -2186,163 +2189,108 @@ You can make passwords for all sorts of things, like email addresses, sites or r - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - + - + + + + + + + + @@ -2369,15 +2325,7 @@ You can make passwords for all sorts of things, like email addresses, sites or r Outdated - - - - - - - - - + @@ -2399,7 +2347,7 @@ You can make passwords for all sorts of things, like email addresses, sites or r - + + + - + - + - - + + - - + + + - + + + + + + + + + + + + + + + + + + + + + + + @@ -2477,70 +2494,38 @@ You can make passwords for all sorts of things, like email addresses, sites or r - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - + + @@ -2559,9 +2544,11 @@ You can make passwords for all sorts of things, like email addresses, sites or r + + @@ -2620,6 +2607,24 @@ You can make passwords for all sorts of things, like email addresses, sites or r + + + + + + + + + + + + + + + + + + @@ -2694,6 +2699,7 @@ You can make passwords for all sorts of things, like email addresses, sites or r + diff --git a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj index 245dbdcc..7a652394 100644 --- a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj +++ b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj @@ -36,6 +36,8 @@ DA497C0C15E8C95700B52167 /* libGoogle+.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA497B9715E8C90E00B52167 /* libGoogle+.a */; }; DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; }; DA4DA1DA1564471F00F6F596 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; }; + DA5A09DF171A70E4005284AB /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DD171A70E4005284AB /* play.png */; }; + DA5A09E0171A70E4005284AB /* play@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DE171A70E4005284AB /* play@2x.png */; }; DA5BFA49147E415C00F98B1E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA48147E415C00F98B1E /* UIKit.framework */; }; DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DA5BFA4D147E415C00F98B1E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */; }; @@ -1032,6 +1034,8 @@ DA3EF17A15A47744003ABF4E /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libUbiquityStoreManager.a; sourceTree = BUILT_PRODUCTS_DIR; }; DA497B9715E8C90E00B52167 /* libGoogle+.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libGoogle+.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + DA5A09DD171A70E4005284AB /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = ""; }; + DA5A09DE171A70E4005284AB /* play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play@2x.png"; sourceTree = ""; }; DA5BFA44147E415C00F98B1E /* MasterPassword.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MasterPassword.app; sourceTree = BUILT_PRODUCTS_DIR; }; DA5BFA48147E415C00F98B1E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -2202,6 +2206,8 @@ DABD360D1711E29400CF925C /* Media */ = { isa = PBXGroup; children = ( + DA5A09DD171A70E4005284AB /* play.png */, + DA5A09DE171A70E4005284AB /* play@2x.png */, DABD360E1711E29400CF925C /* Automaton */, DABD366B1711E29400CF925C /* Avatars */, DABD36921711E29400CF925C /* Background */, @@ -4588,6 +4594,8 @@ DABD3FCB1712446200CF925C /* cloud@2x.png in Resources */, DABD3FCE1714F45C00CF925C /* identity.png in Resources */, DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */, + DA5A09DF171A70E4005284AB /* play.png in Resources */, + DA5A09E0171A70E4005284AB /* play@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MasterPassword/Resources/Media/play.png b/MasterPassword/Resources/Media/play.png new file mode 100644 index 00000000..87c6df81 Binary files /dev/null and b/MasterPassword/Resources/Media/play.png differ diff --git a/MasterPassword/Resources/Media/play@2x.png b/MasterPassword/Resources/Media/play@2x.png new file mode 100644 index 00000000..fd234103 Binary files /dev/null and b/MasterPassword/Resources/Media/play@2x.png differ diff --git a/MasterPassword/Resources/Raw/Large Icons.vdesigner/QuickLook/Preview.pdf b/MasterPassword/Resources/Raw/Large Icons.vdesigner/QuickLook/Preview.pdf index c9c1360c..14fb9293 100644 Binary files a/MasterPassword/Resources/Raw/Large Icons.vdesigner/QuickLook/Preview.pdf and b/MasterPassword/Resources/Raw/Large Icons.vdesigner/QuickLook/Preview.pdf differ diff --git a/MasterPassword/Resources/Raw/Large Icons.vdesigner/QuickLook/Thumbnail.jpg b/MasterPassword/Resources/Raw/Large Icons.vdesigner/QuickLook/Thumbnail.jpg index 0e1da73d..e029158a 100644 Binary files a/MasterPassword/Resources/Raw/Large Icons.vdesigner/QuickLook/Thumbnail.jpg and b/MasterPassword/Resources/Raw/Large Icons.vdesigner/QuickLook/Thumbnail.jpg differ diff --git a/MasterPassword/Resources/Raw/Large Icons.vdesigner/VectorDesigner b/MasterPassword/Resources/Raw/Large Icons.vdesigner/VectorDesigner index 39f58601..a4b9441f 100644 Binary files a/MasterPassword/Resources/Raw/Large Icons.vdesigner/VectorDesigner and b/MasterPassword/Resources/Raw/Large Icons.vdesigner/VectorDesigner differ