2
0

Listing all sites now with bookmark button and modal VC.

[ADDED]     Modal VC to show all sites.
[UPDATED]   All sites button on search bar now uses bookmark button.
[REMOVED]   Query string hack for search results button.
This commit is contained in:
Maarten Billemont 2013-02-01 01:13:45 -05:00
parent 2bb0e2e3ef
commit 9a68cbf533
18 changed files with 601 additions and 101 deletions

View File

@ -17,6 +17,7 @@
93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; }; 93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; };
93D399B873AF89808151D2F5 /* MPAppsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390DABAE4368E90E37340 /* MPAppsViewController.m */; }; 93D399B873AF89808151D2F5 /* MPAppsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390DABAE4368E90E37340 /* MPAppsViewController.m */; };
93D39BCE5F69D8EBE7E9F6EC /* MPAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E070BD3F45B3045A1DA /* MPAppViewController.m */; }; 93D39BCE5F69D8EBE7E9F6EC /* MPAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E070BD3F45B3045A1DA /* MPAppViewController.m */; };
93D39BD0F5C7C76678712500 /* MPAllSitesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F16ADA770D8C13B4555 /* MPAllSitesViewController.m */; };
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; }; 93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
93D39DC7A7282137B08C8D82 /* MPAlgorithmV1.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E9D7B9005211E7D5262 /* MPAlgorithmV1.m */; }; 93D39DC7A7282137B08C8D82 /* MPAlgorithmV1.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E9D7B9005211E7D5262 /* MPAlgorithmV1.m */; };
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; }; 93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
@ -972,6 +973,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; }; 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; };
93D390B3209212B3049BEC2D /* MPAllSitesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAllSitesViewController.h; sourceTree = "<group>"; };
93D390DABAE4368E90E37340 /* MPAppsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppsViewController.m; sourceTree = "<group>"; }; 93D390DABAE4368E90E37340 /* MPAppsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppsViewController.m; sourceTree = "<group>"; };
93D3938863322199C3E7E2E3 /* MPAlgorithmV0.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV0.m; sourceTree = "<group>"; }; 93D3938863322199C3E7E2E3 /* MPAlgorithmV0.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV0.m; sourceTree = "<group>"; };
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; }; 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
@ -989,6 +991,8 @@
93D39E070BD3F45B3045A1DA /* MPAppViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppViewController.m; sourceTree = "<group>"; }; 93D39E070BD3F45B3045A1DA /* MPAppViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppViewController.m; sourceTree = "<group>"; };
93D39E81EFABC6085AC8AE69 /* MPKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPKey.m; sourceTree = "<group>"; }; 93D39E81EFABC6085AC8AE69 /* MPKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPKey.m; sourceTree = "<group>"; };
93D39E9D7B9005211E7D5262 /* MPAlgorithmV1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV1.m; sourceTree = "<group>"; }; 93D39E9D7B9005211E7D5262 /* MPAlgorithmV1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV1.m; sourceTree = "<group>"; };
93D39F16ADA770D8C13B4555 /* MPAllSitesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAllSitesViewController.m; sourceTree = "<group>"; };
93D39F37240730C6311B8FBD /* MPElementPickerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementPickerDelegate.h; sourceTree = "<group>"; };
93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlEMail.h; sourceTree = "<group>"; }; 93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlEMail.h; sourceTree = "<group>"; };
DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
DA0A1D0315690A9A0092735D /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Default.png; path = Resources/Default.png; sourceTree = SOURCE_ROOT; }; DA0A1D0315690A9A0092735D /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Default.png; path = Resources/Default.png; sourceTree = SOURCE_ROOT; };
@ -2542,6 +2546,9 @@
DAB8D45215036BCF00CED3BC /* MPUnlockViewController.h */, DAB8D45215036BCF00CED3BC /* MPUnlockViewController.h */,
DAB8D45315036BCF00CED3BC /* MPUnlockViewController.m */, DAB8D45315036BCF00CED3BC /* MPUnlockViewController.m */,
DAB8D45415036BCF00CED3BC /* Settings.bundle */, DAB8D45415036BCF00CED3BC /* Settings.bundle */,
93D39F16ADA770D8C13B4555 /* MPAllSitesViewController.m */,
93D390B3209212B3049BEC2D /* MPAllSitesViewController.h */,
93D39F37240730C6311B8FBD /* MPElementPickerDelegate.h */,
); );
path = iOS; path = iOS;
sourceTree = "<group>"; sourceTree = "<group>";
@ -4716,6 +4723,7 @@
DA81253816B8546B00F4732F /* MPElementStoredEntity.m in Sources */, DA81253816B8546B00F4732F /* MPElementStoredEntity.m in Sources */,
DA81253B16B8546B00F4732F /* MPUserEntity.m in Sources */, DA81253B16B8546B00F4732F /* MPUserEntity.m in Sources */,
DA81253E16B8546C00F4732F /* MPElementGeneratedEntity.m in Sources */, DA81253E16B8546C00F4732F /* MPElementGeneratedEntity.m in Sources */,
93D39BD0F5C7C76678712500 /* MPAllSitesViewController.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@ -18,6 +18,8 @@
@property (strong, nonatomic) MPUserEntity *activeUser; @property (strong, nonatomic) MPUserEntity *activeUser;
@property (strong, nonatomic) MPKey *key; @property (strong, nonatomic) MPKey *key;
+ (instancetype)get;
- (MPUserEntity *)activeUserInContext:(NSManagedObjectContext *)moc; - (MPUserEntity *)activeUserInContext:(NSManagedObjectContext *)moc;
@end @end

View File

@ -28,9 +28,4 @@
return self; return self;
} }
+ (MPConfig *)get {
return (MPConfig *)[super get];
}
@end @end

View File

@ -42,11 +42,6 @@ static EventHotKeyID MPLockHotKey = {.signature = 'lock', .id = 1};
}); });
} }
+ (MPAppDelegate *)get {
return (MPAppDelegate *)[super get];
}
static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData) { static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData) {
// Extract the hotkey ID. // Extract the hotkey ID.

View File

@ -20,9 +20,4 @@
return self; return self;
} }
+ (MPMacConfig *)get {
return (MPMacConfig *)[super get];
}
@end @end

View File

@ -0,0 +1,28 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPAllSitesViewController
//
// Created by Maarten Billemont on 2013-01-31.
// Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPElementPickerDelegate.h"
@interface MPAllSitesViewController : UITableViewController
@property (weak, nonatomic) IBOutlet id<MPElementPickerDelegate> delegate;
- (IBAction)close:(id)sender;
@end

View File

@ -0,0 +1,240 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPAllSitesViewController
//
// Created by Maarten Billemont on 2013-01-31.
// Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
//
#import "MPAllSitesViewController.h"
#import "MPAppDelegate.h"
#import "MPAppDelegate_Store.h"
@interface MPAllSitesViewController() <NSFetchedResultsControllerDelegate>
@property (nonatomic,strong)NSDateFormatter *dateFormatter;
@end
@implementation MPAllSitesViewController {
NSFetchedResultsController *_fetchedResultsController;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.dateFormatter = [NSDateFormatter new];
self.dateFormatter.dateStyle = NSDateFormatterShortStyle;
}
- (IBAction)close:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (NSFetchedResultsController *)fetchedResultsController {
if (!_fetchedResultsController) {
NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must run on 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
sectionNameKeyPath:nil cacheName:nil];
_fetchedResultsController.delegate = self;
}
return _fetchedResultsController;
}
- (void)fetchData {
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
if (!activeUser)
return;
self.fetchedResultsController.fetchRequest.predicate = [NSPredicate predicateWithFormat:@"user == %@", activeUser];
NSError *error;
if (![self.fetchedResultsController performFetch:&error])
err(@"Couldn't fetch elements: %@", error);
[self.tableView reloadData];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self fetchData];
}
// See MP-14, also crashes easily on internal assertions etc..
//- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
//
// [self.searchDisplayController.searchResultsTableView beginUpdates];
//}
//
//- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
// atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
//
// UITableView *tableView = self.searchDisplayController.searchResultsTableView;
// switch(type) {
//
// case NSFetchedResultsChangeInsert:
// [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
// break;
//
// case NSFetchedResultsChangeDelete:
// [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
// break;
//
// case NSFetchedResultsChangeUpdate:
// [self configureCell:[tableView cellForRowAtIndexPath:indexPath]
// inTableView:tableView atIndexPath:indexPath];
// break;
//
// case NSFetchedResultsChangeMove:
// [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
// withRowAnimation:UITableViewRowAnimationFade];
// [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
// withRowAnimation:UITableViewRowAnimationFade];
// break;
// }
//}
//
//
//- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo
// atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
//
// UITableView *tableView = self.searchDisplayController.searchResultsTableView;
// switch(type) {
//
// case NSFetchedResultsChangeInsert:
// [tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
// withRowAnimation:UITableViewRowAnimationFade];
// break;
//
// case NSFetchedResultsChangeDelete:
// [tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
// withRowAnimation:UITableViewRowAnimationFade];
// break;
// }
//}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
dbg(@"controllerDidChangeContent on thread: %@", [NSThread currentThread].name);
[self.tableView reloadData];
//[self.tableView endUpdates];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return (NSInteger)[[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return (NSInteger)[[[self.fetchedResultsController sections] objectAtIndex:(unsigned)section] numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MPElementSearch"];
if (!cell.backgroundView) {
// cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MPElementSearch"];
UIImage *backgroundImage = [[UIImage imageNamed:@"ui_list_middle"] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)
resizingMode:UIImageResizingModeStretch];
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:backgroundImage];
backgroundImageView.frame = CGRectMake(-5, 0, 330, 34);
backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 34)];
[backgroundView addSubview:backgroundImageView];
backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
cell.backgroundView = backgroundView;
// cell.textLabel.backgroundColor = [UIColor clearColor];
// cell.textLabel.textColor = [UIColor whiteColor];
// cell.detailTextLabel.backgroundColor = [UIColor clearColor];
// cell.detailTextLabel.textColor = [UIColor lightGrayColor];
// cell.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
// cell.clipsToBounds = YES;
}
[self configureCell:cell inTableView:tableView atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath {
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = element.name;
cell.detailTextLabel.text = PearlString(@"Used %d times, last on %@",
element.uses, [self.dateFormatter stringFromDate:element.lastUsed]);
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.delegate didSelectElement:[self.fetchedResultsController objectAtIndexPath:indexPath]];
[self close:nil];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[[self.fetchedResultsController sections] objectAtIndex:(unsigned)section] name];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [self.fetchedResultsController sectionIndexTitles];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete)
[self.fetchedResultsController.managedObjectContext performBlock:^{
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
inf(@"Deleting element: %@", element.name);
[self.fetchedResultsController.managedObjectContext deleteObject:element];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointDeleteElement];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointDeleteElement attributes:@{
@"type" : element.typeName,
@"version" : @(element.version)}];
}];
}
@end

View File

@ -92,6 +92,16 @@
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
} }
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotate {
return NO;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController { viewControllerBeforeViewController:(UIViewController *)viewController {

View File

@ -0,0 +1,24 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPElementPickerDelegate
//
// Created by Maarten Billemont on 2013-01-31.
// Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
//
#import "MPElementEntity.h"
@protocol MPElementPickerDelegate<NSObject>
- (void)didSelectElement:(MPElementEntity *)element;
@end

View File

@ -10,7 +10,7 @@
#import "MPTypeViewController.h" #import "MPTypeViewController.h"
#import "MPSearchDelegate.h" #import "MPSearchDelegate.h"
@interface MPMainViewController : UIViewController<MPTypeDelegate, UITextFieldDelegate, MPSearchResultsDelegate, UIWebViewDelegate, UIGestureRecognizerDelegate> @interface MPMainViewController : UIViewController<MPTypeDelegate, UITextFieldDelegate, MPElementPickerDelegate, UIWebViewDelegate, UIGestureRecognizerDelegate>
@property (assign, nonatomic) BOOL siteInfoHidden; @property (assign, nonatomic) BOOL siteInfoHidden;
@property (strong, nonatomic) IBOutlet MPSearchDelegate *searchDelegate; @property (strong, nonatomic) IBOutlet MPSearchDelegate *searchDelegate;

View File

@ -10,6 +10,7 @@
#import "MPAppDelegate.h" #import "MPAppDelegate.h"
#import "MPAppDelegate_Key.h" #import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h" #import "MPAppDelegate_Store.h"
#import "MPAllSitesViewController.h"
@interface MPMainViewController() @interface MPMainViewController()
@ -48,6 +49,8 @@
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"])
((MPAllSitesViewController *)[((UINavigationController *)[segue destinationViewController]) topViewController]).delegate = self;
} }
- (void)viewDidLoad { - (void)viewDidLoad {
@ -753,12 +756,12 @@
} }
case 2: { case 2: {
inf(@"Action: Preferences"); inf(@"Action: Preferences");
[self performSegueWithIdentifier:@"UserProfile" sender:self]; [self performSegueWithIdentifier:@"MP_UserProfile" sender:self];
break; break;
} }
case 3: { case 3: {
inf(@"Action: Other Apps"); inf(@"Action: Other Apps");
[self performSegueWithIdentifier:@"OtherApps" sender:self]; [self performSegueWithIdentifier:@"MP_OtherApps" sender:self];
break; break;
} }
//#if defined(ADHOC) && defined(TESTFLIGHT_SDK_VERSION) //#if defined(ADHOC) && defined(TESTFLIGHT_SDK_VERSION)

View File

@ -7,27 +7,22 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "MPElementEntity.h" #import "MPElementEntity.h"
#import "MPElementPickerDelegate.h"
typedef enum { typedef enum {
MPSearchScopeAll, MPSearchScopeAll,
MPSearchScopeOutdated, MPSearchScopeOutdated,
} MPSearchScope; } MPSearchScope;
@protocol MPSearchResultsDelegate<NSObject>
- (void)didSelectElement:(MPElementEntity *)element;
@end
@interface MPSearchDelegate : NSObject<UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UISearchDisplayDelegate, NSFetchedResultsControllerDelegate> @interface MPSearchDelegate : NSObject<UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UISearchDisplayDelegate, NSFetchedResultsControllerDelegate>
@property (strong, nonatomic) NSDateFormatter *dateFormatter; @property (strong, nonatomic) NSDateFormatter *dateFormatter;
@property (strong, readonly) NSFetchedResultsController *fetchedResultsController; @property (strong, readonly) NSFetchedResultsController *fetchedResultsController;
@property (strong, nonatomic) NSString *query;
@property (strong, nonatomic) UILabel *tipView; @property (strong, nonatomic) UILabel *tipView;
@property (weak, nonatomic) IBOutlet id<MPSearchResultsDelegate> delegate; @property (weak, nonatomic) IBOutlet id<MPElementPickerDelegate> delegate;
@property (strong, nonatomic) IBOutlet UISearchDisplayController *searchDisplayController; @property (strong, nonatomic) IBOutlet UISearchDisplayController *searchDisplayController;
@property (weak, nonatomic) IBOutlet UIView *searchTipContainer; @property (weak, nonatomic) IBOutlet UIView *searchTipContainer;

View File

@ -9,12 +9,7 @@
#import "MPSearchDelegate.h" #import "MPSearchDelegate.h"
#import "MPAppDelegate.h" #import "MPAppDelegate.h"
#import "MPAppDelegate_Store.h" #import "MPAppDelegate_Store.h"
#import "MPMainViewController.h"
@interface MPSearchDelegate (Private)
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath;
@end
@implementation MPSearchDelegate { @implementation MPSearchDelegate {
@ -28,7 +23,6 @@
self.dateFormatter = [NSDateFormatter new]; self.dateFormatter = [NSDateFormatter new];
self.dateFormatter.dateStyle = NSDateFormatterShortStyle; self.dateFormatter.dateStyle = NSDateFormatterShortStyle;
self.query = @"";
self.tipView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 170)]; self.tipView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 170)];
self.tipView.textAlignment = NSTextAlignmentCenter; self.tipView.textAlignment = NSTextAlignmentCenter;
@ -60,6 +54,7 @@
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:@"uses_" ascending:NO]];
fetchRequest.fetchBatchSize = 20;
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc
sectionNameKeyPath:nil cacheName:nil]; sectionNameKeyPath:nil cacheName:nil];
_fetchedResultsController.delegate = self; _fetchedResultsController.delegate = self;
@ -68,6 +63,11 @@
return _fetchedResultsController; return _fetchedResultsController;
} }
- (void)searchBarBookmarkButtonClicked:(UISearchBar *)searchBar {
[((MPMainViewController *)self.delegate) performSegueWithIdentifier:@"MP_AllSites" sender:self];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
UITableView *tableView = self.searchDisplayController.searchResultsTableView; UITableView *tableView = self.searchDisplayController.searchResultsTableView;
@ -89,12 +89,6 @@
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchBar.searchResultsButtonSelected && !searchText.length)
searchBar.text = @" ";
self.query = [searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if (!self.query)
self.query = @"";
} }
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller { - (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
@ -113,8 +107,6 @@
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller { - (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
controller.searchBar.text = controller.searchBar.searchResultsButtonSelected? @" ": @"";
self.query = @"";
} }
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller { - (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
@ -154,31 +146,30 @@
- (void)fetchData { - (void)fetchData {
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if (!query)
return;
MPUserEntity *activeUser = [MPAppDelegate get].activeUser; MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
assert(self.query); if (!activeUser)
assert(activeUser); return;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user == %@", activeUser];
if (self.query.length)
predicate = [NSCompoundPredicate
andPredicateWithSubpredicates:@[[NSPredicate predicateWithFormat:@"name BEGINSWITH[cd] %@", self.query],
predicate]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user == %@ AND name BEGINSWITH[cd] %@", activeUser, query];
switch ((MPSearchScope)self.searchDisplayController.searchBar.selectedScopeButtonIndex) { switch ((MPSearchScope)self.searchDisplayController.searchBar.selectedScopeButtonIndex) {
case MPSearchScopeAll: case MPSearchScopeAll:
break; break;
case MPSearchScopeOutdated: case MPSearchScopeOutdated:
predicate = [NSCompoundPredicate predicate = [NSCompoundPredicate
andPredicateWithSubpredicates:@[[NSPredicate predicateWithFormat:@"requiresExplicitMigration_ == YES"], andPredicateWithSubpredicates:@[[NSPredicate predicateWithFormat:@"requiresExplicitMigration_ == YES"], predicate]];
predicate]];
break; break;
} }
self.fetchedResultsController.fetchRequest.predicate = predicate; self.fetchedResultsController.fetchRequest.predicate = predicate;
NSError *error; NSError *error;
if (![self.fetchedResultsController performFetch:&error]) if (![self.fetchedResultsController performFetch:&error])
err(@"Couldn't fetch elements: %@", error); err(@"Couldn't fetch elements: %@", error);
[self.searchDisplayController.searchBar.superview enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) { [self.searchDisplayController.searchBar.superview enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
CGRect searchBarFrame = self.searchDisplayController.searchBar.frame; CGRect searchBarFrame = self.searchDisplayController.searchBar.frame;
@ -258,12 +249,13 @@
NSArray *sections = [self.fetchedResultsController sections]; NSArray *sections = [self.fetchedResultsController sections];
NSUInteger sectionCount = [sections count]; NSUInteger sectionCount = [sections count];
if ([self.query length]) { NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if ([query length]) {
__block BOOL hasExactQueryMatch = NO; __block BOOL hasExactQueryMatch = NO;
[sections enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [sections enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
id<NSFetchedResultsSectionInfo> sectionInfo = obj; 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:self.query]) { if ([[obj_ name] isEqualToString:query]) {
hasExactQueryMatch = YES; hasExactQueryMatch = YES;
*stop_ = YES; *stop_ = YES;
} }
@ -327,7 +319,8 @@
element.uses, [self.dateFormatter stringFromDate:element.lastUsed]]; element.uses, [self.dateFormatter stringFromDate:element.lastUsed]];
} else { } else {
// "New" section // "New" section
cell.textLabel.text = self.query; NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
cell.textLabel.text = query;
cell.detailTextLabel.text = @"Create a new site."; cell.detailTextLabel.text = @"Create a new site.";
} }
} }
@ -339,7 +332,7 @@
else { else {
// "New" section. // "New" section.
NSString *siteName = self.query; NSString *siteName = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[PearlAlert showAlertWithTitle:@"New Site" [PearlAlert showAlertWithTitle:@"New Site"
message:PearlString(@"Do you want to create a new site named:\n%@", siteName) message:PearlString(@"Do you want to create a new site named:\n%@", siteName)
viewStyle:UIAlertViewStyleDefault viewStyle:UIAlertViewStyleDefault

View File

@ -496,7 +496,6 @@
// Lay out user name label. // Lay out user name label.
self.nameLabel.text = targetedAvatar? (targetedUser? targetedUser.name: @"New User"): nil; self.nameLabel.text = targetedAvatar? (targetedUser? targetedUser.name: @"New User"): nil;
dbg(@"targetedAvatar: %@, targetedUser: %@, nameLabel: %@", targetedAvatar, targetedUser, self.nameLabel.text);
self.nameLabel.bounds = CGRectSetHeight(self.nameLabel.bounds, self.nameLabel.bounds = CGRectSetHeight(self.nameLabel.bounds,
[self.nameLabel.text sizeWithFont:self.nameLabel.font [self.nameLabel.text sizeWithFont:self.nameLabel.font
constrainedToSize:CGSizeMake(self.nameLabel.bounds.size.width - 10, 100) constrainedToSize:CGSizeMake(self.nameLabel.bounds.size.width - 10, 100)

View File

@ -25,9 +25,4 @@
return self; return self;
} }
+ (MPiOSConfig *)get {
return (MPiOSConfig *)[super get];
}
@end @end

View File

@ -633,7 +633,7 @@ Your passwords will be AES-encrypted with your master password.</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>
<searchBar contentMode="redraw" barStyle="blackOpaque" placeholder="Site name" showsSearchResultsButton="YES" id="qeo-n2-WVh"> <searchBar contentMode="redraw" barStyle="blackOpaque" placeholder="Site name" showsBookmarkButton="YES" id="qeo-n2-WVh">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/> <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<gestureRecognizers/> <gestureRecognizers/>
@ -643,25 +643,6 @@ Your passwords will be AES-encrypted with your master password.</string>
<string>Outdated</string> <string>Outdated</string>
</scopeButtonTitles> </scopeButtonTitles>
</searchBar> </searchBar>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="zOR-Du-qRL" userLabel="View - Search Tip">
<rect key="frame" x="10" y="15" width="300" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black_top.png" id="ORD-Xv-bOQ">
<rect key="frame" x="0.0" y="0.0" width="300" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.15000000000000002" y="0.15000000000000002" width="0.69999999999999973" height="0.69999999999999973"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Begin by entering the name of your site." textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" id="21b-bH-lR9">
<rect key="frame" x="-20" y="26" width="340" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<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"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
@ -685,6 +666,25 @@ Your passwords will be AES-encrypted with your master password.</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>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="zOR-Du-qRL" userLabel="View - Search Tip">
<rect key="frame" x="10" y="15" width="300" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black_top.png" id="ORD-Xv-bOQ">
<rect key="frame" x="0.0" y="0.0" width="300" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.15000000000000002" y="0.15000000000000002" width="0.69999999999999973" height="0.69999999999999973"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Begin by entering the name of your site." textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" id="21b-bH-lR9">
<rect key="frame" x="-20" y="26" width="340" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="UM8-56-kAO" userLabel="View - Tool Tip"> <view userInteractionEnabled="NO" contentMode="scaleToFill" id="UM8-56-kAO" userLabel="View - Tool Tip">
<rect key="frame" x="10" y="15" width="266" height="60"/> <rect key="frame" x="10" y="15" width="266" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
@ -935,8 +935,9 @@ L4m3P4sSw0rD</string>
<outlet property="toolTipEditIcon" destination="KEn-n3-qhX" id="zEV-tR-Egq"/> <outlet property="toolTipEditIcon" destination="KEn-n3-qhX" id="zEV-tR-Egq"/>
<outlet property="typeButton" destination="xYM-e3-BMg" id="xvn-nR-MRV"/> <outlet property="typeButton" destination="xYM-e3-BMg" id="xvn-nR-MRV"/>
<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="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="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"/>
</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"/>
@ -1214,7 +1215,7 @@ Pink fluffy door frame.</string>
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="hkm-U7-Dm7" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="hkm-U7-Dm7" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="463" y="-381"/> <point key="canvasLocation" x="455" y="-381"/>
</scene> </scene>
<!--Unlock View Controller--> <!--Unlock View Controller-->
<scene sceneID="HkH-JR-Fhy"> <scene sceneID="HkH-JR-Fhy">
@ -1628,6 +1629,77 @@ You could use the word wall for inspiration in finding a memorable master passw
</objects> </objects>
<point key="canvasLocation" x="455" y="1425"/> <point key="canvasLocation" x="455" y="1425"/>
</scene> </scene>
<!--Navigation Controller-->
<scene sceneID="rAg-OU-9QV">
<objects>
<navigationController definesPresentationContext="YES" id="KZ9-Bb-FN7" sceneMemberID="viewController">
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" barStyle="blackOpaque" prompted="NO"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="blackOpaque" id="s0n-kY-htJ">
<rect key="frame" x="0.0" y="-44" width="0.0" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</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="996" y="1425"/>
</scene>
<!--All Sites View Controller - All Sites-->
<scene sceneID="I7c-vt-d2s">
<objects>
<tableViewController id="idA-Pj-1U9" customClass="MPAllSitesViewController" 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="416"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="MPElementSearch" textLabel="UGt-vQ-i5K" detailTextLabel="Xv8-kG-Tap" style="IBUITableViewCellStyleSubtitle" id="3eb-mJ-xFj">
<rect key="frame" x="0.0" y="22" width="320" height="48"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="47"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="UGt-vQ-i5K">
<rect key="frame" x="10" y="4" width="38" height="22"/>
<autoresizingMask key="autoresizingMask"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
</label>
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Xv8-kG-Tap">
<rect key="frame" x="10" y="26" width="47" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
</tableViewCell>
</prototypes>
<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>
</navigationItem>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="abw-PC-pyQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1537" y="1425"/>
</scene>
<!--Apps View Controller--> <!--Apps View Controller-->
<scene sceneID="3cC-Qq-rgU"> <scene sceneID="3cC-Qq-rgU">
<objects> <objects>
@ -2077,13 +2149,13 @@ You could use the word wall for inspiration in finding a memorable master passw
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="LHv-Mk-8Kp" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="LHv-Mk-8Kp" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="1004" y="-381"/> <point key="canvasLocation" x="996" y="-381"/>
</scene> </scene>
</scenes> </scenes>
<resources> <resources>
<image name="Square-bottom.png" width="551" height="58"/> <image name="Square-bottom.png" width="551" height="58"/>
<image name="avatar-0.png" width="110" height="110"/> <image name="avatar-0.png" width="110" height="110"/>
<image name="background.png" width="480" height="480"/> <image name="background.png" width="568" height="568"/>
<image name="book.png" width="320" height="480"/> <image name="book.png" width="320" height="480"/>
<image name="guide_page_0.png" width="320" height="480"/> <image name="guide_page_0.png" width="320" height="480"/>
<image name="guide_page_1.png" width="320" height="480"/> <image name="guide_page_1.png" width="320" height="480"/>
@ -2121,6 +2193,146 @@ You could use the word wall for inspiration in finding a memorable master passw
<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"/>
</resources> </resources>
<classes>
<class className="MPAllSitesViewController" superclassName="UITableViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPAllSitesViewController.h"/>
<relationships>
<relationship kind="action" name="close:"/>
<relationship kind="outlet" name="delegate"/>
</relationships>
</class>
<class className="MPAppViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPAppViewController.h"/>
<relationships>
<relationship kind="action" name="deblock:" candidateClass="UIButton"/>
<relationship kind="action" name="gorillas:" candidateClass="UIButton"/>
</relationships>
</class>
<class className="MPAppsViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPAppsViewController.h"/>
<relationships>
<relationship kind="action" name="exit"/>
<relationship kind="outlet" name="pagePositionView" candidateClass="UIImageView"/>
</relationships>
</class>
<class className="MPGuideViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPGuideViewController.h"/>
<relationships>
<relationship kind="action" name="close"/>
<relationship kind="outlet" name="pageControl" candidateClass="UIPageControl"/>
<relationship kind="outlet" name="scrollView" candidateClass="UIScrollView"/>
</relationships>
</class>
<class className="MPMainViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPMainViewController.h"/>
<relationships>
<relationship kind="action" name="action:" candidateClass="UIBarButtonItem"/>
<relationship kind="action" name="closeAlert"/>
<relationship kind="action" name="closeOutdatedAlert"/>
<relationship kind="action" name="copyContent"/>
<relationship kind="action" name="editLoginName:" candidateClass="UILongPressGestureRecognizer"/>
<relationship kind="action" name="editPassword"/>
<relationship kind="action" name="incrementPasswordCounter"/>
<relationship kind="action" name="infoOutdatedAlert"/>
<relationship kind="action" name="panHelpDown:" candidateClass="UIPanGestureRecognizer"/>
<relationship kind="action" name="panHelpUp:" candidateClass="UIPanGestureRecognizer"/>
<relationship kind="action" name="resetPasswordCounter:" candidateClass="UILongPressGestureRecognizer"/>
<relationship kind="action" name="searchOutdatedElements"/>
<relationship kind="action" name="toggleUser"/>
<relationship kind="action" name="upgradePassword"/>
<relationship kind="outlet" name="actionsTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="alertBody" candidateClass="UITextView"/>
<relationship kind="outlet" name="alertContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="alertTitle" candidateClass="UILabel"/>
<relationship kind="outlet" name="contentContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="contentField" candidateClass="UITextField"/>
<relationship kind="outlet" name="contentTipBody" candidateClass="UILabel"/>
<relationship kind="outlet" name="contentTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="displayContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="helpContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="helpView" candidateClass="UIWebView"/>
<relationship kind="outlet" name="loginNameContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="loginNameField" candidateClass="UITextField"/>
<relationship kind="outlet" name="loginNameTipBody" candidateClass="UILabel"/>
<relationship kind="outlet" name="loginNameTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="outdatedAlertBack" candidateClass="UIImageView"/>
<relationship kind="outlet" name="outdatedAlertCloseButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="outdatedAlertContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="passwordCounter" candidateClass="UILabel"/>
<relationship kind="outlet" name="passwordEdit" candidateClass="UIButton"/>
<relationship kind="outlet" name="passwordIncrementer" candidateClass="UIButton"/>
<relationship kind="outlet" name="passwordUpgrade" candidateClass="UIButton"/>
<relationship kind="outlet" name="passwordUser" candidateClass="UIButton"/>
<relationship kind="outlet" name="pullDownGesture" candidateClass="UIPanGestureRecognizer"/>
<relationship kind="outlet" name="pullDownView" candidateClass="UIImageView"/>
<relationship kind="outlet" name="pullUpGesture" candidateClass="UIPanGestureRecognizer"/>
<relationship kind="outlet" name="pullUpView" candidateClass="UIImageView"/>
<relationship kind="outlet" name="searchDelegate" candidateClass="MPSearchDelegate"/>
<relationship kind="outlet" name="searchTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="siteName" candidateClass="UILabel"/>
<relationship kind="outlet" name="toolTipBody" candidateClass="UILabel"/>
<relationship kind="outlet" name="toolTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="toolTipEditIcon" candidateClass="UIImageView"/>
<relationship kind="outlet" name="typeButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="typeTipContainer" candidateClass="UIView"/>
</relationships>
</class>
<class className="MPPreferencesViewController" superclassName="UITableViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPPreferencesViewController.h"/>
<relationships>
<relationship kind="action" name="didToggleSwitch:" candidateClass="UISwitch"/>
<relationship kind="action" name="settings:"/>
<relationship kind="outlet" name="avatarTemplate" candidateClass="UIButton"/>
<relationship kind="outlet" name="avatarsView" candidateClass="UIScrollView"/>
<relationship kind="outlet" name="changeMPCell" candidateClass="UITableViewCell"/>
<relationship kind="outlet" name="defaultTypeLabel" candidateClass="UILabel"/>
<relationship kind="outlet" name="exportCell" candidateClass="UITableViewCell"/>
<relationship kind="outlet" name="savePasswordSwitch" candidateClass="UISwitch"/>
</relationships>
</class>
<class className="MPSearchDelegate" superclassName="NSObject">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPSearchDelegate.h"/>
<relationships>
<relationship kind="outlet" name="delegate"/>
<relationship kind="outlet" name="searchDisplayController" candidateClass="UISearchDisplayController"/>
<relationship kind="outlet" name="searchTipContainer" candidateClass="UIView"/>
</relationships>
</class>
<class className="MPTypeViewController" superclassName="UITableViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPTypeViewController.h"/>
<relationships>
<relationship kind="outlet" name="recommendedTipContainer" candidateClass="UIView"/>
</relationships>
</class>
<class className="MPUnlockViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPUnlockViewController.h"/>
<relationships>
<relationship kind="action" name="add:" candidateClass="UIButton"/>
<relationship kind="action" name="facebook:" candidateClass="UIButton"/>
<relationship kind="action" name="google:" candidateClass="UIButton"/>
<relationship kind="action" name="mail:" candidateClass="UIButton"/>
<relationship kind="action" name="targetedUserAction:" candidateClass="UILongPressGestureRecognizer"/>
<relationship kind="action" name="twitter:" candidateClass="UIButton"/>
<relationship kind="outlet" name="avatarTemplate" candidateClass="UIButton"/>
<relationship kind="outlet" name="avatarsView" candidateClass="UIScrollView"/>
<relationship kind="outlet" name="createPasswordTipView" candidateClass="UIView"/>
<relationship kind="outlet" name="loadingUsersIndicator" candidateClass="UIActivityIndicatorView"/>
<relationship kind="outlet" name="nameLabel" candidateClass="UILabel"/>
<relationship kind="outlet" name="newsView" candidateClass="UIWebView"/>
<relationship kind="outlet" name="oldNameLabel" candidateClass="UILabel"/>
<relationship kind="outlet" name="passwordField" candidateClass="UITextField"/>
<relationship kind="outlet" name="passwordFieldLabel" candidateClass="UILabel"/>
<relationship kind="outlet" name="passwordTipLabel" candidateClass="UILabel"/>
<relationship kind="outlet" name="passwordTipView" candidateClass="UIView"/>
<relationship kind="outlet" name="passwordView" candidateClass="UIView"/>
<relationship kind="outlet" name="spinner" candidateClass="UIImageView"/>
<relationship kind="outlet" name="targetedUserActionGesture" candidateClass="UILongPressGestureRecognizer"/>
<relationship kind="outlet" name="tip" candidateClass="UILabel"/>
<relationship kind="outlet" name="uiContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="wordWall" candidateClass="UIView"/>
</relationships>
</class>
</classes>
<simulatedMetricsContainer key="defaultSimulatedMetrics"> <simulatedMetricsContainer key="defaultSimulatedMetrics">
<nil key="statusBar"/> <nil key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/> <simulatedOrientationMetrics key="orientation"/>

View File

@ -0,0 +1,6 @@
SourceCodePro-Light
LucidaGrande
HelveticaNeue-Medium
LucidaGrande
HelveticaNeue-Light
Inconsolata

View File

@ -341,20 +341,7 @@
</ul> </ul>
</p> </p>
<p> <p>
By default, Master Password uses the <em>Long Password</em> type for any new passwords. The user is able to choose a different password type, which is normally only done if the site's password policy is incompatible with the output password produced by this type. Where each of the letters above expand any of the characters in their respective character group:
</p>
<p>
To create the create the output password, the bytes in the <code>seed</code> are encoded according to the template. The first <code>seed</code> byte is used to determine which of the type's templates to use for encoding an output password. We take the byte value of the first <code>seed</code> byte modulo the amount of templates set for the chosen password type and use the result as a zero-based index in the template list for the password type.
</p>
<code><pre>
templates = [ "CvcvCvcvnoCvcv", "CvcvnoCvcvCvcv", "CvcvCvcvCvcvno", ... ]
template = templates[ seed[0] % count( templates ) ]
</pre></code>
<p>
Now that we know what template to use for building our output password, all that's left is to iterate the template, and produce a character of password output for each step. When we iterate the template (index <code>i</code>), we look in the character group identified by the character (string <code>passChars</code>) in the template at index <code>i</code>.
</p>
<p>
The following character groups (<code>passChars</code>) are defined:
<ul> <ul>
<li><p>Template character: <code>V</code> <li><p>Template character: <code>V</code>
<ul> <ul>
@ -403,6 +390,19 @@
</p></li> </p></li>
</ul> </ul>
</p> </p>
<p>
By default, Master Password uses the <em>Long Password</em> type for any new passwords. The user is able to choose a different password type, which is normally only done if the site's password policy is incompatible with the output password produced by this type.
</p>
<p>
To create the output password, the bytes in the <code>seed</code> are encoded according to the template. The first <code>seed</code> byte is used to determine which of the type's templates to use for encoding an output password. We take the byte value of the first <code>seed</code> byte modulo the amount of templates set for the chosen password type and use the result as a zero-based index in the template list for the password type.
</p>
<code><pre>
templates = [ "CvcvCvcvnoCvcv", "CvcvnoCvcvCvcv", "CvcvCvcvCvcvno", ... ]
template = templates[ seed[0] % count( templates ) ]
</pre></code>
<p>
Now that we know what template to use for building our output password, all that's left is to iterate the template, and produce a character of password output for each step. When we iterate the template (index <code>i</code>), we look in the character group identified by the character (string <code>passChars</code>) in the template at index <code>i</code>.
</p>
<p> <p>
We use the <code>seed</code>'s byte value at index <code>i + 1</code> modulo the amount of characters in the character class to determine which character (<code>passChar</code>) in the class to use for the output password at index <code>i</code>. We use the <code>seed</code>'s byte value at index <code>i + 1</code> modulo the amount of characters in the character class to determine which character (<code>passChar</code>) in the class to use for the output password at index <code>i</code>.
</p> </p>