mirror of https://github.com/BTCPrivate/copay.git
Feat: Basic Amount page
This commit is contained in:
parent
0788347829
commit
d05f47d15a
|
@ -37,6 +37,10 @@ import { SettingsPage } from '../pages/settings/settings';
|
|||
import { AboutPage } from '../pages/settings/about/about';
|
||||
import { TermsOfUsePage } from '../pages/settings/about/terms-of-use/terms-of-use';
|
||||
|
||||
/* Send */
|
||||
import { AmountPage } from '../pages/send/amount/amount';
|
||||
import { ConfirmPage } from '../pages/send/confirm/confirm';
|
||||
|
||||
/* Providers */
|
||||
import { WalletProvider } from '../providers/wallet/wallet';
|
||||
import { PersistenceProvider, persistenceProviderFactory } from '../providers/persistence/persistence';
|
||||
|
@ -66,7 +70,9 @@ export function createTranslateLoader(http: Http) {
|
|||
EmailPage,
|
||||
BackupRequestPage,
|
||||
DisclaimerPage,
|
||||
TabsPage
|
||||
TabsPage,
|
||||
AmountPage,
|
||||
ConfirmPage
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -97,7 +103,9 @@ export function createTranslateLoader(http: Http) {
|
|||
EmailPage,
|
||||
BackupRequestPage,
|
||||
DisclaimerPage,
|
||||
TabsPage
|
||||
TabsPage,
|
||||
AmountPage,
|
||||
ConfirmPage
|
||||
],
|
||||
providers: [
|
||||
StatusBar,
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 35 35" style="enable-background:new 0 0 35 35;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{opacity:0.1;}
|
||||
</style>
|
||||
<path class="st0" d="M17.5,0C7.9,0,0,7.9,0,17.5s7.9,17.5,17.5,17.5S35,27.1,35,17.5S27.1,0,17.5,0L17.5,0z M28.6,26.9
|
||||
c-1-2.3-3.2-3.3-5.4-4.1c-1-0.3-1.6-1.3-1.8-2.2c1.9-1.2,3.4-3.5,3.4-6.1v-1.5c0-4.1-3.2-7.3-7.3-7.3s-7.3,3.2-7.3,7.3v1.5
|
||||
c0,2.6,1.5,4.9,3.5,6.3C13.4,21.7,13,22.5,12,23c-2.2,0.7-4.4,1.7-5.4,4.1c-2.3-2.6-3.6-6-3.6-9.6c0-8,6.6-14.5,14.6-14.5
|
||||
s14.6,6.5,14.6,14.5C32.1,21.1,30.8,24.4,28.6,26.9L28.6,26.9z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 812 B |
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Bitcoin_Symbol" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||
y="0px" viewBox="0 0 12 16" style="enable-background:new 0 0 12 16;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#5D5D5D;}
|
||||
</style>
|
||||
<path class="st0" d="M7.4,2.5l0-2.4L6,0.2l0,2.3c-0.4,0-0.8,0-1.2,0l0-2.3l-1.5,0l0,2.4c-0.3,0-0.6,0-0.9,0l-2,0l0,1.5
|
||||
c0,0,1.1,0,1,0c0.6,0,0.8,0.3,0.8,0.6l0,6.5c0,0.2-0.2,0.5-0.6,0.5c0,0-1.1,0-1.1,0l-0.3,1.7l1.9,0c0.4,0,0.7,0,1,0l0,2.4l1.5,0
|
||||
l0-2.4c0.4,0,0.8,0,1.2,0l0,2.3l1.5,0l0-2.4c2.5-0.1,4.2-0.7,4.4-3c0.2-1.8-0.7-2.6-2.1-3C10.5,7,11,6.2,10.9,5
|
||||
C10.7,3.3,9.3,2.7,7.4,2.5z M8.8,10.1c0,1.8-3.1,1.6-4.1,1.6l0-3.2C5.7,8.5,8.8,8.2,8.8,10.1L8.8,10.1z M8.2,5.6
|
||||
c0,1.6-2.6,1.4-3.4,1.4l0-2.9C5.6,4.2,8.2,3.9,8.2,5.6L8.2,5.6z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 939 B |
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="25px" height="15px" viewBox="0 0 25 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 41 (35326) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>scan-ico</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" opacity="0.5">
|
||||
<g id="Send---initial" transform="translate(-326.000000, -139.000000)" stroke-width="1.5" stroke="#4A4A4A">
|
||||
<g id="Send-to-(Field)" transform="translate(0.000000, 70.000000)">
|
||||
<g id="scan-ico" transform="translate(326.000000, 68.000000)">
|
||||
<g id="Icons/Tabs/Scan" transform="translate(0.233333, 0.551724)">
|
||||
<g id="Scan">
|
||||
<path d="M8.01713862,1.23032704 L4.65481836,1.23032704 M4.40485821,1.23032704 L4.40485821,4.48620728" id="Line-Copy-2" stroke-linejoin="round"></path>
|
||||
<path d="M16.3666389,1.23032704 L19.7289592,1.23032704 M19.9789194,1.23032704 L19.9789194,4.48620728" id="Line-Copy-3" stroke-linejoin="round"></path>
|
||||
<path d="M8.01713862,14.3286527 L4.65481836,14.3286527 M4.40485821,14.3286527 L4.40485821,11.0727724" id="Line-Copy-5" stroke-linejoin="round"></path>
|
||||
<path d="M16.3666389,14.3286527 L19.7289592,14.3286527 M19.9789194,14.3286527 L19.9789194,11.0727724" id="Line-Copy-4" stroke-linejoin="round"></path>
|
||||
<path d="M0.559999983,7.67196401 L23.8933334,7.67196401" id="Line"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -3,6 +3,8 @@ import { NavController, NavParams } from 'ionic-angular';
|
|||
import { QRScanner, QRScannerStatus } from '@ionic-native/qr-scanner';
|
||||
import { PlatformProvider } from '../../providers/platform/platform';
|
||||
import { ScanProvider } from '../../providers/scan/scan';
|
||||
import { AmountPage } from '../send/amount/amount';
|
||||
|
||||
//import { QRScanner as QRScannerBrowser } from 'cordova-plugin-qrscanner/src/browser/src/library'
|
||||
|
||||
@Component({
|
||||
|
@ -37,6 +39,8 @@ export class ScanPage {
|
|||
this.scanProvider.activate()
|
||||
.then(resp => {
|
||||
this.text = resp;
|
||||
// TODO: implement incomingData
|
||||
this.navCtrl.push(AmountPage, {address: this.text});
|
||||
})
|
||||
.catch(error => {
|
||||
console.log("error: " + error);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<ion-header>
|
||||
|
||||
<ion-navbar>
|
||||
<ion-title>Amount</ion-title>
|
||||
</ion-navbar>
|
||||
|
||||
</ion-header>
|
||||
|
||||
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<ion-label padding>Recipient</ion-label>
|
||||
<ion-item>
|
||||
<ion-icon name="contact" item-left></ion-icon>
|
||||
<span>{{ address }}</span>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
<div>
|
||||
<div padding>
|
||||
<div>
|
||||
<span>Amount</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ amount || "0.00" }}</span>
|
||||
</div>
|
||||
<div [hidden]="!globalResult">
|
||||
= {{globalResult|| "0.00" }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="keypad">
|
||||
<div class="operator-row">
|
||||
<div class="col operator-send"
|
||||
[hidden]="!allowSend" (click)="finish()">
|
||||
<ion-icon name="arrow-round-forward"></ion-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col digit" (click)="pushDigit('7')">7</div>
|
||||
<div class="col digit" (click)="pushDigit('8')">8</div>
|
||||
<div class="col digit" (click)="pushDigit('9')">9</div>
|
||||
<div class="col operator" (click)="pushOperator('/')">÷</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col digit" (click)="pushDigit('4')">4</div>
|
||||
<div class="col digit" (click)="pushDigit('5')">5</div>
|
||||
<div class="col digit" (click)="pushDigit('6')">6</div>
|
||||
<div class="col operator" (click)="pushOperator('x')">×</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col digit" (click)="pushDigit('1')">1</div>
|
||||
<div class="col digit" (click)="pushDigit('2')">2</div>
|
||||
<div class="col digit" (click)="pushDigit('3')">3</div>
|
||||
<div class="col operator" (click)="pushOperator('+')">+</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col digit" (click)="pushDigit('.')">.</div>
|
||||
<div class="col digit" (click)="pushDigit('0')">0</div>
|
||||
<div class="col digit" (click)="removeDigit()"><ion-icon name="backspace"></ion-icon></div>
|
||||
<div class="col operator" (click)="pushOperator('-')">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
|
@ -0,0 +1,63 @@
|
|||
page-amount {
|
||||
.item-md ion-icon[item-left] + .item-inner {
|
||||
margin: 0px;
|
||||
}
|
||||
.keypad {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
font-weight: lighter;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
color: $v-mid-gray;
|
||||
|
||||
.row {
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.col {
|
||||
line-height: 45px;
|
||||
}
|
||||
|
||||
.operator {
|
||||
background-color: $v-subtle-gray;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
background-color: $v-light-gray;
|
||||
}
|
||||
}
|
||||
|
||||
.operator-row {
|
||||
width: 25%;
|
||||
margin-left: 75%;
|
||||
.operator-send {
|
||||
font-weight: bolder;
|
||||
color: #fff;
|
||||
background-color: #647ce8;
|
||||
font-size: 36px;
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.digit{
|
||||
cursor: pointer;
|
||||
border-top: 1px solid $v-subtle-gray;
|
||||
border-left: 1px solid $v-subtle-gray;
|
||||
&:active {
|
||||
background-color: $v-subtle-gray;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-height: 480px) {
|
||||
font-size: 12px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { NavController, NavParams } from 'ionic-angular';
|
||||
import * as _ from 'lodash';
|
||||
import { ConfirmPage } from '../confirm/confirm';
|
||||
|
||||
@Component({
|
||||
selector: 'page-amount',
|
||||
templateUrl: 'amount.html',
|
||||
})
|
||||
export class AmountPage {
|
||||
|
||||
public address: string;
|
||||
public amount: string;
|
||||
public smallFont: boolean;
|
||||
public allowSend: boolean;
|
||||
public globalResult: string;
|
||||
|
||||
private LENGTH_EXPRESSION_LIMIT = 19;
|
||||
private SMALL_FONT_SIZE_LIMIT = 10;
|
||||
private availableUnits: Array<any> = [];
|
||||
private unitIndex: number = 0;
|
||||
|
||||
constructor(public navCtrl: NavController, public navParams: NavParams) {
|
||||
this.amount = "";
|
||||
this.allowSend = false;
|
||||
}
|
||||
|
||||
ionViewDidLoad() {
|
||||
console.log('ionViewDidLoad AmountPage');
|
||||
console.log("this.navParams.data", this.navParams.data);
|
||||
this.address = this.navParams.data.address;
|
||||
}
|
||||
|
||||
pushDigit(digit: string) {
|
||||
if (this.amount && this.amount.length >= this.LENGTH_EXPRESSION_LIMIT) return;
|
||||
if (this.amount.indexOf('.') > -1 && digit == '.') return;
|
||||
// TODO: next line - Need: isFiat
|
||||
//if (this.availableUnits[this.unitIndex].isFiat && this.amount.indexOf('.') > -1 && this.amount[this.amount.indexOf('.') + 2]) return;
|
||||
|
||||
this.amount = (this.amount + digit).replace('..', '.');
|
||||
console.log("this.amount", this.amount);
|
||||
this.checkFontSize();
|
||||
this.processAmount();
|
||||
};
|
||||
|
||||
removeDigit() {
|
||||
this.amount = (this.amount).toString().slice(0, -1);
|
||||
this.processAmount();
|
||||
this.checkFontSize();
|
||||
};
|
||||
|
||||
pushOperator(operator: string) {
|
||||
if (!this.amount || this.amount.length == 0) return;
|
||||
this.amount = this._pushOperator(this.amount, operator);
|
||||
};
|
||||
|
||||
_pushOperator(val: string, operator: string) {
|
||||
if (!this.isOperator(_.last(val))) {
|
||||
return val + operator;
|
||||
} else {
|
||||
return val.slice(0, -1) + operator;
|
||||
}
|
||||
};
|
||||
|
||||
isOperator(val: string) {
|
||||
var regex = /[\/\-\+\x\*]/;
|
||||
return regex.test(val);
|
||||
};
|
||||
|
||||
isExpression(val: string) {
|
||||
var regex = /^\.?\d+(\.?\d+)?([\/\-\+\*x]\d?\.?\d+)+$/;
|
||||
return regex.test(val);
|
||||
};
|
||||
|
||||
checkFontSize() {
|
||||
if (this.amount && this.amount.length >= this.SMALL_FONT_SIZE_LIMIT) this.smallFont = true;
|
||||
else this.smallFont = false;
|
||||
};
|
||||
|
||||
processAmount() {
|
||||
var formatedValue = this.format(this.amount);
|
||||
var result = this.evaluate(formatedValue);
|
||||
this.allowSend = _.isNumber(result) && +result > 0;
|
||||
if (_.isNumber(result)) {
|
||||
this.globalResult = this.isExpression(this.amount) ? '= ' + this.processResult(result) : '';
|
||||
|
||||
// TODO this.globalResult is always undefinded - Need: processResult()
|
||||
/* if (this.availableUnits[this.unitIndex].isFiat) {
|
||||
|
||||
var a = this.fromFiat(result);
|
||||
if (a) {
|
||||
this.alternativeAmount = txFormatService.formatAmount(a * unitToSatoshi, true);
|
||||
} else {
|
||||
this.alternativeAmount = 'N/A'; //TODO
|
||||
this.allowSend = false;
|
||||
}
|
||||
} else {
|
||||
this.alternativeAmount = $filter('formatFiatAmount')(toFiat(result));
|
||||
} */
|
||||
this.globalResult = result.toString();
|
||||
}
|
||||
};
|
||||
|
||||
format(val: string) {
|
||||
if (!val) return;
|
||||
|
||||
var result = val.toString();
|
||||
|
||||
if (this.isOperator(_.last(val))) result = result.slice(0, -1);
|
||||
|
||||
return result.replace('x', '*');
|
||||
};
|
||||
|
||||
evaluate(val: string) {
|
||||
var result;
|
||||
try {
|
||||
result = eval(val);
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
if (!_.isFinite(result)) return 0;
|
||||
console.log("evaluate result: ", result);
|
||||
return result;
|
||||
};
|
||||
|
||||
processResult(val: number) {
|
||||
// TODO: implement this function correctly - Need: txFormatService, isFiat, $filter
|
||||
console.log("processResult TODO");
|
||||
/*if (this.availableUnits[this.unitIndex].isFiat) return $filter('formatFiatAmount')(val);
|
||||
else return txFormatService.formatAmount(val.toFixed(unitDecimals) * unitToSatoshi, true);*/
|
||||
};
|
||||
|
||||
fromFiat(val: number) {
|
||||
// TODO: implement next line correctly - Need: rateService
|
||||
//return parseFloat((rateService.fromFiat(val, fiatCode, availableUnits[altUnitIndex].id) * satToUnit).toFixed(unitDecimals));
|
||||
};
|
||||
|
||||
toFiat(val) {
|
||||
// TODO: implement next line correctly - Need: rateService
|
||||
/*if (!rateService.getRate(fiatCode)) return;
|
||||
return parseFloat((rateService.toFiat(val * unitToSatoshi, fiatCode, availableUnits[unitIndex].id)).toFixed(2));*/
|
||||
};
|
||||
|
||||
finish() {
|
||||
this.navCtrl.push(ConfirmPage, {address: this.address, amount: this.globalResult});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<ion-header>
|
||||
|
||||
<ion-navbar>
|
||||
<ion-title>Confirm</ion-title>
|
||||
</ion-navbar>
|
||||
|
||||
</ion-header>
|
||||
|
||||
|
||||
<ion-content padding>
|
||||
<div>To: {{address}}</div>
|
||||
<div>Amount: {{amount}}</div>
|
||||
</ion-content>
|
|
@ -0,0 +1,3 @@
|
|||
page-confirm {
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { NavController, NavParams } from 'ionic-angular';
|
||||
|
||||
@Component({
|
||||
selector: 'page-confirm',
|
||||
templateUrl: 'confirm.html',
|
||||
})
|
||||
export class ConfirmPage {
|
||||
|
||||
public address: string;
|
||||
public amount: string;
|
||||
|
||||
constructor(public navCtrl: NavController, public navParams: NavParams) {
|
||||
}
|
||||
|
||||
ionViewDidLoad() {
|
||||
console.log('ionViewDidLoad ConfirmPage');
|
||||
this.address = this.navParams.data.address;
|
||||
this.amount = this.navParams.data.amount;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,3 @@
|
|||
<!--
|
||||
Generated template for the SendPage page.
|
||||
|
||||
See http://ionicframework.com/docs/components/#navigation for more info on
|
||||
Ionic pages and navigation.
|
||||
-->
|
||||
<ion-header>
|
||||
|
||||
<ion-navbar>
|
||||
|
@ -14,5 +8,14 @@
|
|||
|
||||
|
||||
<ion-content padding>
|
||||
<ion-list>
|
||||
|
||||
<ion-label>Recipient</ion-label>
|
||||
<ion-item>
|
||||
<ion-icon name="logo-bitcoin" item-left></ion-icon>
|
||||
<ion-input type="text" placeholder="Search or enter bitcoin address" [(ngModel)]="search" (ngModelChange)="findContact(search)"></ion-input>
|
||||
<ion-icon class="scanner-icon" name="md-qr-scanner" item-right (click)="openScanner()"></ion-icon>
|
||||
</ion-item>
|
||||
|
||||
</ion-list>
|
||||
</ion-content>
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
page-send {
|
||||
|
||||
.item-md ion-icon[item-left] + .item-inner {
|
||||
margin: 0px;
|
||||
}
|
||||
.scanner-icon {
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { NavController, NavParams } from 'ionic-angular';
|
||||
import * as _ from 'lodash';
|
||||
import { AmountPage } from './amount/amount';
|
||||
|
||||
@Component({
|
||||
selector: 'page-send',
|
||||
|
@ -14,4 +16,16 @@ export class SendPage {
|
|||
console.log('ionViewDidLoad SendPage');
|
||||
}
|
||||
|
||||
openScanner() {
|
||||
this.navCtrl.parent.select(2);
|
||||
}
|
||||
|
||||
findContact(search: string) {
|
||||
// TODO: Improve this function
|
||||
console.log("Send search string", search);
|
||||
if (search.length === 34 && _.startsWith(search, '1')) {
|
||||
this.navCtrl.push(AmountPage, {address: search});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue