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:
parent
7cf2c7f5c6
commit
ee93412dd1
2
External/Pearl
vendored
2
External/Pearl
vendored
@ -1 +1 @@
|
||||
Subproject commit 99c73fd3b37b4d2621548f5ae366c163231a346d
|
||||
Subproject commit 0d30693440fd520715f22789d33d5551b3b681c4
|
@ -20,6 +20,7 @@
|
||||
#import "MPElementListController.h"
|
||||
|
||||
@interface MPElementListAllViewController : MPElementListController
|
||||
@property (weak, nonatomic) IBOutlet UINavigationBar *navigationBar;
|
||||
|
||||
- (IBAction)close:(id)sender;
|
||||
- (IBAction)add:(id)sender;
|
||||
|
@ -16,9 +16,32 @@
|
||||
//
|
||||
|
||||
#import "MPElementListAllViewController.h"
|
||||
#import "MPAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
|
||||
#define MPElementUpgradeOldContentKey @"MPElementUpgradeOldContentKey"
|
||||
#define MPElementUpgradeNewContentKey @"MPElementUpgradeNewContentKey"
|
||||
|
||||
@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 {
|
||||
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
@ -40,11 +63,106 @@
|
||||
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 {
|
||||
|
@ -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 "MPElementListDelegate.h"
|
||||
|
||||
typedef enum {
|
||||
MPSearchScopeAll,
|
||||
MPSearchScopeOutdated,
|
||||
} MPSearchScope;
|
||||
#define MPElementListFilterNone @"MPElementListFilterNone"
|
||||
#define MPElementListFilterOutdated @"MPElementListFilterOutdated"
|
||||
|
||||
@interface MPElementListController : UITableViewController <NSFetchedResultsControllerDelegate>
|
||||
|
||||
@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;
|
||||
|
||||
- (void)updateData;
|
||||
- (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;
|
||||
|
||||
@end
|
||||
|
@ -1,10 +1,3 @@
|
||||
//
|
||||
// Created by lhunath on 2013-02-09.
|
||||
//
|
||||
// To change the template use AppCode | Preferences | File Templates.
|
||||
//
|
||||
|
||||
|
||||
#import "MPElementListController.h"
|
||||
|
||||
#import "MPAppDelegate_Store.h"
|
||||
@ -15,7 +8,8 @@
|
||||
|
||||
@implementation MPElementListController {
|
||||
|
||||
NSFetchedResultsController *_fetchedResultsController;
|
||||
NSFetchedResultsController *_fetchedResultsControllerByUses;
|
||||
NSFetchedResultsController *_fetchedResultsControllerByLastUsed;
|
||||
NSDateFormatter *_dateFormatter;
|
||||
}
|
||||
|
||||
@ -57,23 +51,47 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSFetchedResultsController *)fetchedResultsController {
|
||||
- (NSFetchedResultsController *)fetchedResultsControllerByLastUsed {
|
||||
|
||||
if (!_fetchedResultsController) {
|
||||
NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must run on the main thread.");
|
||||
if (!_fetchedResultsControllerByLastUsed) {
|
||||
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:@"uses_" ascending:NO]];
|
||||
fetchRequest.fetchBatchSize = 20;
|
||||
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc
|
||||
fetchRequest.sortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector(lastUsed) ) ascending:NO]];
|
||||
[self configureFetchRequest:fetchRequest];
|
||||
_fetchedResultsControllerByLastUsed = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc
|
||||
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 {
|
||||
@ -92,34 +110,33 @@
|
||||
|
||||
// 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;
|
||||
|
||||
// Add query predicate.
|
||||
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
|
||||
@[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;
|
||||
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);
|
||||
else
|
||||
[self.tableView reloadData];
|
||||
if (![self.fetchedResultsControllerByUses performFetch:&error])
|
||||
err(@"Couldn't fetch elements: %@", error);
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)customTableViewUpdates {
|
||||
@ -140,52 +157,32 @@
|
||||
|
||||
case NSFetchedResultsChangeInsert:
|
||||
dbg(@"%@ -- NSFetchedResultsChangeInsert:%@", NSStringFromSelector(_cmd), anObject);
|
||||
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
[self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
break;
|
||||
|
||||
case NSFetchedResultsChangeDelete:
|
||||
dbg(@"%@ -- NSFetchedResultsChangeDelete:%@", NSStringFromSelector(_cmd), anObject);
|
||||
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
[self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
break;
|
||||
|
||||
case NSFetchedResultsChangeUpdate:
|
||||
dbg(@"%@ -- NSFetchedResultsChangeUpdate:%@", NSStringFromSelector(_cmd), anObject);
|
||||
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
[self.tableView reloadRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
break;
|
||||
|
||||
case NSFetchedResultsChangeMove:
|
||||
dbg(@"%@ -- NSFetchedResultsChangeMove:%@", NSStringFromSelector(_cmd), anObject);
|
||||
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
|
||||
[self.tableView deleteRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:indexPath] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
|
||||
[self.tableView insertRowsAtIndexPaths:@[ [self tableIndexPathForFetchController:controller indexPath:newIndexPath] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
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 {
|
||||
|
||||
dbg(@"%@ on %@", NSStringFromSelector(_cmd), [NSThread currentThread].name);
|
||||
@ -195,16 +192,18 @@
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
|
||||
NSInteger integer = (NSInteger)[[self.fetchedResultsController sections] count];
|
||||
dbg(@"%@ = %d", NSStringFromSelector(_cmd), integer);
|
||||
return integer;
|
||||
return 2;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
|
||||
NSInteger integer = (NSInteger)[[[self.fetchedResultsController sections] objectAtIndex:(unsigned)section] numberOfObjects];
|
||||
dbg(@"%@%d = %d", NSStringFromSelector(_cmd), section, integer);
|
||||
return integer;
|
||||
if (section == 0)
|
||||
return (NSInteger)[[[self.fetchedResultsControllerByLastUsed sections] lastObject] numberOfObjects];
|
||||
|
||||
if (section == 1)
|
||||
return (NSInteger)[[[self.fetchedResultsControllerByUses sections] lastObject] numberOfObjects];
|
||||
|
||||
Throw(@"Unsupported section: %d", section);
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
@ -213,50 +212,82 @@
|
||||
if (!cell)
|
||||
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;
|
||||
}
|
||||
|
||||
- (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.detailTextLabel.text = PearlString(@"%d views, last on %@: %@",
|
||||
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 {
|
||||
|
||||
[self.delegate didSelectElement:[self.fetchedResultsController objectAtIndexPath:indexPath]];
|
||||
[self.delegate didSelectElement:[self elementForTableIndexPath:indexPath]];
|
||||
}
|
||||
|
||||
- (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 {
|
||||
|
||||
return [self.fetchedResultsController sectionIndexTitles];
|
||||
return @[@"recency", @"uses"];
|
||||
}
|
||||
|
||||
- (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
|
||||
forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete) {
|
||||
NSManagedObjectContext *moc = self.fetchedResultsController.managedObjectContext;
|
||||
[moc performBlock:^{
|
||||
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
||||
MPElementEntity *element = [self elementForTableIndexPath:indexPath];
|
||||
[element.managedObjectContext performBlockAndWait:^{
|
||||
|
||||
inf(@"Deleting element: %@", element.name);
|
||||
[moc deleteObject:element];
|
||||
[element.managedObjectContext deleteObject:element];
|
||||
[element.managedObjectContext saveToStore];
|
||||
|
||||
#ifdef TESTFLIGHT_SDK_VERSION
|
||||
[TestFlight passCheckpoint:MPCheckpointDeleteElement];
|
||||
|
@ -10,7 +10,6 @@
|
||||
#import "MPMainViewController.h"
|
||||
#import "MPAppDelegate.h"
|
||||
|
||||
|
||||
@interface MPElementListSearchController ()
|
||||
|
||||
@property (nonatomic) BOOL newSiteSectionWasNeeded;
|
||||
@ -47,7 +46,7 @@
|
||||
|
||||
- (void)searchBarBookmarkButtonClicked:(UISearchBar *)searchBar {
|
||||
|
||||
[((MPMainViewController *)self.delegate) performSegueWithIdentifier:@"MP_AllSites" sender:self];
|
||||
[((MPMainViewController *)self.delegate) performSegueWithIdentifier:@"MP_AllSites" sender:MPElementListFilterNone];
|
||||
}
|
||||
|
||||
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
|
||||
@ -70,12 +69,7 @@
|
||||
|
||||
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
|
||||
|
||||
controller.searchBar.showsScopeBar = controller.searchBar.selectedScopeButtonIndex != MPSearchScopeAll;
|
||||
controller.searchBar.text = @"";
|
||||
if (controller.searchBar.showsScopeBar)
|
||||
controller.searchBar.scopeButtonTitles = @[@"All", @"Outdated"];
|
||||
else
|
||||
controller.searchBar.scopeButtonTitles = nil;
|
||||
|
||||
[UIView animateWithDuration:0.2f animations:^{
|
||||
self.searchTipContainer.alpha = 0;
|
||||
@ -91,8 +85,6 @@
|
||||
|
||||
controller.searchBar.prompt = nil;
|
||||
controller.searchBar.searchResultsButtonSelected = NO;
|
||||
controller.searchBar.selectedScopeButtonIndex = MPSearchScopeAll;
|
||||
controller.searchBar.showsScopeBar = NO;
|
||||
}
|
||||
|
||||
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView {
|
||||
@ -110,13 +102,6 @@
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
|
||||
|
||||
[self updateData];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (void)updateData {
|
||||
|
||||
[super updateData];
|
||||
@ -146,37 +131,39 @@
|
||||
return NO;
|
||||
|
||||
__block BOOL hasExactQueryMatch = NO;
|
||||
[[self.fetchedResultsController sections] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
|
||||
id <NSFetchedResultsSectionInfo> sectionInfo = obj;
|
||||
[[sectionInfo objects] enumerateObjectsUsingBlock:^(id obj_, NSUInteger idx_, BOOL *stop_) {
|
||||
if ([[obj_ name] isEqualToString:query]) {
|
||||
hasExactQueryMatch = YES;
|
||||
*stop_ = YES;
|
||||
}
|
||||
}];
|
||||
if (hasExactQueryMatch)
|
||||
*stop = YES;
|
||||
id <NSFetchedResultsSectionInfo> 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;
|
||||
|
||||
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 {
|
||||
|
||||
BOOL newSiteSectionIsNeeded = [self newSiteSectionNeeded];
|
||||
dbg(@"isNeeded:%d, wasNeeded:%d", newSiteSectionIsNeeded, self.newSiteSectionWasNeeded);
|
||||
if (newSiteSectionIsNeeded && !self.newSiteSectionWasNeeded) {
|
||||
dbg(@"%@ -- insertSection:%d", NSStringFromSelector(_cmd), [[self.fetchedResultsController sections] count]);
|
||||
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:[[self.fetchedResultsController sections] count]]
|
||||
if (newSiteSectionIsNeeded && !self.newSiteSectionWasNeeded)
|
||||
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:2]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
}
|
||||
else if (!newSiteSectionIsNeeded && self.newSiteSectionWasNeeded) {
|
||||
dbg(@"%@ -- deleteSection:%d", NSStringFromSelector(_cmd), [[self.fetchedResultsController sections] count]);
|
||||
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:[[self.fetchedResultsController sections] count]]
|
||||
else if (!newSiteSectionIsNeeded && self.newSiteSectionWasNeeded)
|
||||
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:2]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
}
|
||||
self.newSiteSectionWasNeeded = newSiteSectionIsNeeded;
|
||||
dbg(@"wasNeeded->%d", self.newSiteSectionWasNeeded);
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
@ -185,39 +172,37 @@
|
||||
if ([self newSiteSectionNeeded])
|
||||
++sectionCount;
|
||||
|
||||
dbg(@"%@ (actually) = %d", NSStringFromSelector(_cmd), sectionCount);
|
||||
return sectionCount;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
|
||||
NSUInteger fetchSections = [[self.fetchedResultsController sections] count];
|
||||
if (section < (NSInteger)fetchSections)
|
||||
if (section < [super numberOfSectionsInTableView:tableView])
|
||||
// Section is one of super's sections.
|
||||
return [super tableView:tableView numberOfRowsInSection:section];
|
||||
|
||||
dbg(@"%@%d = %d", NSStringFromSelector(_cmd), section, 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 < (NSInteger)fetchSections)
|
||||
[super configureCell:cell inTableView:tableView atIndexPath:indexPath];
|
||||
|
||||
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]]);
|
||||
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:[[MPAppDelegate get].activeUser defaultType]]);
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
NSUInteger fetchSections = [[self.fetchedResultsController sections] count];
|
||||
if (indexPath.section < (NSInteger)fetchSections) {
|
||||
if (indexPath.section < [super numberOfSectionsInTableView:tableView]) {
|
||||
// Section is one of super's sections.
|
||||
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
|
||||
return;
|
||||
}
|
||||
@ -240,18 +225,18 @@
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||
|
||||
NSUInteger fetchSections = [[self.fetchedResultsController sections] count];
|
||||
if (section < (NSInteger)fetchSections)
|
||||
if (section < [super numberOfSectionsInTableView:tableView])
|
||||
// Section is one of super's sections.
|
||||
return [super tableView:tableView titleForHeaderInSection:section];
|
||||
|
||||
return @"";
|
||||
return @"Create";
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
|
||||
forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
NSUInteger fetchSections = [[self.fetchedResultsController sections] count];
|
||||
if (indexPath.section < (NSInteger)fetchSections)
|
||||
if (indexPath.section < [super numberOfSectionsInTableView:tableView])
|
||||
// Section is one of super's sections.
|
||||
[super tableView:tableView commitEditingStyle:editingStyle forRowAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
|
@ -8,10 +8,8 @@
|
||||
|
||||
#import "MPMainViewController.h"
|
||||
#import "MPAppDelegate.h"
|
||||
#import "MPAppDelegate_Key.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "MPElementListAllViewController.h"
|
||||
#import "MPElementListSearchController.h"
|
||||
|
||||
|
||||
@interface MPMainViewController()
|
||||
@ -50,8 +48,10 @@
|
||||
|
||||
if ([[segue identifier] isEqualToString:@"MP_ChooseType"])
|
||||
((MPTypeViewController *)[segue destinationViewController]).delegate = self;
|
||||
if ([[segue identifier] isEqualToString:@"MP_AllSites"])
|
||||
((MPElementListAllViewController *)[((UINavigationController *)[segue destinationViewController]) topViewController]).delegate = self;
|
||||
if ([[segue identifier] isEqualToString:@"MP_AllSites"]) {
|
||||
((MPElementListAllViewController *)[segue destinationViewController]).delegate = self;
|
||||
((MPElementListAllViewController *)[segue destinationViewController]).filter = sender;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
@ -262,10 +262,10 @@
|
||||
|
||||
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);
|
||||
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.frame = CGRectSetY(self.helpContainer.frame, 246);
|
||||
[self.helpContainer setFrameFromCurrentSizeAndParentPaddingTop:CGFLOAT_MAX right:0 bottom:0 left:0];
|
||||
}
|
||||
}
|
||||
|
||||
@ -690,9 +690,7 @@
|
||||
|
||||
- (IBAction)searchOutdatedElements {
|
||||
|
||||
self.searchDisplayController.searchBar.selectedScopeButtonIndex = MPSearchScopeOutdated;
|
||||
self.searchDisplayController.searchBar.searchResultsButtonSelected = YES;
|
||||
[self.searchDisplayController.searchBar becomeFirstResponder];
|
||||
[self performSegueWithIdentifier:@"MP_AllSites" sender:MPElementListFilterOutdated];
|
||||
}
|
||||
|
||||
- (IBAction)closeAlert {
|
||||
|
@ -21,6 +21,7 @@
|
||||
@interface MPSetupViewController : UIViewController
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UISwitch *cloudSwitch;
|
||||
@property (weak, nonatomic) IBOutlet UISwitch *rememberLoginSwitch;
|
||||
|
||||
- (IBAction)close:(UIBarButtonItem *)sender;
|
||||
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
if (self.cloudSwitch && [[MPiOSConfig get].iCloudDecided boolValue])
|
||||
self.cloudSwitch.on = [MPAppDelegate get].storeManager.cloudEnabled;
|
||||
if (self.rememberLoginSwitch)
|
||||
self.rememberLoginSwitch.on = [[MPiOSConfig get].rememberLogin boolValue];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
@ -40,6 +42,8 @@
|
||||
[MPiOSConfig get].iCloudDecided = @YES;
|
||||
[MPAppDelegate get].storeManager.cloudEnabled = self.cloudSwitch.on;
|
||||
}
|
||||
if (self.rememberLoginSwitch)
|
||||
[MPiOSConfig get].rememberLogin = @(self.rememberLoginSwitch.on);
|
||||
}
|
||||
|
||||
- (IBAction)close:(UIBarButtonItem *)sender {
|
||||
|
@ -212,7 +212,7 @@
|
||||
if (!moc)
|
||||
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;
|
||||
[moc performBlockAndWait:^{
|
||||
@ -266,15 +266,13 @@
|
||||
avatar.backgroundColor = [UIColor clearColor];
|
||||
} options:0];
|
||||
[avatar onSelect:^(BOOL selected) {
|
||||
if (selected) {
|
||||
if ((self.selectedUser = user))
|
||||
[self didToggleUserSelection];
|
||||
else
|
||||
[self didSelectNewUserAvatar:avatar];
|
||||
} else {
|
||||
if (!selected) {
|
||||
self.selectedUser = nil;
|
||||
[self didToggleUserSelection];
|
||||
}
|
||||
} else if ((self.selectedUser = user))
|
||||
[self didToggleUserSelection];
|
||||
else
|
||||
[self didSelectNewUserAvatar:avatar];
|
||||
} options:0];
|
||||
|
||||
[self.avatarToUserOID setObject:NilToNSNull([user objectID]) forKey:[NSValue valueWithNonretainedObject:avatar]];
|
||||
|
@ -705,10 +705,6 @@ Your passwords will be AES-encrypted with your master password.</string>
|
||||
<gestureRecognizers/>
|
||||
<color key="tintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL"/>
|
||||
<scopeButtonTitles>
|
||||
<string>All</string>
|
||||
<string>Outdated</string>
|
||||
</scopeButtonTitles>
|
||||
</searchBar>
|
||||
<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"/>
|
||||
@ -1006,7 +1002,7 @@ L4m3P4sSw0rD</string>
|
||||
<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="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>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="mK2-p1-3zC" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
@ -1101,7 +1097,7 @@ L4m3P4sSw0rD</string>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_spinner.png" id="27q-lX-0vy">
|
||||
<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>
|
||||
<view contentMode="scaleToFill" id="JTj-nh-BWs" userLabel="Word Wall">
|
||||
<rect key="frame" x="0.0" y="0.0" width="960" height="200"/>
|
||||
@ -1254,11 +1250,11 @@ L4m3P4sSw0rD</string>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</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"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<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"/>
|
||||
<color key="shadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</label>
|
||||
@ -1287,7 +1283,7 @@ L4m3P4sSw0rD</string>
|
||||
</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">
|
||||
<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"/>
|
||||
<fontDescription key="fontDescription" name="Futura-CondensedExtraBold" family="Futura" pointSize="13"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
@ -1295,7 +1291,7 @@ L4m3P4sSw0rD</string>
|
||||
</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">
|
||||
<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"/>
|
||||
<fontDescription key="fontDescription" name="Futura-CondensedExtraBold" family="Futura" pointSize="13"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
@ -1303,7 +1299,7 @@ L4m3P4sSw0rD</string>
|
||||
</label>
|
||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="xWL-xQ-KjX">
|
||||
<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>
|
||||
<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"/>
|
||||
@ -1325,7 +1321,7 @@ You could use the word wall for inspiration in finding a memorable master passw
|
||||
</view>
|
||||
<view contentMode="scaleToFill" id="7cc-yu-i0m">
|
||||
<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>
|
||||
<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"/>
|
||||
@ -1433,7 +1429,7 @@ You could use the word wall for inspiration in finding a memorable master passw
|
||||
</button>
|
||||
<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"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="26"/>
|
||||
<state key="normal" title="+">
|
||||
<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">
|
||||
<barButtonItem key="rightBarButtonItem" title="Next" id="Kxp-c7-ErS">
|
||||
<connections>
|
||||
<segue destination="ZgN-2j-05b" kind="push" id="llz-jX-HRQ"/>
|
||||
<segue destination="kSj-yX-DmT" kind="push" id="gbD-CB-5c8"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
@ -1569,51 +1565,44 @@ If you set a custom password, it will be encrypted before it is saved to the clo
|
||||
</objects>
|
||||
<point key="canvasLocation" x="996" y="1425"/>
|
||||
</scene>
|
||||
<!--Navigation 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-->
|
||||
<!--Element List All View Controller-->
|
||||
<scene sceneID="I7c-vt-d2s">
|
||||
<objects>
|
||||
<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">
|
||||
<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"/>
|
||||
<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>
|
||||
<outlet property="dataSource" destination="idA-Pj-1U9" id="yPh-6k-Ba9"/>
|
||||
<outlet property="delegate" destination="idA-Pj-1U9" id="bdk-Iu-Hpv"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="All Sites" id="Ipv-Tt-WPc">
|
||||
<barButtonItem key="leftBarButtonItem" systemItem="cancel" 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>
|
||||
<connections>
|
||||
<outlet property="navigationBar" destination="l0p-Tu-L9k" id="9DR-L3-ggI"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="abw-PC-pyQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2078" y="-495"/>
|
||||
<point key="canvasLocation" x="1537" y="-495"/>
|
||||
</scene>
|
||||
<!--Apps View Controller-->
|
||||
<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"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<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"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
<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"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<rect key="frame" x="0.0" y="81" width="305" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<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"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<rect key="frame" x="85" y="536" width="150" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<state key="normal">
|
||||
<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>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
|
||||
</view>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<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">
|
||||
<rect key="frame" x="221" y="8" width="79" height="27"/>
|
||||
<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>
|
||||
<action selector="didToggleSwitch:" destination="oLN-6u-GLb" eventType="valueChanged" id="e5q-mf-XK7"/>
|
||||
</connections>
|
||||
@ -2066,7 +2055,7 @@ If you set a custom password, it will be encrypted before it is saved to the clo
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1004" y="-495"/>
|
||||
</scene>
|
||||
<!--Setup View Controller-->
|
||||
<!--Setup View Controller - About-->
|
||||
<scene sceneID="p4k-3T-J0X">
|
||||
<objects>
|
||||
<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"/>
|
||||
</label>
|
||||
<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"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<attributedString key="attributedText">
|
||||
<fragment>
|
||||
<string key="content">The passwords created by this app are not stored anywhere but created on the spot.
|
||||
|
||||
It is vital that you </string>
|
||||
<fragment content="The passwords created by this app are not stored anywhere but ">
|
||||
<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="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>
|
||||
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<font key="NSFont" size="14" name="Helvetica-Bold"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment content=" and that it is secure. A small nonsense sentence is a great password. Eg. ">
|
||||
<fragment content="remember">
|
||||
<attributes>
|
||||
<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"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment content="Banana colored duckling">
|
||||
<fragment content=" your master password">
|
||||
<attributes>
|
||||
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<font key="NSFont" size="14" name="Helvetica-BoldOblique"/>
|
||||
@ -2122,28 +2126,29 @@ It is vital that you </string>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment>
|
||||
<string key="content" base64-UTF8="YES">
|
||||
Cgo
|
||||
</string>
|
||||
<string key="content"> 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. </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>
|
||||
<string key="content">Don't reuse an old password!
|
||||
</string>
|
||||
<fragment content="Eg. Banana colored duckling">
|
||||
<attributes>
|
||||
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<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"/>
|
||||
</attributes>
|
||||
</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>
|
||||
<color key="NSColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<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>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</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">
|
||||
<connections>
|
||||
<action selector="close:" destination="ZgN-2j-05b" id="aKm-zK-xbg"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem key="rightBarButtonItem" title="Guide" id="rVv-Hh-KDw">
|
||||
<barButtonItem key="rightBarButtonItem" title="Overview" id="rVv-Hh-KDw">
|
||||
<connections>
|
||||
<segue destination="myN-X7-9Tg" kind="push" id="jgo-j3-gbW"/>
|
||||
</connections>
|
||||
@ -2175,7 +2180,7 @@ You can make passwords for all sorts of things, like email addresses, sites or r
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="561-Zo-a0K" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1537" y="1425"/>
|
||||
<point key="canvasLocation" x="2078" y="1425"/>
|
||||
</scene>
|
||||
<!--Guide View Controller-->
|
||||
<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="ayP-1f-n2G"/>
|
||||
</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>
|
||||
</scenes>
|
||||
<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_spinner.png" width="75" height="75"/>
|
||||
<image name="ui_textfield.png" width="158" height="34"/>
|
||||
<image name="unlocked.png" width="84" height="80"/>
|
||||
</resources>
|
||||
<classes>
|
||||
<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>
|
||||
<relationship kind="action" name="add:"/>
|
||||
<relationship kind="action" name="close:"/>
|
||||
<relationship kind="outlet" name="navigationBar" candidateClass="UINavigationBar"/>
|
||||
</relationships>
|
||||
</class>
|
||||
<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="showGuide:" candidateClass="UIBarButtonItem"/>
|
||||
<relationship kind="outlet" name="cloudSwitch" candidateClass="UISwitch"/>
|
||||
<relationship kind="outlet" name="rememberLoginSwitch" candidateClass="UISwitch"/>
|
||||
</relationships>
|
||||
</class>
|
||||
<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"/>
|
||||
</simulatedMetricsContainer>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="KIl-ZW-M7G"/>
|
||||
<segue reference="jgo-j3-gbW"/>
|
||||
<segue reference="9Bs-cD-ddF"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
</document>
|
@ -38,6 +38,8 @@
|
||||
DA4DA1DA1564471F00F6F596 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; };
|
||||
DA5A09DF171A70E4005284AB /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DD171A70E4005284AB /* play.png */; };
|
||||
DA5A09E0171A70E4005284AB /* play@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DE171A70E4005284AB /* play@2x.png */; };
|
||||
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 */; };
|
||||
DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.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; };
|
||||
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>"; };
|
||||
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; };
|
||||
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; };
|
||||
@ -2206,6 +2210,8 @@
|
||||
DABD360D1711E29400CF925C /* Media */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA5A09E8171BB0F7005284AB /* unlocked.png */,
|
||||
DA5A09E9171BB0F7005284AB /* unlocked@2x.png */,
|
||||
DA5A09DD171A70E4005284AB /* play.png */,
|
||||
DA5A09DE171A70E4005284AB /* play@2x.png */,
|
||||
DABD360E1711E29400CF925C /* Automaton */,
|
||||
@ -4596,6 +4602,8 @@
|
||||
DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */,
|
||||
DA5A09DF171A70E4005284AB /* play.png in Resources */,
|
||||
DA5A09E0171A70E4005284AB /* play@2x.png in Resources */,
|
||||
DA5A09EA171BB0F7005284AB /* unlocked.png in Resources */,
|
||||
DA5A09EB171BB0F7005284AB /* unlocked@2x.png in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
BIN
MasterPassword/Resources/Media/unlocked.png
Normal file
BIN
MasterPassword/Resources/Media/unlocked.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
BIN
MasterPassword/Resources/Media/unlocked@2x.png
Normal file
BIN
MasterPassword/Resources/Media/unlocked@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 21 KiB |
Binary file not shown.
Loading…
Reference in New Issue
Block a user