2
0

Settings toggle and site user name.

[ADDED]     Allow saving a user name per site.  This is an optional
            addition, toggled by tapping the new settings icon.
            Obviously user names can't be recovered after loss.
This commit is contained in:
Maarten Billemont 2012-07-16 20:29:48 +02:00
parent 559e11b16e
commit fc60460935
12 changed files with 551 additions and 331 deletions

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit 396fe5bd8a53adad376231ff32c56984f94c9c96 Subproject commit 032b71a820d7f9526a42f51a00023e8247cd0943

View File

@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */; }; DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */; };
DA0757EA15B3681200613FAA /* MPElementEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0757E915B3681200613FAA /* MPElementEntity.m */; };
DA0A1D0515690A9A0092735D /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D0315690A9A0092735D /* Default.png */; }; DA0A1D0515690A9A0092735D /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D0315690A9A0092735D /* Default.png */; };
DA0A1D0615690A9A0092735D /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D0415690A9A0092735D /* Default@2x.png */; }; DA0A1D0615690A9A0092735D /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D0415690A9A0092735D /* Default@2x.png */; };
DA0A1D1515690AF40092735D /* Icon-72@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D1315690AF30092735D /* Icon-72@2x.png */; }; DA0A1D1515690AF40092735D /* Icon-72@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D1315690AF30092735D /* Icon-72@2x.png */; };
@ -675,7 +676,6 @@
DAB9FE1C15AC00C0007A7E5C /* MPElementGeneratedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB9FE1B15AC00C0007A7E5C /* MPElementGeneratedEntity.m */; }; DAB9FE1C15AC00C0007A7E5C /* MPElementGeneratedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB9FE1B15AC00C0007A7E5C /* MPElementGeneratedEntity.m */; };
DAB9FE1F15AC00C0007A7E5C /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB9FE1E15AC00C0007A7E5C /* MPUserEntity.m */; }; DAB9FE1F15AC00C0007A7E5C /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB9FE1E15AC00C0007A7E5C /* MPUserEntity.m */; };
DAB9FE2215AC00C0007A7E5C /* MPElementStoredEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB9FE2115AC00C0007A7E5C /* MPElementStoredEntity.m */; }; DAB9FE2215AC00C0007A7E5C /* MPElementStoredEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB9FE2115AC00C0007A7E5C /* MPElementStoredEntity.m */; };
DAB9FE2515AC00C0007A7E5C /* MPElementEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB9FE2415AC00C0007A7E5C /* MPElementEntity.m */; };
DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DABB981515100B4000B05417 /* SystemConfiguration.framework */; }; DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DABB981515100B4000B05417 /* SystemConfiguration.framework */; };
DAC6325E1486805C0075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DAC6325E1486805C0075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DAC6326D148680650075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DAC6326D148680650075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
@ -888,6 +888,8 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
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; };
DA0757E815B3681200613FAA /* MPElementEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementEntity.h; sourceTree = "<group>"; };
DA0757E915B3681200613FAA /* MPElementEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementEntity.m; sourceTree = "<group>"; };
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; };
DA0A1D0415690A9A0092735D /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default@2x.png"; path = "Resources/Default@2x.png"; sourceTree = SOURCE_ROOT; }; DA0A1D0415690A9A0092735D /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default@2x.png"; path = "Resources/Default@2x.png"; sourceTree = SOURCE_ROOT; };
DA0A1D0715690AD40092735D /* tip_arrow_banana.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = tip_arrow_banana.png; path = Resources/Tooltips/tip_arrow_banana.png; sourceTree = SOURCE_ROOT; }; DA0A1D0715690AD40092735D /* tip_arrow_banana.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = tip_arrow_banana.png; path = Resources/Tooltips/tip_arrow_banana.png; sourceTree = SOURCE_ROOT; };
@ -1646,8 +1648,6 @@
DAB9FE1E15AC00C0007A7E5C /* MPUserEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUserEntity.m; sourceTree = "<group>"; }; DAB9FE1E15AC00C0007A7E5C /* MPUserEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUserEntity.m; sourceTree = "<group>"; };
DAB9FE2015AC00C0007A7E5C /* MPElementStoredEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementStoredEntity.h; sourceTree = "<group>"; }; DAB9FE2015AC00C0007A7E5C /* MPElementStoredEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementStoredEntity.h; sourceTree = "<group>"; };
DAB9FE2115AC00C0007A7E5C /* MPElementStoredEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementStoredEntity.m; sourceTree = "<group>"; }; DAB9FE2115AC00C0007A7E5C /* MPElementStoredEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementStoredEntity.m; sourceTree = "<group>"; };
DAB9FE2315AC00C0007A7E5C /* MPElementEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementEntity.h; sourceTree = "<group>"; };
DAB9FE2415AC00C0007A7E5C /* MPElementEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementEntity.m; sourceTree = "<group>"; };
DABB980C150FF40100B05417 /* SendToMac-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SendToMac-Prefix.pch"; sourceTree = "<group>"; }; DABB980C150FF40100B05417 /* SendToMac-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SendToMac-Prefix.pch"; sourceTree = "<group>"; };
DABB980D150FF40100B05417 /* SendToMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SendToMac.h; sourceTree = "<group>"; }; DABB980D150FF40100B05417 /* SendToMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SendToMac.h; sourceTree = "<group>"; };
DABB980E150FF40100B05417 /* SendToMac.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SendToMac.m; sourceTree = "<group>"; }; DABB980E150FF40100B05417 /* SendToMac.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SendToMac.m; sourceTree = "<group>"; };
@ -1999,8 +1999,6 @@
DA5BFA50147E415C00F98B1E /* MasterPassword */ = { DA5BFA50147E415C00F98B1E /* MasterPassword */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DAB9FE2315AC00C0007A7E5C /* MPElementEntity.h */,
DAB9FE2415AC00C0007A7E5C /* MPElementEntity.m */,
DAB9FE2015AC00C0007A7E5C /* MPElementStoredEntity.h */, DAB9FE2015AC00C0007A7E5C /* MPElementStoredEntity.h */,
DAB9FE2115AC00C0007A7E5C /* MPElementStoredEntity.m */, DAB9FE2115AC00C0007A7E5C /* MPElementStoredEntity.m */,
DAB9FE1D15AC00C0007A7E5C /* MPUserEntity.h */, DAB9FE1D15AC00C0007A7E5C /* MPUserEntity.h */,
@ -2010,6 +2008,8 @@
DA0E07941577FE490008A67E /* MPEntities.h */, DA0E07941577FE490008A67E /* MPEntities.h */,
DA0E07951577FE490008A67E /* MPEntities.m */, DA0E07951577FE490008A67E /* MPEntities.m */,
DAB8D43C15036BCF00CED3BC /* MasterPassword.xcdatamodeld */, DAB8D43C15036BCF00CED3BC /* MasterPassword.xcdatamodeld */,
DA0757E815B3681200613FAA /* MPElementEntity.h */,
DA0757E915B3681200613FAA /* MPElementEntity.m */,
DA600C2415054F3A008E9AB6 /* MPAppDelegate_Key.h */, DA600C2415054F3A008E9AB6 /* MPAppDelegate_Key.h */,
DA600C2315054F3A008E9AB6 /* MPAppDelegate_Key.m */, DA600C2315054F3A008E9AB6 /* MPAppDelegate_Key.m */,
DA4426041557C1990052177D /* MPAppDelegate_Shared.h */, DA4426041557C1990052177D /* MPAppDelegate_Shared.h */,
@ -4248,7 +4248,7 @@
DAB9FE1C15AC00C0007A7E5C /* MPElementGeneratedEntity.m in Sources */, DAB9FE1C15AC00C0007A7E5C /* MPElementGeneratedEntity.m in Sources */,
DAB9FE1F15AC00C0007A7E5C /* MPUserEntity.m in Sources */, DAB9FE1F15AC00C0007A7E5C /* MPUserEntity.m in Sources */,
DAB9FE2215AC00C0007A7E5C /* MPElementStoredEntity.m in Sources */, DAB9FE2215AC00C0007A7E5C /* MPElementStoredEntity.m in Sources */,
DAB9FE2515AC00C0007A7E5C /* MPElementEntity.m in Sources */, DA0757EA15B3681200613FAA /* MPElementEntity.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@ -2,7 +2,7 @@
// MPElementEntity.h // MPElementEntity.h
// MasterPassword-iOS // MasterPassword-iOS
// //
// Created by Maarten Billemont on 10/07/12. // Created by Maarten Billemont on 15/07/12.
// Copyright (c) 2012 Lyndir. All rights reserved. // Copyright (c) 2012 Lyndir. All rights reserved.
// //
@ -16,10 +16,11 @@
@property (nonatomic, retain) id content; @property (nonatomic, retain) id content;
@property (nonatomic, retain) NSDate * lastUsed; @property (nonatomic, retain) NSDate * lastUsed;
@property (nonatomic, retain) NSString * name; @property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSNumber * requiresExplicitMigration_;
@property (nonatomic, retain) NSNumber * type_; @property (nonatomic, retain) NSNumber * type_;
@property (nonatomic, retain) NSNumber * uses_; @property (nonatomic, retain) NSNumber * uses_;
@property (nonatomic, retain) NSNumber * version_; @property (nonatomic, retain) NSNumber * version_;
@property (nonatomic, retain) NSNumber * requiresExplicitMigration_; @property (nonatomic, retain) NSString * userName;
@property (nonatomic, retain) MPUserEntity *user; @property (nonatomic, retain) MPUserEntity *user;
@end @end

View File

@ -2,7 +2,7 @@
// MPElementEntity.m // MPElementEntity.m
// MasterPassword-iOS // MasterPassword-iOS
// //
// Created by Maarten Billemont on 10/07/12. // Created by Maarten Billemont on 15/07/12.
// Copyright (c) 2012 Lyndir. All rights reserved. // Copyright (c) 2012 Lyndir. All rights reserved.
// //
@ -15,10 +15,11 @@
@dynamic content; @dynamic content;
@dynamic lastUsed; @dynamic lastUsed;
@dynamic name; @dynamic name;
@dynamic requiresExplicitMigration_;
@dynamic type_; @dynamic type_;
@dynamic uses_; @dynamic uses_;
@dynamic version_; @dynamic version_;
@dynamic requiresExplicitMigration_; @dynamic userName;
@dynamic user; @dynamic user;
@end @end

View File

@ -45,9 +45,11 @@ typedef enum {
#define MPCheckpointAction @"MPCheckpointAction" #define MPCheckpointAction @"MPCheckpointAction"
#define MPCheckpointHelpChapter @"MPCheckpointHelpChapter" #define MPCheckpointHelpChapter @"MPCheckpointHelpChapter"
#define MPCheckpointCopyToPasteboard @"MPCheckpointCopyToPasteboard" #define MPCheckpointCopyToPasteboard @"MPCheckpointCopyToPasteboard"
#define MPCheckpointCopyUserNameToPasteboard @"MPCheckpointCopyUserNameToPasteboard"
#define MPCheckpointResetPasswordCounter @"MPCheckpointResetPasswordCounter" #define MPCheckpointResetPasswordCounter @"MPCheckpointResetPasswordCounter"
#define MPCheckpointIncrementPasswordCounter @"MPCheckpointIncrementPasswordCounter" #define MPCheckpointIncrementPasswordCounter @"MPCheckpointIncrementPasswordCounter"
#define MPCheckpointEditPassword @"MPCheckpointEditPassword" #define MPCheckpointEditPassword @"MPCheckpointEditPassword"
#define MPCheckpointEditUserName @"MPCheckpointEditUserName"
#define MPCheckpointCloseAlert @"MPCheckpointCloseAlert" #define MPCheckpointCloseAlert @"MPCheckpointCloseAlert"
#define MPCheckpointUseType @"MPCheckpointUseType" #define MPCheckpointUseType @"MPCheckpointUseType"
#define MPCheckpointDeleteElement @"MPCheckpointDeleteElement" #define MPCheckpointDeleteElement @"MPCheckpointDeleteElement"

View File

@ -6,6 +6,7 @@
<attribute name="name" attributeType="String" minValueString="1" indexed="YES" syncable="YES"/> <attribute name="name" attributeType="String" minValueString="1" indexed="YES" syncable="YES"/>
<attribute name="requiresExplicitMigration_" transient="YES" attributeType="Boolean" defaultValueString="NO" syncable="YES"/> <attribute name="requiresExplicitMigration_" transient="YES" attributeType="Boolean" defaultValueString="NO" syncable="YES"/>
<attribute name="type_" attributeType="Integer 16" defaultValueString="17" syncable="YES"/> <attribute name="type_" attributeType="Integer 16" defaultValueString="17" syncable="YES"/>
<attribute name="userName" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="uses_" attributeType="Integer 16" defaultValueString="0" syncable="YES"/> <attribute name="uses_" attributeType="Integer 16" defaultValueString="0" syncable="YES"/>
<attribute name="version_" attributeType="Integer 16" minValueString="0" defaultValueString="0" syncable="YES"/> <attribute name="version_" attributeType="Integer 16" minValueString="0" defaultValueString="0" syncable="YES"/>
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements" inverseEntity="MPUserEntity" syncable="YES"/> <relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements" inverseEntity="MPUserEntity" syncable="YES"/>
@ -26,7 +27,7 @@
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/> <relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
</entity> </entity>
<elements> <elements>
<element name="MPElementEntity" positionX="160" positionY="192" width="128" height="165"/> <element name="MPElementEntity" positionX="160" positionY="192" width="128" height="180"/>
<element name="MPElementGeneratedEntity" positionX="160" positionY="192" width="128" height="60"/> <element name="MPElementGeneratedEntity" positionX="160" positionY="192" width="128" height="60"/>
<element name="MPElementStoredEntity" positionX="160" positionY="192" width="128" height="60"/> <element name="MPElementStoredEntity" positionX="160" positionY="192" width="128" height="60"/>
<element name="MPUserEntity" positionX="160" positionY="192" width="128" height="150"/> <element name="MPUserEntity" positionX="160" positionY="192" width="128" height="150"/>

View File

@ -11,11 +11,11 @@
#import "MPElementEntity.h" #import "MPElementEntity.h"
#import "MPSearchDelegate.h" #import "MPSearchDelegate.h"
@interface MPMainViewController : UIViewController<MPTypeDelegate, UITextFieldDelegate, MPSearchResultsDelegate, UIWebViewDelegate, MFMailComposeViewControllerDelegate> @interface MPMainViewController : UIViewController<MPTypeDelegate, UITextFieldDelegate, MPSearchResultsDelegate, UIWebViewDelegate, MFMailComposeViewControllerDelegate, UIGestureRecognizerDelegate>
@property (nonatomic, assign) BOOL showSettings;
@property (strong, nonatomic) MPElementEntity *activeElement; @property (strong, nonatomic) MPElementEntity *activeElement;
@property (strong, nonatomic) IBOutlet MPSearchDelegate *searchDelegate; @property (strong, nonatomic) IBOutlet MPSearchDelegate *searchDelegate;
@property (strong, nonatomic) IBOutlet UILongPressGestureRecognizer *resetPasswordCounterGesture;
@property (weak, nonatomic) IBOutlet UITextField *contentField; @property (weak, nonatomic) IBOutlet UITextField *contentField;
@property (weak, nonatomic) IBOutlet UIButton *typeButton; @property (weak, nonatomic) IBOutlet UIButton *typeButton;
@property (weak, nonatomic) IBOutlet UIWebView *helpView; @property (weak, nonatomic) IBOutlet UIWebView *helpView;
@ -25,18 +25,23 @@
@property (weak, nonatomic) IBOutlet UIButton *passwordEdit; @property (weak, nonatomic) IBOutlet UIButton *passwordEdit;
@property (weak, nonatomic) IBOutlet UIButton *passwordUpgrade; @property (weak, nonatomic) IBOutlet UIButton *passwordUpgrade;
@property (weak, nonatomic) IBOutlet UIView *contentContainer; @property (weak, nonatomic) IBOutlet UIView *contentContainer;
@property (weak, nonatomic) IBOutlet UIView *displayContainer;
@property (weak, nonatomic) IBOutlet UIView *helpContainer; @property (weak, nonatomic) IBOutlet UIView *helpContainer;
@property (weak, nonatomic) IBOutlet UIView *contentTipContainer; @property (weak, nonatomic) IBOutlet UIView *contentTipContainer;
@property (weak, nonatomic) IBOutlet UIView *userNameTipContainer;
@property (weak, nonatomic) IBOutlet UIView *alertContainer; @property (weak, nonatomic) IBOutlet UIView *alertContainer;
@property (weak, nonatomic) IBOutlet UILabel *alertTitle; @property (weak, nonatomic) IBOutlet UILabel *alertTitle;
@property (weak, nonatomic) IBOutlet UITextView *alertBody; @property (weak, nonatomic) IBOutlet UITextView *alertBody;
@property (weak, nonatomic) IBOutlet UILabel *contentTipBody; @property (weak, nonatomic) IBOutlet UILabel *contentTipBody;
@property (weak, nonatomic) IBOutlet UILabel *userNameTipBody;
@property (weak, nonatomic) IBOutlet UIImageView *toolTipEditIcon; @property (weak, nonatomic) IBOutlet UIImageView *toolTipEditIcon;
@property (weak, nonatomic) IBOutlet UIView *searchTipContainer; @property (weak, nonatomic) IBOutlet UIView *searchTipContainer;
@property (weak, nonatomic) IBOutlet UIView *actionsTipContainer; @property (weak, nonatomic) IBOutlet UIView *actionsTipContainer;
@property (weak, nonatomic) IBOutlet UIView *typeTipContainer; @property (weak, nonatomic) IBOutlet UIView *typeTipContainer;
@property (weak, nonatomic) IBOutlet UIView *toolTipContainer; @property (weak, nonatomic) IBOutlet UIView *toolTipContainer;
@property (weak, nonatomic) IBOutlet UILabel *toolTipBody; @property (weak, nonatomic) IBOutlet UILabel *toolTipBody;
@property (weak, nonatomic) IBOutlet UIView *userNameContainer;
@property (weak, nonatomic) IBOutlet UITextField *userNameField;
@property (copy) void (^contentTipCleanup)(BOOL finished); @property (copy) void (^contentTipCleanup)(BOOL finished);
@property (copy) void (^toolTipCleanup)(BOOL finished); @property (copy) void (^toolTipCleanup)(BOOL finished);
@ -44,12 +49,13 @@
- (IBAction)copyContent; - (IBAction)copyContent;
- (IBAction)incrementPasswordCounter; - (IBAction)incrementPasswordCounter;
- (IBAction)resetPasswordCounter:(UILongPressGestureRecognizer *)sender; - (IBAction)resetPasswordCounter:(UILongPressGestureRecognizer *)sender;
- (IBAction)editUserName:(UILongPressGestureRecognizer *)sender;
- (IBAction)editPassword; - (IBAction)editPassword;
- (IBAction)closeAlert; - (IBAction)closeAlert;
- (IBAction)upgradePassword; - (IBAction)upgradePassword;
- (IBAction)action:(UIBarButtonItem *)sender; - (IBAction)action:(UIBarButtonItem *)sender;
- (IBAction)toggleSettings;
- (BOOL)isHelpVisible;
- (void)toggleHelpAnimated:(BOOL)animated; - (void)toggleHelpAnimated:(BOOL)animated;
- (void)setHelpHidden:(BOOL)hidden animated:(BOOL)animated; - (void)setHelpHidden:(BOOL)hidden animated:(BOOL)animated;
- (void)setHelpChapter:(NSString *)chapter; - (void)setHelpChapter:(NSString *)chapter;

View File

@ -27,6 +27,7 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
@end @end
@implementation MPMainViewController @implementation MPMainViewController
@synthesize showSettings = _showSettings;
@synthesize activeElement = _activeElement; @synthesize activeElement = _activeElement;
@synthesize searchDelegate = _searchDelegate; @synthesize searchDelegate = _searchDelegate;
@synthesize typeButton = _typeButton; @synthesize typeButton = _typeButton;
@ -37,19 +38,23 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
@synthesize passwordEdit = _passwordEdit; @synthesize passwordEdit = _passwordEdit;
@synthesize passwordUpgrade = _passwordUpgrade; @synthesize passwordUpgrade = _passwordUpgrade;
@synthesize contentContainer = _contentContainer; @synthesize contentContainer = _contentContainer;
@synthesize displayContainer = _displayContainer;
@synthesize helpContainer = _helpContainer; @synthesize helpContainer = _helpContainer;
@synthesize contentTipContainer = _copiedContainer; @synthesize contentTipContainer = _copiedContainer;
@synthesize userNameTipContainer = _userNameTipContainer;
@synthesize alertContainer = _alertContainer; @synthesize alertContainer = _alertContainer;
@synthesize alertTitle = _alertTitle; @synthesize alertTitle = _alertTitle;
@synthesize alertBody = _alertBody; @synthesize alertBody = _alertBody;
@synthesize contentTipBody = _contentTipBody; @synthesize contentTipBody = _contentTipBody;
@synthesize userNameTipBody = _userNameTipBody;
@synthesize toolTipEditIcon = _contentTipEditIcon; @synthesize toolTipEditIcon = _contentTipEditIcon;
@synthesize searchTipContainer = _searchTipContainer; @synthesize searchTipContainer = _searchTipContainer;
@synthesize actionsTipContainer = _actionsTipContainer; @synthesize actionsTipContainer = _actionsTipContainer;
@synthesize typeTipContainer = _typeTipContainer; @synthesize typeTipContainer = _typeTipContainer;
@synthesize toolTipContainer = _toolTipContainer; @synthesize toolTipContainer = _toolTipContainer;
@synthesize toolTipBody = _toolTipBody; @synthesize toolTipBody = _toolTipBody;
@synthesize resetPasswordCounterGesture = _resetPasswordCounterGesture; @synthesize userNameContainer = _userNameContainer;
@synthesize userNameField = _userNameField;
@synthesize contentField = _contentField; @synthesize contentField = _contentField;
@synthesize contentTipCleanup = _contentTipCleanup, toolTipCleanup = _toolTipCleanup; @synthesize contentTipCleanup = _contentTipCleanup, toolTipCleanup = _toolTipCleanup;
@ -62,7 +67,8 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[self setHelpHidden:![self isHelpVisible] animated:NO]; [self updateHelpHiddenAnimated:NO];
[self updateSettingsHiddenAnimated:NO];
} }
@ -83,8 +89,9 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
self.searchDisplayController.searchResultsDelegate = self.searchDelegate; self.searchDisplayController.searchResultsDelegate = self.searchDelegate;
self.searchDisplayController.searchResultsDataSource = self.searchDelegate; self.searchDisplayController.searchResultsDataSource = self.searchDelegate;
self.resetPasswordCounterGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(resetPasswordCounter:)]; [self.passwordIncrementer addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(resetPasswordCounter:)]];
[self.passwordIncrementer addGestureRecognizer:self.resetPasswordCounterGesture]; [self.userNameContainer addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(editUserName:)]];
[self.userNameContainer addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(copyUserName)]];
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui_background"]]; self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui_background"]];
@ -127,7 +134,8 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
self.typeTipContainer.alpha = 0; self.typeTipContainer.alpha = 0;
self.toolTipContainer.alpha = 0; self.toolTipContainer.alpha = 0;
[self setHelpHidden:[[MPiOSConfig get].helpHidden boolValue] animated:animated]; [self updateHelpHiddenAnimated:NO];
[self updateSettingsHiddenAnimated:NO];
[self updateAnimated:animated]; [self updateAnimated:animated];
[super viewWillAppear:animated]; [super viewWillAppear:animated];
@ -185,10 +193,13 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
[self setSearchTipContainer:nil]; [self setSearchTipContainer:nil];
[self setActionsTipContainer:nil]; [self setActionsTipContainer:nil];
[self setTypeTipContainer:nil]; [self setTypeTipContainer:nil];
[self setSearchDelegate:nil];
[self setResetPasswordCounterGesture:nil];
[self setToolTipContainer:nil]; [self setToolTipContainer:nil];
[self setToolTipBody:nil]; [self setToolTipBody:nil];
[self setDisplayContainer:nil];
[self setUserNameField:nil];
[self setUserNameTipContainer:nil];
[self setUserNameTipBody:nil];
[self setUserNameContainer:nil];
[super viewDidUnload]; [super viewDidUnload];
} }
@ -225,7 +236,8 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
forState:UIControlStateNormal]; forState:UIControlStateNormal];
self.typeButton.alpha = NSStringFromMPElementType(self.activeElement.type).length? 1: 0; self.typeButton.alpha = NSStringFromMPElementType(self.activeElement.type).length? 1: 0;
self.contentField.enabled = NO; self.contentField.enabled = NO;
self.userNameField.enabled = NO;
if ([self.activeElement isKindOfClass:[MPElementGeneratedEntity class]]) if ([self.activeElement isKindOfClass:[MPElementGeneratedEntity class]])
self.passwordCounter.text = PearlString(@"%u", ((MPElementGeneratedEntity *)self.activeElement).counter); self.passwordCounter.text = PearlString(@"%u", ((MPElementGeneratedEntity *)self.activeElement).counter);
@ -241,31 +253,62 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
}); });
} }
- (BOOL)isHelpVisible {
return self.helpContainer.frame.origin.y == 216;
}
- (void)toggleHelpAnimated:(BOOL)animated { - (void)toggleHelpAnimated:(BOOL)animated {
[self setHelpHidden:[self isHelpVisible] animated:animated]; [self setHelpHidden:![[MPiOSConfig get].helpHidden boolValue] animated:animated];
} }
- (void)setHelpHidden:(BOOL)hidden animated:(BOOL)animated { - (void)setHelpHidden:(BOOL)hidden animated:(BOOL)animated {
dispatch_async(dispatch_get_main_queue(), ^{ [MPiOSConfig get].helpHidden = PearlBool(hidden);
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{ [self updateHelpHiddenAnimated:animated];
if (hidden) { }
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, self.view.bounds.size.height - 44);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, self.view.bounds.size.height); - (void)updateHelpHiddenAnimated:(BOOL)animated {
[MPiOSConfig get].helpHidden = [NSNumber numberWithBool:YES];
} else { if (animated) {
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, 175); [UIView animateWithDuration:0.3f animations:^{
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, 216); [self updateHelpHiddenAnimated:NO];
[MPiOSConfig get].helpHidden = [NSNumber numberWithBool:NO];
}
}]; }];
}); return;
}
if ([[MPiOSConfig get].helpHidden boolValue]) {
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, self.view.bounds.size.height - 44);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, self.view.bounds.size.height);
} else {
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, 225);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, 266);
}
}
- (IBAction)toggleSettings {
[self toggleSettingsAnimated:YES];
}
- (void)toggleSettingsAnimated:(BOOL)animated {
[MPiOSConfig get].settingsHidden = PearlBoolNot([MPiOSConfig get].settingsHidden);
self.showSettings = ![[MPiOSConfig get].settingsHidden boolValue];
[self updateSettingsHiddenAnimated:animated];
}
- (void)updateSettingsHiddenAnimated:(BOOL)animated {
if (animated) {
[UIView animateWithDuration:0.3f animations:^{
[self updateSettingsHiddenAnimated:NO];
}];
return;
}
if (self.showSettings) {
self.displayContainer.frame = CGRectSetHeight(self.displayContainer.frame, 137);
} else {
self.displayContainer.frame = CGRectSetHeight(self.displayContainer.frame, 87);
}
} }
- (void)setHelpChapter:(NSString *)chapter { - (void)setHelpChapter:(NSString *)chapter {
@ -315,6 +358,26 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
}); });
} }
- (void)showUserNameTip:(NSString *)message {
dispatch_async(dispatch_get_main_queue(), ^{
self.userNameTipBody.text = message;
[UIView animateWithDuration:0.3f animations:^{
self.userNameTipContainer.alpha = 1;
} completion:^(BOOL finished) {
if (finished) {
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
[UIView animateWithDuration:0.2f animations:^{
self.userNameTipContainer.alpha = 0;
}];
});
}
}];
});
}
- (void)showToolTip:(NSString *)message withIcon:(UIImageView *)icon { - (void)showToolTip:(NSString *)message withIcon:(UIImageView *)icon {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
@ -376,6 +439,27 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCopyToPasteboard [[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCopyToPasteboard
attributes:[NSDictionary dictionaryWithObjectsAndKeys: attributes:[NSDictionary dictionaryWithObjectsAndKeys:
NSStringFromMPElementType(self.activeElement.type), @"type", NSStringFromMPElementType(self.activeElement.type), @"type",
PearlUnsignedInteger(self.activeElement.version),
@"version",
nil]];
}
- (IBAction)copyUserName {
if (!self.activeElement.userName)
return;
inf(@"Copying user name for: %@", self.activeElement.name);
[UIPasteboard generalPasteboard].string = [self.activeElement.content description];
[self showUserNameTip:@"Copied!"];
[TestFlight passCheckpoint:MPCheckpointCopyUserNameToPasteboard];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCopyUserNameToPasteboard
attributes:[NSDictionary dictionaryWithObjectsAndKeys:
NSStringFromMPElementType(self.activeElement.type), @"type",
PearlUnsignedInteger(self.activeElement.version),
@"version",
nil]]; nil]];
} }
@ -399,6 +483,8 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
attributes:[NSDictionary dictionaryWithObjectsAndKeys: attributes:[NSDictionary dictionaryWithObjectsAndKeys:
NSStringFromMPElementType( NSStringFromMPElementType(
self.activeElement.type), @"type", self.activeElement.type), @"type",
PearlUnsignedInteger(self.activeElement.version),
@"version",
nil]]; nil]];
}]; }];
} }
@ -428,10 +514,34 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
attributes:[NSDictionary dictionaryWithObjectsAndKeys: attributes:[NSDictionary dictionaryWithObjectsAndKeys:
NSStringFromMPElementType( NSStringFromMPElementType(
self.activeElement.type), @"type", self.activeElement.type), @"type",
PearlUnsignedInteger(self.activeElement.version),
@"version",
nil]]; nil]];
}]; }];
} }
- (IBAction)editUserName:(UILongPressGestureRecognizer *)sender {
if (sender.state != UIGestureRecognizerStateBegan)
// Only fire when the gesture was first detected.
return;
if (!self.activeElement)
return;
self.userNameField.enabled = YES;
[self.userNameField becomeFirstResponder];
[TestFlight passCheckpoint:MPCheckpointEditUserName];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointEditUserName attributes:[NSDictionary dictionaryWithObjectsAndKeys:
NSStringFromMPElementType(
self.activeElement.type),
@"type",
PearlUnsignedInteger(self.activeElement.version),
@"version",
nil]];
}
- (void)changeElementWithWarning:(NSString *)warning do:(void (^)(void))task; { - (void)changeElementWithWarning:(NSString *)warning do:(void (^)(void))task; {
[PearlAlert showAlertWithTitle:@"Password Change" message:warning viewStyle:UIAlertViewStyleDefault [PearlAlert showAlertWithTitle:@"Password Change" message:warning viewStyle:UIAlertViewStyleDefault
@ -474,6 +584,8 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
attributes:[NSDictionary dictionaryWithObjectsAndKeys: attributes:[NSDictionary dictionaryWithObjectsAndKeys:
NSStringFromMPElementType( NSStringFromMPElementType(
self.activeElement.type), @"type", self.activeElement.type), @"type",
PearlUnsignedInteger(self.activeElement.version),
@"version",
nil]]; nil]];
} }
} }
@ -616,7 +728,8 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
[TestFlight passCheckpoint:MPCheckpointAction]; [TestFlight passCheckpoint:MPCheckpointAction];
} }
cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil otherTitles: cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil otherTitles:
[self isHelpVisible]? @"Hide Help": @"Show Help", @"FAQ", @"Tutorial", @"Preferences", @"Feedback", @"Sign Out", nil]; [[MPiOSConfig get].helpHidden boolValue]? @"Show Help": @"Hide Help", @"FAQ", @"Tutorial", @"Preferences", @"Feedback", @"Sign Out",
nil];
} }
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result - (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result
@ -707,9 +820,12 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
NSStringFromMPElementType( NSStringFromMPElementType(
self.activeElement.type), self.activeElement.type),
@"type", @"type",
PearlUnsignedInteger(self.activeElement.version),
@"version",
nil]]; nil]];
} }
self.showSettings = ![[MPiOSConfig get].settingsHidden boolValue] || (element.userName != nil);
[self updateAnimated:YES]; [self updateAnimated:YES];
} }
@ -717,6 +833,8 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
if (textField == self.contentField) if (textField == self.contentField)
[self.contentField resignFirstResponder]; [self.contentField resignFirstResponder];
if (textField == self.userNameField)
[self.userNameField resignFirstResponder];
return YES; return YES;
} }
@ -737,6 +855,21 @@ void MPElementMigrate(MPElementEntity *entity, BOOL i);
((MPElementStoredEntity *)self.activeElement).content = self.contentField.text; ((MPElementStoredEntity *)self.activeElement).content = self.contentField.text;
}]; }];
} }
if (textField == self.userNameField) {
self.userNameField.enabled = NO;
if (![[MPiOSConfig get].userNameTipShown boolValue]) {
[self showUserNameTip:@"Tap to copy or hold to edit."];
[MPiOSConfig get].userNameTipShown = PearlBool(YES);
}
if ([self.userNameField.text length])
self.activeElement.userName = self.userNameField.text;
else
self.activeElement.userName = nil;
[[MPAppDelegate get] saveContext];
}
} }
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request

View File

@ -39,7 +39,7 @@
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses_" ascending:NO]]; fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses_" ascending:NO]];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:[MPAppDelegate managedObjectContext] managedObjectContext:[MPAppDelegate managedObjectContext]
sectionNameKeyPath:nil cacheName:nil]; sectionNameKeyPath:nil cacheName:nil];
self.fetchedResultsController.delegate = self; self.fetchedResultsController.delegate = self;
self.tipView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 170)]; self.tipView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 170)];
@ -129,7 +129,8 @@
assert(self.query); assert(self.query);
self.fetchedResultsController.fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(%@ == '' OR name BEGINSWITH[cd] %@) AND user == %@", self.fetchedResultsController.fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(%@ == '' OR name BEGINSWITH[cd] %@) AND user == %@",
self.query, self.query, NilToNSNull([MPAppDelegate get].activeUser)]; self.query, self.query,
NilToNSNull([MPAppDelegate get].activeUser)];
NSError *error; NSError *error;
if (![self.fetchedResultsController performFetch:&error]) if (![self.fetchedResultsController performFetch:&error])
@ -316,7 +317,7 @@
[self.delegate didSelectElement:element]; [self.delegate didSelectElement:element];
}); });
}]; }];
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil]; } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil];
} }
} }
@ -353,6 +354,8 @@ forRowAtIndexPath:(NSIndexPath *)indexPath {
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointDeleteElement [[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointDeleteElement
attributes:[NSDictionary dictionaryWithObjectsAndKeys: attributes:[NSDictionary dictionaryWithObjectsAndKeys:
NSStringFromMPElementType(element.type), @"type", NSStringFromMPElementType(element.type), @"type",
PearlUnsignedInteger(element.version),
@"version",
nil]]; nil]];
}]; }];
} }

View File

@ -12,9 +12,11 @@
@property (nonatomic, retain) NSNumber *sendInfo; @property (nonatomic, retain) NSNumber *sendInfo;
@property (nonatomic, retain) NSNumber *helpHidden; @property (nonatomic, retain) NSNumber *helpHidden;
@property (nonatomic, retain) NSNumber *settingsHidden;
@property (nonatomic, retain) NSNumber *showQuickStart; @property (nonatomic, retain) NSNumber *showQuickStart;
@property (nonatomic, retain) NSNumber *actionsTipShown; @property (nonatomic, retain) NSNumber *actionsTipShown;
@property (nonatomic, retain) NSNumber *typeTipShown; @property (nonatomic, retain) NSNumber *typeTipShown;
@property (nonatomic, retain) NSNumber *userNameTipShown;
+ (MPiOSConfig *)get; + (MPiOSConfig *)get;

View File

@ -7,7 +7,7 @@
// //
@implementation MPiOSConfig @implementation MPiOSConfig
@dynamic sendInfo, helpHidden, showQuickStart, actionsTipShown, typeTipShown; @dynamic sendInfo, helpHidden, settingsHidden, showQuickStart, actionsTipShown, typeTipShown, userNameTipShown;
- (id)init { - (id)init {
@ -17,10 +17,12 @@
[self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys: [self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(sendInfo)), [NSNumber numberWithBool:NO], NSStringFromSelector(@selector(sendInfo)),
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(helpHidden)), [NSNumber numberWithBool:NO], NSStringFromSelector(@selector(helpHidden)),
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(settingsHidden)),
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(showQuickStart)), [NSNumber numberWithBool:YES], NSStringFromSelector(@selector(showQuickStart)),
@"510296984", NSStringFromSelector(@selector(iTunesID)), @"510296984", NSStringFromSelector(@selector(iTunesID)),
PearlBoolNot(self.firstRun), NSStringFromSelector(@selector(actionsTipShown)), PearlBoolNot(self.firstRun), NSStringFromSelector(@selector(actionsTipShown)),
PearlBoolNot(self.firstRun), NSStringFromSelector(@selector(typeTipShown)), PearlBoolNot(self.firstRun), NSStringFromSelector(@selector(typeTipShown)),
PearlBool(NO), NSStringFromSelector(@selector(userNameTipShown)),
nil]]; nil]];
return self; return self;

File diff suppressed because it is too large Load Diff