Development fuel, store improvements and navigation fixes.
This commit is contained in:
parent
a5bc2eb584
commit
6050b5d6fd
@ -553,7 +553,7 @@
|
||||
|
||||
NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
|
||||
NSString *name = site.name;
|
||||
BOOL loginGenerated = site.loginGenerated && [[MPAppDelegate_Shared get] isPurchased:MPProductGenerateLogins];
|
||||
BOOL loginGenerated = site.loginGenerated && [[MPAppDelegate_Shared get] isFeatureUnlocked:MPProductGenerateLogins];
|
||||
NSString *loginName = loginGenerated? nil: site.loginName;
|
||||
id<MPAlgorithm> algorithm = nil;
|
||||
if (!name.length)
|
||||
|
@ -6,21 +6,32 @@
|
||||
// Copyright (c) 2011 Lyndir. All rights reserved.
|
||||
//
|
||||
|
||||
#import <StoreKit/StoreKit.h>
|
||||
#import "MPAppDelegate_Shared.h"
|
||||
|
||||
#define MPProductGenerateLogins @"com.lyndir.masterpassword.products.generatelogins"
|
||||
#define MPProductGenerateAnswers @"com.lyndir.masterpassword.products.generateanswers"
|
||||
#define MPProductGenerateLogins @"com.lyndir.masterpassword.products.generatelogins"
|
||||
#define MPProductGenerateAnswers @"com.lyndir.masterpassword.products.generateanswers"
|
||||
#define MPProductFuel @"com.lyndir.masterpassword.products.fuel"
|
||||
|
||||
#define MP_FUEL_HOURLY_RATE 30.f /* Tier 1 purchases/h ~> USD/h */
|
||||
|
||||
@protocol MPInAppDelegate
|
||||
|
||||
- (void)updateWithProducts:(NSArray /* SKProduct */ *)products;
|
||||
- (void)updateWithTransaction:(SKPaymentTransaction *)transaction;
|
||||
|
||||
@end
|
||||
|
||||
@interface MPAppDelegate_Shared(InApp)
|
||||
|
||||
@property(nonatomic, strong) NSArray /* SKProduct */ *products;
|
||||
@property(nonatomic, strong) NSArray /* SKPaymentTransaction */ *paymentTransactions;
|
||||
- (void)registerProductsObserver:(id<MPInAppDelegate>)delegate;
|
||||
- (void)removeProductsObserver:(id<MPInAppDelegate>)delegate;
|
||||
|
||||
- (void)updateProducts;
|
||||
- (void)reloadProducts;
|
||||
- (BOOL)canMakePayments;
|
||||
- (BOOL)isPurchased:(NSString *)productIdentifier;
|
||||
- (BOOL)isFeatureUnlocked:(NSString *)productIdentifier;
|
||||
|
||||
- (void)restoreCompletedTransactions;
|
||||
- (void)purchaseProductWithIdentifier:(NSString *)productIdentifier;
|
||||
- (void)purchaseProductWithIdentifier:(NSString *)productIdentifier quantity:(NSInteger)quantity;
|
||||
|
||||
@end
|
||||
|
@ -7,7 +7,6 @@
|
||||
//
|
||||
|
||||
#import "MPAppDelegate_InApp.h"
|
||||
#import <StoreKit/StoreKit.h>
|
||||
|
||||
@interface MPAppDelegate_Shared(InApp_Private)<SKProductsRequestDelegate, SKPaymentTransactionObserver>
|
||||
@end
|
||||
@ -15,12 +14,29 @@
|
||||
@implementation MPAppDelegate_Shared(InApp)
|
||||
|
||||
PearlAssociatedObjectProperty( NSArray*, Products, products );
|
||||
PearlAssociatedObjectProperty( NSArray*, PaymentTransactions, paymentTransactions );
|
||||
PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObservers );
|
||||
|
||||
- (void)updateProducts {
|
||||
- (void)registerProductsObserver:(id<MPInAppDelegate>)delegate {
|
||||
|
||||
if (!self.productObservers)
|
||||
self.productObservers = [NSMutableArray array];
|
||||
[self.productObservers addObject:delegate];
|
||||
|
||||
if (self.products)
|
||||
[delegate updateWithProducts:self.products];
|
||||
else
|
||||
[self reloadProducts];
|
||||
}
|
||||
|
||||
- (void)removeProductsObserver:(id<MPInAppDelegate>)delegate {
|
||||
|
||||
[self.productObservers removeObject:delegate];
|
||||
}
|
||||
|
||||
- (void)reloadProducts {
|
||||
|
||||
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:
|
||||
[[NSSet alloc] initWithObjects:MPProductGenerateLogins, MPProductGenerateAnswers, nil]];
|
||||
[[NSSet alloc] initWithObjects:MPProductGenerateLogins, MPProductGenerateAnswers, MPProductFuel, nil]];
|
||||
productsRequest.delegate = self;
|
||||
[productsRequest start];
|
||||
}
|
||||
@ -40,9 +56,22 @@ PearlAssociatedObjectProperty( NSArray*, PaymentTransactions, paymentTransaction
|
||||
return [SKPaymentQueue canMakePayments];
|
||||
}
|
||||
|
||||
- (BOOL)isPurchased:(NSString *)productIdentifier {
|
||||
- (BOOL)isFeatureUnlocked:(NSString *)productIdentifier {
|
||||
|
||||
return YES; //[[NSUserDefaults standardUserDefaults] objectForKey:productIdentifier] != nil;
|
||||
if (![productIdentifier length])
|
||||
// Missing a product.
|
||||
return NO;
|
||||
if ([productIdentifier isEqualToString:MPProductFuel])
|
||||
// Consumable product.
|
||||
return NO;
|
||||
|
||||
#if ADHOC || DEBUG
|
||||
// All features are unlocked for beta / debug versions.
|
||||
return YES;
|
||||
#else
|
||||
// Check if product is purchased.
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:productIdentifier] != nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)restoreCompletedTransactions {
|
||||
@ -50,11 +79,13 @@ PearlAssociatedObjectProperty( NSArray*, PaymentTransactions, paymentTransaction
|
||||
[[self paymentQueue] restoreCompletedTransactions];
|
||||
}
|
||||
|
||||
- (void)purchaseProductWithIdentifier:(NSString *)productIdentifier {
|
||||
- (void)purchaseProductWithIdentifier:(NSString *)productIdentifier quantity:(NSInteger)quantity {
|
||||
|
||||
for (SKProduct *product in self.products)
|
||||
if ([product.productIdentifier isEqualToString:productIdentifier]) {
|
||||
[[self paymentQueue] addPayment:[SKPayment paymentWithProduct:product]];
|
||||
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
|
||||
payment.quantity = quantity;
|
||||
[[self paymentQueue] addPayment:payment];
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -65,10 +96,21 @@ PearlAssociatedObjectProperty( NSArray*, PaymentTransactions, paymentTransaction
|
||||
|
||||
inf( @"products: %@, invalid: %@", response.products, response.invalidProductIdentifiers );
|
||||
self.products = response.products;
|
||||
|
||||
for (id<MPInAppDelegate> productObserver in self.productObservers)
|
||||
[productObserver updateWithProducts:self.products];
|
||||
}
|
||||
|
||||
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
[PearlAlert showAlertWithTitle:@"Purchase Failed" message:
|
||||
strf( @"%@\n\n%@", error.localizedDescription,
|
||||
@"Ensure you are online and try logging out and back into iTunes from your device's Settings." )
|
||||
viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil
|
||||
cancelTitle:@"OK" otherTitles:nil];
|
||||
#else
|
||||
#endif
|
||||
err( @"StoreKit request (%@) failed: %@", request, [error fullDescription] );
|
||||
}
|
||||
|
||||
@ -82,23 +124,39 @@ PearlAssociatedObjectProperty( NSArray*, PaymentTransactions, paymentTransaction
|
||||
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
|
||||
|
||||
for (SKPaymentTransaction *transaction in transactions) {
|
||||
dbg( @"transaction updated: %@", transaction );
|
||||
dbg( @"transaction updated: %@ -> %d", transaction.payment.productIdentifier, transaction.transactionState );
|
||||
switch (transaction.transactionState) {
|
||||
case SKPaymentTransactionStatePurchased:
|
||||
case SKPaymentTransactionStateRestored: {
|
||||
case SKPaymentTransactionStatePurchased: {
|
||||
inf( @"purchased: %@", transaction.payment.productIdentifier );
|
||||
if ([transaction.payment.productIdentifier isEqualToString:MPProductFuel]) {
|
||||
float currentFuel = [[MPiOSConfig get].developmentFuel floatValue];
|
||||
float purchasedFuel = transaction.payment.quantity / MP_FUEL_HOURLY_RATE;
|
||||
[MPiOSConfig get].developmentFuel = @(currentFuel + purchasedFuel);
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:transaction.transactionIdentifier
|
||||
forKey:transaction.payment.productIdentifier];
|
||||
[queue finishTransaction:transaction];
|
||||
break;
|
||||
}
|
||||
case SKPaymentTransactionStateRestored: {
|
||||
inf( @"restored: %@", transaction.payment.productIdentifier );
|
||||
[[NSUserDefaults standardUserDefaults] setObject:transaction.transactionIdentifier
|
||||
forKey:transaction.payment.productIdentifier];
|
||||
[queue finishTransaction:transaction];
|
||||
break;
|
||||
}
|
||||
case SKPaymentTransactionStatePurchasing:
|
||||
case SKPaymentTransactionStateFailed:
|
||||
case SKPaymentTransactionStateDeferred:
|
||||
break;
|
||||
case SKPaymentTransactionStateFailed:
|
||||
err( @"Transaction failed: %@, reason: %@", transaction.payment.productIdentifier, [transaction.error fullDescription] );
|
||||
[queue finishTransaction:transaction];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.paymentTransactions = transactions;
|
||||
for (id<MPInAppDelegate> productObserver in self.productObservers)
|
||||
[productObserver updateWithTransaction:transaction];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
|
||||
|
@ -197,7 +197,7 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
|
||||
^(NSNotification *note) {
|
||||
[self.mainManagedObjectContext saveToStore];
|
||||
}];
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:UIApp
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:UIApp
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:
|
||||
^(NSNotification *note) {
|
||||
[self.mainManagedObjectContext saveToStore];
|
||||
|
@ -16,6 +16,10 @@
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPUsersViewController.h"
|
||||
#import "MPPasswordsViewController.h"
|
||||
#import "MPEmergencyViewController.h"
|
||||
|
||||
typedef NS_ENUM(NSUInteger, MPCombinedMode) {
|
||||
MPCombinedModeUserSelection,
|
||||
MPCombinedModePasswordSelection,
|
||||
@ -23,7 +27,9 @@ typedef NS_ENUM(NSUInteger, MPCombinedMode) {
|
||||
|
||||
@interface MPCombinedViewController : UIViewController
|
||||
|
||||
@property(assign, nonatomic) MPCombinedMode mode;
|
||||
@property(strong, nonatomic) IBOutlet UIView *usersView;
|
||||
@property(nonatomic) MPCombinedMode mode;
|
||||
@property(nonatomic, weak) MPUsersViewController *usersVC;
|
||||
@property(nonatomic, weak) MPPasswordsViewController *passwordsVC;
|
||||
@property(nonatomic, weak) MPEmergencyViewController *emergencyVC;
|
||||
|
||||
@end
|
||||
|
@ -22,15 +22,8 @@
|
||||
#import "MPEmergencyViewController.h"
|
||||
#import "MPPasswordsSegue.h"
|
||||
|
||||
@interface MPCombinedViewController()
|
||||
|
||||
@property(nonatomic, weak) MPUsersViewController *usersVC;
|
||||
@property(nonatomic, weak) MPEmergencyViewController *emergencyVC;
|
||||
@end
|
||||
|
||||
@implementation MPCombinedViewController {
|
||||
NSArray *_notificationObservers;
|
||||
MPPasswordsViewController *_passwordsVC;
|
||||
}
|
||||
|
||||
#pragma mark - Life
|
||||
@ -40,6 +33,7 @@
|
||||
[super viewDidLoad];
|
||||
|
||||
_mode = MPCombinedModeUserSelection;
|
||||
[self performSegueWithIdentifier:@"users" sender:self];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
@ -128,7 +122,7 @@
|
||||
|
||||
switch (self.mode) {
|
||||
case MPCombinedModeUserSelection: {
|
||||
self.usersView.userInteractionEnabled = YES;
|
||||
self.usersVC.view.userInteractionEnabled = YES;
|
||||
[self.usersVC setActive:YES animated:animated];
|
||||
if (_passwordsVC) {
|
||||
MPPasswordsSegue *segue = [[MPPasswordsSegue alloc] initWithIdentifier:@"passwords" source:_passwordsVC destination:self];
|
||||
@ -138,7 +132,7 @@
|
||||
break;
|
||||
}
|
||||
case MPCombinedModePasswordSelection: {
|
||||
self.usersView.userInteractionEnabled = NO;
|
||||
self.usersVC.view.userInteractionEnabled = NO;
|
||||
[self.usersVC setActive:NO animated:animated];
|
||||
[self performSegueWithIdentifier:@"passwords" sender:@{ @"animated" : @(animated) }];
|
||||
break;
|
||||
|
@ -29,12 +29,11 @@
|
||||
_dismissSegueByButton = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
- (void)viewDidLoad {
|
||||
|
||||
[super viewWillAppear:animated];
|
||||
[super viewDidLoad];
|
||||
|
||||
if (![self.childViewControllers count])
|
||||
[self performSegueWithIdentifier:@"root" sender:self];
|
||||
[self performSegueWithIdentifier:@"root" sender:self];
|
||||
}
|
||||
|
||||
- (UIViewController *)childViewControllerForStatusBarStyle {
|
||||
@ -110,26 +109,25 @@
|
||||
if (!destinationViewController.parentViewController) {
|
||||
// Winding
|
||||
[containerViewController addChildViewController:destinationViewController];
|
||||
[containerViewController setNeedsStatusBarAppearanceUpdate];
|
||||
|
||||
[containerViewController addDismissButtonForSegue:self];
|
||||
destinationViewController.view.frame = containerViewController.view.bounds;
|
||||
destinationViewController.view.translatesAutoresizingMaskIntoConstraints = YES;
|
||||
destinationViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[containerViewController.view addSubview:destinationViewController.view];
|
||||
[containerViewController setNeedsStatusBarAppearanceUpdate];
|
||||
|
||||
CGRectSetY( destinationViewController.view.frame, 100 );
|
||||
destinationViewController.view.transform = CGAffineTransformMakeScale( 1.2f, 1.2f );
|
||||
destinationViewController.view.alpha = 0;
|
||||
|
||||
[UIView transitionWithView:containerViewController.view duration:[self.identifier isEqualToString:@"root"]? 0: 0.3f
|
||||
[UIView transitionWithView:containerViewController.view duration:0.3f
|
||||
options:UIViewAnimationOptionAllowAnimatedContent animations:^{
|
||||
destinationViewController.view.transform = CGAffineTransformIdentity;
|
||||
CGRectSetY( destinationViewController.view.frame, 0 );
|
||||
destinationViewController.view.alpha = 1;
|
||||
} completion:^(BOOL finished) {
|
||||
if (finished)
|
||||
[destinationViewController didMoveToParentViewController:containerViewController];
|
||||
[destinationViewController didMoveToParentViewController:containerViewController];
|
||||
[containerViewController setNeedsStatusBarAppearanceUpdate];
|
||||
}];
|
||||
}
|
||||
else {
|
||||
|
@ -466,7 +466,7 @@
|
||||
|
||||
// UI
|
||||
self.upgradeButton.gone = !mainSite.requiresExplicitMigration;
|
||||
self.answersButton.gone = ![[MPiOSAppDelegate get] isPurchased:MPProductGenerateAnswers];
|
||||
self.answersButton.gone = ![[MPiOSAppDelegate get] isFeatureUnlocked:MPProductGenerateAnswers];
|
||||
BOOL settingsMode = self.mode == MPPasswordCellModeSettings;
|
||||
self.loginNameContainer.alpha = settingsMode || mainSite.loginGenerated || [mainSite.loginName length]? 0.7f: 0;
|
||||
self.loginNameField.textColor = [UIColor colorWithHexString:mainSite.loginGenerated? @"5E636D": @"6D5E63"];
|
||||
@ -480,7 +480,7 @@
|
||||
[self.loginNameField resignFirstResponder];
|
||||
[self.passwordField resignFirstResponder];
|
||||
}
|
||||
if ([[MPiOSAppDelegate get] isPurchased:MPProductGenerateLogins])
|
||||
if ([[MPiOSAppDelegate get] isFeatureUnlocked:MPProductGenerateLogins])
|
||||
[self.loginNameButton setTitle:@"Tap to generate username or use pencil to save one" forState:UIControlStateNormal];
|
||||
else
|
||||
[self.loginNameButton setTitle:@"Tap the pencil to save a username" forState:UIControlStateNormal];
|
||||
|
@ -42,11 +42,9 @@
|
||||
passwordsVC.active = NO;
|
||||
|
||||
UIView *passwordsView = passwordsVC.view;
|
||||
passwordsView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[combinedVC.view insertSubview:passwordsView belowSubview:combinedVC.usersView];
|
||||
[combinedVC.view addConstraintsWithVisualFormats:@[ @"H:|[passwordsView]|", @"V:|[passwordsView]|" ]
|
||||
options:0 metrics:nil
|
||||
views:NSDictionaryOfVariableBindings( passwordsView )];
|
||||
passwordsView.frame = combinedVC.view.bounds;
|
||||
passwordsView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[combinedVC.view insertSubview:passwordsView belowSubview:combinedVC.usersVC.view];
|
||||
|
||||
[passwordsVC setActive:YES animated:self.animated completion:^(BOOL finished) {
|
||||
if (!finished)
|
||||
|
@ -286,12 +286,28 @@ referenceSizeForHeaderInSection:(NSInteger)section {
|
||||
Weakify( self );
|
||||
_notificationObservers = @[
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:UIApplicationWillResignActiveNotification object:nil
|
||||
addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
Strongify( self );
|
||||
|
||||
self.passwordSelectionContainer.alpha = 0;
|
||||
}],
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:UIApplicationWillEnterForegroundNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
Strongify( self );
|
||||
|
||||
[self updatePasswords];
|
||||
}],
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:UIApplicationDidBecomeActiveNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
Strongify( self );
|
||||
|
||||
[UIView animateWithDuration:0.7f animations:^{
|
||||
self.passwordSelectionContainer.alpha = 1;
|
||||
}];
|
||||
}],
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:MPSignedOutNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
@ -301,16 +317,6 @@ referenceSizeForHeaderInSection:(NSInteger)section {
|
||||
self.passwordsSearchBar.text = nil;
|
||||
[self.passwordCollectionView reloadData];
|
||||
}],
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:UIApplicationDidBecomeActiveNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
Strongify( self );
|
||||
|
||||
[self updatePasswords];
|
||||
[UIView animateWithDuration:1 animations:^{
|
||||
self.passwordSelectionContainer.alpha = 1;
|
||||
}];
|
||||
}],
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:MPCheckConfigNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
|
25
MasterPassword/ObjC/iOS/MPRootSegue.h
Normal file
25
MasterPassword/ObjC/iOS/MPRootSegue.h
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPRootSegue.h
|
||||
// MPRootSegue
|
||||
//
|
||||
// Created by lhunath on 2014-09-26.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
|
||||
@interface MPRootSegue : UIStoryboardSegue
|
||||
|
||||
|
||||
@end
|
38
MasterPassword/ObjC/iOS/MPRootSegue.m
Normal file
38
MasterPassword/ObjC/iOS/MPRootSegue.m
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// MPRootSegue.h
|
||||
// MPRootSegue
|
||||
//
|
||||
// Created by lhunath on 2014-09-26.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPRootSegue.h"
|
||||
|
||||
|
||||
@implementation MPRootSegue {
|
||||
|
||||
}
|
||||
|
||||
- (void)perform {
|
||||
|
||||
UIViewController *sourceViewController = self.sourceViewController;
|
||||
UIViewController *destinationViewController = self.destinationViewController;
|
||||
[sourceViewController addChildViewController:destinationViewController];
|
||||
destinationViewController.view.frame = sourceViewController.view.bounds;
|
||||
destinationViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[sourceViewController.view addSubview:destinationViewController.view];
|
||||
[destinationViewController didMoveToParentViewController:sourceViewController];
|
||||
[sourceViewController setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
|
||||
@end
|
@ -16,6 +16,9 @@
|
||||
@property(weak, nonatomic) IBOutlet MPStoreProductCell *generateAnswersCell;
|
||||
@property(weak, nonatomic) IBOutlet MPStoreProductCell *iOSIntegrationCell;
|
||||
@property(weak, nonatomic) IBOutlet MPStoreProductCell *touchIDCell;
|
||||
@property(weak, nonatomic) IBOutlet MPStoreProductCell *fuelCell;
|
||||
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *fuelMeterConstraint;
|
||||
@property(weak, nonatomic) IBOutlet UIButton *fuelSpeedButton;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -10,11 +10,14 @@
|
||||
#import "MPiOSAppDelegate.h"
|
||||
#import "UIColor+Expanded.h"
|
||||
#import "MPAppDelegate_InApp.h"
|
||||
#import <StoreKit/StoreKit.h>
|
||||
|
||||
@interface MPStoreViewController()
|
||||
PearlEnum( MPDevelopmentFuelConsumption,
|
||||
MPDevelopmentFuelConsumptionQuarterly, MPDevelopmentFuelConsumptionMonthly, MPDevelopmentFuelWeekly );
|
||||
|
||||
@interface MPStoreViewController()<MPInAppDelegate>
|
||||
|
||||
@property(nonatomic, strong) NSNumberFormatter *currencyFormatter;
|
||||
@property(nonatomic, strong) NSArray *products;
|
||||
|
||||
@end
|
||||
|
||||
@ -47,24 +50,13 @@
|
||||
}
|
||||
}];
|
||||
|
||||
[[MPiOSAppDelegate get] observeKeyPath:@"products" withBlock:^(id from, id to, NSKeyValueChange cause, id _self) {
|
||||
if (NSNullToNil( to ))
|
||||
PearlMainQueue( ^{
|
||||
[self updateWithProducts:to];
|
||||
} );
|
||||
}];
|
||||
[[MPiOSAppDelegate get] observeKeyPath:@"paymentTransactions" withBlock:^(id from, id to, NSKeyValueChange cause, id _self) {
|
||||
if (NSNullToNil( to ))
|
||||
PearlMainQueue( ^{
|
||||
[self updateWithTransactions:to];
|
||||
} );
|
||||
}];
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:NSUserDefaultsDidChangeNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
[self updateWithProducts:[MPiOSAppDelegate get].products];
|
||||
[self updateProducts];
|
||||
[self updateFuel];
|
||||
}];
|
||||
|
||||
[[MPiOSAppDelegate get] updateProducts];
|
||||
[[MPiOSAppDelegate get] registerProductsObserver:self];
|
||||
[self updateFuel];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDelegate
|
||||
@ -80,7 +72,7 @@
|
||||
}
|
||||
|
||||
if (indexPath.section == 0)
|
||||
cell.selectionStyle = [[MPiOSAppDelegate get] isPurchased:[self productForCell:cell].productIdentifier]?
|
||||
cell.selectionStyle = [[MPiOSAppDelegate get] isFeatureUnlocked:[self productForCell:cell].productIdentifier]?
|
||||
UITableViewCellSelectionStyleDefault: UITableViewCellSelectionStyleNone;
|
||||
|
||||
if (cell.selectionStyle != UITableViewCellSelectionStyleNone) {
|
||||
@ -113,13 +105,21 @@
|
||||
SKProduct *product = [self productForCell:cell];
|
||||
|
||||
if (product)
|
||||
[[MPAppDelegate_Shared get] purchaseProductWithIdentifier:product.productIdentifier];
|
||||
[[MPAppDelegate_Shared get] purchaseProductWithIdentifier:product.productIdentifier
|
||||
quantity:[self quantityForProductIdentifier:product.productIdentifier]];
|
||||
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)toggleFuelConsumption:(id)sender {
|
||||
|
||||
NSUInteger fuelConsumption = [[MPiOSConfig get].developmentFuelConsumption unsignedIntegerValue];
|
||||
[MPiOSConfig get].developmentFuelConsumption = @((fuelConsumption + 1) % MPDevelopmentFuelConsumptionCount);
|
||||
[self updateProducts];
|
||||
}
|
||||
|
||||
- (IBAction)restorePurchases:(id)sender {
|
||||
|
||||
[PearlAlert showAlertWithTitle:@"Restore Previous Purchases" message:
|
||||
@ -133,11 +133,45 @@
|
||||
} cancelTitle:@"Cancel" otherTitles:@"Find Purchases", nil];
|
||||
}
|
||||
|
||||
#pragma mark - MPInAppDelegate
|
||||
|
||||
- (void)updateWithProducts:(NSArray *)products {
|
||||
|
||||
self.products = products;
|
||||
|
||||
[self updateProducts];
|
||||
}
|
||||
|
||||
- (void)updateWithTransaction:(SKPaymentTransaction *)transaction {
|
||||
|
||||
MPStoreProductCell *cell = [self cellForProductIdentifier:transaction.payment.productIdentifier];
|
||||
if (!cell)
|
||||
return;
|
||||
|
||||
switch (transaction.transactionState) {
|
||||
case SKPaymentTransactionStatePurchasing:
|
||||
[cell.activityIndicator startAnimating];
|
||||
break;
|
||||
case SKPaymentTransactionStatePurchased:
|
||||
[cell.activityIndicator stopAnimating];
|
||||
break;
|
||||
case SKPaymentTransactionStateFailed:
|
||||
[cell.activityIndicator stopAnimating];
|
||||
break;
|
||||
case SKPaymentTransactionStateRestored:
|
||||
[cell.activityIndicator stopAnimating];
|
||||
break;
|
||||
case SKPaymentTransactionStateDeferred:
|
||||
[cell.activityIndicator startAnimating];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (SKProduct *)productForCell:(MPStoreProductCell *)cell {
|
||||
|
||||
for (SKProduct *product in [MPiOSAppDelegate get].products)
|
||||
for (SKProduct *product in self.products)
|
||||
if ([self cellForProductIdentifier:product.productIdentifier] == cell)
|
||||
return product;
|
||||
|
||||
@ -150,19 +184,22 @@
|
||||
return self.generateLoginCell;
|
||||
if ([productIdentifier isEqualToString:MPProductGenerateAnswers])
|
||||
return self.generateAnswersCell;
|
||||
if ([productIdentifier isEqualToString:MPProductFuel])
|
||||
return self.fuelCell;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)updateWithProducts:(NSArray *)products {
|
||||
- (void)updateProducts {
|
||||
|
||||
NSMutableArray *showCells = [NSMutableArray array];
|
||||
NSMutableArray *hideCells = [NSMutableArray array];
|
||||
[hideCells addObjectsFromArray:self.allCellsBySection[0]];
|
||||
|
||||
for (SKProduct *product in products) {
|
||||
for (SKProduct *product in self.products) {
|
||||
[self showCellForProductWithIdentifier:MPProductGenerateLogins ifProduct:product showingCells:showCells];
|
||||
[self showCellForProductWithIdentifier:MPProductGenerateAnswers ifProduct:product showingCells:showCells];
|
||||
[self showCellForProductWithIdentifier:MPProductFuel ifProduct:product showingCells:showCells];
|
||||
}
|
||||
|
||||
[hideCells removeObjectsInArray:showCells];
|
||||
@ -172,6 +209,38 @@
|
||||
[self updateCellsHiding:hideCells showing:showCells animation:UITableViewRowAnimationNone];
|
||||
}
|
||||
|
||||
- (void)updateFuel {
|
||||
|
||||
CGFloat weeklyFuelConsumption = [self weeklyFuelConsumption]; /* consume x fuel / week */
|
||||
CGFloat fuel = [[MPiOSConfig get].developmentFuel floatValue]; /* x fuel left */
|
||||
NSTimeInterval fuelSecondsElapsed = [[MPiOSConfig get].developmentFuelChecked timeIntervalSinceNow];
|
||||
if (fuelSecondsElapsed > 3600) {
|
||||
NSTimeInterval weeksElapsed = fuelSecondsElapsed / (3600 * 24 * 7 /* 1 week */); /* x weeks elapsed */
|
||||
fuel -= weeklyFuelConsumption * weeksElapsed;
|
||||
[MPiOSConfig get].developmentFuel = @(fuel);
|
||||
}
|
||||
|
||||
CGFloat fuelRatio = weeklyFuelConsumption == 0? 0: fuel / weeklyFuelConsumption; /* x weeks worth of fuel left */
|
||||
[self.fuelMeterConstraint updateConstant:MIN(0.5f, fuelRatio - 0.5f) * 160]; /* -80pt = 0 weeks left, 80pt = >=1 week left */
|
||||
}
|
||||
|
||||
- (CGFloat)weeklyFuelConsumption {
|
||||
|
||||
switch ((MPDevelopmentFuelConsumption)[[MPiOSConfig get].developmentFuelConsumption unsignedIntegerValue]) {
|
||||
case MPDevelopmentFuelConsumptionQuarterly:
|
||||
[self.fuelSpeedButton setTitle:@"1h / quarter" forState:UIControlStateNormal];
|
||||
return 1.f / 12 /* 12 weeks */;
|
||||
case MPDevelopmentFuelConsumptionMonthly:
|
||||
[self.fuelSpeedButton setTitle:@"1h / month" forState:UIControlStateNormal];
|
||||
return 1.f / 4 /* 4 weeks */;
|
||||
case MPDevelopmentFuelWeekly:
|
||||
[self.fuelSpeedButton setTitle:@"1h / week" forState:UIControlStateNormal];
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)showCellForProductWithIdentifier:(NSString *)productIdentifier ifProduct:(SKProduct *)product
|
||||
showingCells:(NSMutableArray *)showCells {
|
||||
|
||||
@ -182,36 +251,18 @@
|
||||
[showCells addObject:cell];
|
||||
|
||||
self.currencyFormatter.locale = product.priceLocale;
|
||||
BOOL purchased = [[MPiOSAppDelegate get] isPurchased:productIdentifier];
|
||||
cell.priceLabel.text = purchased? @"": [self.currencyFormatter stringFromNumber:product.price];
|
||||
BOOL purchased = [[MPiOSAppDelegate get] isFeatureUnlocked:productIdentifier];
|
||||
NSInteger quantity = [self quantityForProductIdentifier:productIdentifier];
|
||||
cell.priceLabel.text = purchased? @"": [self.currencyFormatter stringFromNumber:@([product.price floatValue] * quantity)];
|
||||
cell.purchasedIndicator.alpha = purchased? 1: 0;
|
||||
}
|
||||
|
||||
- (void)updateWithTransactions:(NSArray *)transactions {
|
||||
- (NSInteger)quantityForProductIdentifier:(NSString *)productIdentifier {
|
||||
|
||||
for (SKPaymentTransaction *transaction in transactions) {
|
||||
MPStoreProductCell *cell = [self cellForProductIdentifier:transaction.payment.productIdentifier];
|
||||
if (!cell)
|
||||
continue;
|
||||
if ([productIdentifier isEqualToString:MPProductFuel])
|
||||
return (NSInteger)(MP_FUEL_HOURLY_RATE * [self weeklyFuelConsumption]);
|
||||
|
||||
switch (transaction.transactionState) {
|
||||
case SKPaymentTransactionStatePurchasing:
|
||||
[cell.activityIndicator startAnimating];
|
||||
break;
|
||||
case SKPaymentTransactionStatePurchased:
|
||||
[cell.activityIndicator stopAnimating];
|
||||
break;
|
||||
case SKPaymentTransactionStateFailed:
|
||||
[cell.activityIndicator stopAnimating];
|
||||
break;
|
||||
case SKPaymentTransactionStateRestored:
|
||||
[cell.activityIndicator stopAnimating];
|
||||
break;
|
||||
case SKPaymentTransactionStateDeferred:
|
||||
[cell.activityIndicator startAnimating];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -592,21 +592,25 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
Weakify( self );
|
||||
_notificationObservers = @[
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:UIApplicationWillResignActiveNotification object:nil
|
||||
addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
Strongify( self );
|
||||
|
||||
// [self emergencyCloseAnimated:NO];
|
||||
self.userSelectionContainer.alpha = 0;
|
||||
}],
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:UIApplicationWillEnterForegroundNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
Strongify( self );
|
||||
|
||||
[self reloadUsers];
|
||||
}],
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:UIApplicationDidBecomeActiveNotification object:nil
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
Strongify( self );
|
||||
|
||||
[self reloadUsers];
|
||||
|
||||
[UIView animateWithDuration:1 animations:^{
|
||||
[UIView animateWithDuration:0.7f animations:^{
|
||||
self.userSelectionContainer.alpha = 1;
|
||||
}];
|
||||
}],
|
||||
|
@ -140,7 +140,7 @@
|
||||
@"jailbroken" : PearlStringB( [PearlDeviceUtils isJailbroken] ),
|
||||
@"platform" : [PearlDeviceUtils platform],
|
||||
#ifdef APPSTORE
|
||||
@"legal" : PearlStringB([PearlDeviceUtils isAppEncrypted]),
|
||||
@"legal" : PearlStringB([PearlDeviceUtils isAppEncrypted]),
|
||||
#else
|
||||
@"legal" : @"YES",
|
||||
#endif
|
||||
@ -256,13 +256,13 @@
|
||||
[super applicationDidReceiveMemoryWarning:application];
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
||||
|
||||
inf( @"Will deactivate" );
|
||||
inf( @"Will background" );
|
||||
if (![[MPiOSConfig get].rememberLogin boolValue])
|
||||
[self signOutAnimated:NO];
|
||||
|
||||
[super applicationWillResignActive:application];
|
||||
[super applicationDidEnterBackground:application];
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
|
@ -18,5 +18,8 @@
|
||||
@property(nonatomic, retain) NSNumber *loginNameTipShown;
|
||||
@property(nonatomic, retain) NSNumber *traceMode;
|
||||
@property(nonatomic, retain) NSNumber *dictationSearch;
|
||||
@property(nonatomic, retain) NSNumber *developmentFuel;
|
||||
@property(nonatomic, retain) NSNumber *developmentFuelConsumption;
|
||||
@property(nonatomic, retain) NSDate *developmentFuelChecked;
|
||||
|
||||
@end
|
||||
|
@ -9,6 +9,7 @@
|
||||
@implementation MPiOSConfig
|
||||
|
||||
@dynamic helpHidden, siteInfoHidden, showSetup, actionsTipShown, typeTipShown, loginNameTipShown, traceMode, dictationSearch;
|
||||
@dynamic developmentFuel, developmentFuelConsumption, developmentFuelChecked;
|
||||
|
||||
- (id)init {
|
||||
|
||||
@ -16,15 +17,15 @@
|
||||
return self;
|
||||
|
||||
[self.defaults registerDefaults:@{
|
||||
NSStringFromSelector( @selector(helpHidden) ) : @NO,
|
||||
NSStringFromSelector( @selector(siteInfoHidden) ) : @YES,
|
||||
NSStringFromSelector( @selector(showSetup) ) : @YES,
|
||||
NSStringFromSelector( @selector(iTunesID) ) : @"510296984",
|
||||
NSStringFromSelector( @selector(actionsTipShown) ) : @(!self.firstRun),
|
||||
NSStringFromSelector( @selector(typeTipShown) ) : @(!self.firstRun),
|
||||
NSStringFromSelector( @selector(loginNameTipShown) ) : @NO,
|
||||
NSStringFromSelector( @selector(traceMode) ) : @NO,
|
||||
NSStringFromSelector( @selector(dictationSearch) ) : @NO
|
||||
NSStringFromSelector( @selector( helpHidden ) ) : @NO,
|
||||
NSStringFromSelector( @selector( siteInfoHidden ) ) : @YES,
|
||||
NSStringFromSelector( @selector( showSetup ) ) : @YES,
|
||||
NSStringFromSelector( @selector( iTunesID ) ) : @"510296984",
|
||||
NSStringFromSelector( @selector( actionsTipShown ) ) : @(!self.firstRun),
|
||||
NSStringFromSelector( @selector( typeTipShown ) ) : @(!self.firstRun),
|
||||
NSStringFromSelector( @selector( loginNameTipShown ) ) : @NO,
|
||||
NSStringFromSelector( @selector( traceMode ) ) : @NO,
|
||||
NSStringFromSelector( @selector( dictationSearch ) ) : @NO,
|
||||
}];
|
||||
|
||||
return self;
|
||||
|
@ -39,6 +39,7 @@
|
||||
93D39A53D76CA70786423458 /* UICollectionView+PearlReloadFromArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadFromArray.h */; };
|
||||
93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */; };
|
||||
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D8A953779B35403AF6E /* PearlUICollectionView.m */; };
|
||||
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399493FEDDE74DD1A0C15 /* MPRootSegue.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 */; };
|
||||
@ -127,6 +128,14 @@
|
||||
DA32D04219D27093004F3F0E /* thumb_generated_answers@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D03F19D27093004F3F0E /* thumb_generated_answers@3x.png */; };
|
||||
DA32D04319D27093004F3F0E /* thumb_generated_answers@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D04019D27093004F3F0E /* thumb_generated_answers@2x.png */; };
|
||||
DA32D04419D27093004F3F0E /* thumb_generated_answers.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D04119D27093004F3F0E /* thumb_generated_answers.png */; };
|
||||
DA32D04819D2F417004F3F0E /* thumb_fuel@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D04519D2F417004F3F0E /* thumb_fuel@3x.png */; };
|
||||
DA32D04919D2F417004F3F0E /* thumb_fuel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D04619D2F417004F3F0E /* thumb_fuel@2x.png */; };
|
||||
DA32D04A19D2F417004F3F0E /* thumb_fuel.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D04719D2F417004F3F0E /* thumb_fuel.png */; };
|
||||
DA32D04E19D2F59B004F3F0E /* meter_fuel@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D04B19D2F59B004F3F0E /* meter_fuel@3x.png */; };
|
||||
DA32D04F19D2F59B004F3F0E /* meter_fuel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D04C19D2F59B004F3F0E /* meter_fuel@2x.png */; };
|
||||
DA32D05019D2F59B004F3F0E /* meter_fuel.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D04D19D2F59B004F3F0E /* meter_fuel.png */; };
|
||||
DA32D05119D3D107004F3F0E /* icon_meter.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37BA1711E29600CF925C /* icon_meter.png */; };
|
||||
DA32D05219D3D107004F3F0E /* icon_meter@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37BB1711E29600CF925C /* icon_meter@2x.png */; };
|
||||
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3509FC15F101A500C14A8E /* PearlQueue.h */; };
|
||||
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3509FD15F101A500C14A8E /* PearlQueue.m */; };
|
||||
DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */; };
|
||||
@ -425,6 +434,7 @@
|
||||
93D3916C1D8F1427DFBDEBCA /* MPAppSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppSettingsViewController.m; sourceTree = "<group>"; };
|
||||
93D391943675426839501BB8 /* MPLogsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLogsViewController.h; sourceTree = "<group>"; };
|
||||
93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadFromArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionView+PearlReloadFromArray.h"; sourceTree = "<group>"; };
|
||||
93D3924D6F77E6BF41AC32D3 /* MPRootSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootSegue.h; sourceTree = "<group>"; };
|
||||
93D3924EE15017F8A12CB436 /* MPPasswordsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordsViewController.m; sourceTree = "<group>"; };
|
||||
93D392876BE5C011DE73B43F /* MPPopdownSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPopdownSegue.h; sourceTree = "<group>"; };
|
||||
93D393310223DDB35218467A /* MPCombinedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCombinedViewController.m; sourceTree = "<group>"; };
|
||||
@ -446,6 +456,7 @@
|
||||
93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlNavigationController.h; sourceTree = "<group>"; };
|
||||
93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; };
|
||||
93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPWebViewController.m; sourceTree = "<group>"; };
|
||||
93D399493FEDDE74DD1A0C15 /* MPRootSegue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRootSegue.m; sourceTree = "<group>"; };
|
||||
93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCoachmarkViewController.m; sourceTree = "<group>"; };
|
||||
93D39975CE5AEC99E3F086C7 /* MPPasswordCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordCell.h; sourceTree = "<group>"; };
|
||||
93D3999693660C89A7465F4E /* MPCoachmarkViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCoachmarkViewController.h; sourceTree = "<group>"; };
|
||||
@ -552,6 +563,12 @@
|
||||
DA32D03F19D27093004F3F0E /* thumb_generated_answers@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_generated_answers@3x.png"; sourceTree = "<group>"; };
|
||||
DA32D04019D27093004F3F0E /* thumb_generated_answers@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_generated_answers@2x.png"; sourceTree = "<group>"; };
|
||||
DA32D04119D27093004F3F0E /* thumb_generated_answers.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thumb_generated_answers.png; sourceTree = "<group>"; };
|
||||
DA32D04519D2F417004F3F0E /* thumb_fuel@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_fuel@3x.png"; sourceTree = "<group>"; };
|
||||
DA32D04619D2F417004F3F0E /* thumb_fuel@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_fuel@2x.png"; sourceTree = "<group>"; };
|
||||
DA32D04719D2F417004F3F0E /* thumb_fuel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thumb_fuel.png; sourceTree = "<group>"; };
|
||||
DA32D04B19D2F59B004F3F0E /* meter_fuel@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "meter_fuel@3x.png"; sourceTree = "<group>"; };
|
||||
DA32D04C19D2F59B004F3F0E /* meter_fuel@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "meter_fuel@2x.png"; sourceTree = "<group>"; };
|
||||
DA32D04D19D2F59B004F3F0E /* meter_fuel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = meter_fuel.png; sourceTree = "<group>"; };
|
||||
DA3509FC15F101A500C14A8E /* PearlQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlQueue.h; sourceTree = "<group>"; };
|
||||
DA3509FD15F101A500C14A8E /* PearlQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlQueue.m; sourceTree = "<group>"; };
|
||||
DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = "<group>"; };
|
||||
@ -1525,6 +1542,8 @@
|
||||
93D3957D76F71A652716EECC /* MPStoreViewController.m */,
|
||||
93D39C426E03358384018E85 /* MPAnswersViewController.m */,
|
||||
93D39D6604447D7708039155 /* MPAnswersViewController.h */,
|
||||
93D399493FEDDE74DD1A0C15 /* MPRootSegue.m */,
|
||||
93D3924D6F77E6BF41AC32D3 /* MPRootSegue.h */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@ -1606,6 +1625,12 @@
|
||||
DABD360D1711E29400CF925C /* Media */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA32D04B19D2F59B004F3F0E /* meter_fuel@3x.png */,
|
||||
DA32D04C19D2F59B004F3F0E /* meter_fuel@2x.png */,
|
||||
DA32D04D19D2F59B004F3F0E /* meter_fuel.png */,
|
||||
DA32D04519D2F417004F3F0E /* thumb_fuel@3x.png */,
|
||||
DA32D04619D2F417004F3F0E /* thumb_fuel@2x.png */,
|
||||
DA32D04719D2F417004F3F0E /* thumb_fuel.png */,
|
||||
DA32D03F19D27093004F3F0E /* thumb_generated_answers@3x.png */,
|
||||
DA32D04019D27093004F3F0E /* thumb_generated_answers@2x.png */,
|
||||
DA32D04119D27093004F3F0E /* thumb_generated_answers.png */,
|
||||
@ -3086,6 +3111,7 @@
|
||||
DAFE4A5A1503982E003ABA7C /* Pearl.strings in Resources */,
|
||||
DACA296F1705DF81002C6C22 /* Crashlytics.plist in Resources */,
|
||||
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */,
|
||||
DA32D04F19D2F59B004F3F0E /* meter_fuel@2x.png in Resources */,
|
||||
DA250A0F1956484D00AC23F1 /* image-1@2x.png in Resources */,
|
||||
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
|
||||
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */,
|
||||
@ -3096,6 +3122,7 @@
|
||||
DA69540617D975D900BF294E /* icon_gears.png in Resources */,
|
||||
DA67460D18DE7F0C00DFE240 /* Exo2.0-Thin.otf in Resources */,
|
||||
DA4522451902355C008F650A /* icon_book@2x.png in Resources */,
|
||||
DA32D04919D2F417004F3F0E /* thumb_fuel@2x.png in Resources */,
|
||||
DABD39371711E29700CF925C /* avatar-0.png in Resources */,
|
||||
DABD39381711E29700CF925C /* avatar-0@2x.png in Resources */,
|
||||
DA250A041956484D00AC23F1 /* image-7.png in Resources */,
|
||||
@ -3139,16 +3166,19 @@
|
||||
DABD394D1711E29700CF925C /* avatar-2.png in Resources */,
|
||||
DABD394E1711E29700CF925C /* avatar-2@2x.png in Resources */,
|
||||
DA250A061956484D00AC23F1 /* image-6.png in Resources */,
|
||||
DA32D04A19D2F417004F3F0E /* thumb_fuel.png in Resources */,
|
||||
DABD394F1711E29700CF925C /* avatar-3.png in Resources */,
|
||||
DA67460F18DE7F0C00DFE240 /* Exo2.0-ExtraBold.otf in Resources */,
|
||||
DABD39501711E29700CF925C /* avatar-3@2x.png in Resources */,
|
||||
DA25C600197DBF260046CDCF /* icon_trash.png in Resources */,
|
||||
DA32D05219D3D107004F3F0E /* icon_meter@2x.png in Resources */,
|
||||
DABD39511711E29700CF925C /* avatar-4.png in Resources */,
|
||||
DA2509FD1956484D00AC23F1 /* image-10@2x.png in Resources */,
|
||||
DABD39521711E29700CF925C /* avatar-4@2x.png in Resources */,
|
||||
DABD39531711E29700CF925C /* avatar-5.png in Resources */,
|
||||
DA73049E194E022700E72520 /* ui_spinner@2x.png in Resources */,
|
||||
DABD39541711E29700CF925C /* avatar-5@2x.png in Resources */,
|
||||
DA32D05019D2F59B004F3F0E /* meter_fuel.png in Resources */,
|
||||
DA250A031956484D00AC23F1 /* image-7@2x.png in Resources */,
|
||||
DA25C5FA197CCAE00046CDCF /* icon_delete.png in Resources */,
|
||||
DA25C601197DBF260046CDCF /* icon_trash@2x.png in Resources */,
|
||||
@ -3168,6 +3198,7 @@
|
||||
DA45224719062899008F650A /* icon_settings.png in Resources */,
|
||||
DABD395E1711E29700CF925C /* background@2x.png in Resources */,
|
||||
DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */,
|
||||
DA32D04E19D2F59B004F3F0E /* meter_fuel@3x.png in Resources */,
|
||||
DA250A101956484D00AC23F1 /* image-1.png in Resources */,
|
||||
DA25C5FE197DBF200046CDCF /* icon_thumbs-up.png in Resources */,
|
||||
DABD39871711E29700CF925C /* SourceCodePro-Black.otf in Resources */,
|
||||
@ -3214,6 +3245,7 @@
|
||||
DABD3B971711E29800CF925C /* pull-up.png in Resources */,
|
||||
DABD3B981711E29800CF925C /* pull-up@2x.png in Resources */,
|
||||
DA7304A0194E022B00E72520 /* ui_textfield@2x.png in Resources */,
|
||||
DA32D04819D2F417004F3F0E /* thumb_fuel@3x.png in Resources */,
|
||||
DA452249190628A1008F650A /* icon_wrench.png in Resources */,
|
||||
DA45224819062899008F650A /* icon_settings@2x.png in Resources */,
|
||||
DA250A001956484D00AC23F1 /* image-9.png in Resources */,
|
||||
@ -3221,6 +3253,7 @@
|
||||
DABD3C241711E2DC00CF925C /* MasterPassword.entitlements in Resources */,
|
||||
DABD3C251711E2DC00CF925C /* Settings.bundle in Resources */,
|
||||
DABD3C261711E2DC00CF925C /* InfoPlist.strings in Resources */,
|
||||
DA32D05119D3D107004F3F0E /* icon_meter.png in Resources */,
|
||||
DA25C5F8197AFFB40046CDCF /* icon_tools.png in Resources */,
|
||||
DA250A0B1956484D00AC23F1 /* image-3@2x.png in Resources */,
|
||||
DABD3FCA1712446200CF925C /* cloud.png in Resources */,
|
||||
@ -3331,6 +3364,7 @@
|
||||
93D390C1B93F9D3AE37DD0A5 /* MPAnswersViewController.m in Sources */,
|
||||
93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */,
|
||||
93D39A27F2506C6FEEF9C588 /* MPAlgorithmV2.m in Sources */,
|
||||
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -3959,6 +3993,7 @@
|
||||
DA32D03019D111C7004F3F0E /* AppStore-iOS */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = "AdHoc-iOS";
|
||||
};
|
||||
DA5BFA3E147E415C00F98B1E /* Build configuration list for PBXProject "MasterPassword-iOS" */ = {
|
||||
isa = XCConfigurationList;
|
||||
|
@ -28,6 +28,7 @@
|
||||
<string>Exo2.0-Bold</string>
|
||||
<string>Exo2.0-Bold</string>
|
||||
<string>Exo2.0-Bold</string>
|
||||
<string>Exo2.0-Bold</string>
|
||||
</mutableArray>
|
||||
<mutableArray key="Exo2.0-ExtraBold.otf">
|
||||
<string>Exo2.0-ExtraBold</string>
|
||||
@ -65,6 +66,8 @@
|
||||
<string>Exo2.0-Regular</string>
|
||||
<string>Exo2.0-Regular</string>
|
||||
<string>Exo2.0-Regular</string>
|
||||
<string>Exo2.0-Regular</string>
|
||||
<string>Exo2.0-Regular</string>
|
||||
</mutableArray>
|
||||
<mutableArray key="Exo2.0-Thin.otf">
|
||||
<string>Exo2.0-Thin</string>
|
||||
@ -84,6 +87,7 @@
|
||||
<string>Exo2.0-Thin</string>
|
||||
<string>Exo2.0-Thin</string>
|
||||
<string>Exo2.0-Thin</string>
|
||||
<string>Exo2.0-Thin</string>
|
||||
</mutableArray>
|
||||
<mutableArray key="SourceCodePro-Black.otf">
|
||||
<string>SourceCodePro-Black</string>
|
||||
@ -112,11 +116,11 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="VGz-R0-vMD"/>
|
||||
</layoutGuides>
|
||||
<view key="view" clipsSubviews="YES" contentMode="scaleToFill" id="DOr-Xu-P9q" userLabel="Root">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="X8H-vh-j7B" userLabel="Keyboard">
|
||||
<rect key="frame" x="0.0" y="431" width="375" height="216"/>
|
||||
<rect key="frame" x="0.0" y="451" width="375" height="216"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="216" id="GcG-kq-fq2"/>
|
||||
@ -124,13 +128,13 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rWM-08-aab" userLabel="Users Root">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<subviews>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="VDd-oM-ZOO" userLabel="Store Activity">
|
||||
<rect key="frame" x="169" y="305" width="37" height="37"/>
|
||||
<rect key="frame" x="169" y="315" width="37" height="37"/>
|
||||
</activityIndicatorView>
|
||||
<collectionView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" alpha="0.0" contentMode="scaleToFill" minimumZoomScale="0.0" maximumZoomScale="0.0" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="L6J-pd-gcp" userLabel="Avatar Collection">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="ATB-kM-EGu">
|
||||
<size key="itemSize" width="215" height="647"/>
|
||||
@ -147,7 +151,7 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<navigationBar hidden="YES" contentMode="scaleToFill" verticalHuggingPriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="CQo-kd-XAU">
|
||||
<rect key="frame" x="0.0" y="0.0" width="215" height="44"/>
|
||||
<rect key="frame" x="0.0" y="20" width="215" height="44"/>
|
||||
</navigationBar>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="J7b-uT-zY2" userLabel="Keyboard">
|
||||
<rect key="frame" x="0.0" y="431" width="215" height="216"/>
|
||||
@ -157,10 +161,10 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_spinner.png" translatesAutoresizingMaskIntoConstraints="NO" id="y4j-ds-HM7" userLabel="Spinner">
|
||||
<rect key="frame" x="52" y="-33" width="110" height="110"/>
|
||||
<rect key="frame" x="52" y="-13" width="110" height="110"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar-0.png" translatesAutoresizingMaskIntoConstraints="NO" id="Aca-he-7Qi" userLabel="Avatar">
|
||||
<rect key="frame" x="52" y="-33" width="110" height="110"/>
|
||||
<rect key="frame" x="52" y="-13" width="110" height="110"/>
|
||||
<color key="tintColor" red="0.47450980390000003" green="0.86666666670000003" blue="0.98431372549999996" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="110" id="Ezz-dq-dfq"/>
|
||||
@ -168,7 +172,7 @@
|
||||
</constraints>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0Sa-Vg-EEI" userLabel="Name Backdrop">
|
||||
<rect key="frame" x="43" y="14" width="128.5" height="16"/>
|
||||
<rect key="frame" x="43" y="34" width="128.5" height="16"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalCompressionResistancePriority="1000" text="Maarten Billemont" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cLT-s0-4SQ" userLabel="Name Field">
|
||||
<rect key="frame" x="5" y="0.0" width="118.5" height="16"/>
|
||||
@ -201,7 +205,7 @@
|
||||
<constraint firstAttribute="trailing" secondItem="J7b-uT-zY2" secondAttribute="trailing" id="SFQ-jz-Kj4"/>
|
||||
<constraint firstItem="y4j-ds-HM7" firstAttribute="centerY" secondItem="Aca-he-7Qi" secondAttribute="centerY" id="b7q-13-zb4"/>
|
||||
<constraint firstAttribute="centerY" secondItem="Aca-he-7Qi" secondAttribute="centerY" priority="500" id="fKx-ZZ-sJa"/>
|
||||
<constraint firstItem="CQo-kd-XAU" firstAttribute="top" secondItem="Zab-uQ-uk9" secondAttribute="top" id="kO6-Hn-9ab"/>
|
||||
<constraint firstItem="CQo-kd-XAU" firstAttribute="top" secondItem="Zab-uQ-uk9" secondAttribute="top" constant="20" id="kO6-Hn-9ab"/>
|
||||
<constraint firstAttribute="bottom" secondItem="J7b-uT-zY2" secondAttribute="bottom" id="sKD-RY-oA8"/>
|
||||
<constraint firstItem="CQo-kd-XAU" firstAttribute="leading" secondItem="Zab-uQ-uk9" secondAttribute="leading" id="trm-Bp-zf3"/>
|
||||
<constraint firstItem="y4j-ds-HM7" firstAttribute="height" secondItem="Aca-he-7Qi" secondAttribute="height" id="wyT-4c-SaV"/>
|
||||
@ -233,7 +237,7 @@
|
||||
</connections>
|
||||
</collectionView>
|
||||
<button opaque="NO" alpha="0.69999999999999996" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9u7-pu-Wtv" userLabel="Previous Avatar">
|
||||
<rect key="frame" x="0.0" y="224.5" width="44" height="53"/>
|
||||
<rect key="frame" x="0.0" y="244" width="44" height="53"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="44" id="Ay6-Jg-c3T"/>
|
||||
</constraints>
|
||||
@ -246,7 +250,7 @@
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" alpha="0.69999999999999996" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fUK-gJ-NRE" userLabel="Next Avatar">
|
||||
<rect key="frame" x="331" y="224.5" width="44" height="53"/>
|
||||
<rect key="frame" x="331" y="244" width="44" height="53"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="44" id="oAm-YX-Fx5"/>
|
||||
</constraints>
|
||||
@ -259,7 +263,7 @@
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qp1-nX-o4i" userLabel="Entry">
|
||||
<rect key="frame" x="20" y="340.5" width="335" height="70.5"/>
|
||||
<rect key="frame" x="20" y="360" width="335" height="70.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Enter your full name:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="5fe-rt-zFa" userLabel="Entry Label">
|
||||
<rect key="frame" x="20" y="0.0" width="295" height="20.5"/>
|
||||
@ -337,7 +341,7 @@
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XEP-O3-ayG" userLabel="Footer">
|
||||
<rect key="frame" x="0.0" y="575" width="375" height="72"/>
|
||||
<rect key="frame" x="0.0" y="595" width="375" height="72"/>
|
||||
<subviews>
|
||||
<button opaque="NO" alpha="0.5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4md-Gp-SLG">
|
||||
<rect key="frame" x="20" y="48" width="335" height="24"/>
|
||||
@ -410,12 +414,12 @@
|
||||
<constraints>
|
||||
<constraint firstItem="VGz-R0-vMD" firstAttribute="top" secondItem="X8H-vh-j7B" secondAttribute="bottom" id="8Ed-3Y-ll0"/>
|
||||
<constraint firstAttribute="trailing" secondItem="X8H-vh-j7B" secondAttribute="trailing" id="8Gr-Dq-UpZ"/>
|
||||
<constraint firstAttribute="bottom" secondItem="rWM-08-aab" secondAttribute="bottom" id="9Yx-cj-wHh"/>
|
||||
<constraint firstItem="X8H-vh-j7B" firstAttribute="top" secondItem="9u7-pu-Wtv" secondAttribute="centerY" constant="180" id="Gp5-h6-53S"/>
|
||||
<constraint firstItem="rWM-08-aab" firstAttribute="leading" secondItem="DOr-Xu-P9q" secondAttribute="leading" id="Il8-kg-Dra"/>
|
||||
<constraint firstItem="X8H-vh-j7B" firstAttribute="top" secondItem="fUK-gJ-NRE" secondAttribute="centerY" constant="180" id="PgC-ZL-cQo"/>
|
||||
<constraint firstAttribute="trailing" secondItem="rWM-08-aab" secondAttribute="trailing" id="UPP-1n-zIe"/>
|
||||
<constraint firstItem="X8H-vh-j7B" firstAttribute="top" secondItem="qp1-nX-o4i" secondAttribute="bottom" constant="20" id="WdK-tA-njz"/>
|
||||
<constraint firstItem="VGz-R0-vMD" firstAttribute="top" secondItem="rWM-08-aab" secondAttribute="bottom" id="fcH-lm-76a"/>
|
||||
<constraint firstItem="X8H-vh-j7B" firstAttribute="leading" secondItem="DOr-Xu-P9q" secondAttribute="leading" id="jbn-ko-MPq"/>
|
||||
<constraint firstAttribute="top" secondItem="rWM-08-aab" secondAttribute="top" id="xBe-1Q-mz2"/>
|
||||
</constraints>
|
||||
@ -537,7 +541,7 @@
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="V6W-ql-3TD"/>
|
||||
<connections>
|
||||
<segue destination="Ac5-na-hOV" kind="custom" identifier="root" customClass="MPOverlaySegue" id="UKS-gd-oD2"/>
|
||||
<segue destination="Ac5-na-hOV" kind="custom" identifier="root" customClass="MPRootSegue" id="UKS-gd-oD2"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="fQY-fV-sIe" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
@ -559,30 +563,20 @@
|
||||
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" translatesAutoresizingMaskIntoConstraints="NO" id="Lkg-xn-bce" userLabel="Background">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
</imageView>
|
||||
<containerView clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jDK-5y-QRP" userLabel="Users">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
|
||||
<connections>
|
||||
<segue destination="S8q-YF-Kt9" kind="embed" identifier="users" id="9AR-TX-BkY"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="lXD-AZ-Umi" firstAttribute="top" secondItem="Lkg-xn-bce" secondAttribute="bottom" id="4xV-YK-k7B"/>
|
||||
<constraint firstItem="Lkg-xn-bce" firstAttribute="top" secondItem="fkJ-D0-yue" secondAttribute="top" id="EIy-Cd-0vW"/>
|
||||
<constraint firstItem="jDK-5y-QRP" firstAttribute="top" secondItem="zOG-3W-l4v" secondAttribute="bottom" id="GFh-An-RJs"/>
|
||||
<constraint firstAttribute="trailing" secondItem="jDK-5y-QRP" secondAttribute="trailing" id="L2M-Eb-kwd"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Lkg-xn-bce" secondAttribute="trailing" id="ROW-fK-z92"/>
|
||||
<constraint firstItem="lXD-AZ-Umi" firstAttribute="top" secondItem="jDK-5y-QRP" secondAttribute="bottom" id="TUm-Qo-P4W"/>
|
||||
<constraint firstItem="Lkg-xn-bce" firstAttribute="leading" secondItem="fkJ-D0-yue" secondAttribute="leading" id="UH5-Kk-taJ"/>
|
||||
<constraint firstItem="jDK-5y-QRP" firstAttribute="leading" secondItem="fkJ-D0-yue" secondAttribute="leading" id="jPw-0w-Fbo"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Lkg-xn-bce" secondAttribute="bottom" id="txR-pf-v3l"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="MPa-zX-Kaq"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<connections>
|
||||
<outlet property="usersView" destination="jDK-5y-QRP" id="cuP-gN-eBE"/>
|
||||
<segue destination="osn-5H-SWW" kind="custom" identifier="emergency" customClass="MPOverlaySegue" id="gtX-Cx-AA2"/>
|
||||
<segue destination="nkY-z6-8jd" kind="custom" identifier="passwords" customClass="MPPasswordsSegue" id="Ozp-YT-Utx"/>
|
||||
<segue destination="S8q-YF-Kt9" kind="custom" identifier="users" customClass="MPRootSegue" id="StK-nr-nps"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="F33-Fe-Tb6" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
@ -2692,6 +2686,82 @@ See </string>
|
||||
<outlet property="purchasedIndicator" destination="yZX-ns-8oV" id="7x0-eq-oSs"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" rowHeight="328" id="le3-Q5-MSO" userLabel="Fuel" customClass="MPStoreProductCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="97"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="le3-Q5-MSO" id="SzQ-Y5-XIF">
|
||||
<rect key="frame" x="0.0" y="0.0" width="287" height="96"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="751" text="Fuel Top-Up" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="12" adjustsLetterSpacingToFitWidth="YES" preferredMaxLayoutWidth="292" translatesAutoresizingMaskIntoConstraints="NO" id="Jnv-uN-xeg">
|
||||
<rect key="frame" x="20" y="226" width="292" height="20.5"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fz2-AO-aGW">
|
||||
<rect key="frame" x="20" y="254" width="335" height="53.5"/>
|
||||
<string key="text">You really love Master Password and how it's solving your password problems. You're eager to encourage the maintenance, technical support and development of new features. I am a one-man shop, more fuel means I can allocate more hours to Master Password.</string>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Thin" family="Exo 2.0" pointSize="11"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="thumb_fuel.png" translatesAutoresizingMaskIntoConstraints="NO" id="PnG-hP-syh">
|
||||
<rect key="frame" x="88" y="20" width="198" height="198"/>
|
||||
</imageView>
|
||||
<activityIndicatorView hidden="YES" opaque="NO" tag="2" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="eS4-59-Xny">
|
||||
<rect key="frame" x="169" y="100" width="37" height="37"/>
|
||||
</activityIndicatorView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="751" text="$2.95" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="35.5" translatesAutoresizingMaskIntoConstraints="NO" id="EbU-DV-fKF">
|
||||
<rect key="frame" x="320" y="226" width="34.5" height="20.5"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="14"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="meter_fuel.png" translatesAutoresizingMaskIntoConstraints="NO" id="aGb-QC-A92">
|
||||
<rect key="frame" x="261" y="208" width="12" height="10"/>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dsR-fr-dY4">
|
||||
<rect key="frame" x="20" y="20" width="107" height="44"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="W6p-kB-VBX"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="14"/>
|
||||
<state key="normal" title="1h / quarter" image="icon_meter.png">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="toggleFuelConsumption:" destination="pdl-xv-zjX" eventType="touchUpInside" id="NkB-Dy-IeY"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="aGb-QC-A92" firstAttribute="bottom" secondItem="PnG-hP-syh" secondAttribute="bottom" id="0Jx-M5-xlh"/>
|
||||
<constraint firstItem="Jnv-uN-xeg" firstAttribute="leading" secondItem="SzQ-Y5-XIF" secondAttribute="leading" constant="20" symbolic="YES" id="1ng-ce-JH9"/>
|
||||
<constraint firstItem="Jnv-uN-xeg" firstAttribute="top" secondItem="EbU-DV-fKF" secondAttribute="top" id="F04-ip-fHo"/>
|
||||
<constraint firstItem="fz2-AO-aGW" firstAttribute="top" secondItem="Jnv-uN-xeg" secondAttribute="bottom" constant="8" symbolic="YES" id="F3H-iv-edF"/>
|
||||
<constraint firstItem="fz2-AO-aGW" firstAttribute="leading" secondItem="SzQ-Y5-XIF" secondAttribute="leading" constant="20" symbolic="YES" id="G6B-g9-Z35"/>
|
||||
<constraint firstItem="PnG-hP-syh" firstAttribute="top" secondItem="SzQ-Y5-XIF" secondAttribute="top" constant="20" symbolic="YES" id="JNg-lM-Jns"/>
|
||||
<constraint firstItem="Jnv-uN-xeg" firstAttribute="bottom" secondItem="EbU-DV-fKF" secondAttribute="bottom" id="KbL-rF-pVN"/>
|
||||
<constraint firstItem="Jnv-uN-xeg" firstAttribute="top" secondItem="PnG-hP-syh" secondAttribute="bottom" constant="8" symbolic="YES" id="OZV-m1-YZ1"/>
|
||||
<constraint firstItem="dsR-fr-dY4" firstAttribute="top" secondItem="SzQ-Y5-XIF" secondAttribute="top" constant="20" id="VH2-O8-CGj"/>
|
||||
<constraint firstAttribute="bottom" secondItem="fz2-AO-aGW" secondAttribute="bottom" constant="20" symbolic="YES" id="Wqo-Le-AcG"/>
|
||||
<constraint firstItem="eS4-59-Xny" firstAttribute="centerX" secondItem="PnG-hP-syh" secondAttribute="centerX" id="ZbQ-LX-kmS"/>
|
||||
<constraint firstItem="EbU-DV-fKF" firstAttribute="leading" secondItem="Jnv-uN-xeg" secondAttribute="trailing" constant="8" symbolic="YES" id="cku-JX-4bK"/>
|
||||
<constraint firstItem="aGb-QC-A92" firstAttribute="centerX" secondItem="PnG-hP-syh" secondAttribute="centerX" constant="80" id="eMa-Gj-BUc"/>
|
||||
<constraint firstItem="dsR-fr-dY4" firstAttribute="leading" secondItem="SzQ-Y5-XIF" secondAttribute="leading" constant="20" id="eX0-7y-eHi"/>
|
||||
<constraint firstAttribute="centerX" secondItem="PnG-hP-syh" secondAttribute="centerX" id="gO5-ME-YVO"/>
|
||||
<constraint firstAttribute="trailing" secondItem="EbU-DV-fKF" secondAttribute="trailing" constant="20" id="hae-Jv-wOU"/>
|
||||
<constraint firstAttribute="trailing" secondItem="fz2-AO-aGW" secondAttribute="trailing" constant="20" id="vlt-qH-1Xx"/>
|
||||
<constraint firstItem="eS4-59-Xny" firstAttribute="centerY" secondItem="PnG-hP-syh" secondAttribute="centerY" id="yUc-2F-y1r"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="eS4-59-Xny" id="kGW-fn-VqH"/>
|
||||
<outlet property="priceLabel" destination="EbU-DV-fKF" id="pg2-8o-7We"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
<tableViewSection id="hN1-J4-w3w">
|
||||
@ -2745,6 +2815,9 @@ See </string>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<connections>
|
||||
<outlet property="fuelCell" destination="le3-Q5-MSO" id="oAk-6g-cFj"/>
|
||||
<outlet property="fuelMeterConstraint" destination="eMa-Gj-BUc" id="9iF-EO-UU6"/>
|
||||
<outlet property="fuelSpeedButton" destination="dsR-fr-dY4" id="XGI-PE-9mh"/>
|
||||
<outlet property="generateAnswersCell" destination="l1g-Ul-Vg8" id="GlG-iZ-7FP"/>
|
||||
<outlet property="generateLoginCell" destination="JVW-tG-xxe" id="PXM-WX-8Qe"/>
|
||||
<outlet property="iOSIntegrationCell" destination="9Na-CL-jBq" id="LSO-OV-9KA"/>
|
||||
@ -2753,7 +2826,7 @@ See </string>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="WvF-bk-cgx" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2624.5" y="463.5"/>
|
||||
<point key="canvasLocation" x="2624.5" y="427.5"/>
|
||||
</scene>
|
||||
<!--Answers View Controller-->
|
||||
<scene sceneID="OG6-nJ-1A0">
|
||||
@ -2956,6 +3029,7 @@ See </string>
|
||||
<image name="icon_edit.png" width="32" height="32"/>
|
||||
<image name="icon_gears.png" width="32" height="32"/>
|
||||
<image name="icon_list-names.png" width="32" height="32"/>
|
||||
<image name="icon_meter.png" width="32" height="32"/>
|
||||
<image name="icon_person.png" width="32" height="32"/>
|
||||
<image name="icon_plus.png" width="32" height="32"/>
|
||||
<image name="icon_question.png" width="32" height="32"/>
|
||||
@ -2966,6 +3040,8 @@ See </string>
|
||||
<image name="icon_up.png" width="32" height="32"/>
|
||||
<image name="identity.png" width="82" height="80"/>
|
||||
<image name="image-0.png" width="320" height="568"/>
|
||||
<image name="meter_fuel.png" width="12" height="10"/>
|
||||
<image name="thumb_fuel.png" width="198" height="198"/>
|
||||
<image name="thumb_generated_answers.png" width="198" height="198"/>
|
||||
<image name="thumb_generated_login.png" width="198" height="198"/>
|
||||
<image name="tip_basic_black.png" width="210" height="60"/>
|
||||
@ -2979,7 +3055,7 @@ See </string>
|
||||
<simulatedScreenMetrics key="destination" type="retina47"/>
|
||||
</simulatedMetricsContainer>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="GZk-I4-JyH"/>
|
||||
<segue reference="gtb-zE-u9H"/>
|
||||
<segue reference="Ql4-wf-T8u"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
<color key="tintColor" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
|
BIN
MasterPassword/Resources/Media/meter_fuel.png
Normal file
BIN
MasterPassword/Resources/Media/meter_fuel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 366 B |
BIN
MasterPassword/Resources/Media/meter_fuel@2x.png
Normal file
BIN
MasterPassword/Resources/Media/meter_fuel@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 437 B |
BIN
MasterPassword/Resources/Media/meter_fuel@3x.png
Normal file
BIN
MasterPassword/Resources/Media/meter_fuel@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
MasterPassword/Resources/Media/thumb_fuel.png
Normal file
BIN
MasterPassword/Resources/Media/thumb_fuel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 906 B |
BIN
MasterPassword/Resources/Media/thumb_fuel@2x.png
Normal file
BIN
MasterPassword/Resources/Media/thumb_fuel@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
MasterPassword/Resources/Media/thumb_fuel@3x.png
Normal file
BIN
MasterPassword/Resources/Media/thumb_fuel@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
Loading…
Reference in New Issue
Block a user