diff --git a/src/app/app.component.ts b/src/app/app.component.ts index a3665e62b..99c972a56 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -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(); + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index c71f9bd69..57aabcfd5 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -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, diff --git a/src/pages/pin/pin.html b/src/pages/pin/pin.html new file mode 100644 index 000000000..da3f88781 --- /dev/null +++ b/src/pages/pin/pin.html @@ -0,0 +1,46 @@ + + + + + + + Please enter your PIN + Confirm your PIN + + + + + +
+
+
+
+
+
+
+
+
1
+
2
+
3
+
+
+
4
+
5
+
6
+
+
+
7
+
8
+
9
+
+
+
+
0
+
+ +
+
+
+
\ No newline at end of file diff --git a/src/pages/pin/pin.scss b/src/pages/pin/pin.scss new file mode 100644 index 000000000..bb4ee9289 --- /dev/null +++ b/src/pages/pin/pin.scss @@ -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; + } +} \ No newline at end of file diff --git a/src/pages/pin/pin.ts b/src/pages/pin/pin.ts new file mode 100644 index 000000000..a7e1191e8 --- /dev/null +++ b/src/pages/pin/pin.ts @@ -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; + } + +} diff --git a/src/pages/settings/lock/lock.html b/src/pages/settings/lock/lock.html new file mode 100644 index 000000000..59198d87c --- /dev/null +++ b/src/pages/settings/lock/lock.html @@ -0,0 +1,20 @@ + + + + Lock + + + + + + + + Startup lock by + + + + {{opt.method}} + + + + \ No newline at end of file diff --git a/src/pages/settings/lock/lock.ts b/src/pages/settings/lock/lock.ts new file mode 100644 index 000000000..ee4082aad --- /dev/null +++ b/src/pages/settings/lock/lock.ts @@ -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(); + } +} diff --git a/src/pages/settings/settings.html b/src/pages/settings/settings.html index 09ba0acd4..f846fa240 100644 --- a/src/pages/settings/settings.html +++ b/src/pages/settings/settings.html @@ -57,18 +57,12 @@ Urgent - + Lock - - Disabled - Lock by PIN - Lock by fingerprint - - Wallets & integrations @@ -81,13 +75,13 @@ More - - Advanced - + + Advanced + About {{appName}} - + \ No newline at end of file diff --git a/src/pages/settings/settings.ts b/src/pages/settings/settings.ts index 09f3eb541..2ccef15c1 100644 --- a/src/pages/settings/settings.ts +++ b/src/pages/settings/settings.ts @@ -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); + } + } diff --git a/src/providers/app/app.ts b/src/providers/app/app.ts index 0dc234e79..d3d8b527b 100644 --- a/src/providers/app/app.ts +++ b/src/providers/app/app.ts @@ -75,6 +75,6 @@ export class AppProvider { getInfo() { return this.http.get(this.jsonPath) - .map((res:Response) => res.json()); + .map((res: Response) => res.json()); } } diff --git a/src/providers/config/config.ts b/src/providers/config/config.ts index 2da6b00b2..c382e5e4c 100644 --- a/src/providers/config/config.ts +++ b/src/providers/config/config.ts @@ -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(() => {