2
0

Temporary moc fix, setup & new guide.

[FIXED]     Pass along temporary mocs, they appear to be stored __weak in the object and we can't rely on them not being nil.
[ADDED]     Setup flow for initially setting the iCloud preference.
[ADDED]     New guide.
[IMPROVED]  Hierarchy and flow of unlock -> main.
This commit is contained in:
Maarten Billemont 2013-04-13 13:40:17 -04:00
parent 036c04f65f
commit abe874cda3
28 changed files with 930 additions and 424 deletions

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit 17a3f485d1056976f55d0311d20ce4a693a62748
Subproject commit d8c2fa3755d1f440cd5eaa980adffef08a805b25

View File

@ -35,7 +35,7 @@
NSError *error = nil;
NSFetchRequest *migrationRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
migrationRequest.predicate = [NSPredicate predicateWithFormat:@"version_ < %d AND user == %@", MPAlgorithmDefaultVersion, user];
migrationRequest.predicate = [NSPredicate predicateWithFormat:@"version_ < %d AND user == %@", self.version, user];
NSArray *migrationElements = [user.managedObjectContext executeFetchRequest:migrationRequest error:&error];
if (!migrationElements) {
err(@"While looking for elements to migrate: %@", error);

View File

@ -15,9 +15,9 @@
#define MPAvatarCount 19
@interface NSManagedObject (MP)
@interface NSManagedObjectContext(MP)
- (BOOL)saveContext;
- (BOOL)saveToStore;
@end

View File

@ -9,22 +9,17 @@
#import "MPEntities.h"
#import "MPAppDelegate.h"
@implementation NSManagedObject (MP)
@implementation NSManagedObjectContext (MP)
- (BOOL)saveContext {
- (BOOL)saveToStore {
NSError *error;
NSManagedObjectContext *moc = [self managedObjectContext];
if (![moc save:&error]) {
err(@"While saving %@: %@", NSStringFromClass([self class]), error);
return NO;
}
if (![moc.parentContext save:&error]) {
err(@"While saving parent %@: %@", NSStringFromClass([self class]), error);
if (![self save:&error]) {
err(@"While saving: %@", NSStringFromClass([self class]), error);
return NO;
}
return YES;
return !self.parentContext || [self.parentContext saveToStore];
}
@end

View File

@ -52,6 +52,7 @@ typedef enum {
#define MPCheckpointUseType @"MPCheckpointUseType"
#define MPCheckpointDeleteElement @"MPCheckpointDeleteElement"
#define MPCheckpointShowGuide @"MPCheckpointShowGuide"
#define MPCheckpointShowSetup @"MPCheckpointShowSetup"
#define MPCheckpointChangeMP @"MPCheckpointChangeMP"
#define MPCheckpointMPErrorUbiquity @"MPCheckpointMPErrorUbiquity"
#define MPCheckpointLocalStoreReset @"MPCheckpointLocalStoreReset"

View File

@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>MasterPassword 1.xcdatamodel</string>
<string>MasterPassword 4.xcdatamodel</string>
</dict>
</plist>

View File

@ -17,9 +17,10 @@
@property (nonatomic, readonly) GPPShare *googlePlus;
- (void)showGuide;
- (void)showSetup;
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController;
- (void)export;
- (void)changeMasterPasswordFor:(MPUserEntity *)user didResetBlock:(void(^)(void))didReset;
- (void)changeMasterPasswordFor:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc didResetBlock:(void(^)(void))didReset;
@end

View File

@ -188,14 +188,6 @@
[[UISegmentedControl appearance] setDividerImage:segUnselectedSelected forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
*/
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil queue:nil
usingBlock:^(NSNotification *note) {
if ([[note.userInfo objectForKey:@"animated"] boolValue])
[self.navigationController performSegueWithIdentifier:@"MP_Unlock" sender:nil];
else
[self.navigationController presentViewController:[self.navigationController.storyboard instantiateViewControllerWithIdentifier:@"MPUnlockViewController"]
animated:NO completion:nil];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPCheckConfigNotification object:nil queue:nil usingBlock:
^(NSNotification *note) {
if ([[MPiOSConfig get].sendInfo boolValue]) {
@ -207,7 +199,7 @@
[[Crashlytics sharedInstance] setBoolValue:[[MPConfig get].iCloudDecided boolValue] forKey:@"iCloudDecided"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].sendInfo boolValue] forKey:@"sendInfo"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].helpHidden boolValue] forKey:@"helpHidden"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].showQuickStart boolValue] forKey:@"showQuickStart"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].showSetup boolValue] forKey:@"showQuickStart"];
[[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].firstRun boolValue] forKey:@"firstRun"];
[[Crashlytics sharedInstance] setIntValue:[[PearlConfig get].launchCount intValue] forKey:@"launchCount"];
[[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].askForReviews boolValue] forKey:@"askForReviews"];
@ -220,7 +212,7 @@
[TestFlight addCustomEnvironmentInformation:[[MPConfig get].iCloudDecided boolValue]? @"YES": @"NO" forKey:@"iCloudDecided"];
[TestFlight addCustomEnvironmentInformation:[[MPiOSConfig get].sendInfo boolValue]? @"YES": @"NO" forKey:@"sendInfo"];
[TestFlight addCustomEnvironmentInformation:[[MPiOSConfig get].helpHidden boolValue]? @"YES": @"NO" forKey:@"helpHidden"];
[TestFlight addCustomEnvironmentInformation:[[MPiOSConfig get].showQuickStart boolValue]? @"YES": @"NO"
[TestFlight addCustomEnvironmentInformation:[[MPiOSConfig get].showSetup boolValue]? @"YES": @"NO"
forKey:@"showQuickStart"];
[TestFlight addCustomEnvironmentInformation:[[PearlConfig get].firstRun boolValue]? @"YES": @"NO" forKey:@"firstRun"];
[TestFlight addCustomEnvironmentInformation:[[PearlConfig get].launchCount description] forKey:@"launchCount"];
@ -237,7 +229,7 @@
@"iCloudDecided" : [[MPConfig get].iCloudDecided boolValue]? @"YES": @"NO",
@"sendInfo" : [[MPiOSConfig get].sendInfo boolValue]? @"YES": @"NO",
@"helpHidden" : [[MPiOSConfig get].helpHidden boolValue]? @"YES": @"NO",
@"showQuickStart" : [[MPiOSConfig get].showQuickStart boolValue]? @"YES": @"NO",
@"showQuickStart" : [[MPiOSConfig get].showSetup boolValue]? @"YES": @"NO",
@"firstRun" : [[PearlConfig get].firstRun boolValue]? @"YES": @"NO",
@"launchCount" : NilToNSNull([[PearlConfig get].launchCount description]),
@"askForReviews" : [[PearlConfig get].askForReviews boolValue]? @"YES": @"NO",
@ -268,6 +260,9 @@
inf(@"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier]);
if ([[MPiOSConfig get].showSetup boolValue])
[[MPAppDelegate get] showSetup];
return YES;
}
@ -438,6 +433,16 @@
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointShowGuide attributes:nil];
}
- (void)showSetup {
[self.navigationController performSegueWithIdentifier:@"MP_Setup" sender:self];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointShowSetup];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointShowSetup attributes:nil];
}
- (void)showFeedback {
[self showFeedbackWithLogs:NO forVC:nil];
@ -575,7 +580,7 @@
nil];
}
- (void)changeMasterPasswordFor:(MPUserEntity *)user didResetBlock:(void (^)(void))didReset {
- (void)changeMasterPasswordFor:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc didResetBlock:(void (^)(void))didReset {
[PearlAlert showAlertWithTitle:@"Changing Master Password"
message:
@ -587,12 +592,13 @@
if (buttonIndex == [alert cancelButtonIndex])
return;
[user.managedObjectContext performBlock:^{
[moc performBlock:^{
inf(@"Unsetting master password for: %@.", user.userID);
user.keyID = nil;
[self forgetSavedKeyFor:user];
[self signOutAnimated:YES];
[moc saveToStore];
[self signOutAnimated:YES];
if (didReset)
didReset();

View File

@ -10,9 +10,6 @@
@interface MPGuideViewController : UIViewController <UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
- (IBAction)close;
@end

View File

@ -21,18 +21,9 @@
return UIInterfaceOrientationPortrait;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.scrollView autoSizeContent];
}
- (void)viewWillAppear:(BOOL)animated {
inf(@"Guide will appear.");
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
[super viewWillAppear:animated];
}
@ -46,10 +37,6 @@
- (void)viewWillDisappear:(BOOL)animated {
inf(@"Guide will disappear.");
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[MPiOSConfig get].showQuickStart = @NO;
[super viewWillDisappear:animated];
}
@ -58,12 +45,4 @@
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView_ {
NSInteger page = (NSInteger)(self.scrollView.contentOffset.x / self.scrollView.bounds.size.width);
self.pageControl.currentPage = page;
self.pageControl.hidden = (page == self.pageControl.numberOfPages - 1);
}
@end

View File

@ -91,30 +91,24 @@
[self showToolTip:@"Password outdated. Tap to upgrade it." withIcon:nil];
}];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil queue:nil
usingBlock:^void(NSNotification *note) {
_activeElementOID = nil;
self.suppressOutdatedAlert = NO;
[self updateAnimated:NO];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil queue:nil usingBlock:
^(NSNotification *note) {
_activeElementOID = nil;
self.suppressOutdatedAlert = NO;
[self updateAnimated:NO];
[self.navigationController popToRootViewControllerAnimated:[[note.userInfo objectForKey:@"animated"] boolValue]];
}];
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
if ([[MPiOSConfig get].showQuickStart boolValue])
[[MPAppDelegate get] showGuide];
if (![MPAppDelegate get].activeUser)
// FIXME: Remove either this one or the one in -viewDidAppear:
[self presentViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"MPUnlockViewController"]
animated:animated completion:nil];
[self activeElementDo:^(MPElementEntity *activeElement) {
if (activeElement.user != [MPAppDelegate get].activeUser)
_activeElementOID = nil;
}];
self.searchDisplayController.searchBar.text = nil;
self.alertContainer.alpha = 0;
self.outdatedAlertContainer.alpha = 0;
@ -137,17 +131,15 @@
// Needed for when we appear after a modal VC dismisses:
// We can't present until the other modal VC has been fully dismissed and presenting in -viewWillAppear: will fail.
if ([MPAppDelegate get].activeUser)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
if ([MPAlgorithmDefault migrateUser:[MPAppDelegate get].activeUser] && !self.suppressOutdatedAlert)
[UIView animateWithDuration:0.3f animations:^{
self.outdatedAlertContainer.alpha = 1;
self.suppressOutdatedAlert = YES;
}];
});
else
[self presentViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"MPUnlockViewController"]
animated:animated completion:nil];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
if ([MPAlgorithmDefault migrateUser:activeUser] && !self.suppressOutdatedAlert)
[UIView animateWithDuration:0.3f animations:^{
self.outdatedAlertContainer.alpha = 1;
self.suppressOutdatedAlert = YES;
}];
[activeUser saveContext];
});
if (![[MPiOSConfig get].actionsTipShown boolValue])
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
@ -686,19 +678,20 @@
if (!warning)
return;
[self changeActiveElementWithWarning:warning
do:^BOOL(MPElementEntity *activeElement) {
inf(@"Explicitly migrating element: %@", activeElement);
[activeElement migrateExplicitly:YES];
[self changeActiveElementWithWarning:warning do:
^BOOL(MPElementEntity *activeElement) {
inf(@"Explicitly migrating element: %@", activeElement);
[activeElement migrateExplicitly:YES];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointExplicitMigration];
[TestFlight passCheckpoint:MPCheckpointExplicitMigration];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointExplicitMigration
attributes:@{@"type" : activeElement.typeName,
@"version" : @(activeElement.version)}];
return YES;
}];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointExplicitMigration attributes:@{
@"type" : activeElement.typeName,
@"version" : @(activeElement.version)
}];
return YES;
}];
}
- (IBAction)searchOutdatedElements {
@ -736,63 +729,59 @@
- (IBAction)action:(id)sender {
[PearlSheet showSheetWithTitle:nil viewStyle:UIActionSheetStyleAutomatic
initSheet:nil
tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
if (buttonIndex == [sheet cancelButtonIndex])
return;
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
if (buttonIndex == [sheet cancelButtonIndex])
return;
switch (buttonIndex - [sheet firstOtherButtonIndex]) {
case 0: {
inf(@"Action: FAQ");
[self setHelpChapter:@"faq"];
[self setHelpHidden:NO animated:YES];
break;
}
case 1: {
inf(@"Action: Guide");
[[MPAppDelegate get] showGuide];
break;
}
case 2: {
inf(@"Action: Preferences");
[self performSegueWithIdentifier:@"MP_UserProfile" sender:self];
break;
}
case 3: {
inf(@"Action: Other Apps");
[self performSegueWithIdentifier:@"MP_OtherApps" sender:self];
break;
}
switch (buttonIndex - [sheet firstOtherButtonIndex]) {
case 0: {
inf(@"Action: FAQ");
[self setHelpChapter:@"faq"];
[self setHelpHidden:NO animated:YES];
break;
}
case 1: {
inf(@"Action: Guide");
[[MPAppDelegate get] showGuide];
break;
}
case 2: {
inf(@"Action: Preferences");
[self performSegueWithIdentifier:@"MP_UserProfile" sender:self];
break;
}
case 3: {
inf(@"Action: Other Apps");
[self performSegueWithIdentifier:@"MP_OtherApps" sender:self];
break;
}
//#if defined(ADHOC) && defined(TESTFLIGHT_SDK_VERSION)
// case 4: {
// inf(@"Action: Feedback via TestFlight");
// [TestFlight openFeedbackView];
// break;
// }
// case 5:
//#else
case 4: {
inf(@"Action: Feedback via Mail");
[[MPAppDelegate get] showFeedbackWithLogs:YES forVC:self];
break;
}
case 5:
case 4: {
inf(@"Action: Feedback via Mail");
[[MPAppDelegate get] showFeedbackWithLogs:YES forVC:self];
break;
}
//#endif
{
inf(@"Action: Sign out");
[[MPAppDelegate get] signOutAnimated:YES];
break;
}
default: {
wrn(@"Unsupported action: %u", buttonIndex - [sheet firstOtherButtonIndex]);
break;
}
}
}
default: {
wrn(@"Unsupported action: %u", buttonIndex - [sheet firstOtherButtonIndex]);
break;
}
}
}
cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil otherTitles:
@"FAQ", @"Tutorial", @"Preferences", @"Other Apps", @"Feedback", @"Sign Out",
nil];
@" FAQ",
@" Quick Guide",
@"⚙ Preferences",
@"⬇ Other Apps",
@"✉ Feedback",
nil];
}
- (MPElementType)selectedType {

View File

@ -114,8 +114,7 @@
else
if (cell == self.changeMPCell) {
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
[[MPAppDelegate get] changeMasterPasswordFor:activeUser didResetBlock:nil];
[activeUser saveContext];
[[MPAppDelegate get] changeMasterPasswordFor:activeUser inContext:activeUser.managedObjectContext didResetBlock:nil];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];

View File

@ -0,0 +1,24 @@
/**
* 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
*/
//
// MPSetupViewController.h
// MPSetupViewController
//
// Created by lhunath on 2013-04-11.
// Copyright, lhunath (Maarten Billemont) 2013. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MPSetupViewController : UIViewController
- (IBAction)close:(UIBarButtonItem *)sender;
- (IBAction)showGuide:(UIBarButtonItem *)sender;
@end

View File

@ -0,0 +1,38 @@
/**
* 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
*/
//
// MPSetupViewController.h
// MPSetupViewController
//
// Created by lhunath on 2013-04-11.
// Copyright, lhunath (Maarten Billemont) 2013. All rights reserved.
//
#import "MPSetupViewController.h"
#import "MPAppDelegate.h"
@implementation MPSetupViewController
- (IBAction)close:(UIBarButtonItem *)sender {
[MPiOSConfig get].showSetup = @NO;
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)showGuide:(UIBarButtonItem *)sender {
[MPiOSConfig get].showSetup = @NO;
[self dismissViewControllerAnimated:YES completion:^{
[[MPAppDelegate get] showGuide];
}];
}
@end

View File

@ -26,7 +26,7 @@
NSManagedObjectID *_selectedUserOID;
}
- (void)initializeAvatarAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user {
- (void)initializeAvatarAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc {
UIScrollView *alertAvatarScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(12, 30, 260, 150)];
alertAvatarScrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
@ -59,7 +59,7 @@
} options:0];
[avatar onSelect:^(BOOL selected) {
if (selected)
[user.managedObjectContext performBlock:^{
[moc performBlock:^{
user.avatar = (unsigned)avatar.tag;
}];
} options:0];
@ -164,9 +164,12 @@
- (void)viewWillAppear:(BOOL)animated {
inf(@"Lock screen will appear");
[self.navigationController setNavigationBarHidden:YES animated:animated];
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
inf(@"Lock screen will appear");
[[MPAppDelegate get] signOutAnimated:NO];
_selectedUserOID = nil;
[self updateUsers];
@ -196,6 +199,9 @@
inf(@"Lock screen will disappear");
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self.navigationController setNavigationBarHidden:NO animated:animated];
}];
[super viewWillDisappear:animated];
}
@ -288,7 +294,7 @@
[self.passwordField resignFirstResponder];
else
if ([[MPAppDelegate get] signInAsUser:selectedUser usingMasterPassword:nil]) {
[self dismissViewControllerAnimated:YES completion:nil];
[self performSegueWithIdentifier:@"MP_Unlock" sender:self];
return;
}
@ -301,19 +307,17 @@
- (void)didSelectNewUserAvatar:(UIButton *)newUserAvatar {
[MPAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
MPUserEntity *newUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class])
inManagedObjectContext:moc];
MPUserEntity *newUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class]) inManagedObjectContext:moc];
[self showNewUserNameAlertFor:newUser completion:^(BOOL finished) {
[self showNewUserNameAlertFor:newUser inContext:moc completion:^(BOOL finished) {
newUserAvatar.selected = NO;
if (finished)
[newUser saveContext];
self.selectedUser = newUser;
}];
}];
}
- (void)showNewUserNameAlertFor:(MPUserEntity *)newUser completion:(void (^)(BOOL finished))completion {
- (void)showNewUserNameAlertFor:(MPUserEntity *)newUser inContext:(NSManagedObjectContext *)moc
completion:(void (^)(BOOL finished))completion {
dispatch_async(dispatch_get_main_queue(), ^{
[PearlAlert showAlertWithTitle:@"Enter Your Name"
@ -333,40 +337,42 @@
if (![alert textFieldAtIndex:0].text.length) {
[PearlAlert showAlertWithTitle:@"Name Is Required" message:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
[newUser.managedObjectContext performBlock:^{
[self showNewUserNameAlertFor:newUser completion:completion];
[moc performBlock:^{
[self showNewUserNameAlertFor:newUser inContext:moc completion:completion];
}];
} cancelTitle:@"Try Again" otherTitles:nil];
return;
}
// Save
[newUser.managedObjectContext performBlock:^{
[moc performBlock:^{
newUser.name = [alert textFieldAtIndex:0].text;
[self showNewUserAvatarAlertFor:newUser completion:completion];
[self showNewUserAvatarAlertFor:newUser inContext:moc completion:completion];
}];
}
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonSave, nil];
});
}
- (void)showNewUserAvatarAlertFor:(MPUserEntity *)newUser completion:(void (^)(BOOL finished))completion {
- (void)showNewUserAvatarAlertFor:(MPUserEntity *)newUser inContext:(NSManagedObjectContext *)moc
completion:(void (^)(BOOL finished))completion {
[PearlAlert showAlertWithTitle:@"Choose Your Avatar"
message:@"\n\n\n\n\n\n" viewStyle:UIAlertViewStyleDefault
initAlert:^(UIAlertView *_alert, UITextField *_firstField) {
[self initializeAvatarAlert:_alert forUser:newUser];
[self initializeAvatarAlert:_alert forUser:newUser inContext:moc];
}
tappedButtonBlock:^(UIAlertView *_alert, NSInteger _buttonIndex) {
// Okay
[newUser.managedObjectContext performBlock:^{
[self showNewUserConfirmationAlertFor:newUser completion:completion];
[moc performBlock:^{
[self showNewUserConfirmationAlertFor:newUser inContext:moc completion:completion];
}];
} cancelTitle:nil otherTitles:[PearlStrings get].commonButtonOkay, nil];
}
- (void)showNewUserConfirmationAlertFor:(MPUserEntity *)newUser completion:(void (^)(BOOL finished))completion {
- (void)showNewUserConfirmationAlertFor:(MPUserEntity *)newUser inContext:(NSManagedObjectContext *)moc
completion:(void (^)(BOOL finished))completion {
[PearlAlert showAlertWithTitle:@"Is this correct?"
message:
@ -378,15 +384,15 @@
}
tappedButtonBlock:^void(UIAlertView *__alert, NSInteger __buttonIndex) {
if (__buttonIndex == [__alert cancelButtonIndex]) {
[newUser.managedObjectContext performBlock:^{
[self showNewUserNameAlertFor:newUser completion:completion];
[moc performBlock:^{
[self showNewUserNameAlertFor:newUser inContext:moc completion:completion];
}];
return;
}
// Confirm
[moc saveToStore];
completion(YES);
self.selectedUser = newUser;
[self updateUsers];
}
@ -556,7 +562,7 @@
dispatch_async(dispatch_get_main_queue(), ^{
if (unlocked)
[self dismissViewControllerAnimated:YES completion:nil];
[self performSegueWithIdentifier:@"MP_Unlock" sender:self];
else {
if (self.passwordField.text.length)
@ -782,6 +788,7 @@
if (!targetedUser)
return;
NSManagedObjectContext *moc = targetedUser.managedObjectContext;
[PearlSheet showSheetWithTitle:targetedUser.name
viewStyle:UIActionSheetStyleBlackTranslucent
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
@ -789,9 +796,9 @@
return;
if (buttonIndex == [sheet destructiveButtonIndex]) {
[targetedUser.managedObjectContext performBlock:^{
[targetedUser.managedObjectContext deleteObject:targetedUser];
[targetedUser saveContext];
[moc performBlock:^{
[moc deleteObject:targetedUser];
[moc saveToStore];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateUsers];
@ -801,7 +808,7 @@
}
if (buttonIndex == [sheet firstOtherButtonIndex])
[targetedUser.managedObjectContext performBlock:^{
[moc performBlock:^{
[[MPAppDelegate get] changeMasterPasswordFor:targetedUser didResetBlock:^{
dispatch_async(dispatch_get_main_queue(), ^{
[[self avatarForUser:targetedUser] setSelected:YES];

View File

@ -12,7 +12,7 @@
@property (nonatomic, retain) NSNumber *helpHidden;
@property (nonatomic, retain) NSNumber *siteInfoHidden;
@property (nonatomic, retain) NSNumber *showQuickStart;
@property (nonatomic, retain) NSNumber *showSetup;
@property (nonatomic, retain) NSNumber *actionsTipShown;
@property (nonatomic, retain) NSNumber *typeTipShown;
@property (nonatomic, retain) NSNumber *loginNameTipShown;

View File

@ -7,7 +7,7 @@
//
@implementation MPiOSConfig
@dynamic sendInfo, helpHidden, siteInfoHidden, showQuickStart, actionsTipShown, typeTipShown, loginNameTipShown;
@dynamic sendInfo, helpHidden, siteInfoHidden, showSetup, actionsTipShown, typeTipShown, loginNameTipShown;
- (id)init {
@ -16,7 +16,7 @@
[self.defaults registerDefaults:@{ NSStringFromSelector(@selector(helpHidden)): @NO,
NSStringFromSelector(@selector(siteInfoHidden)): @YES,
NSStringFromSelector(@selector(showQuickStart)): @YES,
NSStringFromSelector(@selector(showSetup)): @YES,
NSStringFromSelector(@selector(iTunesID)): @"510296984",
NSStringFromSelector(@selector(actionsTipShown)): PearlBoolNot(self.firstRun),
NSStringFromSelector(@selector(typeTipShown)): PearlBoolNot(self.firstRun),

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@
93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; };
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A28369954D147E239BA /* MPSetupViewController.m */; };
DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */; };
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 */; };
@ -750,6 +751,10 @@
DABD3C261711E2DC00CF925C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BFA1711E2DC00CF925C /* InfoPlist.strings */; };
DABD3C271711E2DC00CF925C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BFC1711E2DC00CF925C /* main.m */; };
DABD3FC717122ADD00CF925C /* libscrypt-bin-ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DABD3FC617122ADD00CF925C /* libscrypt-bin-ios.a */; };
DABD3FCA1712446200CF925C /* cloud.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD3FC81712446200CF925C /* cloud.png */; };
DABD3FCB1712446200CF925C /* cloud@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD3FC91712446200CF925C /* cloud@2x.png */; };
DABD3FCE1714F45C00CF925C /* identity.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD3FCC1714F45B00CF925C /* identity.png */; };
DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD3FCD1714F45B00CF925C /* identity@2x.png */; };
DAC6325E1486805C0075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DAC6326D148680650075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DAC632891486D9690075AEA5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC632871486D95D0075AEA5 /* Security.framework */; };
@ -938,6 +943,41 @@
remoteGlobalIDString = DA5BFA43147E415C00F98B1E;
remoteInfo = MasterPassword;
};
DA5A09D21714FA83005284AB /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DACA29C01705E313002C6C22 /* scrypt.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = D2AAC07E0554694100DB518D;
remoteInfo = scryptenc;
};
DA5A09D41714FA83005284AB /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DACA29C01705E313002C6C22 /* scrypt.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = A0511C5A127770FD00DE46C4;
remoteInfo = scryptcrypto;
};
DA5A09D61714FA83005284AB /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DACA29C01705E313002C6C22 /* scrypt.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = DA67FE5D14E4834300DB7CC9;
remoteInfo = util;
};
DA5A09D81714FA83005284AB /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DACA29C01705E313002C6C22 /* scrypt.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = DABD3E841711E7D600CF925C;
remoteInfo = "scrypt-bin-ios";
};
DA5A09DA1714FA83005284AB /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DACA29C01705E313002C6C22 /* scrypt.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = DABD3E9D1711E7E000CF925C;
remoteInfo = "scrypt-bin-osx";
};
DAC63283148681200075AEA5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */;
@ -974,6 +1014,8 @@
93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = "<group>"; };
93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = "<group>"; };
93D39730673227EFF6DEFF19 /* MPSetupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSetupViewController.h; sourceTree = "<group>"; };
93D39A28369954D147E239BA /* MPSetupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSetupViewController.m; sourceTree = "<group>"; };
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = "<group>"; };
93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlEMail.h; sourceTree = "<group>"; };
DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
@ -1735,7 +1777,11 @@
DABD3BF91711E2DC00CF925C /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
DABD3BFB1711E2DC00CF925C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
DABD3BFC1711E2DC00CF925C /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
DABD3FC617122ADD00CF925C /* libscrypt-bin-ios.a */ = {isa = PBXFileReference; lastKnownFileType = file; name = "libscrypt-bin-ios.a"; path = "../../../External/Pearl/External/iOSPorts/ports/security/scrypt/build/Release-iphoneos/libscrypt-bin-ios.a"; sourceTree = "<group>"; };
DABD3FC617122ADD00CF925C /* libscrypt-bin-ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libscrypt-bin-ios.a"; path = "../../../External/Pearl/External/iOSPorts/ports/security/scrypt/build/Release-iphoneos/libscrypt-bin-ios.a"; sourceTree = "<group>"; };
DABD3FC81712446200CF925C /* cloud.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cloud.png; sourceTree = "<group>"; };
DABD3FC91712446200CF925C /* cloud@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cloud@2x.png"; sourceTree = "<group>"; };
DABD3FCC1714F45B00CF925C /* identity.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = identity.png; sourceTree = "<group>"; };
DABD3FCD1714F45B00CF925C /* identity@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "identity@2x.png"; sourceTree = "<group>"; };
DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libuicolor-utilities.a"; sourceTree = BUILT_PRODUCTS_DIR; };
DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; };
DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
@ -2088,6 +2134,18 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
DA5A09C91714FA83005284AB /* Products */ = {
isa = PBXGroup;
children = (
DA5A09D31714FA83005284AB /* libscryptenc.a */,
DA5A09D51714FA83005284AB /* libscryptcrypto.a */,
DA5A09D71714FA83005284AB /* libutil.a */,
DA5A09D91714FA83005284AB /* libscrypt-bin-ios.a */,
DA5A09DB1714FA83005284AB /* libscrypt-bin-osx.a */,
);
name = Products;
sourceTree = "<group>";
};
DA5BFA39147E415C00F98B1E = {
isa = PBXGroup;
children = (
@ -2166,8 +2224,12 @@
DABD38751711E29700CF925C /* Tooltips */,
DABD38C41711E29700CF925C /* book.png */,
DABD38C51711E29700CF925C /* book@2x.png */,
DABD3FC81712446200CF925C /* cloud.png */,
DABD3FC91712446200CF925C /* cloud@2x.png */,
DABD38C61711E29700CF925C /* help.html */,
DABD38C71711E29700CF925C /* iTunesArtwork.png */,
DABD3FCC1714F45B00CF925C /* identity.png */,
DABD3FCD1714F45B00CF925C /* identity@2x.png */,
DABD38C81711E29700CF925C /* jquery-1.6.1.min.js */,
DABD38C91711E29700CF925C /* keypad.png */,
DABD38CA1711E29700CF925C /* logo-bare.png */,
@ -2944,6 +3006,8 @@
DABD3BF91711E2DC00CF925C /* Settings.bundle */,
DABD3BFA1711E2DC00CF925C /* InfoPlist.strings */,
DABD3BFC1711E2DC00CF925C /* main.m */,
93D39A28369954D147E239BA /* MPSetupViewController.m */,
93D39730673227EFF6DEFF19 /* MPSetupViewController.h */,
);
path = iOS;
sourceTree = "<group>";
@ -3769,6 +3833,12 @@
mainGroup = DA5BFA39147E415C00F98B1E;
productRefGroup = DA5BFA45147E415C00F98B1E /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = DA5A09C91714FA83005284AB /* Products */;
ProjectRef = DACA29C01705E313002C6C22 /* scrypt.xcodeproj */;
},
);
projectRoot = "";
targets = (
DA5BFA43147E415C00F98B1E /* MasterPassword */,
@ -3785,6 +3855,44 @@
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
DA5A09D31714FA83005284AB /* libscryptenc.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libscryptenc.a;
remoteRef = DA5A09D21714FA83005284AB /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
DA5A09D51714FA83005284AB /* libscryptcrypto.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libscryptcrypto.a;
remoteRef = DA5A09D41714FA83005284AB /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
DA5A09D71714FA83005284AB /* libutil.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libutil.a;
remoteRef = DA5A09D61714FA83005284AB /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
DA5A09D91714FA83005284AB /* libscrypt-bin-ios.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = "libscrypt-bin-ios.a";
remoteRef = DA5A09D81714FA83005284AB /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
DA5A09DB1714FA83005284AB /* libscrypt-bin-osx.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = "libscrypt-bin-osx.a";
remoteRef = DA5A09DA1714FA83005284AB /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
DA3EF17615A47744003ABF4E /* Resources */ = {
isa = PBXResourcesBuildPhase;
@ -4476,6 +4584,10 @@
DABD3C241711E2DC00CF925C /* MasterPassword.entitlements in Resources */,
DABD3C251711E2DC00CF925C /* Settings.bundle in Resources */,
DABD3C261711E2DC00CF925C /* InfoPlist.strings in Resources */,
DABD3FCA1712446200CF925C /* cloud.png in Resources */,
DABD3FCB1712446200CF925C /* cloud@2x.png in Resources */,
DABD3FCE1714F45C00CF925C /* identity.png in Resources */,
DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -4612,6 +4724,7 @@
DABD3C201711E2DC00CF925C /* MPUnlockViewController.m in Sources */,
DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */,
DABD3C271711E2DC00CF925C /* main.m in Sources */,
93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -5459,7 +5572,7 @@
DABD3BD31711E2DC00CF925C /* MasterPassword 3.xcdatamodel */,
DABD3BD41711E2DC00CF925C /* MasterPassword 4.xcdatamodel */,
);
currentVersion = DABD3BD11711E2DC00CF925C /* MasterPassword 1.xcdatamodel */;
currentVersion = DABD3BD41711E2DC00CF925C /* MasterPassword 4.xcdatamodel */;
path = MasterPassword.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB