TestFlight update + search improvements.
[UPDATED] TestFlight SDK updated to 0.8.3 [ADDED] Log >=info messages to TestFlight [ADDED] Hide status bar while locked. [ADDED] Show all sites when search results icon is tapped. [IMPROVED] Search table cells.
@@ -73,9 +73,16 @@
|
||||
@try {
|
||||
[TestFlight takeOff:@"bd44885deee7adce0645ce8e5498d80a_NDQ5NDQyMDExLTEyLTAyIDExOjM1OjQ4LjQ2NjM4NA"];
|
||||
[TestFlight setOptions:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithBool:YES], @"logToConsole",
|
||||
[NSNumber numberWithBool:NO], @"logToConsole",
|
||||
[NSNumber numberWithBool:NO], @"logToSTDERR",
|
||||
nil]];
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointLaunched];
|
||||
[[Logger get] registerListener:^BOOL(LogMessage *message) {
|
||||
if (message.level >= LogLevelInfo)
|
||||
TFLog(@"%@", message);
|
||||
|
||||
return YES;
|
||||
}];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
err(@"TestFlight: %@", exception);
|
||||
@@ -146,6 +153,8 @@
|
||||
[self loadKeyPhrase];
|
||||
}];
|
||||
|
||||
[self loadKeyPhrase];
|
||||
|
||||
return [super application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
}
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
@@ -171,13 +180,19 @@
|
||||
|
||||
- (void)loadKeyPhrase {
|
||||
|
||||
if (self.keyPhrase)
|
||||
return;
|
||||
|
||||
if ([[MPConfig get].forgetKeyPhrase boolValue]) {
|
||||
[self forgetKeyPhrase];
|
||||
return;
|
||||
}
|
||||
|
||||
[self loadStoredKeyPhrase];
|
||||
if (!self.keyPhrase) {
|
||||
if (self.keyPhrase)
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:NO
|
||||
withAnimation:UIStatusBarAnimationSlide];
|
||||
else {
|
||||
// Key phrase is not known. Ask user to set/specify it.
|
||||
dbg(@"Key phrase not known. Will ask user.");
|
||||
[self askKeyPhrase];
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#import "MPSearchDelegate.h"
|
||||
#import "IASKAppSettingsViewController.h"
|
||||
|
||||
@interface MPMainViewController : UIViewController <MPTypeDelegate, UITextFieldDelegate, UISearchBarDelegate, MPSearchResultsDelegate, UIWebViewDelegate, IASKSettingsDelegate>
|
||||
@interface MPMainViewController : UIViewController <MPTypeDelegate, UITextFieldDelegate, MPSearchResultsDelegate, UIWebViewDelegate, IASKSettingsDelegate>
|
||||
|
||||
@property (strong, nonatomic) MPElementEntity *activeElement;
|
||||
@property (strong, nonatomic) IBOutlet MPSearchDelegate *searchResultsController;
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
|
||||
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
self.searchTipContainer.hidden = YES;
|
||||
@@ -147,11 +147,11 @@
|
||||
[[MPAppDelegate get] saveContext];
|
||||
|
||||
if (animated)
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
[self updateWasAnimated:YES];
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
[self updateWasAnimated:animated];
|
||||
}];
|
||||
else
|
||||
[self updateWasAnimated:NO];
|
||||
[self updateWasAnimated:animated];
|
||||
}
|
||||
|
||||
- (void)updateWasAnimated:(BOOL)animated {
|
||||
@@ -219,7 +219,7 @@
|
||||
[[NSBundle mainBundle] URLForResource:@"help" withExtension:@"html"]]]];
|
||||
|
||||
NSString *error = [self.helpView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"setClass('%@');",
|
||||
ClassNameFromMPElementType(self.activeElement.type)]];
|
||||
ClassNameFromMPElementType(self.activeElement.type)]];
|
||||
if (error.length)
|
||||
err(@"setClass: %@", error);
|
||||
}
|
||||
@@ -312,7 +312,7 @@
|
||||
self.contentField.enabled = YES;
|
||||
[self.contentField becomeFirstResponder];
|
||||
}
|
||||
|
||||
|
||||
#ifndef PRODUCTION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointEditPassword];
|
||||
#endif
|
||||
@@ -325,7 +325,7 @@
|
||||
} completion:^(BOOL finished) {
|
||||
self.alertBody.text = nil;
|
||||
}];
|
||||
|
||||
|
||||
#ifndef PRODUCTION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointCloseAlert];
|
||||
#endif
|
||||
@@ -354,7 +354,7 @@
|
||||
settingsVC.delegate = self;
|
||||
[self.navigationController pushViewController:settingsVC animated:YES];
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifndef PRODUCTION
|
||||
case 4:
|
||||
[TestFlight openFeedbackView];
|
||||
@@ -387,7 +387,7 @@
|
||||
// Type requires a different class of element. Recreate the element.
|
||||
[[MPAppDelegate managedObjectContext] performBlockAndWait:^{
|
||||
MPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:ClassNameFromMPElementType(type)
|
||||
inManagedObjectContext:[MPAppDelegate managedObjectContext]];
|
||||
inManagedObjectContext:[MPAppDelegate managedObjectContext]];
|
||||
newElement.name = self.activeElement.name;
|
||||
newElement.mpHashHex = self.activeElement.mpHashHex;
|
||||
newElement.uses = self.activeElement.uses;
|
||||
@@ -410,24 +410,17 @@
|
||||
|
||||
- (void)didSelectElement:(MPElementEntity *)element {
|
||||
|
||||
self.activeElement = element;
|
||||
[self.activeElement use];
|
||||
|
||||
[self.searchDisplayController setActive:NO animated:YES];
|
||||
self.searchDisplayController.searchBar.text = self.activeElement.name;
|
||||
|
||||
if (element) {
|
||||
self.activeElement = element;
|
||||
[self.activeElement use];
|
||||
|
||||
[self.searchDisplayController setActive:NO animated:YES];
|
||||
self.searchDisplayController.searchBar.text = self.activeElement.name;
|
||||
|
||||
#ifndef PRODUCTION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointSelectElement];
|
||||
#endif
|
||||
|
||||
[self updateAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
|
||||
|
||||
#ifndef PRODUCTION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointCancelSearch];
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointSelectElement];
|
||||
#endif
|
||||
}
|
||||
|
||||
[self updateAnimated:YES];
|
||||
}
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface MPSearchDelegate : NSObject <UITableViewDelegate, UITableViewDataSource, UISearchDisplayDelegate, NSFetchedResultsControllerDelegate>
|
||||
@interface MPSearchDelegate : NSObject <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UISearchDisplayDelegate, NSFetchedResultsControllerDelegate>
|
||||
|
||||
@property (strong, nonatomic) NSDateFormatter *dateFormatter;
|
||||
@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
|
||||
@property (strong, nonatomic) NSString *query;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet id<MPSearchResultsDelegate> delegate;
|
||||
@property (weak, nonatomic) IBOutlet UISearchDisplayController *searchDisplayController;
|
||||
|
||||
@@ -18,40 +18,85 @@
|
||||
@end
|
||||
|
||||
@implementation MPSearchDelegate
|
||||
@synthesize query;
|
||||
@synthesize dateFormatter;
|
||||
@synthesize fetchedResultsController;
|
||||
@synthesize delegate;
|
||||
@synthesize searchDisplayController;
|
||||
@synthesize searchTipContainer;
|
||||
|
||||
- (id)init {
|
||||
|
||||
if (!([super init]))
|
||||
return nil;
|
||||
|
||||
self.dateFormatter = [NSDateFormatter new];
|
||||
self.dateFormatter.timeStyle = NSDateFormatterNoStyle;
|
||||
self.dateFormatter.dateStyle = NSDateFormatterShortStyle;
|
||||
self.query = @"";
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
|
||||
|
||||
UITableView *tableView = self.searchDisplayController.searchResultsTableView;
|
||||
for (NSUInteger section = 0; section < [self numberOfSectionsInTableView:tableView]; ++section) {
|
||||
NSUInteger rowCount = [self tableView:tableView numberOfRowsInSection:section];
|
||||
if (!rowCount)
|
||||
continue;
|
||||
|
||||
if (rowCount == 1)
|
||||
[self tableView:tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
|
||||
|
||||
#ifndef PRODUCTION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointCancelSearch];
|
||||
#endif
|
||||
|
||||
[self.delegate didSelectElement:nil];
|
||||
}
|
||||
|
||||
- (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 {
|
||||
|
||||
self.searchDisplayController.searchBar.text = @"";
|
||||
self.searchDisplayController.searchBar.prompt = @"Enter the site's domain name (eg. apple.com):";
|
||||
controller.searchBar.prompt = @"Enter the site's name (eg. apple.com):";
|
||||
|
||||
[UIView animateWithDuration:0.2f animations:^{
|
||||
self.searchTipContainer.alpha = 0;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
|
||||
|
||||
[self update];
|
||||
controller.searchBar.text = controller.searchBar.searchResultsButtonSelected? @" ": @"";
|
||||
self.query = @"";
|
||||
}
|
||||
|
||||
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
|
||||
|
||||
self.searchDisplayController.searchBar.prompt = nil;
|
||||
controller.searchBar.prompt = nil;
|
||||
controller.searchBar.searchResultsButtonSelected = NO;
|
||||
}
|
||||
|
||||
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView {
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:UIScreenModeDidChangeNotification
|
||||
object:nil queue:nil usingBlock:^(NSNotification *note) {
|
||||
NSError *error;
|
||||
if (![self.fetchedResultsController performFetch:&error])
|
||||
err(@"Couldn't fetch elements: %@", error);
|
||||
}];
|
||||
|
||||
tableView.backgroundColor = [UIColor blackColor];
|
||||
tableView.rowHeight = 34.0f;
|
||||
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
tableView.rowHeight = 48.0f;
|
||||
}
|
||||
|
||||
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
|
||||
@@ -63,19 +108,18 @@
|
||||
|
||||
- (void)update {
|
||||
|
||||
NSString *query = self.searchDisplayController.searchBar.text;
|
||||
if (!query)
|
||||
query = @"";
|
||||
|
||||
assert(self.query);
|
||||
assert([MPAppDelegate get].keyPhraseHashHex);
|
||||
NSFetchRequest *fetchRequest = [[MPAppDelegate get].managedObjectModel
|
||||
fetchRequestFromTemplateWithName:@"MPSearchElement"
|
||||
fetchRequestFromTemplateWithName:@"MPElements"
|
||||
substitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
query, @"query",
|
||||
self.query, @"query",
|
||||
[MPAppDelegate get].keyPhraseHashHex, @"mpHashHex",
|
||||
nil]];
|
||||
[fetchRequest setSortDescriptors:
|
||||
[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses" ascending:NO]]];
|
||||
|
||||
self.fetchedResultsController.delegate = nil;
|
||||
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
|
||||
managedObjectContext:[MPAppDelegate managedObjectContext]
|
||||
sectionNameKeyPath:nil cacheName:nil];
|
||||
@@ -107,8 +151,7 @@
|
||||
|
||||
case NSFetchedResultsChangeUpdate:
|
||||
[self configureCell:[tableView cellForRowAtIndexPath:indexPath]
|
||||
inTableView:tableView
|
||||
atIndexPath:indexPath];
|
||||
inTableView:tableView atIndexPath:indexPath];
|
||||
break;
|
||||
|
||||
case NSFetchedResultsChangeMove:
|
||||
@@ -121,7 +164,7 @@
|
||||
}
|
||||
|
||||
|
||||
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
|
||||
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo
|
||||
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
|
||||
|
||||
UITableView *tableView = self.searchDisplayController.searchResultsTableView;
|
||||
@@ -146,32 +189,38 @@
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
|
||||
return [[self.fetchedResultsController sections] count] + 1;
|
||||
return [[self.fetchedResultsController sections] count] + ([self.query length]? 1: 0);
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
|
||||
if (section == [self numberOfSectionsInTableView:tableView] - 1)
|
||||
return 1;
|
||||
if (section < [[self.fetchedResultsController sections] count])
|
||||
return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
|
||||
|
||||
return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MPElementSearch"];
|
||||
if (!cell) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"MPElementSearch"];
|
||||
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"ui_list_middle"] resizableImageWithCapInsets:UIEdgeInsetsMake(5, 5, 5, 5)]];
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MPElementSearch"];
|
||||
|
||||
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ui_list_middle"]];
|
||||
backgroundImageView.frame = CGRectMake(-5, 0, 330, 34);
|
||||
UIView *backgroundView = [[UIView alloc] initWithFrame:cell.frame];
|
||||
backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
backgroundImageView.contentStretch = CGRectMake(0.2f, 0.2f, 0.6f, 0.6f);
|
||||
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];
|
||||
@@ -185,11 +234,12 @@
|
||||
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
||||
|
||||
cell.textLabel.text = element.name;
|
||||
cell.detailTextLabel.text = [NSString stringWithFormat:@"%d", element.uses];
|
||||
cell.detailTextLabel.text = [NSString stringWithFormat:@"Used %d times, last on %@",
|
||||
element.uses, [self.dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceReferenceDate:element.lastUsed]]];
|
||||
} else {
|
||||
// "New" section
|
||||
cell.textLabel.text = self.searchDisplayController.searchBar.text;
|
||||
cell.detailTextLabel.text = @"New";
|
||||
cell.textLabel.text = self.query;
|
||||
cell.detailTextLabel.text = @"Create a new site.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +250,7 @@
|
||||
|
||||
else {
|
||||
// "New" section.
|
||||
NSString *siteName = self.searchDisplayController.searchBar.text;
|
||||
NSString *siteName = self.query;
|
||||
[AlertViewController showAlertWithTitle:@"New Site"
|
||||
message:l(@"Do you want to create a new site named:\n%@", siteName)
|
||||
viewStyle:UIAlertViewStyleDefault
|
||||
@@ -228,10 +278,10 @@
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||
|
||||
if (--section == -1)
|
||||
return @"";
|
||||
if (section < [[self.fetchedResultsController sections] count])
|
||||
return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
|
||||
|
||||
return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
|
||||
@@ -246,19 +296,17 @@
|
||||
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
if (indexPath.section == [[self.fetchedResultsController sections] count])
|
||||
// "New" section.
|
||||
return;
|
||||
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete)
|
||||
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
||||
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
||||
[self.fetchedResultsController.managedObjectContext deleteObject:element];
|
||||
|
||||
if (indexPath.section < [[self.fetchedResultsController sections] count]) {
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete)
|
||||
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
||||
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
||||
[self.fetchedResultsController.managedObjectContext deleteObject:element];
|
||||
|
||||
#ifndef PRODUCTION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointDeleteElement];
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointDeleteElement];
|
||||
#endif
|
||||
}];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -130,6 +130,13 @@ typedef enum {
|
||||
[super viewWillDisappear:animated];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
|
||||
[self.field becomeFirstResponder];
|
||||
|
||||
[super viewDidAppear:animated];
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
|
||||
if ([textField.text length]) {
|
||||
|
||||
@@ -334,7 +334,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
|
||||
<rect key="frame" x="0.0" y="64" width="320" height="416"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="top" image="Content-Backdrop.png" id="0hY-LL-ITu">
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="bottom" image="background.png" id="0hY-LL-ITu">
|
||||
<rect key="frame" x="0.0" y="44" width="320" height="372"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
@@ -342,10 +342,6 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
|
||||
<rect key="frame" x="0.0" y="43" width="320" height="175"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="bottom" image="background.png" id="enb-OH-DVZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="175"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" alpha="0.80000000000000004" contentMode="scaleToFill" image="ui_panel_container.png" id="0Yh-Py-lB6">
|
||||
<rect key="frame" x="11" y="20" width="298" height="87"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
@@ -382,7 +378,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
|
||||
<size key="shadowOffset" width="0.0" height="1"/>
|
||||
</label>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="S3cre7^Pa$swcrD" textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" id="fiX-10-fif">
|
||||
<rect key="frame" x="20" y="46" width="280" height="60"/>
|
||||
<rect key="frame" x="20" y="33" width="280" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="textColor" red="0.47450980390000003" green="0.86666666670000003" blue="0.98431372549999996" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<fontDescription key="fontDescription" name="Copperplate-Bold" family="Copperplate" pointSize="26"/>
|
||||
@@ -401,8 +397,8 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
|
||||
<size key="shadowOffset" width="0.0" height="1"/>
|
||||
</label>
|
||||
<button opaque="NO" alpha="0.50000000000000011" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="jec-mu-nPt">
|
||||
<rect key="frame" x="274.5" y="18.5" width="37" height="37"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<rect key="frame" x="272.5" y="18.5" width="36.5" height="36"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
|
||||
<state key="normal" image="icon_plus.png">
|
||||
@@ -417,7 +413,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" alpha="0.5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="9FS-fS-xH6">
|
||||
<rect key="frame" x="274.5" y="18.5" width="37.5" height="37"/>
|
||||
<rect key="frame" x="273" y="18.5" width="36" height="36"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
|
||||
@@ -538,13 +534,13 @@ L4m3P4sSw0rD</string>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<searchBar contentMode="redraw" barStyle="blackOpaque" placeholder="Site" id="qeo-n2-WVh">
|
||||
<searchBar contentMode="redraw" barStyle="blackOpaque" placeholder="Site" showsSearchResultsButton="YES" id="qeo-n2-WVh">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<gestureRecognizers/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="PQa-Xl-A3x" id="oXp-0r-Gkl"/>
|
||||
<outlet property="delegate" destination="0QO-2P-OhD" id="Maj-Iz-6Hb"/>
|
||||
</connections>
|
||||
</searchBar>
|
||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="zOR-Du-qRL">
|
||||
@@ -800,7 +796,6 @@ L4m3P4sSw0rD</string>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Content-Backdrop.png" width="16" height="16"/>
|
||||
<image name="Square-bottom.png" width="551" height="58"/>
|
||||
<image name="background.png" width="480" height="480"/>
|
||||
<image name="guide_page_0.png" width="320" height="480"/>
|
||||
@@ -826,6 +821,64 @@ L4m3P4sSw0rD</string>
|
||||
<image name="ui_spinner.png" width="75" height="75"/>
|
||||
<image name="ui_textfield.png" width="158" height="34"/>
|
||||
</resources>
|
||||
<classes>
|
||||
<class className="MPGuideViewController" superclassName="UIViewController">
|
||||
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPGuideViewController.h"/>
|
||||
<relationships>
|
||||
<relationship kind="action" name="close"/>
|
||||
<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="copyContent"/>
|
||||
<relationship kind="action" name="editPassword"/>
|
||||
<relationship kind="action" name="incrementPasswordCounter"/>
|
||||
<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="contentTipEditIcon" candidateClass="UIImageView"/>
|
||||
<relationship kind="outlet" name="helpContainer" candidateClass="UIView"/>
|
||||
<relationship kind="outlet" name="helpView" candidateClass="UIWebView"/>
|
||||
<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="searchResultsController" candidateClass="MPSearchDelegate"/>
|
||||
<relationship kind="outlet" name="searchTipContainer" candidateClass="UIView"/>
|
||||
<relationship kind="outlet" name="siteName" candidateClass="UILabel"/>
|
||||
<relationship kind="outlet" name="typeButton" candidateClass="UIButton"/>
|
||||
</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"/>
|
||||
</class>
|
||||
<class className="MPUnlockViewController" superclassName="UIViewController">
|
||||
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPUnlockViewController.h"/>
|
||||
<relationships>
|
||||
<relationship kind="action" name="changeMP"/>
|
||||
<relationship kind="outlet" name="changeMPView" candidateClass="UIView"/>
|
||||
<relationship kind="outlet" name="field" candidateClass="UITextField"/>
|
||||
<relationship kind="outlet" name="lock" candidateClass="UIImageView"/>
|
||||
<relationship kind="outlet" name="messageLabel" candidateClass="UILabel"/>
|
||||
<relationship kind="outlet" name="spinner" candidateClass="UIImageView"/>
|
||||
</relationships>
|
||||
</class>
|
||||
</classes>
|
||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||
<simulatedStatusBarMetrics key="statusBar" statusBarStyle="blackTranslucent"/>
|
||||
<simulatedOrientationMetrics key="orientation"/>
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<true/>
|
||||
<key>UIStatusBarStyle</key>
|
||||
<string>UIStatusBarStyleBlackOpaque</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="872" systemVersion="11C74" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1170" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<entity name="MPElementEntity" representedClassName="MPElementEntity" isAbstract="YES" syncable="YES">
|
||||
<attribute name="lastUsed" attributeType="Date" syncable="YES"/>
|
||||
<attribute name="mpHashHex" optional="YES" attributeType="String" syncable="YES"/>
|
||||
@@ -13,10 +13,10 @@
|
||||
<entity name="MPElementStoredEntity" representedClassName="MPElementStoredEntity" parentEntity="MPElementEntity" syncable="YES">
|
||||
<attribute name="contentObject" optional="YES" attributeType="Transformable" storedInTruthFile="YES" syncable="YES"/>
|
||||
</entity>
|
||||
<fetchRequest name="MPSearchElement" entity="MPElementEntity" predicateString="name BEGINSWITH[cd] $query AND mpHashHex == $mpHashHex"/>
|
||||
<fetchRequest name="MPElements" entity="MPElementEntity" predicateString="($query == '' OR name BEGINSWITH[cd] $query) AND mpHashHex == $mpHashHex"/>
|
||||
<elements>
|
||||
<element name="MPElementEntity" positionX="160" positionY="192" width="128" height="135"/>
|
||||
<element name="MPElementGeneratedEntity" positionX="160" positionY="192" width="128" height="60"/>
|
||||
<element name="MPElementStoredEntity" positionX="160" positionY="192" width="128" height="60"/>
|
||||
</elements>
|
||||
</model>
|
||||
</model>
|
||||
BIN
MasterPassword/Resources/Insignia/icon_action.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
MasterPassword/Resources/Insignia/icon_action@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
MasterPassword/Resources/Insignia/icon_addressbook-person.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 650 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
BIN
MasterPassword/Resources/Insignia/icon_aligned-center.png
Normal file
|
After Width: | Height: | Size: 1020 B |
|
Before Width: | Height: | Size: 883 B After Width: | Height: | Size: 1.6 KiB |
BIN
MasterPassword/Resources/Insignia/icon_aligned-justified.png
Normal file
|
After Width: | Height: | Size: 952 B |
|
Before Width: | Height: | Size: 664 B After Width: | Height: | Size: 1.4 KiB |
BIN
MasterPassword/Resources/Insignia/icon_aligned-left.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 856 B After Width: | Height: | Size: 1.5 KiB |
BIN
MasterPassword/Resources/Insignia/icon_aligned-right.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 806 B After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 801 B After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 772 B After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.9 KiB |
BIN
MasterPassword/Resources/Insignia/icon_battery-charging.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.3 KiB |
BIN
MasterPassword/Resources/Insignia/icon_battery-drained.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.1 KiB |
BIN
MasterPassword/Resources/Insignia/icon_battery-empty.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.8 KiB |
BIN
MasterPassword/Resources/Insignia/icon_battery-full.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1010 B After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 686 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 3.0 KiB |
BIN
MasterPassword/Resources/Insignia/icon_boy-girl.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 763 B After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.9 KiB |
BIN
MasterPassword/Resources/Insignia/icon_bubble-text.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 622 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 851 B After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
MasterPassword/Resources/Insignia/icon_cabinet-empty.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.3 KiB |
BIN
MasterPassword/Resources/Insignia/icon_cabinet-full.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 691 B After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 636 B After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.8 KiB |
BIN
MasterPassword/Resources/Insignia/icon_calendar-day.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.3 KiB |
BIN
MasterPassword/Resources/Insignia/icon_calendar-month.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 853 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.0 KiB |