mirror of https://github.com/BTCPrivate/copay.git
lock by PIN
This commit is contained in:
parent
94dd6fd3e8
commit
6a0555773f
|
@ -1,14 +1,16 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Platform } from 'ionic-angular';
|
||||
import { Platform, ModalController } from 'ionic-angular';
|
||||
import { StatusBar } from '@ionic-native/status-bar';
|
||||
import { SplashScreen } from '@ionic-native/splash-screen';
|
||||
|
||||
import { Logger } from '@nsalaun/ng-logger';
|
||||
import { AppProvider } from '../providers/app/app';
|
||||
import { ProfileProvider } from '../providers/profile/profile';
|
||||
import { ConfigProvider } from '../providers/config/config';
|
||||
|
||||
import { TabsPage } from '../pages/tabs/tabs';
|
||||
import { OnboardingPage } from '../pages/onboarding/onboarding';
|
||||
import { PinModalPage } from '../pages/pin/pin';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'app.html'
|
||||
|
@ -22,7 +24,9 @@ export class CopayApp {
|
|||
private splashScreen: SplashScreen,
|
||||
private logger: Logger,
|
||||
private app: AppProvider,
|
||||
private profile: ProfileProvider
|
||||
private profile: ProfileProvider,
|
||||
private config: ConfigProvider,
|
||||
private modalCtrl: ModalController
|
||||
) {
|
||||
|
||||
this.initializeApp();
|
||||
|
@ -44,6 +48,7 @@ export class CopayApp {
|
|||
this.profile.get().then((profile: any) => {
|
||||
if (profile) {
|
||||
this.logger.info('Profile read. Go to HomePage.');
|
||||
this.openLockModal();
|
||||
this.rootPage = TabsPage;
|
||||
} else {
|
||||
// TODO: go to onboarding page
|
||||
|
@ -53,4 +58,16 @@ export class CopayApp {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
openLockModal() {
|
||||
let config = this.config.get();
|
||||
let lockMethod = config['lock'] && config['lock']['method'];
|
||||
if (!config['lock']['method']) return;
|
||||
if (config['lock']['method'] == 'PIN') this.openPINModal('checkPin');
|
||||
}
|
||||
|
||||
openPINModal(action) {
|
||||
let modal = this.modalCtrl.create(PinModalPage, { action }, { showBackdrop: false, enableBackdropDismiss: false });
|
||||
modal.present();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ import { SettingsPage } from '../pages/settings/settings';
|
|||
import { AboutPage } from '../pages/settings/about/about';
|
||||
import { AdvancedPage } from '../pages/settings/advanced/advanced';
|
||||
import { AltCurrencyPage } from '../pages/settings/alt-currency/alt-currency';
|
||||
import { LockPage } from '../pages/settings/lock/lock';
|
||||
import { PinModalPage } from '../pages/pin/pin';
|
||||
import { TermsOfUsePage } from '../pages/settings/about/terms-of-use/terms-of-use';
|
||||
|
||||
/* Send */
|
||||
|
@ -84,7 +86,9 @@ let pages: any = [
|
|||
DisclaimerPage,
|
||||
EmailPage,
|
||||
HomePage,
|
||||
LockPage,
|
||||
OnboardingPage,
|
||||
PinModalPage,
|
||||
ReceivePage,
|
||||
SendPage,
|
||||
ScanPage,
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<ion-header>
|
||||
|
||||
<ion-navbar>
|
||||
<ion-buttons start>
|
||||
<button *ngIf="action === 'pinSetUp'" (click)="goBack()" ion-button icon-only>
|
||||
<ion-icon name="arrow-back"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
<ion-title *ngIf="!confirmingPin">Please enter your PIN</ion-title>
|
||||
<ion-title *ngIf="confirmingPin">Confirm your PIN</ion-title>
|
||||
</ion-navbar>
|
||||
|
||||
</ion-header>
|
||||
|
||||
<ion-content padding>
|
||||
<div class="block-code">
|
||||
<div class="circle-{{appName}}" [ngClass]="getFilledClass(1)"></div>
|
||||
<div class="circle-{{appName}}" [ngClass]="getFilledClass(2)"></div>
|
||||
<div class="circle-{{appName}}" [ngClass]="getFilledClass(3)"></div>
|
||||
<div class="circle-{{appName}}" [ngClass]="getFilledClass(4)"></div>
|
||||
</div>
|
||||
<div class="block-buttons">
|
||||
<div class="row">
|
||||
<div (click)="newEntry('1')">1</div>
|
||||
<div (click)="newEntry('2')">2</div>
|
||||
<div (click)="newEntry('3')">3</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div (click)="newEntry('4')">4</div>
|
||||
<div (click)="newEntry('5')">5</div>
|
||||
<div (click)="newEntry('6')">6</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div (click)="newEntry('7')">7</div>
|
||||
<div (click)="newEntry('8')">8</div>
|
||||
<div (click)="newEntry('9')">9</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div></div>
|
||||
<div (click)="newEntry('0')">0</div>
|
||||
<div (click)="delete()">
|
||||
<ion-icon name="arrow-round-back"></ion-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
|
@ -0,0 +1,41 @@
|
|||
page-pin {
|
||||
.block-code {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
max-width: 300px;
|
||||
margin: auto;
|
||||
}
|
||||
.block-buttons{
|
||||
.row {
|
||||
font-size: 1.7rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
div {
|
||||
padding: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@mixin circle {
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 3px 0px #5b5b5b;
|
||||
transition: background-color .2s ease-in-out;
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
margin: 10px;
|
||||
}
|
||||
.circle-copay {
|
||||
@include circle;
|
||||
border: 1px solid #1f3598;
|
||||
}
|
||||
.circle-bitpay {
|
||||
@include circle;
|
||||
border: 1px solid #1f3598;
|
||||
}
|
||||
.filled-copay {
|
||||
background-color: #1f3598;
|
||||
}
|
||||
.filled-bitpay {
|
||||
background-color: #1f3598;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { NavController, NavParams, ViewController } from 'ionic-angular';
|
||||
import { ConfigProvider } from '../../providers/config/config';
|
||||
import { Logger } from '@nsalaun/ng-logger';
|
||||
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@Component({
|
||||
selector: 'page-pin',
|
||||
templateUrl: 'pin.html',
|
||||
})
|
||||
export class PinModalPage {
|
||||
|
||||
public currentPin: string = '';
|
||||
public firstPinEntered: string = '';
|
||||
public confirmingPin: boolean = false;
|
||||
public action: string = '';
|
||||
public appName: string = 'copay';
|
||||
|
||||
constructor(
|
||||
public navCtrl: NavController,
|
||||
public navParams: NavParams,
|
||||
private config: ConfigProvider,
|
||||
private logger: Logger,
|
||||
public viewCtrl: ViewController
|
||||
) {
|
||||
|
||||
switch (this.navParams.get('action')) {
|
||||
case 'checkPin':
|
||||
this.action = 'checkPin';
|
||||
break;
|
||||
case 'pinSetUp':
|
||||
this.action = 'pinSetUp';
|
||||
break;
|
||||
case 'removeLock':
|
||||
this.action = 'removeLock'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
goBack(): void {
|
||||
this.navCtrl.pop();
|
||||
}
|
||||
|
||||
newEntry(value: string): void {
|
||||
this.currentPin = this.currentPin + value;
|
||||
if (!this.isComplete()) return;
|
||||
if (this.action === 'checkPin' || this.action === 'removeLock') this.checkIfCorrect();
|
||||
if (this.action === 'pinSetUp') {
|
||||
if (!this.confirmingPin) {
|
||||
this.confirmingPin = true;
|
||||
this.firstPinEntered = this.currentPin;
|
||||
this.currentPin = '';
|
||||
}
|
||||
else if (this.firstPinEntered === this.currentPin) this.save();
|
||||
else {
|
||||
this.firstPinEntered = this.currentPin = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete(): void {
|
||||
this.currentPin = this.currentPin.substring(0, this.currentPin.length - 1);
|
||||
}
|
||||
|
||||
isComplete(): boolean {
|
||||
if (this.currentPin.length < 4) return false;
|
||||
else return true;
|
||||
};
|
||||
|
||||
save(): void {
|
||||
let lock = { method: 'PIN', value: this.currentPin, bannedUntil: null };
|
||||
this.config.set({ lock });
|
||||
this.viewCtrl.dismiss();
|
||||
}
|
||||
|
||||
checkIfCorrect(): void {
|
||||
let config = this.config.get();
|
||||
let pinValue = config['lock'] && config['lock']['value'];
|
||||
if (pinValue == this.currentPin) {
|
||||
if (this.action === 'removeLock') {
|
||||
let lock = { method: 'Disabled', value: null, bannedUntil: null };
|
||||
this.config.set({ lock });
|
||||
this.viewCtrl.dismiss();
|
||||
}
|
||||
if (this.action === 'checkPin') this.viewCtrl.dismiss();
|
||||
}
|
||||
else this.currentPin = '';
|
||||
}
|
||||
|
||||
getFilledClass(limit): string {
|
||||
return this.currentPin.length >= limit ? 'filled-' + this.appName : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<ion-header>
|
||||
|
||||
<ion-navbar>
|
||||
<ion-title>Lock</ion-title>
|
||||
</ion-navbar>
|
||||
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-list radio-group>
|
||||
<ion-list-header>
|
||||
Startup lock by
|
||||
</ion-list-header>
|
||||
|
||||
<ion-item *ngFor="let opt of options">
|
||||
<ion-label>{{opt.method}}</ion-label>
|
||||
<ion-radio (click)="select(opt.method)" value="{{opt.method}}" checked="{{opt.enabled}}"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</ion-content>
|
|
@ -0,0 +1,47 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { NavController, NavParams, ModalController } from 'ionic-angular';
|
||||
import { ConfigProvider } from '../../../providers/config/config';
|
||||
|
||||
import { PinModalPage } from '../../pin/pin';
|
||||
|
||||
@Component({
|
||||
selector: 'page-lock',
|
||||
templateUrl: 'lock.html',
|
||||
})
|
||||
export class LockPage {
|
||||
public options: Array<{ method: string, enabled: boolean }> = [];
|
||||
public lockOptions: Object;
|
||||
|
||||
constructor(
|
||||
private modalCtrl: ModalController,
|
||||
private config: ConfigProvider
|
||||
) {
|
||||
|
||||
this.lockOptions = this.config.get()['lock'];
|
||||
this.options = [
|
||||
{
|
||||
method: 'Disabled',
|
||||
enabled: this.lockOptions['method'] == 'Disabled' ? true : false
|
||||
},
|
||||
{
|
||||
method: 'PIN',
|
||||
enabled: this.lockOptions['method'] == 'PIN' ? true : false
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
select(method): void {
|
||||
switch (method) {
|
||||
case 'PIN':
|
||||
this.openPinModal('pinSetUp');
|
||||
break;
|
||||
case 'Disabled':
|
||||
this.openPinModal('removeLock');
|
||||
}
|
||||
}
|
||||
|
||||
openPinModal(action) {
|
||||
let modal = this.modalCtrl.create(PinModalPage, { action });
|
||||
modal.present();
|
||||
}
|
||||
}
|
|
@ -57,18 +57,12 @@
|
|||
<ion-option>Urgent</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-item (click)="openLockPage()">
|
||||
<ion-icon name="lock" item-start></ion-icon>
|
||||
<ion-label>
|
||||
Lock
|
||||
</ion-label>
|
||||
<ion-select>
|
||||
<ion-option value="">Disabled</ion-option>
|
||||
<ion-option value="pin">Lock by PIN</ion-option>
|
||||
<ion-option value="finger">Lock by fingerprint</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item-divider color="light">Wallets & integrations</ion-item-divider>
|
||||
<ion-item>
|
||||
<ion-icon name="folder" item-start></ion-icon>
|
||||
|
|
|
@ -5,7 +5,7 @@ import { AppProvider } from '../../providers/app/app';
|
|||
import { LanguageProvider } from '../../providers/language/language';
|
||||
import { RateProvider } from '../../providers/rate/rate';
|
||||
import { AltCurrencyPage } from './alt-currency/alt-currency';
|
||||
|
||||
import { LockPage } from './lock/lock';
|
||||
import { AboutPage } from './about/about';
|
||||
import { AdvancedPage } from './advanced/advanced';
|
||||
|
||||
|
@ -55,4 +55,8 @@ export class SettingsPage {
|
|||
this.navCtrl.push(AboutPage);
|
||||
}
|
||||
|
||||
openLockPage() {
|
||||
this.navCtrl.push(LockPage);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -123,7 +123,6 @@ export class ConfigProvider {
|
|||
if (_.isString(newOpts)) {
|
||||
newOpts = JSON.parse(newOpts);
|
||||
}
|
||||
|
||||
_.merge(config, this.configCache, newOpts);
|
||||
this.configCache = config;
|
||||
this.persistence.storeConfig(this.configCache).then(() => {
|
||||
|
|
Loading…
Reference in New Issue