diff --git a/MasterPassword/ObjC/iOS/MPAppViewController.m b/MasterPassword/ObjC/iOS/MPAppViewController.m deleted file mode 100644 index 4c7d3222..00000000 --- a/MasterPassword/ObjC/iOS/MPAppViewController.m +++ /dev/null @@ -1,41 +0,0 @@ -/** - * 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 - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPAppViewController -// -// Created by Maarten Billemont on 2012-08-31. -// Copyright 2012 lhunath (Maarten Billemont). All rights reserved. -// - -#import "MPAppViewController.h" - -@implementation MPAppViewController { -} - -- (IBAction)gorillas:(UIButton *)sender { - - MPCheckpoint( MPCheckpointApp, @{ - @"app" : @"gorillas" - } ); - - [UIApp openURL:[NSURL URLWithString:@"http://itunes.apple.com/app/lyndir/gorillas/id302275459?mt=8"]]; -} - -- (IBAction)deblock:(UIButton *)sender { - - MPCheckpoint( MPCheckpointApp, @{ - @"app" : @"deblock" - } ); - - [UIApp openURL:[NSURL URLWithString:@"http://itunes.apple.com/app/lyndir/deblock/id325058485?mt=8"]]; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPAppsViewController.h b/MasterPassword/ObjC/iOS/MPAppsViewController.h deleted file mode 100644 index 7664eb0a..00000000 --- a/MasterPassword/ObjC/iOS/MPAppsViewController.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * 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 - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPAppsViewController -// -// Created by Maarten Billemont on 2012-08-31. -// Copyright 2012 lhunath (Maarten Billemont). All rights reserved. -// - -#import - -@interface MPAppsViewController : UIViewController - -@property(weak, nonatomic) IBOutlet UIImageView *pagePositionView; - -- (IBAction)exit; - -@end diff --git a/MasterPassword/ObjC/iOS/MPAppsViewController.m b/MasterPassword/ObjC/iOS/MPAppsViewController.m deleted file mode 100644 index e0579e41..00000000 --- a/MasterPassword/ObjC/iOS/MPAppsViewController.m +++ /dev/null @@ -1,117 +0,0 @@ -/** - * 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 - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPAppsViewController -// -// Created by Maarten Billemont on 2012-08-31. -// Copyright 2012 lhunath (Maarten Billemont). All rights reserved. -// - -#import "MPAppsViewController.h" - -@interface MPAppsViewController() - -@property(nonatomic, strong) NSMutableArray *pageVCs; -@property(nonatomic, strong) UIPageViewController *pageViewController; - -@end - -@implementation MPAppsViewController { -} - -@synthesize pagePositionView = _pagePositionView; -@synthesize pageVCs = _pageVCs; -@synthesize pageViewController = _pageViewController; - -- (void)viewDidLoad { - - self.pageVCs = [NSMutableArray array]; - UIViewController *vc; - @try { - for (NSUInteger p = 0; - (vc = [self.storyboard instantiateViewControllerWithIdentifier:PearlString( @"MPAppViewController_%lu", (long)p )]); - ++p) - [self.pageVCs addObject:vc]; - } - @catch (NSException *e) { - if (![e.name isEqualToString:NSInvalidArgumentException]) - [e raise]; - } - - self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl - navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal - options:nil]; - self.pageViewController.dataSource = self; - self.pageViewController.delegate = self; - self.pageViewController.view.frame = CGRectFromOriginWithSize( CGPointZero, self.pagePositionView.bounds.size ); - [self addChildViewController:self.pageViewController]; - [self.pagePositionView addSubview:self.pageViewController.view]; - [self.pageViewController didMoveToParentViewController:self]; - - [super viewDidLoad]; -} - -- (void)viewWillAppear:(BOOL)animated { - - [UIApp setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide]; - MPCheckpoint( MPCheckpointApps, nil ); - - [self.pageViewController setViewControllers:@[ (self.pageVCs)[1] ] direction:UIPageViewControllerNavigationDirectionForward - animated:NO completion:nil]; - - [super viewWillAppear:animated]; -} - -- (void)viewDidAppear:(BOOL)animated { - - [self.pageViewController setViewControllers:@[ (self.pageVCs)[0] ] direction:UIPageViewControllerNavigationDirectionForward - animated:YES completion:nil]; - - [super viewDidAppear:animated]; -} - -- (void)viewWillDisappear:(BOOL)animated { - - [UIApp setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide]; - - [super viewWillDisappear:animated]; -} - -- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { - - return UIInterfaceOrientationPortrait; -} - -- (BOOL)shouldAutorotate { - - return NO; -} - -- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController - viewControllerBeforeViewController:(UIViewController *)viewController { - - NSUInteger vcIndex = [self.pageVCs indexOfObject:viewController]; - return (self.pageVCs)[(vcIndex + [self.pageVCs count] - 1) % self.pageVCs.count]; -} - -- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController - viewControllerAfterViewController:(UIViewController *)viewController { - - NSUInteger vcIndex = [self.pageVCs indexOfObject:viewController]; - return (self.pageVCs)[(vcIndex + 1) % self.pageVCs.count]; -} - -- (IBAction)exit { - - [self dismissViewControllerAnimated:YES completion:nil]; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPAvatarCell.m b/MasterPassword/ObjC/iOS/MPAvatarCell.m index b8056be1..8c4481f5 100644 --- a/MasterPassword/ObjC/iOS/MPAvatarCell.m +++ b/MasterPassword/ObjC/iOS/MPAvatarCell.m @@ -206,13 +206,11 @@ const long MPAvatarAdd = 10000; } switch (self.mode) { - case MPAvatarModeLowered: { - - self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height; - self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultLow; - self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow; - self.nameToCenterConstraint.priority = UILayoutPriorityDefaultLow; + [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height]; + [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; + [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; + [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; self.nameContainer.alpha = self.visibility; self.nameContainer.backgroundColor = [UIColor clearColor]; self.avatarImageView.alpha = self.visibility / 0.7f + 0.3f; @@ -220,10 +218,10 @@ const long MPAvatarAdd = 10000; break; } case MPAvatarModeRaisedButInactive: { - self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height; - self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultHigh; - self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow; - self.nameToCenterConstraint.priority = UILayoutPriorityDefaultLow; + [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height]; + [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; + [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; + [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; self.nameContainer.alpha = self.visibility; self.nameContainer.backgroundColor = [UIColor clearColor]; self.avatarImageView.alpha = 0; @@ -231,10 +229,10 @@ const long MPAvatarAdd = 10000; break; } case MPAvatarModeRaisedAndActive: { - self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height; - self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultHigh; - self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow; - self.nameToCenterConstraint.priority = UILayoutPriorityDefaultHigh; + [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height]; + [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; + [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; + [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; self.nameContainer.alpha = self.visibility; self.nameContainer.backgroundColor = [UIColor blackColor]; self.avatarImageView.alpha = 1; @@ -242,10 +240,10 @@ const long MPAvatarAdd = 10000; break; } case MPAvatarModeRaisedAndHidden: { - self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height; - self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultHigh; - self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow; - self.nameToCenterConstraint.priority = UILayoutPriorityDefaultHigh; + [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height]; + [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; + [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; + [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; self.nameContainer.alpha = 0; self.nameContainer.backgroundColor = [UIColor blackColor]; self.avatarImageView.alpha = 0; @@ -253,20 +251,16 @@ const long MPAvatarAdd = 10000; break; } case MPAvatarModeRaisedAndMinimized: { - self.avatarSizeConstraint.constant = 36; - self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultLow; - self.avatarToTopConstraint.priority = UILayoutPriorityDefaultHigh; - self.nameToCenterConstraint.priority = UILayoutPriorityDefaultHigh; + [self.avatarSizeConstraint layoutWithConstant:36]; + [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; + [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; + [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; self.nameContainer.alpha = 0; self.nameContainer.backgroundColor = [UIColor blackColor]; self.avatarImageView.alpha = 1; break; } } - [self.avatarSizeConstraint apply]; - [self.avatarRaisedConstraint apply]; - [self.avatarToTopConstraint apply]; - [self.nameToCenterConstraint apply]; // Avatar minimized. if (self.mode == MPAvatarModeRaisedAndMinimized) diff --git a/MasterPassword/ObjC/iOS/MPElementListAllViewController.h b/MasterPassword/ObjC/iOS/MPElementListAllViewController.h deleted file mode 100644 index 984cf97b..00000000 --- a/MasterPassword/ObjC/iOS/MPElementListAllViewController.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * 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 - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPElementListAllViewController -// -// Created by Maarten Billemont on 2013-01-31. -// Copyright 2013 lhunath (Maarten Billemont). All rights reserved. -// - -#import - -#import "MPElementListController.h" - -@interface MPElementListAllViewController : MPElementListController - -- (IBAction)close:(id)sender; -- (IBAction)add:(id)sender; - -@end diff --git a/MasterPassword/ObjC/iOS/MPElementListAllViewController.m b/MasterPassword/ObjC/iOS/MPElementListAllViewController.m deleted file mode 100644 index 6c46ff69..00000000 --- a/MasterPassword/ObjC/iOS/MPElementListAllViewController.m +++ /dev/null @@ -1,188 +0,0 @@ -/** - * 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 - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPElementListAllViewController -// -// Created by Maarten Billemont on 2013-01-31. -// Copyright 2013 lhunath (Maarten Billemont). All rights reserved. -// - -#import "MPElementListAllViewController.h" -#import "MPiOSAppDelegate.h" -#import "MPAppDelegate_Store.h" - -#define MPElementUpgradeOldContentKey @"MPElementUpgradeOldContentKey" -#define MPElementUpgradeNewContentKey @"MPElementUpgradeNewContentKey" - -@implementation MPElementListAllViewController - -- (BOOL)prefersStatusBarHidden { - - return NO; -} - -- (UIStatusBarStyle)preferredStatusBarStyle { - - return UIStatusBarStyleLightContent; -} - -- (void)viewWillAppear:(BOOL)animated { - - [super viewWillAppear:animated]; - - if ([self.filter isEqualToString:MPElementListFilterNone]) { - self.navigationItem.title = @"All Sites"; - self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] - initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add:)]; - } - else if ([self.filter isEqualToString:MPElementListFilterOutdated]) { - self.navigationItem.title = @"Outdated"; - self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] - initWithTitle:@"Upgrade All" style:UIBarButtonItemStyleBordered target:self action:@selector(upgradeAll:)]; - } - - [self updateData]; -} - -- (IBAction)close:(id)sender { - - [self dismissViewControllerAnimated:YES completion:nil]; -} - -- (IBAction)add:(id)sender { - - [PearlAlert showAlertWithTitle:@"Add Site" message:nil viewStyle:UIAlertViewStylePlainTextInput initAlert:nil - tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { - if (alert.cancelButtonIndex == buttonIndex) - return; - - __weak MPElementListAllViewController *wSelf = self; - [[MPiOSAppDelegate get] addElementNamed:[alert textFieldAtIndex:0].text completion:^(MPElementEntity *element) { - if (element) - PearlMainQueue( ^{ - [wSelf.delegate didSelectElement:element]; - [wSelf close:nil]; - } ); - }]; - } - cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonOkay, nil]; -} - -- (IBAction)upgradeAll:(id)sender { - - [PearlAlert showAlertWithTitle:@"Upgrading All Sites" - message:@"You are about to upgrade all outdated sites. This will cause passwords to change. " - @"Afterwards, you can get an overview of the changes." - viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock: - ^(UIAlertView *alert, NSInteger buttonIndex) { - if (buttonIndex == [alert cancelButtonIndex]) - return; - - PearlOverlay *activity = [PearlOverlay showProgressOverlayWithTitle:@"Upgrading Sites"]; - [self performUpgradeAllWithCompletion:^(BOOL success, NSDictionary *changes) { - dispatch_async( dispatch_get_main_queue(), ^{ - [self showUpgradeChanges:changes]; - [activity cancelOverlayAnimated:YES]; - } ); - }]; - } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil]; -} - -- (void)performUpgradeAllWithCompletion:(void (^)(BOOL success, NSDictionary *changes))completion { - - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) { - NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )]; - fetchRequest.fetchBatchSize = 20; - - NSError *error = nil; - NSArray *elements = [moc executeFetchRequest:fetchRequest error:&error]; - if (!elements) { - err(@"Failed to fetch outdated sites for upgrade: %@", error); - completion( NO, nil ); - return; - } - - MPKey *key = [MPAppDelegate_Shared get].key; - NSMutableDictionary *elementChanges = [NSMutableDictionary dictionaryWithCapacity:[elements count]]; - for (MPElementEntity *element in elements) { - id oldContent = [element.algorithm resolveContentForElement:element usingKey:key]; - [element migrateExplicitly:YES]; - id newContent = [element.algorithm resolveContentForElement:element usingKey:key]; - - if (!(element.type & MPElementFeatureDevicePrivate) && (!oldContent || ![oldContent isEqual:newContent])) - elementChanges[element.name] = @{ - MPElementUpgradeOldContentKey : oldContent, - MPElementUpgradeNewContentKey : newContent, - }; - } - - [moc saveToStore]; - completion( YES, elementChanges ); - }]; -} - -- (void)showUpgradeChanges:(NSDictionary *)changes { - - if (![changes count]) - return; - - NSMutableString *formattedChanges = [NSMutableString new]; - for (NSString *changedElementName in changes) { - NSDictionary *elementChanges = changes[changedElementName]; - id oldContent = elementChanges[MPElementUpgradeOldContentKey]; - id newContent = elementChanges[MPElementUpgradeNewContentKey]; - [formattedChanges appendFormat:@"%@: %@ -> %@\n", changedElementName, oldContent, newContent]; - } - - [PearlAlert showAlertWithTitle:@"Sites Upgraded" - message:PearlString( @"This upgrade has caused %lu passwords to change.\n" - @"To make updating the actual passwords of these accounts easier, " - @"you can email a summary of these changes to yourself.", (unsigned long)[changes count] ) - viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { - if (buttonIndex == [alert cancelButtonIndex]) - return; - - [PearlEMail sendEMailTo:nil fromVC:self subject:@"[Master Password] Upgrade Changes" body:formattedChanges]; - } cancelTitle:@"Don't Email" otherTitles:@"Send Email", nil]; -} - -- (NSFetchedResultsController *)fetchedResultsControllerByUses { - - return nil; -} - -- (void)configureFetchRequest:(NSFetchRequest *)fetchRequest { - - fetchRequest.fetchBatchSize = 10; -} - -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - - return 1; -} - -- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { - - return nil; -} - -- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { - - return nil; -} - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - - [super tableView:tableView didSelectRowAtIndexPath:indexPath]; - [self close:nil]; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPElementListCellView.xib b/MasterPassword/ObjC/iOS/MPElementListCellView.xib deleted file mode 100644 index c48cd027..00000000 --- a/MasterPassword/ObjC/iOS/MPElementListCellView.xib +++ /dev/null @@ -1,253 +0,0 @@ - - - - 1552 - 12D78 - 3084 - 1187.37 - 626.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 2083 - - - IBProxyObject - IBUIImageView - IBUILabel - IBUITableViewCell - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 1280 - - - - 1280 - - - - 1280 - - {{10, 4}, {38, 22}} - - - - 3 - MCAwAA - - NO - YES - 7 - YES - IBCocoaTouchFramework - Title - - 3 - MQA - - - 1 - MSAxIDEAA - - 0 - - 2 - 18 - - - Helvetica-Bold - 18 - 16 - - NO - - - - 1280 - - {{10, 26}, {47, 18}} - - - NO - YES - 7 - YES - IBCocoaTouchFramework - Subtitle - - 3 - MC42NjY2NjY2NjY3AA - - - 0 - - 1 - 14 - - - Helvetica - 14 - 16 - - NO - - - - {320, 47} - - - - NO - YES - 4 - YES - IBCocoaTouchFramework - - - - {320, 48} - - - - 3 - MAA - - IBCocoaTouchFramework - NO - 1 - 0.0 - - MPElementListCell - - - - - - - 274 - {320, 48} - _NS:9 - - NO - {{0.10000000000000001, 0.10000000000000001}, {0.79999999999999982, 0.79999999999999982}} - IBCocoaTouchFramework - - NSImage - ui_list_middle.png - - - - - - - - view - - - - 11 - - - - backgroundView - - - - 10 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - - - - - - - 5 - - - - - 6 - - - - - 8 - - - - - - - UIViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 11 - - - 0 - IBCocoaTouchFramework - YES - 3 - - ui_list_middle.png - {300, 34} - - 2083 - - diff --git a/MasterPassword/ObjC/iOS/MPElementListController.h b/MasterPassword/ObjC/iOS/MPElementListController.h deleted file mode 100644 index 170e926b..00000000 --- a/MasterPassword/ObjC/iOS/MPElementListController.h +++ /dev/null @@ -1,21 +0,0 @@ -#import - -#import "MPElementListDelegate.h" - -#define MPElementListFilterNone @"MPElementListFilterNone" -#define MPElementListFilterOutdated @"MPElementListFilterOutdated" - -@interface MPElementListController : UITableViewController - -@property(weak, nonatomic) IBOutlet id delegate; -@property(strong, nonatomic) NSString *filter; - -@property(readonly) NSFetchedResultsController *fetchedResultsControllerByUses; -@property(readonly) NSFetchedResultsController *fetchedResultsControllerByLastUsed; -@property(readonly) NSDateFormatter *dateFormatter; - -- (void)updateData; -- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atTableIndexPath:(NSIndexPath *)indexPath; -- (void)customTableViewUpdates; - -@end diff --git a/MasterPassword/ObjC/iOS/MPElementListController.m b/MasterPassword/ObjC/iOS/MPElementListController.m deleted file mode 100644 index edf657c6..00000000 --- a/MasterPassword/ObjC/iOS/MPElementListController.m +++ /dev/null @@ -1,279 +0,0 @@ -#import "MPElementListController.h" - -#import "MPAppDelegate_Store.h" -#import "MPiOSAppDelegate.h" - -@interface MPElementListController() -@end - -@implementation MPElementListController { - - NSFetchedResultsController *_fetchedResultsControllerByUses; - NSFetchedResultsController *_fetchedResultsControllerByLastUsed; - NSDateFormatter *_dateFormatter; -} - -- (void)viewDidLoad { - - [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - [self updateData]; - }]; - - [super viewDidLoad]; -} - -- (NSFetchedResultsController *)fetchedResultsControllerByLastUsed { - - NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must be accessed from the main thread."); - - if (!_fetchedResultsControllerByLastUsed) { - NSManagedObjectContext *context = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady]; - if (!context) - return nil; - - NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )]; - fetchRequest.sortDescriptors = @[ [[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector(lastUsed) ) ascending:NO] ]; - [self configureFetchRequest:fetchRequest]; - _fetchedResultsControllerByLastUsed = [[NSFetchedResultsController alloc] - initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil]; - _fetchedResultsControllerByLastUsed.delegate = self; - } - - return _fetchedResultsControllerByLastUsed; -} - -- (NSFetchedResultsController *)fetchedResultsControllerByUses { - - NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must be accessed from the main thread."); - - if (!_fetchedResultsControllerByUses) { - NSManagedObjectContext *context = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady]; - if (!context) - return nil; - - NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )]; - fetchRequest.sortDescriptors = @[ [[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector(uses_) ) ascending:NO] ]; - [self configureFetchRequest:fetchRequest]; - _fetchedResultsControllerByUses = [[NSFetchedResultsController alloc] - initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil]; - _fetchedResultsControllerByUses.delegate = self; - } - - return _fetchedResultsControllerByUses; -} - -- (void)configureFetchRequest:(NSFetchRequest *)fetchRequest { - - fetchRequest.fetchLimit = 5; -} - -- (NSDateFormatter *)dateFormatter { - - if (!_dateFormatter) - (_dateFormatter = [NSDateFormatter new]).dateStyle = NSDateFormatterShortStyle; - - return _dateFormatter; -} - -- (void)updateData { - - MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:self.fetchedResultsControllerByLastUsed.managedObjectContext]; - if (!activeUser) { - _fetchedResultsControllerByLastUsed = nil; - _fetchedResultsControllerByUses = nil; - [self.tableView reloadData]; - return; - } - - // Build predicate. - NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user == %@", activeUser]; - - // Add query predicate. - UISearchBar *searchBar = self.searchDisplayController.searchBar; - if (searchBar) { - NSString *query = [searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - if (!query) - return; - - predicate = [NSCompoundPredicate andPredicateWithSubpredicates: - @[ predicate, [NSPredicate predicateWithFormat:@"name BEGINSWITH[cd] %@", query] ]]; - } - - // Add filter predicate. - if ([self.filter isEqualToString:MPElementListFilterOutdated]) - predicate = [NSCompoundPredicate andPredicateWithSubpredicates: - @[ [NSPredicate predicateWithFormat:@"requiresExplicitMigration_ == YES"], predicate ]]; - - // Fetch - NSError *error; - self.fetchedResultsControllerByLastUsed.fetchRequest.predicate = predicate; - self.fetchedResultsControllerByUses.fetchRequest.predicate = predicate; - if (self.fetchedResultsControllerByLastUsed && ![self.fetchedResultsControllerByLastUsed performFetch:&error]) - err(@"Couldn't fetch elements: %@", error); - if (self.fetchedResultsControllerByUses && ![self.fetchedResultsControllerByUses performFetch:&error]) - err(@"Couldn't fetch elements: %@", error); - - [self.tableView reloadData]; -} - -- (void)customTableViewUpdates { -} - -// See MP-14, also crashes easily on internal assertions etc.. -//- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { -// -// [self.tableView beginUpdates]; -//} -// -//- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject -// atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { -// -// switch (type) { -// -// case NSFetchedResultsChangeInsert: -// [self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ] -// withRowAnimation:UITableViewRowAnimationAutomatic]; -// break; -// -// case NSFetchedResultsChangeDelete: -// [self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ] -// withRowAnimation:UITableViewRowAnimationAutomatic]; -// break; -// -// case NSFetchedResultsChangeUpdate: -// [self.tableView reloadRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ] -// withRowAnimation:UITableViewRowAnimationAutomatic]; -// break; -// -// case NSFetchedResultsChangeMove: -// [self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ] -// withRowAnimation:UITableViewRowAnimationAutomatic]; -// [self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ] -// withRowAnimation:UITableViewRowAnimationAutomatic]; -// break; -// } -//} - -- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { - -// [self customTableViewUpdates]; -// [self.tableView endUpdates]; - - [self.tableView reloadData]; -} - -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - - return 2; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - - if (section == 0) - return (NSInteger)[[[self.fetchedResultsControllerByLastUsed sections] lastObject] numberOfObjects]; - - if (section == 1) - return (NSInteger)[[[self.fetchedResultsControllerByUses sections] lastObject] numberOfObjects]; - - Throw(@"Unsupported section: %ld", (long)section); -} - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MPElementListCell"]; - if (!cell) - cell = (UITableViewCell *)[[UIViewController alloc] initWithNibName:@"MPElementListCellView" bundle:nil].view; - - [self configureCell:cell inTableView:tableView atTableIndexPath:indexPath]; - - return cell; -} - -- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atTableIndexPath:(NSIndexPath *)indexPath { - - MPElementEntity *element = [self elementForTableIndexPath:indexPath]; - - cell.textLabel.text = element.name; - cell.detailTextLabel.text = PearlString( @"%lu views, last on %@: %@", - (unsigned long)element.uses, [self.dateFormatter stringFromDate:element.lastUsed], - [element.algorithm shortNameOfType:element.type] ); -} - -- (NSIndexPath *)tableIndexPathForFetchController:(NSFetchedResultsController *)fetchedResultsController - indexPath:(NSIndexPath *)indexPath { - - if (fetchedResultsController == self.fetchedResultsControllerByLastUsed) - return [NSIndexPath indexPathForRow:indexPath.row inSection:0]; - if (fetchedResultsController == self.fetchedResultsControllerByUses) - return [NSIndexPath indexPathForRow:indexPath.row inSection:1]; - - Throw(@"Unknown fetched results controller: %@, for index path: %@", fetchedResultsController, indexPath); -} - -- (NSIndexPath *)fetchedIndexPathForTableIndexPath:(NSIndexPath *)indexPath { - - return [NSIndexPath indexPathForRow:indexPath.row inSection:0]; -} - -- (MPElementEntity *)elementForTableIndexPath:(NSIndexPath *)indexPath { - - if (indexPath.section == 0) - return [self.fetchedResultsControllerByLastUsed objectAtIndexPath:[self fetchedIndexPathForTableIndexPath:indexPath]]; - - if (indexPath.section == 1) - return [self.fetchedResultsControllerByUses objectAtIndexPath:[self fetchedIndexPathForTableIndexPath:indexPath]]; - - Throw(@"Unsupported section: %ld", (long)indexPath.section); -} - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - - [self.delegate didSelectElement:[self elementForTableIndexPath:indexPath]]; -} - -- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { - - if (section == 0) - return @"Most Recently Used"; - - if (section == 1) - return @"Most Commonly Used"; - - Throw(@"Unsupported section: %ld", (long)section); -} - -- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { - - return @[ @"recency", @"uses" ]; -} - -- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { - - return index; -} - -- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle -forRowAtIndexPath:(NSIndexPath *)indexPath { - - if (editingStyle == UITableViewCellEditingStyleDelete) { - NSManagedObjectID *elementOID = [self elementForTableIndexPath:indexPath].objectID; - [MPiOSAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) { - MPElementEntity *element = [MPElementEntity existingObjectWithID:elementOID inContext:context]; - if (!element) - return; - - inf(@"Deleting element: %@", element.name); - [context deleteObject:element]; - [context saveToStore]; - - MPCheckpoint( MPCheckpointDeleteElement, @{ - @"type" : NilToNSNull(element.typeName), - @"version" : @(element.version) - } ); - }]; - } -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPElementListDelegate.h b/MasterPassword/ObjC/iOS/MPElementListDelegate.h deleted file mode 100644 index a6dbaa7e..00000000 --- a/MasterPassword/ObjC/iOS/MPElementListDelegate.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * 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 - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPElementListDelegate -// -// Created by Maarten Billemont on 2013-01-31. -// Copyright 2013 lhunath (Maarten Billemont). All rights reserved. -// - -#import "MPElementEntity.h" - -@protocol MPElementListDelegate - -- (void)didSelectElement:(MPElementEntity *)element; - -@end diff --git a/MasterPassword/ObjC/iOS/MPElementListSearchController.h b/MasterPassword/ObjC/iOS/MPElementListSearchController.h deleted file mode 100644 index fd04adae..00000000 --- a/MasterPassword/ObjC/iOS/MPElementListSearchController.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// MPSearchDelegate.h -// MasterPassword -// -// Created by Maarten Billemont on 04/01/12. -// Copyright (c) 2012 Lyndir. All rights reserved. -// - -#import -#import "MPElementListController.h" - -@interface MPElementListSearchController : MPElementListController - -@property(strong, nonatomic) UILabel *tipView; - -@property(strong, nonatomic) IBOutlet UISearchDisplayController *searchDisplayController; -@property(weak, nonatomic) IBOutlet UIView *searchTipContainer; - -@end diff --git a/MasterPassword/ObjC/iOS/MPElementListSearchController.m b/MasterPassword/ObjC/iOS/MPElementListSearchController.m deleted file mode 100644 index 88b04629..00000000 --- a/MasterPassword/ObjC/iOS/MPElementListSearchController.m +++ /dev/null @@ -1,247 +0,0 @@ -// -// MPSearchDelegate.m -// MasterPassword -// -// Created by Maarten Billemont on 04/01/12. -// Copyright (c) 2012 Lyndir. All rights reserved. -// - -#import "MPElementListSearchController.h" -#import "MPMainViewController.h" -#import "MPiOSAppDelegate.h" -#import "MPAppDelegate_Store.h" - -@interface MPElementListSearchController() - -@property(nonatomic) BOOL newSiteSectionWasNeeded; - -@end - -@implementation MPElementListSearchController - -@synthesize searchDisplayController; - -- (id)init { - - if (!(self = [super init])) - return nil; - - self.tipView = [[UILabel alloc] initWithFrame:CGRectMake( 0, 0, 320, 170 )]; - self.tipView.textAlignment = NSTextAlignmentCenter; - self.tipView.backgroundColor = [UIColor clearColor]; - self.tipView.textColor = [UIColor lightTextColor]; - self.tipView.shadowColor = [UIColor blackColor]; - self.tipView.shadowOffset = CGSizeMake( 0, -1 ); - self.tipView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight - | UIViewAutoresizingFlexibleBottomMargin; - self.tipView.numberOfLines = 0; - self.tipView.font = [UIFont systemFontOfSize:14]; - self.tipView.text = - @"Tip:\n" - @"Name your sites by their domain name:\n" - @"apple.com, twitter.com\n\n" - @"For email accounts, use the address:\n" - @"john@apple.com, john@gmail.com"; - - return self; -} - -- (void)searchBarBookmarkButtonClicked:(UISearchBar *)searchBar { - - [((MPMainViewController *)self.delegate) performSegueWithIdentifier:@"MP_AllSites" sender:MPElementListFilterNone]; -} - -- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { - - // Simulate a tap on the first visible row. - UITableView *tableView = self.searchDisplayController.searchResultsTableView; - for (NSInteger section = 0; section < [self numberOfSectionsInTableView:tableView]; ++section) { - - if (![self tableView:tableView numberOfRowsInSection:section]) - continue; - - [self tableView:tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]]; - } -} - -- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller { - - controller.searchBar.text = @""; - - [UIView animateWithDuration:0.2f animations:^{ - self.searchTipContainer.alpha = 0; - }]; -} - -- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller { - - [self updateData]; -} - -- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller { - - controller.searchBar.prompt = nil; - controller.searchBar.searchResultsButtonSelected = NO; -} - -- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView { - - tableView.backgroundColor = [UIColor blackColor]; - tableView.separatorStyle = UITableViewCellSeparatorStyleNone; - tableView.rowHeight = 48.0f; - - self.tableView = tableView; -} - -- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { - - [self updateData]; - return NO; -} - -- (void)updateData { - - [super updateData]; - - UISearchBar *searchBar = self.searchDisplayController.searchBar; - CGRect searchBarFrame = searchBar.frame; - [searchBar.superview enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) { - - if ([subview isKindOfClass:[UIControl class]] && - CGPointEqualToPoint( - CGPointDistanceBetweenCGPoints( searchBarFrame.origin, subview.frame.origin ), - CGPointMake( 0, searchBarFrame.size.height ) )) { - dispatch_async( dispatch_get_main_queue(), ^{ - [self.tipView removeFromSuperview]; - [subview addSubview:self.tipView]; - } ); - - *stop = YES; - } - } recurse:NO]; -} - -- (BOOL)newSiteSectionNeeded { - - NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - if (![query length]) - return NO; - - __block BOOL hasExactQueryMatch = NO; - id sectionInfo = [[self.fetchedResultsControllerByUses sections] lastObject]; - [[sectionInfo objects] enumerateObjectsUsingBlock:^(id obj_, NSUInteger idx_, BOOL *stop_) { - if ([[obj_ name] isEqualToString:query]) { - hasExactQueryMatch = YES; - *stop_ = YES; - } - }]; - if (hasExactQueryMatch) - return NO; - - sectionInfo = [[self.fetchedResultsControllerByLastUsed sections] lastObject]; - [[sectionInfo objects] enumerateObjectsUsingBlock:^(id obj_, NSUInteger idx_, BOOL *stop_) { - if ([[obj_ name] isEqualToString:query]) { - hasExactQueryMatch = YES; - *stop_ = YES; - } - }]; - if (hasExactQueryMatch) - return NO; - - return YES; -} - -- (void)customTableViewUpdates { - - BOOL newSiteSectionIsNeeded = [self newSiteSectionNeeded]; - if (newSiteSectionIsNeeded && !self.newSiteSectionWasNeeded) - [self.tableView insertSections:[NSIndexSet indexSetWithIndex:2] - withRowAnimation:UITableViewRowAnimationAutomatic]; - else if (!newSiteSectionIsNeeded && self.newSiteSectionWasNeeded) - [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:2] - withRowAnimation:UITableViewRowAnimationAutomatic]; - self.newSiteSectionWasNeeded = newSiteSectionIsNeeded; -} - -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - - NSInteger sectionCount = [super numberOfSectionsInTableView:tableView]; - if ([self newSiteSectionNeeded]) - ++sectionCount; - - return sectionCount; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - - if (section < [super numberOfSectionsInTableView:tableView]) - // Section is one of super's sections. - return [super tableView:tableView numberOfRowsInSection:section]; - - return 1; -} - -- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atTableIndexPath:(NSIndexPath *)indexPath { - - if (indexPath.section < [super numberOfSectionsInTableView:tableView]) { - // Section is one of super's sections. - [super configureCell:cell inTableView:tableView atTableIndexPath:indexPath]; - return; - } - - // "New" section - NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - cell.textLabel.text = query; - cell.detailTextLabel.text = PearlString( @"New site: %@", - [MPAlgorithmDefault shortNameOfType:[[MPiOSAppDelegate get] activeUserForMainThread].defaultType] ); -} - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - - if (indexPath.section < [super numberOfSectionsInTableView:tableView]) { - // Section is one of super's sections. - [super tableView:tableView didSelectRowAtIndexPath:indexPath]; - return; - } - - // "New" section. - NSString *siteName - = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - - [PearlAlert showAlertWithTitle:@"New Site" - message:PearlString( @"Do you want to create a new site named:\n%@", siteName ) - viewStyle:UIAlertViewStyleDefault - initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { - [tableView deselectRowAtIndexPath:indexPath animated:YES]; - - if (buttonIndex == [alert cancelButtonIndex]) - return; - - __weak MPElementListController *wSelf = self; - [[MPiOSAppDelegate get] addElementNamed:siteName completion:^(MPElementEntity *element) { - if (element) - PearlMainQueue( ^{ - [wSelf.delegate didSelectElement:element]; - } ); - }]; - } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil]; -} - -- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { - - if (section < [super numberOfSectionsInTableView:tableView]) - // Section is one of super's sections. - return [super tableView:tableView titleForHeaderInSection:section]; - - return @"Create"; -} - -- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle -forRowAtIndexPath:(NSIndexPath *)indexPath { - - if (indexPath.section < [super numberOfSectionsInTableView:tableView]) - // Section is one of super's sections. - [super tableView:tableView commitEditingStyle:editingStyle forRowAtIndexPath:indexPath]; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPMainViewController.h b/MasterPassword/ObjC/iOS/MPMainViewController.h deleted file mode 100644 index dcd3a935..00000000 --- a/MasterPassword/ObjC/iOS/MPMainViewController.h +++ /dev/null @@ -1,74 +0,0 @@ -// -// MPMainViewController.h -// MasterPassword -// -// Created by Maarten Billemont on 24/11/11. -// Copyright (c) 2011 Lyndir. All rights reserved. -// - -#import -#import "MPTypeViewController.h" -#import "MPElementListSearchController.h" - -@interface MPMainViewController : UIViewController - -@property(assign, nonatomic) BOOL siteInfoHidden; -@property(strong, nonatomic) IBOutlet MPElementListSearchController *searchDelegate; -@property(strong, nonatomic) IBOutlet UIPanGestureRecognizer *pullDownGesture; -@property(strong, nonatomic) IBOutlet UIPanGestureRecognizer *pullUpGesture; -@property(weak, nonatomic) IBOutlet UITextField *contentField; -@property(weak, nonatomic) IBOutlet UIButton *typeButton; -@property(weak, nonatomic) IBOutlet UIWebView *helpView; -@property(weak, nonatomic) IBOutlet UILabel *siteName; -@property(weak, nonatomic) IBOutlet UILabel *passwordCounter; -@property(weak, nonatomic) IBOutlet UIButton *passwordIncrementer; -@property(weak, nonatomic) IBOutlet UIButton *passwordEdit; -@property(weak, nonatomic) IBOutlet UIButton *passwordUpgrade; -@property(weak, nonatomic) IBOutlet UIView *contentContainer; -@property(weak, nonatomic) IBOutlet UIView *displayContainer; -@property(weak, nonatomic) IBOutlet UIView *helpContainer; -@property(weak, nonatomic) IBOutlet UIView *contentTipContainer; -@property(weak, nonatomic) IBOutlet UIView *loginNameTipContainer; -@property(weak, nonatomic) IBOutlet UIView *alertContainer; -@property(weak, nonatomic) IBOutlet UILabel *alertTitle; -@property(weak, nonatomic) IBOutlet UITextView *alertBody; -@property(weak, nonatomic) IBOutlet UILabel *contentTipBody; -@property(weak, nonatomic) IBOutlet UILabel *loginNameTipBody; -@property(weak, nonatomic) IBOutlet UIImageView *toolTipEditIcon; -@property(weak, nonatomic) IBOutlet UIView *searchTipContainer; -@property(weak, nonatomic) IBOutlet UIView *actionsTipContainer; -@property(weak, nonatomic) IBOutlet UIView *typeTipContainer; -@property(weak, nonatomic) IBOutlet UIView *toolTipContainer; -@property(weak, nonatomic) IBOutlet UILabel *toolTipBody; -@property(weak, nonatomic) IBOutlet UIView *loginNameContainer; -@property(weak, nonatomic) IBOutlet UITextField *loginNameField; -@property(weak, nonatomic) IBOutlet UIButton *passwordUser; -@property(weak, nonatomic) IBOutlet UIView *outdatedAlertContainer; -@property(weak, nonatomic) IBOutlet UIImageView *outdatedAlertBack; -@property(weak, nonatomic) IBOutlet UIButton *outdatedAlertCloseButton; -@property(weak, nonatomic) IBOutlet UIImageView *pullUpView; -@property(weak, nonatomic) IBOutlet UIImageView *pullDownView; - -@property(copy, nonatomic) void (^contentTipCleanup)(BOOL finished); -@property(copy, nonatomic) void (^toolTipCleanup)(BOOL finished); - -- (IBAction)copyContent; -- (IBAction)incrementPasswordCounter; -- (IBAction)resetPasswordCounter:(UILongPressGestureRecognizer *)sender; -- (IBAction)editLoginName:(UILongPressGestureRecognizer *)sender; -- (IBAction)editPassword; -- (IBAction)closeAlert; -- (IBAction)upgradePassword; -- (IBAction)action:(UIBarButtonItem *)sender; -- (IBAction)toggleUser; -- (IBAction)searchOutdatedElements; -- (IBAction)closeOutdatedAlert; -- (IBAction)infoOutdatedAlert; - -- (void)toggleHelpAnimated:(BOOL)animated; -- (void)setHelpHidden:(BOOL)hidden animated:(BOOL)animated; -- (void)setHelpChapter:(NSString *)chapter; -- (IBAction)panHelpDown:(UIPanGestureRecognizer *)sender; -- (IBAction)panHelpUp:(UIPanGestureRecognizer *)sender; - -@end diff --git a/MasterPassword/ObjC/iOS/MPMainViewController.m b/MasterPassword/ObjC/iOS/MPMainViewController.m deleted file mode 100644 index 60010de0..00000000 --- a/MasterPassword/ObjC/iOS/MPMainViewController.m +++ /dev/null @@ -1,887 +0,0 @@ -// -// MPMainViewController.m -// MasterPassword -// -// Created by Maarten Billemont on 24/11/11. -// Copyright (c) 2011 Lyndir. All rights reserved. -// - -#import "MPMainViewController.h" -#import "MPiOSAppDelegate.h" -#import "MPAppDelegate_Store.h" -#import "MPElementListAllViewController.h" - -@interface MPMainViewController() - -@property(nonatomic) BOOL suppressOutdatedAlert; -@end - -@implementation MPMainViewController { - NSManagedObjectID *_activeElementOID; -} - -#pragma mark - View lifecycle - -- (BOOL)shouldAutorotate { - - return YES; -} - -- (NSUInteger)supportedInterfaceOrientations { - - return UIInterfaceOrientationMaskAllButUpsideDown; -} - -- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { - - return UIInterfaceOrientationPortrait; -} - -- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - - [self updateHelpHiddenAnimated:NO]; - [self updateUserHiddenAnimated:NO]; -} - -- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - - if ([[segue identifier] isEqualToString:@"MP_ChooseType"]) - ((MPTypeViewController *)[segue destinationViewController]).delegate = self; - if ([[segue identifier] isEqualToString:@"MP_AllSites"]) { - ((MPElementListAllViewController *)[[segue destinationViewController] topViewController]).delegate = self; - ((MPElementListAllViewController *)[[segue destinationViewController] topViewController]).filter = sender; - } -} - -- (void)viewDidLoad { - - self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui_background"]]; - - self.alertBody.text = nil; - self.toolTipEditIcon.hidden = YES; - - [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:self queue:nil usingBlock: - ^(NSNotification *note) { - self.suppressOutdatedAlert = NO; - }]; - [[NSNotificationCenter defaultCenter] addObserverForName:MPElementUpdatedNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - MPElementEntity *activeElement = [self activeElementForMainThread]; - if (activeElement.type & MPElementTypeClassStored && - ![[activeElement.algorithm resolveContentForElement:activeElement usingKey:[MPAppDelegate_Shared get].key] length]) - [self showToolTip:@"Tap to set a password." withIcon:self.toolTipEditIcon]; - if (activeElement.requiresExplicitMigration) - [self showToolTip:@"Password outdated. Tap to upgrade it." withIcon:nil]; - }]; - [[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - BOOL animated = [(note.userInfo)[@"animated"] boolValue]; - - _activeElementOID = nil; - self.suppressOutdatedAlert = NO; - [self updateAnimated:NO]; - - [[[PearlSheet activeSheets] copy] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - [obj cancelSheetAnimated:NO]; - }]; - if (![self.navigationController presentedViewController]) - [self.navigationController popToRootViewControllerAnimated:animated]; - else - [self.navigationController dismissViewControllerAnimated:animated completion:^{ - [self.navigationController popToRootViewControllerAnimated:animated]; - }]; - }]; - [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - if (!self.activeElementForMainThread) - [self didSelectElement:nil]; - }]; - - [super viewDidLoad]; -} - -- (void)viewWillAppear:(BOOL)animated { - - if (![super respondsToSelector:@selector(prefersStatusBarHidden)]) - [UIApp setStatusBarHidden:NO withAnimation:animated? UIStatusBarAnimationSlide: UIStatusBarAnimationNone]; - [self.navigationController setNavigationBarHidden:NO animated:animated]; - - MPElementEntity *activeElement = [self activeElementForMainThread]; - if (activeElement.user != [[MPiOSAppDelegate get] activeUserForMainThread]) - _activeElementOID = nil; - - self.searchDisplayController.searchBar.text = nil; - self.alertContainer.hidden = NO; - self.outdatedAlertContainer.hidden = NO; - self.searchTipContainer.hidden = NO; - self.actionsTipContainer.hidden = NO; - self.typeTipContainer.hidden = NO; - self.toolTipContainer.hidden = NO; - self.contentTipContainer.hidden = NO; - self.loginNameTipContainer.hidden = NO; - - [self updateAnimated:NO]; - - [super viewWillAppear:animated]; -} - -- (void)viewDidAppear:(BOOL)animated { - - inf(@"Main will appear"); - - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) { - MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc]; - if ([MPAlgorithmDefault migrateUser:activeUser inContext:moc] && !self.suppressOutdatedAlert) - [UIView animateWithDuration:0.3f animations:^{ - self.outdatedAlertContainer.alpha = 1; - self.suppressOutdatedAlert = YES; - }]; - [moc saveToStore]; - }]; - - if (![[MPiOSConfig get].actionsTipShown boolValue]) - [UIView animateWithDuration:animated? 0.3f: 0 animations:^{ - self.actionsTipContainer.alpha = 1; - } completion:^(BOOL finished) { - if (!finished) - return; - - [MPiOSConfig get].actionsTipShown = @YES; - - dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ), dispatch_get_main_queue(), ^{ - [UIView animateWithDuration:0.2f animations:^{ - self.actionsTipContainer.alpha = 0; - } completion:^(BOOL finished_) { - if (!_activeElementOID) - [UIView animateWithDuration:animated? 0.3f: 0 animations:^{ - self.searchTipContainer.alpha = 1; - }]; - }]; - } ); - }]; - - [super viewDidAppear:animated]; -} - -- (void)viewWillDisappear:(BOOL)animated { - - inf(@"Main will disappear."); - [super viewWillDisappear:animated]; -} - -- (void)updateAnimated:(BOOL)animated { - - if (animated) { - [UIView animateWithDuration:0.3f animations:^{ - [self updateAnimated:NO]; - }]; - return; - } - - MPElementEntity *activeElement = [self activeElementForMainThread]; - [self setHelpChapter:activeElement? @"2": @"1"]; - [self updateHelpHiddenAnimated:NO]; - - self.passwordCounter.alpha = 0; - self.passwordIncrementer.alpha = 0; - self.passwordEdit.alpha = 0; - self.passwordUpgrade.alpha = 0; - self.passwordUser.alpha = 0; - self.displayContainer.alpha = 0; - - if (activeElement) { - self.passwordUser.alpha = 0.5f; - self.displayContainer.alpha = 1.0f; - } - - if (activeElement.requiresExplicitMigration) - self.passwordUpgrade.alpha = 0.5f; - - else { - if (activeElement.type & MPElementTypeClassGenerated) { - self.passwordCounter.alpha = 0.5f; - self.passwordIncrementer.alpha = 0.5f; - } - else if (activeElement.type & MPElementTypeClassStored) - self.passwordEdit.alpha = 0.5f; - } - - self.siteName.text = activeElement.name; - - self.typeButton.alpha = activeElement? 1: 0; - [self.typeButton setTitle:activeElement.typeName - forState:UIControlStateNormal]; - - if ([activeElement isKindOfClass:[MPElementGeneratedEntity class]]) - self.passwordCounter.text = PearlString( @"%lu", (unsigned long)((MPElementGeneratedEntity *)activeElement).counter ); - - self.contentField.enabled = NO; - self.contentField.text = @""; - if (activeElement.name && ![activeElement isDeleted]) - [activeElement.algorithm resolveContentForElement:activeElement usingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) { - dispatch_async( dispatch_get_main_queue(), ^{ - self.contentField.text = result; - } ); - }]; - - self.loginNameField.enabled = NO; - self.loginNameField.text = activeElement.loginName; - self.siteInfoHidden = !activeElement || ([[MPiOSConfig get].siteInfoHidden boolValue] && (activeElement.loginName == nil)); - [self updateUserHiddenAnimated:NO]; -} - -- (void)toggleHelpAnimated:(BOOL)animated { - - [self setHelpHidden:![[MPiOSConfig get].helpHidden boolValue] animated:animated]; -} - -- (void)setHelpHidden:(BOOL)hidden animated:(BOOL)animated { - - [MPiOSConfig get].helpHidden = @(hidden); - [self updateHelpHiddenAnimated:animated]; -} - -- (void)updateHelpHiddenAnimated:(BOOL)animated { - - if (animated) { - [UIView animateWithDuration:0.3f animations:^{ - [self updateHelpHiddenAnimated:NO]; - }]; - return; - } - - self.pullUpView.hidden = ![[MPiOSConfig get].helpHidden boolValue]; - self.pullDownView.hidden = [[MPiOSConfig get].helpHidden boolValue]; - - if ([[MPiOSConfig get].helpHidden boolValue]) { - self.contentContainer.frame = CGRectSetHeight( self.contentContainer.frame, self.view.bounds.size.height - 44 /* search bar */); - self.helpContainer.frame = CGRectSetY( self.helpContainer.frame, self.view.bounds.size.height - 20 /* pull-up */); - } - else { - self.contentContainer.frame = CGRectSetHeight( self.contentContainer.frame, 225 ); - [self.helpContainer setFrameFromCurrentSizeAndParentPaddingTop:CGFLOAT_MAX right:0 bottom:0 left:0]; - } -} - -- (IBAction)toggleUser { - - [self toggleUserAnimated:YES]; -} - -- (void)toggleUserAnimated:(BOOL)animated { - - [MPiOSConfig get].siteInfoHidden = @(!self.siteInfoHidden); - self.siteInfoHidden = [[MPiOSConfig get].siteInfoHidden boolValue]; - [self updateUserHiddenAnimated:animated]; -} - -- (void)updateUserHiddenAnimated:(BOOL)animated { - - if (animated) { - [UIView animateWithDuration:0.3f animations:^{ - [self updateUserHiddenAnimated:NO]; - }]; - return; - } - - if (self.siteInfoHidden) { - self.displayContainer.frame = CGRectSetHeight( self.displayContainer.frame, 87 ); - } - else { - self.displayContainer.frame = CGRectSetHeight( self.displayContainer.frame, 137 ); - } -} - -- (void)setHelpChapter:(NSString *)chapter { - - MPCheckpoint( MPCheckpointHelpChapter, @{ - @"chapter" : NilToNSNull(chapter) - } ); - - dispatch_async( dispatch_get_main_queue(), ^{ - NSURL *url = [NSURL URLWithString:[@"#" stringByAppendingString:chapter] - relativeToURL:[[NSBundle mainBundle] URLForResource:@"help" withExtension:@"html"]]; - [self.helpView loadRequest:[NSURLRequest requestWithURL:url]]; - } ); -} - -- (IBAction)panHelpDown:(UIPanGestureRecognizer *)sender { - - CGFloat targetY = MIN(self.view.bounds.size.height - 20, 246 + [sender translationInView:self.helpContainer].y); - BOOL hideHelp = YES; - if (targetY <= 246) { - hideHelp = NO; - targetY = 246; - } - - self.helpContainer.frame = CGRectSetY( self.helpContainer.frame, targetY ); - - if (sender.state == UIGestureRecognizerStateEnded) - [self setHelpHidden:hideHelp animated:YES]; -} - -- (IBAction)panHelpUp:(UIPanGestureRecognizer *)sender { - - CGFloat targetY = MAX(246, self.view.bounds.size.height - 20 + [sender translationInView:self.helpContainer].y); - BOOL hideHelp = NO; - if (targetY >= self.view.bounds.size.height - 20) { - hideHelp = YES; - targetY = self.view.bounds.size.height - 20; - } - - self.helpContainer.frame = CGRectSetY( self.helpContainer.frame, targetY ); - - if (sender.state == UIGestureRecognizerStateEnded) - [self setHelpHidden:hideHelp animated:YES]; -} - -- (void)webViewDidFinishLoad:(UIWebView *)webView { - - MPElementEntity *activeElement = [self activeElementForMainThread]; - NSString *error = [self.helpView stringByEvaluatingJavaScriptFromString: - PearlString( @"setClass('%@');", activeElement.typeClassName )]; - if (error.length) - err(@"helpView.setClass: %@", error); -} - -- (void)showContentTip:(NSString *)message withIcon:(UIImageView *)icon { - - dispatch_async( dispatch_get_main_queue(), ^{ - if (self.contentTipCleanup) - self.contentTipCleanup( NO ); - - __weak MPMainViewController *wSelf = self; - self.contentTipBody.text = message; - self.contentTipCleanup = ^(BOOL finished) { - icon.hidden = YES; - wSelf.contentTipCleanup = nil; - }; - - icon.hidden = NO; - [UIView animateWithDuration:0.3f animations:^{ - self.contentTipContainer.alpha = 1; - } completion:^(BOOL finished) { - if (finished) { - dispatch_time_t popTime = dispatch_time( DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC ); - dispatch_after( popTime, dispatch_get_main_queue(), ^(void) { - [UIView animateWithDuration:0.2f animations:^{ - self.contentTipContainer.alpha = 0; - } completion:self.contentTipCleanup]; - } ); - } - }]; - } ); -} - -- (void)showLoginNameTip:(NSString *)message { - - dispatch_async( dispatch_get_main_queue(), ^{ - self.loginNameTipBody.text = message; - - [UIView animateWithDuration:0.3f animations:^{ - self.loginNameTipContainer.alpha = 1; - } completion:^(BOOL finished) { - if (finished) { - dispatch_time_t popTime = dispatch_time( DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC ); - dispatch_after( popTime, dispatch_get_main_queue(), ^(void) { - [UIView animateWithDuration:0.2f animations:^{ - self.loginNameTipContainer.alpha = 0; - }]; - } ); - } - }]; - } ); -} - -- (void)showToolTip:(NSString *)message withIcon:(UIImageView *)icon { - - dispatch_async( dispatch_get_main_queue(), ^{ - if (self.toolTipCleanup) - self.toolTipCleanup( NO ); - - __weak MPMainViewController *wSelf = self; - self.toolTipBody.text = message; - self.toolTipCleanup = ^(BOOL finished) { - icon.hidden = YES; - wSelf.toolTipCleanup = nil; - }; - - icon.hidden = NO; - [UIView animateWithDuration:0.3f animations:^{ - self.toolTipContainer.alpha = 1; - } completion:^(BOOL finished) { - if (finished) { - dispatch_time_t popTime = dispatch_time( DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC ); - dispatch_after( popTime, dispatch_get_main_queue(), ^(void) { - [UIView animateWithDuration:0.2f animations:^{ - self.toolTipContainer.alpha = 0; - } completion:self.toolTipCleanup]; - } ); - } - }]; - } ); -} - -- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message { - - dispatch_async( dispatch_get_main_queue(), ^{ - self.alertTitle.text = title; - NSRange scrollRange = NSMakeRange( self.alertBody.text.length, message.length ); - if ([self.alertBody.text length]) - self.alertBody.text = [NSString stringWithFormat:@"%@\n\n---\n\n%@", self.alertBody.text, message]; - else - self.alertBody.text = message; - [self.alertBody scrollRangeToVisible:scrollRange]; - - [UIView animateWithDuration:0.3f animations:^{ - self.alertContainer.alpha = 1; - }]; - } ); -} - -#pragma mark - Protocols - -- (IBAction)copyContent { - - MPElementEntity *activeElement = [self activeElementForMainThread]; - inf(@"Copying password for: %@", activeElement.name); - MPCheckpoint( MPCheckpointCopyToPasteboard, @{ - @"type" : NilToNSNull(activeElement.typeName), - @"version" : @(activeElement.version), - @"emergency" : @NO - } ); - - [activeElement.algorithm resolveContentForElement:activeElement usingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) { - if (!result) - // Nothing to copy. - return; - - [UIPasteboard generalPasteboard].string = result; - [self showContentTip:@"Copied!" withIcon:nil]; - }]; -} - -- (IBAction)copyLoginName:(UITapGestureRecognizer *)sender { - - MPElementEntity *activeElement = [self activeElementForMainThread]; - if (!activeElement.loginName) - return; - - inf(@"Copying user name for: %@", activeElement.name); - [UIPasteboard generalPasteboard].string = activeElement.loginName; - - [self showLoginNameTip:@"Copied!"]; - - MPCheckpoint( MPCheckpointCopyLoginNameToPasteboard, @{ - @"type" : NilToNSNull(activeElement.typeName), - @"version" : @(activeElement.version) - } ); -} - -- (IBAction)incrementPasswordCounter { - - [self changeActiveElementWithWarning: - @"You are incrementing the site's password counter.\n\n" - @"If you continue, a new password will be generated for this site. " - @"You will then need to update your account's old password to this newly generated password.\n\n" - @"You can reset the counter by holding down on this button." - do:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) { - if (![activeElement isKindOfClass:[MPElementGeneratedEntity class]]) { - // Not of a type that supports a password counter. - err(@"Cannot increment password counter: Element is not generated: %@", activeElement.name); - return NO; - } - MPElementGeneratedEntity *activeGeneratedElement = (MPElementGeneratedEntity *)activeElement; - - inf(@"Incrementing password counter for: %@", activeGeneratedElement.name); - ++activeGeneratedElement.counter; - - MPCheckpoint( MPCheckpointIncrementPasswordCounter, @{ - @"type" : NilToNSNull(activeGeneratedElement.typeName), - @"version" : @(activeGeneratedElement.version), - @"counter" : @(activeGeneratedElement.counter) - } ); - return YES; - }]; -} - -- (IBAction)resetPasswordCounter:(UILongPressGestureRecognizer *)sender { - - if (sender.state != UIGestureRecognizerStateBegan) - // Only fire when the gesture was first detected. - return; - MPElementEntity *activeElement = [self activeElementForMainThread]; - if (![activeElement isKindOfClass:[MPElementGeneratedEntity class]]) { - // Not of a type that supports a password counter. - err(@"Cannot reset password counter: Element is not generated: %@", activeElement.name); - return; - } - else if (((MPElementGeneratedEntity *)activeElement).counter == 1) - // Counter has initial value, no point resetting. - return; - - [self changeActiveElementWithWarning: - @"You are resetting the site's password counter.\n\n" - @"If you continue, the site's password will change back to its original value. " - @"You will then need to update your account's password back to this original value." - do:^BOOL(MPElementEntity *activeElement_, NSManagedObjectContext *context) { - inf(@"Resetting password counter for: %@", activeElement_.name); - ((MPElementGeneratedEntity *)activeElement_).counter = 1; - - MPCheckpoint( MPCheckpointResetPasswordCounter, @{ - @"type" : NilToNSNull(activeElement_.typeName), - @"version" : @(activeElement_.version) - } ); - return YES; - }]; -} - -- (IBAction)editLoginName:(UILongPressGestureRecognizer *)sender { - - if (sender.state != UIGestureRecognizerStateBegan) - // Only fire when the gesture was first detected. - return; - - MPElementEntity *activeElement = [self activeElementForMainThread]; - if (!activeElement) - return; - - self.loginNameField.enabled = YES; - [self.loginNameField becomeFirstResponder]; - - MPCheckpoint( MPCheckpointEditLoginName, @{ - @"type" : NilToNSNull(activeElement.typeName), - @"version" : @(activeElement.version) - } ); -} - -- (void)changeActiveElementWithWarning:(NSString *)warning - do:(BOOL (^)(MPElementEntity *activeElement, NSManagedObjectContext *context))task { - - [PearlAlert showAlertWithTitle:@"Password Change" message:warning viewStyle:UIAlertViewStyleDefault - initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { - if (buttonIndex == [alert cancelButtonIndex]) - return; - - [self changeActiveElementWithoutWarningDo:task]; - } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil]; -} - -- (void)changeActiveElementWithoutWarningDo:(BOOL (^)(MPElementEntity *, NSManagedObjectContext *context))task { - - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - MPElementEntity *activeElement = [self activeElementInContext:context]; - if (!activeElement) - return; - - MPKey *key = [MPAppDelegate_Shared get].key; - NSString *oldPassword = [activeElement.algorithm resolveContentForElement:activeElement usingKey:key]; - if (!task( activeElement, context )) - return; - - activeElement = [self activeElementInContext:context]; - NSString *newPassword = [activeElement.algorithm resolveContentForElement:activeElement usingKey:key]; - - // Save. - [context saveToStore]; - - // 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 )]; - } ); - }]; -} - -- (MPElementEntity *)activeElementForMainThread { - - return [self activeElementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]; -} - -- (MPElementEntity *)activeElementInContext:(NSManagedObjectContext *)moc { - - if (!_activeElementOID) - return nil; - - NSError *error; - MPElementEntity *activeElement = (MPElementEntity *)[moc existingObjectWithID:_activeElementOID error:&error]; - if (!activeElement) - err(@"Couldn't retrieve active element: %@", error); - - return activeElement; -} - -- (IBAction)editPassword { - - MPElementEntity *activeElement = [self activeElementForMainThread]; - if (!(activeElement.type & MPElementTypeClassStored)) { - // Not of a type that supports editing the content. - err(@"Cannot edit content: Element is not stored: %@", activeElement.name); - return; - } - - self.contentField.enabled = YES; - [self.contentField becomeFirstResponder]; - - MPCheckpoint( MPCheckpointEditPassword, @{ - @"type" : NilToNSNull(activeElement.typeName), - @"version" : @(activeElement.version) - } ); -} - -- (IBAction)upgradePassword { - - MPElementEntity *activeElement = [self activeElementForMainThread]; - if (!activeElement) - return; - - NSString *warning = activeElement.type & MPElementTypeClassGenerated? - @"You are upgrading the site.\n\n" - @"This upgrade improves the site's compatibility with the latest version of Master Password.\n\n" - @"Your password will change and you will need to update your site's account." - : - @"You are upgrading the site.\n\n" - @"This upgrade improves the site's compatibility with the latest version of Master Password."; - - [self changeActiveElementWithWarning:warning do: - ^BOOL(MPElementEntity *activeElement_, NSManagedObjectContext *context) { - inf(@"Explicitly migrating element: %@", activeElement_); - [activeElement_ migrateExplicitly:YES]; - - MPCheckpoint( MPCheckpointExplicitMigration, @{ - @"type" : NilToNSNull(activeElement_.typeName), - @"version" : @(activeElement_.version) - } ); - return YES; - }]; -} - -- (IBAction)searchOutdatedElements { - - [self performSegueWithIdentifier:@"MP_AllSites" sender:MPElementListFilterOutdated]; -} - -- (IBAction)closeAlert { - - [UIView animateWithDuration:0.3f animations:^{ - self.alertContainer.alpha = 0; - } completion:^(BOOL finished) { - if (finished) - self.alertBody.text = nil; - }]; -} - -- (IBAction)closeOutdatedAlert { - - [UIView animateWithDuration:0.3f animations:^{ - self.outdatedAlertContainer.alpha = 0; - }]; -} - -- (IBAction)infoOutdatedAlert { - - [self setHelpChapter:@"outdated"]; - [self setHelpHidden:NO animated:YES]; - [self closeOutdatedAlert]; - self.suppressOutdatedAlert = NO; -} - -- (IBAction)action:(id)sender { - - [PearlSheet showSheetWithTitle:nil viewStyle:UIActionSheetStyleAutomatic - 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 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; -// } -//#else - case 4: { - inf(@"Action: Feedback via Mail"); - [[MPiOSAppDelegate get] showFeedbackWithLogs:YES forVC:self]; - break; - } -//#endif - - default: { - wrn(@"Unsupported action: %ld", (long)(buttonIndex - [sheet firstOtherButtonIndex])); - break; - } - } - } - cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil otherTitles: - @"FAQ", - @"Overview", - @"User Profile", - @"Other Apps", - @"Feedback", - nil]; -} - -- (MPElementType)selectedType { - - return [self selectedElement].type; -} - -- (MPElementEntity *)selectedElement { - - return [self activeElementForMainThread]; -} - -- (void)didSelectType:(MPElementType)type { - - [self changeActiveElementWithWarning: - @"You are about to change the type of this password.\n\n" - @"If you continue, the password for this site will change. " - @"You will need to update your account's old password to the new one." - do:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) { - _activeElementOID = [[MPiOSAppDelegate get] changeElement:activeElement saveInContext:context - toType:type].objectID; - return YES; - }]; -} - -- (void)didSelectElement:(MPElementEntity *)element { - - inf(@"Selected: %@", element.name); - _activeElementOID = element.objectID; - [self closeAlert]; - - if (element) { - [self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) { - if ([activeElement use] == 1) - [self showAlertWithTitle:@"New Site" message: - PearlString( @"You've just created a password for %@.\n\n" - @"IMPORTANT:\n" - @"Go to %@ and set or change the password for your account to the password above.\n" - @"Do this right away: if you forget, you may have trouble remembering which password to use to log into the site later on.", - activeElement.name, activeElement.name )]; - return YES; - }]; - - if (![[MPiOSConfig get].typeTipShown boolValue]) - [UIView animateWithDuration:0.5f animations:^{ - self.typeTipContainer.alpha = 1; - } completion:^(BOOL finished) { - if (finished) { - [MPiOSConfig get].typeTipShown = PearlBool(YES); - - dispatch_after( - dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ), dispatch_get_main_queue(), ^{ - [UIView animateWithDuration:0.2f animations:^{ - self.typeTipContainer.alpha = 0; - }]; - } ); - } - }]; - - MPCheckpoint( MPCheckpointUseType, @{ - @"type" : NilToNSNull(element.typeName), - @"version" : @(element.version) - } ); - } - - [self.searchDisplayController setActive:NO animated:YES]; - self.searchDisplayController.searchBar.text = element.name; - - [self updateAnimated:YES]; -} - -- (BOOL)textFieldShouldReturn:(UITextField *)textField { - - if (textField == self.contentField) - [self.contentField resignFirstResponder]; - if (textField == self.loginNameField) - [self.loginNameField resignFirstResponder]; - - return YES; -} - -- (void)textFieldDidEndEditing:(UITextField *)textField { - - if (textField == self.contentField) { - self.contentField.enabled = NO; - MPElementEntity *activeElement = [self activeElementForMainThread]; - MPKey *key = [MPAppDelegate_Shared get].key; - if (![activeElement isKindOfClass:[MPElementStoredEntity class]]) { - // Not of a type whose content can be edited. - err(@"Cannot update element content: Element is not stored: %@", activeElement.name); - return; - } - else if ([[activeElement.algorithm resolveContentForElement:activeElement usingKey:key] isEqual:self.contentField.text]) - // Content hasn't changed. - return; - - [self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement_, NSManagedObjectContext *context) { - [activeElement_.algorithm saveContent:self.contentField.text toElement:activeElement_ usingKey:key]; - return YES; - }]; - } - - if (textField == self.loginNameField) { - self.loginNameField.enabled = NO; - if (![[MPiOSConfig get].loginNameTipShown boolValue]) { - [self showLoginNameTip:@"Tap to copy or hold to edit."]; - [MPiOSConfig get].loginNameTipShown = @YES; - } - - [self changeActiveElementWithoutWarningDo:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) { - if ([self.loginNameField.text length]) - activeElement.loginName = self.loginNameField.text; - else - activeElement.loginName = nil; - - return YES; - }]; - } -} - -- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request - navigationType:(UIWebViewNavigationType)navigationType { - - if (navigationType == UIWebViewNavigationTypeLinkClicked) { - if ([[[request URL] query] isEqualToString:@"outdated"]) { - [self searchOutdatedElements]; - return NO; - } - - [UIApp openURL:[request URL]]; - return NO; - } - - return YES; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPAppViewController.h b/MasterPassword/ObjC/iOS/MPNavigationController.h similarity index 59% rename from MasterPassword/ObjC/iOS/MPAppViewController.h rename to MasterPassword/ObjC/iOS/MPNavigationController.h index 28a50db5..ba3cf92d 100644 --- a/MasterPassword/ObjC/iOS/MPAppViewController.h +++ b/MasterPassword/ObjC/iOS/MPNavigationController.h @@ -9,17 +9,15 @@ */ // -// MPAppViewController +// MPNavigationController.h +// MPNavigationController // -// Created by Maarten Billemont on 2012-08-31. -// Copyright 2012 lhunath (Maarten Billemont). All rights reserved. +// Created by lhunath on 2014-06-03. +// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. // #import -@interface MPAppViewController : UIViewController - -- (IBAction)gorillas:(UIButton *)sender; -- (IBAction)deblock:(UIButton *)sender; +@interface MPNavigationController : UINavigationController @end diff --git a/MasterPassword/ObjC/iOS/MPNavigationController.m b/MasterPassword/ObjC/iOS/MPNavigationController.m new file mode 100644 index 00000000..cbaa9776 --- /dev/null +++ b/MasterPassword/ObjC/iOS/MPNavigationController.m @@ -0,0 +1,30 @@ +/** + * 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 + * @license http://www.gnu.org/licenses/lgpl-3.0.txt + */ + +// +// MPNavigationController.h +// MPNavigationController +// +// Created by lhunath on 2014-06-03. +// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. +// + +#import "MPNavigationController.h" +#import "MPWebViewController.h" + +@implementation MPNavigationController + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + + if ([segue.identifier isEqualToString:@"web"]) + ((MPWebViewController *)segue.destinationViewController).initialURL = [NSURL URLWithString:@"http://thanks.lhunath.com"]; +} + +@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeCell.h b/MasterPassword/ObjC/iOS/MPPasswordLargeCell.h index c3bae0e8..ce416af4 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeCell.h +++ b/MasterPassword/ObjC/iOS/MPPasswordLargeCell.h @@ -45,6 +45,7 @@ typedef NS_ENUM (NSUInteger, MPContentFieldMode) { - (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock; - (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock; +- (void)willBeginDragging; - (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context; @end diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeCell.m b/MasterPassword/ObjC/iOS/MPPasswordLargeCell.m index 654ba6ee..1a2326fd 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeCell.m +++ b/MasterPassword/ObjC/iOS/MPPasswordLargeCell.m @@ -152,6 +152,9 @@ resultBlock( nil ); } +- (void)willBeginDragging { +} + - (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context { return [[MPiOSAppDelegate get] changeElement:element saveInContext:context toType:self.type]; diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.h b/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.h index fa34073b..34d6b655 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.h +++ b/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.h @@ -21,6 +21,7 @@ @interface MPPasswordLargeGeneratedCell : MPPasswordLargeCell +@property(strong, nonatomic) IBOutlet UILabel *strengthLabel; @property(strong, nonatomic) IBOutlet UILabel *counterLabel; @property(strong, nonatomic) IBOutlet UIButton *counterButton; diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.m b/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.m index 3f2229a8..f2be70a6 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.m +++ b/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.m @@ -1,12 +1,12 @@ /** - * 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 - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ +* 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 +* @license http://www.gnu.org/licenses/lgpl-3.0.txt +*/ // // MPPasswordLargeGeneratedCell.h @@ -21,6 +21,11 @@ #import "MPAppDelegate_Store.h" #import "MPPasswordTypesCell.h" +@interface MPPasswordLargeGeneratedCell() + +@property(nonatomic, weak) NSTimer *hideStrengthTimer; +@end + @implementation MPPasswordLargeGeneratedCell - (void)awakeFromNib { @@ -28,10 +33,40 @@ [super awakeFromNib]; UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc] - initWithTarget:self action:@selector(doResetCounterRecognizer:)]; + initWithTarget:self action:@selector( doResetCounterRecognizer: )]; [self.counterButton addGestureRecognizer:gestureRecognizer]; } +- (void)prepareForReuse { + + [super prepareForReuse]; + + self.strengthLabel.alpha = 0; +} + +- (void)willBeginDragging { + + [super willBeginDragging]; + + [UIView animateWithDuration:0.3f animations:^{ + self.strengthLabel.alpha = 1; + }]; + + [self.hideStrengthTimer invalidate]; + self.hideStrengthTimer = [NSTimer scheduledTimerWithTimeInterval:1 block:^(NSTimer *timer) { + [UIView animateWithDuration:0.3f animations:^{ + self.strengthLabel.alpha = 0; + }]; + } repeats:NO]; +} + +- (void)update { + + [super update]; + + self.counterLabel.alpha = self.counterButton.alpha = 0; +} + - (void)updateWithElement:(MPElementEntity *)mainElement { [super updateWithElement:mainElement]; @@ -42,24 +77,18 @@ else self.counterLabel.text = @"1"; - if (!mainElement || mainElement.requiresExplicitMigration) { - self.counterLabel.alpha = 0; - self.counterButton.alpha = 0; - } - else { - self.counterLabel.alpha = 1; - self.counterButton.alpha = 1; - } + if (mainElement && !mainElement.requiresExplicitMigration) + self.counterLabel.alpha = self.counterButton.alpha = 1; } -- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock { +- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void ( ^ )(NSString *))resultBlock { PearlNotMainQueue( ^{ resultBlock( [MPAlgorithmDefault generateContentNamed:siteName ofType:self.type withCounter:1 usingKey:key] ); } ); } -- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock { +- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void ( ^ )(NSString *))resultBlock { id algorithm = element.algorithm; NSString *siteName = element.name; @@ -103,7 +132,7 @@ - (void)doResetCounterRecognizer:(UILongPressGestureRecognizer *)gestureRecognizer { - if (gestureRecognizer.state != UIGestureRecognizerStateEnded) + if (gestureRecognizer.state != UIGestureRecognizerStateRecognized) return; [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { @@ -123,6 +152,38 @@ #pragma mark - Properties +- (void)setType:(MPElementType)type { + + [super setType:type]; + + switch (type) { + case MPElementTypeGeneratedMaximum: + self.strengthLabel.text = @"> age of the universe"; + break; + case MPElementTypeGeneratedLong: + self.strengthLabel.text = @"196 billion years"; + break; + case MPElementTypeGeneratedMedium: + self.strengthLabel.text = @"5 months"; + break; + case MPElementTypeGeneratedBasic: + self.strengthLabel.text = @"12 days"; + break; + case MPElementTypeGeneratedShort: + self.strengthLabel.text = @"trivial"; + break; + case MPElementTypeGeneratedPIN: + self.strengthLabel.text = @"trivial"; + break; + case MPElementTypeStoredPersonal: + self.strengthLabel.text = @""; + break; + case MPElementTypeStoredDevicePrivate: + self.strengthLabel.text = @""; + break; + } +} + - (MPElementGeneratedEntity *)generatedElementInContext:(NSManagedObjectContext *)context { return [self generatedElement:[[MPPasswordTypesCell findAsSuperviewOf:self] elementInContext:context]]; diff --git a/MasterPassword/ObjC/iOS/MPPasswordTypesCell.m b/MasterPassword/ObjC/iOS/MPPasswordTypesCell.m index a567ad63..b6e85430 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordTypesCell.m +++ b/MasterPassword/ObjC/iOS/MPPasswordTypesCell.m @@ -24,6 +24,7 @@ @implementation MPPasswordTypesCell { NSManagedObjectID *_elementOID; + BOOL _scrolling; } #pragma mark - Lifecycle @@ -110,7 +111,9 @@ [cell updateWithTransientSite:self.transientSite]; else [cell updateWithElement:self.mainElement]; - dbg( @"cell %d, contentFieldMode: %d", indexPath.item, cell.contentFieldMode ); + + if (_scrolling) + [cell willBeginDragging]; return cell; } @@ -189,6 +192,13 @@ #pragma mark - UIScrollViewDelegate +- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { + + _scrolling = YES; + for (MPPasswordLargeCell *cell in [self.contentCollectionView visibleCells]) + [cell willBeginDragging]; +} + - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { @@ -202,12 +212,14 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { + _scrolling = NO; if (scrollView == self.contentCollectionView && !decelerate) [self saveContentType]; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { + _scrolling = NO; if (scrollView == self.contentCollectionView) [self saveContentType]; } diff --git a/MasterPassword/ObjC/iOS/MPPasswordsViewController.m b/MasterPassword/ObjC/iOS/MPPasswordsViewController.m index 2c9b6286..d8181aa4 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordsViewController.m +++ b/MasterPassword/ObjC/iOS/MPPasswordsViewController.m @@ -408,11 +408,8 @@ referenceSizeForHeaderInSection:(NSInteger)section { _active = active; [UIView animateWithDuration:animated? 0.4f: 0 animations:^{ - self.navigationBarToTopConstraint.priority = active? 1: UILayoutPriorityDefaultHigh; - self.passwordsToBottomConstraint.priority = active? 1: UILayoutPriorityDefaultHigh; - - [self.navigationBarToTopConstraint apply]; - [self.passwordsToBottomConstraint apply]; + [self.navigationBarToTopConstraint layoutWithPriority:active? 1: UILayoutPriorityDefaultHigh]; + [self.passwordsToBottomConstraint layoutWithPriority:active? 1: UILayoutPriorityDefaultHigh]; } completion:completion]; } diff --git a/MasterPassword/ObjC/iOS/MPPopdownSegue.m b/MasterPassword/ObjC/iOS/MPPopdownSegue.m index f5a007da..8603fd36 100644 --- a/MasterPassword/ObjC/iOS/MPPopdownSegue.m +++ b/MasterPassword/ObjC/iOS/MPPopdownSegue.m @@ -38,9 +38,8 @@ metrics:nil views:NSDictionaryOfVariableBindings(popdownView)]; [UIView animateWithDuration:0.3f animations:^{ - passwordsVC.popdownToTopConstraint.priority = 1; - [passwordsVC.popdownToTopConstraint apply]; - } completion:^(BOOL finished) { + [passwordsVC.popdownToTopConstraint layoutWithPriority:1]; + } completion:^(BOOL finished) { if (finished) [popdownVC didMoveToParentViewController:passwordsVC]; }]; @@ -51,8 +50,7 @@ [popdownVC willMoveToParentViewController:nil]; [UIView animateWithDuration:0.3f delay:0 options:UIViewAnimationOptionOverrideInheritedDuration animations:^{ - passwordsVC.popdownToTopConstraint.priority = UILayoutPriorityDefaultHigh; - [passwordsVC.popdownToTopConstraint apply]; + [passwordsVC.popdownToTopConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; } completion:^(BOOL finished) { if (finished) { [popdownVC.view removeFromSuperview]; diff --git a/MasterPassword/ObjC/iOS/MPPreferencesViewController.h b/MasterPassword/ObjC/iOS/MPPreferencesViewController.h index a865d42f..f8fa6c49 100644 --- a/MasterPassword/ObjC/iOS/MPPreferencesViewController.h +++ b/MasterPassword/ObjC/iOS/MPPreferencesViewController.h @@ -24,5 +24,9 @@ - (IBAction)previousAvatar:(id)sender; - (IBAction)nextAvatar:(id)sender; - (IBAction)valueChanged:(id)sender; +- (IBAction)homePageButton:(id)sender; +- (IBAction)securityButton:(id)sender; +- (IBAction)sourceButton:(id)sender; +- (IBAction)thanksButton:(id)sender; @end diff --git a/MasterPassword/ObjC/iOS/MPPreferencesViewController.m b/MasterPassword/ObjC/iOS/MPPreferencesViewController.m index 5c973b9b..fba96b81 100644 --- a/MasterPassword/ObjC/iOS/MPPreferencesViewController.m +++ b/MasterPassword/ObjC/iOS/MPPreferencesViewController.m @@ -142,6 +142,30 @@ }]; } +- (IBAction)homePageButton:(id)sender { + + [[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender: + [NSURL URLWithString:@"http://masterpasswordapp.com"]]; +} + +- (IBAction)securityButton:(id)sender { + + [[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender: + [NSURL URLWithString:@"http://masterpasswordapp.com/security.html"]]; +} + +- (IBAction)sourceButton:(id)sender { + + [[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender: + [NSURL URLWithString:@"https://github.com/Lyndir/MasterPassword/"]]; +} + +- (IBAction)thanksButton:(id)sender { + + [[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender: + [NSURL URLWithString:@"http://thanks.lhunath.com"]]; +} + #pragma mark - Private - (MPPasswordsViewController *)dismissPopup { diff --git a/MasterPassword/ObjC/iOS/MPPreferencesViewControllerOld.h b/MasterPassword/ObjC/iOS/MPPreferencesViewControllerOld.h deleted file mode 100644 index 3561068b..00000000 --- a/MasterPassword/ObjC/iOS/MPPreferencesViewControllerOld.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// MPPreferencesViewController.h -// MasterPassword-iOS -// -// Created by Maarten Billemont on 04/06/12. -// Copyright (c) 2012 Lyndir. All rights reserved. -// - -#import -#import "MPTypeViewController.h" - -@interface MPPreferencesViewControllerOld : UITableViewController - -@property(weak, nonatomic) IBOutlet UIScrollView *avatarsView; -@property(weak, nonatomic) IBOutlet UIButton *avatarTemplate; -@property(weak, nonatomic) IBOutlet UISwitch *savePasswordSwitch; -@property(weak, nonatomic) IBOutlet UITableViewCell *exportCell; -@property(weak, nonatomic) IBOutlet UITableViewCell *changeMPCell; -@property(weak, nonatomic) IBOutlet UILabel *defaultTypeLabel; - -- (IBAction)didToggleSwitch:(UISwitch *)sender; - -@end diff --git a/MasterPassword/ObjC/iOS/MPPreferencesViewControllerOld.m b/MasterPassword/ObjC/iOS/MPPreferencesViewControllerOld.m deleted file mode 100644 index 746eebda..00000000 --- a/MasterPassword/ObjC/iOS/MPPreferencesViewControllerOld.m +++ /dev/null @@ -1,163 +0,0 @@ -// -// MPPreferencesViewController.m -// MasterPassword-iOS -// -// Created by Maarten Billemont on 04/06/12. -// Copyright (c) 2012 Lyndir. All rights reserved. -// - -#import - -#import "MPPreferencesViewControllerOld.h" -#import "MPiOSAppDelegate.h" -#import "MPAppDelegate_Key.h" -#import "MPAppDelegate_Store.h" - -@interface MPPreferencesViewControllerOld() - -@end - -@implementation MPPreferencesViewControllerOld - -- (void)viewDidLoad { - - self.avatarTemplate.hidden = YES; - - for (NSUInteger a = 0; a < MPAvatarCount; ++a) { - UIButton *avatar = [self.avatarTemplate clone]; - avatar.tag = a; - avatar.hidden = NO; - avatar.center = CGPointMake( - self.avatarTemplate.center.x * (a + 1) + self.avatarTemplate.bounds.size.width / 2 * a, - self.avatarTemplate.center.y ); - [avatar setBackgroundImage:[UIImage imageNamed:PearlString( @"avatar-%ld", (long)a )] - forState:UIControlStateNormal]; - [avatar setSelectionInSuperviewCandidate:YES isClearable:NO]; - - avatar.layer.cornerRadius = avatar.bounds.size.height / 2; - avatar.layer.shadowColor = [UIColor blackColor].CGColor; - avatar.layer.shadowOpacity = 1; - avatar.layer.shadowRadius = 5; - avatar.backgroundColor = [UIColor clearColor]; - - [avatar onHighlightOrSelect:^(BOOL highlighted, BOOL selected) { - if (highlighted || selected) - avatar.backgroundColor = self.avatarTemplate.backgroundColor; - else - avatar.backgroundColor = [UIColor clearColor]; - } options:0]; - [avatar onSelect:^(BOOL selected) { - if (selected) { - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) { - [[MPiOSAppDelegate get] activeUserInContext:moc].avatar = (unsigned)avatar.tag; - [moc saveToStore]; - }]; - } - } options:0]; - avatar.selected = (a == [[MPiOSAppDelegate get] activeUserForMainThread].avatar); - } - - [super viewDidLoad]; -} - -- (void)viewWillAppear:(BOOL)animated { - - inf(@"Preferences will appear"); - [self.avatarsView autoSizeContent]; - [self.avatarsView enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) { - if (subview.tag && ((UIControl *)subview).selected) { - [self.avatarsView setContentOffset:CGPointMake( subview.center.x - self.avatarsView.bounds.size.width / 2, 0 ) - animated:animated]; - } - } recurse:NO]; - - MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForMainThread]; - self.savePasswordSwitch.on = activeUser.saveKey; - self.defaultTypeLabel.text = [[MPiOSAppDelegate get].key.algorithm shortNameOfType:activeUser.defaultType]; - - [super viewWillAppear:animated]; -} - -- (BOOL)canBecomeFirstResponder { - - return YES; -} - -- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { - - if (motion == UIEventSubtypeMotionShake) { - MPCheckpoint( MPCheckpointLogs, @{ - @"trace" : [MPiOSConfig get].traceMode - } ); - [self performSegueWithIdentifier:@"MP_Logs" sender:self]; - } -} - -- (BOOL)shouldAutorotate { - - return NO; -} - -- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { - - return UIInterfaceOrientationPortrait; -} - -- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - - if ([[segue identifier] isEqualToString:@"MP_ChooseType"]) - ((MPTypeViewController *)[segue destinationViewController]).delegate = self; -} - -#pragma mark - UITableViewDelegate - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - - UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath]; - if (cell == self.exportCell) - [[MPiOSAppDelegate get] showExportForVC:self]; - - else if (cell == self.changeMPCell) { - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) { - MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc]; - [[MPiOSAppDelegate get] changeMasterPasswordFor:activeUser saveInContext:moc didResetBlock:nil]; - }]; - } - - [tableView deselectRowAtIndexPath:indexPath animated:YES]; -} - -#pragma mark - MPTypeDelegate - -- (void)didSelectType:(MPElementType)type { - - self.defaultTypeLabel.text = [[MPiOSAppDelegate get].key.algorithm shortNameOfType:type]; - - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:context]; - activeUser.defaultType = type; - [context saveToStore]; - }]; -} - -- (MPElementType)selectedType { - - return [[MPiOSAppDelegate get] activeUserForMainThread].defaultType; -} - -#pragma mark - IBActions - -- (IBAction)didToggleSwitch:(UISwitch *)sender { - - if (sender == self.savePasswordSwitch) - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) { - MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc]; - if ((activeUser.saveKey = sender.on)) - [[MPiOSAppDelegate get] storeSavedKeyFor:activeUser]; - else - [[MPiOSAppDelegate get] forgetSavedKeyFor:activeUser]; - [moc saveToStore]; - }]; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPUnlockViewController.h b/MasterPassword/ObjC/iOS/MPUnlockViewController.h deleted file mode 100644 index d8d236a5..00000000 --- a/MasterPassword/ObjC/iOS/MPUnlockViewController.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// MBUnlockViewController.h -// MasterPassword -// -// Created by Maarten Billemont on 22/02/12. -// Copyright (c) 2012 Lyndir. All rights reserved. -// - -#import -#import "LLGitTip.h" - -@interface MPUnlockViewController : UIViewController - -@property(weak, nonatomic) IBOutlet UIImageView *spinner; -@property(weak, nonatomic) IBOutlet UILabel *passwordFieldLabel; -@property(weak, nonatomic) IBOutlet UITextField *passwordField; -@property(weak, nonatomic) IBOutlet UIView *passwordView; -@property(weak, nonatomic) IBOutlet UIScrollView *avatarsView; -@property(weak, nonatomic) IBOutlet UILabel *nameLabel; -@property(weak, nonatomic) IBOutlet UILabel *oldNameLabel; -@property(weak, nonatomic) IBOutlet UIButton *avatarTemplate; -@property(weak, nonatomic) IBOutlet UIView *createPasswordTipView; -@property(weak, nonatomic) IBOutlet UILabel *tip; -@property(weak, nonatomic) IBOutlet UIView *passwordTipView; -@property(weak, nonatomic) IBOutlet UILabel *passwordTipLabel; -@property(weak, nonatomic) IBOutlet UIView *wordWall; -@property(strong, nonatomic) IBOutlet UILongPressGestureRecognizer *targetedUserActionGesture; -@property(weak, nonatomic) IBOutlet UIView *uiContainer; -@property(weak, nonatomic) IBOutlet UIView *shareContainer; -@property(weak, nonatomic) IBOutlet UIView *tipsTipContainer; -@property(weak, nonatomic) IBOutlet LLGitTip *gitTipButton; -@property(weak, nonatomic) IBOutlet UIWebView *newsView; -@property(weak, nonatomic) IBOutlet UIView *emergencyGeneratorContainer; -@property(weak, nonatomic) IBOutlet UITextField *emergencyName; -@property(weak, nonatomic) IBOutlet UITextField *emergencyMasterPassword; -@property(weak, nonatomic) IBOutlet UITextField *emergencySite; -@property(weak, nonatomic) IBOutlet UIStepper *emergencyCounterStepper; -@property(weak, nonatomic) IBOutlet UISegmentedControl *emergencyTypeControl; -@property(weak, nonatomic) IBOutlet UILabel *emergencyCounter; -@property(weak, nonatomic) IBOutlet UIActivityIndicatorView *emergencyActivity; -@property(weak, nonatomic) IBOutlet UIButton *emergencyPassword; -@property(weak, nonatomic) IBOutlet UIView *emergencyContentTipContainer; - -- (IBAction)targetedUserAction:(UILongPressGestureRecognizer *)sender; -- (IBAction)facebook:(id)sender; -- (IBAction)twitter:(id)sender; -- (IBAction)google:(id)sender; -- (IBAction)mail:(id)sender; -- (IBAction)add:(id)sender; -- (IBAction)emergencyOpen:(id)sender; -- (IBAction)emergencyClose:(id)sender; -- (IBAction)emergencyCopy:(id)sender; - -@end diff --git a/MasterPassword/ObjC/iOS/MPUnlockViewController.m b/MasterPassword/ObjC/iOS/MPUnlockViewController.m deleted file mode 100644 index 4b63275d..00000000 --- a/MasterPassword/ObjC/iOS/MPUnlockViewController.m +++ /dev/null @@ -1,1231 +0,0 @@ -// -// MBUnlockViewController.m -// MasterPassword -// -// Created by Maarten Billemont on 22/02/12. -// Copyright (c) 2012 Lyndir. All rights reserved. -// - -#import - -#import "MPUnlockViewController.h" -#import "MPiOSAppDelegate.h" -#import "MPAppDelegate_Key.h" -#import "MPAppDelegate_Store.h" -#import "LLGitTip.h" - -@interface MPUnlockViewController() - -@property(strong, nonatomic) NSMutableDictionary *avatarToUserOID; -@property(nonatomic) BOOL wordWallAnimating; -@property(nonatomic, strong) NSArray *wordList; - -@property(nonatomic, strong) NSOperationQueue *emergencyQueue; -@property(nonatomic, strong) MPKey *emergencyKey; - -@property(nonatomic, strong) NSTimer *marqueeTipTimer; -@property(nonatomic) NSUInteger marqueeTipTextIndex; -@property(nonatomic, strong) NSArray *marqueeTipTexts; -@property(nonatomic, strong) id mocObserver; -@end - -@implementation MPUnlockViewController { - NSManagedObjectID *_selectedUserOID; -} - -- (void)dealloc { - if (self.mocObserver) - [[NSNotificationCenter defaultCenter] removeObserver:self.mocObserver]; -} - -- (void)initializeAvatarAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc { - - UIScrollView *alertAvatarScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake( 12, 30, 260, 150 )]; - alertAvatarScrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite; - [alertAvatarScrollView flashScrollIndicatorsContinuously]; - [alert addSubview:alertAvatarScrollView]; - - CGPoint selectedOffset = CGPointZero; - for (NSUInteger a = 0; a < MPAvatarCount; ++a) { - UIButton *avatar = [self.avatarTemplate cloneAddedTo:alertAvatarScrollView]; - - avatar.tag = (NSInteger)a; - avatar.hidden = NO; - avatar.center = CGPointMake( - (20 + self.avatarTemplate.bounds.size.width / 2) * (a + 1) + self.avatarTemplate.bounds.size.width / 2 * a, - 20 + self.avatarTemplate.bounds.size.height / 2 ); - [avatar setBackgroundImage:[UIImage imageNamed:PearlString( @"avatar-%ld", (long)a )] forState:UIControlStateNormal]; - [avatar setSelectionInSuperviewCandidate:YES isClearable:NO]; - - avatar.layer.cornerRadius = avatar.bounds.size.height / 2; - avatar.layer.shadowColor = [UIColor blackColor].CGColor; - avatar.layer.shadowOpacity = 1; - avatar.layer.shadowRadius = 5; - avatar.backgroundColor = [UIColor clearColor]; - - [avatar onHighlightOrSelect:^(BOOL highlighted, BOOL selected) { - if (highlighted || selected) - avatar.backgroundColor = self.avatarTemplate.backgroundColor; - else - avatar.backgroundColor = [UIColor clearColor]; - } options:0]; - [avatar onSelect:^(BOOL selected) { - if (selected) - [moc performBlock:^{ - user.avatar = (unsigned)avatar.tag; - }]; - } options:0]; - avatar.selected = (a == user.avatar); - if (avatar.selected) - selectedOffset = CGPointMake( avatar.center.x - alertAvatarScrollView.bounds.size.width / 2, 0 ); - } - - [alertAvatarScrollView autoSizeContent]; - [alertAvatarScrollView setContentOffset:selectedOffset animated:YES]; -} - -- (void)initializeConfirmationAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user { - - UIView *container = [[UIView alloc] initWithFrame:CGRectMake( 12, 70, 260, 110 )]; - [alert addSubview:container]; - - UIButton *alertAvatar = [self.avatarTemplate cloneAddedTo:container]; - alertAvatar.center = CGPointMake( 130, 55 ); - alertAvatar.hidden = NO; - alertAvatar.layer.shadowColor = [UIColor blackColor].CGColor; - alertAvatar.layer.shadowOpacity = 1; - alertAvatar.layer.shadowRadius = 5; - alertAvatar.backgroundColor = [UIColor clearColor]; - [alertAvatar setBackgroundImage:[UIImage imageNamed:PearlString( @"avatar-%lu", (unsigned long)user.avatar )] - forState:UIControlStateNormal]; - - UILabel *alertNameLabel = [self.nameLabel cloneAddedTo:container]; - alertNameLabel.center = alertAvatar.center; - alertNameLabel.text = user.name; - [alertNameLabel sizeToFit]; - alertNameLabel.layer.cornerRadius = 5; - alertNameLabel.backgroundColor = [UIColor blackColor]; -} - -- (BOOL)shouldAutorotate { - - return YES; -} - -- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { - - return UIInterfaceOrientationPortrait; -} - -- (NSUInteger)supportedInterfaceOrientations { - - return UIInterfaceOrientationMaskPortrait; -} - -- (void)viewDidLoad { - - self.gitTipButton.iTunesID = [MPConfig get].iTunesID; - self.avatarToUserOID = [NSMutableDictionary dictionaryWithCapacity:3]; - - [self.avatarsView addGestureRecognizer:self.targetedUserActionGesture]; - self.avatarsView.decelerationRate = UIScrollViewDecelerationRateFast; - self.avatarsView.clipsToBounds = NO; - self.tip.text = @""; - self.nameLabel.layer.cornerRadius = 5; - self.avatarTemplate.hidden = YES; - self.passwordTipView.hidden = NO; - self.createPasswordTipView.hidden = NO; - [self.emergencyPassword setTitle:@"" forState:UIControlStateNormal]; - self.emergencyGeneratorContainer.alpha = 0; - self.emergencyGeneratorContainer.hidden = YES; - self.emergencyQueue = [NSOperationQueue new]; - [self.emergencyCounterStepper addTargetBlock:^(id sender, UIControlEvents event, id weakSelf) { - self.emergencyCounter.text = PearlString( @"%lu", (unsigned long)self.emergencyCounterStepper.value ); - - [self updateEmergencyPassword]; - } forControlEvents:UIControlEventValueChanged]; - [self.emergencyTypeControl addTargetBlock:^(id sender, UIControlEvents event, id weakSelf) { - [self updateEmergencyPassword]; - } forControlEvents:UIControlEventValueChanged]; - self.emergencyContentTipContainer.alpha = 0; - self.emergencyContentTipContainer.hidden = NO; - self.marqueeTipTexts = @[ - @"Tap and hold to delete or reset user.", - @"Shake for emergency generator." - ]; - - NSMutableArray *wordListLines = [NSMutableArray arrayWithCapacity:27413]; - [[[NSString alloc] initWithData:[NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"dictionary" withExtension:@"lst"]] - encoding:NSUTF8StringEncoding] enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) { - [wordListLines addObject:line]; - }]; - self.wordList = wordListLines; - - self.wordWall.alpha = 0; - [self.wordWall enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) { - UILabel *wordLabel = (UILabel *)subview; - - [self initializeWordLabel:wordLabel]; - } recurse:NO]; - - [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - [self updateUsers]; - }]; - [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidImportChangesNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - [self updateUsers]; - }]; - [[NSNotificationCenter defaultCenter] addObserverForName:MPSitesImportedNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - [self updateUsers]; - }]; - [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - [self emergencyCloseAnimated:NO]; - self.uiContainer.alpha = 0; - self.shareContainer.alpha = 0; - }]; - [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - [self updateLayoutAnimated:NO allowScroll:NO completion:nil]; - [UIView animateWithDuration:1 animations:^{ - self.uiContainer.alpha = 1; - } completion:^(BOOL finished) { - if (finished) - [UIView animateWithDuration:1 animations:^{ - self.shareContainer.alpha = 1; - }]; - }]; - - NSString *newsURL = PearlString( @"http://masterpasswordapp.com/news.html?version=%@", - [[PearlInfoPlist get] CFBundleVersion] ); - [self.newsView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:newsURL]]]; - }]; - - [self updateLayoutAnimated:NO allowScroll:YES completion:nil]; - - [super viewDidLoad]; -} - -- (void)viewWillAppear:(BOOL)animated { - - inf(@"Lock screen will appear"); - if (![super respondsToSelector:@selector(prefersStatusBarHidden)]) - [UIApp setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide]; - [self.navigationController setNavigationBarHidden:YES animated:animated]; - - [[MPiOSAppDelegate get] signOutAnimated:NO]; - - _selectedUserOID = nil; - [self updateUsers]; - - self.uiContainer.alpha = 0; - self.shareContainer.alpha = 0; - self.spinner.alpha = 0; - self.tipsTipContainer.alpha = 0; - - [super viewWillAppear:animated]; -} - -- (void)viewDidAppear:(BOOL)animated { - - [self becomeFirstResponder]; - - if (!animated && !self.navigationController.presentedViewController) - [[self findTargetedAvatar] setSelected:YES]; - else - [self updateLayoutAnimated:YES allowScroll:YES completion:nil]; - - [UIView animateWithDuration:1 animations:^{ - self.uiContainer.alpha = 1; - } completion:^(BOOL finished) { - if (finished) - [UIView animateWithDuration:1 animations:^{ - self.shareContainer.alpha = 1; - if ([MPConfig get].firstVersionRun) - self.tipsTipContainer.alpha = 1; - }]; - }]; - - [self.marqueeTipTimer invalidate]; - self.marqueeTipTimer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(marqueeTip) userInfo:nil repeats:YES]; - - [super viewDidAppear:animated]; -} - -- (void)viewWillDisappear:(BOOL)animated { - - inf(@"Lock screen will disappear"); - [self emergencyCloseAnimated:animated]; - [self.marqueeTipTimer invalidate]; - - [super viewWillDisappear:animated]; -} - -- (BOOL)prefersStatusBarHidden { - - return YES; -} - -- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { - - return UIStatusBarAnimationSlide; -} - -- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - - if ([segue.identifier isEqualToString:@"MP_Settings"]) - [self.navigationController setNavigationBarHidden:NO animated:YES]; -} - -- (BOOL)canBecomeFirstResponder { - - return YES; -} - -- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { - - if (motion == UIEventSubtypeMotionShake) - [self emergencyOpenAnimated:YES]; -} - -- (void)marqueeTip { - - [UIView animateWithDuration:0.5 animations:^{ - self.tip.alpha = 0; - } completion:^(BOOL finished) { - if (!finished) - return; - - self.tip.text = self.marqueeTipTexts[++self.marqueeTipTextIndex % [self.marqueeTipTexts count]]; - [UIView animateWithDuration:0.5 animations:^{ - self.tip.alpha = 1; - }]; - }]; -} - -- (void)updateUsers { - - NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady]; - if (mainContext) { - if (self.mocObserver) - [[NSNotificationCenter defaultCenter] removeObserver:self.mocObserver]; - self.mocObserver = [[NSNotificationCenter defaultCenter] - addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:mainContext - queue:nil usingBlock:^(NSNotification *note) { - [self updateUsers]; - }]; - } - - [MPiOSAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) { - NSError *error = nil; - NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )]; - fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO] ]; - NSArray *users = [context executeFetchRequest:fetchRequest error:&error]; - if (!users) - err(@"Failed to load users: %@", error); - - // Clean up avatars. - for (UIView *subview in [self.avatarsView subviews]) - if ([[self.avatarToUserOID allKeys] containsObject:[NSValue valueWithNonretainedObject:subview]]) - // This subview is a former avatar. - [subview removeFromSuperview]; - [self.avatarToUserOID removeAllObjects]; - - // Create avatars. - for (MPUserEntity *user in users) - [self setupAvatar:[self.avatarTemplate clone] forUser:user]; - [self setupAvatar:[self.avatarTemplate clone] forUser:nil]; - }]; - - // Scroll view's content changed, update its content size. - [self.avatarsView autoSizeContentIgnoreHidden:YES ignoreInvisible:YES limitPadding:NO ignoreSubviews:nil]; - - [self updateLayoutAnimated:YES allowScroll:YES completion:nil]; -} - -- (UIButton *)setupAvatar:(UIButton *)avatar forUser:(MPUserEntity *)user { - - avatar.center = CGPointMake( avatar.center.x + [self.avatarToUserOID count] * 160, avatar.center.y ); - avatar.hidden = NO; - avatar.layer.cornerRadius = avatar.bounds.size.height / 2; - avatar.layer.shadowColor = [UIColor blackColor].CGColor; - avatar.layer.shadowOpacity = 1; - avatar.layer.shadowRadius = 20; - avatar.layer.masksToBounds = NO; - avatar.backgroundColor = [UIColor clearColor]; - avatar.tag = (NSInteger)user.avatar; - - [avatar setBackgroundImage:[UIImage imageNamed:PearlString( @"avatar-%lu", (unsigned long)user.avatar )] - forState:UIControlStateNormal]; - [avatar setSelectionInSuperviewCandidate:YES isClearable:YES]; - [avatar onHighlightOrSelect:^(BOOL highlighted, BOOL selected) { - if (highlighted || selected) - avatar.backgroundColor = self.avatarTemplate.backgroundColor; - else - avatar.backgroundColor = [UIColor clearColor]; - } options:0]; - [avatar onSelect:^(BOOL selected) { - if (!selected) { - self.selectedUser = nil; - [self didToggleUserSelection]; - } - else if (!user) - [self didSelectNewUserAvatar:avatar]; - else if ([self setSelectedUser:user]) - [self didToggleUserSelection]; - } options:0]; - - (self.avatarToUserOID)[[NSValue valueWithNonretainedObject:avatar]] = NilToNSNull([user objectID]); - - if ([_selectedUserOID isEqual:[user objectID]]) - avatar.selected = YES; - - return avatar; -} - -- (void)didToggleUserSelection { - - NSAssert([[NSThread currentThread] isMainThread], @"User selection should only be toggled from the main thread."); - - NSManagedObjectContext *context = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady]; - MPUserEntity *selectedUser = [self selectedUserInContext:context]; - if (!selectedUser) - [self.passwordField resignFirstResponder]; - else if ([[MPiOSAppDelegate get] signInAsUser:selectedUser saveInContext:context usingMasterPassword:nil]) { - [self performSegueWithIdentifier:@"MP_Unlock" sender:self]; - return; - } - - [self updateLayoutAnimated:YES allowScroll:YES completion:^(BOOL finished) { - if ([self selectedUserForThread]) - [self.passwordField becomeFirstResponder]; - }]; -} - -- (void)didSelectNewUserAvatar:(UIButton *)newUserAvatar { - - if (![MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - MPUserEntity *newUser = [MPUserEntity insertNewObjectInContext:context]; - - [self showNewUserNameAlertFor:newUser saveInContext:context completion:^(BOOL finished) { - newUserAvatar.selected = NO; - }]; - }]) - newUserAvatar.selected = NO; -} - -- (void)showNewUserNameAlertFor:(MPUserEntity *)newUser saveInContext:(NSManagedObjectContext *)context - completion:(void (^)(BOOL finished))completion { - - [PearlAlert showAlertWithTitle:@"Enter Your Name" - message:nil viewStyle:UIAlertViewStylePlainTextInput - initAlert:^(UIAlertView *alert, UITextField *firstField) { - firstField.autocapitalizationType = UITextAutocapitalizationTypeWords; - firstField.keyboardType = UIKeyboardTypeAlphabet; - firstField.text = newUser.name; - firstField.placeholder = @"eg. Robert Lee Mitchell"; - firstField.enablesReturnKeyAutomatically = YES; - } - tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { - if (buttonIndex == [alert cancelButtonIndex]) { - completion( NO ); - return; - } - 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_) { - [self showNewUserNameAlertFor:newUser saveInContext:context completion:completion]; - } cancelTitle:@"Try Again" otherTitles:nil]; - return; - } - - // Save - [context performBlockAndWait:^{ - newUser.name = name; - }]; - [self showNewUserAvatarAlertFor:newUser saveInContext:context completion:completion]; - } - cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonSave, nil]; -} - -- (void)showNewUserAvatarAlertFor:(MPUserEntity *)newUser saveInContext:(NSManagedObjectContext *)context - 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 inContext:context]; - } - tappedButtonBlock:^(UIAlertView *_alert, NSInteger _buttonIndex) { - - // Okay - [self showNewUserConfirmationAlertFor:newUser saveInContext:context completion:completion]; - } cancelTitle:nil otherTitles:[PearlStrings get].commonButtonOkay, nil]; -} - -- (void)showNewUserConfirmationAlertFor:(MPUserEntity *)newUser saveInContext:(NSManagedObjectContext *)context - completion:(void (^)(BOOL finished))completion { - - [PearlAlert showAlertWithTitle:@"Is this correct?" - message: - @"Please double-check your name.\n" - @"\n\n\n\n\n\n" - viewStyle:UIAlertViewStyleDefault - initAlert:^void(UIAlertView *__alert, UITextField *__firstField) { - [self initializeConfirmationAlert:__alert forUser:newUser]; - } - tappedButtonBlock:^void(UIAlertView *__alert, NSInteger __buttonIndex) { - if (__buttonIndex == [__alert cancelButtonIndex]) { - [self showNewUserNameAlertFor:newUser saveInContext:context completion:completion]; - return; - } - - // Confirm - [context performBlockAndWait:^{ - [context saveToStore]; - NSError *error = nil; - if (![context obtainPermanentIDsForObjects:@[ newUser ] error:&error]) - err(@"Failed to obtain permanent object ID for new user: %@", error); - self.selectedUser = newUser; - }]; - completion( YES ); - - [self updateUsers]; - } - cancelTitle:@"Change" otherTitles:@"Confirm", nil]; -} - -- (void)updateLayoutAnimated:(BOOL)animated allowScroll:(BOOL)allowScroll completion:(void (^)(BOOL finished))completion { - - if (animated) { - self.oldNameLabel.text = self.nameLabel.text; - self.oldNameLabel.alpha = 1; - self.nameLabel.alpha = 0; - - [UIView animateWithDuration:0.5f animations:^{ - [self updateLayoutAnimated:NO allowScroll:allowScroll completion:nil]; - - self.oldNameLabel.alpha = 0; - self.nameLabel.alpha = 1; - } completion:^(BOOL finished) { - if (completion) - completion( finished ); - }]; - return; - } - - // Lay out password entry and user selection views. - MPUserEntity *selectedUser = [self selectedUserForThread]; - if (selectedUser && !self.passwordView.alpha) { - // User was just selected. - self.passwordView.alpha = 1; - self.avatarsView.frame = CGRectSetY( self.avatarsView.frame, 16 ); - self.avatarsView.scrollEnabled = NO; - self.nameLabel.center = CGPointMake( 160, 94 ); - self.nameLabel.backgroundColor = [UIColor blackColor]; - self.oldNameLabel.center = self.nameLabel.center; - } - else if (!selectedUser && self.passwordView.alpha == 1) { - // User was just deselected. - self.passwordField.text = nil; - self.passwordView.alpha = 0; - self.avatarsView.frame = CGRectSetY( self.avatarsView.frame, 140 ); - self.avatarsView.scrollEnabled = YES; - self.nameLabel.center = CGPointMake( 160, 296 ); - self.nameLabel.backgroundColor = [UIColor clearColor]; - self.oldNameLabel.center = self.nameLabel.center; - } - - // Lay out the word wall. - if (!selectedUser || selectedUser.keyID) { - self.passwordFieldLabel.text = @"Enter your master password:"; - - self.wordWall.alpha = 0; - self.createPasswordTipView.alpha = 0; - self.wordWallAnimating = NO; - } - else { - self.passwordFieldLabel.text = @"Create your master password:"; - - if (!self.wordWallAnimating) { - self.wordWallAnimating = YES; - self.wordWall.alpha = 1; - self.createPasswordTipView.alpha = 1; - - dispatch_async( dispatch_get_main_queue(), ^{ - // Jump out of our UIView animation block. - [self beginWordWallAnimation]; - } ); - dispatch_after( dispatch_time( DISPATCH_TIME_NOW, 15 * NSEC_PER_SEC ), dispatch_get_main_queue(), ^{ - [UIView animateWithDuration:1 animations:^{ - self.createPasswordTipView.alpha = 0; - }]; - } ); - } - } - - // Lay out user targeting. - UIButton *selectedAvatar = [self avatarForUser:selectedUser]; - MPUserEntity *targetedUser = selectedUser; - UIButton *targetedAvatar = selectedAvatar; - if (!targetedAvatar) { - targetedAvatar = [self findTargetedAvatar]; - targetedUser = [self userForAvatar:targetedAvatar inContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]; - } - - [self.avatarsView enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) { - if (![[self.avatarToUserOID allKeys] containsObject:[NSValue valueWithNonretainedObject:subview]]) - // This subview is not one of the user avatars. - return; - UIButton *avatar = (UIButton *)subview; - - BOOL isTargeted = avatar == targetedAvatar; - - avatar.userInteractionEnabled = isTargeted; - avatar.alpha = isTargeted? 1: [self selectedUserForThread]? 0.1F: 0.4F; - - [self updateAvatarShadowColor:avatar isTargeted:isTargeted]; - } recurse:NO]; - - if (allowScroll) { - CGPoint targetContentOffset = CGPointMake( - MAX(0, targetedAvatar.center.x - self.avatarsView.bounds.size.width / 2), - self.avatarsView.contentOffset.y ); - if (!CGPointEqualToPoint( self.avatarsView.contentOffset, targetContentOffset )) - [self.avatarsView setContentOffset:targetContentOffset animated:animated]; - } - - // Lay out user name label. - self.nameLabel.text = targetedAvatar? (targetedUser? targetedUser.name: @"New User"): nil; - [self.nameLabel sizeToFit]; - self.oldNameLabel.bounds = self.nameLabel.bounds; - if (completion) - completion( YES ); -} - -- (void)beginWordWallAnimation { - - [self.wordWall enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) { - UILabel *wordLabel = (UILabel *)subview; - - if (wordLabel.frame.origin.x < -self.wordWall.frame.size.width / 3) { - wordLabel.frame = CGRectSetX( wordLabel.frame, wordLabel.frame.origin.x + self.wordWall.frame.size.width ); - [self initializeWordLabel:wordLabel]; - } - } recurse:NO]; - - if (self.wordWallAnimating) - [UIView animateWithDuration:15 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ - [self.wordWall enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) { - UILabel *wordLabel = (UILabel *)subview; - - wordLabel.frame = CGRectSetX( wordLabel.frame, wordLabel.frame.origin.x - self.wordWall.frame.size.width / 3 ); - } recurse:NO]; - } completion:^(BOOL finished) { - if (finished) - [self beginWordWallAnimation]; - }]; -} - -- (void)initializeWordLabel:(UILabel *)wordLabel { - - wordLabel.alpha = 0.05F + (random() % 35) / 100.0F; - wordLabel.text = (self.wordList)[(NSUInteger)random() % [self.wordList count]]; -} - -- (void)setPasswordTip:(NSString *)string { - - if (string.length) - self.passwordTipLabel.text = string; - - [UIView animateWithDuration:0.3f animations:^{ - self.passwordTipView.alpha = string.length? 1: 0; - }]; -} - -- (void)tryMasterPassword { - - if (![self selectedUserForThread]) - // No user selected, can't try sign-in. - return; - - [self setSpinnerActive:YES]; - - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) { - BOOL unlocked = [[MPiOSAppDelegate get] signInAsUser:[self selectedUserInContext:moc] saveInContext:moc - usingMasterPassword:self.passwordField.text]; - - dispatch_async( dispatch_get_main_queue(), ^{ - if (unlocked) - [self performSegueWithIdentifier:@"MP_Unlock" sender:self]; - - else { - if (self.passwordField.text.length) - [self setPasswordTip:@"Incorrect password."]; - - [self setSpinnerActive:NO]; - } - } ); - }]; -} - -- (UIButton *)findTargetedAvatar { - - CGFloat xOfMiddle = self.avatarsView.contentOffset.x + self.avatarsView.bounds.size.width / 2; - return (UIButton *)[PearlUIUtils viewClosestTo:CGPointMake( xOfMiddle, self.avatarsView.contentOffset.y ) - ofArray:self.avatarsView.subviews]; -} - -- (UIButton *)avatarForUser:(MPUserEntity *)user { - - NSManagedObjectID *userOID = [user objectID]; - __block UIButton *avatar = nil; - if (userOID) - [self.avatarToUserOID enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { - if ([obj isEqual:userOID]) - avatar = [key nonretainedObjectValue]; - }]; - - return avatar; -} - -- (MPUserEntity *)userForAvatar:(UIButton *)avatar inContext:(NSManagedObjectContext *)context { - - NSManagedObjectID *userOID = NSNullToNil((self.avatarToUserOID)[[NSValue valueWithNonretainedObject:avatar]]); - if (!userOID) - return nil; - - NSError *error; - MPUserEntity *user = (MPUserEntity *)[context existingObjectWithID:userOID error:&error]; - if (!user) - err(@"Failed retrieving user for avatar: %@", error); - - return user; -} - -- (void)setSpinnerActive:(BOOL)active { - - PearlMainQueue( ^{ - CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; - rotate.toValue = [NSNumber numberWithDouble:2 * M_PI]; - rotate.duration = 5.0; - - if (active) { - rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; - rotate.fromValue = @0.0; - rotate.repeatCount = MAXFLOAT; - } - else { - rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; - rotate.repeatCount = 1; - } - - [self.spinner.layer removeAnimationForKey:@"rotation"]; - [self.spinner.layer addAnimation:rotate forKey:@"rotation"]; - - [UIView animateWithDuration:0.3f animations:^{ - self.spinner.alpha = active? 1: 0; - - if (active) - [self avatarForUser:[self selectedUserForThread]].backgroundColor = [UIColor clearColor]; - else - [self avatarForUser:[self selectedUserForThread]].backgroundColor = self.avatarTemplate.backgroundColor; - }]; - } ); -} - -- (void)updateAvatarShadowColor:(UIButton *)avatar isTargeted:(BOOL)targeted { - - if (targeted) { - if (![avatar.layer animationForKey:@"targetedShadow"]) { - CABasicAnimation *toShadowColorAnimation = [CABasicAnimation animationWithKeyPath:@"shadowColor"]; - toShadowColorAnimation.toValue = (__bridge id)(avatar.selected? self.avatarTemplate.backgroundColor - : [UIColor whiteColor]).CGColor; - toShadowColorAnimation.beginTime = 0.0f; - toShadowColorAnimation.duration = 0.5f; - toShadowColorAnimation.fillMode = kCAFillModeForwards; - - CABasicAnimation *toShadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"]; - toShadowOpacityAnimation.toValue = @0.2f; - toShadowOpacityAnimation.duration = 0.5f; - - CABasicAnimation *pulseShadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"]; - pulseShadowOpacityAnimation.fromValue = @0.2f; - pulseShadowOpacityAnimation.toValue = @0.6f; - pulseShadowOpacityAnimation.beginTime = 0.5f; - pulseShadowOpacityAnimation.duration = 2.0f; - pulseShadowOpacityAnimation.autoreverses = YES; - pulseShadowOpacityAnimation.repeatCount = MAXFLOAT; - - CAAnimationGroup *group = [[CAAnimationGroup alloc] init]; - group.animations = @[ toShadowColorAnimation, toShadowOpacityAnimation, pulseShadowOpacityAnimation ]; - group.duration = MAXFLOAT; - - [avatar.layer removeAnimationForKey:@"inactiveShadow"]; - [avatar.layer addAnimation:group forKey:@"targetedShadow"]; - } - } - else { - if ([avatar.layer animationForKey:@"targetedShadow"]) { - CABasicAnimation *toShadowColorAnimation = [CABasicAnimation animationWithKeyPath:@"shadowColor"]; - toShadowColorAnimation.toValue = (__bridge id)[UIColor blackColor].CGColor; - toShadowColorAnimation.duration = 0.5f; - - CABasicAnimation *toShadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"]; - toShadowOpacityAnimation.toValue = @1.0f; - toShadowOpacityAnimation.duration = 0.5f; - - CAAnimationGroup *group = [[CAAnimationGroup alloc] init]; - group.animations = @[ toShadowColorAnimation, toShadowOpacityAnimation ]; - group.duration = 0.5f; - - [avatar.layer removeAnimationForKey:@"targetedShadow"]; - [avatar.layer addAnimation:group forKey:@"inactiveShadow"]; - } - } -} - -#pragma mark - UITextFieldDelegate - -- (void)textFieldDidBeginEditing:(UITextField *)textField { - - [self setPasswordTip:nil]; -} - -- (BOOL)textFieldShouldReturn:(UITextField *)textField { - - [textField resignFirstResponder]; - - if (textField == self.emergencyName) { - if (![self.emergencyMasterPassword.text length]) - [self.emergencyMasterPassword becomeFirstResponder]; - } - - else if (textField == self.emergencyMasterPassword) { - if (![self.emergencySite.text length]) - [self.emergencySite becomeFirstResponder]; - } - - else if (textField == self.passwordField) { - [self setSpinnerActive:YES]; - - if ([self selectedUserForThread].keyID) - [self tryMasterPassword]; - - else - [PearlAlert showAlertWithTitle:@"New Master Password" - message:@"Please confirm the spelling of this new master password." - viewStyle:UIAlertViewStyleSecureTextInput - initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { - [self setSpinnerActive:NO]; - - if (buttonIndex == [alert cancelButtonIndex]) - 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 initAlert:nil tappedButtonBlock:nil - cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; - return; - } - - [self tryMasterPassword]; - } - cancelTitle:[PearlStrings get].commonButtonCancel - otherTitles:[PearlStrings get].commonButtonContinue, nil]; - } - - return YES; -} - -- (void)textFieldDidEndEditing:(UITextField *)textField { - - if (textField == self.emergencyName || textField == self.emergencyMasterPassword) - [self updateEmergencyKey]; - - if (textField == self.emergencySite) - [self updateEmergencyPassword]; -} - -- (void)updateEmergencyKey { - - if (![self.emergencyMasterPassword.text length] || ![self.emergencyName.text length]) - return; - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - [self.emergencyActivity startAnimating]; - [self.emergencyPassword setTitle:@"" forState:UIControlStateNormal]; - - NSString *masterPassword = self.emergencyMasterPassword.text; - NSString *userName = self.emergencyName.text; - - [self.emergencyQueue addOperationWithBlock:^{ - self.emergencyKey = [MPAlgorithmDefault keyForPassword:masterPassword ofUserNamed:userName]; - - [self updateEmergencyPassword]; - }]; - }]; -} - -- (MPElementType)emergencyType { - - switch (self.emergencyTypeControl.selectedSegmentIndex) { - case 0: - return MPElementTypeGeneratedMaximum; - case 1: - return MPElementTypeGeneratedLong; - case 2: - return MPElementTypeGeneratedMedium; - case 3: - return MPElementTypeGeneratedBasic; - case 4: - return MPElementTypeGeneratedShort; - case 5: - return MPElementTypeGeneratedPIN; - default: - Throw(@"Unsupported type index: %ld", (long)self.emergencyTypeControl.selectedSegmentIndex); - } -} - -- (void)updateEmergencyPassword { - - if (!self.emergencyKey || ![self.emergencySite.text length]) - return; - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - [self.emergencyPassword setTitle:@"" forState:UIControlStateNormal]; - - NSString *name = self.emergencySite.text; - NSUInteger counter = (NSUInteger)self.emergencyCounterStepper.value; - - [self.emergencyQueue addOperationWithBlock:^{ - NSString *content = [MPAlgorithmDefault generateContentNamed:name ofType:[self emergencyType] - withCounter:counter usingKey:self.emergencyKey]; - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - [self.emergencyActivity stopAnimating]; - [self.emergencyPassword setTitle:content forState:UIControlStateNormal]; - }]; - }]; - }]; -} - -- (IBAction)emergencyOpen:(id)sender { - - if ([sender isKindOfClass:[UIGestureRecognizer class]] && ((UIGestureRecognizer *)sender).state != UIGestureRecognizerStateBegan) - return; - - [self emergencyOpenAnimated:YES]; -} - -- (IBAction)emergencyClose:(id)sender { - - [self emergencyCloseAnimated:YES]; -} - -- (IBAction)emergencyCopy:(id)sender { - - inf(@"Copying emergency password for: %@", self.emergencyName.text); - [UIPasteboard generalPasteboard].string = [self.emergencyPassword titleForState:UIControlStateNormal]; - - [UIView animateWithDuration:0.3f animations:^{ - self.emergencyContentTipContainer.alpha = 1; - } completion:^(BOOL finished) { - if (finished) { - dispatch_time_t popTime = dispatch_time( DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC ); - dispatch_after( popTime, dispatch_get_main_queue(), ^(void) { - [UIView animateWithDuration:0.2f animations:^{ - self.emergencyContentTipContainer.alpha = 0; - }]; - } ); - } - }]; - - MPCheckpoint( MPCheckpointCopyToPasteboard, @{ - @"type" : NilToNSNull([MPAlgorithmDefault nameOfType:self.emergencyType]), - @"version" : @MPAlgorithmDefaultVersion, - @"emergency" : @YES, - } ); -} - -- (void)emergencyOpenAnimated:(BOOL)animated { - - [[self.emergencyGeneratorContainer findFirstResponderInHierarchy] resignFirstResponder]; - - if (animated) { - self.emergencyGeneratorContainer.alpha = 0; - self.emergencyGeneratorContainer.hidden = NO; - self.emergencyGeneratorContainer.frame = CGRectSetX( self.emergencyGeneratorContainer.frame, - self.emergencyGeneratorContainer.frame.origin.x - 100 ); - - [UIView animateWithDuration:0.2 animations:^{ - self.emergencyGeneratorContainer.frame = CGRectSetX( self.emergencyGeneratorContainer.frame, - self.emergencyGeneratorContainer.frame.origin.x + 100 ); - self.emergencyGeneratorContainer.alpha = 1; - } completion:^(BOOL finished) { - if (finished) - [self emergencyOpenAnimated:NO]; - }]; - return; - } - - MPCheckpoint( MPCheckpointEmergencyGenerator, nil ); - self.emergencyGeneratorContainer.hidden = NO; - self.emergencyGeneratorContainer.alpha = 1; - [self.emergencyName becomeFirstResponder]; -} - -- (void)emergencyCloseAnimated:(BOOL)animated { - - [[self.emergencyGeneratorContainer findFirstResponderInHierarchy] resignFirstResponder]; - - if (animated) { - [UIView animateWithDuration:0.2 animations:^{ - self.emergencyGeneratorContainer.alpha = 0; - } completion:^(BOOL finished) { - if (finished) - [self emergencyCloseAnimated:NO]; - }]; - return; - } - - self.emergencyName.text = @""; - self.emergencyMasterPassword.text = @""; - self.emergencySite.text = @""; - self.emergencyCounterStepper.value = 1; - [self.emergencyPassword setTitle:@"" forState:UIControlStateNormal]; - [self.emergencyActivity stopAnimating]; - self.emergencyGeneratorContainer.alpha = 0; - self.emergencyGeneratorContainer.hidden = YES; -} - -#pragma mark - UIScrollViewDelegate - -- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity - targetContentOffset:(inout CGPoint *)targetContentOffset { - - CGFloat xOfMiddle = targetContentOffset->x + scrollView.bounds.size.width / 2; - UIButton *middleAvatar = (UIButton *)[PearlUIUtils viewClosestTo:CGPointMake( xOfMiddle, targetContentOffset->y ) - ofArray:scrollView.subviews]; - *targetContentOffset = CGPointMake( middleAvatar.center.x - scrollView.bounds.size.width / 2, targetContentOffset->y ); - - [self updateLayoutAnimated:NO allowScroll:NO completion:nil]; -} - -- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { - - [self updateLayoutAnimated:YES allowScroll:YES completion:nil]; -} - -- (void)scrollViewDidScroll:(UIScrollView *)scrollView { - - [self updateLayoutAnimated:NO allowScroll:NO completion:nil]; -} - -#pragma mark - UIWebViewDelegate - -- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request - navigationType:(UIWebViewNavigationType)navigationType { - - if (navigationType == UIWebViewNavigationTypeLinkClicked) { - [UIApp openURL:[request URL]]; - return NO; - } - - return YES; -} - -#pragma mark - IBActions - -- (IBAction)targetedUserAction:(UILongPressGestureRecognizer *)sender { - - if (sender.state != UIGestureRecognizerStateBegan) - return; - - if ([self selectedUserForThread]) - return; - - NSManagedObjectContext *context = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady]; - MPUserEntity *targetedUser = [self userForAvatar:[self findTargetedAvatar] inContext:context]; - if (!targetedUser) - return; - - [PearlSheet showSheetWithTitle:targetedUser.name - viewStyle:UIActionSheetStyleBlackTranslucent - initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) { - if (buttonIndex == [sheet cancelButtonIndex]) - return; - - if (buttonIndex == [sheet destructiveButtonIndex]) { - [context deleteObject:targetedUser]; - [context saveToStore]; - - dispatch_async( dispatch_get_main_queue(), ^{ - [self updateUsers]; - } ); - return; - } - - if (buttonIndex == [sheet firstOtherButtonIndex]) - [[MPiOSAppDelegate get] changeMasterPasswordFor:targetedUser saveInContext:context didResetBlock:^{ - dispatch_async( dispatch_get_main_queue(), ^{ - [[self avatarForUser:targetedUser] setSelected:YES]; - } ); - }]; - } cancelTitle:[PearlStrings get].commonButtonCancel - destructiveTitle:@"Delete User" otherTitles:@"Reset Password", nil]; -} - -- (IBAction)facebook:(id)sender { - - if (![SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) { - [PearlAlert showAlertWithTitle:@"Facebook Not Enabled" message:@"To send tweets, configure Facebook from Settings." - viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil cancelTitle:nil otherTitles:@"OK", nil]; - return; - } - - SLComposeViewController *vc = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook]; - [vc setInitialText:@"I've started doing passwords properly thanks to Master Password for iOS."]; - [vc addImage:[UIImage imageNamed:@"iTunesArtwork-Rounded"]]; - [vc addURL:[NSURL URLWithString:@"http://masterpasswordapp.com"]]; - [self presentViewController:vc animated:YES completion:nil]; -} - -- (IBAction)twitter:(id)sender { - - if (![SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) { - [PearlAlert showAlertWithTitle:@"Twitter Not Enabled" message:@"To send tweets, configure Twitter from Settings." - viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil cancelTitle:nil otherTitles:@"OK", nil]; - return; - } - - SLComposeViewController *vc = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]; - [vc setInitialText:@"I've started doing passwords properly thanks to Master Password."]; - [vc addImage:[UIImage imageNamed:@"iTunesArtwork-Rounded"]]; - [vc addURL:[NSURL URLWithString:@"http://masterpasswordapp.com"]]; - [self presentViewController:vc animated:YES completion:nil]; -} - -- (IBAction)google:(id)sender { - -// id shareDialog = [[GPPShare sharedInstance] shareDialog]; -// [[[shareDialog setURLToShare:[NSURL URLWithString:@"http://masterpasswordapp.com"]] -// setPrefillText:@"I've started doing passwords properly thanks to Master Password."] open]; -} - -- (IBAction)mail:(id)sender { - - [[MPiOSAppDelegate get] showFeedbackWithLogs:NO forVC:self]; -} - -- (IBAction)add:(id)sender { - - [PearlSheet showSheetWithTitle:@"Follow Master Password" viewStyle:UIActionSheetStyleBlackTranslucent - initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) { - if (buttonIndex == [sheet cancelButtonIndex]) - return; - - if (buttonIndex == [sheet firstOtherButtonIndex]) { - // Google+ - [UIApp openURL:[NSURL URLWithString:@"https://plus.google.com/116256327773442623984/about"]]; - return; - } - if (buttonIndex == [sheet firstOtherButtonIndex] + 1) { - // Facebook - [UIApp openURL:[NSURL URLWithString:@"https://www.facebook.com/masterpasswordapp"]]; - return; - } - if (buttonIndex == [sheet firstOtherButtonIndex] + 2) { - // Twitter - UIApplication *application = UIApp; - for (NSString *candidate in @[ - @"twitter://user?screen_name=%@", // Twitter - @"tweetbot:///user_profile/%@", // TweetBot - @"echofon:///user_timeline?%@", // Echofon - @"twit:///user?screen_name=%@", // Twittelator Pro - @"x-seesmic://twitter_profile?twitter_screen_name=%@", // Seesmic - @"x-birdfeed://user?screen_name=%@", // Birdfeed - @"tweetings:///user?screen_name=%@", // Tweetings - @"simplytweet:?link=http://twitter.com/%@", // SimplyTweet - @"icebird://user?screen_name=%@", // IceBird - @"fluttr://user/%@", // Fluttr - @"http://twitter.com/%@" - ]) { - NSURL *url = [NSURL URLWithString:PearlString( candidate, @"master_password" )]; - - if ([application canOpenURL:url]) { - [application openURL:url]; - break; - } - } - return; - } - if (buttonIndex == [sheet firstOtherButtonIndex] + 3) { - // Mailing List - [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; - } - if (buttonIndex == [sheet firstOtherButtonIndex] + 4) { - // GitHub - [UIApp openURL:[NSURL URLWithString:@"https://github.com/Lyndir/MasterPassword"]]; - return; - } - } cancelTitle:[PearlStrings get].commonButtonCancel - destructiveTitle:nil otherTitles:@"Google+", @"Facebook", @"Twitter", @"Mailing List", @"GitHub", nil]; -} - -#pragma mark - Core Data - -- (MPUserEntity *)selectedUserForThread { - - return [self selectedUserInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]; -} - -- (MPUserEntity *)selectedUserInContext:(NSManagedObjectContext *)moc { - - if (!_selectedUserOID) - return nil; - - NSError *error; - MPUserEntity *selectedUser = (MPUserEntity *)[moc existingObjectWithID:_selectedUserOID error:&error]; - if (!selectedUser) { - err(@"Failed to retrieve selected user: %@", error); - _selectedUserOID = nil; - [self updateUsers]; - } - - return selectedUser; -} - -- (BOOL)setSelectedUser:(MPUserEntity *)selectedUser { - - if ([_selectedUserOID isEqual:selectedUser.objectID]) - return NO; - - NSError *error = nil; - if (selectedUser.objectID.isTemporaryID && - ![selectedUser.managedObjectContext obtainPermanentIDsForObjects:@[ selectedUser ] error:&error]) { - err(@"Failed to obtain a permanent object ID after setting selected user: %@", error); - _selectedUserOID = nil; - [self updateUsers]; - } - - _selectedUserOID = selectedUser.objectID; - return YES; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPUsersViewController.m b/MasterPassword/ObjC/iOS/MPUsersViewController.m index eae97458..12057bd4 100644 --- a/MasterPassword/ObjC/iOS/MPUsersViewController.m +++ b/MasterPassword/ObjC/iOS/MPUsersViewController.m @@ -805,7 +805,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) { case MPActiveUserStateUserName: case MPActiveUserStateMasterPasswordChoice: case MPActiveUserStateMasterPasswordConfirmation: { - self.navigationBarToTopConstraint.priority = UILayoutPriorityDefaultHigh; + [self.navigationBarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; self.avatarCollectionView.scrollEnabled = NO; self.entryContainer.alpha = 1; self.footerContainer.alpha = 1; @@ -813,14 +813,13 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) { break; } case MPActiveUserStateMinimized: { - self.navigationBarToTopConstraint.priority = 1; + [self.navigationBarToTopConstraint layoutWithPriority:1]; self.avatarCollectionView.scrollEnabled = NO; self.entryContainer.alpha = 0; self.footerContainer.alpha = 0; break; } } - [self.navigationBarToTopConstraint apply]; } completion:^(BOOL finished) { dbg(@"resume updates"); [_afterUpdates setSuspended:NO]; diff --git a/MasterPassword/ObjC/iOS/MPWebViewController.m b/MasterPassword/ObjC/iOS/MPWebViewController.m index 327244d0..94ccc45c 100644 --- a/MasterPassword/ObjC/iOS/MPWebViewController.m +++ b/MasterPassword/ObjC/iOS/MPWebViewController.m @@ -34,6 +34,8 @@ if (!self.initialURL) self.initialURL = [NSURL URLWithString:@"http://masterpasswordapp.com"]; + self.webNavigationItem.title = self.initialURL.host; + self.webView.alpha = 0; [self.webView loadRequest:[[NSURLRequest alloc] initWithURL:self.initialURL]]; } diff --git a/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m b/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m index 77d6409b..95b2c834 100644 --- a/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m +++ b/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m @@ -364,27 +364,34 @@ - (void)showExportForVC:(UIViewController *)viewController { - [PearlAlert showNotice: - @"This will export all your site names.\n\n" - @"You can open the export with a text editor to get an overview of all your sites.\n\n" - @"The file also acts as a personal backup of your site list in case you don't sync with iCloud/iTunes." - tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { - [PearlAlert showAlertWithTitle:@"Reveal Passwords?" message: - @"Would you like to make all your passwords visible in the export?\n\n" - @"A safe export will only include your stored passwords, in an encrypted manner, " - @"making the result safe from falling in the wrong hands.\n\n" - @"If all your passwords are shown and somebody else finds the export, " - @"they could gain access to all your sites!" - viewStyle:UIAlertViewStyleDefault initAlert:nil - tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { - if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 0) - // Safe Export - [self showExportRevealPasswords:NO forVC:viewController]; - if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 1) - // Show Passwords - [self showExportRevealPasswords:YES forVC:viewController]; - } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Safe Export", @"Show Passwords", nil]; - } otherTitles:nil]; + [PearlAlert showAlertWithTitle:@"Exporting Your Sites" + message:@"An export is great for keeping a " + @"backup list of your accounts.\n\n" + @"When the file is ready, you will be " + @"able to mail it to yourself.\n" + @"You can open it with a text editor or " + @"with Master Password if you need to " + @"restore your list of sites." + viewStyle:UIAlertViewStyleDefault initAlert:nil + tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { + if (buttonIndex != [alert cancelButtonIndex]) + [PearlAlert showAlertWithTitle:@"Show Passwords?" + message:@"Would you like to make all your passwords " + @"visible in the export file?\n\n" + @"A safe export will include all sites " + @"but make their passwords invisible.\n" + @"It is great as a backup and remains " + @"safe when fallen in the wrong hands." + viewStyle:UIAlertViewStyleDefault initAlert:nil + tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { + if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 0) + // Safe Export + [self showExportRevealPasswords:NO forVC:viewController]; + if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 1) + // Show Passwords + [self showExportRevealPasswords:YES forVC:viewController]; + } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Safe Export", @"Show Passwords", nil]; + } cancelTitle:@"Cancel" otherTitles:@"Export Sites", nil]; } - (void)showExportRevealPasswords:(BOOL)revealPasswords forVC:(UIViewController *)viewController { diff --git a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard b/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard deleted file mode 100644 index d5635626..00000000 --- a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard +++ /dev/null @@ -1,3176 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 119-20:51:52 MPiOSAppDelegate.m:36 | INFO : Initializing TestFlight -119-20:51:52 MPiOSAppDelegate.m:80 | INFO : Initializing Crashlytics -119-20:51:53 PearlAppDelegate.m:71 | INFO : Master Password (MasterPassword) 1.4 (1.4.0) (GIT: 1.4-0-g8a4eecd-dirty) -119-20:51:53 MPiOSAppDelegate.m:257 | INFO : Started up with device identifier: A8C51CDA-6F60-4F0C-BFC9-68A08F2F2DD7 -119-20:51:59 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] (Re)loading store... -119-20:51:59 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Will load cloud store: 0B3CA2DF-5796-44DF-B5E0-121EC3846464 (definite). -119-20:51:59 PearlConfig.m:193 | INFO : Lock screen will appear -119-20:51:59 MPiOSAppDelegate.m:412 | INFO : Re-activated -119-20:51:59 PearlConfig.m:180 | DEBUG : MPiOSConfig.launchCount = [70 ->] 71 -119-20:52:02 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Clearing stores... -119-20:52:03 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Loading store without seeding. -119-20:52:09 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Cloud enabled and successfully loaded cloud store. -119-20:52:09 MPAppDelegate_Store.m:299 | INFO : Using iCloud? 1 -119-20:52:12 MPAppDelegate_Key.m:28 | INFO : Found key in keychain for: b55911588b178466be1d6392597e899b8de46f9a -119-20:52:12 MPAppDelegate_Key.m:132 | INFO : Logged in: b55911588b178466be1d6392597e899b8de46f9a -119-20:52:13 MPUnlockViewController.m:229 | INFO : Lock screen will disappear -119-20:52:13 MPMainViewController.m:142 | INFO : Main will appear -119-20:52:16 MPMainViewController.m:734 | INFO : Action: Preferences -119-20:52:17 MPMainViewController.m:187 | INFO : Main will disappear. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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. - -Note that even without iCloud syncing, you can make your passwords available from any device by simply creating the same user on all your devices. Enabling iCloud is mainly benefitial to keep the list of sites you use in sync on all your devices. - -Only site names and custom passwords are sent to iCloud. Passwords are encrypted with your master password and illegible by Apple or any interceptor. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . - -You don't need to remember any password generated by this app, but - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - and that it is secure. - -Don't reuse an old password! -Don't give out your master password. -A small nonsense sentence is a great password. - - - - - - - - - - - - - - - - - -You can make passwords for anything, like email addresses, sites or real-world things like a bike lock: if you can name it, you can get a password for it. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The right balance between security and convenience is often very personal. - -To make getting to your passwords faster, you can remain logged in after you close Master Password. This allows you to skip having to log in the next time. - -However, it means that anyone who finds your device unlocked can do the same. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj index 259c9694..7fd1ebcf 100644 --- a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj +++ b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj @@ -41,7 +41,6 @@ 93D399BBC0A7EC746CB1B19B /* MPLogsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D391943675426839501BB8 /* MPLogsViewController.h */; }; 93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */; }; 93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D8A953779B35403AF6E /* PearlUICollectionView.m */; }; - 93D39B21156EC9A0B4C2BC83 /* MPPreferencesViewControllerOld.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390381D3D3AE241B5D341 /* MPPreferencesViewControllerOld.m */; }; 93D39B76DD5AB108BA8928E8 /* UIScrollView+PearlAdjustInsets.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */; }; 93D39B842AB9A5D072810D76 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */; }; 93D39B8F90F58A5D158DDBA3 /* MPPasswordsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3924EE15017F8A12CB436 /* MPPasswordsViewController.m */; }; @@ -50,6 +49,7 @@ 93D39C8AD8EAB747856B3A8C /* LLModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3923B42DA2DA18F287092 /* LLModel.m */; }; 93D39CB5E2EC1078E898F46A /* MPPasswordLargeCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3937863061C3916AF7AD2 /* MPPasswordLargeCell.m */; }; 93D39D596A2E376D6F6F5DA1 /* MPCombinedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D393310223DDB35218467A /* MPCombinedViewController.m */; }; + 93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39CC01630D0421205C4C4 /* MPNavigationController.m */; }; 93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; }; 93D39E34FD28D24FE3442C48 /* UITextView+PearlAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3977321EB249981821AB0 /* UITextView+PearlAttributes.m */; }; 93D39EAA4D064193074D3021 /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A813CA9D7E192261ED2 /* MPFixable.m */; }; @@ -249,19 +249,10 @@ DABD3C091711E2DC00CF925C /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BBA1711E2DC00CF925C /* MPUserEntity.m */; }; DABD3C141711E2DC00CF925C /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BD01711E2DC00CF925C /* MasterPassword.xcdatamodeld */; }; DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BD91711E2DC00CF925C /* MPiOSAppDelegate.m */; }; - DABD3C161711E2DC00CF925C /* MPAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BDB1711E2DC00CF925C /* MPAppViewController.m */; }; - DABD3C171711E2DC00CF925C /* MPAppsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BDD1711E2DC00CF925C /* MPAppsViewController.m */; }; - DABD3C181711E2DC00CF925C /* MPElementListAllViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BDF1711E2DC00CF925C /* MPElementListAllViewController.m */; }; - DABD3C191711E2DC00CF925C /* MPElementListCellView.xib in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BE01711E2DC00CF925C /* MPElementListCellView.xib */; }; - DABD3C1A1711E2DC00CF925C /* MPElementListController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BE21711E2DC00CF925C /* MPElementListController.m */; }; - DABD3C1B1711E2DC00CF925C /* MPElementListSearchController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BE51711E2DC00CF925C /* MPElementListSearchController.m */; }; DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BE71711E2DC00CF925C /* MPGuideViewController.m */; }; - DABD3C1D1711E2DC00CF925C /* MPMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BE91711E2DC00CF925C /* MPMainViewController.m */; }; DABD3C1E1711E2DC00CF925C /* MPPreferencesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BEB1711E2DC00CF925C /* MPPreferencesViewController.m */; }; DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BED1711E2DC00CF925C /* MPTypeViewController.m */; }; - DABD3C201711E2DC00CF925C /* MPUnlockViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BEF1711E2DC00CF925C /* MPUnlockViewController.m */; }; DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BF11711E2DC00CF925C /* MPiOSConfig.m */; }; - DABD3C221711E2DC00CF925C /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BF21711E2DC00CF925C /* MainStoryboard_iPhone.storyboard */; }; DABD3C241711E2DC00CF925C /* MasterPassword.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BF81711E2DC00CF925C /* MasterPassword.entitlements */; }; DABD3C251711E2DC00CF925C /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BF91711E2DC00CF925C /* Settings.bundle */; }; DABD3C261711E2DC00CF925C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BFA1711E2DC00CF925C /* InfoPlist.strings */; }; @@ -511,7 +502,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 93D390381D3D3AE241B5D341 /* MPPreferencesViewControllerOld.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPreferencesViewControllerOld.m; sourceTree = ""; }; 93D390519405B76CC6A57C4F /* MPCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCell.h; sourceTree = ""; }; 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = ""; }; 93D39097C0AAE62C1C321BFC /* MPPasswordTypesCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordTypesCell.m; sourceTree = ""; }; @@ -540,6 +530,7 @@ 93D395BA6B2CFF5F49A4D25F /* MPPasswordLargeStoredCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeStoredCell.h; sourceTree = ""; }; 93D3966B527CA47A0A661CE2 /* MPPasswordLargeDeleteCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeDeleteCell.h; sourceTree = ""; }; 93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = ""; }; + 93D3970502644794E8A027BE /* MPNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPNavigationController.h; sourceTree = ""; }; 93D3971FE104BB4052484151 /* MPUsersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUsersViewController.h; sourceTree = ""; }; 93D39730673227EFF6DEFF19 /* MPSetupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSetupViewController.h; sourceTree = ""; }; 93D3977321EB249981821AB0 /* UITextView+PearlAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITextView+PearlAttributes.m"; sourceTree = ""; }; @@ -551,7 +542,6 @@ 93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPWebViewController.m; sourceTree = ""; }; 93D3993422E207BF0B21D089 /* MPPasswordLargeGeneratedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeGeneratedCell.m; sourceTree = ""; }; 93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCoachmarkViewController.m; sourceTree = ""; }; - 93D39961CD6A43648CC0B0DB /* MPPreferencesViewControllerOld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPreferencesViewControllerOld.h; sourceTree = ""; }; 93D39975CE5AEC99E3F086C7 /* MPPasswordCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordCell.h; sourceTree = ""; }; 93D3999693660C89A7465F4E /* MPCoachmarkViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCoachmarkViewController.h; sourceTree = ""; }; 93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUsersViewController.m; sourceTree = ""; }; @@ -574,6 +564,7 @@ 93D39C44361BE57AF0B3071F /* MPPasswordsSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordsSegue.h; sourceTree = ""; }; 93D39C86E984EC65DA5ACB1D /* MPAppSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppSettingsViewController.h; sourceTree = ""; }; 93D39C8E26B06F01566785B7 /* LLToggleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLToggleViewController.m; sourceTree = ""; }; + 93D39CC01630D0421205C4C4 /* MPNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNavigationController.m; sourceTree = ""; }; 93D39CDD434AFD6E1B0DA359 /* MPEmergencyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEmergencyViewController.h; sourceTree = ""; }; 93D39CE1138FDA4D3D1B847A /* MPPasswordLargeGeneratedCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeGeneratedCell.h; sourceTree = ""; }; 93D39CF8ADF4542CDC4CD385 /* MPCombinedViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCombinedViewController.h; sourceTree = ""; }; @@ -1310,31 +1301,14 @@ DABD3BD41711E2DC00CF925C /* MasterPassword 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 4.xcdatamodel"; sourceTree = ""; }; DABD3BD81711E2DC00CF925C /* MPiOSAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPiOSAppDelegate.h; sourceTree = ""; }; DABD3BD91711E2DC00CF925C /* MPiOSAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPiOSAppDelegate.m; sourceTree = ""; }; - DABD3BDA1711E2DC00CF925C /* MPAppViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppViewController.h; sourceTree = ""; }; - DABD3BDB1711E2DC00CF925C /* MPAppViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppViewController.m; sourceTree = ""; }; - DABD3BDC1711E2DC00CF925C /* MPAppsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppsViewController.h; sourceTree = ""; }; - DABD3BDD1711E2DC00CF925C /* MPAppsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppsViewController.m; sourceTree = ""; }; - DABD3BDE1711E2DC00CF925C /* MPElementListAllViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListAllViewController.h; sourceTree = ""; }; - DABD3BDF1711E2DC00CF925C /* MPElementListAllViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementListAllViewController.m; sourceTree = ""; }; - DABD3BE01711E2DC00CF925C /* MPElementListCellView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPElementListCellView.xib; sourceTree = ""; }; - DABD3BE11711E2DC00CF925C /* MPElementListController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListController.h; sourceTree = ""; }; - DABD3BE21711E2DC00CF925C /* MPElementListController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementListController.m; sourceTree = ""; }; - DABD3BE31711E2DC00CF925C /* MPElementListDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListDelegate.h; sourceTree = ""; }; - DABD3BE41711E2DC00CF925C /* MPElementListSearchController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListSearchController.h; sourceTree = ""; }; - DABD3BE51711E2DC00CF925C /* MPElementListSearchController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementListSearchController.m; sourceTree = ""; }; DABD3BE61711E2DC00CF925C /* MPGuideViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPGuideViewController.h; sourceTree = ""; }; DABD3BE71711E2DC00CF925C /* MPGuideViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPGuideViewController.m; sourceTree = ""; }; - DABD3BE81711E2DC00CF925C /* MPMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMainViewController.h; sourceTree = ""; }; - DABD3BE91711E2DC00CF925C /* MPMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMainViewController.m; sourceTree = ""; }; DABD3BEA1711E2DC00CF925C /* MPPreferencesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPreferencesViewController.h; sourceTree = ""; }; DABD3BEB1711E2DC00CF925C /* MPPreferencesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPreferencesViewController.m; sourceTree = ""; }; DABD3BEC1711E2DC00CF925C /* MPTypeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPTypeViewController.h; sourceTree = ""; }; DABD3BED1711E2DC00CF925C /* MPTypeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTypeViewController.m; sourceTree = ""; }; - DABD3BEE1711E2DC00CF925C /* MPUnlockViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUnlockViewController.h; sourceTree = ""; }; - DABD3BEF1711E2DC00CF925C /* MPUnlockViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUnlockViewController.m; sourceTree = ""; }; DABD3BF01711E2DC00CF925C /* MPiOSConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPiOSConfig.h; sourceTree = ""; }; DABD3BF11711E2DC00CF925C /* MPiOSConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPiOSConfig.m; sourceTree = ""; }; - DABD3BF21711E2DC00CF925C /* MainStoryboard_iPhone.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MainStoryboard_iPhone.storyboard; sourceTree = ""; }; DABD3BF31711E2DC00CF925C /* MasterPassword-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MasterPassword-Info.plist"; sourceTree = ""; }; DABD3BF41711E2DC00CF925C /* MasterPassword-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MasterPassword-Prefix.pch"; sourceTree = ""; }; DABD3BF81711E2DC00CF925C /* MasterPassword.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = ""; }; @@ -2523,35 +2497,16 @@ 93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */, 93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */, 93D39CDD434AFD6E1B0DA359 /* MPEmergencyViewController.h */, - 93D390381D3D3AE241B5D341 /* MPPreferencesViewControllerOld.m */, - 93D39961CD6A43648CC0B0DB /* MPPreferencesViewControllerOld.h */, DABD3BD81711E2DC00CF925C /* MPiOSAppDelegate.h */, DABD3BD91711E2DC00CF925C /* MPiOSAppDelegate.m */, - DABD3BDA1711E2DC00CF925C /* MPAppViewController.h */, - DABD3BDB1711E2DC00CF925C /* MPAppViewController.m */, - DABD3BDC1711E2DC00CF925C /* MPAppsViewController.h */, - DABD3BDD1711E2DC00CF925C /* MPAppsViewController.m */, - DABD3BDE1711E2DC00CF925C /* MPElementListAllViewController.h */, - DABD3BDF1711E2DC00CF925C /* MPElementListAllViewController.m */, - DABD3BE01711E2DC00CF925C /* MPElementListCellView.xib */, - DABD3BE11711E2DC00CF925C /* MPElementListController.h */, - DABD3BE21711E2DC00CF925C /* MPElementListController.m */, - DABD3BE31711E2DC00CF925C /* MPElementListDelegate.h */, - DABD3BE41711E2DC00CF925C /* MPElementListSearchController.h */, - DABD3BE51711E2DC00CF925C /* MPElementListSearchController.m */, DABD3BE61711E2DC00CF925C /* MPGuideViewController.h */, DABD3BE71711E2DC00CF925C /* MPGuideViewController.m */, - DABD3BE81711E2DC00CF925C /* MPMainViewController.h */, - DABD3BE91711E2DC00CF925C /* MPMainViewController.m */, DABD3BEA1711E2DC00CF925C /* MPPreferencesViewController.h */, DABD3BEB1711E2DC00CF925C /* MPPreferencesViewController.m */, DABD3BEC1711E2DC00CF925C /* MPTypeViewController.h */, DABD3BED1711E2DC00CF925C /* MPTypeViewController.m */, - DABD3BEE1711E2DC00CF925C /* MPUnlockViewController.h */, - DABD3BEF1711E2DC00CF925C /* MPUnlockViewController.m */, DABD3BF01711E2DC00CF925C /* MPiOSConfig.h */, DABD3BF11711E2DC00CF925C /* MPiOSConfig.m */, - DABD3BF21711E2DC00CF925C /* MainStoryboard_iPhone.storyboard */, DABD3BF31711E2DC00CF925C /* MasterPassword-Info.plist */, DABD3BF41711E2DC00CF925C /* MasterPassword-Prefix.pch */, DABD3BF81711E2DC00CF925C /* MasterPassword.entitlements */, @@ -2595,6 +2550,8 @@ 93D390FD93EFCFECB5193DEF /* MPPasswordsCoachmarkViewController.h */, 93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */, 93D39F556F2F142740A65E59 /* MPWebViewController.h */, + 93D39CC01630D0421205C4C4 /* MPNavigationController.m */, + 93D3970502644794E8A027BE /* MPNavigationController.h */, ); path = iOS; sourceTree = ""; @@ -3676,9 +3633,7 @@ DADEF4121810D2940052CA3E /* love-lyndir.button.green.png in Resources */, DABD3B9D1711E29800CF925C /* social-twitter.png in Resources */, DABD3B9E1711E29800CF925C /* social-twitter@2x.png in Resources */, - DABD3C191711E2DC00CF925C /* MPElementListCellView.xib in Resources */, DA854C8418D4CFBF00106317 /* avatar-add.png in Resources */, - DABD3C221711E2DC00CF925C /* MainStoryboard_iPhone.storyboard in Resources */, DABD3C241711E2DC00CF925C /* MasterPassword.entitlements in Resources */, DABD3C251711E2DC00CF925C /* Settings.bundle in Resources */, DABD3C261711E2DC00CF925C /* InfoPlist.strings in Resources */, @@ -3777,16 +3732,9 @@ DABD3C091711E2DC00CF925C /* MPUserEntity.m in Sources */, DABD3C141711E2DC00CF925C /* MasterPassword.xcdatamodeld in Sources */, DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */, - DABD3C161711E2DC00CF925C /* MPAppViewController.m in Sources */, - DABD3C171711E2DC00CF925C /* MPAppsViewController.m in Sources */, - DABD3C181711E2DC00CF925C /* MPElementListAllViewController.m in Sources */, - DABD3C1A1711E2DC00CF925C /* MPElementListController.m in Sources */, - DABD3C1B1711E2DC00CF925C /* MPElementListSearchController.m in Sources */, DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */, - DABD3C1D1711E2DC00CF925C /* MPMainViewController.m in Sources */, DABD3C1E1711E2DC00CF925C /* MPPreferencesViewController.m in Sources */, DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */, - DABD3C201711E2DC00CF925C /* MPUnlockViewController.m in Sources */, DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */, DABD3C271711E2DC00CF925C /* main.m in Sources */, 93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */, @@ -3805,13 +3753,13 @@ 93D391ED37C9F687FA51EAA1 /* MPEmergencySegue.m in Sources */, 93D394B5036C882B33C71872 /* MPPasswordsSegue.m in Sources */, 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 */, 93D39EAA4D064193074D3021 /* MPFixable.m in Sources */, 93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */, 93D398BD8B83FEE8BE4EFFFC /* MPPasswordLargeDeleteCell.m in Sources */, + 93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MasterPassword/ObjC/iOS/Storyboard.storyboard b/MasterPassword/ObjC/iOS/Storyboard.storyboard index 63b4c275..4b8c5063 100644 --- a/MasterPassword/ObjC/iOS/Storyboard.storyboard +++ b/MasterPassword/ObjC/iOS/Storyboard.storyboard @@ -251,7 +251,7 @@ - + @@ -410,7 +410,7 @@ - + @@ -504,7 +504,7 @@ - + @@ -538,7 +538,7 @@ - + @@ -604,7 +604,7 @@ - + @@ -684,7 +684,7 @@ - + @@ -728,7 +728,7 @@ - + @@ -762,7 +762,7 @@ - + @@ -796,7 +796,7 @@ - + @@ -830,7 +830,7 @@ - + @@ -865,6 +865,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1130,6 +1210,13 @@ +