2
0

Fixed sending emails when the key window is an alert window + added coachmarks.

This commit is contained in:
Maarten Billemont 2014-04-24 21:43:47 -04:00
parent e070082f4a
commit aa461b73c8
20 changed files with 1173 additions and 140 deletions

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit 9a506ea9d153dfee48b6d67babf7d33e7aaa5982
Subproject commit 2e328ecff09d7d271e75f8521112aa8698e852f0

View File

@ -34,6 +34,6 @@ typedef enum {
- (MPImportResult)importSites:(NSString *)importedSitesString
askImportPassword:(NSString *(^)(NSString *userName))importPassword
askUserPassword:(NSString *(^)(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))userPassword;
- (NSString *)exportSitesShowingPasswords:(BOOL)showPasswords;
- (NSString *)exportSitesRevealPasswords:(BOOL)revealPasswords;
@end

View File

@ -694,15 +694,15 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
return MPImportResultSuccess;
}
- (NSString *)exportSitesShowingPasswords:(BOOL)showPasswords {
- (NSString *)exportSitesRevealPasswords:(BOOL)revealPasswords {
MPUserEntity *activeUser = [self activeUserForMainThread];
inf(@"Exporting sites, %@, for: %@", showPasswords? @"showing passwords": @"omitting passwords", activeUser.userID);
inf(@"Exporting sites, %@, for: %@", revealPasswords? @"revealing passwords": @"omitting passwords", activeUser.userID);
// Header.
NSMutableString *export = [NSMutableString new];
[export appendFormat:@"# Master Password site export\n"];
if (showPasswords)
if (revealPasswords)
[export appendFormat:@"# Export of site names and passwords in clear-text.\n"];
else
[export appendFormat:@"# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n"];
@ -712,7 +712,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
[export appendFormat:@"# User Name: %@\n", activeUser.name];
[export appendFormat:@"# Key ID: %@\n", [activeUser.keyID encodeHex]];
[export appendFormat:@"# Date: %@\n", [[NSDateFormatter rfc3339DateFormatter] stringFromDate:[NSDate date]]];
if (showPasswords)
if (revealPasswords)
[export appendFormat:@"# Passwords: VISIBLE\n"];
else
[export appendFormat:@"# Passwords: PROTECTED\n"];
@ -732,7 +732,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
// Determine the content to export.
if (!(type & MPElementFeatureDevicePrivate)) {
if (showPasswords)
if (revealPasswords)
content = [element.algorithm resolveContentForElement:element usingKey:self.key];
else if (type & MPElementFeatureExportContent)
content = [element.algorithm exportContentForElement:element usingKey:self.key];
@ -745,7 +745,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
}
MPCheckpoint( MPCheckpointSitesExported, @{
@"showPasswords" : @(showPasswords)
@"showPasswords" : @(revealPasswords)
} );
return export;

View File

@ -0,0 +1,37 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPCoachmarkViewController.h
// MPCoachmarkViewController
//
// Created by lhunath on 2014-04-22.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MPCoachmark : NSObject
@property(nonatomic, strong) Class coachedClass;
@property(nonatomic) int coachedVersion;
@property(nonatomic) BOOL coached;
+ (instancetype)coachmarkForClass:(Class)class version:(NSInteger)version;
@end
@interface MPCoachmarkViewController : UIViewController
@property(nonatomic, strong) MPCoachmark *coachmark;
- (IBAction)close:(id)sender;
@end

View File

@ -0,0 +1,53 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPCoachmarkViewController.h
// MPCoachmarkViewController
//
// Created by lhunath on 2014-04-22.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import "MPCoachmarkViewController.h"
@implementation MPCoachmarkViewController {
}
- (IBAction)close:(id)sender {
[self dismissViewControllerAnimated:YES completion:^{
self.coachmark.coached = YES;
}];
}
@end
@implementation MPCoachmark
+ (instancetype)coachmarkForClass:(Class)coachedClass version:(NSInteger)coachedVersion {
MPCoachmark *coachmark = [self new];
coachmark.coachedClass = coachedClass;
coachmark.coachedVersion = coachedVersion;
return coachmark;
}
- (BOOL)coached {
return [[NSUserDefaults standardUserDefaults] boolForKey:strf( @"%@.%d.coached", self.coachedClass, self.coachedVersion )];
}
- (void)setCoached:(BOOL)coached {
[[NSUserDefaults standardUserDefaults] setBool:coached forKey:strf( @"%@.%d.coached", self.coachedClass, self.coachedVersion )];
}
@end

View File

@ -150,7 +150,7 @@
if (buttonIndex == [alert cancelButtonIndex])
return;
[PearlEMail sendEMailTo:nil subject:@"[Master Password] Upgrade Changes" body:formattedChanges];
[PearlEMail sendEMailTo:nil fromVC:self subject:@"[Master Password] Upgrade Changes" body:formattedChanges];
} cancelTitle:@"Don't Email" otherTitles:@"Send Email", nil];
}

View File

@ -715,11 +715,6 @@
[self setHelpHidden:NO animated:YES];
break;
}
case 1: {
inf(@"Action: Guide");
[[MPiOSAppDelegate get] showGuide];
break;
}
case 2: {
inf(@"Action: Preferences");
[self performSegueWithIdentifier:@"MP_UserProfile" sender:self];

View File

@ -0,0 +1,23 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPPasswordsCoachmarkViewController.h
// MPPasswordsCoachmarkViewController
//
// Created by lhunath on 2014-04-23.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPCoachmarkViewController.h"
@interface MPPasswordsCoachmarkViewController : MPCoachmarkViewController <UICollectionViewDataSource>
@end

View File

@ -0,0 +1,51 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPPasswordsCoachmarkViewController.h
// MPPasswordsCoachmarkViewController
//
// Created by lhunath on 2014-04-23.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import "MPPasswordsCoachmarkViewController.h"
#import "MPPasswordLargeGeneratedCell.h"
#import "MPPasswordLargeStoredCell.h"
@implementation MPPasswordsCoachmarkViewController
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 2;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.item == 0) {
MPPasswordLargeGeneratedCell *cell = [MPPasswordLargeGeneratedCell dequeueCellWithType:MPElementTypeGeneratedLong
fromCollectionView:collectionView atIndexPath:indexPath];
[cell reloadWithTransientSite:@"apple.com"];
return cell;
}
else if (indexPath.item == 1) {
MPPasswordLargeStoredCell *cell = [MPPasswordLargeStoredCell dequeueCellWithType:MPElementTypeStoredPersonal
fromCollectionView:collectionView atIndexPath:indexPath];
[cell reloadWithTransientSite:@"gmail.com"];
[cell.contentField setText:@"PaS$w0rD"];
return cell;
}
Throw(@"Unexpected item for indexPath: %@", indexPath);
}
@end

View File

@ -18,6 +18,7 @@
#import "LLGitTip.h"
@class MPElementEntity;
@class MPCoachmark;
@interface MPPasswordsViewController : UIViewController<UISearchBarDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
@ -33,6 +34,8 @@
@property(assign, nonatomic) BOOL active;
@property(nonatomic, copy) NSString *originalQuery;
@property(nonatomic, readonly) MPCoachmark *coachmark;
- (void)setActive:(BOOL)active animated:(BOOL)animated completion:(void (^)(BOOL finished))completion;
- (IBAction)dismissPopdown:(id)sender;

View File

@ -22,9 +22,9 @@
#import "MPPasswordLargeCell.h"
#import "MPPasswordTypesCell.h"
#import "MPPasswordSmallCell.h"
#import "UIColor+Expanded.h"
#import "MPPopdownSegue.h"
#import "MPAppDelegate_Key.h"
#import "MPCoachmarkViewController.h"
@interface MPPasswordsViewController()<NSFetchedResultsControllerDelegate>
@ -53,8 +53,9 @@
[super viewDidLoad];
_fetchedUpdates = [NSMutableDictionary dictionaryWithCapacity:4];
_backgroundColor = [UIColor clearColor];
_darkenedBackgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6f];
_backgroundColor = self.passwordCollectionView.backgroundColor;
_darkenedBackgroundColor = [_backgroundColor colorWithAlphaComponent:0.6f];
_coachmark = [MPCoachmark coachmarkForClass:[self class] version:0];
self.view.backgroundColor = [UIColor clearColor];
self.passwordCollectionView.contentInset = UIEdgeInsetsMake( 108, 0, 0, 0 );
@ -70,6 +71,16 @@
[self updatePasswords];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
PearlMainQueueAfter( 1, ^{
if (!self.coachmark.coached)
[self performSegueWithIdentifier:@"coachmarks" sender:self];
} );
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
@ -82,6 +93,8 @@
if ([segue.identifier isEqualToString:@"popdown"])
_popdownVC = segue.destinationViewController;
if ([segue.identifier isEqualToString:@"coachmarks"])
((MPCoachmarkViewController *)segue.destinationViewController).coachmark = self.coachmark;
}
#pragma mark - UICollectionViewDelegateFlowLayout
@ -376,7 +389,7 @@
_passwordsDismissRecognizer = [self.view dismissKeyboardForField:self.passwordsSearchBar onTouchForced:NO];
[UIView animateWithDuration:0.3f animations:^{
searchBar.superview.backgroundColor = _darkenedBackgroundColor;
self.passwordCollectionView.backgroundColor = _darkenedBackgroundColor;
}];
}
}
@ -389,7 +402,7 @@
[self.view removeGestureRecognizer:_passwordsDismissRecognizer];
[UIView animateWithDuration:0.3f animations:^{
searchBar.superview.backgroundColor = _backgroundColor;
self.passwordCollectionView.backgroundColor = _backgroundColor;
}];
}
}

View File

@ -13,6 +13,7 @@
@property(weak, nonatomic) IBOutlet UISwitch *savePasswordSwitch;
@property(weak, nonatomic) IBOutlet UITableViewCell *feedbackCell;
@property(weak, nonatomic) IBOutlet UITableViewCell *coachmarksCell;
@property(weak, nonatomic) IBOutlet UITableViewCell *exportCell;
@property(weak, nonatomic) IBOutlet UIImageView *avatarImage;
@property(weak, nonatomic) IBOutlet UISegmentedControl *typeControl;

View File

@ -11,6 +11,8 @@
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "UIColor+Expanded.h"
#import "MPPasswordsViewController.h"
#import "MPCoachmarkViewController.h"
@interface MPPreferencesViewController()
@ -54,8 +56,19 @@
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
if (cell == self.feedbackCell)
[[MPiOSAppDelegate get] showFeedbackWithLogs:YES forVC:self];
if (cell == self.exportCell)
[[MPiOSAppDelegate get] export];
[[MPiOSAppDelegate get] showExportForVC:self];
if (cell == self.coachmarksCell) {
for (UIViewController *vc = self; (vc = vc.parentViewController); )
if ([vc isKindOfClass:[MPPasswordsViewController class]]) {
MPPasswordsViewController *passwordsVC = (MPPasswordsViewController *)vc;
passwordsVC.coachmark.coached = NO;
[passwordsVC dismissPopdown:self];
[vc performSegueWithIdentifier:@"coachmarks" sender:self];
}
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}

View File

@ -130,7 +130,7 @@
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
if (cell == self.exportCell)
[[MPiOSAppDelegate get] export];
[[MPiOSAppDelegate get] showExportForVC:self];
else if (cell == self.changeMPCell) {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {

View File

@ -54,12 +54,4 @@
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)showGuide:(UIBarButtonItem *)sender {
[MPiOSConfig get].showSetup = @NO;
[self dismissViewControllerAnimated:YES completion:^{
[[MPiOSAppDelegate get] showGuide];
}];
}
@end

View File

@ -1178,7 +1178,7 @@
}
if (buttonIndex == [sheet firstOtherButtonIndex] + 3) {
// Mailing List
[PearlEMail sendEMailTo:@"masterpassword-join@lists.lyndir.com" subject:@"Subscribe"
[PearlEMail sendEMailTo:@"masterpassword-join@lists.lyndir.com" fromVC:self subject:@"Subscribe"
body:@"Press 'Send' now to subscribe to the Master Password mailing list.\n\n"
@"You'll be kept up-to-date on the evolution of and discussions revolving Master Password."];
return;

View File

@ -14,12 +14,10 @@
@interface MPiOSAppDelegate : MPAppDelegate_Shared
- (void)showGuide;
- (void)showSetup;
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController;
- (void)openFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController;
- (void)export;
- (void)showExportForVC:(UIViewController *)viewController;
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void (^)(void))didReset;
@end

View File

@ -10,7 +10,6 @@
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "IASKSettingsReader.h"
#import "JRSwizzle.h"
@interface MPiOSAppDelegate()
@ -221,7 +220,7 @@
dispatch_async( dispatch_get_main_queue(), ^{
if ([[MPiOSConfig get].showSetup boolValue])
[[MPiOSAppDelegate get] showSetup];
[self.navigationController performSegueWithIdentifier:@"setup" sender:self];
} );
MPCheckpoint( MPCheckpointStarted, @{
@ -410,20 +409,6 @@
#pragma mark - Behavior
- (void)showGuide {
//TODO [self.navigationController performSegueWithIdentifier:@"MP_Guide" sender:self];
MPCheckpoint( MPCheckpointShowGuide, nil );
}
- (void)showSetup {
//TODO [self.navigationController performSegueWithIdentifier:@"MP_Setup" sender:self];
MPCheckpoint( MPCheckpointShowSetup, nil );
}
- (void)showReview {
[super showReview];
@ -487,7 +472,7 @@
showComposerForVC:viewController];
}
- (void)export {
- (void)showExportForVC:(UIViewController *)viewController {
[PearlAlert showNotice:
@"This will export all your site names.\n\n"
@ -504,15 +489,15 @@
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 0)
// Safe Export
[self exportShowPasswords:NO];
[self showExportRevealPasswords:NO forVC:viewController];
if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 1)
// Show Passwords
[self exportShowPasswords:YES];
[self showExportRevealPasswords:YES forVC:viewController];
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Safe Export", @"Show Passwords", nil];
} otherTitles:nil];
}
- (void)exportShowPasswords:(BOOL)showPasswords {
- (void)showExportRevealPasswords:(BOOL)revealPasswords forVC:(UIViewController *)viewController {
if (![PearlEMail canSendMail]) {
[PearlAlert showAlertWithTitle:@"Cannot Send Mail"
@ -525,10 +510,10 @@
return;
}
NSString *exportedSites = [self exportSitesShowingPasswords:showPasswords];
NSString *exportedSites = [self exportSitesRevealPasswords:revealPasswords];
NSString *message;
if (showPasswords)
if (revealPasswords)
message = PearlString( @"Export of Master Password sites with passwords included.\n\n"
@"REMINDER: Make sure nobody else sees this file! Passwords are visible!\n\n\n"
@"--\n"
@ -549,7 +534,7 @@
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
[PearlEMail sendEMailTo:nil subject:@"Master Password Export" body:message
[PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
attachments:[[PearlEMailAttachment alloc] initWithContent:[exportedSites dataUsingEncoding:NSUTF8StringEncoding]
mimeType:@"text/plain" fileName:
PearlString( @"%@ (%@).mpsites", [self activeUserForMainThread].name,

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
93D391C07818F4C2DC1B6956 /* MPPasswordsCoachmarkViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D397E3650384498E7E53C4 /* MPPasswordsCoachmarkViewController.m */; };
93D391ED37C9F687FA51EAA1 /* MPEmergencySegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3937712BF1B67623E5764 /* MPEmergencySegue.m */; };
93D3922A53E41A54832E90D9 /* PearlOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390FADEB325D8D54A957D /* PearlOverlay.m */; };
93D39233C3EDD9A947ABA52D /* LLButtonView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39BF6BCBDFFE844E7D34C /* LLButtonView.m */; };
@ -25,6 +26,7 @@
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B050DD5F55E9794EFD4 /* MPPopdownSegue.m */; };
93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3956915634581E737B38C /* PearlNavigationController.m */; };
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3942A356B639724157982 /* PearlOverlay.h */; };
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */; };
93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */; };
93D3980046016EFD05B35BC5 /* PearlUICollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */; };
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */; };
@ -74,6 +76,12 @@
DA44260A1557D9E40052177D /* libUbiquityStoreManager.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */; };
DA4522441902355C008F650A /* icon_book.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD370C1711E29500CF925C /* icon_book.png */; };
DA4522451902355C008F650A /* icon_book@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD370D1711E29500CF925C /* icon_book@2x.png */; };
DA45224719062899008F650A /* icon_settings.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38141711E29600CF925C /* icon_settings.png */; };
DA45224819062899008F650A /* icon_settings@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38151711E29600CF925C /* icon_settings@2x.png */; };
DA452249190628A1008F650A /* icon_wrench.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD386A1711E29700CF925C /* icon_wrench.png */; };
DA45224A190628A1008F650A /* icon_wrench@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD386B1711E29700CF925C /* icon_wrench@2x.png */; };
DA45224B190628B2008F650A /* icon_gear.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37821711E29500CF925C /* icon_gear.png */; };
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37831711E29500CF925C /* icon_gear@2x.png */; };
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 */; };
@ -531,6 +539,7 @@
93D390A66F69AB1CDB0BFF93 /* LLModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLModel.h; sourceTree = "<group>"; };
93D390FADEB325D8D54A957D /* PearlOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlOverlay.m; sourceTree = "<group>"; };
93D390FB3110DCCE68E600DC /* UIScrollView+PearlAdjustInsets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+PearlAdjustInsets.m"; sourceTree = "<group>"; };
93D390FD93EFCFECB5193DEF /* MPPasswordsCoachmarkViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordsCoachmarkViewController.h; sourceTree = "<group>"; };
93D391243F64A77798B4D6A4 /* MPPasswordTypesCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordTypesCell.h; sourceTree = "<group>"; };
93D3914D7597F9A28DB9D85E /* MPPasswordsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordsViewController.h; sourceTree = "<group>"; };
93D3916C1D8F1427DFBDEBCA /* MPAppSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppSettingsViewController.m; sourceTree = "<group>"; };
@ -557,14 +566,17 @@
93D3971FE104BB4052484151 /* MPUsersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUsersViewController.h; sourceTree = "<group>"; };
93D39730673227EFF6DEFF19 /* MPSetupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSetupViewController.h; sourceTree = "<group>"; };
93D3979190DACEBD1F6AE9F4 /* MPLogsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPLogsViewController.m; sourceTree = "<group>"; };
93D397E3650384498E7E53C4 /* MPPasswordsCoachmarkViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordsCoachmarkViewController.m; sourceTree = "<group>"; };
93D3983278751A530262F64E /* LLConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLConfig.h; sourceTree = "<group>"; };
93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlNavigationController.h; sourceTree = "<group>"; };
93D39888EE06F06264CC963B /* MPPasswordSmallCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordSmallCell.h; sourceTree = "<group>"; };
93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; };
93D398EBF99FF0C245FD561E /* NSManagedObject+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObject+Pearl.m"; sourceTree = "<group>"; };
93D3993422E207BF0B21D089 /* MPPasswordLargeGeneratedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeGeneratedCell.m; sourceTree = "<group>"; };
93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCoachmarkViewController.m; sourceTree = "<group>"; };
93D39961CD6A43648CC0B0DB /* MPPreferencesViewControllerOld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPreferencesViewControllerOld.h; sourceTree = "<group>"; };
93D39975CE5AEC99E3F086C7 /* MPPasswordCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordCell.h; sourceTree = "<group>"; };
93D3999693660C89A7465F4E /* MPCoachmarkViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCoachmarkViewController.h; sourceTree = "<group>"; };
93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUsersViewController.m; sourceTree = "<group>"; };
93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIResponder+PearlFirstResponder.m"; sourceTree = "<group>"; };
93D39A28369954D147E239BA /* MPSetupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSetupViewController.m; sourceTree = "<group>"; };
@ -2619,6 +2631,10 @@
93D392876BE5C011DE73B43F /* MPPopdownSegue.h */,
93D3916C1D8F1427DFBDEBCA /* MPAppSettingsViewController.m */,
93D39C86E984EC65DA5ACB1D /* MPAppSettingsViewController.h */,
93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */,
93D3999693660C89A7465F4E /* MPCoachmarkViewController.h */,
93D397E3650384498E7E53C4 /* MPPasswordsCoachmarkViewController.m */,
93D390FD93EFCFECB5193DEF /* MPPasswordsCoachmarkViewController.h */,
);
path = iOS;
sourceTree = "<group>";
@ -3675,12 +3691,14 @@
DABD38FA1711E29700CF925C /* ui_list_middle@2x.png in Resources */,
DABD38FB1711E29700CF925C /* ui_navbar_back.png in Resources */,
DABD38FC1711E29700CF925C /* ui_navbar_back@2x.png in Resources */,
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */,
DABD38FD1711E29700CF925C /* ui_navbar_button.png in Resources */,
DABD38FE1711E29700CF925C /* ui_navbar_button@2x.png in Resources */,
DABD38FF1711E29700CF925C /* ui_navbar_container.png in Resources */,
DABD39001711E29700CF925C /* ui_navbar_container@2x.png in Resources */,
DABD39011711E29700CF925C /* ui_panel_container.png in Resources */,
DA854C8318D4CFBF00106317 /* avatar-add@2x.png in Resources */,
DA45224A190628A1008F650A /* icon_wrench@2x.png in Resources */,
DABD39021711E29700CF925C /* ui_panel_container@2x.png in Resources */,
DABD39031711E29700CF925C /* ui_panel_display.png in Resources */,
DABD39041711E29700CF925C /* ui_panel_display@2x.png in Resources */,
@ -3740,6 +3758,7 @@
DABD395B1711E29700CF925C /* avatar-9.png in Resources */,
DABD395C1711E29700CF925C /* avatar-9@2x.png in Resources */,
DABD395D1711E29700CF925C /* background.png in Resources */,
DA45224719062899008F650A /* icon_settings.png in Resources */,
DABD395E1711E29700CF925C /* background@2x.png in Resources */,
DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */,
DABD39871711E29700CF925C /* SourceCodePro-Black.otf in Resources */,
@ -3799,7 +3818,9 @@
DABD3B971711E29800CF925C /* pull-up.png in Resources */,
DABD3B981711E29800CF925C /* pull-up@2x.png in Resources */,
DABD3B991711E29800CF925C /* social-facebook.png in Resources */,
DA452249190628A1008F650A /* icon_wrench.png in Resources */,
DABD3B9A1711E29800CF925C /* social-facebook@2x.png in Resources */,
DA45224819062899008F650A /* icon_settings@2x.png in Resources */,
DABD3B9B1711E29800CF925C /* social-google+.png in Resources */,
DADEF4121810D2940052CA3E /* love-lyndir.button.green.png in Resources */,
DABD3B9C1711E29800CF925C /* social-google+@2x.png in Resources */,
@ -3816,6 +3837,7 @@
DABD3FCE1714F45C00CF925C /* identity.png in Resources */,
DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */,
DADEF4151810D2940052CA3E /* love-lyndir.button.grey@2x.png in Resources */,
DA45224B190628B2008F650A /* icon_gear.png in Resources */,
DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */,
DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */,
DA5A09DF171A70E4005284AB /* play.png in Resources */,
@ -3937,6 +3959,8 @@
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */,
93D39B21156EC9A0B4C2BC83 /* MPPreferencesViewControllerOld.m in Sources */,
93D39BA1EA3CAAC8A220B4A6 /* MPAppSettingsViewController.m in Sources */,
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */,
93D391C07818F4C2DC1B6956 /* MPPasswordsCoachmarkViewController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

File diff suppressed because it is too large Load Diff