2
0
MasterPassword/platform-darwin/Source/iOS/MPPreferencesViewController.m
2020-01-14 13:59:32 -05:00

332 lines
12 KiB
Objective-C

//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
#import "MPPreferencesViewController.h"
#import "MPiOSAppDelegate.h"
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "UIColor+Expanded.h"
#import "MPSitesViewController.h"
#import "MPAppDelegate_InApp.h"
@interface MPPreferencesViewController()
@end
@implementation MPPreferencesViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor clearColor];
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 100;
self.tableView.contentInset = UIEdgeInsetsMake( 64, 0, 49, 0 );
}
- (void)viewWillAppear:(BOOL)animated {
inf( @"Preferences will appear" );
[super viewWillAppear:animated];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"tipped.passwordsPreferences"];
if (![[NSUserDefaults standardUserDefaults] synchronize])
wrn( @"Couldn't synchronize after preferences appearance." );
[self reload];
}
- (void)reload {
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForMainThread];
self.avatarImage.image = [UIImage imageNamed:strf( @"avatar-%lu", (unsigned long)activeUser.avatar )];
self.savePasswordSwitch.on = activeUser.saveKey;
self.touchIDSwitch.on = activeUser.touchID;
self.touchIDSwitch.enabled = self.savePasswordSwitch.on && [[MPiOSAppDelegate get] isFeatureUnlocked:MPProductTouchID];
MPResultType defaultType = activeUser.defaultType;
self.generated1TypeControl.selectedSegmentIndex = [self generated1SegmentIndexForType:defaultType];
self.generated2TypeControl.selectedSegmentIndex = [self generated2SegmentIndexForType:defaultType];
self.storedTypeControl.selectedSegmentIndex = [self storedSegmentIndexForType:defaultType];
PearlNotMainQueue( ^{
NSString *examplePassword = nil;
if (defaultType & MPResultTypeClassTemplate)
examplePassword = [MPAlgorithmDefault mpwTemplateForSiteNamed:@"test" ofType:defaultType
withCounter:1 usingKey:[MPiOSAppDelegate get].key];
PearlMainQueue( ^{
self.typeSamplePassword.text = [examplePassword length]? [NSString stringWithFormat:@"eg. %@", examplePassword]: nil;
} );
} );
}
#pragma mark - UITableViewDelegate
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if (cell.selectionStyle != UITableViewCellSelectionStyleNone) {
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.bounds];
cell.selectedBackgroundView.backgroundColor = [UIColor colorWithRGBAHex:0x78DDFB33];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
if (cell == self.signOutCell) {
[self dismissPopup];
[[MPiOSAppDelegate get] signOutAnimated:YES];
}
if (cell == self.feedbackCell)
[[MPiOSAppDelegate get] showFeedbackWithLogs:YES forVC:self];
if (cell == self.exportCell)
[[MPiOSAppDelegate get] showExportForVC:self];
if (cell == self.showHelpCell) {
MPSitesViewController *passwordsVC = [self dismissPopup];
[passwordsVC performSegueWithIdentifier:@"guide" sender:self];
}
if (cell == self.checkInconsistencies)
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
if ([[MPiOSAppDelegate get] findAndFixInconsistenciesSaveInContext:context] == MPFixableResultNoProblems) {
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"No Inconsistencies" message:
@"No inconsistencies were detected in your sites."
preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:nil]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
}
}];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - IBActions
- (IBAction)valueChanged:(id)sender {
if (sender == self.savePasswordSwitch)
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:context];
if ((activeUser.saveKey = self.savePasswordSwitch.on))
[[MPiOSAppDelegate get] storeSavedKeyFor:activeUser];
else
[[MPiOSAppDelegate get] forgetSavedKeyFor:activeUser];
[context saveToStore];
PearlMainQueue( ^{
[self reload];
} );
}];
if (sender == self.touchIDSwitch)
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:context];
if ((activeUser.touchID = self.touchIDSwitch.on))
[[MPiOSAppDelegate get] storeSavedKeyFor:activeUser];
else
[[MPiOSAppDelegate get] forgetSavedKeyFor:activeUser];
[context saveToStore];
PearlMainQueue( ^{
[self reload];
} );
}];
if (sender == self.generated1TypeControl || sender == self.generated2TypeControl || sender == self.storedTypeControl) {
if (sender != self.generated1TypeControl)
self.generated1TypeControl.selectedSegmentIndex = -1;
if (sender != self.generated2TypeControl)
self.generated2TypeControl.selectedSegmentIndex = -1;
if (sender != self.storedTypeControl)
self.storedTypeControl.selectedSegmentIndex = -1;
MPResultType defaultType = [self typeForSelectedSegment];
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
[[MPiOSAppDelegate get] activeUserInContext:context].defaultType = defaultType;
[context saveToStore];
PearlMainQueue( ^{
[self reload];
} );
}];
}
}
- (IBAction)previousAvatar:(id)sender {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:context];
activeUser.avatar = (activeUser.avatar - 1 + MPAvatarCount) % MPAvatarCount;
[context saveToStore];
NSUInteger avatar = activeUser.avatar;
PearlMainQueue( ^{
self.avatarImage.image = [UIImage imageNamed:strf( @"avatar-%lu", (unsigned long)avatar )];
} );
}];
}
- (IBAction)nextAvatar:(id)sender {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:context];
activeUser.avatar = (activeUser.avatar + 1 + MPAvatarCount) % MPAvatarCount;
[context saveToStore];
NSUInteger avatar = activeUser.avatar;
PearlMainQueue( ^{
self.avatarImage.image = [UIImage imageNamed:strf( @"avatar-%lu", (unsigned long)avatar )];
} );
}];
}
- (IBAction)homePageButton:(id)sender {
[[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender:
[NSURL URLWithString:@"https://masterpassword.app"]];
}
- (IBAction)securityButton:(id)sender {
[[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender:
[NSURL URLWithString:@"https://masterpassword.app/security.html"]];
}
- (IBAction)sourceButton:(id)sender {
[[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender:
[NSURL URLWithString:@"https://gitlab.com/MasterPassword/MasterPassword/"]];
}
- (IBAction)thanksButton:(id)sender {
[[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender:
[NSURL URLWithString:@"https://thanks.lhunath.com"]];
}
#pragma mark - Private
- (MPSitesViewController *)dismissPopup {
for (UIViewController *vc = self; (vc = vc.parentViewController);)
if ([vc isKindOfClass:[MPSitesViewController class]]) {
MPSitesViewController *passwordsVC = (MPSitesViewController *)vc;
[passwordsVC dismissPopdown:self];
return passwordsVC;
}
return nil;
}
- (MPResultType)typeForSelectedSegment {
NSInteger selectedGenerated1Index = self.generated1TypeControl.selectedSegmentIndex;
NSInteger selectedGenerated2Index = self.generated2TypeControl.selectedSegmentIndex;
NSInteger selectedStoredIndex = self.storedTypeControl.selectedSegmentIndex;
switch (selectedGenerated1Index) {
case 0:
return MPResultTypeTemplatePhrase;
case 1:
return MPResultTypeTemplateName;
default:
switch (selectedGenerated2Index) {
case 0:
return MPResultTypeTemplateMaximum;
case 1:
return MPResultTypeTemplateLong;
case 2:
return MPResultTypeTemplateMedium;
case 3:
return MPResultTypeTemplateBasic;
case 4:
return MPResultTypeTemplateShort;
case 5:
return MPResultTypeTemplatePIN;
default:
switch (selectedStoredIndex) {
case 0:
return MPResultTypeStatefulPersonal;
case 1:
return MPResultTypeStatefulDevice;
default:
Throw( @"unsupported selected type index: generated1=%ld, generated2=%ld, stored=%ld",
(long)selectedGenerated1Index, (long)selectedGenerated2Index, (long)selectedStoredIndex );
}
}
}
}
- (NSInteger)generated1SegmentIndexForType:(MPResultType)type {
switch (type) {
case MPResultTypeTemplatePhrase:
return 0;
case MPResultTypeTemplateName:
return 1;
default:
return -1;
}
}
- (NSInteger)generated2SegmentIndexForType:(MPResultType)type {
switch (type) {
case MPResultTypeTemplateMaximum:
return 0;
case MPResultTypeTemplateLong:
return 1;
case MPResultTypeTemplateMedium:
return 2;
case MPResultTypeTemplateBasic:
return 3;
case MPResultTypeTemplateShort:
return 4;
case MPResultTypeTemplatePIN:
return 5;
default:
return -1;
}
}
- (NSInteger)storedSegmentIndexForType:(MPResultType)type {
switch (type) {
case MPResultTypeStatefulPersonal:
return 0;
case MPResultTypeStatefulDevice:
return 1;
default:
return -1;
}
}
@end