Completed password cell handling and misc UI and moc update improvements.
[UPDATED] Make private moc parent of all private blocks to avoid blocking the main thread for writes, update the main moc on private moc updates. [FIXED] Don't cause a crash on elements with a bad type. [UPDATED] Improved cell handling and UI update handling. [UPDATED] Replace FontReplacer with moarfonts to fix issues in UICollectionViewCells.
This commit is contained in:
parent
f475c15360
commit
bd37f1d6a7
1
External/FontReplacer
vendored
1
External/FontReplacer
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 4e3dea08702906fc5d51c8b75dda5da29c545a74
|
2
External/Pearl
vendored
2
External/Pearl
vendored
@ -1 +1 @@
|
||||
Subproject commit b50115c767e7c0d412099ae169891dbb625b8c64
|
||||
Subproject commit d462ada876939cab875e08736b1efc7af065848d
|
@ -31,6 +31,21 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
|
||||
return strf( @"<%@: version=%d>", NSStringFromClass( [self class] ), self.version );
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)other {
|
||||
|
||||
if (other == self)
|
||||
return YES;
|
||||
if (!other || ![other conformsToProtocol:@protocol(MPAlgorithm)])
|
||||
return NO;
|
||||
|
||||
return [(id<MPAlgorithm>)other version] == [self version];
|
||||
}
|
||||
|
||||
- (BOOL)migrateUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc {
|
||||
|
||||
NSError *error = nil;
|
||||
@ -250,23 +265,24 @@
|
||||
uint32_t ncounter = htonl(counter), nnameLength = htonl(name.length);
|
||||
NSData *counterBytes = [NSData dataWithBytes:&ncounter length:sizeof(ncounter)];
|
||||
NSData *nameLengthBytes = [NSData dataWithBytes:&nnameLength length:sizeof(nnameLength)];
|
||||
trc(@"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %@ | %@ | %@)", [key.keyData encodeBase64], [nameLengthBytes encodeHex], name, [counterBytes encodeHex]);
|
||||
trc(@"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %@ | %@ | %@)", [key.keyData encodeBase64],
|
||||
[nameLengthBytes encodeHex], name, [counterBytes encodeHex]);
|
||||
NSData *seed = [[NSData dataByConcatenatingDatas:
|
||||
[@"com.lyndir.masterpassword" dataUsingEncoding:NSUTF8StringEncoding],
|
||||
nameLengthBytes,
|
||||
[name dataUsingEncoding:NSUTF8StringEncoding],
|
||||
counterBytes,
|
||||
nil]
|
||||
nameLengthBytes, [name dataUsingEncoding:NSUTF8StringEncoding],
|
||||
counterBytes, nil]
|
||||
hmacWith:PearlHashSHA256 key:key.keyData];
|
||||
trc(@"seed is: %@", [seed encodeBase64]);
|
||||
const char *seedBytes = seed.bytes;
|
||||
|
||||
// Determine the cipher from the first seed byte.
|
||||
NSAssert([seed length], @"Missing seed.");
|
||||
NSArray *typeCiphers = [[MPTypes_ciphers valueForKey:[self classNameOfType:type]]
|
||||
valueForKey:[self nameOfType:type]];
|
||||
NSString *typeClass = [self classNameOfType:type];
|
||||
NSString *typeName = [self nameOfType:type];
|
||||
id classCiphers = [MPTypes_ciphers valueForKey:typeClass];
|
||||
NSArray *typeCiphers = [classCiphers valueForKey:typeName];
|
||||
NSString *cipher = typeCiphers[htons(seedBytes[0]) % [typeCiphers count]];
|
||||
trc(@"type %@, ciphers: %@, selected: %@", [self nameOfType:type], typeCiphers, cipher);
|
||||
trc(@"type %@, ciphers: %@, selected: %@", typeName, typeCiphers, cipher);
|
||||
|
||||
// Encode the content, character by character, using subsequent seed bytes and the cipher.
|
||||
NSAssert([seed length] >= [cipher length] + 1, @"Insufficient seed bytes to encode cipher.");
|
||||
@ -275,8 +291,7 @@
|
||||
uint16_t keyByte = htons(seedBytes[c + 1]);
|
||||
NSString *cipherClass = [cipher substringWithRange:NSMakeRange( c, 1 )];
|
||||
NSString *cipherClassCharacters = [[MPTypes_ciphers valueForKey:@"MPCharacterClasses"] valueForKey:cipherClass];
|
||||
NSString *character = [cipherClassCharacters substringWithRange:NSMakeRange( keyByte % [cipherClassCharacters length],
|
||||
1 )];
|
||||
NSString *character = [cipherClassCharacters substringWithRange:NSMakeRange( keyByte % [cipherClassCharacters length], 1 )];
|
||||
|
||||
trc(@"class %@ has characters: %@, index: %u, selected: %@", cipherClass, cipherClassCharacters, keyByte, character);
|
||||
[content appendString:character];
|
||||
|
@ -168,7 +168,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
||||
|
||||
MPKey *recoverKey = newKey;
|
||||
#ifdef PEARL_UIKIT
|
||||
PearlOverlay *activityOverlay = [PearlOverlay showOverlayWithTitle:PearlString( @"Migrating %ld sites...", (long)[user.elements count] )];
|
||||
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:PearlString( @"Migrating %ld sites...", (long)[user.elements count] )];
|
||||
#endif
|
||||
|
||||
for (MPElementEntity *element in user.elements) {
|
||||
|
@ -30,11 +30,12 @@
|
||||
|
||||
- (MPUserEntity *)activeUserInContext:(NSManagedObjectContext *)moc {
|
||||
|
||||
if (!self.activeUserOID || !moc)
|
||||
NSManagedObjectID *activeUserOID = self.activeUserOID;
|
||||
if (!activeUserOID || !moc)
|
||||
return nil;
|
||||
|
||||
NSError *error;
|
||||
MPUserEntity *activeUser = (MPUserEntity *)[moc existingObjectWithID:self.activeUserOID error:&error];
|
||||
MPUserEntity *activeUser = (MPUserEntity *)[moc existingObjectWithID:activeUserOID error:&error];
|
||||
if (!activeUser) {
|
||||
[self signOutAnimated:YES];
|
||||
err(@"Failed to retrieve active user: %@", error);
|
||||
|
@ -30,7 +30,7 @@ typedef enum {
|
||||
|
||||
/** @param completion The block to execute after adding the element, executed from the main thread with the new element in the main MOC. */
|
||||
- (void)addElementNamed:(NSString *)siteName completion:(void (^)(MPElementEntity *element))completion;
|
||||
- (MPElementEntity *)changeElement:(MPElementEntity *)element inContext:(NSManagedObjectContext *)context toType:(MPElementType)type;
|
||||
- (MPElementEntity *)changeElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context toType:(MPElementType)type;
|
||||
- (MPImportResult)importSites:(NSString *)importedSitesString
|
||||
askImportPassword:(NSString *(^)(NSString *userName))importPassword
|
||||
askUserPassword:(NSString *(^)(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))userPassword;
|
||||
|
@ -32,7 +32,8 @@ typedef NS_ENUM(NSInteger, MPMigrationLevelCloudStore) {
|
||||
};
|
||||
|
||||
@implementation MPAppDelegate_Shared(Store)
|
||||
PearlAssociatedObjectProperty(NSManagedObjectContext*, PrivateManagedObjectContext, privateManagedObjectContext);
|
||||
PearlAssociatedObjectProperty(id, SaveObserver, saveObserver);
|
||||
PearlAssociatedObjectProperty(NSManagedObjectContext*, PrivateManagedObjectContext, privateManagedObjectContext);
|
||||
PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, mainManagedObjectContext);
|
||||
|
||||
|
||||
@ -50,7 +51,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
||||
|
||||
+ (BOOL)managedObjectContextForMainThreadPerformBlock:(void (^)(NSManagedObjectContext *mainContext))mocBlock {
|
||||
|
||||
NSManagedObjectContext *mainManagedObjectContext = [self managedObjectContextForMainThreadIfReady];
|
||||
NSManagedObjectContext *mainManagedObjectContext = [[self get] mainManagedObjectContextIfReady];
|
||||
if (!mainManagedObjectContext)
|
||||
return NO;
|
||||
|
||||
@ -63,7 +64,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
||||
|
||||
+ (BOOL)managedObjectContextForMainThreadPerformBlockAndWait:(void (^)(NSManagedObjectContext *mainContext))mocBlock {
|
||||
|
||||
NSManagedObjectContext *mainManagedObjectContext = [self managedObjectContextForMainThreadIfReady];
|
||||
NSManagedObjectContext *mainManagedObjectContext = [[self get] mainManagedObjectContextIfReady];
|
||||
if (!mainManagedObjectContext)
|
||||
return NO;
|
||||
|
||||
@ -318,6 +319,11 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
||||
[moc saveToStore];
|
||||
[moc reset];
|
||||
|
||||
if (self.saveObserver) {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self.saveObserver];
|
||||
self.saveObserver = nil;
|
||||
}
|
||||
|
||||
self.privateManagedObjectContext = nil;
|
||||
self.mainManagedObjectContext = nil;
|
||||
}];
|
||||
@ -334,8 +340,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
||||
} );
|
||||
|
||||
// Create our contexts.
|
||||
NSManagedObjectContext
|
||||
*privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
|
||||
NSManagedObjectContext *privateManagedObjectContext =
|
||||
[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
|
||||
[privateManagedObjectContext performBlockAndWait:^{
|
||||
privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
|
||||
privateManagedObjectContext.persistentStoreCoordinator = coordinator;
|
||||
@ -358,6 +364,16 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
||||
NSManagedObjectContext *mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
||||
mainManagedObjectContext.parentContext = privateManagedObjectContext;
|
||||
|
||||
if (self.saveObserver)
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self.saveObserver];
|
||||
self.saveObserver = [[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:NSManagedObjectContextDidSaveNotification object:privateManagedObjectContext queue:nil usingBlock:
|
||||
^(NSNotification *note) {
|
||||
[mainManagedObjectContext performBlock:^{
|
||||
[mainManagedObjectContext mergeChangesFromContextDidSaveNotification:note];
|
||||
}];
|
||||
}];
|
||||
|
||||
self.privateManagedObjectContext = privateManagedObjectContext;
|
||||
self.mainManagedObjectContext = mainManagedObjectContext;
|
||||
}
|
||||
@ -386,12 +402,12 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
||||
[MPAppDelegate_Shared managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPUserEntity *activeUser = [self activeUserInContext:context];
|
||||
NSAssert(activeUser, @"Missing user.");
|
||||
if (!activeUser)
|
||||
if (!activeUser) {
|
||||
completion( nil );
|
||||
return;
|
||||
}
|
||||
|
||||
MPElementType type = activeUser.defaultType;
|
||||
if (!type)
|
||||
type = activeUser.defaultType = MPElementTypeGeneratedLong;
|
||||
NSString *typeEntityClassName = [MPAlgorithmDefault classNameOfType:type];
|
||||
|
||||
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityClassName
|
||||
@ -408,18 +424,19 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
||||
if (element.objectID.isTemporaryID && ![context obtainPermanentIDsForObjects:@[ element ] error:&error])
|
||||
err(@"Failed to obtain a permanent object ID after creating new element: %@", error);
|
||||
|
||||
NSManagedObjectID *elementOID = [element objectID];
|
||||
dispatch_async( dispatch_get_main_queue(), ^{
|
||||
completion(
|
||||
(MPElementEntity *)[[MPAppDelegate_Shared managedObjectContextForMainThreadIfReady] objectRegisteredForID:elementOID] );
|
||||
} );
|
||||
completion( element );
|
||||
}];
|
||||
}
|
||||
|
||||
- (MPElementEntity *)changeElement:(MPElementEntity *)element inContext:(NSManagedObjectContext *)context toType:(MPElementType)type {
|
||||
- (MPElementEntity *)changeElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context toType:(MPElementType)type {
|
||||
|
||||
if ([element.algorithm classOfType:type] == element.typeClass)
|
||||
if (element.type == type)
|
||||
return element;
|
||||
|
||||
if ([element.algorithm classOfType:type] == element.typeClass) {
|
||||
element.type = type;
|
||||
[context saveToStore];
|
||||
}
|
||||
|
||||
else {
|
||||
// Type requires a different class of element. Recreate the element.
|
||||
@ -435,14 +452,13 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
||||
newElement.loginName = element.loginName;
|
||||
|
||||
[context deleteObject:element];
|
||||
// TODO: Dodgy... we're not saving consistently here.
|
||||
// Either we should save regardless and change the method signature to saveInContext: or not save at all.
|
||||
[context saveToStore];
|
||||
|
||||
NSError *error;
|
||||
if (![context obtainPermanentIDsForObjects:@[ newElement ] error:&error])
|
||||
err(@"Failed to obtain a permanent object ID after changing object type: %@", error);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPElementUpdatedNotification object:element.objectID];
|
||||
element = newElement;
|
||||
}
|
||||
|
||||
@ -728,7 +744,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
||||
[export appendFormat:@"%@ %8ld %8s %20s\t%@\n",
|
||||
[[NSDateFormatter rfc3339DateFormatter] stringFromDate:lastUsed], (long)uses,
|
||||
[PearlString( @"%lu:%lu", (long)type, (unsigned long)version ) UTF8String], [name UTF8String], content
|
||||
? content: @""];
|
||||
? content: @""];
|
||||
}
|
||||
|
||||
MPCheckpoint( MPCheckpointSitesExported, @{
|
||||
|
@ -8,13 +8,14 @@
|
||||
|
||||
#import "MPEntities.h"
|
||||
#import "MPAppDelegate_Shared.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
|
||||
@implementation NSManagedObjectContext(MP)
|
||||
|
||||
- (BOOL)saveToStore {
|
||||
|
||||
__block BOOL success = YES;
|
||||
if ([self hasChanges])
|
||||
if ([self hasChanges]) {
|
||||
[self performBlockAndWait:^{
|
||||
@try {
|
||||
NSError *error = nil;
|
||||
@ -26,6 +27,7 @@
|
||||
err(@"While saving: %@", exception);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
return success && (!self.parentContext || [self.parentContext saveToStore]);
|
||||
}
|
||||
@ -42,6 +44,14 @@
|
||||
type = [self.user defaultType];
|
||||
if (!type || type == (MPElementType)NSNotFound)
|
||||
type = MPElementTypeGeneratedLong;
|
||||
if (![self isKindOfClass:[self.algorithm classOfType:type]]) {
|
||||
// NSAssert(NO, @"This object's class does not support the type: %lu", (long)type);
|
||||
for (MPElementType aType = type; type != (aType = [self.algorithm nextType:aType]);)
|
||||
if ([self isKindOfClass:[self.algorithm classOfType:aType]]) {
|
||||
err(@"Invalid type for: %@, type: %lu. Will use %lu instead.", self.name, (long)type, (long)aType);
|
||||
return aType;
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
@ -199,7 +209,7 @@
|
||||
|
||||
- (MPElementType)defaultType {
|
||||
|
||||
return (MPElementType)[self.defaultType_ unsignedIntegerValue];
|
||||
return IfElse((MPElementType)[self.defaultType_ unsignedIntegerValue], MPElementTypeGeneratedLong);
|
||||
}
|
||||
|
||||
- (void)setDefaultType:(MPElementType)aDefaultType {
|
||||
|
@ -113,9 +113,8 @@
|
||||
// "Next type" button.
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||
element = [[MPMacAppDelegate get] changeElement:element inContext:context
|
||||
element = [[MPMacAppDelegate get] changeElement:element saveInContext:context
|
||||
toType:[element.algorithm nextType:element.type]];
|
||||
[context saveToStore];
|
||||
|
||||
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||
}];
|
||||
@ -131,9 +130,8 @@
|
||||
// "Previous type" button.
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||
element = [[MPMacAppDelegate get] changeElement:element inContext:context
|
||||
element = [[MPMacAppDelegate get] changeElement:element saveInContext:context
|
||||
toType:[element.algorithm previousType:element.type]];
|
||||
[context saveToStore];
|
||||
|
||||
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||
}];
|
||||
|
@ -182,7 +182,7 @@
|
||||
// "Create" button.
|
||||
[[MPMacAppDelegate get] addElementNamed:[self.siteField stringValue] completion:^(MPElementEntity *element) {
|
||||
if (element)
|
||||
[self updateElements];
|
||||
PearlMainQueue( ^{ [self updateElements]; } );
|
||||
}];
|
||||
break;
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ typedef NS_ENUM(NSUInteger, MPAvatarMode) {
|
||||
@property (assign, nonatomic) MPAvatarMode mode;
|
||||
@property (assign, nonatomic) CGFloat visibility;
|
||||
@property (assign, nonatomic) BOOL spinnerActive;
|
||||
@property (assign, nonatomic, readonly) BOOL newUser;
|
||||
|
||||
+ (NSString *)reuseIdentifier;
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
//
|
||||
|
||||
#import "MPAvatarCell.h"
|
||||
#import "MPPasswordLargeCell.h"
|
||||
|
||||
const long MPAvatarAdd = 10000;
|
||||
|
||||
@ -34,6 +35,7 @@ const long MPAvatarAdd = 10000;
|
||||
@end
|
||||
|
||||
@implementation MPAvatarCell {
|
||||
CAAnimationGroup *_targetedShadowAnimation;
|
||||
}
|
||||
|
||||
+ (NSString *)reuseIdentifier {
|
||||
@ -47,6 +49,8 @@ const long MPAvatarAdd = 10000;
|
||||
|
||||
[super awakeFromNib];
|
||||
|
||||
self.alpha = 0;
|
||||
|
||||
self.nameContainer.layer.cornerRadius = 5;
|
||||
|
||||
self.avatarImageView.hidden = NO;
|
||||
@ -73,15 +77,21 @@ const long MPAvatarAdd = 10000;
|
||||
pulseShadowOpacityAnimation.autoreverses = YES;
|
||||
pulseShadowOpacityAnimation.repeatCount = MAXFLOAT;
|
||||
|
||||
CAAnimationGroup *group = [CAAnimationGroup new];
|
||||
group.animations = @[ toShadowOpacityAnimation, pulseShadowOpacityAnimation ];
|
||||
group.duration = MAXFLOAT;
|
||||
[self.avatarImageView.layer addAnimation:group forKey:@"targetedShadow"];
|
||||
_targetedShadowAnimation = [CAAnimationGroup new];
|
||||
_targetedShadowAnimation.animations = @[ toShadowOpacityAnimation, pulseShadowOpacityAnimation ];
|
||||
_targetedShadowAnimation.duration = MAXFLOAT;
|
||||
self.avatarImageView.layer.shadowColor = [UIColor whiteColor].CGColor;
|
||||
self.avatarImageView.layer.shadowOffset = CGSizeZero;
|
||||
}
|
||||
|
||||
- (void)prepareForReuse {
|
||||
|
||||
[super prepareForReuse];
|
||||
|
||||
_newUser = NO;
|
||||
[self setVisibility:0 animated:NO];
|
||||
[self setMode:MPAvatarModeLowered animated:NO];
|
||||
[self setSpinnerActive:NO animated:NO];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
@ -95,8 +105,11 @@ const long MPAvatarAdd = 10000;
|
||||
|
||||
_avatar = avatar;
|
||||
|
||||
if (avatar == MPAvatarAdd)
|
||||
if (avatar == MPAvatarAdd) {
|
||||
self.avatarImageView.image = [UIImage imageNamed:@"avatar-add"];
|
||||
self.name = strl( @"New User" );
|
||||
_newUser = YES;
|
||||
}
|
||||
else
|
||||
self.avatarImageView.image = [UIImage imageNamed:strf( @"avatar-%ld", avatar )];
|
||||
}
|
||||
@ -151,6 +164,8 @@ const long MPAvatarAdd = 10000;
|
||||
|
||||
- (void)setSpinnerActive:(BOOL)spinnerActive animated:(BOOL)animated {
|
||||
|
||||
if (_spinnerActive == spinnerActive)
|
||||
return;
|
||||
_spinnerActive = spinnerActive;
|
||||
|
||||
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
|
||||
@ -180,10 +195,20 @@ const long MPAvatarAdd = 10000;
|
||||
[UIView animateWithDuration:animated? 0.2f: 0 animations:^{
|
||||
self.avatarImageView.transform = CGAffineTransformIdentity;
|
||||
}];
|
||||
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
|
||||
[UIView animateWithDuration:animated? 0.3f: 0 delay:0 options:UIViewAnimationOptionOverrideInheritedDuration animations:^{
|
||||
self.alpha = 1;
|
||||
|
||||
if (self.newUser) {
|
||||
if (self.mode == MPAvatarModeLowered)
|
||||
self.avatar = MPAvatarAdd;
|
||||
else if (self.avatar == MPAvatarAdd)
|
||||
self.avatar = arc4random() % MPAvatarCount;
|
||||
}
|
||||
|
||||
switch (self.mode) {
|
||||
|
||||
case MPAvatarModeLowered: {
|
||||
|
||||
self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height;
|
||||
self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultLow;
|
||||
self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow;
|
||||
@ -235,14 +260,20 @@ const long MPAvatarAdd = 10000;
|
||||
self.nameContainer.alpha = 0;
|
||||
self.nameContainer.backgroundColor = [UIColor blackColor];
|
||||
self.avatarImageView.alpha = 1;
|
||||
self.avatarImageView.layer.shadowOpacity = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
[self.avatarSizeConstraint apply];
|
||||
[self.avatarRaisedConstraint apply];
|
||||
[self.avatarToTopConstraint apply];
|
||||
[self.nameToCenterConstraint apply];
|
||||
|
||||
// Avatar minimized.
|
||||
if (self.mode == MPAvatarModeRaisedAndMinimized)
|
||||
[self.avatarImageView.layer removeAllAnimations];
|
||||
else if (![self.avatarImageView.layer animationForKey:@"targetedShadow"])
|
||||
[self.avatarImageView.layer addAnimation:_targetedShadowAnimation forKey:@"targetedShadow"];
|
||||
|
||||
// Avatar selection and spinner.
|
||||
if (self.mode != MPAvatarModeRaisedAndMinimized && (self.selected || self.highlighted) && !self.spinnerActive)
|
||||
self.avatarImageView.backgroundColor = self.avatarImageView.tintColor;
|
||||
@ -250,7 +281,7 @@ const long MPAvatarAdd = 10000;
|
||||
self.avatarImageView.backgroundColor = [UIColor clearColor];
|
||||
self.avatarImageView.layer.cornerRadius = self.avatarImageView.bounds.size.height / 2;
|
||||
self.spinner.alpha = self.spinnerActive? 1: 0;
|
||||
}];
|
||||
} completion:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -9,17 +9,15 @@
|
||||
*/
|
||||
|
||||
//
|
||||
// PearlUIView.h
|
||||
// PearlUIView
|
||||
// MPCell.h
|
||||
// MPCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-17.
|
||||
// Created by lhunath on 2014-03-27.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface PearlUIView : UIView
|
||||
|
||||
@property(assign, nonatomic) BOOL ignoreTouches;
|
||||
@interface MPCell : UICollectionViewCell
|
||||
|
||||
@end
|
@ -9,18 +9,16 @@
|
||||
*/
|
||||
|
||||
//
|
||||
// PearlUINavigationBar.h
|
||||
// PearlUINavigationBar
|
||||
// MPCell.h
|
||||
// MPCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-17.
|
||||
// Created by lhunath on 2014-03-27.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPCell.h"
|
||||
|
||||
@interface PearlUINavigationBar : UINavigationBar
|
||||
|
||||
@property (assign, nonatomic) BOOL ignoreTouches;
|
||||
@property (assign, nonatomic) BOOL invisible;
|
||||
@implementation MPCell {
|
||||
}
|
||||
|
||||
@end
|
@ -89,19 +89,18 @@
|
||||
|
||||
[self becomeFirstResponder];
|
||||
|
||||
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
|
||||
switch (self.mode) {
|
||||
case MPCombinedModeUserSelection: {
|
||||
[self.usersVC setActive:YES animated:NO];
|
||||
[self.passwordsVC setActive:NO animated:NO];
|
||||
[self.usersVC setActive:YES animated:animated];
|
||||
[self.passwordsVC setActive:NO animated:animated];
|
||||
// MPUsersViewController *usersVC = [self.storyboard instantiateViewControllerWithIdentifier:@"MPUsersViewController"];
|
||||
// [self setViewControllers:@[ usersVC ] direction:UIPageViewControllerNavigationDirectionReverse
|
||||
// animated:animated completion:nil];
|
||||
break;
|
||||
}
|
||||
case MPCombinedModePasswordSelection: {
|
||||
[self.usersVC setActive:NO animated:NO];
|
||||
[self.passwordsVC setActive:YES animated:NO];
|
||||
[self.usersVC setActive:NO animated:animated];
|
||||
[self.passwordsVC setActive:YES animated:animated];
|
||||
// MPPasswordsViewController *passwordsVC = [self.storyboard instantiateViewControllerWithIdentifier:@"MPPasswordsViewController"];
|
||||
// [self setViewControllers:@[ passwordsVC ] direction:UIPageViewControllerNavigationDirectionForward
|
||||
// animated:animated completion:nil];
|
||||
@ -110,7 +109,6 @@
|
||||
}
|
||||
|
||||
[self.passwordsTopConstraint apply];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
@ -66,10 +66,11 @@
|
||||
|
||||
__weak MPElementListAllViewController *wSelf = self;
|
||||
[[MPiOSAppDelegate get] addElementNamed:[alert textFieldAtIndex:0].text completion:^(MPElementEntity *element) {
|
||||
if (element) {
|
||||
[wSelf.delegate didSelectElement:element];
|
||||
[wSelf close:nil];
|
||||
}
|
||||
if (element)
|
||||
PearlMainQueue( ^{
|
||||
[wSelf.delegate didSelectElement:element];
|
||||
[wSelf close:nil];
|
||||
} );
|
||||
}];
|
||||
}
|
||||
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonOkay, nil];
|
||||
@ -85,7 +86,7 @@
|
||||
if (buttonIndex == [alert cancelButtonIndex])
|
||||
return;
|
||||
|
||||
PearlOverlay *activity = [PearlOverlay showOverlayWithTitle:@"Upgrading Sites"];
|
||||
PearlOverlay *activity = [PearlOverlay showProgressOverlayWithTitle:@"Upgrading Sites"];
|
||||
[self performUpgradeAllWithCompletion:^(BOOL success, NSDictionary *changes) {
|
||||
dispatch_async( dispatch_get_main_queue(), ^{
|
||||
[self showUpgradeChanges:changes];
|
||||
|
@ -193,7 +193,7 @@
|
||||
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
cell.textLabel.text = query;
|
||||
cell.detailTextLabel.text = PearlString( @"New site: %@",
|
||||
[MPAlgorithmDefault shortNameOfType:[[[MPiOSAppDelegate get] activeUserForMainThread] defaultType]] );
|
||||
[MPAlgorithmDefault shortNameOfType:[[MPiOSAppDelegate get] activeUserForMainThread].defaultType] );
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
@ -220,7 +220,9 @@
|
||||
__weak MPElementListController *wSelf = self;
|
||||
[[MPiOSAppDelegate get] addElementNamed:siteName completion:^(MPElementEntity *element) {
|
||||
if (element)
|
||||
[wSelf.delegate didSelectElement:element];
|
||||
PearlMainQueue( ^{
|
||||
[wSelf.delegate didSelectElement:element];
|
||||
} );
|
||||
}];
|
||||
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil];
|
||||
}
|
||||
|
@ -62,7 +62,7 @@
|
||||
if (buttonIndex_ == alert.cancelButtonIndex)
|
||||
return;
|
||||
|
||||
_switchCloudStoreProgress = [PearlOverlay showOverlayWithTitle:@"Enumerating Stores"];
|
||||
_switchCloudStoreProgress = [PearlOverlay showProgressOverlayWithTitle:@"Enumerating Stores"];
|
||||
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{
|
||||
[self switchCloudStore];
|
||||
} );
|
||||
|
@ -776,7 +776,7 @@
|
||||
@"If you continue, the password for this site will change. "
|
||||
@"You will need to update your account's old password to the new one."
|
||||
do:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) {
|
||||
_activeElementOID = [[MPiOSAppDelegate get] changeElement:activeElement inContext:context
|
||||
_activeElementOID = [[MPiOSAppDelegate get] changeElement:activeElement saveInContext:context
|
||||
toType:type].objectID;
|
||||
return YES;
|
||||
}];
|
||||
|
@ -18,19 +18,17 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPEntities.h"
|
||||
#import "MPCell.h"
|
||||
|
||||
@interface MPPasswordCell : UICollectionViewCell <UITextFieldDelegate>
|
||||
@interface MPPasswordCell : MPCell
|
||||
|
||||
@property(nonatomic, copy) NSString *transientSite;
|
||||
@property(strong, nonatomic) IBOutlet UITextField *contentField;
|
||||
|
||||
+ (NSString *)reuseIdentifier;
|
||||
|
||||
- (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context;
|
||||
+ (NSString *)reuseIdentifierForElement:(MPElementEntity *)entity;
|
||||
- (void)setElement:(MPElementEntity *)element;
|
||||
@property(strong, nonatomic) IBOutlet UILabel *nameLabel;
|
||||
@property(strong, nonatomic) IBOutlet UIButton *loginButton;
|
||||
|
||||
/** Populate our UI to reflect the current state. */
|
||||
- (void)updateAnimated:(BOOL)animated;
|
||||
- (void)populateWithElement:(MPElementEntity *)element;
|
||||
|
||||
- (void)reloadWithElement:(MPElementEntity *)mainElement;
|
||||
- (void)reloadWithTransientSite:(NSString *)siteName;
|
||||
|
||||
@end
|
||||
|
@ -19,47 +19,9 @@
|
||||
#import "MPPasswordCell.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "MPPasswordGeneratedCell.h"
|
||||
#import "MPPasswordStoredCell.h"
|
||||
|
||||
@interface MPPasswordCell()
|
||||
|
||||
@property(strong, nonatomic) IBOutlet UILabel *nameLabel;
|
||||
@property(strong, nonatomic) IBOutlet UIButton *loginButton;
|
||||
|
||||
@property(nonatomic, strong) NSManagedObjectID *elementOID;
|
||||
@end
|
||||
|
||||
@implementation MPPasswordCell
|
||||
|
||||
+ (NSString *)reuseIdentifier {
|
||||
|
||||
return NSStringFromClass( self );
|
||||
}
|
||||
|
||||
+ (NSString *)reuseIdentifierForElement:(MPElementEntity *)element {
|
||||
|
||||
if ([element isKindOfClass:[MPElementGeneratedEntity class]])
|
||||
return [MPPasswordGeneratedCell reuseIdentifier];
|
||||
|
||||
if ([element isKindOfClass:[MPElementStoredEntity class]])
|
||||
return [MPPasswordStoredCell reuseIdentifier];
|
||||
|
||||
return [self reuseIdentifier];
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
|
||||
if (textField == self.contentField && [self.contentField.text length]) {
|
||||
[self.contentField resignFirstResponder];
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - Life cycle
|
||||
|
||||
- (void)awakeFromNib {
|
||||
@ -67,120 +29,68 @@
|
||||
[super awakeFromNib];
|
||||
|
||||
self.layer.cornerRadius = 5;
|
||||
self.layer.shadowOffset = CGSizeZero;
|
||||
self.layer.shadowRadius = 5;
|
||||
self.layer.shadowOpacity = 0;
|
||||
self.layer.shadowColor = [UIColor whiteColor].CGColor;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
- (void)prepareForReuse {
|
||||
|
||||
[self removeKeyPathObservers];
|
||||
[super prepareForReuse];
|
||||
[self updateAnimated:NO];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
// Unblocks animations for all CALayer properties (eg. shadowOpacity)
|
||||
- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event {
|
||||
|
||||
- (IBAction)doUser:(id)sender {
|
||||
id<CAAction> defaultAction = [super actionForLayer:layer forKey:event];
|
||||
if (defaultAction == (id)[NSNull null] && [event isEqualToString:@"position"])
|
||||
return defaultAction;
|
||||
|
||||
return NSNullToNil(defaultAction);
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setTransientSite:(NSString *)name {
|
||||
- (void)setSelected:(BOOL)selected {
|
||||
|
||||
_transientSite = name;
|
||||
_elementOID = nil;
|
||||
[super setSelected:selected];
|
||||
|
||||
[self updateAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)setElement:(MPElementEntity *)element {
|
||||
- (void)setHighlighted:(BOOL)highlighted {
|
||||
|
||||
self.elementOID = [element objectID];
|
||||
}
|
||||
|
||||
- (void)setElementOID:(NSManagedObjectID *)elementOID {
|
||||
|
||||
_transientSite = nil;
|
||||
_elementOID = elementOID;
|
||||
[super setHighlighted:highlighted];
|
||||
|
||||
[self updateAnimated:YES];
|
||||
}
|
||||
|
||||
- (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
NSError *error = nil;
|
||||
MPElementEntity *element = _elementOID? (MPElementEntity *)[context existingObjectWithID:_elementOID error:&error]: nil;
|
||||
if (_elementOID && !element)
|
||||
err(@"Failed to load element: %@", error);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)updateAnimated:(BOOL)animated {
|
||||
|
||||
Weakify(self);
|
||||
|
||||
if (self.transientSite) {
|
||||
self.alpha = 1;
|
||||
self.nameLabel.text = self.transientSite;
|
||||
self.contentField.text = nil;
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPKey *key = [MPiOSAppDelegate get].key;
|
||||
if (!key) {
|
||||
self.alpha = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
MPElementType type = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType;
|
||||
if (!type)
|
||||
type = MPElementTypeGeneratedLong;
|
||||
NSString *newContent = [MPAlgorithmDefault generateContentNamed:self.transientSite ofType:type withCounter:1 usingKey:key];
|
||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||
self.contentField.text = newContent;
|
||||
}];
|
||||
if (![NSThread isMainThread]) {
|
||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||
[self updateAnimated:animated];
|
||||
}];
|
||||
return;
|
||||
}
|
||||
else if (self.elementOID) {
|
||||
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
|
||||
[mainContext performBlock:^{
|
||||
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
|
||||
Strongify(self);
|
||||
NSError *error = nil;
|
||||
MPKey *key = [MPiOSAppDelegate get].key;
|
||||
if (!key) {
|
||||
self.alpha = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
MPElementEntity *element = (MPElementEntity *)[mainContext existingObjectWithID:_elementOID error:&error];
|
||||
if (!element) {
|
||||
err(@"Failed to load element: %@", error);
|
||||
self.alpha = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
self.alpha = 1;
|
||||
[self populateWithElement:element];
|
||||
|
||||
[element resolveContentUsingKey:key result:^(NSString *result) {
|
||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||
Strongify(self);
|
||||
self.contentField.text = result;
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
else {
|
||||
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
|
||||
self.alpha = 0;
|
||||
}];
|
||||
}
|
||||
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
|
||||
self.layer.shadowOpacity = self.selected? 1: self.highlighted? 0.3f: 0;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)populateWithElement:(MPElementEntity *)element {
|
||||
- (void)reloadWithElement:(MPElementEntity *)mainElement {
|
||||
|
||||
self.nameLabel.text = element.name;
|
||||
self.contentField.text = nil;
|
||||
self.nameLabel.text = mainElement.name;
|
||||
}
|
||||
|
||||
- (void)reloadWithTransientSite:(NSString *)siteName {
|
||||
|
||||
self.nameLabel.text = strl( @"%@ - Tap to create", siteName );
|
||||
}
|
||||
|
||||
@end
|
||||
|
31
MasterPassword/ObjC/iOS/MPPasswordElementCell.h
Normal file
31
MasterPassword/ObjC/iOS/MPPasswordElementCell.h
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordElementCell.h
|
||||
// MPPasswordElementCell
|
||||
//
|
||||
// Created by lhunath on 2014-04-03.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPPasswordCell.h"
|
||||
|
||||
@interface MPPasswordElementCell : MPPasswordCell
|
||||
|
||||
@property(nonatomic, copy) NSString *transientSite;
|
||||
|
||||
- (MPElementEntity *)mainElement;
|
||||
- (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context;
|
||||
- (void)setElement:(MPElementEntity *)element;
|
||||
- (void)reloadData;
|
||||
|
||||
@end
|
93
MasterPassword/ObjC/iOS/MPPasswordElementCell.m
Normal file
93
MasterPassword/ObjC/iOS/MPPasswordElementCell.m
Normal file
@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordElementCell.h
|
||||
// MPPasswordElementCell
|
||||
//
|
||||
// Created by lhunath on 2014-04-03.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPPasswordElementCell.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
|
||||
@implementation MPPasswordElementCell {
|
||||
NSManagedObjectID *_elementOID;
|
||||
}
|
||||
|
||||
- (void)prepareForReuse {
|
||||
|
||||
_elementOID = nil;
|
||||
_transientSite = nil;
|
||||
|
||||
[super prepareForReuse];
|
||||
}
|
||||
|
||||
- (void)setTransientSite:(NSString *)transientSite {
|
||||
|
||||
if ([_transientSite isEqualToString:transientSite])
|
||||
return;
|
||||
|
||||
dbg(@"transientSite: %@ -> %@", _transientSite, transientSite);
|
||||
|
||||
_transientSite = transientSite;
|
||||
_elementOID = nil;
|
||||
|
||||
[self updateAnimated:YES];
|
||||
[self reloadData];
|
||||
}
|
||||
|
||||
- (void)setElement:(MPElementEntity *)element {
|
||||
|
||||
if ([_elementOID isEqual:element.objectID])
|
||||
return;
|
||||
|
||||
dbg(@"element: %@ -> %@", _elementOID, element.objectID);
|
||||
|
||||
_transientSite = nil;
|
||||
_elementOID = element.objectID;
|
||||
|
||||
[self updateAnimated:YES];
|
||||
[self reloadData];
|
||||
}
|
||||
|
||||
- (MPElementEntity *)mainElement {
|
||||
|
||||
return [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||
}
|
||||
|
||||
- (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
if (!_elementOID)
|
||||
return nil;
|
||||
|
||||
NSError *error = nil;
|
||||
MPElementEntity *element = _elementOID? (MPElementEntity *)[context existingObjectWithID:_elementOID error:&error]: nil;
|
||||
if (_elementOID && !element)
|
||||
err(@"Failed to load element: %@", error);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)reloadData {
|
||||
|
||||
if (self.transientSite)
|
||||
PearlMainQueue( ^{
|
||||
[self reloadWithTransientSite:self.transientSite];
|
||||
} );
|
||||
else
|
||||
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
|
||||
[self reloadWithElement:[self elementInContext:mainContext]];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
@ -1,87 +0,0 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordGeneratedCell.h
|
||||
// MPPasswordGeneratedCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-19.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPPasswordGeneratedCell.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
|
||||
@interface MPPasswordGeneratedCell()
|
||||
|
||||
@property(strong, nonatomic) IBOutlet UILabel *counterLabel;
|
||||
@property(strong, nonatomic) IBOutlet UIButton *counterButton;
|
||||
@property(strong, nonatomic) IBOutlet UIButton *upgradeButton;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPPasswordGeneratedCell
|
||||
|
||||
- (void)populateWithElement:(MPElementEntity *)element {
|
||||
|
||||
[super populateWithElement:element];
|
||||
|
||||
MPElementGeneratedEntity *generatedElement = [self generatedElement:element];
|
||||
self.counterLabel.text = strf(@"%lu", (unsigned long)generatedElement.counter);
|
||||
|
||||
if (element.requiresExplicitMigration) {
|
||||
self.upgradeButton.alpha = 1;
|
||||
self.counterButton.alpha = 0;
|
||||
} else {
|
||||
self.upgradeButton.alpha = 0;
|
||||
self.counterButton.alpha = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)doUpgrade:(UIButton *)sender {
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlock:^(NSManagedObjectContext *mainContext) {
|
||||
[[self elementInContext:mainContext] migrateExplicitly:YES];
|
||||
[mainContext saveToStore];
|
||||
|
||||
[self updateAnimated:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
- (IBAction)doIncrementCounter:(UIButton *)sender {
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlock:^(NSManagedObjectContext *mainContext) {
|
||||
++[self elementInContext:mainContext].counter;
|
||||
[mainContext saveToStore];
|
||||
|
||||
[self updateAnimated:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (MPElementGeneratedEntity *)elementInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
return [self generatedElement:[super elementInContext:context]];
|
||||
}
|
||||
|
||||
- (MPElementGeneratedEntity *)generatedElement:(MPElementEntity *)element {
|
||||
|
||||
NSAssert([element isKindOfClass:[MPElementGeneratedEntity class]], @"Element is not of generated type: %@", element.name);
|
||||
if (![element isKindOfClass:[MPElementGeneratedEntity class]])
|
||||
return nil;
|
||||
|
||||
return (MPElementGeneratedEntity *)element;
|
||||
}
|
||||
|
||||
@end
|
44
MasterPassword/ObjC/iOS/MPPasswordLargeCell.h
Normal file
44
MasterPassword/ObjC/iOS/MPPasswordLargeCell.h
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPAvatarCell.h
|
||||
// MPAvatarCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-11.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPEntities.h"
|
||||
#import "MPCell.h"
|
||||
#import "MPPasswordCell.h"
|
||||
|
||||
typedef NS_ENUM (NSUInteger, MPContentFieldMode) {
|
||||
MPContentFieldModePassword,
|
||||
MPContentFieldModeUser,
|
||||
};
|
||||
|
||||
@interface MPPasswordLargeCell : MPPasswordCell <UITextFieldDelegate>
|
||||
|
||||
@property(nonatomic) MPElementType type;
|
||||
@property(nonatomic) MPContentFieldMode contentFieldMode;
|
||||
@property(nonatomic, strong) IBOutlet UILabel *typeLabel;
|
||||
@property(nonatomic, strong) IBOutlet UITextField *contentField;
|
||||
@property(nonatomic, strong) IBOutlet UIButton *upgradeButton;
|
||||
|
||||
+ (instancetype)dequeueCellWithType:(MPElementType)type fromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock;
|
||||
- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock;
|
||||
|
||||
- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context;
|
||||
|
||||
@end
|
213
MasterPassword/ObjC/iOS/MPPasswordLargeCell.m
Normal file
213
MasterPassword/ObjC/iOS/MPPasswordLargeCell.m
Normal file
@ -0,0 +1,213 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPAvatarCell.h
|
||||
// MPAvatarCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-11.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPPasswordLargeCell.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "MPPasswordLargeGeneratedCell.h"
|
||||
#import "MPPasswordLargeStoredCell.h"
|
||||
#import "MPPasswordTypesCell.h"
|
||||
|
||||
@implementation MPPasswordLargeCell
|
||||
|
||||
+ (instancetype)dequeueCellWithType:(MPElementType)type fromCollectionView:(UICollectionView *)collectionView
|
||||
atIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
NSString *reuseIdentifier;
|
||||
if (type & MPElementTypeClassGenerated)
|
||||
reuseIdentifier = NSStringFromClass( [MPPasswordLargeGeneratedCell class] );
|
||||
else if (type & MPElementTypeClassStored)
|
||||
reuseIdentifier = NSStringFromClass( [MPPasswordLargeStoredCell class] );
|
||||
else
|
||||
Throw(@"Unexpected password type: %@", [MPAlgorithmDefault nameOfType:type]);
|
||||
|
||||
MPPasswordLargeCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
|
||||
cell.type = type;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
|
||||
[textField resignFirstResponder];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)textFieldDidEndEditing:(UITextField *)textField {
|
||||
|
||||
if (textField == self.contentField) {
|
||||
NSString *newContent = textField.text;
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPElementEntity *element = [[MPPasswordElementCell findAsSuperviewOf:self] elementInContext:context];
|
||||
|
||||
switch (self.contentFieldMode) {
|
||||
case MPContentFieldModePassword:
|
||||
break;
|
||||
case MPContentFieldModeUser: {
|
||||
element.loginName = newContent;
|
||||
[context saveToStore];
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[self updateAnimated:YES];
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Login Updated" dismissAfter:2];
|
||||
} );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Life cycle
|
||||
|
||||
- (void)prepareForReuse {
|
||||
|
||||
_contentFieldMode = 0;
|
||||
|
||||
[super prepareForReuse];
|
||||
}
|
||||
|
||||
- (void)reloadWithTransientSite:(NSString *)siteName {
|
||||
|
||||
[super reloadWithTransientSite:siteName];
|
||||
|
||||
self.loginButton.alpha = 0;
|
||||
self.upgradeButton.alpha = 0;
|
||||
self.contentField.enabled = NO;
|
||||
self.contentField.placeholder = strl( @"Tap to enter password" );
|
||||
self.typeLabel.text = [MPAlgorithmDefault nameOfType:self.type];
|
||||
|
||||
[self resolveContentOfCellTypeForTransientSite:siteName usingKey:[MPiOSAppDelegate get].key result:^(NSString *string) {
|
||||
PearlMainQueue( ^{ self.contentField.text = string; } );
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)reloadWithElement:(MPElementEntity *)mainElement {
|
||||
|
||||
[super reloadWithElement:mainElement];
|
||||
|
||||
self.loginButton.alpha = 1;
|
||||
self.typeLabel.text = [mainElement.algorithm nameOfType:self.type];
|
||||
|
||||
if (mainElement.requiresExplicitMigration)
|
||||
self.upgradeButton.alpha = 1;
|
||||
else
|
||||
self.upgradeButton.alpha = 0;
|
||||
|
||||
switch (self.contentFieldMode) {
|
||||
case MPContentFieldModePassword: {
|
||||
if (self.type & MPElementTypeClassStored) {
|
||||
self.contentField.enabled = YES;
|
||||
self.contentField.placeholder = strl( @"Enter custom password" );
|
||||
}
|
||||
else if (self.type & MPElementTypeClassGenerated) {
|
||||
self.contentField.enabled = NO;
|
||||
self.contentField.placeholder = strl( @"Generating..." );
|
||||
}
|
||||
else {
|
||||
self.contentField.enabled = NO;
|
||||
self.contentField.placeholder = nil;
|
||||
}
|
||||
self.contentField.text = nil;
|
||||
|
||||
MPKey *key = [MPiOSAppDelegate get].key;
|
||||
|
||||
if (self.type == mainElement.type)
|
||||
[mainElement resolveContentUsingKey:key result:^(NSString *string) {
|
||||
PearlMainQueue( ^{ self.contentField.text = string; } );
|
||||
}];
|
||||
else
|
||||
[self resolveContentOfCellTypeForElement:mainElement usingKey:key result:^(NSString *string) {
|
||||
PearlMainQueue( ^{ self.contentField.text = string; } );
|
||||
}];
|
||||
break;
|
||||
}
|
||||
case MPContentFieldModeUser: {
|
||||
self.contentField.enabled = YES;
|
||||
self.contentField.placeholder = strl( @"Enter login name" );
|
||||
self.contentField.text = mainElement.loginName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
|
||||
|
||||
resultBlock( nil );
|
||||
}
|
||||
|
||||
- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
|
||||
|
||||
resultBlock( nil );
|
||||
}
|
||||
|
||||
- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
return [[MPiOSAppDelegate get] changeElement:element saveInContext:context toType:self.type];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)doUser:(id)sender {
|
||||
|
||||
switch (self.contentFieldMode) {
|
||||
case MPContentFieldModePassword: {
|
||||
self.contentFieldMode = MPContentFieldModeUser;
|
||||
break;
|
||||
}
|
||||
case MPContentFieldModeUser: {
|
||||
self.contentFieldMode = MPContentFieldModePassword;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)doUpgrade:(UIButton *)sender {
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
if ([[[MPPasswordElementCell findAsSuperviewOf:self] elementInContext:context] migrateExplicitly:YES]) {
|
||||
[context saveToStore];
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[[MPPasswordElementCell findAsSuperviewOf:self] reloadData];
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Site Upgraded" dismissAfter:2];
|
||||
} );
|
||||
}
|
||||
else
|
||||
PearlMainQueue( ^{
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Site Not Upgraded" dismissAfter:2];
|
||||
} );
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setContentFieldMode:(MPContentFieldMode)contentFieldMode {
|
||||
|
||||
if (_contentFieldMode == contentFieldMode)
|
||||
return;
|
||||
|
||||
_contentFieldMode = contentFieldMode;
|
||||
|
||||
[[MPPasswordElementCell findAsSuperviewOf:self] reloadData];
|
||||
}
|
||||
|
||||
@end
|
@ -9,18 +9,19 @@
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordGeneratedCell.h
|
||||
// MPPasswordGeneratedCell
|
||||
// MPPasswordLargeGeneratedCell.h
|
||||
// MPPasswordLargeGeneratedCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-19.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPPasswordCell.h"
|
||||
#import "MPPasswordLargeCell.h"
|
||||
|
||||
@interface MPPasswordGeneratedCell : MPPasswordCell
|
||||
@interface MPPasswordLargeGeneratedCell : MPPasswordLargeCell
|
||||
|
||||
- (MPElementGeneratedEntity *)elementInContext:(NSManagedObjectContext *)context;
|
||||
@property(strong, nonatomic) IBOutlet UILabel *counterLabel;
|
||||
@property(strong, nonatomic) IBOutlet UIButton *counterButton;
|
||||
|
||||
@end
|
139
MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.m
Normal file
139
MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.m
Normal file
@ -0,0 +1,139 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordLargeGeneratedCell.h
|
||||
// MPPasswordLargeGeneratedCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-19.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPPasswordLargeGeneratedCell.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "MPPasswordElementCell.h"
|
||||
|
||||
@implementation MPPasswordLargeGeneratedCell
|
||||
|
||||
- (void)awakeFromNib {
|
||||
|
||||
[super awakeFromNib];
|
||||
|
||||
UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc]
|
||||
initWithTarget:self action:@selector(doResetCounterRecognizer:)];
|
||||
[self.counterButton addGestureRecognizer:gestureRecognizer];
|
||||
}
|
||||
|
||||
- (void)reloadWithElement:(MPElementEntity *)mainElement {
|
||||
|
||||
[super reloadWithElement:mainElement];
|
||||
|
||||
MPElementGeneratedEntity *generatedElement = [self generatedElement:mainElement];
|
||||
if (generatedElement)
|
||||
self.counterLabel.text = strf( @"%lu", (unsigned long)generatedElement.counter );
|
||||
else
|
||||
self.counterLabel.text = @"1";
|
||||
|
||||
if (!mainElement || mainElement.requiresExplicitMigration) {
|
||||
self.counterLabel.alpha = 0;
|
||||
self.counterButton.alpha = 0;
|
||||
}
|
||||
else {
|
||||
self.counterLabel.alpha = 1;
|
||||
self.counterButton.alpha = 1;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
|
||||
|
||||
PearlNotMainQueue( ^{
|
||||
resultBlock( [MPAlgorithmDefault generateContentNamed:siteName ofType:self.type withCounter:1 usingKey:key] );
|
||||
} );
|
||||
}
|
||||
|
||||
- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
|
||||
|
||||
id<MPAlgorithm> algorithm = element.algorithm;
|
||||
NSString *siteName = element.name;
|
||||
|
||||
PearlNotMainQueue( ^{
|
||||
resultBlock( [algorithm generateContentNamed:siteName ofType:self.type withCounter:1 usingKey:key] );
|
||||
} );
|
||||
}
|
||||
|
||||
- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
element = [super saveContentTypeWithElement:element saveInContext:context];
|
||||
|
||||
MPElementGeneratedEntity *generatedElement = [self generatedElement:element];
|
||||
if (generatedElement) {
|
||||
generatedElement.counter = [self.counterLabel.text intValue];
|
||||
[context saveToStore];
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)doIncrementCounter:(UIButton *)sender {
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPElementGeneratedEntity *generatedElement = [self generatedElementInContext:context];
|
||||
if (!generatedElement)
|
||||
return;
|
||||
|
||||
++generatedElement.counter;
|
||||
[context saveToStore];
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[self updateAnimated:YES];
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Counter Incremented" dismissAfter:2];
|
||||
} );
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)doResetCounterRecognizer:(UILongPressGestureRecognizer *)gestureRecognizer {
|
||||
|
||||
if (gestureRecognizer.state != UIGestureRecognizerStateEnded)
|
||||
return;
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPElementGeneratedEntity *generatedElement = [self generatedElementInContext:context];
|
||||
if (!generatedElement)
|
||||
return;
|
||||
|
||||
generatedElement.counter = 1;
|
||||
[context saveToStore];
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[self updateAnimated:YES];
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Counter Reset" dismissAfter:2];
|
||||
} );
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (MPElementGeneratedEntity *)generatedElementInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
return [self generatedElement:[[MPPasswordElementCell findAsSuperviewOf:self] elementInContext:context]];
|
||||
}
|
||||
|
||||
- (MPElementGeneratedEntity *)generatedElement:(MPElementEntity *)element {
|
||||
|
||||
if (![element isKindOfClass:[MPElementGeneratedEntity class]])
|
||||
return nil;
|
||||
|
||||
return (MPElementGeneratedEntity *)element;
|
||||
}
|
||||
|
||||
@end
|
@ -9,18 +9,16 @@
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordStoredCell.h
|
||||
// MPPasswordStoredCell
|
||||
// MPPasswordLargeStoredCell.h
|
||||
// MPPasswordLargeStoredCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-19.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPPasswordCell.h"
|
||||
#import "MPPasswordLargeCell.h"
|
||||
|
||||
@interface MPPasswordStoredCell : MPPasswordCell
|
||||
|
||||
- (MPElementStoredEntity *)elementInContext:(NSManagedObjectContext *)context;
|
||||
@interface MPPasswordLargeStoredCell : MPPasswordLargeCell
|
||||
|
||||
@end
|
112
MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.m
Normal file
112
MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.m
Normal file
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordLargeGeneratedCell.h
|
||||
// MPPasswordLargeGeneratedCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-19.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPPasswordLargeStoredCell.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "MPPasswordElementCell.h"
|
||||
|
||||
@interface MPPasswordLargeStoredCell()
|
||||
|
||||
@property(strong, nonatomic) IBOutlet UIButton *editButton;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPPasswordLargeStoredCell
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
|
||||
|
||||
if (element.type & MPElementTypeClassStored)
|
||||
[element resolveContentUsingKey:key result:resultBlock];
|
||||
else
|
||||
[super resolveContentOfCellTypeForElement:element usingKey:key result:resultBlock];
|
||||
}
|
||||
|
||||
- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
element = [super saveContentTypeWithElement:element saveInContext:context];
|
||||
|
||||
MPElementStoredEntity *storedElement = [self storedElement:element];
|
||||
if (storedElement) {
|
||||
storedElement.contentObject = self.contentField.text;
|
||||
[context saveToStore];
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)doEditContent:(UIButton *)sender {
|
||||
|
||||
UITextField *field = self.contentField;
|
||||
field.enabled = YES;
|
||||
[field becomeFirstResponder];
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
- (void)textFieldDidEndEditing:(UITextField *)textField {
|
||||
|
||||
[super textFieldDidEndEditing:textField];
|
||||
|
||||
if (textField == self.contentField) {
|
||||
NSString *newContent = textField.text;
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPElementStoredEntity *storedElement = [self storedElementInContext:context];
|
||||
if (!storedElement)
|
||||
return;
|
||||
|
||||
switch (self.contentFieldMode) {
|
||||
case MPContentFieldModePassword: {
|
||||
storedElement.contentObject = newContent;
|
||||
[context saveToStore];
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[self updateAnimated:YES];
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2];
|
||||
} );
|
||||
break;
|
||||
}
|
||||
case MPContentFieldModeUser:
|
||||
break;
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (MPElementStoredEntity *)storedElementInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
return [self storedElement:[[MPPasswordElementCell findAsSuperviewOf:self] elementInContext:context]];
|
||||
}
|
||||
|
||||
- (MPElementStoredEntity *)storedElement:(MPElementEntity *)element {
|
||||
|
||||
if (![element isKindOfClass:[MPElementStoredEntity class]])
|
||||
return nil;
|
||||
|
||||
return (MPElementStoredEntity *)element;
|
||||
}
|
||||
|
||||
@end
|
33
MasterPassword/ObjC/iOS/MPPasswordSmallCell.h
Normal file
33
MasterPassword/ObjC/iOS/MPPasswordSmallCell.h
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordSmallCell.h
|
||||
// MPPasswordSmallCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-28.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPPasswordCell.h"
|
||||
|
||||
@interface MPPasswordSmallCell : MPPasswordElementCell
|
||||
|
||||
+ (instancetype)dequeueCellForElement:(MPElementEntity *)element
|
||||
fromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
@end
|
||||
|
||||
@interface MPPasswordSmallGeneratedCell : MPPasswordSmallCell
|
||||
@end
|
||||
|
||||
@interface MPPasswordSmallStoredCell : MPPasswordSmallCell
|
||||
@end
|
48
MasterPassword/ObjC/iOS/MPPasswordSmallCell.m
Normal file
48
MasterPassword/ObjC/iOS/MPPasswordSmallCell.m
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordSmallCell.h
|
||||
// MPPasswordSmallCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-28.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPPasswordElementCell.h"
|
||||
#import "MPPasswordSmallCell.h"
|
||||
|
||||
@implementation MPPasswordSmallCell {
|
||||
}
|
||||
|
||||
+ (instancetype)dequeueCellForElement:(MPElementEntity *)element fromCollectionView:(UICollectionView *)collectionView
|
||||
atIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
NSString *reuseIdentifier;
|
||||
if (element.type & MPElementTypeClassGenerated)
|
||||
reuseIdentifier = NSStringFromClass( [MPPasswordSmallGeneratedCell class] );
|
||||
else if (element.type & MPElementTypeClassStored)
|
||||
reuseIdentifier = NSStringFromClass( [MPPasswordSmallStoredCell class] );
|
||||
else
|
||||
Throw(@"Unexpected password type: %@", [MPAlgorithmDefault nameOfType:element.type]);
|
||||
|
||||
MPPasswordSmallCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
|
||||
[cell setElement:element];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPPasswordSmallGeneratedCell
|
||||
@end
|
||||
|
||||
@implementation MPPasswordSmallStoredCell
|
||||
@end
|
@ -1,73 +0,0 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordGeneratedCell.h
|
||||
// MPPasswordGeneratedCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-19.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPPasswordStoredCell.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
|
||||
@interface MPPasswordStoredCell()
|
||||
|
||||
@property(strong, nonatomic) IBOutlet UIButton *editButton;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPPasswordStoredCell
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)doEditContent:(UIButton *)sender {
|
||||
|
||||
self.contentField.enabled = YES;
|
||||
[self.contentField becomeFirstResponder];
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
- (void)textFieldDidEndEditing:(UITextField *)textField {
|
||||
|
||||
[super textFieldDidEndEditing:textField];
|
||||
|
||||
if (textField == self.contentField) {
|
||||
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlock:^(NSManagedObjectContext *mainContext) {
|
||||
if (mainContext) {
|
||||
[[self elementInContext:mainContext] setContentObject:self.contentField.text];
|
||||
[mainContext saveToStore];
|
||||
}
|
||||
|
||||
[self updateAnimated:YES];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (MPElementStoredEntity *)elementInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
return [self storedElement:[super elementInContext:context]];
|
||||
}
|
||||
|
||||
- (MPElementStoredEntity *)storedElement:(MPElementEntity *)element {
|
||||
|
||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]], @"Element is not of generated type: %@", element.name);
|
||||
if (![element isKindOfClass:[MPElementStoredEntity class]])
|
||||
return nil;
|
||||
|
||||
return (MPElementStoredEntity *)element;
|
||||
}
|
||||
|
||||
@end
|
34
MasterPassword/ObjC/iOS/MPPasswordTypesCell.h
Normal file
34
MasterPassword/ObjC/iOS/MPPasswordTypesCell.h
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordTypesCell.h
|
||||
// MPPasswordTypesCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-27.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPCell.h"
|
||||
#import "MPPasswordCell.h"
|
||||
#import "MPPasswordElementCell.h"
|
||||
|
||||
@interface MPPasswordTypesCell : MPPasswordElementCell <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||
|
||||
@property(nonatomic, strong) IBOutlet UICollectionView *contentCollectionView;
|
||||
@property(nonatomic, strong) id<MPAlgorithm> algorithm;
|
||||
|
||||
+ (instancetype)dequeueCellForElement:(MPElementEntity *)element
|
||||
fromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath;
|
||||
+ (instancetype)dequeueCellForTransientSite:(NSString *)siteName
|
||||
fromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
@end
|
218
MasterPassword/ObjC/iOS/MPPasswordTypesCell.m
Normal file
218
MasterPassword/ObjC/iOS/MPPasswordTypesCell.m
Normal file
@ -0,0 +1,218 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPPasswordTypesCell.h
|
||||
// MPPasswordTypesCell
|
||||
//
|
||||
// Created by lhunath on 2014-03-27.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPPasswordTypesCell.h"
|
||||
#import "MPPasswordLargeCell.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
|
||||
@implementation MPPasswordTypesCell
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
+ (instancetype)dequeueCellForTransientSite:(NSString *)siteName fromCollectionView:(UICollectionView *)collectionView
|
||||
atIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
MPPasswordTypesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass( [MPPasswordTypesCell class] )
|
||||
forIndexPath:indexPath];
|
||||
[cell setTransientSite:siteName];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
+ (instancetype)dequeueCellForElement:(MPElementEntity *)element fromCollectionView:(UICollectionView *)collectionView
|
||||
atIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
MPPasswordTypesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass( [MPPasswordTypesCell class] )
|
||||
forIndexPath:indexPath];
|
||||
[cell setElement:element];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
|
||||
[super awakeFromNib];
|
||||
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.layer.shadowColor = [UIColor clearColor].CGColor;
|
||||
|
||||
[self prepareForReuse];
|
||||
}
|
||||
|
||||
- (void)prepareForReuse {
|
||||
|
||||
_algorithm = MPAlgorithmDefault;
|
||||
|
||||
[super prepareForReuse];
|
||||
}
|
||||
|
||||
- (void)reloadWithTransientSite:(NSString *)siteName {
|
||||
|
||||
[super reloadWithTransientSite:siteName];
|
||||
|
||||
[self.contentCollectionView reloadData];
|
||||
NSIndexPath *visibleIndexPath = [self contentIndexPathForType:
|
||||
IfElse([[MPiOSAppDelegate get] activeUserForMainThread].defaultType, MPElementTypeGeneratedLong)];
|
||||
[self.contentCollectionView scrollToItemAtIndexPath:visibleIndexPath atScrollPosition:NO
|
||||
animated:UICollectionViewScrollPositionCenteredHorizontally];
|
||||
}
|
||||
|
||||
- (void)reloadWithElement:(MPElementEntity *)mainElement {
|
||||
|
||||
[super reloadWithElement:mainElement];
|
||||
|
||||
self.algorithm = IfNotNilElse([self mainElement].algorithm, MPAlgorithmDefault);
|
||||
|
||||
[self.contentCollectionView reloadData];
|
||||
NSIndexPath *visibleIndexPath = [self contentIndexPathForType:mainElement.type];
|
||||
[self.contentCollectionView scrollToItemAtIndexPath:visibleIndexPath atScrollPosition:NO
|
||||
animated:UICollectionViewScrollPositionCenteredHorizontally];
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
|
||||
if (!self.algorithm)
|
||||
dbg_return_tr(0, @, @(section));
|
||||
|
||||
NSInteger types = 1;
|
||||
|
||||
MPElementType type = [self typeForContentIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
|
||||
for (MPElementType nextType = type; type != (nextType = [self.algorithm nextType:nextType]);)
|
||||
++types;
|
||||
|
||||
dbg_return_tr(types, @, @(section));
|
||||
}
|
||||
|
||||
- (MPPasswordLargeCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
MPPasswordLargeCell *cell = [MPPasswordLargeCell dequeueCellWithType:[self typeForContentIndexPath:indexPath]
|
||||
fromCollectionView:collectionView atIndexPath:indexPath];
|
||||
if (self.transientSite)
|
||||
[cell reloadWithTransientSite:self.transientSite];
|
||||
else
|
||||
[cell reloadWithElement:self.mainElement];
|
||||
|
||||
dbg_return(cell, indexPath);
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDelegateFlowLayout
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
UICollectionView *passwordCollectionView = [UICollectionView findAsSuperviewOf:self];
|
||||
[passwordCollectionView.delegate collectionView:passwordCollectionView didSelectItemAtIndexPath:[passwordCollectionView indexPathForCell:self]];
|
||||
}
|
||||
|
||||
#pragma mark - UIScrollViewDelegate
|
||||
|
||||
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity
|
||||
targetContentOffset:(inout CGPoint *)targetContentOffset {
|
||||
|
||||
if (scrollView == self.contentCollectionView) {
|
||||
NSIndexPath *targetIndexPath = [self.contentCollectionView indexPathForItemAtPoint:
|
||||
CGPointPlusCGPoint( *targetContentOffset, self.contentCollectionView.center )];
|
||||
*targetContentOffset = CGPointFromCGRectTopLeft(
|
||||
[self.contentCollectionView layoutAttributesForItemAtIndexPath:targetIndexPath].frame );
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
|
||||
|
||||
if (scrollView == self.contentCollectionView && !decelerate)
|
||||
[self saveContentType];
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
|
||||
|
||||
if (scrollView == self.contentCollectionView)
|
||||
[self saveContentType];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (MPElementType)typeForContentIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
MPElementType type = MPElementTypeGeneratedPIN;
|
||||
|
||||
for (NSUInteger i = 0; i < indexPath.item; ++i)
|
||||
type = [self.algorithm nextType:type];
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
- (NSIndexPath *)contentIndexPathForType:(MPElementType)type {
|
||||
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
||||
while ([self typeForContentIndexPath:indexPath] != type) {
|
||||
indexPath = [NSIndexPath indexPathForItem:indexPath.item + 1 inSection:indexPath.section];
|
||||
NSAssert1(indexPath.item < [self.contentCollectionView numberOfItemsInSection:0],
|
||||
@"No item found for type: %@", [self.algorithm nameOfType:type]);
|
||||
}
|
||||
|
||||
return indexPath;
|
||||
}
|
||||
|
||||
- (void)saveContentType {
|
||||
|
||||
if (self.transientSite)
|
||||
return;
|
||||
|
||||
CGPoint centerPoint = CGPointFromCGRectCenter( self.contentCollectionView.bounds );
|
||||
NSIndexPath *centerIndexPath = [self.contentCollectionView indexPathForItemAtPoint:centerPoint];
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPPasswordLargeCell *cell = (MPPasswordLargeCell *)[self.contentCollectionView cellForItemAtIndexPath:centerIndexPath];
|
||||
if (!cell) {
|
||||
err(@"Couldn't find cell to change type: centerIndexPath=%@", centerIndexPath);
|
||||
return;
|
||||
}
|
||||
|
||||
MPElementEntity *element = [self elementInContext:context];
|
||||
if (element.type == cell.type)
|
||||
// Nothing changed.
|
||||
return;
|
||||
|
||||
self.element = [cell saveContentTypeWithElement:element saveInContext:context];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setSelected:(BOOL)selected {
|
||||
|
||||
[super setSelected:selected];
|
||||
|
||||
if (!selected)
|
||||
for (NSIndexPath *indexPath in [self.contentCollectionView indexPathsForSelectedItems])
|
||||
[self.contentCollectionView deselectItemAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
|
||||
- (void)setAlgorithm:(id<MPAlgorithm>)algorithm {
|
||||
|
||||
if ([_algorithm isEqual:algorithm])
|
||||
return;
|
||||
|
||||
_algorithm = algorithm;
|
||||
|
||||
[self.contentCollectionView reloadData];
|
||||
}
|
||||
|
||||
@end
|
@ -17,8 +17,9 @@
|
||||
//
|
||||
|
||||
#import "LLGitTip.h"
|
||||
@class MPElementEntity;
|
||||
|
||||
@interface MPPasswordsViewController : UIViewController<UISearchBarDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UITextFieldDelegate>
|
||||
@interface MPPasswordsViewController : UIViewController<UISearchBarDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||
|
||||
@property(strong, nonatomic) IBOutlet UIView *passwordSelectionContainer;
|
||||
@property(strong, nonatomic) IBOutlet UICollectionView *passwordCollectionView;
|
||||
|
@ -19,14 +19,17 @@
|
||||
#import "MPPasswordsViewController.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "MPPasswordCell.h"
|
||||
#import "MPPasswordLargeCell.h"
|
||||
#import "UIScrollView+PearlAdjustInsets.h"
|
||||
#import "MPPasswordTypesCell.h"
|
||||
#import "MPPasswordSmallCell.h"
|
||||
#import "UIColor+Expanded.h"
|
||||
|
||||
@interface MPPasswordsViewController()<NSFetchedResultsControllerDelegate>
|
||||
|
||||
@property(strong, nonatomic) IBOutlet UINavigationBar *navigationBar;
|
||||
|
||||
@property(nonatomic, strong) IBOutlet UINavigationBar *navigationBar;
|
||||
@property(nonatomic, readonly) NSString *query;
|
||||
@property(nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPPasswordsViewController {
|
||||
@ -34,13 +37,23 @@
|
||||
__weak id _mocObserver;
|
||||
NSArray *_notificationObservers;
|
||||
__weak UITapGestureRecognizer *_passwordsDismissRecognizer;
|
||||
NSFetchedResultsController *_fetchedResultsController;
|
||||
NSManagedObjectID *_activeElementOID;
|
||||
BOOL _exactMatch;
|
||||
NSMutableDictionary *_fetchedUpdates;
|
||||
UIColor *_backgroundColor;
|
||||
UIColor *_darkenedBackgroundColor;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
|
||||
[super viewDidLoad];
|
||||
|
||||
_fetchedUpdates = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||
_darkenedBackgroundColor = [(_backgroundColor = [UIColor colorWithRGBHex:0x1F2124]) colorByMultiplyingBy:0.7f];
|
||||
|
||||
self.view.backgroundColor = [UIColor clearColor];
|
||||
[self.passwordCollectionView automaticallyAdjustInsetsForKeyboard];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
@ -59,74 +72,260 @@
|
||||
[self stopObservingStore];
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
#pragma mark - UICollectionViewDelegateFlowLayout
|
||||
|
||||
- (void)textFieldDidEndEditing:(UITextField *)textField {
|
||||
}
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout
|
||||
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
if (collectionView == self.passwordCollectionView) {
|
||||
if (indexPath.item < 3 ||
|
||||
indexPath.item >= ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[indexPath.section]).numberOfObjects)
|
||||
return CGSizeMake( 300, 100 );
|
||||
|
||||
return NO;
|
||||
}
|
||||
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)collectionViewLayout;
|
||||
return CGSizeMake( (300 - layout.minimumInteritemSpacing) / 2, 44 );
|
||||
}
|
||||
|
||||
// This isn't really in UITextFieldDelegate. We fake it from UITextFieldTextDidChangeNotification.
|
||||
- (void)textFieldDidChange:(UITextField *)textField {
|
||||
Throw(@"Unexpected collection view: %@", collectionView);
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||
|
||||
return [self.fetchedResultsController.sections count] + 1;
|
||||
if (collectionView == self.passwordCollectionView)
|
||||
dbg_return_tr([self.fetchedResultsController.sections count], @);
|
||||
|
||||
Throw(@"Unexpected collection view: %@", collectionView);
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
|
||||
if (collectionView == self.passwordCollectionView) {
|
||||
if (section < [self.fetchedResultsController.sections count])
|
||||
return ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[section]).numberOfObjects;
|
||||
if (collectionView == self.passwordCollectionView)
|
||||
dbg_return_tr(!self.query.length? 0: ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[section]).numberOfObjects +
|
||||
(_exactMatch? 0: 1), @, @(section));
|
||||
|
||||
// New Site.
|
||||
return [self.query length]? 1: 0;
|
||||
}
|
||||
|
||||
Throw(@"unexpected collection view: %@", collectionView);
|
||||
Throw(@"Unexpected collection view: %@", collectionView);
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
if (collectionView == self.passwordCollectionView) {
|
||||
MPPasswordCell *cell;
|
||||
if (indexPath.section < [self.fetchedResultsController.sections count]) {
|
||||
[UIView setAnimationsEnabled:NO];
|
||||
MPPasswordElementCell *cell;
|
||||
if (indexPath.item < ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[indexPath.section]).numberOfObjects) {
|
||||
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
||||
if (indexPath.item < 2)
|
||||
cell = [collectionView dequeueReusableCellWithReuseIdentifier:[MPPasswordCell reuseIdentifierForElement:element] forIndexPath:indexPath];
|
||||
if (indexPath.item < 3)
|
||||
cell = [MPPasswordTypesCell dequeueCellForElement:element fromCollectionView:collectionView atIndexPath:indexPath];
|
||||
else
|
||||
cell = [collectionView dequeueReusableCellWithReuseIdentifier:[MPPasswordCell reuseIdentifierForElement:element] forIndexPath:indexPath];
|
||||
|
||||
[cell setElement:element];
|
||||
} else {
|
||||
// New Site.
|
||||
cell = [collectionView dequeueReusableCellWithReuseIdentifier:[MPPasswordCell reuseIdentifier] forIndexPath:indexPath];
|
||||
cell.transientSite = self.query;
|
||||
cell = [MPPasswordSmallCell dequeueCellForElement:element fromCollectionView:collectionView atIndexPath:indexPath];
|
||||
}
|
||||
return cell;
|
||||
else
|
||||
// New Site.
|
||||
cell = [MPPasswordTypesCell dequeueCellForTransientSite:self.query fromCollectionView:collectionView atIndexPath:indexPath];
|
||||
|
||||
[UIView setAnimationsEnabled:YES];
|
||||
dbg_return(cell, indexPath);
|
||||
}
|
||||
|
||||
Throw(@"unexpected collection view: %@", collectionView);
|
||||
Throw(@"Unexpected collection view: %@", collectionView);
|
||||
}
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
MPPasswordElementCell *cell = (MPPasswordElementCell *)[collectionView cellForItemAtIndexPath:indexPath];
|
||||
NSString *newSiteName = cell.transientSite;
|
||||
if (newSiteName) {
|
||||
[PearlAlert showAlertWithTitle:@"Create Site"
|
||||
message:strf( @"Do you want to create a new site named:\n%@", newSiteName )
|
||||
viewStyle:UIAlertViewStyleDefault
|
||||
initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
||||
if (buttonIndex == [alert cancelButtonIndex]) {
|
||||
// Cancel
|
||||
[collectionView selectItemAtIndexPath:indexPath animated:NO
|
||||
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
|
||||
return;
|
||||
}
|
||||
|
||||
// Create
|
||||
[[MPiOSAppDelegate get] addElementNamed:newSiteName completion:^(MPElementEntity *element) {
|
||||
self.activeElement = element;
|
||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:strf( @"Added %@", newSiteName ) dismissAfter:2];
|
||||
[collectionView selectItemAtIndexPath:indexPath animated:NO
|
||||
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
|
||||
}];
|
||||
}];
|
||||
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil];
|
||||
return;
|
||||
}
|
||||
|
||||
MPElementEntity *element = [cell mainElement];
|
||||
if (!element) {
|
||||
[collectionView selectItemAtIndexPath:indexPath animated:NO
|
||||
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
|
||||
return;
|
||||
}
|
||||
|
||||
inf(@"Copying password for: %@", element.name);
|
||||
MPCheckpoint( MPCheckpointCopyToPasteboard, @{
|
||||
@"type" : NilToNSNull(element.typeName),
|
||||
@"version" : @(element.version),
|
||||
@"emergency" : @NO
|
||||
} );
|
||||
|
||||
[element use];
|
||||
[element resolveContentUsingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) {
|
||||
if (![result length]) {
|
||||
[collectionView selectItemAtIndexPath:indexPath animated:NO
|
||||
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
|
||||
return;
|
||||
}
|
||||
|
||||
[UIPasteboard generalPasteboard].string = result;
|
||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Password Copied" dismissAfter:2];
|
||||
PearlMainQueueAfter( 0.1f, ^{
|
||||
[collectionView selectItemAtIndexPath:indexPath animated:NO
|
||||
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
|
||||
} );
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
#pragma mark - NSFetchedResultsControllerDelegate
|
||||
|
||||
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
|
||||
|
||||
if (controller == _fetchedResultsController) {
|
||||
dbg(@"controllerWillChangeContent");
|
||||
NSAssert(![_fetchedUpdates count], @"Didn't finish a previous change update?");
|
||||
if ([_fetchedUpdates count]) {
|
||||
[_fetchedUpdates removeAllObjects];
|
||||
[self.passwordCollectionView reloadData];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UILongPressGestureRecognizer
|
||||
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath
|
||||
forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
|
||||
|
||||
- (void)didLongPress:(UILongPressGestureRecognizer *)recognizer {
|
||||
if (controller == _fetchedResultsController) {
|
||||
NSMutableArray *updatesForType = _fetchedUpdates[@(type)];
|
||||
if (!updatesForType)
|
||||
_fetchedUpdates[@(type)] = updatesForType = [NSMutableArray new];
|
||||
|
||||
[updatesForType addObject:@{ @"object" : NilToNSNull(anObject),
|
||||
@"indexPath" : NilToNSNull(indexPath),
|
||||
@"newIndexPath" : NilToNSNull(newIndexPath) }];
|
||||
switch (type) {
|
||||
case NSFetchedResultsChangeInsert:
|
||||
dbg(@"didChangeObject: insert: %@", [updatesForType lastObject]);
|
||||
break;
|
||||
case NSFetchedResultsChangeDelete:
|
||||
dbg(@"didChangeObject: delete: %@", [updatesForType lastObject]);
|
||||
break;
|
||||
case NSFetchedResultsChangeMove:
|
||||
dbg(@"didChangeObject: move: %@", [updatesForType lastObject]);
|
||||
break;
|
||||
case NSFetchedResultsChangeUpdate:
|
||||
dbg(@"didChangeObject: update: %@", [updatesForType lastObject]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo
|
||||
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
|
||||
|
||||
if (controller == _fetchedResultsController) {
|
||||
NSMutableArray *updatesForType = _fetchedUpdates[@(type << 3)];
|
||||
if (!updatesForType)
|
||||
_fetchedUpdates[@(type << 3)] = updatesForType = [NSMutableArray new];
|
||||
|
||||
[updatesForType addObject:@{ @"sectionInfo" : NilToNSNull(sectionInfo),
|
||||
@"index" : @(sectionIndex) }];
|
||||
switch (type) {
|
||||
case NSFetchedResultsChangeInsert:
|
||||
dbg(@"didChangeSection: insert: %@", [updatesForType lastObject]);
|
||||
break;
|
||||
case NSFetchedResultsChangeDelete:
|
||||
dbg(@"didChangeSection: delete: %@", [updatesForType lastObject]);
|
||||
break;
|
||||
case NSFetchedResultsChangeMove:
|
||||
dbg(@"didChangeSection: move: %@", [updatesForType lastObject]);
|
||||
break;
|
||||
case NSFetchedResultsChangeUpdate:
|
||||
dbg(@"didChangeSection: update: %@", [updatesForType lastObject]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
|
||||
|
||||
if (controller == _fetchedResultsController && [_fetchedUpdates count]) {
|
||||
[self.passwordCollectionView performBatchUpdates:^{
|
||||
[_fetchedUpdates enumerateKeysAndObjectsUsingBlock:^(NSNumber *typeNumber, NSArray *updates, BOOL *stop) {
|
||||
BOOL updateIsSection = NO;
|
||||
NSFetchedResultsChangeType type = [typeNumber unsignedIntegerValue];
|
||||
if (type >= 1 << 3) {
|
||||
updateIsSection = YES;
|
||||
type = type >> 3;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case NSFetchedResultsChangeInsert:
|
||||
if (updateIsSection) {
|
||||
for (NSDictionary *update in updates) {
|
||||
dbg(@"insertSections:%@", update[@"index"]);
|
||||
[self.passwordCollectionView insertSections:
|
||||
[NSIndexSet indexSetWithIndex:[update[@"index"] unsignedIntegerValue]]];
|
||||
}
|
||||
}
|
||||
else {
|
||||
dbg(@"insertItemsAtIndexPaths:%@", [updates valueForKeyPath:@"@unionOfObjects.newIndexPath"]);
|
||||
[self.passwordCollectionView insertItemsAtIndexPaths:[updates valueForKeyPath:@"@unionOfObjects.newIndexPath"]];
|
||||
}
|
||||
break;
|
||||
case NSFetchedResultsChangeDelete:
|
||||
if (updateIsSection) {
|
||||
for (NSDictionary *update in updates) {
|
||||
dbg(@"deleteSections:%@", update[@"index"]);
|
||||
[self.passwordCollectionView deleteSections:
|
||||
[NSIndexSet indexSetWithIndex:[update[@"index"] unsignedIntegerValue]]];
|
||||
}
|
||||
}
|
||||
else {
|
||||
dbg(@"deleteItemsAtIndexPaths:%@", [updates valueForKeyPath:@"@unionOfObjects.indexPath"]);
|
||||
[self.passwordCollectionView deleteItemsAtIndexPaths:[updates valueForKeyPath:@"@unionOfObjects.indexPath"]];
|
||||
}
|
||||
break;
|
||||
case NSFetchedResultsChangeMove:
|
||||
NSAssert(!updateIsSection, @"Move not supported for sections");
|
||||
for (NSDictionary *update in updates) {
|
||||
dbg(@"moveItemAtIndexPath:%@ toIndexPath:%@", update[@"indexPath"], update[@"newIndexPath"]);
|
||||
[self.passwordCollectionView moveItemAtIndexPath:update[@"indexPath"] toIndexPath:update[@"newIndexPath"]];
|
||||
}
|
||||
break;
|
||||
case NSFetchedResultsChangeUpdate:
|
||||
NSAssert(!updateIsSection, @"Update not supported for sections");
|
||||
dbg(@"reloadItemsAtIndexPaths:%@", [updates valueForKeyPath:@"@unionOfObjects.indexPath"]);
|
||||
[self.passwordCollectionView reloadItemsAtIndexPaths:[updates valueForKeyPath:@"@unionOfObjects.indexPath"]];
|
||||
break;
|
||||
}
|
||||
}];
|
||||
} completion:nil];
|
||||
[_fetchedUpdates removeAllObjects];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - UIScrollViewDelegate
|
||||
|
||||
#pragma mark - UISearchBarDelegate
|
||||
@ -138,9 +337,9 @@
|
||||
self.passwordsSearchBar.showsCancelButton = YES;
|
||||
_passwordsDismissRecognizer = [self.view dismissKeyboardForField:self.passwordsSearchBar onTouchForced:NO];
|
||||
|
||||
// [UIView animateWithDuration:0.3f animations:^{
|
||||
// self.passwordCollectionView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.3f];
|
||||
// }];
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
searchBar.superview.backgroundColor = _darkenedBackgroundColor;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +351,7 @@
|
||||
[self.view removeGestureRecognizer:_passwordsDismissRecognizer];
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.passwordCollectionView.backgroundColor = [UIColor clearColor];
|
||||
searchBar.superview.backgroundColor = _backgroundColor;
|
||||
}];
|
||||
}
|
||||
}
|
||||
@ -195,12 +394,22 @@
|
||||
|
||||
self.passwordSelectionContainer.alpha = 0;
|
||||
}],
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:MPSignedOutNotification object:nil
|
||||
queue:nil usingBlock:^(NSNotification *note) {
|
||||
Strongify(self);
|
||||
|
||||
self.activeElement = nil;
|
||||
_fetchedResultsController = nil;
|
||||
self.passwordsSearchBar.text = nil;
|
||||
[self updatePasswords];
|
||||
}],
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:UIApplicationDidBecomeActiveNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
Strongify(self);
|
||||
|
||||
// [self updateMode]; TODO: reload passwords list
|
||||
[self updatePasswords];
|
||||
[UIView animateWithDuration:1 animations:^{
|
||||
self.passwordSelectionContainer.alpha = 1;
|
||||
}];
|
||||
@ -217,22 +426,22 @@
|
||||
|
||||
- (void)observeStore {
|
||||
|
||||
Weakify(self);
|
||||
Weakify(self);
|
||||
|
||||
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
|
||||
if (!_mocObserver && mainContext)
|
||||
_mocObserver = [[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:mainContext
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
// Strongify(self);
|
||||
// [self updateMode]; TODO: reload passwords list
|
||||
Strongify(self);
|
||||
[self updatePasswords];
|
||||
}];
|
||||
if (!_storeObserver)
|
||||
_storeObserver = [[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:USMStoreDidChangeNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
Strongify(self);
|
||||
self.fetchedResultsController = nil;
|
||||
_fetchedResultsController = nil;
|
||||
[self updatePasswords];
|
||||
}];
|
||||
}
|
||||
@ -247,20 +456,48 @@
|
||||
|
||||
- (void)updatePasswords {
|
||||
|
||||
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
||||
NSManagedObjectID *activeUserOID = [MPiOSAppDelegate get].activeUserOID;
|
||||
if (!activeUserOID)
|
||||
return;
|
||||
NSString *query = self.query;
|
||||
NSManagedObjectID *activeUserOID = [MPiOSAppDelegate get].activeUserOID;
|
||||
if (!activeUserOID || ![query length]) {
|
||||
self.passwordsSearchBar.text = nil;
|
||||
PearlMainQueue( ^{ [self.passwordCollectionView reloadData]; } );
|
||||
return;
|
||||
}
|
||||
|
||||
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
||||
NSError *error = nil;
|
||||
self.fetchedResultsController.fetchRequest.predicate = [NSPredicate predicateWithFormat:
|
||||
@"user == %@ AND name BEGINSWITH[cd] %@", activeUserOID, self.query];
|
||||
@"user == %@ AND name BEGINSWITH[cd] %@", activeUserOID, query];
|
||||
if (![self.fetchedResultsController performFetch:&error])
|
||||
err(@"Couldn't fetch elements: %@", error);
|
||||
|
||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||
[self.passwordCollectionView reloadData];
|
||||
}];
|
||||
_exactMatch = NO;
|
||||
for (MPElementEntity *entity in self.fetchedResultsController.fetchedObjects)
|
||||
if ([entity.name isEqualToString:query]) {
|
||||
_exactMatch = YES;
|
||||
break;
|
||||
}
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[self.passwordCollectionView performBatchUpdates:^{
|
||||
NSInteger fromSections = self.passwordCollectionView.numberOfSections;
|
||||
NSInteger toSections = [self numberOfSectionsInCollectionView:self.passwordCollectionView];
|
||||
for (int section = 0; section < MAX(toSections, fromSections); section++) {
|
||||
if (section >= fromSections) {
|
||||
dbg(@"insertSections:%d", section);
|
||||
[self.passwordCollectionView insertSections:[NSIndexSet indexSetWithIndex:section]];
|
||||
}
|
||||
else if (section >= toSections) {
|
||||
dbg(@"deleteSections:%d", section);
|
||||
[self.passwordCollectionView deleteSections:[NSIndexSet indexSetWithIndex:section]];
|
||||
}
|
||||
else {
|
||||
dbg(@"reloadSections:%d", section);
|
||||
[self.passwordCollectionView reloadSections:[NSIndexSet indexSetWithIndex:section]];
|
||||
}
|
||||
}
|
||||
} completion:nil];
|
||||
} );
|
||||
}];
|
||||
}
|
||||
|
||||
@ -273,21 +510,30 @@
|
||||
|
||||
- (NSFetchedResultsController *)fetchedResultsController {
|
||||
|
||||
if (!_fetchedResultsController)
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
|
||||
if (!_fetchedResultsController) {
|
||||
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
|
||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
|
||||
fetchRequest.sortDescriptors = @[
|
||||
[[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector(lastUsed) ) ascending:NO]
|
||||
];
|
||||
fetchRequest.fetchBatchSize = 10;
|
||||
_fetchedResultsController = [[NSFetchedResultsController alloc]
|
||||
initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
|
||||
initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil];
|
||||
_fetchedResultsController.delegate = self;
|
||||
}];
|
||||
[self observeStore];
|
||||
}
|
||||
|
||||
return _fetchedResultsController;
|
||||
}
|
||||
|
||||
- (void)setActiveElement:(MPElementEntity *)activeElement {
|
||||
|
||||
_activeElementOID = activeElement.objectID;
|
||||
|
||||
[self updatePasswords];
|
||||
}
|
||||
|
||||
- (void)setActive:(BOOL)active {
|
||||
|
||||
[self setActive:active animated:YES];
|
||||
|
@ -102,11 +102,7 @@
|
||||
UILabel *alertNameLabel = [self.nameLabel cloneAddedTo:container];
|
||||
alertNameLabel.center = alertAvatar.center;
|
||||
alertNameLabel.text = user.name;
|
||||
alertNameLabel.bounds = CGRectSetHeight( alertNameLabel.bounds,
|
||||
[alertNameLabel.text sizeWithFont:self.nameLabel.font
|
||||
constrainedToSize:CGSizeMake( alertNameLabel.bounds.size.width - 10,
|
||||
100 )
|
||||
lineBreakMode:self.nameLabel.lineBreakMode].height );
|
||||
[alertNameLabel sizeToFit];
|
||||
alertNameLabel.layer.cornerRadius = 5;
|
||||
alertNameLabel.backgroundColor = [UIColor blackColor];
|
||||
}
|
||||
@ -614,10 +610,7 @@
|
||||
|
||||
// Lay out user name label.
|
||||
self.nameLabel.text = targetedAvatar? (targetedUser? targetedUser.name: @"New User"): nil;
|
||||
self.nameLabel.bounds = CGRectSetHeight( self.nameLabel.bounds,
|
||||
[self.nameLabel.text sizeWithFont:self.nameLabel.font
|
||||
constrainedToSize:CGSizeMake( self.nameLabel.bounds.size.width - 10, 100 )
|
||||
lineBreakMode:self.nameLabel.lineBreakMode].height );
|
||||
[self.nameLabel sizeToFit];
|
||||
self.oldNameLabel.bounds = self.nameLabel.bounds;
|
||||
if (completion)
|
||||
completion( YES );
|
||||
@ -725,7 +718,7 @@
|
||||
|
||||
- (void)setSpinnerActive:(BOOL)active {
|
||||
|
||||
PearlMainThread(^{
|
||||
PearlMainQueue( ^{
|
||||
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
|
||||
rotate.toValue = [NSNumber numberWithDouble:2 * M_PI];
|
||||
rotate.duration = 5.0;
|
||||
@ -751,7 +744,7 @@
|
||||
else
|
||||
[self avatarForUser:[self selectedUserForThread]].backgroundColor = self.avatarTemplate.backgroundColor;
|
||||
}];
|
||||
});
|
||||
} );
|
||||
}
|
||||
|
||||
- (void)updateAvatarShadowColor:(UIButton *)avatar isTargeted:(BOOL)targeted {
|
||||
|
@ -52,15 +52,18 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
__weak id _mocObserver;
|
||||
NSArray *_notificationObservers;
|
||||
NSString *_masterPasswordChoice;
|
||||
NSOperationQueue *_afterUpdates;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
|
||||
[super viewDidLoad];
|
||||
|
||||
_afterUpdates = [NSOperationQueue new];
|
||||
|
||||
self.marqueeTipTexts = @[
|
||||
strl(@"Press and hold to change password or delete."),
|
||||
strl(@"Shake for emergency generator."),
|
||||
strl( @"Press and hold to change password or delete." ),
|
||||
strl( @"Shake for emergency generator." ),
|
||||
];
|
||||
|
||||
self.view.backgroundColor = [UIColor clearColor];
|
||||
@ -81,7 +84,8 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
[self reloadUsers];
|
||||
|
||||
[self.marqueeTipTimer invalidate];
|
||||
self.marqueeTipTimer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(firedMarqueeTimer:) userInfo:nil repeats:YES];
|
||||
self.marqueeTipTimer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(firedMarqueeTimer:) userInfo:nil
|
||||
repeats:YES];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
@ -119,6 +123,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
break;
|
||||
}
|
||||
case MPActiveUserStateLogin: {
|
||||
[self.entryField endEditing:YES];
|
||||
[self selectedAvatar].spinnerActive = YES;
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
BOOL signedIn = NO, isNew = NO;
|
||||
@ -178,6 +183,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
[self.entryField endEditing:YES];
|
||||
[self selectedAvatar].spinnerActive = YES;
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
BOOL isNew = NO;
|
||||
@ -240,7 +246,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource
|
||||
#pragma mark - UICollectionViewDelegateFlowLayout
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout
|
||||
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
@ -253,6 +259,8 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
Throw(@"unexpected collection view: %@", collectionView);
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
|
||||
if (collectionView == self.avatarCollectionView)
|
||||
@ -272,11 +280,9 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
BOOL isNew = NO;
|
||||
MPUserEntity *user = [self userForIndexPath:indexPath inContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]
|
||||
isNew:&isNew];
|
||||
if (isNew) {
|
||||
// New User
|
||||
if (isNew)
|
||||
// New User
|
||||
cell.avatar = MPAvatarAdd;
|
||||
cell.name = strl( @"New User" );
|
||||
}
|
||||
else {
|
||||
// Existing User
|
||||
cell.avatar = user.avatar;
|
||||
@ -305,6 +311,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
BOOL isNew = NO;
|
||||
MPUserEntity *user = [self userForIndexPath:indexPath inContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]
|
||||
isNew:&isNew];
|
||||
|
||||
if (isNew)
|
||||
self.activeUserState = MPActiveUserStateUserName;
|
||||
else if (!user.keyID)
|
||||
@ -316,9 +323,8 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
if (collectionView == self.avatarCollectionView) {
|
||||
if (collectionView == self.avatarCollectionView)
|
||||
self.activeUserState = MPActiveUserStateNone;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UILongPressGestureRecognizer
|
||||
@ -363,13 +369,12 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
MPUserEntity *user_ = (MPUserEntity *)[context existingObjectWithID:userID error:NULL];
|
||||
if (user_)
|
||||
[[MPiOSAppDelegate get] changeMasterPasswordFor:user_ saveInContext:context didResetBlock:^{
|
||||
dbg(@"changing mp for user: %@, keyID: %@", user_.name, user_.keyID);
|
||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||
PearlMainQueue( ^{
|
||||
NSIndexPath *avatarIndexPath = [self.avatarCollectionView indexPathForCell:avatarCell];
|
||||
[self.avatarCollectionView selectItemAtIndexPath:avatarIndexPath animated:NO
|
||||
scrollPosition:UICollectionViewScrollPositionNone];
|
||||
[self collectionView:self.avatarCollectionView didSelectItemAtIndexPath:avatarIndexPath];
|
||||
}];
|
||||
} );
|
||||
}];
|
||||
}];
|
||||
} cancelTitle:[PearlStrings get].commonButtonCancel
|
||||
@ -383,9 +388,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
targetContentOffset:(inout CGPoint *)targetContentOffset {
|
||||
|
||||
if (scrollView == self.avatarCollectionView) {
|
||||
CGPoint offsetToCenter = CGPointMake(
|
||||
self.avatarCollectionView.bounds.size.width / 2,
|
||||
self.avatarCollectionView.bounds.size.height / 2 );
|
||||
CGPoint offsetToCenter = self.avatarCollectionView.center;
|
||||
NSIndexPath *avatarIndexPath = [self.avatarCollectionView indexPathForItemAtPoint:
|
||||
CGPointPlusCGPoint( *targetContentOffset, offsetToCenter )];
|
||||
CGPoint targetCenter = [self.avatarCollectionView layoutAttributesForItemAtIndexPath:avatarIndexPath].center;
|
||||
@ -502,6 +505,13 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
}
|
||||
}
|
||||
|
||||
- (void)afterUpdatesMainQueue:(void (^)(void))block {
|
||||
|
||||
[_afterUpdates addOperationWithBlock:^{
|
||||
PearlMainQueue( block );
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)registerObservers {
|
||||
|
||||
if ([_notificationObservers count])
|
||||
@ -555,7 +565,13 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:mainContext
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
Strongify(self);
|
||||
[self reloadUsers];
|
||||
NSSet *insertedObjects = note.userInfo[NSInsertedObjectsKey];
|
||||
NSSet *deletedObjects = note.userInfo[NSDeletedObjectsKey];
|
||||
if ([[NSSetUnion(insertedObjects, deletedObjects)
|
||||
filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
|
||||
return [evaluatedObject isKindOfClass:[MPUserEntity class]];
|
||||
}]] count])
|
||||
[self reloadUsers];
|
||||
}];
|
||||
if (!_storeObserver)
|
||||
_storeObserver = [[NSNotificationCenter defaultCenter]
|
||||
@ -576,20 +592,25 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
|
||||
- (void)reloadUsers {
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
NSError *error = nil;
|
||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
|
||||
fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO] ];
|
||||
NSArray *users = [context executeFetchRequest:fetchRequest error:&error];
|
||||
if (!users) {
|
||||
err(@"Failed to load users: %@", error);
|
||||
self.userIDs = nil;
|
||||
}
|
||||
[self afterUpdatesMainQueue:^{
|
||||
[self observeStore];
|
||||
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
|
||||
NSError *error = nil;
|
||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
|
||||
fetchRequest.sortDescriptors = @[
|
||||
[NSSortDescriptor sortDescriptorWithKey:NSStringFromSelector( @selector(lastUsed) ) ascending:NO]
|
||||
];
|
||||
NSArray *users = [mainContext executeFetchRequest:fetchRequest error:&error];
|
||||
if (!users) {
|
||||
err(@"Failed to load users: %@", error);
|
||||
self.userIDs = nil;
|
||||
}
|
||||
|
||||
NSMutableArray *userIDs = [NSMutableArray arrayWithCapacity:[users count]];
|
||||
for (MPUserEntity *user in users)
|
||||
[userIDs addObject:user.objectID];
|
||||
self.userIDs = userIDs;
|
||||
NSMutableArray *userIDs = [NSMutableArray arrayWithCapacity:[users count]];
|
||||
for (MPUserEntity *user in users)
|
||||
[userIDs addObject:user.objectID];
|
||||
self.userIDs = userIDs;
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
@ -616,13 +637,23 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
_userIDs = userIDs;
|
||||
dbg(@"userIDs -> %lu", (unsigned long)[userIDs count]);
|
||||
|
||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||
PearlMainQueue( ^{
|
||||
BOOL isNew = NO;
|
||||
NSManagedObjectID *selectUserID = [MPiOSAppDelegate get].activeUserOID;
|
||||
if (!selectUserID)
|
||||
selectUserID = [self selectedUserInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]
|
||||
isNew:&isNew].objectID;
|
||||
[self.avatarCollectionView reloadData];
|
||||
|
||||
NSUInteger selectedAvatarItem = isNew? [_userIDs count]: selectUserID? [_userIDs indexOfObject:selectUserID]: NSNotFound;
|
||||
if (selectedAvatarItem != NSNotFound)
|
||||
[self.avatarCollectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:selectedAvatarItem inSection:0] animated:NO
|
||||
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.userSelectionContainer.alpha = 1;
|
||||
}];
|
||||
}];
|
||||
} );
|
||||
}
|
||||
|
||||
- (void)setActiveUserState:(MPActiveUserState)activeUserState {
|
||||
@ -635,11 +666,14 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
_activeUserState = activeUserState;
|
||||
_masterPasswordChoice = nil;
|
||||
|
||||
if (activeUserState != MPActiveUserStateMinimized && [MPiOSAppDelegate get].key) {
|
||||
if (activeUserState != MPActiveUserStateMinimized && (!self.active || [MPiOSAppDelegate get].activeUserOID)) {
|
||||
[[MPiOSAppDelegate get] signOutAnimated:YES];
|
||||
return;
|
||||
}
|
||||
|
||||
[_afterUpdates setSuspended:YES];
|
||||
dbg(@"suspend updates");
|
||||
__block BOOL requestFirstResponder = NO;
|
||||
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
|
||||
MPAvatarCell *selectedAvatar = [self selectedAvatar];
|
||||
|
||||
@ -647,7 +681,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
for (NSUInteger item = 0; item < [self.avatarCollectionView numberOfItemsInSection:0]; ++item) {
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:0];
|
||||
MPAvatarCell *avatarCell = (MPAvatarCell *)[self.avatarCollectionView cellForItemAtIndexPath:indexPath];
|
||||
[self updateModeForAvatar:avatarCell atIndexPath:indexPath animated:NO];
|
||||
[self updateModeForAvatar:avatarCell atIndexPath:indexPath animated:animated];
|
||||
|
||||
if (selectedAvatar && avatarCell == selectedAvatar)
|
||||
[self.avatarCollectionView scrollToItemAtIndexPath:indexPath
|
||||
@ -693,16 +727,6 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Manage the random avatar for the new user if selected.
|
||||
if (selectedAvatar.avatar == MPAvatarAdd)
|
||||
selectedAvatar.avatar = arc4random() % MPAvatarCount;
|
||||
else {
|
||||
NSIndexPath *newUserIndexPath = [NSIndexPath indexPathForItem:[_userIDs count] inSection:0];
|
||||
MPAvatarCell *newUserAvatar = (MPAvatarCell *)[[self avatarCollectionView] cellForItemAtIndexPath:newUserIndexPath];
|
||||
newUserAvatar.avatar = MPAvatarAdd;
|
||||
newUserAvatar.name = strl( @"New User" );
|
||||
}
|
||||
|
||||
// Manage the entry container depending on whether a user is activate or not.
|
||||
switch (activeUserState) {
|
||||
case MPActiveUserStateNone: {
|
||||
@ -722,6 +746,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
self.avatarCollectionView.scrollEnabled = NO;
|
||||
self.entryContainer.alpha = 1;
|
||||
self.footerContainer.alpha = 1;
|
||||
requestFirstResponder = YES;
|
||||
break;
|
||||
}
|
||||
case MPActiveUserStateMinimized: {
|
||||
@ -737,12 +762,15 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
|
||||
[self.avatarCollectionCenterConstraint apply];
|
||||
|
||||
// Toggle the keyboard.
|
||||
if (!self.entryContainer.alpha)
|
||||
[self.entryField resignFirstResponder];
|
||||
} completion:^(BOOL finished) {
|
||||
if (finished && self.entryContainer.alpha)
|
||||
[self.entryField becomeFirstResponder];
|
||||
dbg(@"resume updates");
|
||||
[_afterUpdates setSuspended:NO];
|
||||
}];
|
||||
|
||||
if (requestFirstResponder)
|
||||
[self.entryField becomeFirstResponder];
|
||||
else
|
||||
[self.entryField resignFirstResponder];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
@ -13,9 +13,10 @@
|
||||
|
||||
@interface MPiOSAppDelegate()
|
||||
|
||||
@property(nonatomic, strong) PearlAlert *handleCloudContentAlert;
|
||||
@property(nonatomic, strong) PearlAlert *fixCloudContentAlert;
|
||||
@property(nonatomic, strong) PearlOverlay *storeLoading;
|
||||
@property(nonatomic, weak) PearlAlert *handleCloudDisabledAlert;
|
||||
@property(nonatomic, weak) PearlAlert *handleCloudContentAlert;
|
||||
@property(nonatomic, weak) PearlAlert *fixCloudContentAlert;
|
||||
@property(nonatomic, weak) PearlOverlay *storeLoading;
|
||||
@end
|
||||
|
||||
@implementation MPiOSAppDelegate
|
||||
@ -120,12 +121,14 @@
|
||||
UIImage *navBarImage = [[UIImage imageNamed:@"ui_navbar_container"] resizableImageWithCapInsets:UIEdgeInsetsMake( 0, 5, 0, 5 )];
|
||||
[[UINavigationBar appearance] setBackgroundImage:navBarImage forBarMetrics:UIBarMetricsDefault];
|
||||
[[UINavigationBar appearance] setBackgroundImage:navBarImage forBarMetrics:UIBarMetricsLandscapePhone];
|
||||
NSShadow *titleShadow = [NSShadow new];
|
||||
titleShadow.shadowColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.8f];
|
||||
titleShadow.shadowOffset = CGSizeMake( 0, -1 );
|
||||
[[UINavigationBar appearance] setTitleTextAttributes:
|
||||
@{
|
||||
UITextAttributeTextColor : [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f],
|
||||
UITextAttributeTextShadowColor : [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.8f],
|
||||
UITextAttributeTextShadowOffset : [NSValue valueWithUIOffset:UIOffsetMake( 0, -1 )],
|
||||
UITextAttributeFont : [UIFont fontWithName:@"Exo-Bold" size:20.0f]
|
||||
NSForegroundColorAttributeName : [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f],
|
||||
NSShadowAttributeName : titleShadow,
|
||||
NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-Bold" size:20.0f]
|
||||
}];
|
||||
|
||||
UIImage *navBarButton = [[UIImage imageNamed:@"ui_navbar_button"] resizableImageWithCapInsets:UIEdgeInsetsMake( 0, 5, 0, 5 )];
|
||||
@ -136,13 +139,15 @@
|
||||
setBackButtonBackgroundImage:navBarBack forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
|
||||
[[UIBarButtonItem appearance]
|
||||
setBackButtonBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
|
||||
NSShadow *barButtonShadow = [NSShadow new];
|
||||
barButtonShadow.shadowColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.5f];
|
||||
barButtonShadow.shadowOffset = CGSizeMake( 0, 1 );
|
||||
[[UIBarButtonItem appearance] setTitleTextAttributes:
|
||||
@{
|
||||
UITextAttributeTextColor : [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f],
|
||||
UITextAttributeTextShadowColor : [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.5f],
|
||||
UITextAttributeTextShadowOffset : [NSValue valueWithUIOffset:UIOffsetMake( 0, 1 )]//,
|
||||
NSForegroundColorAttributeName : [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f],
|
||||
NSShadowAttributeName : barButtonShadow,
|
||||
// Causes a bug in iOS where image views get oddly stretched... or something.
|
||||
//UITextAttributeFont: [UIFont fontWithName:@"HelveticaNeue" size:13.0f]
|
||||
//NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:13.0f]
|
||||
}
|
||||
forState:UIControlStateNormal];
|
||||
|
||||
@ -257,7 +262,7 @@
|
||||
if (!importedSitesData)
|
||||
return;
|
||||
|
||||
PearlOverlay *activityOverlay = [PearlOverlay showOverlayWithTitle:@"Importing"];
|
||||
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"];
|
||||
|
||||
NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
|
||||
MPImportResult result = [self importSites:importedSitesString askImportPassword:^NSString *(NSString *userName) {
|
||||
@ -463,9 +468,9 @@
|
||||
@"--\n"
|
||||
@"%@"
|
||||
@"Master Password %@, build %@",
|
||||
userName? ([userName stringByAppendingString:@"\n"]): @"",
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion )
|
||||
userName? ([userName stringByAppendingString:@"\n"]): @"",
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion )
|
||||
|
||||
attachments:(logs
|
||||
? [[PearlEMailAttachment alloc]
|
||||
@ -473,8 +478,8 @@
|
||||
dataUsingEncoding:NSUTF8StringEncoding]
|
||||
mimeType:@"text/plain"
|
||||
fileName:PearlString( @"%@-%@.log",
|
||||
[[NSDateFormatter rfc3339DateFormatter] stringFromDate:[NSDate date]],
|
||||
[PearlKeyChain deviceIdentifier] )]
|
||||
[[NSDateFormatter rfc3339DateFormatter] stringFromDate:[NSDate date]],
|
||||
[PearlKeyChain deviceIdentifier] )]
|
||||
: nil), nil]
|
||||
showComposerForVC:viewController];
|
||||
}
|
||||
@ -526,17 +531,17 @@
|
||||
@"--\n"
|
||||
@"%@\n"
|
||||
@"Master Password %@, build %@",
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
else
|
||||
message = PearlString( @"Backup of Master Password sites.\n\n\n"
|
||||
@"--\n"
|
||||
@"%@\n"
|
||||
@"Master Password %@, build %@",
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
|
||||
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
||||
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
||||
@ -545,7 +550,7 @@
|
||||
attachments:[[PearlEMailAttachment alloc] initWithContent:[exportedSites dataUsingEncoding:NSUTF8StringEncoding]
|
||||
mimeType:@"text/plain" fileName:
|
||||
PearlString( @"%@ (%@).mpsites", [self activeUserForMainThread].name,
|
||||
[exportDateFormatter stringFromDate:[NSDate date]] )],
|
||||
[exportDateFormatter stringFromDate:[NSDate date]] )],
|
||||
nil];
|
||||
}
|
||||
|
||||
@ -727,7 +732,7 @@
|
||||
dispatch_async( dispatch_get_main_queue(), ^{
|
||||
[self.handleCloudContentAlert cancelAlertAnimated:YES];
|
||||
if (![self.storeLoading isVisible])
|
||||
self.storeLoading = [PearlOverlay showOverlayWithTitle:@"Loading Sites"];
|
||||
self.storeLoading = [PearlOverlay showProgressOverlayWithTitle:@"Loading Sites"];
|
||||
} );
|
||||
|
||||
[super ubiquityStoreManager:manager willLoadStoreIsCloud:isCloudStore];
|
||||
@ -739,32 +744,47 @@
|
||||
[MPiOSConfig get].iCloudEnabled = @(isCloudStore);
|
||||
[super ubiquityStoreManager:manager didLoadStoreForCoordinator:coordinator isCloud:isCloudStore];
|
||||
|
||||
dispatch_async( dispatch_get_main_queue(), ^{
|
||||
[self.handleCloudContentAlert cancelAlertAnimated:YES];
|
||||
[self.fixCloudContentAlert cancelAlertAnimated:YES];
|
||||
[self.storeLoading cancelOverlayAnimated:YES];
|
||||
} );
|
||||
[self.handleCloudContentAlert cancelAlertAnimated:YES];
|
||||
[self.fixCloudContentAlert cancelAlertAnimated:YES];
|
||||
[self.storeLoading cancelOverlayAnimated:YES];
|
||||
[self.handleCloudDisabledAlert cancelAlertAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager failedLoadingStoreWithCause:(UbiquityStoreErrorCause)cause context:(id)context
|
||||
wasCloud:(BOOL)wasCloudStore {
|
||||
|
||||
dispatch_async( dispatch_get_main_queue(), ^{
|
||||
[self.storeLoading cancelOverlayAnimated:YES];
|
||||
} );
|
||||
[self.storeLoading cancelOverlayAnimated:YES];
|
||||
[self.handleCloudDisabledAlert cancelAlertAnimated:YES];
|
||||
}
|
||||
|
||||
- (BOOL)ubiquityStoreManager:(UbiquityStoreManager *)manager handleCloudContentCorruptionWithHealthyStore:(BOOL)storeHealthy {
|
||||
|
||||
if (manager.cloudEnabled && !storeHealthy && !([self.handleCloudContentAlert.alertView isVisible] || [self.fixCloudContentAlert.alertView isVisible]))
|
||||
dispatch_async( dispatch_get_main_queue(), ^{
|
||||
[self.storeLoading cancelOverlayAnimated:YES];
|
||||
[self showCloudContentAlert];
|
||||
} );
|
||||
if (manager.cloudEnabled && !storeHealthy && !([self.handleCloudContentAlert.alertView isVisible] || [self.fixCloudContentAlert.alertView isVisible])) {
|
||||
[self.storeLoading cancelOverlayAnimated:YES];
|
||||
[self.handleCloudDisabledAlert cancelAlertAnimated:YES];
|
||||
[self showCloudContentAlert];
|
||||
};
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)ubiquityStoreManagerHandleCloudDisabled:(UbiquityStoreManager *)manager {
|
||||
|
||||
if (![self.handleCloudDisabledAlert isVisible])
|
||||
self.handleCloudDisabledAlert = [PearlAlert showAlertWithTitle:@"iCloud Login" message:
|
||||
@"You haven't added an iCloud account to your device yet.\n"
|
||||
@"To add one, tap 'Wait For Me', go into Apple's Settings and add an iCloud account."
|
||||
viewStyle:UIAlertViewStyleDefault initAlert:nil
|
||||
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
||||
if (buttonIndex == alert.firstOtherButtonIndex)
|
||||
return;
|
||||
|
||||
[self.storeManager reloadStore];
|
||||
} cancelTitle:@"Wait For Me" otherTitles:@"Disable iCloud", nil];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)showCloudContentAlert {
|
||||
|
||||
__weak MPiOSAppDelegate *wSelf = self;
|
||||
|
@ -71,9 +71,10 @@
|
||||
</dict>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>Exo-Bold.otf</string>
|
||||
<string>Exo-ExtraBold.otf</string>
|
||||
<string>Exo-Regular.otf</string>
|
||||
<string>Exo2.0-Bold.otf</string>
|
||||
<string>Exo2.0-ExtraBold.otf</string>
|
||||
<string>Exo2.0-Regular.otf</string>
|
||||
<string>Exo2.0-Thin.otf</string>
|
||||
<string>SourceCodePro-Black.otf</string>
|
||||
<string>SourceCodePro-ExtraLight.otf</string>
|
||||
</array>
|
||||
|
@ -12,27 +12,34 @@
|
||||
93D39262A8A97DB748213309 /* PearlEMail.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D393BB973253D4BAAC84AA /* PearlEMail.m */; };
|
||||
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */; };
|
||||
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */; };
|
||||
93D393543ACC701C018C74DA /* PearlUIView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D393676C32D23A47E27957 /* PearlUIView.m */; };
|
||||
93D394F6D3F6E2553AA0D684 /* MPPasswordStoredCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3947F6BB69CA9A9124A5D /* MPPasswordStoredCell.m */; };
|
||||
93D39392DEDA376F93C6C718 /* MPCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39BAA71DE51B4D8A1286C /* MPCell.m */; };
|
||||
93D393BA1B8402D08DB40231 /* MPPasswordElementCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39342E5F115EFCC90E976 /* MPPasswordElementCell.m */; };
|
||||
93D394F6D3F6E2553AA0D684 /* MPPasswordLargeStoredCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3947F6BB69CA9A9124A5D /* MPPasswordLargeStoredCell.m */; };
|
||||
93D3954E96236384AFA00453 /* UIScrollView+PearlAdjustInsets.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390FB3110DCCE68E600DC /* UIScrollView+PearlAdjustInsets.m */; };
|
||||
93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */; };
|
||||
93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B381350802A194BF332 /* MPAvatarCell.m */; };
|
||||
93D3959643EACF286D0152BA /* PearlUINavigationBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DDDAC305E8ABB4220C7 /* PearlUINavigationBar.m */; };
|
||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
|
||||
93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3956915634581E737B38C /* PearlNavigationController.m */; };
|
||||
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3942A356B639724157982 /* PearlOverlay.h */; };
|
||||
93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */; };
|
||||
93D3980046016EFD05B35BC5 /* PearlUICollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */; };
|
||||
93D399278165FD6D950F0025 /* MPPasswordTypesCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39097C0AAE62C1C321BFC /* MPPasswordTypesCell.m */; };
|
||||
93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; };
|
||||
93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; };
|
||||
93D399BBC0A7EC746CB1B19B /* MPLogsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D391943675426839501BB8 /* MPLogsViewController.h */; };
|
||||
93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */; };
|
||||
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D8A953779B35403AF6E /* PearlUICollectionView.m */; };
|
||||
93D39B76DD5AB108BA8928E8 /* UIScrollView+PearlAdjustInsets.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */; };
|
||||
93D39B842AB9A5D072810D76 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */; };
|
||||
93D39B8F90F58A5D158DDBA3 /* MPPasswordsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3924EE15017F8A12CB436 /* MPPasswordsViewController.m */; };
|
||||
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
|
||||
93D39C8AD8EAB747856B3A8C /* LLModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3923B42DA2DA18F287092 /* LLModel.m */; };
|
||||
93D39CB5E2EC1078E898F46A /* MPPasswordCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3937863061C3916AF7AD2 /* MPPasswordCell.m */; };
|
||||
93D39CB5E2EC1078E898F46A /* MPPasswordLargeCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3937863061C3916AF7AD2 /* MPPasswordLargeCell.m */; };
|
||||
93D39D596A2E376D6F6F5DA1 /* MPCombinedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D393310223DDB35218467A /* MPCombinedViewController.m */; };
|
||||
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
|
||||
93D39EDD960C381D64E4DCDD /* MPPasswordSmallCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3952CC60991B97D69F26A /* MPPasswordSmallCell.m */; };
|
||||
93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A28369954D147E239BA /* MPSetupViewController.m */; };
|
||||
93D39FA97F4C3F69A75D5A03 /* MPPasswordGeneratedCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3993422E207BF0B21D089 /* MPPasswordGeneratedCell.m */; };
|
||||
93D39FA97F4C3F69A75D5A03 /* MPPasswordLargeGeneratedCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3993422E207BF0B21D089 /* MPPasswordLargeGeneratedCell.m */; };
|
||||
DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */; };
|
||||
DA095E75172F4CD8001C948B /* MPLogsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3979190DACEBD1F6AE9F4 /* MPLogsViewController.m */; };
|
||||
DA2CA4DD18D28859007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */; };
|
||||
@ -69,11 +76,13 @@
|
||||
DA6701E016406BB400B61001 /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA6701DF16406BB400B61001 /* AdSupport.framework */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||
DA672D2F14F92C6B004A189C /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DA672D2E14F92C6B004A189C /* libz.dylib */; };
|
||||
DA672D3014F9413D004A189C /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
|
||||
DA67460D18DE7F0C00DFE240 /* Exo2.0-Thin.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA67460918DE7F0C00DFE240 /* Exo2.0-Thin.otf */; };
|
||||
DA67460E18DE7F0C00DFE240 /* Exo2.0-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA67460A18DE7F0C00DFE240 /* Exo2.0-Regular.otf */; };
|
||||
DA67460F18DE7F0C00DFE240 /* Exo2.0-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA67460B18DE7F0C00DFE240 /* Exo2.0-ExtraBold.otf */; };
|
||||
DA67461018DE7F0C00DFE240 /* Exo2.0-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA67460C18DE7F0C00DFE240 /* Exo2.0-Bold.otf */; };
|
||||
DA69540617D975D900BF294E /* icon_gears.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37841711E29500CF925C /* icon_gears.png */; };
|
||||
DA69540717D975D900BF294E /* icon_gears@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37851711E29500CF925C /* icon_gears@2x.png */; };
|
||||
DA70EC801811B13C00F65DB2 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA70EC7F1811B13C00F65DB2 /* StoreKit.framework */; };
|
||||
DA829E52159847E0002417D3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||
DA829E6215984832002417D3 /* libFontReplacer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA829E51159847E0002417D3 /* libFontReplacer.a */; };
|
||||
DA854C8318D4CFBF00106317 /* avatar-add@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA854C8118D4CFBF00106317 /* avatar-add@2x.png */; };
|
||||
DA854C8418D4CFBF00106317 /* avatar-add.png in Resources */ = {isa = PBXBuildFile; fileRef = DA854C8218D4CFBF00106317 /* avatar-add.png */; };
|
||||
DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA945C8617E3F3FD0053236B /* Images.xcassets */; };
|
||||
@ -147,9 +156,6 @@
|
||||
DABD395C1711E29700CF925C /* avatar-9@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD36911711E29400CF925C /* avatar-9@2x.png */; };
|
||||
DABD395D1711E29700CF925C /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD36931711E29400CF925C /* background.png */; };
|
||||
DABD395E1711E29700CF925C /* background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD36941711E29400CF925C /* background@2x.png */; };
|
||||
DABD39841711E29700CF925C /* Exo-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = DABD36BC1711E29500CF925C /* Exo-Bold.otf */; };
|
||||
DABD39851711E29700CF925C /* Exo-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = DABD36BD1711E29500CF925C /* Exo-ExtraBold.otf */; };
|
||||
DABD39861711E29700CF925C /* Exo-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DABD36BE1711E29500CF925C /* Exo-Regular.otf */; };
|
||||
DABD39871711E29700CF925C /* SourceCodePro-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = DABD36BF1711E29500CF925C /* SourceCodePro-Black.otf */; };
|
||||
DABD39881711E29700CF925C /* SourceCodePro-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = DABD36C01711E29500CF925C /* SourceCodePro-ExtraLight.otf */; };
|
||||
DABD39A01711E29700CF925C /* icon_action.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD36DA1711E29500CF925C /* icon_action.png */; };
|
||||
@ -243,8 +249,6 @@
|
||||
DAC6326D148680650075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||
DAC632891486D9690075AEA5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC632871486D95D0075AEA5 /* Security.framework */; };
|
||||
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||
DACA22161705DE13002C6C22 /* UIFont+Replacement.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA22141705DE13002C6C22 /* UIFont+Replacement.m */; };
|
||||
DACA22171705DE13002C6C22 /* UIFont+Replacement.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA22151705DE13002C6C22 /* UIFont+Replacement.h */; };
|
||||
DACA22191705DE28002C6C22 /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DACA22181705DE28002C6C22 /* Crashlytics.framework */; };
|
||||
DACA22BB1705DE7D002C6C22 /* UbiquityStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA22B71705DE7D002C6C22 /* UbiquityStoreManager.m */; };
|
||||
DACA22BC1705DE7D002C6C22 /* NSError+UbiquityStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */; };
|
||||
@ -373,6 +377,10 @@
|
||||
DAEB938218AA537D000490CC /* x509_vfy.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB933118AA537D000490CC /* x509_vfy.h */; };
|
||||
DAEB938318AA537D000490CC /* x509v3.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB933218AA537D000490CC /* x509v3.h */; };
|
||||
DAEBC45314F6364500987BF6 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
|
||||
DAEC85B518E3DD9A007FC0DF /* PearlUIView.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEC85B118E3DD9A007FC0DF /* PearlUIView.m */; };
|
||||
DAEC85B618E3DD9A007FC0DF /* PearlUINavigationBar.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEC85B218E3DD9A007FC0DF /* PearlUINavigationBar.m */; };
|
||||
DAEC85B718E3DD9A007FC0DF /* PearlUINavigationBar.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEC85B318E3DD9A007FC0DF /* PearlUINavigationBar.h */; };
|
||||
DAEC85B818E3DD9A007FC0DF /* PearlUIView.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEC85B418E3DD9A007FC0DF /* PearlUIView.h */; };
|
||||
DAFC5656172C573B00CB5CC5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||
DAFC5683172C57EC00CB5CC5 /* IASKAppSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC5665172C57EC00CB5CC5 /* IASKAppSettingsViewController.m */; };
|
||||
DAFC5684172C57EC00CB5CC5 /* IASKAppSettingsWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC5667172C57EC00CB5CC5 /* IASKAppSettingsWebViewController.m */; };
|
||||
@ -502,46 +510,56 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
93D390519405B76CC6A57C4F /* MPCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCell.h; sourceTree = "<group>"; };
|
||||
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; };
|
||||
93D39083C93D90C4B94541AD /* PearlUIView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUIView.h; sourceTree = "<group>"; };
|
||||
93D39097C0AAE62C1C321BFC /* MPPasswordTypesCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordTypesCell.m; sourceTree = "<group>"; };
|
||||
93D390A66F69AB1CDB0BFF93 /* LLModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLModel.h; sourceTree = "<group>"; };
|
||||
93D390EEC85E94D9C888643F /* PearlUINavigationBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUINavigationBar.h; sourceTree = "<group>"; };
|
||||
93D390FADEB325D8D54A957D /* PearlOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlOverlay.m; sourceTree = "<group>"; };
|
||||
93D390FB3110DCCE68E600DC /* UIScrollView+PearlAdjustInsets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+PearlAdjustInsets.m"; sourceTree = "<group>"; };
|
||||
93D391243F64A77798B4D6A4 /* MPPasswordTypesCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordTypesCell.h; sourceTree = "<group>"; };
|
||||
93D3914D7597F9A28DB9D85E /* MPPasswordsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordsViewController.h; sourceTree = "<group>"; };
|
||||
93D391943675426839501BB8 /* MPLogsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLogsViewController.h; sourceTree = "<group>"; };
|
||||
93D3923B42DA2DA18F287092 /* LLModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLModel.m; sourceTree = "<group>"; };
|
||||
93D3924EE15017F8A12CB436 /* MPPasswordsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordsViewController.m; sourceTree = "<group>"; };
|
||||
93D3932D6C25F2C2D929F8A1 /* MPPasswordElementCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordElementCell.h; sourceTree = "<group>"; };
|
||||
93D393310223DDB35218467A /* MPCombinedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCombinedViewController.m; sourceTree = "<group>"; };
|
||||
93D393676C32D23A47E27957 /* PearlUIView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUIView.m; sourceTree = "<group>"; };
|
||||
93D3937863061C3916AF7AD2 /* MPPasswordCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordCell.m; sourceTree = "<group>"; };
|
||||
93D39342E5F115EFCC90E976 /* MPPasswordElementCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordElementCell.m; sourceTree = "<group>"; };
|
||||
93D3937863061C3916AF7AD2 /* MPPasswordLargeCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeCell.m; sourceTree = "<group>"; };
|
||||
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
|
||||
93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; };
|
||||
93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
|
||||
93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = "<group>"; };
|
||||
93D3947F6BB69CA9A9124A5D /* MPPasswordStoredCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordStoredCell.m; sourceTree = "<group>"; };
|
||||
93D3947F6BB69CA9A9124A5D /* MPPasswordLargeStoredCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeStoredCell.m; sourceTree = "<group>"; };
|
||||
93D3952CC60991B97D69F26A /* MPPasswordSmallCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordSmallCell.m; sourceTree = "<group>"; };
|
||||
93D3956915634581E737B38C /* PearlNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlNavigationController.m; sourceTree = "<group>"; };
|
||||
93D395BA6B2CFF5F49A4D25F /* MPPasswordStoredCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordStoredCell.h; sourceTree = "<group>"; };
|
||||
93D395BA6B2CFF5F49A4D25F /* MPPasswordLargeStoredCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeStoredCell.h; sourceTree = "<group>"; };
|
||||
93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = "<group>"; };
|
||||
93D3971FE104BB4052484151 /* MPUsersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUsersViewController.h; sourceTree = "<group>"; };
|
||||
93D39730673227EFF6DEFF19 /* MPSetupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSetupViewController.h; sourceTree = "<group>"; };
|
||||
93D3979190DACEBD1F6AE9F4 /* MPLogsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPLogsViewController.m; sourceTree = "<group>"; };
|
||||
93D3983278751A530262F64E /* LLConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLConfig.h; sourceTree = "<group>"; };
|
||||
93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlNavigationController.h; sourceTree = "<group>"; };
|
||||
93D39888EE06F06264CC963B /* MPPasswordSmallCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordSmallCell.h; sourceTree = "<group>"; };
|
||||
93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; };
|
||||
93D3993422E207BF0B21D089 /* MPPasswordGeneratedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordGeneratedCell.m; sourceTree = "<group>"; };
|
||||
93D3993422E207BF0B21D089 /* MPPasswordLargeGeneratedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeGeneratedCell.m; sourceTree = "<group>"; };
|
||||
93D39975CE5AEC99E3F086C7 /* MPPasswordCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordCell.h; sourceTree = "<group>"; };
|
||||
93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUsersViewController.m; sourceTree = "<group>"; };
|
||||
93D39A28369954D147E239BA /* MPSetupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSetupViewController.m; sourceTree = "<group>"; };
|
||||
93D39A3CC4D8330831FC8CB4 /* LLToggleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLToggleViewController.h; sourceTree = "<group>"; };
|
||||
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = "<group>"; };
|
||||
93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUICollectionView.h; sourceTree = "<group>"; };
|
||||
93D39B381350802A194BF332 /* MPAvatarCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAvatarCell.m; sourceTree = "<group>"; };
|
||||
93D39BA6C5CB452973918B7D /* LLButtonView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLButtonView.h; sourceTree = "<group>"; };
|
||||
93D39BAA71DE51B4D8A1286C /* MPCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCell.m; sourceTree = "<group>"; };
|
||||
93D39BF6BCBDFFE844E7D34C /* LLButtonView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLButtonView.m; sourceTree = "<group>"; };
|
||||
93D39C8E26B06F01566785B7 /* LLToggleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLToggleViewController.m; sourceTree = "<group>"; };
|
||||
93D39CE1138FDA4D3D1B847A /* MPPasswordGeneratedCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordGeneratedCell.h; sourceTree = "<group>"; };
|
||||
93D39CE1138FDA4D3D1B847A /* MPPasswordLargeGeneratedCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeGeneratedCell.h; sourceTree = "<group>"; };
|
||||
93D39CF8ADF4542CDC4CD385 /* MPCombinedViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCombinedViewController.h; sourceTree = "<group>"; };
|
||||
93D39D8A953779B35403AF6E /* PearlUICollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUICollectionView.m; sourceTree = "<group>"; };
|
||||
93D39DA27D768B53C8B1330C /* MPAvatarCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAvatarCell.h; sourceTree = "<group>"; };
|
||||
93D39DDDAC305E8ABB4220C7 /* PearlUINavigationBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUINavigationBar.m; sourceTree = "<group>"; };
|
||||
93D39E02F69CACAB61C056F8 /* MPPasswordCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordCell.h; sourceTree = "<group>"; };
|
||||
93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+PearlAdjustInsets.h"; sourceTree = "<group>"; };
|
||||
93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordCell.m; sourceTree = "<group>"; };
|
||||
93D39E02F69CACAB61C056F8 /* MPPasswordLargeCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeCell.h; sourceTree = "<group>"; };
|
||||
93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlEMail.h; sourceTree = "<group>"; };
|
||||
93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; };
|
||||
DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
|
||||
@ -579,8 +597,11 @@
|
||||
DA6701DD16406B7300B61001 /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; };
|
||||
DA6701DF16406BB400B61001 /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; };
|
||||
DA672D2E14F92C6B004A189C /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||
DA67460918DE7F0C00DFE240 /* Exo2.0-Thin.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo2.0-Thin.otf"; sourceTree = "<group>"; };
|
||||
DA67460A18DE7F0C00DFE240 /* Exo2.0-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo2.0-Regular.otf"; sourceTree = "<group>"; };
|
||||
DA67460B18DE7F0C00DFE240 /* Exo2.0-ExtraBold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo2.0-ExtraBold.otf"; sourceTree = "<group>"; };
|
||||
DA67460C18DE7F0C00DFE240 /* Exo2.0-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo2.0-Bold.otf"; sourceTree = "<group>"; };
|
||||
DA70EC7F1811B13C00F65DB2 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
|
||||
DA829E51159847E0002417D3 /* libFontReplacer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFontReplacer.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DA854C8118D4CFBF00106317 /* avatar-add@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-add@2x.png"; sourceTree = "<group>"; };
|
||||
DA854C8218D4CFBF00106317 /* avatar-add.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-add.png"; sourceTree = "<group>"; };
|
||||
DA945C8617E3F3FD0053236B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
@ -722,9 +743,6 @@
|
||||
DABD36911711E29400CF925C /* avatar-9@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-9@2x.png"; sourceTree = "<group>"; };
|
||||
DABD36931711E29400CF925C /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = background.png; sourceTree = "<group>"; };
|
||||
DABD36941711E29400CF925C /* background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "background@2x.png"; sourceTree = "<group>"; };
|
||||
DABD36BC1711E29500CF925C /* Exo-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo-Bold.otf"; sourceTree = "<group>"; };
|
||||
DABD36BD1711E29500CF925C /* Exo-ExtraBold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo-ExtraBold.otf"; sourceTree = "<group>"; };
|
||||
DABD36BE1711E29500CF925C /* Exo-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo-Regular.otf"; sourceTree = "<group>"; };
|
||||
DABD36BF1711E29500CF925C /* SourceCodePro-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Black.otf"; sourceTree = "<group>"; };
|
||||
DABD36C01711E29500CF925C /* SourceCodePro-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-ExtraLight.otf"; sourceTree = "<group>"; };
|
||||
DABD36DA1711E29500CF925C /* icon_action.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_action.png; sourceTree = "<group>"; };
|
||||
@ -1305,8 +1323,6 @@
|
||||
DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
||||
DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Pearl-Prefix.pch"; path = "../../MasterPassword/ObjC/Pearl/Pearl-Prefix.pch"; sourceTree = "<group>"; };
|
||||
DACA22141705DE13002C6C22 /* UIFont+Replacement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIFont+Replacement.m"; sourceTree = "<group>"; };
|
||||
DACA22151705DE13002C6C22 /* UIFont+Replacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIFont+Replacement.h"; sourceTree = "<group>"; };
|
||||
DACA22181705DE28002C6C22 /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Crashlytics.framework; sourceTree = "<group>"; };
|
||||
DACA22B71705DE7D002C6C22 /* UbiquityStoreManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UbiquityStoreManager.m; sourceTree = "<group>"; };
|
||||
DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+UbiquityStoreManager.h"; sourceTree = "<group>"; };
|
||||
@ -1439,6 +1455,10 @@
|
||||
DAEB933118AA537D000490CC /* x509_vfy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509_vfy.h; sourceTree = "<group>"; };
|
||||
DAEB933218AA537D000490CC /* x509v3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509v3.h; sourceTree = "<group>"; };
|
||||
DAEBC45214F6364500987BF6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
||||
DAEC85B118E3DD9A007FC0DF /* PearlUIView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUIView.m; sourceTree = "<group>"; };
|
||||
DAEC85B218E3DD9A007FC0DF /* PearlUINavigationBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUINavigationBar.m; sourceTree = "<group>"; };
|
||||
DAEC85B318E3DD9A007FC0DF /* PearlUINavigationBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUINavigationBar.h; sourceTree = "<group>"; };
|
||||
DAEC85B418E3DD9A007FC0DF /* PearlUIView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUIView.h; sourceTree = "<group>"; };
|
||||
DAFC5655172C573B00CB5CC5 /* libInAppSettingsKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libInAppSettingsKit.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DAFC5659172C573B00CB5CC5 /* InAppSettingsKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "InAppSettingsKit-Prefix.pch"; sourceTree = "<group>"; };
|
||||
DAFC565A172C573B00CB5CC5 /* InAppSettingsKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InAppSettingsKit.h; sourceTree = "<group>"; };
|
||||
@ -1585,7 +1605,6 @@
|
||||
DA6701E016406BB400B61001 /* AdSupport.framework in Frameworks */,
|
||||
DA6701DE16406B7300B61001 /* Social.framework in Frameworks */,
|
||||
DA6701B816406A4100B61001 /* Accounts.framework in Frameworks */,
|
||||
DA829E6215984832002417D3 /* libFontReplacer.a in Frameworks */,
|
||||
DA44260A1557D9E40052177D /* libUbiquityStoreManager.a in Frameworks */,
|
||||
DAD312C21552A22700A3F9ED /* libsqlite3.dylib in Frameworks */,
|
||||
DAD312BF1552A1BD00A3F9ED /* libLocalytics.a in Frameworks */,
|
||||
@ -1608,14 +1627,6 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DA829E4E159847E0002417D3 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DA829E52159847E0002417D3 /* Foundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DAC6325A1486805C0075AEA5 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -1688,14 +1699,8 @@
|
||||
DAFC5657172C573B00CB5CC5 /* InAppSettingsKit */,
|
||||
DA5BFA47147E415C00F98B1E /* Frameworks */,
|
||||
DA5BFA45147E415C00F98B1E /* Products */,
|
||||
93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */,
|
||||
93D3971FE104BB4052484151 /* MPUsersViewController.h */,
|
||||
93D393676C32D23A47E27957 /* PearlUIView.m */,
|
||||
93D39083C93D90C4B94541AD /* PearlUIView.h */,
|
||||
93D39E02F69CACAB61C056F8 /* MPPasswordCell.h */,
|
||||
93D3937863061C3916AF7AD2 /* MPPasswordCell.m */,
|
||||
93D395BA6B2CFF5F49A4D25F /* MPPasswordStoredCell.h */,
|
||||
93D3947F6BB69CA9A9124A5D /* MPPasswordStoredCell.m */,
|
||||
93D39975CE5AEC99E3F086C7 /* MPPasswordCell.h */,
|
||||
93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@ -1708,7 +1713,6 @@
|
||||
DAC6326C148680650075AEA5 /* libjrswizzle.a */,
|
||||
DAD3127115528CD200A3F9ED /* libLocalytics.a */,
|
||||
DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */,
|
||||
DA829E51159847E0002417D3 /* libFontReplacer.a */,
|
||||
DAFC5655172C573B00CB5CC5 /* libInAppSettingsKit.a */,
|
||||
DAE1EF2917ED112600BC0086 /* libDCIntrospect.a */,
|
||||
DADEF4221810D5530052CA3E /* libLoveLyndir.a */,
|
||||
@ -1965,9 +1969,10 @@
|
||||
DABD36BB1711E29500CF925C /* Fonts */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DABD36BC1711E29500CF925C /* Exo-Bold.otf */,
|
||||
DABD36BD1711E29500CF925C /* Exo-ExtraBold.otf */,
|
||||
DABD36BE1711E29500CF925C /* Exo-Regular.otf */,
|
||||
DA67460918DE7F0C00DFE240 /* Exo2.0-Thin.otf */,
|
||||
DA67460A18DE7F0C00DFE240 /* Exo2.0-Regular.otf */,
|
||||
DA67460B18DE7F0C00DFE240 /* Exo2.0-ExtraBold.otf */,
|
||||
DA67460C18DE7F0C00DFE240 /* Exo2.0-Bold.otf */,
|
||||
DABD36BF1711E29500CF925C /* SourceCodePro-Black.otf */,
|
||||
DABD36C01711E29500CF925C /* SourceCodePro-ExtraLight.otf */,
|
||||
);
|
||||
@ -2552,10 +2557,22 @@
|
||||
DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */,
|
||||
93D39B381350802A194BF332 /* MPAvatarCell.m */,
|
||||
93D39DA27D768B53C8B1330C /* MPAvatarCell.h */,
|
||||
93D39DDDAC305E8ABB4220C7 /* PearlUINavigationBar.m */,
|
||||
93D390EEC85E94D9C888643F /* PearlUINavigationBar.h */,
|
||||
93D3993422E207BF0B21D089 /* MPPasswordGeneratedCell.m */,
|
||||
93D39CE1138FDA4D3D1B847A /* MPPasswordGeneratedCell.h */,
|
||||
93D3993422E207BF0B21D089 /* MPPasswordLargeGeneratedCell.m */,
|
||||
93D39CE1138FDA4D3D1B847A /* MPPasswordLargeGeneratedCell.h */,
|
||||
93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */,
|
||||
93D3971FE104BB4052484151 /* MPUsersViewController.h */,
|
||||
93D39E02F69CACAB61C056F8 /* MPPasswordLargeCell.h */,
|
||||
93D3937863061C3916AF7AD2 /* MPPasswordLargeCell.m */,
|
||||
93D395BA6B2CFF5F49A4D25F /* MPPasswordLargeStoredCell.h */,
|
||||
93D3947F6BB69CA9A9124A5D /* MPPasswordLargeStoredCell.m */,
|
||||
93D39BAA71DE51B4D8A1286C /* MPCell.m */,
|
||||
93D390519405B76CC6A57C4F /* MPCell.h */,
|
||||
93D39097C0AAE62C1C321BFC /* MPPasswordTypesCell.m */,
|
||||
93D391243F64A77798B4D6A4 /* MPPasswordTypesCell.h */,
|
||||
93D3952CC60991B97D69F26A /* MPPasswordSmallCell.m */,
|
||||
93D39888EE06F06264CC963B /* MPPasswordSmallCell.h */,
|
||||
93D39342E5F115EFCC90E976 /* MPPasswordElementCell.m */,
|
||||
93D3932D6C25F2C2D929F8A1 /* MPPasswordElementCell.h */,
|
||||
);
|
||||
path = iOS;
|
||||
sourceTree = "<group>";
|
||||
@ -2581,7 +2598,6 @@
|
||||
DABF632217B744F900DA7E38 /* GoogleOpenSource.framework */,
|
||||
DABF632317B744F900DA7E38 /* GooglePlus.framework */,
|
||||
DACA22181705DE28002C6C22 /* Crashlytics.framework */,
|
||||
DACA22131705DE13002C6C22 /* UIFont+Replacement */,
|
||||
DAFC5662172C57EC00CB5CC5 /* InAppSettingsKit */,
|
||||
DACA22C71705DEB0002C6C22 /* Localytics */,
|
||||
DAC77CAF148291A600BCF976 /* Pearl */,
|
||||
@ -2592,16 +2608,6 @@
|
||||
path = ../../../External;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DACA22131705DE13002C6C22 /* UIFont+Replacement */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DACA22141705DE13002C6C22 /* UIFont+Replacement.m */,
|
||||
DACA22151705DE13002C6C22 /* UIFont+Replacement.h */,
|
||||
);
|
||||
name = "UIFont+Replacement";
|
||||
path = "FontReplacer/UIFont+Replacement";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DACA22B61705DE7D002C6C22 /* UbiquityStoreManager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -3045,6 +3051,10 @@
|
||||
DAFE460715039823003ABA7C /* Pearl-UIKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DAEC85B118E3DD9A007FC0DF /* PearlUIView.m */,
|
||||
DAEC85B218E3DD9A007FC0DF /* PearlUINavigationBar.m */,
|
||||
DAEC85B318E3DD9A007FC0DF /* PearlUINavigationBar.h */,
|
||||
DAEC85B418E3DD9A007FC0DF /* PearlUIView.h */,
|
||||
DA2CA4E518D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m */,
|
||||
DA2CA4E218D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h */,
|
||||
93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */,
|
||||
@ -3094,6 +3104,10 @@
|
||||
93D3942A356B639724157982 /* PearlOverlay.h */,
|
||||
93D3956915634581E737B38C /* PearlNavigationController.m */,
|
||||
93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */,
|
||||
93D390FB3110DCCE68E600DC /* UIScrollView+PearlAdjustInsets.m */,
|
||||
93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */,
|
||||
93D39D8A953779B35403AF6E /* PearlUICollectionView.m */,
|
||||
93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */,
|
||||
);
|
||||
path = "Pearl-UIKit";
|
||||
sourceTree = "<group>";
|
||||
@ -3118,14 +3132,6 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DA829E4F159847E0002417D3 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DACA22171705DE13002C6C22 /* UIFont+Replacement.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DAC6325B1486805C0075AEA5 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -3207,6 +3213,7 @@
|
||||
DAEB933C18AA537D000490CC /* aes.h in Headers */,
|
||||
DAEB937618AA537D000490CC /* ssl2.h in Headers */,
|
||||
DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */,
|
||||
DAEC85B818E3DD9A007FC0DF /* PearlUIView.h in Headers */,
|
||||
DAEB935B18AA537D000490CC /* krb5_asn.h in Headers */,
|
||||
DAEB935818AA537D000490CC /* evp.h in Headers */,
|
||||
DAEB934118AA537D000490CC /* blowfish.h in Headers */,
|
||||
@ -3275,6 +3282,7 @@
|
||||
DAEB935C18AA537D000490CC /* kssl.h in Headers */,
|
||||
DAEB933418AA537D000490CC /* crypto_scrypt.h in Headers */,
|
||||
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */,
|
||||
DAEC85B718E3DD9A007FC0DF /* PearlUINavigationBar.h in Headers */,
|
||||
DAEB934918AA537D000490CC /* conf_api.h in Headers */,
|
||||
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */,
|
||||
DAEB937518AA537D000490CC /* ssl.h in Headers */,
|
||||
@ -3282,6 +3290,8 @@
|
||||
93D39B842AB9A5D072810D76 /* NSError+PearlFullDescription.h in Headers */,
|
||||
DAEB936218AA537D000490CC /* obj_mac.h in Headers */,
|
||||
DAEB934218AA537D000490CC /* bn.h in Headers */,
|
||||
93D39B76DD5AB108BA8928E8 /* UIScrollView+PearlAdjustInsets.h in Headers */,
|
||||
93D3980046016EFD05B35BC5 /* PearlUICollectionView.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -3324,6 +3334,7 @@
|
||||
DA5BFA40147E415C00F98B1E /* Sources */,
|
||||
DA5BFA41147E415C00F98B1E /* Frameworks */,
|
||||
DA5BFA42147E415C00F98B1E /* Resources */,
|
||||
DA67460818DE7B2C00DFE240 /* Run Script: Moarfonts */,
|
||||
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */,
|
||||
DAD3125D155288AA00A3F9ED /* Run Script: Crashlytics */,
|
||||
);
|
||||
@ -3336,23 +3347,6 @@
|
||||
productReference = DA5BFA44147E415C00F98B1E /* MasterPassword.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
DA829E50159847E0002417D3 /* FontReplacer */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DA829E59159847E0002417D3 /* Build configuration list for PBXNativeTarget "FontReplacer" */;
|
||||
buildPhases = (
|
||||
DA829E4D159847E0002417D3 /* Sources */,
|
||||
DA829E4E159847E0002417D3 /* Frameworks */,
|
||||
DA829E4F159847E0002417D3 /* Headers */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = FontReplacer;
|
||||
productName = FontReplacer;
|
||||
productReference = DA829E51159847E0002417D3 /* libFontReplacer.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
DAC6325C1486805C0075AEA5 /* uicolor-utilities */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DAC632651486805C0075AEA5 /* Build configuration list for PBXNativeTarget "uicolor-utilities" */;
|
||||
@ -3597,7 +3591,6 @@
|
||||
DAC6326B148680650075AEA5 /* jrswizzle */,
|
||||
DAD3127015528CD200A3F9ED /* Localytics */,
|
||||
DA4425CA1557BED40052177D /* UbiquityStoreManager */,
|
||||
DA829E50159847E0002417D3 /* FontReplacer */,
|
||||
DAFC5654172C573B00CB5CC5 /* InAppSettingsKit */,
|
||||
DAE1EF2817ED112600BC0086 /* DCIntrospect */,
|
||||
DADEF4211810D5530052CA3E /* LoveLyndir */,
|
||||
@ -3642,6 +3635,7 @@
|
||||
DABD391D1711E29700CF925C /* ui_spinner.png in Resources */,
|
||||
DABD391E1711E29700CF925C /* ui_spinner@2x.png in Resources */,
|
||||
DA69540617D975D900BF294E /* icon_gears.png in Resources */,
|
||||
DA67460D18DE7F0C00DFE240 /* Exo2.0-Thin.otf in Resources */,
|
||||
DABD39271711E29700CF925C /* ui_textfield.png in Resources */,
|
||||
DABD39281711E29700CF925C /* ui_textfield@2x.png in Resources */,
|
||||
DABD39291711E29700CF925C /* ui_toolbar_container.png in Resources */,
|
||||
@ -3656,6 +3650,7 @@
|
||||
DABD393D1711E29700CF925C /* avatar-11@2x.png in Resources */,
|
||||
DABD393E1711E29700CF925C /* avatar-12.png in Resources */,
|
||||
DABD393F1711E29700CF925C /* avatar-12@2x.png in Resources */,
|
||||
DA67461018DE7F0C00DFE240 /* Exo2.0-Bold.otf in Resources */,
|
||||
DABD39401711E29700CF925C /* avatar-13.png in Resources */,
|
||||
DABD39411711E29700CF925C /* avatar-13@2x.png in Resources */,
|
||||
DABD39421711E29700CF925C /* avatar-14.png in Resources */,
|
||||
@ -3670,9 +3665,11 @@
|
||||
DABD394A1711E29700CF925C /* avatar-18.png in Resources */,
|
||||
DABD394B1711E29700CF925C /* avatar-18@2x.png in Resources */,
|
||||
DABD394C1711E29700CF925C /* avatar-1@2x.png in Resources */,
|
||||
DA67460E18DE7F0C00DFE240 /* Exo2.0-Regular.otf in Resources */,
|
||||
DABD394D1711E29700CF925C /* avatar-2.png in Resources */,
|
||||
DABD394E1711E29700CF925C /* avatar-2@2x.png in Resources */,
|
||||
DABD394F1711E29700CF925C /* avatar-3.png in Resources */,
|
||||
DA67460F18DE7F0C00DFE240 /* Exo2.0-ExtraBold.otf in Resources */,
|
||||
DABD39501711E29700CF925C /* avatar-3@2x.png in Resources */,
|
||||
DABD39511711E29700CF925C /* avatar-4.png in Resources */,
|
||||
DABD39521711E29700CF925C /* avatar-4@2x.png in Resources */,
|
||||
@ -3689,9 +3686,6 @@
|
||||
DABD395C1711E29700CF925C /* avatar-9@2x.png in Resources */,
|
||||
DABD395D1711E29700CF925C /* background.png in Resources */,
|
||||
DABD395E1711E29700CF925C /* background@2x.png in Resources */,
|
||||
DABD39841711E29700CF925C /* Exo-Bold.otf in Resources */,
|
||||
DABD39851711E29700CF925C /* Exo-ExtraBold.otf in Resources */,
|
||||
DABD39861711E29700CF925C /* Exo-Regular.otf in Resources */,
|
||||
DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */,
|
||||
DABD39871711E29700CF925C /* SourceCodePro-Black.otf in Resources */,
|
||||
DADEF4161810D2940052CA3E /* love-lyndir.button.red.png in Resources */,
|
||||
@ -3794,6 +3788,21 @@
|
||||
shellPath = "/bin/bash -e";
|
||||
shellScript = "PATH+=:/usr/libexec\n\naddPlistWithKey() {\n local key=$1 type=$2 value=$3 plist=${4:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Delete :'$key'\" \"$plist\" 2>/dev/null || true\n PlistBuddy -c \"Add :'$key' '$type' '$value'\" \"$plist\"\n}\nsetPlistWithKey() {\n local key=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Set :'$key' '$value'\" \"$plist\"\n}\ngetPlistWithKey() {\n local key=$1 plist=${2:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Print :'$key'\" \"$plist\"\n}\nsetSettingWithTitle() {\n local i title=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Settings.bundle/Root.plist\"}\n \n for (( i=0; 1; ++i )); do\n PlistBuddy -c \"Print :PreferenceSpecifiers:$i\" \"$plist\" &>/dev/null || break\n echo \"Checking preference specifier $i\"\n \n [[ $(PlistBuddy -c \"Print :PreferenceSpecifiers:$i:Title\" \"$plist\" 2>/dev/null) = $title ]] || continue\n \n echo \"Correct title, setting value.\"\n PlistBuddy -c \"Set :PreferenceSpecifiers:$i:DefaultValue $value\" \"$plist\"\n break\n done\n}\n\ndescription=$(git describe --always --dirty --long)\nversion=${description%-g*}\nIFS=- read major minor <<< \"$version\"\nprintf -v version '%s.%02d' \"$major\" \"$minor\"\nprintf -v commit '%09d' \"$((16#${description##*-g}))\"\n\naddPlistWithKey GITDescription string \"$description\"\nsetPlistWithKey CFBundleVersion \"${version//.}$commit\" # No separator between version and commit because I had already submitted a CFBundleVersion with a really high major. Cry.\nsetPlistWithKey CFBundleShortVersionString \"$version\"\n\nsetSettingWithTitle \"Build\" \"$commit\"\nsetSettingWithTitle \"Version\" \"$version\"\nsetSettingWithTitle \"Copyright\" \"$(getPlistWithKey NSHumanReadableCopyright)\"\n\nif [[ $DEPLOYMENT_LOCATION = YES ]]; then\n # This build is a release. Do some release checks.\n passed=1\n [[ $description != *-dirty ]] || \\\n { passed=0; echo >&2 \"ERROR: Cannot release a dirty version, first commit any changes.\"; }\n [[ $(PlistBuddy -c \"Print :'API Key'\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Crashlytics.plist\") ]] || \\\n { passed=0; echo >&2 \"ERROR: Cannot release: Crashlytics API key is missing.\"; }\n [[ $(PlistBuddy -c \"Print :'ClientID'\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Google+.plist\") ]] || \\\n { passed=0; echo >&2 \"ERROR: Cannot release: Google+ ClientID is missing.\"; }\n [[ $(PlistBuddy -c \"Print :'Key.distribution'\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Localytics.plist\") ]] || \\\n { passed=0; echo >&2 \"ERROR: Cannot release: Localytics distribution key is missing.\"; }\n (( passed )) || \\\n { echo >&2 \"Failed to pass release checks. Fix the above errors and re-try. Aborting.\"; exit 1; }\nfi";
|
||||
};
|
||||
DA67460818DE7B2C00DFE240 /* Run Script: Moarfonts */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Script: Moarfonts";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = "/bin/bash -e";
|
||||
shellScript = "[[ -x /usr/local/bin/moarfonts ]] || {\n echo >&2 \"moarfonts not installed, embedded fonts will not show up in IB.\"\n exit\n}\n\nfind \"${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}\" -name '*.otf' -exec /usr/local/bin/moarfonts install {} +";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
DAD3125D155288AA00A3F9ED /* Run Script: Crashlytics */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -3858,19 +3867,14 @@
|
||||
93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */,
|
||||
93D39B8F90F58A5D158DDBA3 /* MPPasswordsViewController.m in Sources */,
|
||||
93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */,
|
||||
93D3959643EACF286D0152BA /* PearlUINavigationBar.m in Sources */,
|
||||
93D393543ACC701C018C74DA /* PearlUIView.m in Sources */,
|
||||
93D39CB5E2EC1078E898F46A /* MPPasswordCell.m in Sources */,
|
||||
93D39FA97F4C3F69A75D5A03 /* MPPasswordGeneratedCell.m in Sources */,
|
||||
93D394F6D3F6E2553AA0D684 /* MPPasswordStoredCell.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DA829E4D159847E0002417D3 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DACA22161705DE13002C6C22 /* UIFont+Replacement.m in Sources */,
|
||||
93D39CB5E2EC1078E898F46A /* MPPasswordLargeCell.m in Sources */,
|
||||
93D39FA97F4C3F69A75D5A03 /* MPPasswordLargeGeneratedCell.m in Sources */,
|
||||
93D394F6D3F6E2553AA0D684 /* MPPasswordLargeStoredCell.m in Sources */,
|
||||
93D39392DEDA376F93C6C718 /* MPCell.m in Sources */,
|
||||
93D399278165FD6D950F0025 /* MPPasswordTypesCell.m in Sources */,
|
||||
93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */,
|
||||
93D39EDD960C381D64E4DCDD /* MPPasswordSmallCell.m in Sources */,
|
||||
93D393BA1B8402D08DB40231 /* MPPasswordElementCell.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -3924,6 +3928,7 @@
|
||||
DAFE4A5115039824003ABA7C /* PearlUIDebug.m in Sources */,
|
||||
DAFE4A5315039824003ABA7C /* PearlUIUtils.m in Sources */,
|
||||
DAFE4A5515039824003ABA7C /* PearlValidatingTextField.m in Sources */,
|
||||
DAEC85B618E3DD9A007FC0DF /* PearlUINavigationBar.m in Sources */,
|
||||
DAFE4A5715039824003ABA7C /* PearlWebViewController.m in Sources */,
|
||||
DAFE4A5915039824003ABA7C /* UIImage+PearlScaling.m in Sources */,
|
||||
DAFE4A62150399FF003ABA7C /* PearlAppDelegate.m in Sources */,
|
||||
@ -3934,6 +3939,7 @@
|
||||
DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */,
|
||||
DAFE4A63150399FF003ABA82 /* UIControl+PearlBlocks.m in Sources */,
|
||||
DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */,
|
||||
DAEC85B518E3DD9A007FC0DF /* PearlUIView.m in Sources */,
|
||||
DA2CA4DD18D28859007798F8 /* NSArray+Pearl.m in Sources */,
|
||||
DAFE4A63150399FF003ABA8A /* UIControl+PearlSelect.m in Sources */,
|
||||
DAFE4A63150399FF003ABA8E /* UIScrollView+PearlFlashingIndicators.m in Sources */,
|
||||
@ -3947,6 +3953,8 @@
|
||||
93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */,
|
||||
93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */,
|
||||
DA2CA4DF18D28859007798F8 /* NSTimer+PearlBlock.m in Sources */,
|
||||
93D3954E96236384AFA00453 /* UIScrollView+PearlAdjustInsets.m in Sources */,
|
||||
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -4244,6 +4252,7 @@
|
||||
EXCLUDED_SOURCE_FILE_NAMES = libTestFlight.a;
|
||||
GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch";
|
||||
INFOPLIST_FILE = "MasterPassword-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-framework",
|
||||
@ -4269,6 +4278,7 @@
|
||||
EXCLUDED_SOURCE_FILE_NAMES = "";
|
||||
GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch";
|
||||
INFOPLIST_FILE = "MasterPassword-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
PROVISIONING_PROFILE = "";
|
||||
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "4CBD21E7-DB60-4F7F-80F8-98DFA83D2CE0";
|
||||
SKIP_INSTALL = NO;
|
||||
@ -4277,27 +4287,6 @@
|
||||
};
|
||||
name = "AdHoc-iOS";
|
||||
};
|
||||
DA829E5A159847E0002417D3 /* Debug-iOS */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
|
||||
};
|
||||
name = "Debug-iOS";
|
||||
};
|
||||
DA829E5B159847E0002417D3 /* AdHoc-iOS */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
|
||||
};
|
||||
name = "AdHoc-iOS";
|
||||
};
|
||||
DA829E5C159847E0002417D3 /* AppStore-iOS */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
|
||||
};
|
||||
name = "AppStore-iOS";
|
||||
};
|
||||
DA95D60914DF3F3B008D1B94 /* AppStore-iOS */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@ -4405,6 +4394,7 @@
|
||||
);
|
||||
GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch";
|
||||
INFOPLIST_FILE = "MasterPassword-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
PROVISIONING_PROFILE = "";
|
||||
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "6C6B84DD-9D8F-4321-BD77-5F737DBE1778";
|
||||
SKIP_INSTALL = NO;
|
||||
@ -4677,16 +4667,6 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = "AdHoc-iOS";
|
||||
};
|
||||
DA829E59159847E0002417D3 /* Build configuration list for PBXNativeTarget "FontReplacer" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
DA829E5A159847E0002417D3 /* Debug-iOS */,
|
||||
DA829E5B159847E0002417D3 /* AdHoc-iOS */,
|
||||
DA829E5C159847E0002417D3 /* AppStore-iOS */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = "AdHoc-iOS";
|
||||
};
|
||||
DAC632651486805C0075AEA5 /* Build configuration list for PBXNativeTarget "uicolor-utilities" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
@ -1,43 +0,0 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// PearlUINavigationBar.h
|
||||
// PearlUINavigationBar
|
||||
//
|
||||
// Created by lhunath on 2014-03-17.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "PearlUINavigationBar.h"
|
||||
|
||||
@implementation PearlUINavigationBar
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||
|
||||
UIView *hitView = [super hitTest:point withEvent:event];
|
||||
if (self.ignoreTouches && hitView == self)
|
||||
return nil;
|
||||
|
||||
return hitView;
|
||||
}
|
||||
|
||||
- (void)setInvisible:(BOOL)invisible {
|
||||
|
||||
_invisible = invisible;
|
||||
|
||||
if (invisible) {
|
||||
self.translucent = YES;
|
||||
self.shadowImage = [UIImage new];
|
||||
[self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,32 +0,0 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// PearlUIView.h
|
||||
// PearlUIView
|
||||
//
|
||||
// Created by lhunath on 2014-03-17.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "PearlUIView.h"
|
||||
|
||||
@implementation PearlUIView
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||
|
||||
UIView *hitView = [super hitTest:point withEvent:event];
|
||||
if (self.ignoreTouches && hitView == self)
|
||||
return nil;
|
||||
|
||||
return hitView;
|
||||
}
|
||||
|
||||
@end
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
MasterPassword/Resources/Media/Fonts/Exo2.0-Bold.otf
Normal file
BIN
MasterPassword/Resources/Media/Fonts/Exo2.0-Bold.otf
Normal file
Binary file not shown.
BIN
MasterPassword/Resources/Media/Fonts/Exo2.0-ExtraBold.otf
Normal file
BIN
MasterPassword/Resources/Media/Fonts/Exo2.0-ExtraBold.otf
Normal file
Binary file not shown.
BIN
MasterPassword/Resources/Media/Fonts/Exo2.0-Regular.otf
Normal file
BIN
MasterPassword/Resources/Media/Fonts/Exo2.0-Regular.otf
Normal file
Binary file not shown.
BIN
MasterPassword/Resources/Media/Fonts/Exo2.0-Thin.otf
Normal file
BIN
MasterPassword/Resources/Media/Fonts/Exo2.0-Thin.otf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user