2
0

Search & AllSites improvements, sort by recency, rememberLogin setup.

[UPDATED]   Simplified AllSites VC in IB (removed the unused navVC).
[UPDATED]   Outdated sites are now shown in the AllSites VC.
[ADDED]     An update-all-sites button when showing outdated sites in the AllSites VC.
[REMOVED]   Search scopes.
[ADDED]     Sorting elements by recency and usage count now.
[FIXED]     Initial positioning of help container.
[ADDED]     Setup VC for rememberLogin.
This commit is contained in:
Maarten Billemont 2013-04-15 00:04:16 -04:00
parent 7cf2c7f5c6
commit ee93412dd1
17 changed files with 451 additions and 246 deletions

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit 99c73fd3b37b4d2621548f5ae366c163231a346d Subproject commit 0d30693440fd520715f22789d33d5551b3b681c4

View File

@ -20,6 +20,7 @@
#import "MPElementListController.h" #import "MPElementListController.h"
@interface MPElementListAllViewController : MPElementListController @interface MPElementListAllViewController : MPElementListController
@property (weak, nonatomic) IBOutlet UINavigationBar *navigationBar;
- (IBAction)close:(id)sender; - (IBAction)close:(id)sender;
- (IBAction)add:(id)sender; - (IBAction)add:(id)sender;

View File

@ -16,9 +16,32 @@
// //
#import "MPElementListAllViewController.h" #import "MPElementListAllViewController.h"
#import "MPAppDelegate.h"
#import "MPAppDelegate_Store.h"
#define MPElementUpgradeOldContentKey @"MPElementUpgradeOldContentKey"
#define MPElementUpgradeNewContentKey @"MPElementUpgradeNewContentKey"
@implementation MPElementListAllViewController @implementation MPElementListAllViewController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if ([self.filter isEqualToString:MPElementListFilterNone]) {
self.navigationBar.topItem.title = @"All Sites";
self.navigationBar.topItem.rightBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add:)];
}
else if ([self.filter isEqualToString:MPElementListFilterOutdated]) {
self.navigationBar.topItem.title = @"Outdated";
self.navigationBar.topItem.rightBarButtonItem = [[UIBarButtonItem alloc]
initWithTitle:@"Upgrade All" style:UIBarButtonItemStyleBordered target:self action:@selector(upgradeAll:)];
}
[self updateData];
}
- (IBAction)close:(id)sender { - (IBAction)close:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil]; [self dismissViewControllerAnimated:YES completion:nil];
@ -40,11 +63,106 @@
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonOkay, nil]; cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonOkay, nil];
} }
- (void)viewWillAppear:(BOOL)animated { - (IBAction)upgradeAll:(id)sender {
[super viewWillAppear:animated]; [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;
[self updateData]; PearlAlert *activity = [PearlAlert showActivityWithTitle:@"Upgrading Sites"];
[self performUpgradeAllWithCompletion:^(BOOL success, NSDictionary *changes) {
dispatch_async( dispatch_get_main_queue(), ^{
[self showUpgradeChanges:changes];
[activity cancelAlert];
} );
}];
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil];
}
- (void)performUpgradeAllWithCompletion:(void(^)(BOOL success, NSDictionary *changes))completion {
[MPAppDelegate 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;
}
NSMutableDictionary *elementChanges = [NSMutableDictionary dictionaryWithCapacity:[elements count]];
for (MPElementEntity *element in elements) {
id oldContent = [element content];
[element migrateExplicitly:YES];
id newContent = [element content];
if (!(element.type & MPElementFeatureDevicePrivate) && (!oldContent || ![oldContent isEqual:newContent]))
[elementChanges setObject:@{
MPElementUpgradeOldContentKey : oldContent,
MPElementUpgradeNewContentKey : newContent,
} forKey:element.name];
}
completion(YES, elementChanges);
}];
}
- (void)showUpgradeChanges:(NSDictionary *)changes {
if (![changes count])
return;
NSMutableString *formattedChanges = [NSMutableString new];
for (NSString *changedElementName in changes) {
NSDictionary *elementChanges = [changes objectForKey:changedElementName];
id oldContent = [elementChanges objectForKey:MPElementUpgradeOldContentKey];
id newContent = [elementChanges objectForKey:MPElementUpgradeNewContentKey];
[formattedChanges appendFormat:@"%@: %@ -> %@\n", changedElementName, oldContent, newContent];
}
[PearlAlert showAlertWithTitle:@"Sites Upgraded"
message:PearlString( @"This upgrade has caused %d passwords to change.\n"
@"To make updating the actual passwords of these accounts easier, "
@"you can email a summary of these changes to yourself.", [changes count])
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex])
return;
[PearlEMail sendEMailTo:nil 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 { - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

View File

@ -1,28 +1,22 @@
//
// Created by lhunath on 2013-02-09.
//
// To change the template use AppCode | Preferences | File Templates.
//
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "MPElementListDelegate.h" #import "MPElementListDelegate.h"
typedef enum { #define MPElementListFilterNone @"MPElementListFilterNone"
MPSearchScopeAll, #define MPElementListFilterOutdated @"MPElementListFilterOutdated"
MPSearchScopeOutdated,
} MPSearchScope;
@interface MPElementListController : UITableViewController <NSFetchedResultsControllerDelegate> @interface MPElementListController : UITableViewController <NSFetchedResultsControllerDelegate>
@property (weak, nonatomic) IBOutlet id<MPElementListDelegate> delegate; @property (weak, nonatomic) IBOutlet id<MPElementListDelegate> delegate;
@property (readonly) NSFetchedResultsController *fetchedResultsController; @property (strong, nonatomic) NSString *filter;
@property (readonly) NSFetchedResultsController *fetchedResultsControllerByUses;
@property (readonly) NSFetchedResultsController *fetchedResultsControllerByLastUsed;
@property (readonly) NSDateFormatter *dateFormatter; @property (readonly) NSDateFormatter *dateFormatter;
- (void)updateData; - (void)updateData;
- (void)addElementNamed:(NSString *)siteName completion:(void (^)(BOOL success))completion; - (void)addElementNamed:(NSString *)siteName completion:(void (^)(BOOL success))completion;
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath; - (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atTableIndexPath:(NSIndexPath *)indexPath;
- (void)customTableViewUpdates; - (void)customTableViewUpdates;
@end @end

View File

@ -1,10 +1,3 @@
//
// Created by lhunath on 2013-02-09.
//
// To change the template use AppCode | Preferences | File Templates.
//
#import "MPElementListController.h" #import "MPElementListController.h"
#import "MPAppDelegate_Store.h" #import "MPAppDelegate_Store.h"
@ -15,7 +8,8 @@
@implementation MPElementListController { @implementation MPElementListController {
NSFetchedResultsController *_fetchedResultsController; NSFetchedResultsController *_fetchedResultsControllerByUses;
NSFetchedResultsController *_fetchedResultsControllerByLastUsed;
NSDateFormatter *_dateFormatter; NSDateFormatter *_dateFormatter;
} }
@ -57,23 +51,47 @@
}]; }];
} }
- (NSFetchedResultsController *)fetchedResultsController { - (NSFetchedResultsController *)fetchedResultsControllerByLastUsed {
if (!_fetchedResultsController) { if (!_fetchedResultsControllerByLastUsed) {
NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must run on the main thread."); NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must be accessed from the main thread.");
NSManagedObjectContext *moc = [MPAppDelegate managedObjectContextForThreadIfReady]; NSManagedObjectContext *moc = [MPAppDelegate managedObjectContextForThreadIfReady];
if (!moc) if (!moc)
return nil; return nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])]; NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
fetchRequest.sortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:@"uses_" ascending:NO]]; fetchRequest.sortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector(lastUsed) ) ascending:NO]];
fetchRequest.fetchBatchSize = 20; [self configureFetchRequest:fetchRequest];
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc _fetchedResultsControllerByLastUsed = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc
sectionNameKeyPath:nil cacheName:nil]; sectionNameKeyPath:nil cacheName:nil];
_fetchedResultsController.delegate = self; _fetchedResultsControllerByLastUsed.delegate = self;
} }
return _fetchedResultsController; return _fetchedResultsControllerByLastUsed;
}
- (NSFetchedResultsController *)fetchedResultsControllerByUses {
if (!_fetchedResultsControllerByUses) {
NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must be accessed from the main thread.");
NSManagedObjectContext *moc = [MPAppDelegate managedObjectContextForThreadIfReady];
if (!moc)
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:moc
sectionNameKeyPath:nil cacheName:nil];
_fetchedResultsControllerByUses.delegate = self;
}
return _fetchedResultsControllerByUses;
}
- (void)configureFetchRequest:(NSFetchRequest *)fetchRequest {
fetchRequest.fetchLimit = 5;
} }
- (NSDateFormatter *)dateFormatter { - (NSDateFormatter *)dateFormatter {
@ -92,34 +110,33 @@
// Build predicate. // Build predicate.
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user == %@", activeUser]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user == %@", activeUser];
// Add query predicate.
UISearchBar *searchBar = self.searchDisplayController.searchBar; UISearchBar *searchBar = self.searchDisplayController.searchBar;
if (searchBar) { if (searchBar) {
NSString *query = [searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSString *query = [searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if (!query) if (!query)
return; return;
// Add query predicate.
predicate = [NSCompoundPredicate andPredicateWithSubpredicates: predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
@[predicate, [NSPredicate predicateWithFormat:@"name BEGINSWITH[cd] %@", query]]]; @[predicate, [NSPredicate predicateWithFormat:@"name BEGINSWITH[cd] %@", query]]];
// Add scope predicate.
switch ((MPSearchScope) searchBar.selectedScopeButtonIndex) {
case MPSearchScopeAll:
break;
case MPSearchScopeOutdated:
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
@[[NSPredicate predicateWithFormat:@"requiresExplicitMigration_ == YES"], predicate]];
break;
}
} }
self.fetchedResultsController.fetchRequest.predicate = predicate;
// Add filter predicate.
if ([self.filter isEqualToString:MPElementListFilterOutdated])
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
@[[NSPredicate predicateWithFormat:@"requiresExplicitMigration_ == YES"], predicate]];
// Fetch
NSError *error; NSError *error;
if (![self.fetchedResultsController performFetch:&error]) self.fetchedResultsControllerByLastUsed.fetchRequest.predicate = predicate;
self.fetchedResultsControllerByUses.fetchRequest.predicate = predicate;
if (![self.fetchedResultsControllerByLastUsed performFetch:&error])
err(@"Couldn't fetch elements: %@", error); err(@"Couldn't fetch elements: %@", error);
else if (![self.fetchedResultsControllerByUses performFetch:&error])
[self.tableView reloadData]; err(@"Couldn't fetch elements: %@", error);
[self.tableView reloadData];
} }
- (void)customTableViewUpdates { - (void)customTableViewUpdates {
@ -140,52 +157,32 @@
case NSFetchedResultsChangeInsert: case NSFetchedResultsChangeInsert:
dbg(@"%@ -- NSFetchedResultsChangeInsert:%@", NSStringFromSelector(_cmd), anObject); dbg(@"%@ -- NSFetchedResultsChangeInsert:%@", NSStringFromSelector(_cmd), anObject);
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break; break;
case NSFetchedResultsChangeDelete: case NSFetchedResultsChangeDelete:
dbg(@"%@ -- NSFetchedResultsChangeDelete:%@", NSStringFromSelector(_cmd), anObject); dbg(@"%@ -- NSFetchedResultsChangeDelete:%@", NSStringFromSelector(_cmd), anObject);
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break; break;
case NSFetchedResultsChangeUpdate: case NSFetchedResultsChangeUpdate:
dbg(@"%@ -- NSFetchedResultsChangeUpdate:%@", NSStringFromSelector(_cmd), anObject); dbg(@"%@ -- NSFetchedResultsChangeUpdate:%@", NSStringFromSelector(_cmd), anObject);
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView reloadRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break; break;
case NSFetchedResultsChangeMove: case NSFetchedResultsChangeMove:
dbg(@"%@ -- NSFetchedResultsChangeMove:%@", NSStringFromSelector(_cmd), anObject); dbg(@"%@ -- NSFetchedResultsChangeMove:%@", NSStringFromSelector(_cmd), anObject);
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] [self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
withRowAnimation:UITableViewRowAnimationAutomatic]; withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] [self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ]
withRowAnimation:UITableViewRowAnimationAutomatic]; withRowAnimation:UITableViewRowAnimationAutomatic];
break; break;
} }
} }
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch (type) {
case NSFetchedResultsChangeInsert:
dbg(@"%@ -- NSFetchedResultsChangeInsert:%d", NSStringFromSelector(_cmd), sectionIndex);
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeDelete:
dbg(@"%@ -- NSFetchedResultsChangeDelete:%d", NSStringFromSelector(_cmd), sectionIndex);
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeMove:
case NSFetchedResultsChangeUpdate:
Throw(@"Invalid change type for section changes: %d", type);
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
dbg(@"%@ on %@", NSStringFromSelector(_cmd), [NSThread currentThread].name); dbg(@"%@ on %@", NSStringFromSelector(_cmd), [NSThread currentThread].name);
@ -195,16 +192,18 @@
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSInteger integer = (NSInteger)[[self.fetchedResultsController sections] count]; return 2;
dbg(@"%@ = %d", NSStringFromSelector(_cmd), integer);
return integer;
} }
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger integer = (NSInteger)[[[self.fetchedResultsController sections] objectAtIndex:(unsigned)section] numberOfObjects]; if (section == 0)
dbg(@"%@%d = %d", NSStringFromSelector(_cmd), section, integer); return (NSInteger)[[[self.fetchedResultsControllerByLastUsed sections] lastObject] numberOfObjects];
return integer;
if (section == 1)
return (NSInteger)[[[self.fetchedResultsControllerByUses sections] lastObject] numberOfObjects];
Throw(@"Unsupported section: %d", section);
} }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
@ -213,50 +212,82 @@
if (!cell) if (!cell)
cell = (UITableViewCell *) [[UIViewController alloc] initWithNibName:@"MPElementListCellView" bundle:nil].view; cell = (UITableViewCell *) [[UIViewController alloc] initWithNibName:@"MPElementListCellView" bundle:nil].view;
[self configureCell:cell inTableView:tableView atIndexPath:indexPath]; [self configureCell:cell inTableView:tableView atTableIndexPath:indexPath];
return cell; return cell;
} }
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath { - (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atTableIndexPath:(NSIndexPath *)indexPath {
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath]; MPElementEntity *element = [self elementForTableIndexPath:indexPath];
cell.textLabel.text = element.name; cell.textLabel.text = element.name;
cell.detailTextLabel.text = PearlString(@"%d views, last on %@: %@", cell.detailTextLabel.text = PearlString(@"%d views, last on %@: %@",
element.uses, [self.dateFormatter stringFromDate:element.lastUsed], [element.algorithm shortNameOfType:element.type]); 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: %d", indexPath.section);
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.delegate didSelectElement:[self.fetchedResultsController objectAtIndexPath:indexPath]]; [self.delegate didSelectElement:[self elementForTableIndexPath:indexPath]];
} }
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[[self.fetchedResultsController sections] objectAtIndex:(unsigned)section] name]; if (section == 0)
return @"Most Recently Used";
if (section == 1)
return @"Most Commonly Used";
Throw(@"Unsupported section: %d", section);
} }
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [self.fetchedResultsController sectionIndexTitles]; return @[@"recency", @"uses"];
} }
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index]; return index;
} }
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath { forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) { if (editingStyle == UITableViewCellEditingStyleDelete) {
NSManagedObjectContext *moc = self.fetchedResultsController.managedObjectContext; MPElementEntity *element = [self elementForTableIndexPath:indexPath];
[moc performBlock:^{ [element.managedObjectContext performBlockAndWait:^{
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
inf(@"Deleting element: %@", element.name); inf(@"Deleting element: %@", element.name);
[moc deleteObject:element]; [element.managedObjectContext deleteObject:element];
[element.managedObjectContext saveToStore];
#ifdef TESTFLIGHT_SDK_VERSION #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointDeleteElement]; [TestFlight passCheckpoint:MPCheckpointDeleteElement];

View File

@ -10,7 +10,6 @@
#import "MPMainViewController.h" #import "MPMainViewController.h"
#import "MPAppDelegate.h" #import "MPAppDelegate.h"
@interface MPElementListSearchController () @interface MPElementListSearchController ()
@property (nonatomic) BOOL newSiteSectionWasNeeded; @property (nonatomic) BOOL newSiteSectionWasNeeded;
@ -47,7 +46,7 @@
- (void)searchBarBookmarkButtonClicked:(UISearchBar *)searchBar { - (void)searchBarBookmarkButtonClicked:(UISearchBar *)searchBar {
[((MPMainViewController *)self.delegate) performSegueWithIdentifier:@"MP_AllSites" sender:self]; [((MPMainViewController *)self.delegate) performSegueWithIdentifier:@"MP_AllSites" sender:MPElementListFilterNone];
} }
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
@ -70,12 +69,7 @@
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller { - (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
controller.searchBar.showsScopeBar = controller.searchBar.selectedScopeButtonIndex != MPSearchScopeAll;
controller.searchBar.text = @""; controller.searchBar.text = @"";
if (controller.searchBar.showsScopeBar)
controller.searchBar.scopeButtonTitles = @[@"All", @"Outdated"];
else
controller.searchBar.scopeButtonTitles = nil;
[UIView animateWithDuration:0.2f animations:^{ [UIView animateWithDuration:0.2f animations:^{
self.searchTipContainer.alpha = 0; self.searchTipContainer.alpha = 0;
@ -91,8 +85,6 @@
controller.searchBar.prompt = nil; controller.searchBar.prompt = nil;
controller.searchBar.searchResultsButtonSelected = NO; controller.searchBar.searchResultsButtonSelected = NO;
controller.searchBar.selectedScopeButtonIndex = MPSearchScopeAll;
controller.searchBar.showsScopeBar = NO;
} }
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView { - (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView {
@ -110,13 +102,6 @@
return NO; return NO;
} }
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
[self updateData];
return NO;
}
- (void)updateData { - (void)updateData {
[super updateData]; [super updateData];
@ -146,37 +131,39 @@
return NO; return NO;
__block BOOL hasExactQueryMatch = NO; __block BOOL hasExactQueryMatch = NO;
[[self.fetchedResultsController sections] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsControllerByUses sections] lastObject];
id <NSFetchedResultsSectionInfo> sectionInfo = obj; [[sectionInfo objects] enumerateObjectsUsingBlock:^(id obj_, NSUInteger idx_, BOOL *stop_) {
[[sectionInfo objects] enumerateObjectsUsingBlock:^(id obj_, NSUInteger idx_, BOOL *stop_) { if ([[obj_ name] isEqualToString:query]) {
if ([[obj_ name] isEqualToString:query]) { hasExactQueryMatch = YES;
hasExactQueryMatch = YES; *stop_ = YES;
*stop_ = YES; }
}
}];
if (hasExactQueryMatch)
*stop = YES;
}]; }];
if (hasExactQueryMatch)
return NO;
return !hasExactQueryMatch; 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 { - (void)customTableViewUpdates {
BOOL newSiteSectionIsNeeded = [self newSiteSectionNeeded]; BOOL newSiteSectionIsNeeded = [self newSiteSectionNeeded];
dbg(@"isNeeded:%d, wasNeeded:%d", newSiteSectionIsNeeded, self.newSiteSectionWasNeeded); if (newSiteSectionIsNeeded && !self.newSiteSectionWasNeeded)
if (newSiteSectionIsNeeded && !self.newSiteSectionWasNeeded) { [self.tableView insertSections:[NSIndexSet indexSetWithIndex:2]
dbg(@"%@ -- insertSection:%d", NSStringFromSelector(_cmd), [[self.fetchedResultsController sections] count]);
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:[[self.fetchedResultsController sections] count]]
withRowAnimation:UITableViewRowAnimationAutomatic]; withRowAnimation:UITableViewRowAnimationAutomatic];
} else if (!newSiteSectionIsNeeded && self.newSiteSectionWasNeeded)
else if (!newSiteSectionIsNeeded && self.newSiteSectionWasNeeded) { [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:2]
dbg(@"%@ -- deleteSection:%d", NSStringFromSelector(_cmd), [[self.fetchedResultsController sections] count]);
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:[[self.fetchedResultsController sections] count]]
withRowAnimation:UITableViewRowAnimationAutomatic]; withRowAnimation:UITableViewRowAnimationAutomatic];
}
self.newSiteSectionWasNeeded = newSiteSectionIsNeeded; self.newSiteSectionWasNeeded = newSiteSectionIsNeeded;
dbg(@"wasNeeded->%d", self.newSiteSectionWasNeeded);
} }
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
@ -185,39 +172,37 @@
if ([self newSiteSectionNeeded]) if ([self newSiteSectionNeeded])
++sectionCount; ++sectionCount;
dbg(@"%@ (actually) = %d", NSStringFromSelector(_cmd), sectionCount);
return sectionCount; return sectionCount;
} }
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSUInteger fetchSections = [[self.fetchedResultsController sections] count]; if (section < [super numberOfSectionsInTableView:tableView])
if (section < (NSInteger)fetchSections) // Section is one of super's sections.
return [super tableView:tableView numberOfRowsInSection:section]; return [super tableView:tableView numberOfRowsInSection:section];
dbg(@"%@%d = %d", NSStringFromSelector(_cmd), section, 1);
return 1; return 1;
} }
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath { - (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atTableIndexPath:(NSIndexPath *)indexPath {
NSUInteger fetchSections = [[self.fetchedResultsController sections] count]; if (indexPath.section < [super numberOfSectionsInTableView:tableView]) {
if (indexPath.section < (NSInteger)fetchSections) // Section is one of super's sections.
[super configureCell:cell inTableView:tableView atIndexPath:indexPath]; [super configureCell:cell inTableView:tableView atTableIndexPath:indexPath];
return;
else {
// "New" section
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
cell.textLabel.text = query;
cell.detailTextLabel.text = PearlString(@"Add new site: %@",
[MPAlgorithmDefault shortNameOfType:[[MPAppDelegate get].activeUser defaultType]]);
} }
// "New" section
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
cell.textLabel.text = query;
cell.detailTextLabel.text = PearlString(@"New site: %@",
[MPAlgorithmDefault shortNameOfType:[[MPAppDelegate get].activeUser defaultType]]);
} }
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger fetchSections = [[self.fetchedResultsController sections] count]; if (indexPath.section < [super numberOfSectionsInTableView:tableView]) {
if (indexPath.section < (NSInteger)fetchSections) { // Section is one of super's sections.
[super tableView:tableView didSelectRowAtIndexPath:indexPath]; [super tableView:tableView didSelectRowAtIndexPath:indexPath];
return; return;
} }
@ -240,18 +225,18 @@
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSUInteger fetchSections = [[self.fetchedResultsController sections] count]; if (section < [super numberOfSectionsInTableView:tableView])
if (section < (NSInteger)fetchSections) // Section is one of super's sections.
return [super tableView:tableView titleForHeaderInSection:section]; return [super tableView:tableView titleForHeaderInSection:section];
return @""; return @"Create";
} }
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath { forRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger fetchSections = [[self.fetchedResultsController sections] count]; if (indexPath.section < [super numberOfSectionsInTableView:tableView])
if (indexPath.section < (NSInteger)fetchSections) // Section is one of super's sections.
[super tableView:tableView commitEditingStyle:editingStyle forRowAtIndexPath:indexPath]; [super tableView:tableView commitEditingStyle:editingStyle forRowAtIndexPath:indexPath];
} }

View File

@ -8,10 +8,8 @@
#import "MPMainViewController.h" #import "MPMainViewController.h"
#import "MPAppDelegate.h" #import "MPAppDelegate.h"
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h" #import "MPAppDelegate_Store.h"
#import "MPElementListAllViewController.h" #import "MPElementListAllViewController.h"
#import "MPElementListSearchController.h"
@interface MPMainViewController() @interface MPMainViewController()
@ -50,8 +48,10 @@
if ([[segue identifier] isEqualToString:@"MP_ChooseType"]) if ([[segue identifier] isEqualToString:@"MP_ChooseType"])
((MPTypeViewController *)[segue destinationViewController]).delegate = self; ((MPTypeViewController *)[segue destinationViewController]).delegate = self;
if ([[segue identifier] isEqualToString:@"MP_AllSites"]) if ([[segue identifier] isEqualToString:@"MP_AllSites"]) {
((MPElementListAllViewController *)[((UINavigationController *)[segue destinationViewController]) topViewController]).delegate = self; ((MPElementListAllViewController *)[segue destinationViewController]).delegate = self;
((MPElementListAllViewController *)[segue destinationViewController]).filter = sender;
}
} }
- (void)viewDidLoad { - (void)viewDidLoad {
@ -262,10 +262,10 @@
if ([[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.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); self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, self.view.bounds.size.height - 20 /* pull-up */);
} else { } else {
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, 225); self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, 225);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, 246); [self.helpContainer setFrameFromCurrentSizeAndParentPaddingTop:CGFLOAT_MAX right:0 bottom:0 left:0];
} }
} }
@ -690,9 +690,7 @@
- (IBAction)searchOutdatedElements { - (IBAction)searchOutdatedElements {
self.searchDisplayController.searchBar.selectedScopeButtonIndex = MPSearchScopeOutdated; [self performSegueWithIdentifier:@"MP_AllSites" sender:MPElementListFilterOutdated];
self.searchDisplayController.searchBar.searchResultsButtonSelected = YES;
[self.searchDisplayController.searchBar becomeFirstResponder];
} }
- (IBAction)closeAlert { - (IBAction)closeAlert {

View File

@ -21,6 +21,7 @@
@interface MPSetupViewController : UIViewController @interface MPSetupViewController : UIViewController
@property (weak, nonatomic) IBOutlet UISwitch *cloudSwitch; @property (weak, nonatomic) IBOutlet UISwitch *cloudSwitch;
@property (weak, nonatomic) IBOutlet UISwitch *rememberLoginSwitch;
- (IBAction)close:(UIBarButtonItem *)sender; - (IBAction)close:(UIBarButtonItem *)sender;

View File

@ -30,6 +30,8 @@
if (self.cloudSwitch && [[MPiOSConfig get].iCloudDecided boolValue]) if (self.cloudSwitch && [[MPiOSConfig get].iCloudDecided boolValue])
self.cloudSwitch.on = [MPAppDelegate get].storeManager.cloudEnabled; self.cloudSwitch.on = [MPAppDelegate get].storeManager.cloudEnabled;
if (self.rememberLoginSwitch)
self.rememberLoginSwitch.on = [[MPiOSConfig get].rememberLogin boolValue];
} }
- (void)viewWillDisappear:(BOOL)animated { - (void)viewWillDisappear:(BOOL)animated {
@ -40,6 +42,8 @@
[MPiOSConfig get].iCloudDecided = @YES; [MPiOSConfig get].iCloudDecided = @YES;
[MPAppDelegate get].storeManager.cloudEnabled = self.cloudSwitch.on; [MPAppDelegate get].storeManager.cloudEnabled = self.cloudSwitch.on;
} }
if (self.rememberLoginSwitch)
[MPiOSConfig get].rememberLogin = @(self.rememberLoginSwitch.on);
} }
- (IBAction)close:(UIBarButtonItem *)sender { - (IBAction)close:(UIBarButtonItem *)sender {

View File

@ -212,7 +212,7 @@
if (!moc) if (!moc)
return; return;
self.tip.text = @"Tap and hold to delete or reset."; self.tip.text = @"Tap and hold to delete or reset user.";
__block NSArray *users = nil; __block NSArray *users = nil;
[moc performBlockAndWait:^{ [moc performBlockAndWait:^{
@ -266,15 +266,13 @@
avatar.backgroundColor = [UIColor clearColor]; avatar.backgroundColor = [UIColor clearColor];
} options:0]; } options:0];
[avatar onSelect:^(BOOL selected) { [avatar onSelect:^(BOOL selected) {
if (selected) { if (!selected) {
if ((self.selectedUser = user))
[self didToggleUserSelection];
else
[self didSelectNewUserAvatar:avatar];
} else {
self.selectedUser = nil; self.selectedUser = nil;
[self didToggleUserSelection]; [self didToggleUserSelection];
} } else if ((self.selectedUser = user))
[self didToggleUserSelection];
else
[self didSelectNewUserAvatar:avatar];
} options:0]; } options:0];
[self.avatarToUserOID setObject:NilToNSNull([user objectID]) forKey:[NSValue valueWithNonretainedObject:avatar]]; [self.avatarToUserOID setObject:NilToNSNull([user objectID]) forKey:[NSValue valueWithNonretainedObject:avatar]];

View File

@ -705,10 +705,6 @@ Your passwords will be AES-encrypted with your master password.</string>
<gestureRecognizers/> <gestureRecognizers/>
<color key="tintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/> <color key="tintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL"/> <textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL"/>
<scopeButtonTitles>
<string>All</string>
<string>Outdated</string>
</scopeButtonTitles>
</searchBar> </searchBar>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="foz-tW-xGw" userLabel="View - Action Tip"> <view userInteractionEnabled="NO" contentMode="scaleToFill" id="foz-tW-xGw" userLabel="View - Action Tip">
<rect key="frame" x="10" y="0.0" width="300" height="60"/> <rect key="frame" x="10" y="0.0" width="300" height="60"/>
@ -1006,7 +1002,7 @@ L4m3P4sSw0rD</string>
<outlet property="typeTipContainer" destination="g55-0m-WjS" id="KZ9-KV-NMh"/> <outlet property="typeTipContainer" destination="g55-0m-WjS" id="KZ9-KV-NMh"/>
<segue destination="oLN-6u-GLb" kind="push" identifier="MP_UserProfile" id="tKN-Sw-S5J"/> <segue destination="oLN-6u-GLb" kind="push" identifier="MP_UserProfile" id="tKN-Sw-S5J"/>
<segue destination="2Th-Tb-22a" kind="modal" identifier="MP_OtherApps" id="Io5-cz-v9Y"/> <segue destination="2Th-Tb-22a" kind="modal" identifier="MP_OtherApps" id="Io5-cz-v9Y"/>
<segue destination="KZ9-Bb-FN7" kind="modal" identifier="MP_AllSites" id="18w-AW-e8A"/> <segue destination="idA-Pj-1U9" kind="modal" identifier="MP_AllSites" id="nVS-UW-cgK"/>
</connections> </connections>
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="mK2-p1-3zC" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="mK2-p1-3zC" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -1101,7 +1097,7 @@ L4m3P4sSw0rD</string>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_spinner.png" id="27q-lX-0vy"> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_spinner.png" id="27q-lX-0vy">
<rect key="frame" x="105" y="40" width="110" height="110"/> <rect key="frame" x="105" y="40" width="110" height="110"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</imageView> </imageView>
<view contentMode="scaleToFill" id="JTj-nh-BWs" userLabel="Word Wall"> <view contentMode="scaleToFill" id="JTj-nh-BWs" userLabel="Word Wall">
<rect key="frame" x="0.0" y="0.0" width="960" height="200"/> <rect key="frame" x="0.0" y="0.0" width="960" height="200"/>
@ -1254,11 +1250,11 @@ L4m3P4sSw0rD</string>
</subviews> </subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view> </view>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.5" contentMode="left" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="DBJ-Qi-ZcF"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.5" contentMode="left" text="Tap and hold to delete or reset user." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="DBJ-Qi-ZcF">
<rect key="frame" x="20" y="548" width="280" height="20"/> <rect key="frame" x="20" y="548" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="12"/> <fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="12"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" cocoaTouchSystemColor="lightTextColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<color key="shadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> <color key="shadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</label> </label>
@ -1287,7 +1283,7 @@ L4m3P4sSw0rD</string>
</scrollView> </scrollView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="left" text="Maarten Billemont" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumFontSize="10" id="8s0-nT-Aoq"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="left" text="Maarten Billemont" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumFontSize="10" id="8s0-nT-Aoq">
<rect key="frame" x="90" y="377" width="140" height="15"/> <rect key="frame" x="90" y="377" width="140" height="15"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" name="Futura-CondensedExtraBold" family="Futura" pointSize="13"/> <fontDescription key="fontDescription" name="Futura-CondensedExtraBold" family="Futura" pointSize="13"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@ -1295,7 +1291,7 @@ L4m3P4sSw0rD</string>
</label> </label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Maarten Billemont" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumFontSize="10" id="0NM-NI-7UR"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Maarten Billemont" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumFontSize="10" id="0NM-NI-7UR">
<rect key="frame" x="90" y="174" width="140" height="15"/> <rect key="frame" x="90" y="174" width="140" height="15"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" name="Futura-CondensedExtraBold" family="Futura" pointSize="13"/> <fontDescription key="fontDescription" name="Futura-CondensedExtraBold" family="Futura" pointSize="13"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@ -1303,7 +1299,7 @@ L4m3P4sSw0rD</string>
</label> </label>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="xWL-xQ-KjX"> <view userInteractionEnabled="NO" contentMode="scaleToFill" id="xWL-xQ-KjX">
<rect key="frame" x="20" y="60" width="280" height="100"/> <rect key="frame" x="20" y="60" width="280" height="100"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" id="Xrk-S4-ZN5"> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" id="Xrk-S4-ZN5">
<rect key="frame" x="0.0" y="0.0" width="280" height="100"/> <rect key="frame" x="0.0" y="0.0" width="280" height="100"/>
@ -1325,7 +1321,7 @@ You could use the word wall for inspiration in finding a memorable master passw
</view> </view>
<view contentMode="scaleToFill" id="7cc-yu-i0m"> <view contentMode="scaleToFill" id="7cc-yu-i0m">
<rect key="frame" x="20" y="168" width="280" height="88"/> <rect key="frame" x="20" y="168" width="280" height="88"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Enter your master password:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="RhX-bA-EhC"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Enter your master password:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="RhX-bA-EhC">
<rect key="frame" x="10" y="0.0" width="260" height="20"/> <rect key="frame" x="10" y="0.0" width="260" height="20"/>
@ -1433,7 +1429,7 @@ You could use the word wall for inspiration in finding a memorable master passw
</button> </button>
<button opaque="NO" alpha="0.10000000000000001" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="2dq-bb-mPl" userLabel="add"> <button opaque="NO" alpha="0.10000000000000001" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="2dq-bb-mPl" userLabel="add">
<rect key="frame" x="0.0" y="0.0" width="44" height="44"/> <rect key="frame" x="0.0" y="0.0" width="44" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="26"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="26"/>
<state key="normal" title=""> <state key="normal" title="">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@ -1557,7 +1553,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<navigationItem key="navigationItem" title="iCloud" id="mNu-yP-9oW"> <navigationItem key="navigationItem" title="iCloud" id="mNu-yP-9oW">
<barButtonItem key="rightBarButtonItem" title="Next" id="Kxp-c7-ErS"> <barButtonItem key="rightBarButtonItem" title="Next" id="Kxp-c7-ErS">
<connections> <connections>
<segue destination="ZgN-2j-05b" kind="push" id="llz-jX-HRQ"/> <segue destination="kSj-yX-DmT" kind="push" id="gbD-CB-5c8"/>
</connections> </connections>
</barButtonItem> </barButtonItem>
</navigationItem> </navigationItem>
@ -1569,51 +1565,44 @@ If you set a custom password, it will be encrypted before it is saved to the clo
</objects> </objects>
<point key="canvasLocation" x="996" y="1425"/> <point key="canvasLocation" x="996" y="1425"/>
</scene> </scene>
<!--Navigation Controller--> <!--Element List All View Controller-->
<scene sceneID="rAg-OU-9QV">
<objects>
<navigationController definesPresentationContext="YES" id="KZ9-Bb-FN7" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="s0n-kY-htJ">
<rect key="frame" x="0.0" y="-44" width="0.0" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<color key="tintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
</navigationBar>
<connections>
<segue destination="idA-Pj-1U9" kind="relationship" relationship="rootViewController" id="dmZ-bA-SbA"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="vJs-4S-qNG" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1537" y="-495"/>
</scene>
<!--Element List All View Controller - All Sites-->
<scene sceneID="I7c-vt-d2s"> <scene sceneID="I7c-vt-d2s">
<objects> <objects>
<tableViewController id="idA-Pj-1U9" customClass="MPElementListAllViewController" sceneMemberID="viewController"> <tableViewController id="idA-Pj-1U9" customClass="MPElementListAllViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="48" sectionHeaderHeight="22" sectionFooterHeight="22" id="N83-sj-4tl"> <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="48" sectionHeaderHeight="22" sectionFooterHeight="22" id="N83-sj-4tl">
<rect key="frame" x="0.0" y="64" width="320" height="504"/> <rect key="frame" x="0.0" y="20" width="320" height="548"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<navigationBar key="tableHeaderView" contentMode="scaleToFill" id="l0p-Tu-L9k">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="tintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
<items>
<navigationItem title="All Sites" id="Ipv-Tt-WPc">
<barButtonItem key="leftBarButtonItem" title="Close" style="done" id="Mnn-6X-DgP">
<connections>
<action selector="close:" destination="idA-Pj-1U9" id="qqC-U7-8Ci"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" systemItem="add" id="CR8-WY-9Td">
<connections>
<action selector="add:" destination="idA-Pj-1U9" id="G7b-hR-IH0"/>
</connections>
</barButtonItem>
</navigationItem>
</items>
</navigationBar>
<connections> <connections>
<outlet property="dataSource" destination="idA-Pj-1U9" id="yPh-6k-Ba9"/> <outlet property="dataSource" destination="idA-Pj-1U9" id="yPh-6k-Ba9"/>
<outlet property="delegate" destination="idA-Pj-1U9" id="bdk-Iu-Hpv"/> <outlet property="delegate" destination="idA-Pj-1U9" id="bdk-Iu-Hpv"/>
</connections> </connections>
</tableView> </tableView>
<navigationItem key="navigationItem" title="All Sites" id="Ipv-Tt-WPc"> <connections>
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="Mnn-6X-DgP"> <outlet property="navigationBar" destination="l0p-Tu-L9k" id="9DR-L3-ggI"/>
<connections> </connections>
<action selector="close:" destination="idA-Pj-1U9" id="qqC-U7-8Ci"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" systemItem="add" id="CR8-WY-9Td">
<connections>
<action selector="add:" destination="idA-Pj-1U9" id="G7b-hR-IH0"/>
</connections>
</barButtonItem>
</navigationItem>
</tableViewController> </tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="abw-PC-pyQ" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="abw-PC-pyQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="2078" y="-495"/> <point key="canvasLocation" x="1537" y="-495"/>
</scene> </scene>
<!--Apps View Controller--> <!--Apps View Controller-->
<scene sceneID="3cC-Qq-rgU"> <scene sceneID="3cC-Qq-rgU">
@ -1623,17 +1612,17 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/> <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="book.png" id="wjL-OU-K7k"> <imageView userInteractionEnabled="NO" contentMode="center" image="book.png" id="wjL-OU-K7k">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/> <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView> </imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="page-gorillas.png" id="QQT-37-azo"> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="page-gorillas.png" id="QQT-37-azo">
<rect key="frame" x="0.0" y="79" width="305" height="400"/> <rect key="frame" x="0.0" y="81" width="305" height="400"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</imageView> </imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="drq-47-KK9"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="drq-47-KK9">
<rect key="frame" x="85" y="448" width="150" height="32"/> <rect key="frame" x="85" y="536" width="150" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal"> <state key="normal">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/> <color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
@ -1647,7 +1636,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
</connections> </connections>
</button> </button>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> <color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
</view> </view>
<nil key="simulatedStatusBarMetrics"/> <nil key="simulatedStatusBarMetrics"/>
<connections> <connections>
@ -1809,7 +1798,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<switch opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" id="ilG-0h-SOb"> <switch opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" id="ilG-0h-SOb">
<rect key="frame" x="221" y="8" width="79" height="27"/> <rect key="frame" x="221" y="8" width="79" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="onTintColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/> <color key="onTintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
<connections> <connections>
<action selector="didToggleSwitch:" destination="oLN-6u-GLb" eventType="valueChanged" id="e5q-mf-XK7"/> <action selector="didToggleSwitch:" destination="oLN-6u-GLb" eventType="valueChanged" id="e5q-mf-XK7"/>
</connections> </connections>
@ -2066,7 +2055,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
</objects> </objects>
<point key="canvasLocation" x="1004" y="-495"/> <point key="canvasLocation" x="1004" y="-495"/>
</scene> </scene>
<!--Setup View Controller--> <!--Setup View Controller - About-->
<scene sceneID="p4k-3T-J0X"> <scene sceneID="p4k-3T-J0X">
<objects> <objects>
<viewController id="ZgN-2j-05b" customClass="MPSetupViewController" sceneMemberID="viewController"> <viewController id="ZgN-2j-05b" customClass="MPSetupViewController" sceneMemberID="viewController">
@ -2086,35 +2075,50 @@ If you set a custom password, it will be encrypted before it is saved to the clo
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" usesAttributedText="YES" id="hwP-ds-GDh"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" usesAttributedText="YES" id="hwP-ds-GDh">
<rect key="frame" x="20" y="137" width="280" height="347"/> <rect key="frame" x="20" y="137" width="280" height="367"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<attributedString key="attributedText"> <attributedString key="attributedText">
<fragment> <fragment content="The passwords created by this app are not stored anywhere but ">
<string key="content">The passwords created by this app are not stored anywhere but created on the spot.
It is vital that you </string>
<attributes> <attributes>
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<font key="NSFont" size="14" name="Helvetica"/> <font key="NSFont" size="14" name="Helvetica"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/> <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes> </attributes>
</fragment> </fragment>
<fragment content="remember your master password"> <fragment content="created on the spot">
<attributes>
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<font key="NSFont" size="14" name="Helvetica-Oblique"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes>
</fragment>
<fragment>
<string key="content">.
You don't need to remember any password generated by this app, but </string>
<attributes>
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<font key="NSFont" size="14" name="Helvetica"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes>
</fragment>
<fragment content="it is vital that you ">
<attributes> <attributes>
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<font key="NSFont" size="14" name="Helvetica-Bold"/> <font key="NSFont" size="14" name="Helvetica-Bold"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/> <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes> </attributes>
</fragment> </fragment>
<fragment content=" and that it is secure. A small nonsense sentence is a great password. Eg. "> <fragment content="remember">
<attributes> <attributes>
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<font key="NSFont" size="14" name="Helvetica"/> <font key="NSFont" size="14" name="Helvetica-BoldOblique"/>
<font key="NSOriginalFont" size="14" name="Helvetica-BoldOblique"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/> <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes> </attributes>
</fragment> </fragment>
<fragment content="Banana colored duckling"> <fragment content=" your master password">
<attributes> <attributes>
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<font key="NSFont" size="14" name="Helvetica-BoldOblique"/> <font key="NSFont" size="14" name="Helvetica-BoldOblique"/>
@ -2122,28 +2126,29 @@ It is vital that you </string>
</attributes> </attributes>
</fragment> </fragment>
<fragment> <fragment>
<string key="content" base64-UTF8="YES"> <string key="content"> and that it is secure.
Cgo
</string> Don't reuse an old password!
Don't give out your master password.
A small nonsense sentence is a great password. </string>
<attributes> <attributes>
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<font key="NSFont" size="14" name="Helvetica"/> <font key="NSFont" size="14" name="Helvetica"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/> <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes> </attributes>
</fragment> </fragment>
<fragment> <fragment content="Eg. Banana colored duckling">
<string key="content">Don't reuse an old password!
</string>
<attributes> <attributes>
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<font key="NSFont" size="14" name="Helvetica-Bold"/> <font key="NSFont" size="14" name="Helvetica-Bold"/>
<font key="NSOriginalFont" size="14" name="Helvetica-Bold"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/> <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes> </attributes>
</fragment> </fragment>
<fragment> <fragment>
<string key="content">Don't give out your master password, no matter how close you think you are with the other person. <string key="content">
You can make passwords for all sorts of things, like email addresses, sites or real-world objects like your bike lock: if you can name it, you can get a password for it.</string> 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.</string>
<attributes> <attributes>
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<font key="NSFont" size="14" name="Helvetica"/> <font key="NSFont" size="14" name="Helvetica"/>
@ -2160,13 +2165,13 @@ You can make passwords for all sorts of things, like email addresses, sites or r
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view> </view>
<navigationItem key="navigationItem" id="oBl-x2-aUS"> <navigationItem key="navigationItem" title="About" id="oBl-x2-aUS">
<barButtonItem key="leftBarButtonItem" title="Close" style="done" id="yZJ-lt-O5m"> <barButtonItem key="leftBarButtonItem" title="Close" style="done" id="yZJ-lt-O5m">
<connections> <connections>
<action selector="close:" destination="ZgN-2j-05b" id="aKm-zK-xbg"/> <action selector="close:" destination="ZgN-2j-05b" id="aKm-zK-xbg"/>
</connections> </connections>
</barButtonItem> </barButtonItem>
<barButtonItem key="rightBarButtonItem" title="Guide" id="rVv-Hh-KDw"> <barButtonItem key="rightBarButtonItem" title="Overview" id="rVv-Hh-KDw">
<connections> <connections>
<segue destination="myN-X7-9Tg" kind="push" id="jgo-j3-gbW"/> <segue destination="myN-X7-9Tg" kind="push" id="jgo-j3-gbW"/>
</connections> </connections>
@ -2175,7 +2180,7 @@ You can make passwords for all sorts of things, like email addresses, sites or r
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="561-Zo-a0K" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="561-Zo-a0K" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="1537" y="1425"/> <point key="canvasLocation" x="2078" y="1425"/>
</scene> </scene>
<!--Guide View Controller--> <!--Guide View Controller-->
<scene sceneID="k6U-hl-fJt"> <scene sceneID="k6U-hl-fJt">
@ -2527,7 +2532,66 @@ You can make passwords for all sorts of things, like email addresses, sites or r
<panGestureRecognizer minimumNumberOfTouches="1" id="kYj-Dc-rXL"/> <panGestureRecognizer minimumNumberOfTouches="1" id="kYj-Dc-rXL"/>
<panGestureRecognizer minimumNumberOfTouches="1" id="ayP-1f-n2G"/> <panGestureRecognizer minimumNumberOfTouches="1" id="ayP-1f-n2G"/>
</objects> </objects>
<point key="canvasLocation" x="2078" y="1425"/> <point key="canvasLocation" x="2619" y="1425"/>
</scene>
<!--Setup View Controller - Security-->
<scene sceneID="XZC-qy-rbH">
<objects>
<viewController id="kSj-yX-DmT" customClass="MPSetupViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="sT4-Jb-e5D">
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" id="Eqt-R0-LTj">
<rect key="frame" x="0.0" y="-64" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="top" image="unlocked.png" id="4ah-P0-2DG">
<rect key="frame" x="20" y="20" width="280" height="80"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Stay Logged In?" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="R2t-Ug-fY6">
<rect key="frame" x="20" y="108" width="280" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="k4g-1Z-Hfw">
<rect key="frame" x="20" y="137" width="280" height="196"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<string key="text">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.</string>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
<switch opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" id="xmc-hs-riu">
<rect key="frame" x="122" y="345" width="79" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="onTintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
</switch>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
<navigationItem key="navigationItem" title="Security" id="7XO-EZ-YRY">
<barButtonItem key="rightBarButtonItem" title="Next" id="77S-5d-d24">
<connections>
<segue destination="ZgN-2j-05b" kind="push" id="Osp-Zu-L6y"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="rememberLoginSwitch" destination="xmc-hs-riu" id="ROi-H8-rcY"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="M5H-qQ-ytd" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1537" y="1425"/>
</scene> </scene>
</scenes> </scenes>
<resources> <resources>
@ -2567,6 +2631,7 @@ You can make passwords for all sorts of things, like email addresses, sites or r
<image name="ui_panel_display.png" width="300" height="86"/> <image name="ui_panel_display.png" width="300" height="86"/>
<image name="ui_spinner.png" width="75" height="75"/> <image name="ui_spinner.png" width="75" height="75"/>
<image name="ui_textfield.png" width="158" height="34"/> <image name="ui_textfield.png" width="158" height="34"/>
<image name="unlocked.png" width="84" height="80"/>
</resources> </resources>
<classes> <classes>
<class className="MPAppViewController" superclassName="UIViewController"> <class className="MPAppViewController" superclassName="UIViewController">
@ -2588,6 +2653,7 @@ You can make passwords for all sorts of things, like email addresses, sites or r
<relationships> <relationships>
<relationship kind="action" name="add:"/> <relationship kind="action" name="add:"/>
<relationship kind="action" name="close:"/> <relationship kind="action" name="close:"/>
<relationship kind="outlet" name="navigationBar" candidateClass="UINavigationBar"/>
</relationships> </relationships>
</class> </class>
<class className="MPElementListController" superclassName="UITableViewController"> <class className="MPElementListController" superclassName="UITableViewController">
@ -2700,6 +2766,7 @@ You can make passwords for all sorts of things, like email addresses, sites or r
<relationship kind="action" name="close:" candidateClass="UIBarButtonItem"/> <relationship kind="action" name="close:" candidateClass="UIBarButtonItem"/>
<relationship kind="action" name="showGuide:" candidateClass="UIBarButtonItem"/> <relationship kind="action" name="showGuide:" candidateClass="UIBarButtonItem"/>
<relationship kind="outlet" name="cloudSwitch" candidateClass="UISwitch"/> <relationship kind="outlet" name="cloudSwitch" candidateClass="UISwitch"/>
<relationship kind="outlet" name="rememberLoginSwitch" candidateClass="UISwitch"/>
</relationships> </relationships>
</class> </class>
<class className="MPTypeViewController" superclassName="UITableViewController"> <class className="MPTypeViewController" superclassName="UITableViewController">
@ -2742,7 +2809,7 @@ You can make passwords for all sorts of things, like email addresses, sites or r
<simulatedScreenMetrics key="destination" type="retina4"/> <simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer> </simulatedMetricsContainer>
<inferredMetricsTieBreakers> <inferredMetricsTieBreakers>
<segue reference="KIl-ZW-M7G"/>
<segue reference="jgo-j3-gbW"/> <segue reference="jgo-j3-gbW"/>
<segue reference="9Bs-cD-ddF"/>
</inferredMetricsTieBreakers> </inferredMetricsTieBreakers>
</document> </document>

View File

@ -38,6 +38,8 @@
DA4DA1DA1564471F00F6F596 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; }; DA4DA1DA1564471F00F6F596 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; };
DA5A09DF171A70E4005284AB /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DD171A70E4005284AB /* play.png */; }; DA5A09DF171A70E4005284AB /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DD171A70E4005284AB /* play.png */; };
DA5A09E0171A70E4005284AB /* play@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DE171A70E4005284AB /* play@2x.png */; }; DA5A09E0171A70E4005284AB /* play@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DE171A70E4005284AB /* play@2x.png */; };
DA5A09EA171BB0F7005284AB /* unlocked.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09E8171BB0F7005284AB /* unlocked.png */; };
DA5A09EB171BB0F7005284AB /* unlocked@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09E9171BB0F7005284AB /* unlocked@2x.png */; };
DA5BFA49147E415C00F98B1E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA48147E415C00F98B1E /* UIKit.framework */; }; DA5BFA49147E415C00F98B1E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA48147E415C00F98B1E /* UIKit.framework */; };
DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DA5BFA4D147E415C00F98B1E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */; }; DA5BFA4D147E415C00F98B1E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */; };
@ -1036,6 +1038,8 @@
DA497B9715E8C90E00B52167 /* libGoogle+.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libGoogle+.a"; sourceTree = BUILT_PRODUCTS_DIR; }; DA497B9715E8C90E00B52167 /* libGoogle+.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libGoogle+.a"; sourceTree = BUILT_PRODUCTS_DIR; };
DA5A09DD171A70E4005284AB /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = "<group>"; }; DA5A09DD171A70E4005284AB /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = "<group>"; };
DA5A09DE171A70E4005284AB /* play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play@2x.png"; sourceTree = "<group>"; }; DA5A09DE171A70E4005284AB /* play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play@2x.png"; sourceTree = "<group>"; };
DA5A09E8171BB0F7005284AB /* unlocked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unlocked.png; sourceTree = "<group>"; };
DA5A09E9171BB0F7005284AB /* unlocked@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "unlocked@2x.png"; sourceTree = "<group>"; };
DA5BFA44147E415C00F98B1E /* MasterPassword.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MasterPassword.app; sourceTree = BUILT_PRODUCTS_DIR; }; DA5BFA44147E415C00F98B1E /* MasterPassword.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MasterPassword.app; sourceTree = BUILT_PRODUCTS_DIR; };
DA5BFA48147E415C00F98B1E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; DA5BFA48147E415C00F98B1E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@ -2206,6 +2210,8 @@
DABD360D1711E29400CF925C /* Media */ = { DABD360D1711E29400CF925C /* Media */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DA5A09E8171BB0F7005284AB /* unlocked.png */,
DA5A09E9171BB0F7005284AB /* unlocked@2x.png */,
DA5A09DD171A70E4005284AB /* play.png */, DA5A09DD171A70E4005284AB /* play.png */,
DA5A09DE171A70E4005284AB /* play@2x.png */, DA5A09DE171A70E4005284AB /* play@2x.png */,
DABD360E1711E29400CF925C /* Automaton */, DABD360E1711E29400CF925C /* Automaton */,
@ -4596,6 +4602,8 @@
DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */, DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */,
DA5A09DF171A70E4005284AB /* play.png in Resources */, DA5A09DF171A70E4005284AB /* play.png in Resources */,
DA5A09E0171A70E4005284AB /* play@2x.png in Resources */, DA5A09E0171A70E4005284AB /* play@2x.png in Resources */,
DA5A09EA171BB0F7005284AB /* unlocked.png in Resources */,
DA5A09EB171BB0F7005284AB /* unlocked@2x.png in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 21 KiB